/** 回転・クォータニオン ライブラリ Quaternion.cpp */ #include "Rotation.h" using namespace jbxl; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // // クォータニオン クラス // void Quaternion::set(double S, double X, double Y, double Z, double N, double C) { s = S; x = X; y = Y; z = Z; n = N; c = C; //if (n<=0.0) { // n = sqrt(s*s + x*x + y*y + z*z); //} } void Quaternion::normalize() { double nrm = sqrt(s*s + x*x + y*y + z*z); if (nrm>=Zero_Eps) { s = s/nrm; x = x/nrm; y = y/nrm; z = z/nrm; n = 1.0; } else { init(); } } void Quaternion::setRotation(double e, Vector v) { if (v.n!=1.0) v.normalize(); if (e>PI) e = e - PI2; else if (e<-PI) e = PI2 + e; double s2 = e/2.0; double sn = sin(s2); s = cos(s2); x = v.x*sn; y = v.y*sn; z = v.z*sn; n = v.n; c = 1.0; } // X->Y->Z void Quaternion::setEulerXYZ(Vector e) { Vector ex(1.0, 0.0, 0.0, 1.0); Vector ey(0.0, 1.0, 0.0, 1.0); Vector ez(0.0, 0.0, 1.0, 1.0); Quaternion qx, qy, qz; qx.setRotation(e.x, ex); qy.setRotation(e.y, ey); qz.setRotation(e.z, ez); (*this) = qz*qy*qx; } // Z->Y->X void Quaternion::setEulerZYX(Vector e) { Vector ex(1.0, 0.0, 0.0, 1.0); Vector ey(0.0, 1.0, 0.0, 1.0); Vector ez(0.0, 0.0, 1.0, 1.0); Quaternion qx, qy, qz; qx.setRotation(e.z, ex); qy.setRotation(e.y, ey); qz.setRotation(e.x, ez); (*this) = qx*qy*qz; } // X->Z->Y void Quaternion::setEulerXZY(Vector e) { Vector ex(1.0, 0.0, 0.0, 1.0); Vector ey(0.0, 1.0, 0.0, 1.0); Vector ez(0.0, 0.0, 1.0, 1.0); Quaternion qx, qy, qz; qx.setRotation(e.x, ex); qy.setRotation(e.z, ey); qz.setRotation(e.y, ez); (*this) = qy*qz*qx; } // Y->Z->X void Quaternion::setEulerYZX(Vector e) { Vector ex(1.0, 0.0, 0.0, 1.0); Vector ey(0.0, 1.0, 0.0, 1.0); Vector ez(0.0, 0.0, 1.0, 1.0); Quaternion qx, qy, qz; qx.setRotation(e.z, ex); qy.setRotation(e.x, ey); qz.setRotation(e.y, ez); (*this) = qx*qz*qy; } // Y->X->Z void Quaternion::setEulerYXZ(Vector e) { Vector ex(1.0, 0.0, 0.0, 1.0); Vector ey(0.0, 1.0, 0.0, 1.0); Vector ez(0.0, 0.0, 1.0, 1.0); Quaternion qx, qy, qz; qx.setRotation(e.y, ex); qy.setRotation(e.x, ey); qz.setRotation(e.z, ez); (*this) = qz*qx*qy; } // Z->X->Y void Quaternion::setEulerZXY(Vector e) { Vector ex(1.0, 0.0, 0.0, 1.0); Vector ey(0.0, 1.0, 0.0, 1.0); Vector ez(0.0, 0.0, 1.0, 1.0); Quaternion qx, qy, qz; qx.setRotation(e.y, ex); qy.setRotation(e.z, ey); qz.setRotation(e.x, ez); (*this) = qy*qx*qz; } Matrix Quaternion::getRotMatrix() { Matrix mtx(2, 3, 3); // 3x3 2次元マトリックス mtx.element(1, 1) = 1.0 - 2.0*y*y - 2.0*z*z; mtx.element(1, 2) = 2.0*x*y - 2.0*s*z; mtx.element(1, 3) = 2.0*x*z + 2.0*s*y; mtx.element(2, 1) = 2.0*x*y + 2.0*s*z; mtx.element(2, 2) = 1.0 - 2.0*x*x - 2.0*z*z; mtx.element(2, 3) = 2.0*y*z - 2.0*s*x; mtx.element(3, 1) = 2.0*x*z - 2.0*s*y; mtx.element(3, 2) = 2.0*y*z + 2.0*s*x; mtx.element(3, 3) = 1.0 - 2.0*x*x - 2.0*y*y; return mtx; } // // Exec Rotation qv(~q) // Vector Quaternion::execRotation(Vector v) { Quaternion inv = ~(*this); Quaternion qut = ((*this)*(v*inv)); Vector vct = qut.getVector(); return vct; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // // 回転行列,オイラー角 // Matrix jbxl::EulerXYZ2RotMatrix(Vector eul) { Matrix mtx(2, 3, 3); double sinx = sin(eul.x); double cosx = cos(eul.x); double siny = sin(eul.y); double cosy = cos(eul.y); double sinz = sin(eul.z); double cosz = cos(eul.z); mtx.element(1, 1) = cosy*cosz; mtx.element(1, 2) = sinx*siny*cosz - cosx*sinz; mtx.element(1, 3) = cosx*siny*cosz + sinx*sinz; mtx.element(2, 1) = cosy*sinz; mtx.element(2, 2) = sinx*siny*sinz + cosx*cosz; mtx.element(2, 3) = cosx*siny*sinz - sinx*cosz; mtx.element(3, 1) = -siny; mtx.element(3, 2) = sinx*cosy; mtx.element(3, 3) = cosx*cosy; return mtx; } Matrix jbxl::EulerZYX2RotMatrix(Vector eul) { Matrix mtx(2, 3, 3); double sinx = sin(eul.x); double cosx = cos(eul.x); double siny = sin(eul.y); double cosy = cos(eul.y); double sinz = sin(eul.z); double cosz = cos(eul.z); mtx.element(1, 1) = cosy*cosz; mtx.element(1, 2) = -cosy*sinz; mtx.element(1, 3) = siny; mtx.element(2, 1) = cosx*sinz + sinx*siny*cosz; mtx.element(2, 2) = cosx*cosz - sinx*siny*sinz; mtx.element(2, 3) = -sinx*cosy; mtx.element(3, 1) = sinx*sinz - cosx*siny*cosz; mtx.element(3, 2) = sinx*cosz + cosx*siny*sinz; mtx.element(3, 3) = cosx*cosy; return mtx; } Vector jbxl::RotMatrix2EulerXYZ(Matrix mtx, Vector* vct) { Vector eul(0.0, 0.0, 0.0); Vector ev[2]; double m31 = mtx.element(3, 1); if (m31<-1.0 || m31>1.0) return eul; // m31==1.0 || m31==-1.0 if (1.0-m31=0.0) ev[1].y = PI - ev[0].y; else ev[1].y = -PI - ev[0].y; double cy1 = cos(ev[0].y); double cy2 = cos(ev[1].y); if (Xabs(cy1) jbxl::RotMatrixElements2EulerXYZ(double m11, double m12, double m13, double m21, double m31, double m32, double m33, Vector* vct) { Vector eul(0.0, 0.0, 0.0); Vector ev[2]; if (m31<-1.0 || m31>1.0) return eul; // m31==1.0 || m31==-1.0 if (1.0-m31=0.0) ev[1].y = PI - ev[0].y; else ev[1].y = -PI - ev[0].y; double cy1 = cos(ev[0].y); double cy2 = cos(ev[1].y); if (Xabs(cy1) jbxl::RotMatrix2EulerZYX(Matrix mtx, Vector* vct) { Vector eul(0.0, 0.0, 0.0); Vector ev[2]; double m13 = mtx.element(1, 3); if (m13<-1.0 || m13>1.0) return eul; // m13==1.0 || m13==-1.0 if (1.0-m13=0.0) ev[1].y = PI - ev[0].y; else ev[1].y = -PI - ev[0].y; double cy1 = cos(ev[0].y); double cy2 = cos(ev[1].y); if (Xabs(cy1) jbxl::RotMatrixElements2EulerZYX(double m11, double m12, double m13, double m21, double m23, double m31, double m33, Vector* vct) { Vector eul(0.0, 0.0, 0.0); Vector ev[2]; if (m13<-1.0 || m13>1.0) return eul; // m13==1.0 || m13==-1.0 if (1.0-m13=0.0) ev[1].y = PI - ev[0].y; else ev[1].y = -PI - ev[0].y; double cy1 = cos(ev[0].y); double cy2 = cos(ev[1].y); if (Xabs(cy1) jbxl::Quaternion2EulerXYZ(Quaternion qut, Vector* vct) { Matrix mtx = qut.getRotMatrix(); Vector eul = RotMatrix2EulerXYZ(mtx, vct); mtx.free(); return eul; } Vector jbxl::Quaternion2EulerZYX(Quaternion qut, Vector* vct) { Matrix mtx = qut.getRotMatrix(); Vector eul = RotMatrix2EulerZYX(mtx, vct); mtx.free(); return eul; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ベクトルの回転 // Quaternion jbxl::V2VQuaternion(Vector a, Vector b) { Quaternion qut(1.0, 0.0, 0.0, 0.0, 1.0); a.normalize(); b.normalize(); if (a.n nr = a^b; //Vector zv(0.0, 0.0, 0.0, 0.0, 1.0); //Vector ab = a + b; //Vector nr = NewellMethod(zv, a, b); nr.normalize(); //if (nr.n0.5) sn = 0.0; else sn = sqrt(0.5 - cs2); if (Xabs(sn-1.0) c = a + b; if (c.norm()<1.0) { qut.setRotation(PI, nr); if (nr.n a, Vector b, Vector c) { Quaternion qut(1.0, 0.0, 0.0, 0.0, 1.0); if (a.c<0.0 || b.c<0.0 || c.c<0.0) return qut; qut = V2VQuaternion(b-a, c-b); return qut; } Quaternion jbxl::VPPQuaternion(Vector a, Vector b, Vector c) { Quaternion qut(1.0, 0.0, 0.0, 0.0, 1.0); if (a.c<0.0 || b.c<0.0 || c.c<0.0) return qut; qut = V2VQuaternion(a, c-b); return qut; } Quaternion jbxl::PPVQuaternion(Vector a, Vector b, Vector c) { Quaternion qut(1.0, 0.0, 0.0, 0.0, 1.0); if (a.c<0.0 || b.c<0.0 || c.c<0.0) return qut; qut = V2VQuaternion(b-a, c); return qut; } Quaternion jbxl::SlerpQuaternion(Quaternion qa, Quaternion qb, double t) { if (qa.n!=1.0) qa.normalize(); if (qb.n!=1.0) qb.normalize(); // Quaternion qc; Vector va = qa.getVector(); Vector vb = qb.getVector(); va.normalize(); vb.normalize(); // double dot = va*vb; if (dot>1.0) dot = 1.0; else if (dot<-1.0) dot = -1.0; if (dot>1.0-Sin_Tolerance) { double anga = qa.getMathAngle(); double angb = qb.getMathAngle(); double angd = angb - anga; if (angd<-PI) angd += PI2; else if (angd>PI) angd -= PI2; double angc = anga + t*angd; qc.setRotation(angc, va); qc.normalize(); } // else if (dot<-1.0+Sin_Tolerance) { double anga = qa.getMathAngle(); double angb = - qb.getMathAngle(); double angd = angb - anga; if (angd<-PI) angd += PI2; else if (angd>PI) angd -= PI2; double angc = anga + t*angd; qc.setRotation(angc, va); qc.normalize(); return qc; } // SLERP dot = qa.x*qb.x + qa.y*qb.y + qa.z*qb.z + qa.s*qb.s; if (dot>1.0) dot = 1.0; else if (dot<-1.0) dot = -1.0; double th = acos(dot); double sn = sin(th); if (Xabs(sn)