geo_transformations.cpp
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #include "main.h"
11 #include <Eigen/Geometry>
12 #include <Eigen/LU>
13 #include <Eigen/SVD>
14 
15 template<typename T>
17 {
18  return Matrix<T,2,1>(std::cos(a), std::sin(a));
19 }
20 
21 // This permits to workaround a bug in clang/llvm code generation.
22 template<typename T>
24 void dont_over_optimize(T& x) { volatile typename T::Scalar tmp = x(0); x(0) = tmp; }
25 
26 template<typename Scalar, int Mode, int Options> void non_projective_only()
27 {
28  /* this test covers the following files:
29  Cross.h Quaternion.h, Transform.cpp
30  */
32  typedef Quaternion<Scalar> Quaternionx;
33  typedef AngleAxis<Scalar> AngleAxisx;
34  typedef Transform<Scalar,3,Mode,Options> Transform3;
35  typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
36  typedef Translation<Scalar,3> Translation3;
37 
38  Vector3 v0 = Vector3::Random(),
39  v1 = Vector3::Random();
40 
41  Transform3 t0, t1, t2;
42 
43  Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
44 
45  Quaternionx q1, q2;
46 
47  q1 = AngleAxisx(a, v0.normalized());
48 
49  t0 = Transform3::Identity();
50  VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
51 
52  t0.linear() = q1.toRotationMatrix();
53 
54  v0 << 50, 2, 1;
55  t0.scale(v0);
56 
57  VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).template head<3>().norm(), v0.x());
58 
59  t0.setIdentity();
60  t1.setIdentity();
61  v1 << 1, 2, 3;
62  t0.linear() = q1.toRotationMatrix();
63  t0.pretranslate(v0);
64  t0.scale(v1);
65  t1.linear() = q1.conjugate().toRotationMatrix();
66  t1.prescale(v1.cwiseInverse());
67  t1.translate(-v0);
68 
69  VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
70 
71  t1.fromPositionOrientationScale(v0, q1, v1);
72  VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
73  VERIFY_IS_APPROX(t1*v1, t0*v1);
74 
75  // translation * vector
76  t0.setIdentity();
77  t0.translate(v0);
78  VERIFY_IS_APPROX((t0 * v1).template head<3>(), Translation3(v0) * v1);
79 
80  // AlignedScaling * vector
81  t0.setIdentity();
82  t0.scale(v0);
83  VERIFY_IS_APPROX((t0 * v1).template head<3>(), AlignedScaling3(v0) * v1);
84 }
85 
86 template<typename Scalar, int Mode, int Options> void transformations()
87 {
88  /* this test covers the following files:
89  Cross.h Quaternion.h, Transform.cpp
90  */
91  using std::cos;
92  using std::abs;
93  typedef Matrix<Scalar,3,3> Matrix3;
94  typedef Matrix<Scalar,4,4> Matrix4;
97  typedef Matrix<Scalar,4,1> Vector4;
98  typedef Quaternion<Scalar> Quaternionx;
99  typedef AngleAxis<Scalar> AngleAxisx;
100  typedef Transform<Scalar,2,Mode,Options> Transform2;
101  typedef Transform<Scalar,3,Mode,Options> Transform3;
102  typedef typename Transform3::MatrixType MatrixType;
103  typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
104  typedef Translation<Scalar,2> Translation2;
105  typedef Translation<Scalar,3> Translation3;
106 
107  Vector3 v0 = Vector3::Random(),
108  v1 = Vector3::Random();
109  Matrix3 matrot1, m;
110 
111  Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
112  Scalar s0 = internal::random<Scalar>(), s1 = internal::random<Scalar>();
113 
114  while(v0.norm() < test_precision<Scalar>()) v0 = Vector3::Random();
115  while(v1.norm() < test_precision<Scalar>()) v1 = Vector3::Random();
116 
117  VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
118  VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(EIGEN_PI), v0.unitOrthogonal()) * v0);
119  if(abs(cos(a)) > test_precision<Scalar>())
120  {
121  VERIFY_IS_APPROX(cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
122  }
123  m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
124  VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
125  VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
126 
127  Quaternionx q1, q2;
128  q1 = AngleAxisx(a, v0.normalized());
129  q2 = AngleAxisx(a, v1.normalized());
130 
131  // rotation matrix conversion
132  matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
133  * AngleAxisx(Scalar(0.2), Vector3::UnitY())
134  * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
135  VERIFY_IS_APPROX(matrot1 * v1,
136  AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
137  * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
138  * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
139 
140  // angle-axis conversion
141  AngleAxisx aa = AngleAxisx(q1);
142  VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
143 
144  // The following test is stable only if 2*angle != angle and v1 is not colinear with axis
145  if( (abs(aa.angle()) > test_precision<Scalar>()) && (abs(aa.axis().dot(v1.normalized()))<(Scalar(1)-Scalar(4)*test_precision<Scalar>())) )
146  {
147  VERIFY( !(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1) );
148  }
149 
150  aa.fromRotationMatrix(aa.toRotationMatrix());
151  VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
152  // The following test is stable only if 2*angle != angle and v1 is not colinear with axis
153  if( (abs(aa.angle()) > test_precision<Scalar>()) && (abs(aa.axis().dot(v1.normalized()))<(Scalar(1)-Scalar(4)*test_precision<Scalar>())) )
154  {
155  VERIFY( !(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1) );
156  }
157 
158  // AngleAxis
159  VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
160  Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
161 
162  AngleAxisx aa1;
163  m = q1.toRotationMatrix();
164  aa1 = m;
165  VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
166  Quaternionx(m).toRotationMatrix());
167 
168  // Transform
169  // TODO complete the tests !
170  a = 0;
171  while (abs(a)<Scalar(0.1))
172  a = internal::random<Scalar>(-Scalar(0.4)*Scalar(EIGEN_PI), Scalar(0.4)*Scalar(EIGEN_PI));
173  q1 = AngleAxisx(a, v0.normalized());
174  Transform3 t0, t1, t2;
175 
176  // first test setIdentity() and Identity()
177  t0.setIdentity();
178  VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
179  t0.matrix().setZero();
180  t0 = Transform3::Identity();
181  VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
182 
183  t0.setIdentity();
184  t1.setIdentity();
185  v1 << 1, 2, 3;
186  t0.linear() = q1.toRotationMatrix();
187  t0.pretranslate(v0);
188  t0.scale(v1);
189  t1.linear() = q1.conjugate().toRotationMatrix();
190  t1.prescale(v1.cwiseInverse());
191  t1.translate(-v0);
192 
193  VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
194 
195  t1.fromPositionOrientationScale(v0, q1, v1);
196  VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
197 
198  t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
199  t1.setIdentity(); t1.scale(v0).rotate(q1);
200  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
201 
202  t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
203  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
204 
205  VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
206  VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
207 
208  // More transform constructors, operator=, operator*=
209 
210  Matrix3 mat3 = Matrix3::Random();
211  Matrix4 mat4;
212  mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
213  Transform3 tmat3(mat3), tmat4(mat4);
214  if(Mode!=int(AffineCompact))
215  tmat4.matrix()(3,3) = Scalar(1);
216  VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
217 
218  Scalar a3 = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
219  Vector3 v3 = Vector3::Random().normalized();
220  AngleAxisx aa3(a3, v3);
221  Transform3 t3(aa3);
222  Transform3 t4;
223  t4 = aa3;
224  VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
225  t4.rotate(AngleAxisx(-a3,v3));
226  VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
227  t4 *= aa3;
228  VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
229 
230  do {
231  v3 = Vector3::Random();
232  dont_over_optimize(v3);
233  } while (v3.cwiseAbs().minCoeff()<NumTraits<Scalar>::epsilon());
234  Translation3 tv3(v3);
235  Transform3 t5(tv3);
236  t4 = tv3;
237  VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
238  t4.translate((-v3).eval());
239  VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
240  t4 *= tv3;
241  VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
242 
243  AlignedScaling3 sv3(v3);
244  Transform3 t6(sv3);
245  t4 = sv3;
246  VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
247  t4.scale(v3.cwiseInverse());
248  VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
249  t4 *= sv3;
250  VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
251 
252  // matrix * transform
253  VERIFY_IS_APPROX((t3.matrix()*t4).matrix(), (t3*t4).matrix());
254 
255  // chained Transform product
256  VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
257 
258  // check that Transform product doesn't have aliasing problems
259  t5 = t4;
260  t5 = t5*t5;
261  VERIFY_IS_APPROX(t5, t4*t4);
262 
263  // 2D transformation
264  Transform2 t20, t21;
265  Vector2 v20 = Vector2::Random();
266  Vector2 v21 = Vector2::Random();
267  for (int k=0; k<2; ++k)
268  if (abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
269  t21.setIdentity();
270  t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
271  VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
272  t21.pretranslate(v20).scale(v21).matrix());
273 
274  t21.setIdentity();
275  t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
276  VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
277  * (t21.prescale(v21.cwiseInverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
278 
279  // Transform - new API
280  // 3D
281  t0.setIdentity();
282  t0.rotate(q1).scale(v0).translate(v0);
283  // mat * aligned scaling and mat * translation
284  t1 = (Matrix3(q1) * AlignedScaling3(v0)) * Translation3(v0);
285  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
286  t1 = (Matrix3(q1) * Eigen::Scaling(v0)) * Translation3(v0);
287  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
288  t1 = (q1 * Eigen::Scaling(v0)) * Translation3(v0);
289  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
290  // mat * transformation and aligned scaling * translation
291  t1 = Matrix3(q1) * (AlignedScaling3(v0) * Translation3(v0));
292  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
293 
294 
295  t0.setIdentity();
296  t0.scale(s0).translate(v0);
297  t1 = Eigen::Scaling(s0) * Translation3(v0);
298  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
299  t0.prescale(s0);
300  t1 = Eigen::Scaling(s0) * t1;
301  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
302 
303  t0 = t3;
304  t0.scale(s0);
305  t1 = t3 * Eigen::Scaling(s0,s0,s0);
306  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
307  t0.prescale(s0);
308  t1 = Eigen::Scaling(s0,s0,s0) * t1;
309  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
310 
311  t0 = t3;
312  t0.scale(s0);
313  t1 = t3 * Eigen::Scaling(s0);
314  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
315  t0.prescale(s0);
316  t1 = Eigen::Scaling(s0) * t1;
317  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
318 
319  t0.setIdentity();
320  t0.prerotate(q1).prescale(v0).pretranslate(v0);
321  // translation * aligned scaling and transformation * mat
322  t1 = (Translation3(v0) * AlignedScaling3(v0)) * Transform3(q1);
323  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
324  // scaling * mat and translation * mat
325  t1 = Translation3(v0) * (AlignedScaling3(v0) * Transform3(q1));
326  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
327 
328  t0.setIdentity();
329  t0.scale(v0).translate(v0).rotate(q1);
330  // translation * mat and aligned scaling * transformation
331  t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
332  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
333  // transformation * aligned scaling
334  t0.scale(v0);
335  t1 *= AlignedScaling3(v0);
336  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
337  t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
338  t1 = t1 * v0.asDiagonal();
339  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
340  // transformation * translation
341  t0.translate(v0);
342  t1 = t1 * Translation3(v0);
343  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
344  // translation * transformation
345  t0.pretranslate(v0);
346  t1 = Translation3(v0) * t1;
347  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
348 
349  // transform * quaternion
350  t0.rotate(q1);
351  t1 = t1 * q1;
352  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
353 
354  // translation * quaternion
355  t0.translate(v1).rotate(q1);
356  t1 = t1 * (Translation3(v1) * q1);
357  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
358 
359  // aligned scaling * quaternion
360  t0.scale(v1).rotate(q1);
361  t1 = t1 * (AlignedScaling3(v1) * q1);
362  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
363 
364  // quaternion * transform
365  t0.prerotate(q1);
366  t1 = q1 * t1;
367  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
368 
369  // quaternion * translation
370  t0.rotate(q1).translate(v1);
371  t1 = t1 * (q1 * Translation3(v1));
372  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
373 
374  // quaternion * aligned scaling
375  t0.rotate(q1).scale(v1);
376  t1 = t1 * (q1 * AlignedScaling3(v1));
377  VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
378 
379  // test transform inversion
380  t0.setIdentity();
381  t0.translate(v0);
382  do {
383  t0.linear().setRandom();
384  } while(t0.linear().jacobiSvd().singularValues()(2)<test_precision<Scalar>());
385  Matrix4 t044 = Matrix4::Zero();
386  t044(3,3) = 1;
387  t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
388  VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
389  t0.setIdentity();
390  t0.translate(v0).rotate(q1);
391  t044 = Matrix4::Zero();
392  t044(3,3) = 1;
393  t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
394  VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
395 
396  Matrix3 mat_rotation, mat_scaling;
397  t0.setIdentity();
398  t0.translate(v0).rotate(q1).scale(v1);
399  t0.computeRotationScaling(&mat_rotation, &mat_scaling);
400  VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
401  VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
402  VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
403  t0.computeScalingRotation(&mat_scaling, &mat_rotation);
404  VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
405  VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
406  VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
407 
408  // test casting
409  Transform<float,3,Mode> t1f = t1.template cast<float>();
410  VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
411  Transform<double,3,Mode> t1d = t1.template cast<double>();
412  VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
413 
414  Translation3 tr1(v0);
415  Translation<float,3> tr1f = tr1.template cast<float>();
416  VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
417  Translation<double,3> tr1d = tr1.template cast<double>();
418  VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
419 
420  AngleAxis<float> aa1f = aa1.template cast<float>();
421  VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
422  AngleAxis<double> aa1d = aa1.template cast<double>();
423  VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
424 
425  Rotation2D<Scalar> r2d1(internal::random<Scalar>());
426  Rotation2D<float> r2d1f = r2d1.template cast<float>();
427  VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
428  Rotation2D<double> r2d1d = r2d1.template cast<double>();
429  VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
430 
431  for(int k=0; k<100; ++k)
432  {
433  Scalar angle = internal::random<Scalar>(-100,100);
434  Rotation2D<Scalar> rot2(angle);
435  VERIFY( rot2.smallestPositiveAngle() >= 0 );
436  VERIFY( rot2.smallestPositiveAngle() <= Scalar(2)*Scalar(EIGEN_PI) );
437  VERIFY_IS_APPROX( angleToVec(rot2.smallestPositiveAngle()), angleToVec(rot2.angle()) );
438 
439  VERIFY( rot2.smallestAngle() >= -Scalar(EIGEN_PI) );
440  VERIFY( rot2.smallestAngle() <= Scalar(EIGEN_PI) );
441  VERIFY_IS_APPROX( angleToVec(rot2.smallestAngle()), angleToVec(rot2.angle()) );
442 
443  Matrix<Scalar,2,2> rot2_as_mat(rot2);
444  Rotation2D<Scalar> rot3(rot2_as_mat);
445  VERIFY_IS_APPROX( angleToVec(rot2.smallestAngle()), angleToVec(rot3.angle()) );
446  }
447 
448  s0 = internal::random<Scalar>(-100,100);
449  s1 = internal::random<Scalar>(-100,100);
450  Rotation2D<Scalar> R0(s0), R1(s1);
451 
452  t20 = Translation2(v20) * (R0 * Eigen::Scaling(s0));
453  t21 = Translation2(v20) * R0 * Eigen::Scaling(s0);
454  VERIFY_IS_APPROX(t20,t21);
455 
456  t20 = Translation2(v20) * (R0 * R0.inverse() * Eigen::Scaling(s0));
457  t21 = Translation2(v20) * Eigen::Scaling(s0);
458  VERIFY_IS_APPROX(t20,t21);
459 
460  VERIFY_IS_APPROX(s0, (R0.slerp(0, R1)).angle());
461  VERIFY_IS_APPROX( angleToVec(R1.smallestPositiveAngle()), angleToVec((R0.slerp(1, R1)).smallestPositiveAngle()) );
462  VERIFY_IS_APPROX(R0.smallestPositiveAngle(), (R0.slerp(0.5, R0)).smallestPositiveAngle());
463 
464  if(std::cos(s0)>0)
465  VERIFY_IS_MUCH_SMALLER_THAN((R0.slerp(0.5, R0.inverse())).smallestAngle(), Scalar(1));
466  else
467  VERIFY_IS_APPROX(Scalar(EIGEN_PI), (R0.slerp(0.5, R0.inverse())).smallestPositiveAngle());
468 
469  // Check path length
470  Scalar l = 0;
471  int path_steps = 100;
472  for(int k=0; k<path_steps; ++k)
473  {
474  Scalar a1 = R0.slerp(Scalar(k)/Scalar(path_steps), R1).angle();
475  Scalar a2 = R0.slerp(Scalar(k+1)/Scalar(path_steps), R1).angle();
476  l += std::abs(a2-a1);
477  }
478  VERIFY(l<=Scalar(EIGEN_PI)*(Scalar(1)+NumTraits<Scalar>::epsilon()*Scalar(path_steps/2)));
479 
480  // check basic features
481  {
482  Rotation2D<Scalar> r1; // default ctor
483  r1 = Rotation2D<Scalar>(s0); // copy assignment
484  VERIFY_IS_APPROX(r1.angle(),s0);
485  Rotation2D<Scalar> r2(r1); // copy ctor
486  VERIFY_IS_APPROX(r2.angle(),s0);
487  }
488 
489  {
490  Transform3 t32(Matrix4::Random()), t33, t34;
491  t34 = t33 = t32;
492  t32.scale(v0);
493  t33*=AlignedScaling3(v0);
494  VERIFY_IS_APPROX(t32.matrix(), t33.matrix());
495  t33 = t34 * AlignedScaling3(v0);
496  VERIFY_IS_APPROX(t32.matrix(), t33.matrix());
497  }
498 
499 }
500 
501 template<typename A1, typename A2, typename P, typename Q, typename V, typename H>
502 void transform_associativity_left(const A1& a1, const A2& a2, const P& p, const Q& q, const V& v, const H& h)
503 {
504  VERIFY_IS_APPROX( q*(a1*v), (q*a1)*v );
505  VERIFY_IS_APPROX( q*(a2*v), (q*a2)*v );
506  VERIFY_IS_APPROX( q*(p*h).hnormalized(), ((q*p)*h).hnormalized() );
507 }
508 
509 template<typename A1, typename A2, typename P, typename Q, typename V, typename H>
510 void transform_associativity2(const A1& a1, const A2& a2, const P& p, const Q& q, const V& v, const H& h)
511 {
512  VERIFY_IS_APPROX( a1*(q*v), (a1*q)*v );
513  VERIFY_IS_APPROX( a2*(q*v), (a2*q)*v );
514  VERIFY_IS_APPROX( p *(q*v).homogeneous(), (p *q)*v.homogeneous() );
515 
516  transform_associativity_left(a1, a2,p, q, v, h);
517 }
518 
519 template<typename Scalar, int Dim, int Options,typename RotationType>
520 void transform_associativity(const RotationType& R)
521 {
523  typedef Matrix<Scalar,Dim+1,1> HVectorType;
524  typedef Matrix<Scalar,Dim,Dim> LinearType;
526  typedef Transform<Scalar,Dim,AffineCompact,Options> AffineCompactType;
527  typedef Transform<Scalar,Dim,Affine,Options> AffineType;
528  typedef Transform<Scalar,Dim,Projective,Options> ProjectiveType;
529  typedef DiagonalMatrix<Scalar,Dim> ScalingType;
530  typedef Translation<Scalar,Dim> TranslationType;
531 
532  AffineCompactType A1c; A1c.matrix().setRandom();
533  AffineCompactType A2c; A2c.matrix().setRandom();
534  AffineType A1(A1c);
535  AffineType A2(A2c);
536  ProjectiveType P1; P1.matrix().setRandom();
537  VectorType v1 = VectorType::Random();
538  VectorType v2 = VectorType::Random();
539  HVectorType h1 = HVectorType::Random();
540  Scalar s1 = internal::random<Scalar>();
541  LinearType L = LinearType::Random();
542  MatrixType M = MatrixType::Random();
543 
544  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, A2, v2, h1) );
545  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, A2c, v2, h1) );
546  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, v1.asDiagonal(), v2, h1) );
547  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, ScalingType(v1), v2, h1) );
548  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, Scaling(v1), v2, h1) );
549  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, Scaling(s1), v2, h1) );
550  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, TranslationType(v1), v2, h1) );
551  CALL_SUBTEST( transform_associativity_left(A1c, A1, P1, L, v2, h1) );
552  CALL_SUBTEST( transform_associativity2(A1c, A1, P1, R, v2, h1) );
553 
554  VERIFY_IS_APPROX( A1*(M*h1), (A1*M)*h1 );
555  VERIFY_IS_APPROX( A1c*(M*h1), (A1c*M)*h1 );
556  VERIFY_IS_APPROX( P1*(M*h1), (P1*M)*h1 );
557 
558  VERIFY_IS_APPROX( M*(A1*h1), (M*A1)*h1 );
559  VERIFY_IS_APPROX( M*(A1c*h1), (M*A1c)*h1 );
560  VERIFY_IS_APPROX( M*(P1*h1), ((M*P1)*h1) );
561 }
562 
563 template<typename Scalar> void transform_alignment()
564 {
565  typedef Transform<Scalar,3,Projective,AutoAlign> Projective3a;
566  typedef Transform<Scalar,3,Projective,DontAlign> Projective3u;
567 
568  EIGEN_ALIGN_MAX Scalar array1[16];
569  EIGEN_ALIGN_MAX Scalar array2[16];
570  EIGEN_ALIGN_MAX Scalar array3[16+1];
571  Scalar* array3u = array3+1;
572 
573  Projective3a *p1 = ::new(reinterpret_cast<void*>(array1)) Projective3a;
574  Projective3u *p2 = ::new(reinterpret_cast<void*>(array2)) Projective3u;
575  Projective3u *p3 = ::new(reinterpret_cast<void*>(array3u)) Projective3u;
576 
577  p1->matrix().setRandom();
578  *p2 = *p1;
579  *p3 = *p1;
580 
581  VERIFY_IS_APPROX(p1->matrix(), p2->matrix());
582  VERIFY_IS_APPROX(p1->matrix(), p3->matrix());
583 
584  VERIFY_IS_APPROX( (*p1) * (*p1), (*p2)*(*p3));
585 }
586 
587 template<typename Scalar, int Dim, int Options> void transform_products()
588 {
593 
594  Proj p; p.matrix().setRandom();
595  Aff a; a.linear().setRandom(); a.translation().setRandom();
596  AffC ac = a;
597 
598  Mat p_m(p.matrix()), a_m(a.matrix());
599 
600  VERIFY_IS_APPROX((p*p).matrix(), p_m*p_m);
601  VERIFY_IS_APPROX((a*a).matrix(), a_m*a_m);
602  VERIFY_IS_APPROX((p*a).matrix(), p_m*a_m);
603  VERIFY_IS_APPROX((a*p).matrix(), a_m*p_m);
604  VERIFY_IS_APPROX((ac*a).matrix(), a_m*a_m);
605  VERIFY_IS_APPROX((a*ac).matrix(), a_m*a_m);
606  VERIFY_IS_APPROX((p*ac).matrix(), p_m*a_m);
607  VERIFY_IS_APPROX((ac*p).matrix(), a_m*p_m);
608 }
609 
610 template<typename Scalar, int Mode, int Options> void transformations_no_scale()
611 {
612  /* this test covers the following files:
613  Cross.h Quaternion.h, Transform.h
614  */
615  typedef Matrix<Scalar,3,1> Vector3;
616  typedef Matrix<Scalar,4,1> Vector4;
617  typedef Quaternion<Scalar> Quaternionx;
618  typedef AngleAxis<Scalar> AngleAxisx;
619  typedef Transform<Scalar,3,Mode,Options> Transform3;
620  typedef Translation<Scalar,3> Translation3;
621  typedef Matrix<Scalar,4,4> Matrix4;
622 
623  Vector3 v0 = Vector3::Random(),
624  v1 = Vector3::Random();
625 
626  Transform3 t0, t1, t2;
627 
628  Scalar a = internal::random<Scalar>(-Scalar(EIGEN_PI), Scalar(EIGEN_PI));
629 
630  Quaternionx q1, q2;
631 
632  q1 = AngleAxisx(a, v0.normalized());
633 
634  t0 = Transform3::Identity();
635  VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
636 
637  t0.setIdentity();
638  t1.setIdentity();
639  v1 = Vector3::Ones();
640  t0.linear() = q1.toRotationMatrix();
641  t0.pretranslate(v0);
642  t1.linear() = q1.conjugate().toRotationMatrix();
643  t1.translate(-v0);
644 
645  VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
646 
647  t1.fromPositionOrientationScale(v0, q1, v1);
648  VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
649  VERIFY_IS_APPROX(t1*v1, t0*v1);
650 
651  // translation * vector
652  t0.setIdentity();
653  t0.translate(v0);
654  VERIFY_IS_APPROX((t0 * v1).template head<3>(), Translation3(v0) * v1);
655 
656  // Conversion to matrix.
657  Transform3 t3;
658  t3.linear() = q1.toRotationMatrix();
659  t3.translation() = v1;
660  Matrix4 m3 = t3.matrix();
661  VERIFY((m3 * m3.inverse()).isIdentity(test_precision<Scalar>()));
662  // Verify implicit last row is initialized.
663  VERIFY_IS_APPROX(Vector4(m3.row(3)), Vector4(0.0, 0.0, 0.0, 1.0));
664 
665  VERIFY_IS_APPROX(t3.rotation(), t3.linear());
666  if(Mode==Isometry)
667  VERIFY(t3.rotation().data()==t3.linear().data());
668 }
669 
670 template<typename Scalar, int Mode, int Options> void transformations_computed_scaling_continuity()
671 {
673  typedef Transform<Scalar, 3, Mode, Options> Transform3;
674  typedef Matrix<Scalar, 3, 3> Matrix3;
675 
676  // Given: two transforms that differ by '2*eps'.
677  Scalar eps(1e-3);
678  Vector3 v0 = Vector3::Random().normalized(),
679  v1 = Vector3::Random().normalized(),
680  v3 = Vector3::Random().normalized();
681  Transform3 t0, t1;
682  // The interesting case is when their determinants have different signs.
683  Matrix3 rank2 = 50 * v0 * v0.adjoint() + 20 * v1 * v1.adjoint();
684  t0.linear() = rank2 + eps * v3 * v3.adjoint();
685  t1.linear() = rank2 - eps * v3 * v3.adjoint();
686 
687  // When: computing the rotation-scaling parts
688  Matrix3 r0, s0, r1, s1;
689  t0.computeRotationScaling(&r0, &s0);
690  t1.computeRotationScaling(&r1, &s1);
691 
692  // Then: the scaling parts should differ by no more than '2*eps'.
693  const Scalar c(2.1); // 2 + room for rounding errors
694  VERIFY((s0 - s1).norm() < c * eps);
695 }
696 
697 EIGEN_DECLARE_TEST(geo_transformations)
698 {
699  for(int i = 0; i < g_repeat; i++) {
700  CALL_SUBTEST_1(( transformations<double,Affine,AutoAlign>() ));
701  CALL_SUBTEST_1(( non_projective_only<double,Affine,AutoAlign>() ));
702  CALL_SUBTEST_1(( transformations_computed_scaling_continuity<double,Affine,AutoAlign>() ));
703 
704  CALL_SUBTEST_2(( transformations<float,AffineCompact,AutoAlign>() ));
705  CALL_SUBTEST_2(( non_projective_only<float,AffineCompact,AutoAlign>() ));
706  CALL_SUBTEST_2(( transform_alignment<float>() ));
707 
708  CALL_SUBTEST_3(( transformations<double,Projective,AutoAlign>() ));
709  CALL_SUBTEST_3(( transformations<double,Projective,DontAlign>() ));
710  CALL_SUBTEST_3(( transform_alignment<double>() ));
711 
712  CALL_SUBTEST_4(( transformations<float,Affine,RowMajor|AutoAlign>() ));
713  CALL_SUBTEST_4(( non_projective_only<float,Affine,RowMajor>() ));
714 
715  CALL_SUBTEST_5(( transformations<double,AffineCompact,RowMajor|AutoAlign>() ));
716  CALL_SUBTEST_5(( non_projective_only<double,AffineCompact,RowMajor>() ));
717 
718  CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|AutoAlign>() ));
719  CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|DontAlign>() ));
720 
721 
722  CALL_SUBTEST_7(( transform_products<double,3,RowMajor|AutoAlign>() ));
723  CALL_SUBTEST_7(( transform_products<float,2,AutoAlign>() ));
724 
725  CALL_SUBTEST_8(( transform_associativity<double,2,ColMajor>(Rotation2D<double>(internal::random<double>()*double(EIGEN_PI))) ));
726  CALL_SUBTEST_8(( transform_associativity<double,3,ColMajor>(Quaterniond::UnitRandom()) ));
727 
728  CALL_SUBTEST_9(( transformations_no_scale<double,Affine,AutoAlign>() ));
729  CALL_SUBTEST_9(( transformations_no_scale<double,Isometry,AutoAlign>() ));
730  }
731 }
Point2 a1
Definition: testPose2.cpp:769
Matrix3f m
static Matrix A1
Matrix< T, 2, 1 > angleToVec(T a)
SCALAR Scalar
Definition: bench_gemm.cpp:46
#define CALL_SUBTEST_9(FUNC)
#define CALL_SUBTEST_6(FUNC)
#define CALL_SUBTEST_4(FUNC)
Matrix< RealScalar, Dynamic, Dynamic > M
Definition: bench_gemm.cpp:51
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:426
Vector v2
static Point3 p3
Eigen::Vector3d Vector3
Definition: Vector.h:43
Vector v1
void homogeneous(void)
Vector3f p1
Point2 a3
Definition: testPose2.cpp:771
#define EIGEN_PI
void transformations_no_scale()
#define CALL_SUBTEST_3(FUNC)
#define CALL_SUBTEST_7(FUNC)
void transform_products()
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
Rot2 R(Rot2::fromAngle(0.1))
Represents a diagonal matrix with its storage.
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:439
void transformations_computed_scaling_continuity()
MatrixXd L
Definition: LLT_example.cpp:6
MatrixXf MatrixType
Holds information about the various numeric (i.e. scalar) types allowed by Eigen. ...
Definition: NumTraits.h:232
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics set mxtics default set mytics default set mx2tics default set my2tics default set xtics border mirror norotate autofreq set ytics border mirror norotate autofreq set ztics border nomirror norotate autofreq set nox2tics set noy2tics set timestamp bottom norotate set rrange [*:*] noreverse nowriteback set trange [*:*] noreverse nowriteback set urange [*:*] noreverse nowriteback set vrange [*:*] noreverse nowriteback set xlabel matrix size set x2label set timefmt d m y n H
#define EIGEN_ALIGN_MAX
void transform_associativity(const RotationType &R)
void non_projective_only()
static double epsilon
Definition: testRot3.cpp:37
UniformScaling< float > Scaling(float s)
#define EIGEN_DONT_INLINE
Definition: Macros.h:940
EIGEN_DONT_INLINE void dont_over_optimize(T &x)
void transform_associativity2(const A1 &a1, const A2 &a2, const P &p, const Q &q, const V &v, const H &h)
Represents a translation transformation.
#define VERIFY_IS_APPROX(a, b)
Vector v3
static const Line3 l(Rot3(), 1, 1)
#define CALL_SUBTEST_1(FUNC)
static EIGEN_DEVICE_FUNC Matrix< Scalar, 2, 2 > toRotationMatrix(const Scalar &s)
Definition: RotationBase.h:182
static int g_repeat
Definition: main.h:169
Array< int, Dynamic, 1 > v
#define CALL_SUBTEST_8(FUNC)
Array< double, 1, 3 > e(1./3., 0.5, 2.)
static const double r2
EIGEN_DEVICE_FUNC const Scalar & q
EIGEN_DECLARE_TEST(geo_transformations)
#define VERIFY_IS_MUCH_SMALLER_THAN(a, b)
Definition: main.h:390
Point2 a2
Definition: testPose2.cpp:770
const double h
Represents a rotation/orientation in a 2 dimensional space.
Eigen::Vector2d Vector2
Definition: Vector.h:42
#define CALL_SUBTEST_5(FUNC)
static const double r1
#define CALL_SUBTEST(FUNC)
Definition: main.h:399
#define VERIFY(a)
Definition: main.h:380
The quaternion class used to represent 3D orientations and rotations.
static const double v0
float * p
void transformations()
Matrix< Scalar, Dynamic, Dynamic > Mat
Definition: gemm_common.h:15
static Point3 p2
#define CALL_SUBTEST_2(FUNC)
static Rot3 R0
internal::nested_eval< T, 1 >::type eval(const T &xpr)
Map< Matrix< T, Dynamic, Dynamic, ColMajor >, 0, OuterStride<> > matrix(T *data, int rows, int cols, int stride)
The matrix class, also used for vectors and row-vectors.
EIGEN_DEVICE_FUNC bool isApprox(const Scalar &x, const Scalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
void transform_alignment()
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
#define abs(x)
Definition: datatypes.h:17
EIGEN_DEVICE_FUNC Scalar angle() const
Definition: Rotation2D.h:78
void transform_associativity_left(const A1 &a1, const A2 &a2, const P &p, const Q &q, const V &v, const H &h)
Represents a 3D rotation as a rotation angle around an arbitrary 3D axis.
Represents an homogeneous transformation in a N dimensional space.


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:34:17