vgl_rotation_3d.h
Go to the documentation of this file.
1 // This is core/vgl/algo/vgl_rotation_3d.h
2 #ifndef vgl_rotation_3d_h_
3 #define vgl_rotation_3d_h_
4 //:
5 // \file
6 // \brief A class representing a 3d rotation.
7 // \author Thomas Pollard
8 // \date 2005-03-13
9 //
10 // This is a class for storing and doing conversions with 3d rotation transforms
11 // specified by any of the following parameters: quaternions, Euler angles,
12 // Rodrigues vector, an orthonormal 3x3 matrix (with determinant = 1), or a
13 // vgl_h_matrix of proper form.
14 //
15 // \verbatim
16 // Modifications
17 // M. J. Leotta 2007-03-14 Moved from VPGL and implemented member functions
18 // Peter Vanroose 2009-06-11 Robustified the 2-vector constructors: input no longer needs to be unit-norm
19 // Peter Vanroose 2010-10-24 mutators and setters now return *this
20 // \endverbatim
21 
22 #include <cmath>
23 #include <vector>
24 #include <iostream>
25 #include <vnl/vnl_vector_fixed.h>
26 #include <vnl/vnl_matrix_fixed.h>
27 #include <vnl/vnl_quaternion.h>
28 #include <vnl/vnl_cross.h>
29 #include <vnl/vnl_math.h>
30 #include <vgl/vgl_fwd.h>
31 #include <vgl/vgl_point_3d.h>
32 #include <vgl/vgl_homg_point_3d.h>
34 #include <vgl/vgl_tolerance.h>
35 #ifdef _MSC_VER
36 # include <vcl_msvc_warnings.h>
37 #endif
38 
39 template <class T>
40 class vgl_rotation_3d
41 {
42  public:
43  // Constructors:-------------------------------------
44 
45  //: Construct the identity rotation
46  vgl_rotation_3d() : q_(0,0,0,1) {}
47 
48  //: Construct from a quaternion.
49  vgl_rotation_3d( vnl_quaternion<T> const& q ) : q_(q) { q_.normalize(); }
50 
51  //: Construct from Euler angles.
52  vgl_rotation_3d( T const& rx, T const& ry, T const& rz ) : q_(rx,ry,rz) {}
53 
54  //: Construct from a Rodrigues vector.
55  explicit vgl_rotation_3d( vnl_vector_fixed<T,3> const& rvector )
56  {
57  T mag = rvector.magnitude();
58  if (mag > T(0))
59  q_ = vnl_quaternion<T>(rvector/mag,mag);
60  else // identity rotation is a special case
61  q_ = vnl_quaternion<T>(0,0,0,1);
62  }
63 
64  //: Construct from a Rodrigues vector.
65  vgl_rotation_3d& operator=( vnl_vector_fixed<T,3> const& rvector )
66  {
67  T mag = rvector.magnitude();
68  if (mag > T(0))
69  q_ = vnl_quaternion<T>(rvector/mag,mag);
70  else // identity rotation is a special case
71  q_ = vnl_quaternion<T>(0,0,0,1);
72  return *this;
73  }
74 
75  //: Construct from a 3x3 rotation matrix
76  explicit vgl_rotation_3d( vnl_matrix_fixed<T,3,3> const& matrix )
77  : q_(matrix.transpose()) {}
78 
79  //: Construct from a 3x3 rotation matrix
80  vgl_rotation_3d& operator=( vnl_matrix_fixed<T,3,3> const& matrix )
81  { q_ = matrix.transpose(); return *this; }
82 
83  //: Construct from a vgl_h_matrix_3d.
84  explicit vgl_rotation_3d( vgl_h_matrix_3d<T> const& h )
85  : q_(h.get_upper_3x3_matrix().transpose()) { assert(h.is_rotation()); }
86 
87  //: Construct from a vgl_h_matrix_3d.
89  { assert(h.is_rotation()); q_ = h.get_upper_3x3_matrix().transpose(); return *this; }
90 
91  //: Construct to rotate (direction of) vector a to vector b
92  // The input vectors need not be of unit length
93  vgl_rotation_3d(vnl_vector_fixed<T,3> const& a,
94  vnl_vector_fixed<T,3> const& b)
95  {
96  vnl_vector_fixed<T,3> c = vnl_cross_3d(a, b);
97  double aa = 0.0; if (dot_product(a, b) < 0) { aa = vnl_math::pi; c=-c; }
98  double cmag = static_cast<double>(c.magnitude())
99  / static_cast<double>(a.magnitude())
100  / static_cast<double>(b.magnitude());
101  // cross product of unit vectors is at most a unit vector:
102  if (cmag>1.0) cmag=1.0;
103  // if the vectors have the same direction, then set to identity rotation:
105  {
106  if (aa!=vnl_math::pi) {
107  q_ = vnl_quaternion<T>(0, 0, 0, 1);
108  return;
109  }
110  else { // rotation axis not defined for rotation of pi
111  // construct a vector v along the min component axis of a
112  double ax = std::fabs(static_cast<double>(a[0]));
113  double ay = std::fabs(static_cast<double>(a[1]));
114  double az = std::fabs(static_cast<double>(a[2]));
115  vnl_vector_fixed<T,3> v(T(0));
116  double amin = ax; v[0]=T(1);
117  if (ay<amin) { amin = ay; v[0]=T(0); v[1]=T(1); }
118  if (az<amin) { v[0]=T(0); v[1]=T(0); v[2]=T(1); }
119  // define the pi rotation axis perpendicular to both v and a
120  vnl_vector_fixed<T,3> pi_axis = vnl_cross_3d(v, a);
121  q_ = vnl_quaternion<T>(pi_axis/pi_axis.magnitude(), aa);
122  return;
123  }
124  }
125  double angl = std::asin(cmag)+aa;
126  q_ = vnl_quaternion<T>(c/c.magnitude(), angl);
127  }
128 
129  //: Construct to rotate (direction of) vector a to vector b
130  // The input vectors need not be of unit length
132  vgl_vector_3d<T> const& b)
133  {
134  vnl_vector_fixed<T,3> na(a.x(), a.y(), a.z());
135  vnl_vector_fixed<T,3> nb(b.x(), b.y(), b.z());
136  *this = vgl_rotation_3d<T>(na, nb);
137  }
138 
139  // Conversions:--------------------------------------
140 
141  //: Output unit quaternion.
142  vnl_quaternion<T> as_quaternion() const
143  {
144  return q_;
145  }
146 
147  //: Output Euler angles.
148  // The first element is the rotation about the x-axis
149  // The second element is the rotation about the y-axis
150  // The third element is the rotation about the z-axis
151  // The total rotation is a composition of these rotations in this order
152  vnl_vector_fixed<T,3> as_euler_angles() const
153  {
154  return q_.rotation_euler_angles();
155  }
156 
157  //: Output Rodrigues vector.
158  // The direction of this vector is the axis of rotation
159  // The length of this vector is the angle of rotation in radians
160  vnl_vector_fixed<T,3> as_rodrigues() const
161  {
162  double ang = q_.angle();
163  if (ang == 0.0)
164  return vnl_vector_fixed<T,3>(T(0));
165  return q_.axis()*T(ang);
166  }
167 
168  //: Output the matrix representation of this rotation in 3x3 form.
169  vnl_matrix_fixed<T,3,3> as_matrix() const
170  {
171  return q_.rotation_matrix_transpose().transpose();
172  }
173 
174  //: Output the matrix representation of this rotation in 4x4 form.
176  {
177  return vgl_h_matrix_3d<T>(q_.rotation_matrix_transpose_4().transpose());
178  }
179 
180  //: Returns the axis of rotation (unit vector)
181  vnl_vector_fixed<T,3> axis() const { return q_.axis(); }
182 
183  //: Returns the angle of rotation on the range [ 0 360 ] in radians
184  double angle() const { return q_.angle(); }
185 
186  // Operations:----------------------------------------
187 
188  //: Make the rotation the identity (i.e. no rotation)
189  vgl_rotation_3d& set_identity() { q_[0]=0; q_[1]=0; q_[2]=0; q_[3]=1; return *this; }
190 
191  //: The inverse rotation
192  vgl_rotation_3d<T> inverse() const { return vgl_rotation_3d<T>(q_.conjugate()); }
193 
194  //: The transpose or conjugate of the rotation
195  vgl_rotation_3d<T> transpose() const { return this->inverse(); }
196 
197  //: Composition of two rotations.
198  vgl_rotation_3d<T> operator*( vgl_rotation_3d<T> const& first_rotation ) const
199  {
200  return vgl_rotation_3d<T>( q_*first_rotation.q_ );
201  }
202 
203  //: Rotate a homogeneous point.
205  {
206  vnl_vector_fixed<T,3> rp = q_.rotate(vnl_vector_fixed<T,3>(p.x(),p.y(),p.z()));
207  return vgl_homg_point_3d<T>(rp[0],rp[1],rp[2],p.w());
208  }
209 
210  //: Rotate a homogeneous plane.
212  {
213  vnl_vector_fixed<T,3> rp = q_.rotate(vnl_vector_fixed<T,3>(p.a(),p.b(),p.c()));
214  return vgl_homg_plane_3d<T>(rp[0],rp[1],rp[2],p.d());
215  }
216 
217  //: Rotate a homogeneous line.
219  {
220  return vgl_homg_line_3d_2_points<T>(this->operator*(l.point_finite()),
221  this->operator*(l.point_infinite()));
222  }
223 
224  //: Rotate a point.
226  {
227  vnl_vector_fixed<T,3> rp = q_.rotate(vnl_vector_fixed<T,3>(p.x(),p.y(),p.z()));
228  return vgl_point_3d<T>(rp[0],rp[1],rp[2]);
229  }
230 
231  //: Rotate a plane.
233  {
234  vnl_vector_fixed<T,3> rp = q_.rotate(vnl_vector_fixed<T,3>(p.a(),p.b(),p.c()));
235  return vgl_plane_3d<T>(rp[0],rp[1],rp[2],p.d());
236  }
237 
238  //: Rotate a line.
240  {
241  return vgl_line_3d_2_points<T>(this->operator*(l.point1()),
242  this->operator*(l.point2()));
243  }
244 
245  //: Rotate a line segment.
247  {
248  return vgl_line_segment_3d<T>(this->operator*(l.point1()),
249  this->operator*(l.point2()));
250  }
251 
252  //: Rotate a vgl vector.
254  {
255  vnl_vector_fixed<T,3> rv = q_.rotate(vnl_vector_fixed<T,3>(v.x(),v.y(),v.z()));
256  return vgl_vector_3d<T>(rv[0],rv[1],rv[2]);
257  }
258 
259  //: Rotate a vnl vector.
260  vnl_vector_fixed<T, 3> operator*( vnl_vector_fixed<T,3> const& v ) const
261  {
262  return q_.rotate(v);
263  }
264 
265  //: comparison operator
266  bool operator==(vgl_rotation_3d<T> const& r) const { return q_ == r.as_quaternion(); }
267 
268  protected:
269  //: The internal representation of the rotation is a quaternion.
270  vnl_quaternion<T> q_;
271 };
272 
273 
274 // External methods for stream I/O
275 // ----------------------------------------------------------------
276 
277 template <class T>
278 std::istream& operator>>(std::istream& s, vgl_rotation_3d<T> &R)
279 {
280  vnl_quaternion<T> q;
281  s >> q;
282  R = vgl_rotation_3d<T>(q);
283  return s;
284 }
285 
286 template <class T>
287 std::ostream& operator<<(std::ostream& s, vgl_rotation_3d<T> const& R)
288 {
289  return s << R.as_quaternion();
290 }
291 
292 // External methods for more efficient rotation of multiple objects
293 // ----------------------------------------------------------------
294 
295 //: In-place rotation of a vector of homogeneous points
296 // \note This is more efficient than calling vgl_rotation_3d::rotate() on each
297 template <class T> inline
298 void vgl_rotate_3d(vgl_rotation_3d<T> const& rot, std::vector<vgl_homg_point_3d<T> >& pts)
299 {
300  vnl_matrix_fixed<T,3,3> R = rot.as_3matrix();
301  for (typename std::vector<vgl_homg_point_3d<T> >::iterator itr = pts.begin();
302  itr != pts.end(); ++itr)
303  {
304  vgl_homg_point_3d<T>& p = *itr;
305  p.set(R[0][0]*p.x()+R[0][1]*p.y()+R[0][2]*p.z(),
306  R[1][0]*p.x()+R[1][1]*p.y()+R[1][2]*p.z(),
307  R[2][0]*p.x()+R[2][1]*p.y()+R[2][2]*p.z(), p.w());
308  }
309 }
310 
311 #endif // vgl_rotation_3d_h_
vgl_rotation_3d(vnl_vector_fixed< T, 3 > const &a, vnl_vector_fixed< T, 3 > const &b)
Construct to rotate (direction of) vector a to vector b.
vgl_rotation_3d(vnl_vector_fixed< T, 3 > const &rvector)
Construct from a Rodrigues vector.
point in projective 3D space
vnl_matrix_fixed< T, 3, 3 > as_matrix() const
Output the matrix representation of this rotation in 3x3 form.
vgl_point_3d< Type > point1() const
vgl_rotation_3d & operator=(vgl_h_matrix_3d< T > const &h)
Construct from a vgl_h_matrix_3d.
vgl_rotation_3d(vnl_quaternion< T > const &q)
Construct from a quaternion.
bool operator==(vgl_rotation_3d< T > const &r) const
comparison operator.
T a() const
Return x coefficient.
Definition: vgl_plane_3d.h:89
vgl_point_3d< Type > point2() const
vnl_quaternion< T > q_
The internal representation of the rotation is a quaternion.
Type b() const
Return y coefficient.
Type c() const
Return z coefficient.
double angle() const
Returns the angle of rotation on the range [ 0 360 ] in radians.
vgl_rotation_3d< T > inverse() const
The inverse rotation.
vnl_vector_fixed< T, 3 > as_rodrigues() const
Output Rodrigues vector.
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
Type d() const
Return homogeneous scaling coefficient.
Represents a homogeneous 3D point.
Definition: vgl_fwd.h:9
vnl_quaternion< T > as_quaternion() const
Output unit quaternion.
vgl_rotation_3d & operator=(vnl_vector_fixed< T, 3 > const &rvector)
Construct from a Rodrigues vector.
vgl_rotation_3d(vgl_vector_3d< T > const &a, vgl_vector_3d< T > const &b)
Construct to rotate (direction of) vector a to vector b.
Type & z()
Definition: vgl_point_3d.h:73
A class to hold a non-homogeneous representation of a 3D line.
Definition: vgl_fwd.h:17
#define v
Definition: vgl_vector_2d.h:74
vnl_matrix_fixed< T, 3, 3 > get_upper_3x3_matrix() const
T b() const
Return y coefficient.
Definition: vgl_plane_3d.h:92
a point in 3D nonhomogeneous space
T y() const
Definition: vgl_vector_3d.h:37
A class to hold a 3-d projective transformation matrix and to perform common operations using it e....
Definition: vgl_algo_fwd.h:12
vgl_point_3d< Type > point1() const
Return the first point representing this line.
Represents a Euclidean 3D plane.
Definition: vgl_fwd.h:23
vgl_rotation_3d(vnl_matrix_fixed< T, 3, 3 > const &matrix)
Construct from a 3x3 rotation matrix.
Represents a 3D line segment using two points.
Definition: vgl_fwd.h:19
T x() const
Definition: vgl_vector_3d.h:36
vgl_rotation_3d()
Construct the identity rotation.
T d() const
Return constant coefficient.
Definition: vgl_plane_3d.h:98
T z() const
Definition: vgl_vector_3d.h:38
Type a() const
Return x coefficient.
Type & x()
Definition: vgl_point_3d.h:71
vgl_h_matrix_3d< T > as_h_matrix_3d() const
Output the matrix representation of this rotation in 4x4 form.
vgl_rotation_3d< T > operator *(vgl_rotation_3d< T > const &first_rotation) const
Composition of two rotations.
Direction vector in Euclidean 3D space, templated by type of element.
Definition: vgl_fwd.h:13
void vgl_rotate_3d(vgl_rotation_3d< T > const &rot, std::vector< vgl_homg_point_3d< T > > &pts)
In-place rotation of a vector of homogeneous points.
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
void set(Type px, Type py, Type pz, Type pw=(Type) 1)
Set x,y,z,w.
vgl_rotation_3d & operator=(vnl_matrix_fixed< T, 3, 3 > const &matrix)
Construct from a 3x3 rotation matrix.
vgl_rotation_3d(T const &rx, T const &ry, T const &rz)
Construct from Euler angles.
#define l
T dot_product(v const &a, v const &b)
dot product or inner product of two vectors.
vgl_point_3d< Type > point2() const
Return the second point representing this line.
vgl_rotation_3d(vgl_h_matrix_3d< T > const &h)
Construct from a vgl_h_matrix_3d.
vgl_rotation_3d & set_identity()
Make the rotation the identity (i.e. no rotation).
bool is_rotation() const
vgl_rotation_3d< T > transpose() const
The transpose or conjugate of the rotation.
4x4 3D-to-3D projectivity
vnl_vector_fixed< T, 3 > as_euler_angles() const
Output Euler angles.
vgl_homg_point_3d< Type > point_finite() const
Finite point (Could be an ideal point, if the whole line is at infinity.).
vnl_vector_fixed< T, 3 > axis() const
Returns the axis of rotation (unit vector).
T c() const
Return z coefficient.
Definition: vgl_plane_3d.h:95
Type & y()
Definition: vgl_point_3d.h:72
vgl_homg_point_3d< Type > point_infinite() const
Infinite point: the intersection of the line with the plane at infinity.
Represents a homogeneous 3D line using two points.
Definition: vgl_fwd.h:15