GSLAM  3.0.0
SE3.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_SE3_H
32 #define GSLAM_SE3_H
33 
34 #include "SO3.h"
35 
36 namespace GSLAM
37 {
38 /**
39  Represent a three-dimensional Euclidean transformation (a rotation and a translation).
40  | r00 r01 r02 t0 |
41 M = | R T |= | r10 r11 r12 t1 | = | Rx Ry Rz T |
42  | 0 1 | | r20 r21 r22 t2 | | 0 0 0 1 |
43  | 0 0 0 1 |
44 Here R=(Rx,Ry,Rz) is the rotation , T=(x,y,z)^T is the translation.
45 
46 For the matrix M (only if the matrix means a camera to world transform):
47 Rx means the direction of X axis;
48 Ry means the direction of Y axis;
49 Rz means the direction of Z axis;
50 T means the translation of this coordinate.
51 
52 
53 The coordinates of point P=(X,Y,Z)^T in this coordinate can be computed by left-multiply the matrix M:
54 @code
55 SE3<double> C2W; // Camera to world SE3
56 Point3d P_cam(1,2,3); // Coordinates in the camera coordinate
57 cout<<"Coordinates in the world coordinate:"<<C2W*P_cam<<endl;
58 
59 SE3<double> W2C=C2W.inv(); // It also can present a world to camera transform
60 Point3d P_w(4,5,6); // A point in the world
61 cout<<"The coodinates in the camera is "<<W2C*P_w;
62 @endcode
63 
64 It should be noticed that when a SE3 is representing the world-to-camera transform,
65 the function <code>get_translation()</code> does not acqually return the translation.
66 
67  */
68 template <class Precision = double>
69 class SE3_
70 {
71 public:
72  typedef Point3_<Precision> Vec3;
73 
74 public:
75  SE3_():my_rotation(0,0,0,1),my_translation(0,0,0){}
76 
77  SE3_(const Precision& x,const Precision& y,const Precision& z,
78  const Precision& wx,const Precision& wy,const Precision& wz,const Precision& w)
79  :my_rotation(wx,wy,wz,w),my_translation(x,y,z){}
80 
81  SE3_(const SO3_<Precision>& r,const Vec3& t)
82  :my_rotation(r),my_translation(t){}
83 
84  template <typename Scalar>
85  operator SE3_<Scalar>()
86  {
87  return SE3_<Scalar>(my_rotation,my_translation);
88  }
89 
90  /// Returns the rotation part of the transformation as a SO3
91  inline SO3_<Precision>& get_rotation(){return my_rotation;}
92  /// @overload
93  inline const SO3_<Precision>& get_rotation() const {return my_rotation;}
94 
95  /// Returns the translation part of the transformation as a Vector
96  inline Vec3& get_translation() {return my_translation;}
97  /// @overload
98  inline const Vec3& get_translation() const {return my_translation;}
99 
100  inline SE3_ inverse() const {
101  const SO3_<Precision> rinv(my_rotation.inverse());
102  return SE3_(rinv, -(rinv*my_translation));
103  }
104 
105  /// Right-multiply by another SE3 (concatenate the two transformations)
106  /// @param rhs The multipier
107  template<typename P>
108  inline SE3_& operator *=(const SE3_<P> & rhs) {
109  my_translation = my_translation + my_rotation * rhs.get_translation();
110  my_rotation = my_rotation*rhs.get_rotation();
111  return *this;
112  }
113 
114  template<typename P>
115  inline SE3_ operator *(const SE3_<P>& rhs) const
116  {
117  return SE3_(my_rotation*rhs.get_rotation(),
118  my_translation + my_rotation*rhs.get_translation());
119  }
120 
121  template<typename P>
122  inline bool operator <(const SE3_<P>& rhs) const
123  {
124  return false;
125  }
126 
127  /// Right-multiply by a Vector
128  /// @relates SE3
129  friend Vec3 operator*(const SE3_<Precision>& lhs, const Vec3& rhs){
130  return lhs.get_translation() + lhs.get_rotation() * rhs;
131  }
132 
133  /// Write an SE3 to a stream
134  /// @relates SE3
135  friend inline std::ostream& operator <<(std::ostream& os, const SE3_& rhs){
136  os<<rhs.get_translation();
137  os<<" "<<rhs.get_rotation();
138  return os;
139  }
140  /// Write an SE3 from a stream
141  /// @relates SE3
142  friend inline std::istream& operator >>(std::istream& is, SE3_& rhs){
143  Precision x,y,z,rx,ry,rz,w;
144  is>>x>>y>>z>>rx>>ry>>rz>>w;
145  rhs=SE3_(x,y,z,rx,ry,rz,w);
146  return is;
147  }
148 
149 
150  /// R is described as follow, M is a 4*4 Homography matrix
151  /// |r0 r1 r2|
152  /// |r3 r4 r5|
153  /// |r6 r7 r8|
154  void fromMatrix(const Precision* m)
155  {
156  Precision r[9];
157  r[0]=m[0]; r[1]=m[1]; r[2] =m[2]; my_translation[0] =m[3];
158  r[3]=m[4]; r[4]=m[5]; r[5] =m[6]; my_translation[1] =m[7];
159  r[6]=m[8]; r[7]=m[9]; r[8]=m[10]; my_translation[2] =m[11];
160  my_rotation.fromMatrix(r);
161  }
162 
163  //return the matrix
164  void getMatrix(Precision* m)const
165  {
166  Precision r[9];
167  my_rotation.getMatrix(r);
168 
169  m[0]=r[0]; m[1]=r[1]; m[2] =r[2]; m[3] =my_translation[0];
170  m[4]=r[3]; m[5]=r[4]; m[6] =r[5]; m[7] =my_translation[1];
171  m[8]=r[6]; m[9]=r[7]; m[10]=r[8]; m[11]=my_translation[2];
172  }
173 
174 #ifdef HAS_TOON
175  operator TooN::SE3<Precision>()
176  {
177  return TooN::SE3<Precision>(my_rotation,*(TooN::Vector<3,Precision>*)&my_translation);
178  }
179 
180  SE3_<Precision>(const TooN::SE3<Precision>& tn)
181  {
182  my_rotation.fromMatrixUnsafe(tn.get_rotation());
183  my_translation=*(Vec3*)&tn.get_translation();
184  }
185 #endif
186 
187 #ifdef SOPHUS_SE3_HPP
188  operator Sophus::SE3Group<Precision>()
189  {
190  assert(sizeof(Sophus::SE3Group<Precision>) != sizeof(*this));
191 // return *(Sophus::SE3Group<Precision>*)&my_rotation;// FIXME: segment fault occurs
192 
193  Sophus::SE3Group<Precision> sophusSE3;
194  for(int i=0;i<7;i++) sophusSE3.data()[i]=((double*)this)[i];
195  return sophusSE3;
196  }
197 
198  SE3_<Precision>(const Sophus::SE3Group<Precision>& sophus)
199  : my_rotation(sophus.so3()),
200  my_translation(*(Vec3*)&sophus.translation())
201  {
202  }
203 #endif
204 
205  inline Vector<Precision,6> log()const
206  {
207  Vector<Precision,6> result;
208  const auto& l=my_rotation;
209  const auto& t=my_translation;
210  const Precision squared_w = l.w*l.w;
211  const Precision n = sqrt(l.x*l.x+l.y*l.y+l.z*l.z);
212 
213  Precision A_inv;
214  // Atan-based log thanks to
215  //
216  // C. Hertzberg et al.:
217  // "Integrating Generic Sensor Fusion Algorithms with Sound State
218  // Representation through Encapsulation of Manifolds"
219  // Information Fusion, 2011
220 
221  if (n < NEAR_ZERO)
222  {
223  //If n is too small
224  A_inv = 2./l.w - 2.*(1.0-squared_w)/(l.w*squared_w);
225  Point3_<Precision> r(l.x*A_inv,l.y*A_inv,l.z*A_inv);
226  Point3_<Precision> p=t-0.5*r.cross(t)+static_cast<Precision>(1. / 12.)*r.cross(r.cross(t));
227  result.set(Vector3<Precision>(p.x,p.y,p.z),0,0);
228  result.set(Vector3<Precision>(r.x,r.y,r.z),3,0);
229  }
230  else
231  {
232  if (fabs(l.w)<NEAR_ZERO)
233  {
234  //If w is too small
235  if (l.w>0)
236  {
237  A_inv = M_PI/n;
238  }
239  else
240  {
241  A_inv = -M_PI/n;
242  }
243  }
244  else
245  A_inv = 2*atan(n/l.w)/n;
246 
247  auto theta=A_inv*n;
248  Point3_<Precision> r(l.x*A_inv,l.y*A_inv,l.z*A_inv);
249  Point3_<Precision> a=r/theta;
250  Point3_<Precision> p=t-0.5*r.cross(t)+(1-theta/(2*tan(0.5*theta)))*a.cross(a.cross(t));
251  result.set(Vector3<Precision>(p.x,p.y,p.z),0,0);
252  result.set(Vector3<Precision>(r.x,r.y,r.z),3,0);
253  }
254  return result;
255  }
256 
257  template <typename Scalar>
258  static inline SE3_<Scalar> exp(const Vector<Scalar,6>& l)
259  {
260  Point3_<Scalar> p(l[0],l[1],l[2]);
261  Point3_<Scalar> r(l[3],l[4],l[5]);
262  Scalar theta_sq = r.dot(r);
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 = sin(half_theta);
279  imag_factor = sin_half_theta / theta;
280  real_factor = cos(half_theta);
281  }
282 
283  SO3_<Scalar> R( imag_factor * r.x, imag_factor * r.y,imag_factor * r.z,real_factor);
284  auto t= p+(1-cos(theta))/theta_sq*r.cross(p)+
285  (theta-sin(theta))/(theta_sq*theta)*r.cross(r.cross(p));
286  return SE3_<Scalar>(R,t);
287  }
288 
289  template <typename Scalar>
290  static inline SE3_<Scalar> expFast(const Vector<Scalar,6>& l)
291  {
292  Point3_<Scalar> p(l[0],l[1],l[2]);
293  Point3_<Scalar> r(l[3],l[4],l[5]);
294  Scalar theta_sq = r.dot(r);
295  Scalar theta = sqrt(theta_sq);
296  Scalar half_theta = static_cast<Scalar>(0.5) * theta;
297 
298  Scalar imag_factor;
299  Scalar real_factor;
300 
301  if (theta < static_cast<Scalar>(1e-10)) {
302  Scalar theta_po4 = theta_sq * theta_sq;
303  imag_factor = static_cast<Scalar>(0.5) -
304  static_cast<Scalar>(1.0 / 48.0) * theta_sq +
305  static_cast<Scalar>(1.0 / 3840.0) * theta_po4;
306  real_factor = static_cast<Scalar>(1) -
307  static_cast<Scalar>(0.5) * theta_sq +
308  static_cast<Scalar>(1.0 / 384.0) * theta_po4;
309  } else {
310  Scalar sin_half_theta = SO3_<Scalar>::sine(half_theta);
311  imag_factor = sin_half_theta / theta;
312  real_factor = SO3_<Scalar>::cosine(half_theta);
313  }
314 
315  SO3_<Scalar> R( imag_factor * r.x, imag_factor * r.y,imag_factor * r.z,real_factor);
316  auto t= p+(1-SO3_<Scalar>::cosine(theta))/theta_sq*r.cross(p)+
317  (theta-SO3_<Scalar>::sine(theta))/(theta_sq*theta)*r.cross(r.cross(p));
318  return SE3_<Scalar>(R,t);
319  }
320 
321  Vector<Precision,6> ln()const
322  {
323  return log();
324  }
325 
326  SO3_<Precision> getRotation()const{return get_rotation();}
327  Point3_<Precision> getTranslation()const{return get_translation();}
328 
329  void setRotation(SO3_<Precision> R){my_rotation=R;}
330  void setTranslation(Point3_<Precision> t){my_translation=t;}
331 
332  SE3_ mul (const SE3_& rq) const{return (*this)*rq;}
333  Point3_<Precision> trans(const Point3_<Precision>& p) const{return (*this)*p;}
334 
335  std::string toString()const{std::stringstream sst;sst<<*this;return sst.str();}
336 
337 protected:
338  SO3_<Precision> my_rotation;
339  Vec3 my_translation;
340 };
341 
342 typedef SE3_<double> SE3d;
343 typedef SE3_<float > SE3f;
344 typedef SE3d SE3;
345 
346 }
347 #endif
friend Vec3 operator*(const SE3_< Precision > &lhs, const Vec3 &rhs)
Right-multiply by a Vector.
Definition: SE3.h:129
Definition: Matrix.h:697
const Vec3 & get_translation() const
Definition: SE3.h:98
Definition: Point.h:162
3D rotation represented by the quaternion.
Definition: SO3.h:131
Definition: Camera.h:45
friend std::ostream & operator<<(std::ostream &os, const SE3_ &rhs)
Write an SE3 to a stream.
Definition: SE3.h:135
Vec3 & get_translation()
Returns the translation part of the transformation as a Vector.
Definition: SE3.h:96
const SO3_< Precision > & get_rotation() const
Definition: SE3.h:93
friend std::istream & operator>>(std::istream &is, SE3_ &rhs)
Write an SE3 from a stream.
Definition: SE3.h:142
void fromMatrix(const Precision *m)
R is described as follow, M is a 4*4 Homography matrix |r0 r1 r2| |r3 r4 r5| |r6 r7 r8|...
Definition: SE3.h:154
SE3_ & operator*=(const SE3_< P > &rhs)
Right-multiply by another SE3 (concatenate the two transformations)
Definition: SE3.h:108
SO3_< Precision > & get_rotation()
Returns the rotation part of the transformation as a SO3.
Definition: SE3.h:91
Represent a three-dimensional Euclidean transformation (a rotation and a translation).
Definition: SE3.h:69
Definition: Matrix.h:548