GSLAM  3.0.0
SO3.h
1 // GSLAM - A general SLAM framework and benchmark
2 // Copyright 2018 PILAB Inc. All rights reserved.
3 // https://github.com/zdzhaoyong/GSLAM
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors may be
14 // used to endorse or promote products derived from this software without
15 // specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Author: zd5945@126.com (Yong Zhao)
30 
31 #ifndef GSLAM_SO3_H
32 #define GSLAM_SO3_H
33 
34 #include <math.h>
35 #include <iostream>
36 #include "Point.h"
37 #include "Matrix.h"
38 
39 
40 #ifndef M_PI
41 # define M_PI 3.14159265358979323846 /* pi */
42 #endif
43 #define NEAR_ZERO 1e-10
44 
45 namespace GSLAM {
46 
47 
48 /**
49  @brief 3D rotation represented by the quaternion.
50 
51  \section sSO3_intro Introduction
52 
53  For the rotational component, there are several choices for representation, including the matrix, Euler angle, unit quaternion and Lie algebra \f$so(3)\f$.
54  For a given transformation, we can use any of these for representation and can convert one to another.:
55  - An unit orthogonal 3x3 matrix \f$ \mathbf{R} \f$.
56  - The Euler angle representation uses 3 variables such as yaw, roll, pitch.
57  - Quaternion \f$q(x,y,z,w)\f$: the most efficient way to perform multiple.
58  - Lie algebra \f$[a,b,c]\f$: the common representation to perform manifold optimization.
59 
60  This implementation use Quaternion for computation.
61  Class SO3 use 4 paraments to present a 3 dimesion rotation matrix,
62  since 3D rotation matrices are members of the Special Orthogonal Lie group SO3.
63 
64  Every rotation in the 3D euclidean space can be represented by a rotation with one direction.
65  Consider a rotation with direction \f$(a,b,c)^T\f$ and angle theta in radians.
66  - w -- \f$cos(theta/2)\f$
67  - x -- \f$a*sin(theta/2)\f$
68  - y -- \f$b*sin(theta/2)\f$
69  - z -- \f$c*sin(theta/2)\f$
70 
71  this ensures that \f$x^2+y^2+z^2+w^2=1\f$.
72  A quaternion \f$q(x,y,z,w)\f$ is used to present a 3d rotation.
73 
74  \section Constructors
75 
76  Users can construct a SO3 from different data structure:
77  @code
78  SO3 I;// default, idendity
79  SO3 R1(x,y,z,w);// from quaternion
80  SO3 R2(Poin3d(rx,ry,rz),angle)// from axis and angle
81  SO3 R3=SO3::exp(Point3d(rx,ry,rz));// from lie algebra
82  SO3 R4=SO3(Matrix3d(m));// from matrix
83  SO3 R4=SO3(m);// from pointer
84  SO3 R5=SO3::fromPitchYawRoll(pitch,yaw,roll); // from Euler
85  @endcode
86 
87  \section sSO3_usage Usages
88 
89  The following testing codes demonstrated the basic usages of SO3:
90 
91  @code
92 TEST(Transform,SO3){
93  std::default_random_engine e;
94 
95  double pitch=std::uniform_real_distribution<double>(-M_PI/2,M_PI/2)(e);
96  double yaw =std::uniform_real_distribution<double>(-M_PI,M_PI)(e);
97  double roll =std::uniform_real_distribution<double>(-M_PI/2,M_PI/2)(e);
98 
99  SO3 q=SO3::fromPitchYawRoll(pitch,yaw,roll);
100 
101  EXPECT_NEAR(pitch,q.getPitch(),1e-5);
102  EXPECT_NEAR(yaw,q.getYaw(),1e-5);
103  EXPECT_NEAR(roll,q.getRoll(),1e-5);
104 
105  // X: forward Y: right Z: down
106  SO3 qRoll =SO3::exp(Point3d(roll,0,0));
107  SO3 qPitch=SO3::exp(Point3d(0,pitch,0));
108  SO3 qYaw =SO3::exp(Point3d(0,0,yaw));
109 
110  SO3 q1=qYaw*qPitch*qRoll;
111  EXPECT_EQ(q,q1);
112 
113  Matrix3d m=q.getMatrix();
114  q1=SO3(m);
115  EXPECT_EQ(q,q1);
116 
117  Point3d abc=q.log();
118  q1=SO3::exp(abc);
119  EXPECT_EQ(q,q1);
120  EXPECT_EQ(SO3(),q.inverse()*q);
121 
122  std::uniform_real_distribution<double> pt_gen(-1000,1000);
123  Point3d xyz(pt_gen(e),pt_gen(e),pt_gen(e));
124  Point3d p1=q.inverse()*q*xyz;
125  EXPECT_NEAR((xyz-p1).norm(),0,1e-6);
126 }
127  @endcode
128 
129  */
130 template <class Precision=double>
131 class SO3_
132 {
133 public:
134  /// Default constructor, Idendity Matrix
135  SO3_():x(0),y(0),z(0),w(1){}
136 
137  /// Construct from Quaternion
138  SO3_(const Precision& X,const Precision& Y,const Precision& Z,const Precision& W)
139  :x(X),y(Y),z(Z),w(W) { }
140 
141  /// Construct from a direction and angle in radius.
142  SO3_(const Point3_<Precision>& direction,Precision angle)
143  {
144  FromAxis(direction,angle);
145  }
146 
147  /// Construct from a rotation matrix data (ColMajor).
148  SO3_(const Precision* M)
149  {
150  fromMatrix(M);
151  }
152 
153  /// Construct from a rotation matrix
155  fromMatrix(M.data());
156  }
157 
158  /// Construct from another precision
159  template<typename Scalar>
160  SO3_(const SO3_<Scalar>& r):SO3_(r.x,r.y,r.z,r.w){
161  }
162 
163  /// @return The lie algebra representation in \f$[a,b,c]\f$
165  {
166  const Precision squared_w = w*w;
167  const Precision n = sqrt(x*x+y*y+z*z);
168 
169  Precision A_inv;
170  // Atan-based log thanks to
171  //
172  // C. Hertzberg et al.:
173  // "Integrating Generic Sensor Fusion Algorithms with Sound State
174  // Representation through Encapsulation of Manifolds"
175  // Information Fusion, 2011
176 
177  if (n < NEAR_ZERO)
178  {
179  //If n is too small
180  A_inv = 2./w - 2.*(1.0-squared_w)/(w*squared_w);
181  }
182  else
183  {
184  if (fabs(w)<NEAR_ZERO)
185  {
186  //If w is too small
187  if (w>0)
188  {
189  A_inv = M_PI/n;
190  }
191  else
192  {
193  A_inv = -M_PI/n;
194  }
195  }
196  else
197  A_inv = 2*atan(n/w)/n;
198  }
199  return Point3_<Precision>(x*A_inv,y*A_inv,z*A_inv);
200  }
201 
202  /// Construct from lie algebra representation
203  template<typename Scalar>
205  {
206  const Scalar theta_sq=r.x*r.x+r.y*r.y+r.z*r.z;
207  const Scalar theta = sqrt(theta_sq);
208  const Scalar half_theta = 0.5*theta;
209 
210  const Scalar W = cos(half_theta);
211  Scalar sin_half_theta;
212  if(theta<NEAR_ZERO)
213  {
214  Scalar theta_po4 = theta_sq*theta_sq;
215  sin_half_theta = 0.5-0.0208333*theta_sq+0.000260417*theta_po4;
216  }
217  else
218  {
219  sin_half_theta = sin(half_theta);
220  sin_half_theta = sin_half_theta/theta;
221  }
222 
223  return SO3_<Precision>(sin_half_theta*r.x,
224  sin_half_theta*r.y,
225  sin_half_theta*r.z,W);
226  }
227 
228  template <typename T>
229  static inline T sine(T x) {
230  T sin = 0;
231  //always wrap input angle to -PI..PI
232  while (x < -3.14159265)
233  x += 6.28318531;
234  while (x > 3.14159265)
235  x -= 6.28318531;
236  //compute sine
237  if (x < 0) {
238  sin = 1.27323954 * x + .405284735 * x * x;
239  if (sin < 0)
240  sin = .225 * (sin * -sin - sin) + sin;
241  else
242  sin = .225 * (sin * sin - sin) + sin;
243  } else {
244  sin = 1.27323954 * x - 0.405284735 * x * x;
245  if (sin < 0)
246  sin = .225 * (sin * -sin - sin) + sin;
247  else
248  sin = .225 * (sin * sin - sin) + sin;
249  }
250  return sin;
251  }
252 
253  template <typename T>
254  static inline T cosine(T x) {
255  //compute cosine: sin(x + PI/2) = cos(x)
256  return sine(x+1.57079632);
257  }
258 
259  template<typename Scalar>
260  static SO3_<Scalar> expFast(const Point3_<Scalar>& l)
261  {
262  Scalar theta_sq = l.dot(l);
263  Scalar theta = sqrt(theta_sq);
264  Scalar half_theta = static_cast<Scalar>(0.5) * theta;
265 
266  Scalar imag_factor;
267  Scalar real_factor;
268 
269  if (theta < static_cast<Scalar>(1e-10)) {
270  Scalar theta_po4 = theta_sq * theta_sq;
271  imag_factor = static_cast<Scalar>(0.5) -
272  static_cast<Scalar>(1.0 / 48.0) * theta_sq +
273  static_cast<Scalar>(1.0 / 3840.0) * theta_po4;
274  real_factor = static_cast<Scalar>(1) -
275  static_cast<Scalar>(0.5) * theta_sq +
276  static_cast<Scalar>(1.0 / 384.0) * theta_po4;
277  } else {
278  Scalar sin_half_theta = sine(half_theta);
279  imag_factor = sin_half_theta / theta;
280  real_factor = cosine(half_theta);
281  }
282 
283  return SO3_<Scalar>( imag_factor * l.x, imag_factor * l.y,
284  imag_factor * l.z,real_factor);
285  }
286 
287  /// This is an unsafe operation.
288  /// Please make sure that your pointer is both valid and has an appropriate size
289  /// Wrong usage:
290  /// Precision* p;
291  /// getMatrix(p);
292  ///
293  /// Correct:
294  /// Precision p[9];
295  /// getMatrix(p);
296  ///
297  /// M is curved as follow
298  /// |m0 m1 m2|
299  /// |m3 m4 m5|
300  /// |m6 m7 m8|
301  inline void fromMatrix(const Precision* m)
302  {
303  auto SIGN=[](const Precision& v){return v>0?1.:-1.;};
304  Precision& q0=w;
305  Precision& q1=x;
306  Precision& q2=y;
307  Precision& q3=z;
308  const Precision &r11=m[0],&r12=m[1],&r13=m[2],
309  &r21=m[3],&r22=m[4],&r23=m[5],
310  &r31=m[6],&r32=m[7],&r33=m[8];
311  q0 = ( r11 + r22 + r33 + 1.0f) / 4.0f;
312  q1 = ( r11 - r22 - r33 + 1.0f) / 4.0f;
313  q2 = (-r11 + r22 - r33 + 1.0f) / 4.0f;
314  q3 = (-r11 - r22 + r33 + 1.0f) / 4.0f;
315  if(q0 < 0.0f) q0 = 0.0f;
316  if(q1 < 0.0f) q1 = 0.0f;
317  if(q2 < 0.0f) q2 = 0.0f;
318  if(q3 < 0.0f) q3 = 0.0f;
319  q0 = sqrt(q0);
320  q1 = sqrt(q1);
321  q2 = sqrt(q2);
322  q3 = sqrt(q3);
323  if(q0 >= q1 && q0 >= q2 && q0 >= q3) {
324  q0 *= +1.0f;
325  q1 *= SIGN(r32 - r23);
326  q2 *= SIGN(r13 - r31);
327  q3 *= SIGN(r21 - r12);
328  } else if(q1 >= q0 && q1 >= q2 && q1 >= q3) {
329  q0 *= SIGN(r32 - r23);
330  q1 *= +1.0f;
331  q2 *= SIGN(r21 + r12);
332  q3 *= SIGN(r13 + r31);
333  } else if(q2 >= q0 && q2 >= q1 && q2 >= q3) {
334  q0 *= SIGN(r13 - r31);
335  q1 *= SIGN(r21 + r12);
336  q2 *= +1.0f;
337  q3 *= SIGN(r32 + r23);
338  } else if(q3 >= q0 && q3 >= q1 && q3 >= q2) {
339  q0 *= SIGN(r21 - r12);
340  q1 *= SIGN(r31 + r13);
341  q2 *= SIGN(r32 + r23);
342  q3 *= +1.0f;
343  } else {
344  std::cerr<<"Unable to construct SO3 from this Matrix.";
345  }
346  Precision r = sqrt(q0*q0+q1*q1+q2*q2+q3*q3);
347  q0 /= r;
348  q1 /= r;
349  q2 /= r;
350  q3 /= r;
351  }
352 
353  Matrix<Precision,3,3> getMatrix()const{
355  getMatrix(m.data());
356  return m;
357  }
358 
359  /// return the matrix M
360  inline void getMatrix(Precision* m)const
361  {
362  Precision x2 = x * x;
363  Precision y2 = y * y;
364  Precision z2 = z * z;
365  Precision xy = x * y;
366  Precision xz = x * z;
367  Precision yz = y * z;
368  Precision wx = w * x;
369  Precision wy = w * y;
370  Precision wz = w * z;
371  m[0]=1.0-2.0*(y2+z2); m[1]=2.0 * ( xy- wz); m[2]= 2.0 * (xz + wy);
372  m[3]=2.0 * (xy + wz); m[4]=1.0-2.0*(x2+z2); m[5]= 2.0 * (yz - wx);
373  m[6]=2.0 * (xz - wy); m[7]=2.0 * ( yz+ wx); m[8]= 1.0-2.0*(x2+y2);
374  }
375 
376 #ifdef HAS_TOON
377  /// Matrix things
378  SO3_(const TooN::Matrix<3,3,Precision>& m)
379  {
380  fromMatrix(m);
381  }
382 
383  bool fromMatrix(const TooN::Matrix<3,3,Precision>& m)
384  {
385  w=0.5*sqrt(m[0][0]+m[1][1]+m[2][2]+1);
386  Precision oneover4w=0.25/w;
387  x=(m[2][1]-m[1][2])*oneover4w;
388  y=(m[0][2]-m[2][0])*oneover4w;
389  z=(m[1][0]-m[0][1])*oneover4w;
390  if(w<0){x*=-1;y*=-1;z*=-1;w*=-1;}
391  return true;
392  }
393 
394  //return the matrix
395  TooN::Matrix<3,3,Precision> getMatrixTooN()const
396  {
397  Precision x2 = x * x;
398  Precision y2 = y * y;
399  Precision z2 = z * z;
400  Precision xy = x * y;
401  Precision xz = x * z;
402  Precision yz = y * z;
403  Precision wx = w * x;
404  Precision wy = w * y;
405  Precision wz = w * z;
406  return TooN::Data(1.0-2.0*(y2+z2), 2.0 * ( xy- wz), 2.0 * (xz + wy),
407  2.0 * (xy + wz), 1.0-2.0*(x2+z2), 2.0 * (yz - wx),
408  2.0 * (xz - wy), 2.0 * ( yz+ wx), 1.0-2.0*(x2+y2));
409  }
410 
411  operator TooN::SO3<Precision>()
412  {
413  return getMatrixTooN();
414  }
415 
416 #endif
417 
418 #ifdef SOPHUS_SO3_HPP
419  SO3_(const Sophus::SO3Group<Precision>& so3)
420  : x(so3.unit_quaternion().coeffs()[0]),
421  y(so3.unit_quaternion().coeffs()[1]),
422  z(so3.unit_quaternion().coeffs()[2]),
423  w(so3.unit_quaternion().coeffs()[3])
424  {}
425 
426  operator Sophus::SO3Group<Precision>()
427  {
428  return Sophus::SO3Group<Precision>(Eigen::Quaternion<Precision>(w,x,y,z));
429  }
430 #endif
431 
432  static SO3_ fromPitchYawRollAngle(const Precision& pitch,const Precision& yaw,const Precision& roll)
433  {
434  Precision a2r=(3.1415926/180.0);
435  return fromPitchYawRoll(pitch*a2r,yaw*a2r,roll*a2r);
436  }
437 
438  static SO3_ fromPitchYawRoll(const Point3d& pyr){
439  return fromPitchYawRoll(pyr.x,pyr.y,pyr.z);
440  }
441 
442  /// Convert from Euler Angles,
443  /// Please use "Radian" rather than degree to present angle
444  static SO3_ fromPitchYawRoll(const Precision& pitch,const Precision& yaw,const Precision& roll)
445  {
446  // Basically we create 3 Quaternions, one for pitch, one for yaw, one for roll
447  // and multiply those together.
448  // the calculation below does the same, just shorter
449  Precision piover360=0.5;//3.1415926/360.0;
450  Precision p = pitch * piover360;
451  Precision y = yaw * piover360;
452  Precision r = roll * piover360;
453 
454 
455  Precision sinp = sin(p);
456  Precision siny = sin(y);
457  Precision sinr = sin(r);
458  Precision cosp = cos(p);
459  Precision cosy = cos(y);
460  Precision cosr = cos(r);
461 
462 
463  Precision rx = sinr * cosp * cosy - cosr * sinp * siny;
464  Precision ry = cosr * sinp * cosy + sinr * cosp * siny;
465  Precision rz = cosr * cosp * siny - sinr * sinp * cosy;
466  Precision rw = cosr * cosp * cosy + sinr * sinp * siny;
467 
468  SO3_ ret(rx,ry,rz,rw);
469  ret.normalise();
470  return ret;
471  }
472 
473  Precision getRoll()const//Radian about axis X
474  {
475  return atan2(2.0*(w*x+y*z),1.0-2.0*(x*x+y*y));
476  }
477 
478  Precision getPitch()const//Radian about axis Y
479  {
480  return asin(2.0*(w*y-z*x));
481  }
482 
483  Precision getYaw()const//Radian about axis Z
484  {
485  return atan2(2.0*(w*z+x*y),1.0-2.0*(z*z+y*y));
486  }
487 
488  ///
489  SO3_ operator* (const SO3_& rq) const
490  {
491  // the constructor takes its arguments as (x, y, z, w)
492  return SO3_( w * rq.x + x * rq.w + y * rq.z - z * rq.y,
493  w * rq.y + y * rq.w + z * rq.x - x * rq.z,
494  w * rq.z + z * rq.w + x * rq.y - y * rq.x,
495  w * rq.w - x * rq.x - y * rq.y - z * rq.z);
496  }
497 
498  // Multiplying a quaternion q with a vector v applies the q-rotation to v
499  Point3_<Precision> operator* (const Point3_<Precision>& p) const
500  {
501  // Note that this algorithm comes from the optimization by hand
502  // of the conversion to a Matrix followed by a Matrix/Vector product.
503  // It appears to be much faster than the common algorithm found
504  // in the literature (30 versus 39 flops). It also requires two
505  // Vector3 as temporaries.
506  Point3_<Precision> uv = Point3_<Precision>(x,y,z).cross(p);
507  uv = uv + uv;
508  return p + w * uv + Point3_<Precision>(x,y,z).cross(uv);
509  }
510 
511  bool operator ==(const SO3_& rq)const{
512  return ((*this).log()-rq.log()).norm()<1e-6;
513  }
514 
515  // Convert from Axis Angle
516  static SO3_ FromAxis(const Point3_<Precision>& p,Precision angle)
517  {
518  Precision det=sqrt(p.x*p.x+p.y*p.y+p.z*p.z);
519  if(det<0.00001)
520  {
521  return SO3_();
522  }
523  angle *= 0.5;
524  Precision p2v=sin(angle)/det;
525  return SO3_(p.x*p2v,p.y*p2v,p.z*p2v,cos(angle));
526  }
527 
528  void normalise()
529  {
530  // Don't normalize if we don't have to
531  Precision mag2 = w * w + x * x + y * y + z * z;
532  if ( mag2!=0.f && (fabs(mag2 - 1.0f) > 0.001))
533  {
534  Precision mag = 1./sqrt(mag2);
535  w *= mag;
536  x *= mag;
537  y *= mag;
538  z *= mag;
539  }
540  }
541 
542  // We need to get the inverse of a quaternion to properly apply a quaternion-rotation to a vector
543  // The conjugate of a quaternion is the same as the inverse, as long as the quaternion is unit-length
544  SO3_ inverse() const
545  {
546  return SO3_(-x, -y, -z, w);
547  }
548 
549  void getValue(Precision& X,Precision& Y,Precision& Z,Precision& W) const
550  {
551  X=x;Y=y;Z=z;W=w;
552  }
553 
554  operator std::string()const
555  {
556  std::stringstream sst;sst<<*this;return sst.str();
557  }
558 
559  Precision getX()const{return x;}
560  Precision getY()const{return y;}
561  Precision getZ()const{return z;}
562  Precision getW()const{return w;}
563 
564  void setX(Precision X){x=X;}
565  void setY(Precision Y){y=Y;}
566  void setZ(Precision Z){z=Z;}
567  void setW(Precision W){w=W;}
568  SO3_ mul (const SO3_& rq) const{return (*this)*rq;}
569  Point3_<Precision> trans(const Point3_<Precision>& p) const{return (*this)*p;}
570 
571  std::string toString()const{std::stringstream sst;sst<<*this;return sst.str();}
572 
573 public:
574  Precision x,y,z,w;
575 };
576 
577 typedef SO3_<double> SO3d;
578 typedef SO3_<float> SO3f;
579 typedef SO3d SO3;
580 
581 /// Write an SO3 to a stream
582 /// @relates SO3
583 template <typename Precision>
584 inline std::ostream& operator << (std::ostream& os,const SO3_<Precision>& so3)
585 {
586 #if 0//HAS_TOON
587  os<<so3.getMatrix();
588  return os;
589 #else
590  Precision X,Y,Z,W;
591  so3.getValue(X,Y,Z,W);
592  os<<X<<" "<<Y<<" "<<Z<<" "<<W;
593  return os;
594 #endif
595 }
596 
597 /// Write an SO3 from a stream
598 /// @relates SO3
599 template <typename Precision>
600 inline std::istream& operator >> (std::istream& is,SO3_<Precision>& so3)
601 {
602  is>>so3.x>>so3.y>>so3.z>>so3.w;
603  return is;
604 }
605 
606 
607 } //end of namespace
608 
609 #endif // GSLAM_CORE_SO3_H
SO3_(const Matrix< Precision, 3, 3 > &M)
Construct from a rotation matrix.
Definition: SO3.h:154
SO3_(const Point3_< Precision > &direction, Precision angle)
Construct from a direction and angle in radius.
Definition: SO3.h:142
Definition: Point.h:162
3D rotation represented by the quaternion.
Definition: SO3.h:131
SO3_()
Default constructor, Idendity Matrix.
Definition: SO3.h:135
void fromMatrix(const Precision *m)
This is an unsafe operation. Please make sure that your pointer is both valid and has an appropriate ...
Definition: SO3.h:301
static SO3_ fromPitchYawRoll(const Precision &pitch, const Precision &yaw, const Precision &roll)
Convert from Euler Angles, Please use "Radian" rather than degree to present angle.
Definition: SO3.h:444
Point3_< Precision > log() const
Definition: SO3.h:164
SO3_(const Precision &X, const Precision &Y, const Precision &Z, const Precision &W)
Construct from Quaternion.
Definition: SO3.h:138
static SO3_< Precision > exp(const Point3_< Scalar > &r)
Construct from lie algebra representation.
Definition: SO3.h:204
Definition: Camera.h:45
void getMatrix(Precision *m) const
return the matrix M
Definition: SO3.h:360
Definition: Matrix.h:46
SO3_(const SO3_< Scalar > &r)
Construct from another precision.
Definition: SO3.h:160
SO3_(const Precision *M)
Construct from a rotation matrix data (ColMajor).
Definition: SO3.h:148