4元数宝典
这是国内找不到的超好文章。(为什么大陆的4元数文章很垃圾呢?)<br/>(翻译中。。。奉献给大家~~) <p></p><p>70秒即懂,能使用,用四元数,4元数,阔特尼恩,Quaternion旋转<br/>(C) 中田 亨 (独立行政法人 产业技术综合研究所 数字人类研究中心 研究员 博士(工学)) <br/>2003年11月25日</p><p>★这个页面的对象读者<br/>想把三次元的旋转,用CG等定量地处理的人<br/>使用欧拉角(Euler Angles)的话,不懂得其道理的人 <br/>卡尔丹角和欧拉角(Cardan Angles)不能区别的人 <br/>对吉恩瓦尔洛克很困惑的人<br/>但是,对数学之类麻烦的事情很讨厌的人<br/>想要实例程序的人 <br/>没有时间的人</p><p>★旋转篇:<br/> 我将说明使用了四元数(si yuan shu, quaternion)的旋转的操作步骤<br/>(1)四元数的虚部,实部和写法<br/>所谓四元数,就是把4个实数组合起来的东西。<br/>4个元素中,一个是实部,其余3个是虚部。<br/>比如,叫做Q的四元数,实部t而虚部是x,y,z构成,则像下面这样写。<br/>Q = (t; x, y, z) <br/>又,使用向量 V=(x,y,z),<br/>Q = (t; V) <br/>也可以这么写。</p><p>正规地用虚数单位i,j,k的写法的话,<br/>Q = t + xi + yj + zk <br/>也这样写,不过,我不大使用</p><p>(2)四元数之间的乘法<br/>虚数单位之间的乘法 <br/>ii = -1, ij = -ji = k (其他的组合也是循环地以下同文) <br/>有这么一种规则。(我总觉得,这就像是向量积(外积),对吧) <br/>用这个规则一点点地计算很麻烦,所以请用像下面这样的公式计算。</p><p>A = (a; U) <br/>B = (b; V) <br/>AB = (ab - U·V; aV + bU + U×V)<br/>不过,“U·V”是内积,「U×V」是外积的意思。<br/>注意:一般AB<>BA所以乘法的左右要注意!</p><p>(3)3次元的坐标的四元数表示<br/>如要将某坐标(x,y,z)用四元数表示,<br/>P = (0; x, y, z) <br/>则要这么写。<br/> <br/>另外,即使实部是零以外的值,下文的结果也一样。用零的话省事所以我推荐。</p><p>(4)旋转的四元数表示<br/>以原点为旋转中心,旋转的轴是(α, β, γ)<br/>(但 α^2 + β^2 + γ^2 = 1), <br/>(右手系的坐标定义的话,望向向量(α, β, γ)的前进方向反时针地) <br/>转θ角的旋转,用四元数表示就是,<br/>Q = (cos(θ/2); α sin(θ/2), β sin(θ/2), γ sin(θ/2)) <br/>R = (cos(θ/2); -α sin(θ/2), -β sin(θ/2), -γ sin(θ/2)) <br/>(另外R 叫 Q 的共轭四元数。) </p><p>那么,如要实行旋转,<br/>则 R P Q = (0; 答案) </p><p>请像这样三明治式地计算。这个值的虚部就是旋转之后的点的坐标值。<br/> (另外,实部应该为零。请验算看看) </p><p>*未完。。。<br/></p> /// Quaternion.cpp <br/>/// (C) Toru Nakata, toru-nakata@aist.go.jp <br/>/// 2004 Dec 29 <br/> <br/>#include <math.h> <br/>#include <iostream.h> <br/> <br/>/// Define Data type <br/>typedef struct <br/>{ <br/> double t; // real-component <br/> double x; // x-component <br/> double y; // y-component <br/> double z; // z-component <br/>} quaternion; <br/> <br/> <br/>//// Kakezan <br/>quaternion Kakezan(quaternion left, quaternion right) <br/>{ <br/> quaternion ans; <br/> double d1, d2, d3, d4; <br/> <br/> d1 = left.t * right.t; <br/> d2 = -left.x * right.x; <br/> d3 = -left.y * right.y; <br/> d4 = -left.z * right.z; <br/> ans.t = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.x; <br/> d2 = right.t * left.x; <br/> d3 = left.y * right.z; <br/> d4 = -left.z * right.y; <br/> ans.x = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.y; <br/> d2 = right.t * left.y; <br/> d3 = left.z * right.x; <br/> d4 = -left.x * right.z; <br/> ans.y = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.z; <br/> d2 = right.t * left.z; <br/> d3 = left.x * right.y; <br/> d4 = -left.y * right.x; <br/> ans.z = d1+ d2+ d3+ d4; <br/> <br/> return ans; <br/>} <br/> <br/>//// Make Rotational quaternion <br/>quaternion MakeRotationalQuaternion(double radian, double AxisX, double AxisY, double AxisZ) <br/>{ <br/> quaternion ans; <br/> double norm; <br/> double ccc, sss; <br/> <br/> ans.t = ans.x = ans.y = ans.z = 0.0; <br/> <br/> norm = AxisX * AxisX + AxisY * AxisY + AxisZ * AxisZ; <br/> if(norm <= 0.0) return ans; <br/> <br/> norm = 1.0 / sqrt(norm); <br/> AxisX *= norm; <br/> AxisY *= norm; <br/> AxisZ *= norm; <br/> <br/> ccc = cos(0.5 * radian); <br/> sss = sin(0.5 * radian); <br/> <br/> ans.t = ccc; <br/> ans.x = sss * AxisX; <br/> ans.y = sss * AxisY; <br/> ans.z = sss * AxisZ; <br/> <br/> return ans; <br/>} <br/> <br/>//// Put XYZ into quaternion <br/>quaternion PutXYZToQuaternion(double PosX, double PosY, double PosZ) <br/>{ <br/> quaternion ans; <br/> <br/> ans.t = 0.0; <br/> ans.x = PosX; <br/> ans.y = PosY; <br/> ans.z = PosZ; <br/> <br/> return ans; <br/>} <br/> <br/>///// main <br/>int main() <br/>{ <br/> double px, py, pz; <br/> double ax, ay, az, th; <br/> quaternion ppp, qqq, rrr; <br/> <br/> cout << "Point Position (x, y, z) " << endl; <br/> cout << " x = "; <br/> cin >> px; <br/> cout << " y = "; <br/> cin >> py; <br/> cout << " z = "; <br/> cin >> pz; <br/> ppp = PutXYZToQuaternion(px, py, pz); <br/> <br/> while(1) { <br/> cout << "\nRotation Degree ? (Enter 0 to Quit) " << endl; <br/> cout << " angle = "; <br/> cin >> th; <br/> if(th == 0.0) break; <br/> <br/> cout << "Rotation Axis Direction ? (x, y, z) " << endl; <br/> cout << " x = "; <br/> cin >> ax; <br/> cout << " y = "; <br/> cin >> ay; <br/> cout << " z = "; <br/> cin >> az; <br/> <br/> <br/> th *= 3.1415926535897932384626433832795 / 180.0; /// Degree -> radian; <br/> <br/> qqq = MakeRotationalQuaternion(th, ax, ay, az); <br/> rrr = MakeRotationalQuaternion(-th, ax, ay, az); <br/> <br/> ppp = Kakezan(rrr, ppp); <br/> ppp = Kakezan(ppp, qqq); <br/> <br/> cout << "\nAnser X = " << ppp.x <br/> << "\n Y = " << ppp.y <br/> << "\n Z = " << ppp.z << endl; <br/> <br/> } <br/> <br/> return 0; <br/>} /// Quaternion.cpp <br/>/// (C) Toru Nakata, toru-nakata@aist.go.jp <br/>/// 2004 Dec 29 <br/> <br/>#include <math.h> <br/>#include <iostream.h> <br/> <br/>/// Define Data type <br/>typedef struct <br/>{ <br/> double t; // real-component <br/> double x; // x-component <br/> double y; // y-component <br/> double z; // z-component <br/>} quaternion; <br/> <br/> <br/>//// Kakezan <br/>quaternion Kakezan(quaternion left, quaternion right) <br/>{ <br/> quaternion ans; <br/> double d1, d2, d3, d4; <br/> <br/> d1 = left.t * right.t; <br/> d2 = -left.x * right.x; <br/> d3 = -left.y * right.y; <br/> d4 = -left.z * right.z; <br/> ans.t = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.x; <br/> d2 = right.t * left.x; <br/> d3 = left.y * right.z; <br/> d4 = -left.z * right.y; <br/> ans.x = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.y; <br/> d2 = right.t * left.y; <br/> d3 = left.z * right.x; <br/> d4 = -left.x * right.z; <br/> ans.y = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.z; <br/> d2 = right.t * left.z; <br/> d3 = left.x * right.y; <br/> d4 = -left.y * right.x; <br/> ans.z = d1+ d2+ d3+ d4; <br/> <br/> return ans; <br/>} <br/> <br/>//// Make Rotational quaternion <br/>quaternion MakeRotationalQuaternion(double radian, double AxisX, double AxisY, double AxisZ) <br/>{ <br/> quaternion ans; <br/> double norm; <br/> double ccc, sss; <br/> <br/> ans.t = ans.x = ans.y = ans.z = 0.0; <br/> <br/> norm = AxisX * AxisX + AxisY * AxisY + AxisZ * AxisZ; <br/> if(norm <= 0.0) return ans; <br/> <br/> norm = 1.0 / sqrt(norm); <br/> AxisX *= norm; <br/> AxisY *= norm; <br/> AxisZ *= norm; <br/> <br/> ccc = cos(0.5 * radian); <br/> sss = sin(0.5 * radian); <br/> <br/> ans.t = ccc; <br/> ans.x = sss * AxisX; <br/> ans.y = sss * AxisY; <br/> ans.z = sss * AxisZ; <br/> <br/> return ans; <br/>} <br/> <br/>//// Put XYZ into quaternion <br/>quaternion PutXYZToQuaternion(double PosX, double PosY, double PosZ) <br/>{ <br/> quaternion ans; <br/> <br/> ans.t = 0.0; <br/> ans.x = PosX; <br/> ans.y = PosY; <br/> ans.z = PosZ; <br/> <br/> return ans; <br/>} <br/> <br/>///// main <br/>int main() <br/>{ <br/> double px, py, pz; <br/> double ax, ay, az, th; <br/> quaternion ppp, qqq, rrr; <br/> <br/> cout << "Point Position (x, y, z) " << endl; <br/> cout << " x = "; <br/> cin >> px; <br/> cout << " y = "; <br/> cin >> py; <br/> cout << " z = "; <br/> cin >> pz; <br/> ppp = PutXYZToQuaternion(px, py, pz); <br/> <br/> while(1) { <br/> cout << "\nRotation Degree ? (Enter 0 to Quit) " << endl; <br/> cout << " angle = "; <br/> cin >> th; <br/> if(th == 0.0) break; <br/> <br/> cout << "Rotation Axis Direction ? (x, y, z) " << endl; <br/> cout << " x = "; <br/> cin >> ax; <br/> cout << " y = "; <br/> cin >> ay; <br/> cout << " z = "; <br/> cin >> az; <br/> <br/> <br/> th *= 3.1415926535897932384626433832795 / 180.0; /// Degree -> radian; <br/> <br/> qqq = MakeRotationalQuaternion(th, ax, ay, az); <br/> rrr = MakeRotationalQuaternion(-th, ax, ay, az); <br/> <br/> ppp = Kakezan(rrr, ppp); <br/> ppp = Kakezan(ppp, qqq); <br/> <br/> cout << "\nAnser X = " << ppp.x <br/> << "\n Y = " << ppp.y <br/> << "\n Z = " << ppp.z << endl; <br/> <br/> } <br/> <br/> return 0; <br/>} /// Quaternion.cpp <br/>/// (C) Toru Nakata, toru-nakata@aist.go.jp <br/>/// 2004 Dec 29 <br/> <br/>#include <math.h> <br/>#include <iostream.h> <br/> <br/>/// Define Data type <br/>typedef struct <br/>{ <br/> double t; // real-component <br/> double x; // x-component <br/> double y; // y-component <br/> double z; // z-component <br/>} quaternion; <br/> <br/> <br/>//// Kakezan <br/>quaternion Kakezan(quaternion left, quaternion right) <br/>{ <br/> quaternion ans; <br/> double d1, d2, d3, d4; <br/> <br/> d1 = left.t * right.t; <br/> d2 = -left.x * right.x; <br/> d3 = -left.y * right.y; <br/> d4 = -left.z * right.z; <br/> ans.t = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.x; <br/> d2 = right.t * left.x; <br/> d3 = left.y * right.z; <br/> d4 = -left.z * right.y; <br/> ans.x = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.y; <br/> d2 = right.t * left.y; <br/> d3 = left.z * right.x; <br/> d4 = -left.x * right.z; <br/> ans.y = d1+ d2+ d3+ d4; <br/> <br/> d1 = left.t * right.z; <br/> d2 = right.t * left.z; <br/> d3 = left.x * right.y; <br/> d4 = -left.y * right.x; <br/> ans.z = d1+ d2+ d3+ d4; <br/> <br/> return ans; <br/>} <br/> <br/>//// Make Rotational quaternion <br/>quaternion MakeRotationalQuaternion(double radian, double AxisX, double AxisY, double AxisZ) <br/>{ <br/> quaternion ans; <br/> double norm; <br/> double ccc, sss; <br/> <br/> ans.t = ans.x = ans.y = ans.z = 0.0; <br/> <br/> norm = AxisX * AxisX + AxisY * AxisY + AxisZ * AxisZ; <br/> if(norm <= 0.0) return ans; <br/> <br/> norm = 1.0 / sqrt(norm); <br/> AxisX *= norm; <br/> AxisY *= norm; <br/> AxisZ *= norm; <br/> <br/> ccc = cos(0.5 * radian); <br/> sss = sin(0.5 * radian); <br/> <br/> ans.t = ccc; <br/> ans.x = sss * AxisX; <br/> ans.y = sss * AxisY; <br/> ans.z = sss * AxisZ; <br/> <br/> return ans; <br/>} <br/> <br/>//// Put XYZ into quaternion <br/>quaternion PutXYZToQuaternion(double PosX, double PosY, double PosZ) <br/>{ <br/> quaternion ans; <br/> <br/> ans.t = 0.0; <br/> ans.x = PosX; <br/> ans.y = PosY; <br/> ans.z = PosZ; <br/> <br/> return ans; <br/>} <br/> <br/>///// main <br/>int main() <br/>{ <br/> double px, py, pz; <br/> double ax, ay, az, th; <br/> quaternion ppp, qqq, rrr; <br/> <br/> cout << "Point Position (x, y, z) " << endl; <br/> cout << " x = "; <br/> cin >> px; <br/> cout << " y = "; <br/> cin >> py; <br/> cout << " z = "; <br/> cin >> pz; <br/> ppp = PutXYZToQuaternion(px, py, pz); <br/> <br/> while(1) { <br/> cout << "\nRotation Degree ? (Enter 0 to Quit) " << endl; <br/> cout << " angle = "; <br/> cin >> th; <br/> if(th == 0.0) break; <br/> <br/> cout << "Rotation Axis Direction ? (x, y, z) " << endl; <br/> cout << " x = "; <br/> cin >> ax; <br/> cout << " y = "; <br/> cin >> ay; <br/> cout << " z = "; <br/> cin >> az; <br/> <br/> <br/> th *= 3.1415926535897932384626433832795 / 180.0; /// Degree -> radian; <br/> <br/> qqq = MakeRotationalQuaternion(th, ax, ay, az); <br/> rrr = MakeRotationalQuaternion(-th, ax, ay, az); <br/> <br/> ppp = Kakezan(rrr, ppp); <br/> ppp = Kakezan(ppp, qqq); <br/> <br/> cout << "\nAnser X = " << ppp.x <br/> << "\n Y = " << ppp.y <br/> << "\n Z = " << ppp.z << endl; <br/> <br/> } <br/> <br/> return 0; <br/>} 恩,支持
页:
[1]