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