PyOpenGLでクオータニオンによる物体の回転を試してみた
http://staff.aist.go.jp/toru-nakata/quaternion.html
ここに書いてある内容を読んで、pythonで4元数クラスを素直に実装してみた。そしてその実装で物体を回転させるプログラムをPyOpenGLで書いてみた。
Quaternionクラスは単項+,単項-,+,-,*,abs,reprをオーバーロードしていて、conj()で共役4元数、inverse()で逆4元数が得られる。
演算子を適切にオーバーロードしたので座標を回転するコードはごく素直で読みやすく実装できた。
# coding: utf-8 # クオータニオンクラス from numpy import dot, cross, array from math import pi, sin, cos class Quaternion(object): def __init__(self, t, v): self.t = float(t) self.v = array(map(float,v)) def __pos__(p): # +p return p def __neg__(p): # -p return Quaternion(-p.t, -p.v) def __add__(p, q): # p+q return Quaternion(p.t + q.t, p.v + q.v) def __sub__(p, q): # p-q return Quaternion(p.t - q.t, p.v - q.v) def __mul__(p, q): # p*q return Quaternion(p.t*q.t - dot(p.v, q.v), p.t*q.v + q.t*p.v + cross(p.v, q.v) ) def inverse(p): # p*p_ = 1 # 逆4元数 n = p.abs2() p_= p.conj() return Quaternion(p_.t / n, p_.v / n) def abs2(p): return p.t**2 + sum(p.v**2) def __abs__(p): return p.abs2()**.5 def conj(p): # 共役4元数 return Quaternion(p.t, -p.v) def __repr__(p): return "(%f; %f, %f, %f)" % (p.t, p.x, p.y, p.z) @property def x(self): return self.v[0] @property def y(self): return self.v[1] @property def z(self): return self.v[2] def rotation(v, theta, r): # v: 回転対象のベクトル # theta: 回転角度(radian) # r: 回転軸(リスト) # 回転軸の正規化 n = sum(map(lambda x: x**2, r))**.5 r[0] /= n; r[1] /= n; r[2] /= n w = theta / 2. a, b = cos(w), sin(w) p = Quaternion(a, map(lambda x:x*b, r)) p_= p.conj() q = Quaternion(0, v) q = p * q * p_ # 回転 return (q.x, q.y, q.z)