TooN
so3.h
1 // -*- c++ -*-
2 
3 // Copyright (C) 2005,2009 Tom Drummond (twd20@cam.ac.uk)
4 
5 //All rights reserved.
6 //
7 //Redistribution and use in source and binary forms, with or without
8 //modification, are permitted provided that the following conditions
9 //are met:
10 //1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 //THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 //AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 //IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 //ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 //LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 //CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 //SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 //INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 //CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 //ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 //POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef TOON_INCLUDE_SO3_H
29 #define TOON_INCLUDE_SO3_H
30 
31 #include <TooN/TooN.h>
32 #include <TooN/helpers.h>
33 #include <cassert>
34 
35 namespace TooN {
36 
37 template <typename Precision> class SO3;
38 template <typename Precision> class SE3;
39 template <typename Precision> class SIM3;
40 
41 template<class Precision> inline std::istream & operator>>(std::istream &, SO3<Precision> & );
42 template<class Precision> inline std::istream & operator>>(std::istream &, SE3<Precision> & );
43 template<class Precision> inline std::istream & operator>>(std::istream &, SIM3<Precision> & );
44 
52 template <typename Precision = DefaultPrecision>
53 class SO3 {
54 public:
55  friend std::istream& operator>> <Precision> (std::istream& is, SO3<Precision> & rhs);
56  friend std::istream& operator>> <Precision> (std::istream& is, SE3<Precision> & rhs);
57  friend std::istream& operator>> <Precision> (std::istream& is, SIM3<Precision> & rhs);
58  friend class SE3<Precision>;
59  friend class SIM3<Precision>;
60 
62  SO3() : my_matrix(Identity) {}
63 
65  template <int S, typename P, typename A>
66  SO3(const Vector<S, P, A> & v) { *this = exp(v); }
67 
69  template <int R, int C, typename P, typename A>
70  SO3(const Matrix<R,C,P,A>& rhs) { *this = rhs; }
71 
77  template <int S1, int S2, typename P1, typename P2, typename A1, typename A2>
78  SO3(const Vector<S1, P1, A1> & a, const Vector<S2, P2, A2> & b ){
79  SizeMismatch<3,S1>::test(3, a.size());
80  SizeMismatch<3,S2>::test(3, b.size());
81  Vector<3, Precision> n = a ^ b;
82  if(norm_sq(n) == 0) {
83  //check that the vectors are in the same direction if cross product is 0. If not,
84  //this means that the rotation is 180 degrees, which leads to an ambiguity in the rotation axis.
85  assert(a*b>=0);
86  my_matrix = Identity;
87  return;
88  }
89  n = unit(n);
90  Matrix<3> R1;
91  R1.T()[0] = unit(a);
92  R1.T()[1] = n;
93  R1.T()[2] = R1.T()[0] ^ n;
94  my_matrix.T()[0] = unit(b);
95  my_matrix.T()[1] = n;
96  my_matrix.T()[2] = my_matrix.T()[0] ^ n;
97  my_matrix = my_matrix * R1.T();
98  }
99 
102  template <int R, int C, typename P, typename A>
103  SO3& operator=(const Matrix<R,C,P,A> & rhs) {
104  my_matrix = rhs;
105  coerce();
106  return *this;
107  }
108 
110  void coerce() {
111  my_matrix[0] = unit(my_matrix[0]);
112  my_matrix[1] -= my_matrix[0] * (my_matrix[0]*my_matrix[1]);
113  my_matrix[1] = unit(my_matrix[1]);
114  my_matrix[2] -= my_matrix[0] * (my_matrix[0]*my_matrix[2]);
115  my_matrix[2] -= my_matrix[1] * (my_matrix[1]*my_matrix[2]);
116  my_matrix[2] = unit(my_matrix[2]);
117  // check for positive determinant <=> right handed coordinate system of row vectors
118  assert( (my_matrix[0] ^ my_matrix[1]) * my_matrix[2] > 0 );
119  }
120 
123  template<int S, typename VP, typename A> inline static SO3 exp(const Vector<S,VP,A>& vect);
124 
127  inline Vector<3, Precision> ln() const;
128 
130  SO3 inverse() const { return SO3(*this, Invert()); }
131 
133  template <typename P>
134  SO3& operator *=(const SO3<P>& rhs) {
135  *this = *this * rhs;
136  return *this;
137  }
138 
140  template<typename P>
143  }
144 
146  const Matrix<3,3, Precision> & get_matrix() const {return my_matrix;}
147 
152  inline static Matrix<3,3, Precision> generator(int i){
153  Matrix<3,3,Precision> result(Zeros);
154  result[(i+1)%3][(i+2)%3] = -1;
155  result[(i+2)%3][(i+1)%3] = 1;
156  return result;
157  }
158 
160  template<typename Base>
162  {
163  Vector<3, Precision> result;
164  result[i]=0;
165  result[(i+1)%3] = - pos[(i+2)%3];
166  result[(i+2)%3] = pos[(i+1)%3];
167  return result;
168  }
169 
174  template <int S, typename A>
176  {
177  SizeMismatch<3, S>::test(3, vect.size());
178  return *this * vect;
179  }
180 
181  template <typename PA, typename PB>
182  inline SO3(const SO3<PA>& a, const SO3<PB>& b) : my_matrix(a.get_matrix()*b.get_matrix()) {}
183 
184 private:
185  struct Invert {};
186  inline SO3(const SO3& so3, const Invert&) : my_matrix(so3.my_matrix.T()) {}
187 
188  Matrix<3,3, Precision> my_matrix;
189 };
190 
193 template <typename Precision>
194 inline std::ostream& operator<< (std::ostream& os, const SO3<Precision>& rhs){
195  return os << rhs.get_matrix();
196 }
197 
200 template <typename Precision>
201 inline std::istream& operator>>(std::istream& is, SO3<Precision>& rhs){
202  is >> rhs.my_matrix;
203  rhs.coerce();
204  return is;
205 }
206 
218 template <typename Precision, int S, typename VP, typename VA, typename MA>
219 inline void rodrigues_so3_exp(const Vector<S,VP, VA>& w, const Precision A, const Precision B, Matrix<3,3,Precision,MA>& R){
220  SizeMismatch<3,S>::test(3, w.size());
221  {
222  const Precision wx2 = (Precision)w[0]*w[0];
223  const Precision wy2 = (Precision)w[1]*w[1];
224  const Precision wz2 = (Precision)w[2]*w[2];
225 
226  R[0][0] = 1.0 - B*(wy2 + wz2);
227  R[1][1] = 1.0 - B*(wx2 + wz2);
228  R[2][2] = 1.0 - B*(wx2 + wy2);
229  }
230  {
231  const Precision a = A*w[2];
232  const Precision b = B*(w[0]*w[1]);
233  R[0][1] = b - a;
234  R[1][0] = b + a;
235  }
236  {
237  const Precision a = A*w[1];
238  const Precision b = B*(w[0]*w[2]);
239  R[0][2] = b + a;
240  R[2][0] = b - a;
241  }
242  {
243  const Precision a = A*w[0];
244  const Precision b = B*(w[1]*w[2]);
245  R[1][2] = b - a;
246  R[2][1] = b + a;
247  }
248 }
249 
252 template <typename Precision>
253 template<int S, typename VP, typename VA>
255  using std::sqrt;
256  using std::sin;
257  using std::cos;
258  SizeMismatch<3,S>::test(3, w.size());
259 
260  static const Precision one_6th = 1.0/6.0;
261  static const Precision one_20th = 1.0/20.0;
262 
263  SO3<Precision> result;
264 
265  const Precision theta_sq = w*w;
266  const Precision theta = sqrt(theta_sq);
267  Precision A, B;
268  //Use a Taylor series expansion near zero. This is required for
269  //accuracy, since sin t / t and (1-cos t)/t^2 are both 0/0.
270  if (theta_sq < 1e-8) {
271  A = 1.0 - one_6th * theta_sq;
272  B = 0.5;
273  } else {
274  if (theta_sq < 1e-6) {
275  B = 0.5 - 0.25 * one_6th * theta_sq;
276  A = 1.0 - theta_sq * one_6th*(1.0 - one_20th * theta_sq);
277  } else {
278  const Precision inv_theta = 1.0/theta;
279  A = sin(theta) * inv_theta;
280  B = (1 - cos(theta)) * (inv_theta * inv_theta);
281  }
282  }
283  rodrigues_so3_exp(w, A, B, result.my_matrix);
284  return result;
285 }
286 
287 template <typename Precision>
289  using std::sqrt;
290  Vector<3, Precision> result;
291 
292  const Precision cos_angle = (my_matrix[0][0] + my_matrix[1][1] + my_matrix[2][2] - 1.0) * 0.5;
293  result[0] = (my_matrix[2][1]-my_matrix[1][2])/2;
294  result[1] = (my_matrix[0][2]-my_matrix[2][0])/2;
295  result[2] = (my_matrix[1][0]-my_matrix[0][1])/2;
296 
297  Precision sin_angle_abs = sqrt(result*result);
298  if (cos_angle > M_SQRT1_2) { // [0 - Pi/4[ use asin
299  if(sin_angle_abs > 0){
300  result *= asin(sin_angle_abs) / sin_angle_abs;
301  }
302  } else if( cos_angle > -M_SQRT1_2) { // [Pi/4 - 3Pi/4[ use acos, but antisymmetric part
303  const Precision angle = acos(cos_angle);
304  result *= angle / sin_angle_abs;
305  } else { // rest use symmetric part
306  // antisymmetric part vanishes, but still large rotation, need information from symmetric part
307  const Precision angle = M_PI - asin(sin_angle_abs);
308  const Precision d0 = my_matrix[0][0] - cos_angle,
309  d1 = my_matrix[1][1] - cos_angle,
310  d2 = my_matrix[2][2] - cos_angle;
312  if(d0*d0 > d1*d1 && d0*d0 > d2*d2){ // first is largest, fill with first column
313  r2[0] = d0;
314  r2[1] = (my_matrix[1][0]+my_matrix[0][1])/2;
315  r2[2] = (my_matrix[0][2]+my_matrix[2][0])/2;
316  } else if(d1*d1 > d2*d2) { // second is largest, fill with second column
317  r2[0] = (my_matrix[1][0]+my_matrix[0][1])/2;
318  r2[1] = d1;
319  r2[2] = (my_matrix[2][1]+my_matrix[1][2])/2;
320  } else { // third is largest, fill with third column
321  r2[0] = (my_matrix[0][2]+my_matrix[2][0])/2;
322  r2[1] = (my_matrix[2][1]+my_matrix[1][2])/2;
323  r2[2] = d2;
324  }
325  // flip, if we point in the wrong direction!
326  if(r2 * result < 0)
327  r2 *= -1;
328  r2 = unit(r2);
329  result = TooN::operator*(angle,r2);
330  }
331  return result;
332 }
333 
336 template<int S, typename P, typename PV, typename A> inline
338  return lhs.get_matrix() * rhs;
339 }
340 
343 template<int S, typename P, typename PV, typename A> inline
345  return lhs * rhs.get_matrix();
346 }
347 
350 template<int R, int C, typename P, typename PM, typename A> inline
352  return lhs.get_matrix() * rhs;
353 }
354 
357 template<int R, int C, typename P, typename PM, typename A> inline
359  return lhs * rhs.get_matrix();
360 }
361 
362 #if 0 // will be moved to another header file ?
363 
364 template <class A> inline
365 Vector<3> transform(const SO3& pose, const FixedVector<3,A>& x) { return pose*x; }
366 
367 template <class A1, class A2> inline
368 Vector<3> transform(const SO3& pose, const FixedVector<3,A1>& x, FixedMatrix<3,3,A2>& J_x)
369 {
370  J_x = pose.get_matrix();
371  return pose * x;
372 }
373 
374 template <class A1, class A2, class A3> inline
375 Vector<3> transform(const SO3& pose, const FixedVector<3,A1>& x, FixedMatrix<3,3,A2>& J_x, FixedMatrix<3,3,A3>& J_pose)
376 {
377  J_x = pose.get_matrix();
378  const Vector<3> cx = pose * x;
379  J_pose[0][0] = J_pose[1][1] = J_pose[2][2] = 0;
380  J_pose[1][0] = -(J_pose[0][1] = cx[2]);
381  J_pose[0][2] = -(J_pose[2][0] = cx[1]);
382  J_pose[2][1] = -(J_pose[1][2] = cx[0]);
383  return cx;
384 }
385 
386 template <class A1, class A2, class A3> inline
387 Vector<2> project_transformed_point(const SO3& pose, const FixedVector<3,A1>& in_frame, FixedMatrix<2,3,A2>& J_x, FixedMatrix<2,3,A3>& J_pose)
388 {
389  const double z_inv = 1.0/in_frame[2];
390  const double x_z_inv = in_frame[0]*z_inv;
391  const double y_z_inv = in_frame[1]*z_inv;
392  const double cross = x_z_inv * y_z_inv;
393  J_pose[0][0] = -cross;
394  J_pose[0][1] = 1 + x_z_inv*x_z_inv;
395  J_pose[0][2] = -y_z_inv;
396  J_pose[1][0] = -1 - y_z_inv*y_z_inv;
397  J_pose[1][1] = cross;
398  J_pose[1][2] = x_z_inv;
399 
400  const TooN::Matrix<3>& R = pose.get_matrix();
401  J_x[0][0] = z_inv*(R[0][0] - x_z_inv * R[2][0]);
402  J_x[0][1] = z_inv*(R[0][1] - x_z_inv * R[2][1]);
403  J_x[0][2] = z_inv*(R[0][2] - x_z_inv * R[2][2]);
404  J_x[1][0] = z_inv*(R[1][0] - y_z_inv * R[2][0]);
405  J_x[1][1] = z_inv*(R[1][1] - y_z_inv * R[2][1]);
406  J_x[1][2] = z_inv*(R[1][2] - y_z_inv * R[2][2]);
407 
408  return makeVector(x_z_inv, y_z_inv);
409 }
410 
411 
412 template <class A1> inline
413 Vector<2> transform_and_project(const SO3& pose, const FixedVector<3,A1>& x)
414 {
415  return project(transform(pose,x));
416 }
417 
418 template <class A1, class A2, class A3> inline
419 Vector<2> transform_and_project(const SO3& pose, const FixedVector<3,A1>& x, FixedMatrix<2,3,A2>& J_x, FixedMatrix<2,3,A3>& J_pose)
420 {
421  return project_transformed_point(pose, transform(pose,x), J_x, J_pose);
422 }
423 
424 #endif
425 
426 }
427 
428 #endif
Vector< 3, Precision > ln() const
Take the logarithm of the matrix, generating the corresponding vector in the Lie Algebra.
Definition: so3.h:288
Vector< 3, typename Internal::MultiplyType< PV, P >::type > operator*(const Vector< S, PV, A > &lhs, const SO3< P > &rhs)
Left-multiply by a Vector.
Definition: so3.h:344
Represent a three-dimensional Euclidean transformation (a rotation and a translation).
Definition: se3.h:48
SO3 & operator*=(const SO3< P > &rhs)
Right-multiply by another rotation matrix.
Definition: so3.h:134
void rodrigues_so3_exp(const Vector< S, VP, VA > &w, const Precision A, const Precision B, Matrix< 3, 3, Precision, MA > &R)
Compute a rotation exponential using the Rodrigues Formula.
Definition: so3.h:219
SO3 & operator=(const Matrix< R, C, P, A > &rhs)
Assignment operator from a general matrix.
Definition: so3.h:103
Vector< 3, typename Internal::MultiplyType< P, PV >::type > operator*(const SO3< P > &lhs, const Vector< S, PV, A > &rhs)
Right-multiply by a Vector.
Definition: so3.h:337
Vector< 3, Precision > adjoint(const Vector< S, Precision, A > &vect) const
Transfer a vector in the Lie Algebra from one co-ordinate frame to another such that for a matrix ...
Definition: so3.h:175
SO3()
Default constructor. Initialises the matrix to the identity (no rotation)
Definition: so3.h:62
Vector<(Size==Dynamic?Dynamic:Size-1)+0, Precision > project(const Vector< Size, Precision, Base > &v)
For a vector v of length i, return .
Definition: helpers.h:182
static SO3 exp(const Vector< S, VP, A > &vect)
Exponentiate a vector in the Lie algebra to generate a new SO3.
Pretty generic SFINAE introspection generator.
Definition: vec_test.cc:21
std::istream & operator>>(std::istream &is, SO3< Precision > &rhs)
Read from SO3 to a stream.
Definition: so3.h:201
SO3 inverse() const
Returns the inverse of this matrix (=the transpose, so this is a fast operation)
Definition: so3.h:130
Precision norm_sq(const Vector< Size, Precision, Base > &v)
Compute the norm of v.
Definition: helpers.h:106
static Vector< 3, Precision > generator_field(int i, const Vector< 3, Precision, Base > &pos)
Returns the i-th generator times pos.
Definition: so3.h:161
static Matrix< 3, 3, Precision > generator(int i)
Returns the i-th generator.
Definition: so3.h:152
SO3< typename Internal::MultiplyType< Precision, P >::type > operator*(const SO3< P > &rhs) const
Right-multiply by another rotation matrix.
Definition: so3.h:141
Matrix< 3, C, typename Internal::MultiplyType< P, PM >::type > operator*(const SO3< P > &lhs, const Matrix< R, C, PM, A > &rhs)
Right-multiply by a matrix.
Definition: so3.h:351
Class to represent a three-dimensional rotation matrix.
Definition: so3.h:37
SO3(const Vector< S1, P1, A1 > &a, const Vector< S2, P2, A2 > &b)
creates an SO3 as a rotation that takes Vector a into the direction of Vector b with the rotation axi...
Definition: so3.h:78
Matrix< R, 3, typename Internal::MultiplyType< PM, P >::type > operator*(const Matrix< R, C, PM, A > &lhs, const SO3< P > &rhs)
Left-multiply by a matrix.
Definition: so3.h:358
Represent a three-dimensional similarity transformation (a rotation, a scale factor and a translation...
Definition: sim3.h:48
Matrix< R, C, P > sqrt(const Matrix< R, C, P, B > &m)
computes a matrix square root of a matrix m by the product form of the Denman and Beavers iteration a...
Definition: helpers.h:350
Definition: size_mismatch.hh:103
void coerce()
Modifies the matrix to make sure it is a valid rotation matrix.
Definition: so3.h:110
SO3(const Matrix< R, C, P, A > &rhs)
Construct from a rotation matrix.
Definition: so3.h:70
const Matrix< 3, 3, Precision > & get_matrix() const
Returns the SO3 as a Matrix<3>
Definition: so3.h:146
Vector< Size, Precision > unit(const Vector< Size, Precision, Base > &v)
Compute a the unit vector .
Definition: helpers.h:153
SO3(const Vector< S, P, A > &v)
Construct from the axis of rotation (and angle given by the magnitude).
Definition: so3.h:66