Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/lina/qrot is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef tools_qrot
0005 #define tools_qrot
0006 
0007 // rotation done with quaternion.
0008 
0009 namespace tools {
0010 
0011 template <class VEC3,class VEC4>
0012 class qrot {
0013 protected:
0014   typedef typename VEC4::elem_t T; //we assume = T3
0015 public:
0016   qrot()
0017   :m_quat(0,0,0,1)   //zero rotation around the positive Z axis.
0018   {}
0019   qrot(const VEC3& a_axis,T a_radians,T(*a_sin)(T),T(*a_cos)(T)){
0020     if(!set_value(a_axis,a_radians,a_sin,a_cos)) {} //FIXME : throw
0021   }
0022   qrot(const VEC3& a_from,const VEC3& a_to,T(*a_sqrt)(T),T(*a_fabs)(T)){set_value(a_from,a_to,a_sqrt,a_fabs);}
0023   virtual ~qrot(){}
0024 public:
0025   qrot(const qrot& a_from)
0026   :m_quat(a_from.m_quat)
0027   {}
0028   qrot& operator=(const qrot& a_from){
0029     m_quat = a_from.m_quat;
0030     return *this;
0031   }
0032 protected:
0033   qrot(T a_q0,T a_q1,T a_q2,T a_q3)
0034   :m_quat(a_q0,a_q1,a_q2,a_q3)
0035   {
0036     if(!m_quat.normalize()) {} //FIXME throw
0037   }
0038 
0039 public:
0040   qrot& operator*=(const qrot& a_q) {
0041     //Multiplies the quaternions.
0042     //Note that order is important when combining quaternions with the
0043     //multiplication operator.
0044     // Formula from <http://www.lboro.ac.uk/departments/ma/gallery/quat/>
0045 
0046     T tx = m_quat.v0();
0047     T ty = m_quat.v1();
0048     T tz = m_quat.v2();
0049     T tw = m_quat.v3();
0050 
0051     T qx = a_q.m_quat.v0();
0052     T qy = a_q.m_quat.v1();
0053     T qz = a_q.m_quat.v2();
0054     T qw = a_q.m_quat.v3();
0055 
0056     m_quat.set_value(qw*tx + qx*tw + qy*tz - qz*ty,
0057                      qw*ty - qx*tz + qy*tw + qz*tx,
0058                      qw*tz + qx*ty - qy*tx + qz*tw,
0059                      qw*tw - qx*tx - qy*ty - qz*tz);
0060     m_quat.normalize();
0061     return *this;
0062   }
0063 
0064   bool operator==(const qrot& a_r) const {
0065     return m_quat.equal(a_r.m_quat);
0066   }
0067   bool operator!=(const qrot& a_r) const {
0068     return !operator==(a_r);
0069   }
0070   qrot operator*(const qrot& a_r) const {
0071     qrot tmp(*this);
0072     tmp *= a_r;
0073     return tmp;
0074   }
0075 
0076   bool invert(){
0077     T length = m_quat.length();
0078     if(length==T()) return false;
0079 
0080     // Optimize by doing 1 div and 4 muls instead of 4 divs.
0081     T inv = one() / length;
0082 
0083     m_quat.set_value(-m_quat.v0() * inv,
0084                      -m_quat.v1() * inv,
0085                      -m_quat.v2() * inv,
0086                       m_quat.v3() * inv);
0087 
0088     return true;
0089   }
0090 
0091   bool inverse(qrot& a_r) const {
0092     //Non-destructively inverses the rotation and returns the result.
0093     T length = m_quat.length();
0094     if(length==T()) return false;
0095 
0096     // Optimize by doing 1 div and 4 muls instead of 4 divs.
0097     T inv = one() / length;
0098 
0099     a_r.m_quat.set_value(-m_quat.v0() * inv,
0100                          -m_quat.v1() * inv,
0101                          -m_quat.v2() * inv,
0102                           m_quat.v3() * inv);
0103 
0104     return true;
0105   }
0106 
0107 
0108   bool set_value(const VEC3& a_axis,T a_radians,T(*a_sin)(T),T(*a_cos)(T)) {
0109     // Reset rotation with the given axis-of-rotation and rotation angle.
0110     // Make sure axis is not the null vector when calling this method.
0111     // From <http://www.automation.hut.fi/~jaro/thesis/hyper/node9.html>.
0112     if(a_axis.length()==T()) return false;
0113     m_quat.v3(a_cos(a_radians/2));
0114     T sineval = a_sin(a_radians/2);
0115     VEC3 a = a_axis;
0116     a.normalize();
0117     m_quat.v0(a.v0() * sineval);
0118     m_quat.v1(a.v1() * sineval);
0119     m_quat.v2(a.v2() * sineval);
0120     return true;
0121   }
0122 
0123   bool set_value(const VEC3& a_from,const VEC3& a_to,T(*a_sqrt)(T),T(*a_fabs)(T)) {
0124     // code taken from coin3d/SbRotation.
0125     //NOTE : coin3d/SbMatrix logic is transposed relative to us.
0126 
0127     VEC3 from(a_from);
0128     if(from.normalize()==T()) return false;
0129     VEC3 to(a_to);
0130     if(to.normalize()==T()) return false;
0131 
0132     T dot = from.dot(to);
0133     VEC3 crossvec;from.cross(to,crossvec);
0134     T crosslen = crossvec.normalize();
0135 
0136     if(crosslen == T()) { // Parallel vectors
0137       // Check if they are pointing in the same direction.
0138       if (dot > T()) {
0139         m_quat.set_value(0,0,0,1);
0140       } else {
0141         // Ok, so they are parallel and pointing in the opposite direction
0142         // of each other.
0143         // Try crossing with x axis.
0144         VEC3 t;from.cross(VEC3(1,0,0),t);
0145         // If not ok, cross with y axis.
0146         if(t.normalize() == T()) {
0147           from.cross(VEC3(0,1,0),t);
0148           t.normalize();
0149         }
0150         m_quat.set_value(t[0],t[1],t[2],0);
0151       }
0152     } else { // Vectors are not parallel
0153       // The fabs() wrapping is to avoid problems when `dot' "overflows"
0154       // a tiny wee bit, which can lead to sqrt() returning NaN.
0155       crossvec *= (T)a_sqrt(half() * a_fabs(one() - dot));
0156       // The fabs() wrapping is to avoid problems when `dot' "underflows"
0157       // a tiny wee bit, which can lead to sqrt() returning NaN.
0158       m_quat.set_value(crossvec[0], crossvec[1], crossvec[2],(T)a_sqrt(half()*a_fabs(one()+dot)));
0159     }
0160 
0161     return true;
0162   }
0163 
0164 
0165   bool value(VEC3& a_axis,T& a_radians,T(*a_sin)(T),T(*a_acos)(T)) const { //WARNING a_acos and NOT a_cos
0166     //WARNING : can fail.
0167     if( (m_quat.v3()<minus_one()) || (m_quat.v3()> one()) ) {
0168       a_axis.set_value(0,0,1);
0169       a_radians = 0;
0170       return false;
0171     }
0172 
0173     a_radians = a_acos(m_quat.v3()) * 2; //in [0,2*pi]
0174     T sineval = a_sin(a_radians/2);
0175 
0176     if(sineval==T()) { //a_radian = 0 or 2*pi.
0177       a_axis.set_value(0,0,1);
0178       a_radians = 0;
0179       return false;
0180     }
0181     a_axis.set_value(m_quat.v0()/sineval,
0182                      m_quat.v1()/sineval,
0183                      m_quat.v2()/sineval);
0184     return true;
0185   }
0186 
0187   template <class MAT4>
0188   void set_value(const MAT4& a_m,T(*a_sqrt)(T)) {
0189     // See tests/qrot.icc.
0190     // code taken from coin3d/SbRotation.
0191 
0192     //Set the rotation from the components of the given matrix.
0193 
0194     T scalerow = a_m.v00() + a_m.v11() + a_m.v22();
0195     if (scalerow > T()) {
0196       T _s = a_sqrt(scalerow + a_m.v33());
0197       m_quat.v3(_s * half());
0198       _s = half() / _s;
0199 
0200       m_quat.v0((a_m.v21() - a_m.v12()) * _s);
0201       m_quat.v1((a_m.v02() - a_m.v20()) * _s);
0202       m_quat.v2((a_m.v10() - a_m.v01()) * _s);
0203     } else {
0204       unsigned int i = 0;
0205       if (a_m.v11() > a_m.v00()) i = 1;
0206       if (a_m.v22() > a_m.value(i,i)) i = 2;
0207 
0208       unsigned int j = (i+1)%3;
0209       unsigned int k = (j+1)%3;
0210 
0211       T _s = a_sqrt((a_m.value(i,i) - (a_m.value(j,j) + a_m.value(k,k))) + a_m.v33());
0212 
0213       m_quat.set_value(i,_s * half());
0214       _s = half() / _s;
0215 
0216       m_quat.v3((a_m.value(k,j) - a_m.value(j,k)) * _s);
0217       m_quat.set_value(j,(a_m.value(j,i) + a_m.value(i,j)) * _s);
0218       m_quat.set_value(k,(a_m.value(k,i) + a_m.value(i,k)) * _s);
0219     }
0220 
0221     if (a_m.v33()!=one()) {
0222       m_quat.multiply(one()/a_sqrt(a_m.v33()));
0223     }
0224   }
0225 
0226   template <class MAT4>
0227   void value(MAT4& a_m) const {
0228     //Return this rotation in the form of a matrix.
0229     //NOTE : in coin3d/SbRotation, it looks as if "w <-> -w", but coin3d/SbMatrix logic is transposed relative to us.
0230 
0231     const T x = m_quat.v0();
0232     const T y = m_quat.v1();
0233     const T z = m_quat.v2();
0234     const T w = m_quat.v3();
0235     // q = w + x * i + y * j + z * k
0236 
0237     // first row :
0238     a_m.v00(w*w + x*x - y*y - z*z);
0239     a_m.v01(2*x*y - 2*w*z);
0240     a_m.v02(2*x*z + 2*w*y);
0241     a_m.v03(0);
0242 
0243     // second row :
0244     a_m.v10(2*x*y + 2*w*z);
0245     a_m.v11(w*w - x*x + y*y - z*z);
0246     a_m.v12(2*y*z - 2*w*x);
0247     a_m.v13(0);
0248 
0249     // third row :
0250     a_m.v20(2*x*z - 2*w*y);
0251     a_m.v21(2*y*z + 2*w*x);
0252     a_m.v22(w*w - x*x - y*y + z*z);
0253     a_m.v23(0);
0254 
0255     // fourth row :
0256     a_m.v30(0);
0257     a_m.v31(0);
0258     a_m.v32(0);
0259     a_m.v33(w*w + x*x + y*y + z*z);
0260   }
0261 
0262   template <class MAT3>
0263   T value_3(MAT3& a_m) const {
0264     //Return this rotation in the form of a 3D matrix.
0265     //NOTE : in coin3d/SbRotation, it looks as if "w <-> -w", but coin3d/SbMatrix logic is transposed relative to us.
0266 
0267     const T x = m_quat.v0();
0268     const T y = m_quat.v1();
0269     const T z = m_quat.v2();
0270     const T w = m_quat.v3();
0271     // q = w + x * i + y * j + z * k
0272 
0273     // first row :
0274     a_m.v00(w*w + x*x - y*y - z*z);
0275     a_m.v01(2*x*y - 2*w*z);
0276     a_m.v02(2*x*z + 2*w*y);
0277 
0278     // second row :
0279     a_m.v10(2*x*y + 2*w*z);
0280     a_m.v11(w*w - x*x + y*y - z*z);
0281     a_m.v12(2*y*z - 2*w*x);
0282 
0283     // third row :
0284     a_m.v20(2*x*z - 2*w*y);
0285     a_m.v21(2*y*z + 2*w*x);
0286     a_m.v22(w*w - x*x - y*y + z*z);
0287 
0288     return w*w + x*x + y*y + z*z;  //should be 1.
0289   }
0290 
0291   void mul_vec(const VEC3& a_in,VEC3& a_out) const {
0292     const T x = m_quat.v0();
0293     const T y = m_quat.v1();
0294     const T z = m_quat.v2();
0295     const T w = m_quat.v3();
0296 
0297     // first row :
0298     T v0 =     (w*w + x*x - y*y - z*z) * a_in.v0()
0299               +        (2*x*y - 2*w*z) * a_in.v1()
0300               +        (2*x*z + 2*w*y) * a_in.v2();
0301 
0302     T v1 =             (2*x*y + 2*w*z) * a_in.v0()
0303               +(w*w - x*x + y*y - z*z) * a_in.v1()
0304               +        (2*y*z - 2*w*x) * a_in.v2();
0305 
0306     T v2 =             (2*x*z - 2*w*y) * a_in.v0()
0307               +        (2*y*z + 2*w*x) * a_in.v1()
0308               +(w*w - x*x - y*y + z*z) * a_in.v2();
0309 
0310     a_out.set_value(v0,v1,v2);
0311   }
0312 
0313   void mul_vec(VEC3& a_v) const {
0314     const T x = m_quat.v0();
0315     const T y = m_quat.v1();
0316     const T z = m_quat.v2();
0317     const T w = m_quat.v3();
0318 
0319     // first row :
0320     T v0 =     (w*w + x*x - y*y - z*z) * a_v.v0()
0321               +        (2*x*y - 2*w*z) * a_v.v1()
0322               +        (2*x*z + 2*w*y) * a_v.v2();
0323 
0324     T v1 =             (2*x*y + 2*w*z) * a_v.v0()
0325               +(w*w - x*x + y*y - z*z) * a_v.v1()
0326               +        (2*y*z - 2*w*x) * a_v.v2();
0327 
0328     T v2 =             (2*x*z - 2*w*y) * a_v.v0()
0329               +        (2*y*z + 2*w*x) * a_v.v1()
0330               +(w*w - x*x - y*y + z*z) * a_v.v2();
0331 
0332     a_v.set_value(v0,v1,v2);
0333   }
0334 
0335   void mul_3(T& a_x,T& a_y,T& a_z) const {
0336     const T x = m_quat.v0();
0337     const T y = m_quat.v1();
0338     const T z = m_quat.v2();
0339     const T w = m_quat.v3();
0340 
0341     // first row :
0342     T v0 =     (w*w + x*x - y*y - z*z) * a_x
0343               +        (2*x*y - 2*w*z) * a_y
0344               +        (2*x*z + 2*w*y) * a_z;
0345 
0346     T v1 =             (2*x*y + 2*w*z) * a_x
0347               +(w*w - x*x + y*y - z*z) * a_y
0348               +        (2*y*z - 2*w*x) * a_z;
0349 
0350     T v2 =             (2*x*z - 2*w*y) * a_x
0351               +        (2*y*z + 2*w*x) * a_y
0352               +(w*w - x*x - y*y + z*z) * a_z;
0353 
0354     a_x = v0;
0355     a_y = v1;
0356     a_z = v2;
0357   }
0358 
0359 public: //for io::streamer
0360   const VEC4& quat() const {return m_quat;}
0361   VEC4& quat() {return m_quat;}
0362 
0363 protected:
0364   static T one() {return T(1);}
0365   static T minus_one() {return T(-1);}
0366   static T half() {return T(0.5);}
0367 
0368 protected:
0369   VEC4 m_quat;
0370 };
0371 
0372 }
0373 
0374 #endif