Home | History | Annotate | Download | only in eigen2
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra. Eigen itself is part of the KDE project.
      3 //
      4 // Copyright (C) 2008 Gael Guennebaud <g.gael (at) free.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 #define EIGEN2_SUPPORT_STAGE15_RESOLVE_API_CONFLICTS_WARN
     11 
     12 #include "main.h"
     13 #include <Eigen/Geometry>
     14 #include <Eigen/LU>
     15 #include <Eigen/SVD>
     16 
     17 template<typename Scalar> void geometry(void)
     18 {
     19   /* this test covers the following files:
     20      Cross.h Quaternion.h, Transform.cpp
     21   */
     22 
     23   typedef Matrix<Scalar,2,2> Matrix2;
     24   typedef Matrix<Scalar,3,3> Matrix3;
     25   typedef Matrix<Scalar,4,4> Matrix4;
     26   typedef Matrix<Scalar,2,1> Vector2;
     27   typedef Matrix<Scalar,3,1> Vector3;
     28   typedef Matrix<Scalar,4,1> Vector4;
     29   typedef eigen2_Quaternion<Scalar> Quaternionx;
     30   typedef eigen2_AngleAxis<Scalar> AngleAxisx;
     31   typedef eigen2_Transform<Scalar,2> Transform2;
     32   typedef eigen2_Transform<Scalar,3> Transform3;
     33   typedef eigen2_Scaling<Scalar,2> Scaling2;
     34   typedef eigen2_Scaling<Scalar,3> Scaling3;
     35   typedef eigen2_Translation<Scalar,2> Translation2;
     36   typedef eigen2_Translation<Scalar,3> Translation3;
     37 
     38   Scalar largeEps = test_precision<Scalar>();
     39   if (ei_is_same_type<Scalar,float>::ret)
     40     largeEps = 1e-2f;
     41 
     42   Vector3 v0 = Vector3::Random(),
     43     v1 = Vector3::Random(),
     44     v2 = Vector3::Random();
     45   Vector2 u0 = Vector2::Random();
     46   Matrix3 matrot1;
     47 
     48   Scalar a = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
     49 
     50   // cross product
     51   VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1));
     52   Matrix3 m;
     53   m << v0.normalized(),
     54       (v0.cross(v1)).normalized(),
     55       (v0.cross(v1).cross(v0)).normalized();
     56   VERIFY(m.isUnitary());
     57 
     58   // Quaternion: Identity(), setIdentity();
     59   Quaternionx q1, q2;
     60   q2.setIdentity();
     61   VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs());
     62   q1.coeffs().setRandom();
     63   VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs());
     64 
     65   // unitOrthogonal
     66   VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1));
     67   VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1));
     68   VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1));
     69   VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1));
     70 
     71 
     72   VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
     73   VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
     74   VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
     75   m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
     76   VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
     77   VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
     78 
     79   q1 = AngleAxisx(a, v0.normalized());
     80   q2 = AngleAxisx(a, v1.normalized());
     81 
     82   // angular distance
     83   Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle());
     84   if (refangle>Scalar(M_PI))
     85     refangle = Scalar(2)*Scalar(M_PI) - refangle;
     86 
     87   if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps)
     88   {
     89     VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps));
     90   }
     91 
     92   // rotation matrix conversion
     93   VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2);
     94   VERIFY_IS_APPROX(q1 * q2 * v2,
     95     q1.toRotationMatrix() * q2.toRotationMatrix() * v2);
     96 
     97   VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox(
     98     q1.toRotationMatrix() * q2.toRotationMatrix() * v2));
     99 
    100   q2 = q1.toRotationMatrix();
    101   VERIFY_IS_APPROX(q1*v1,q2*v1);
    102 
    103   matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
    104           * AngleAxisx(Scalar(0.2), Vector3::UnitY())
    105           * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
    106   VERIFY_IS_APPROX(matrot1 * v1,
    107        AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
    108     * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
    109     * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
    110 
    111   // angle-axis conversion
    112   AngleAxisx aa = q1;
    113   VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
    114   VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
    115 
    116   // from two vector creation
    117   VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
    118   VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized());
    119 
    120   // inverse and conjugate
    121   VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1);
    122   VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1);
    123 
    124   // AngleAxis
    125   VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
    126     Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
    127 
    128   AngleAxisx aa1;
    129   m = q1.toRotationMatrix();
    130   aa1 = m;
    131   VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
    132     Quaternionx(m).toRotationMatrix());
    133 
    134   // Transform
    135   // TODO complete the tests !
    136   a = 0;
    137   while (ei_abs(a)<Scalar(0.1))
    138     a = ei_random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
    139   q1 = AngleAxisx(a, v0.normalized());
    140   Transform3 t0, t1, t2;
    141   // first test setIdentity() and Identity()
    142   t0.setIdentity();
    143   VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
    144   t0.matrix().setZero();
    145   t0 = Transform3::Identity();
    146   VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
    147 
    148   t0.linear() = q1.toRotationMatrix();
    149   t1.setIdentity();
    150   t1.linear() = q1.toRotationMatrix();
    151 
    152   v0 << 50, 2, 1;//= ei_random_matrix<Vector3>().cwiseProduct(Vector3(10,2,0.5));
    153   t0.scale(v0);
    154   t1.prescale(v0);
    155 
    156   VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x());
    157   //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x()));
    158 
    159   t0.setIdentity();
    160   t1.setIdentity();
    161   v1 << 1, 2, 3;
    162   t0.linear() = q1.toRotationMatrix();
    163   t0.pretranslate(v0);
    164   t0.scale(v1);
    165   t1.linear() = q1.conjugate().toRotationMatrix();
    166   t1.prescale(v1.cwise().inverse());
    167   t1.translate(-v0);
    168 
    169   VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision<Scalar>()));
    170 
    171   t1.fromPositionOrientationScale(v0, q1, v1);
    172   VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
    173   VERIFY_IS_APPROX(t1*v1, t0*v1);
    174 
    175   t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
    176   t1.setIdentity(); t1.scale(v0).rotate(q1);
    177   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    178 
    179   t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
    180   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    181 
    182   VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
    183   VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
    184 
    185   // More transform constructors, operator=, operator*=
    186 
    187   Matrix3 mat3 = Matrix3::Random();
    188   Matrix4 mat4;
    189   mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
    190   Transform3 tmat3(mat3), tmat4(mat4);
    191   tmat4.matrix()(3,3) = Scalar(1);
    192   VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
    193 
    194   Scalar a3 = ei_random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
    195   Vector3 v3 = Vector3::Random().normalized();
    196   AngleAxisx aa3(a3, v3);
    197   Transform3 t3(aa3);
    198   Transform3 t4;
    199   t4 = aa3;
    200   VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
    201   t4.rotate(AngleAxisx(-a3,v3));
    202   VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
    203   t4 *= aa3;
    204   VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
    205 
    206   v3 = Vector3::Random();
    207   Translation3 tv3(v3);
    208   Transform3 t5(tv3);
    209   t4 = tv3;
    210   VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
    211   t4.translate(-v3);
    212   VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
    213   t4 *= tv3;
    214   VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
    215 
    216   Scaling3 sv3(v3);
    217   Transform3 t6(sv3);
    218   t4 = sv3;
    219   VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
    220   t4.scale(v3.cwise().inverse());
    221   VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity());
    222   t4 *= sv3;
    223   VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
    224 
    225   // matrix * transform
    226   VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix());
    227 
    228   // chained Transform product
    229   VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
    230 
    231   // check that Transform product doesn't have aliasing problems
    232   t5 = t4;
    233   t5 = t5*t5;
    234   VERIFY_IS_APPROX(t5, t4*t4);
    235 
    236   // 2D transformation
    237   Transform2 t20, t21;
    238   Vector2 v20 = Vector2::Random();
    239   Vector2 v21 = Vector2::Random();
    240   for (int k=0; k<2; ++k)
    241     if (ei_abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
    242   t21.setIdentity();
    243   t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
    244   VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
    245     t21.pretranslate(v20).scale(v21).matrix());
    246 
    247   t21.setIdentity();
    248   t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
    249   VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
    250         * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
    251 
    252   // Transform - new API
    253   // 3D
    254   t0.setIdentity();
    255   t0.rotate(q1).scale(v0).translate(v0);
    256   // mat * scaling and mat * translation
    257   t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0);
    258   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    259   // mat * transformation and scaling * translation
    260   t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0));
    261   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    262 
    263   t0.setIdentity();
    264   t0.prerotate(q1).prescale(v0).pretranslate(v0);
    265   // translation * scaling and transformation * mat
    266   t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1);
    267   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    268   // scaling * mat and translation * mat
    269   t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1));
    270   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    271 
    272   t0.setIdentity();
    273   t0.scale(v0).translate(v0).rotate(q1);
    274   // translation * mat and scaling * transformation
    275   t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1));
    276   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    277   // transformation * scaling
    278   t0.scale(v0);
    279   t1 = t1 * Scaling3(v0);
    280   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    281   // transformation * translation
    282   t0.translate(v0);
    283   t1 = t1 * Translation3(v0);
    284   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    285   // translation * transformation
    286   t0.pretranslate(v0);
    287   t1 = Translation3(v0) * t1;
    288   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    289 
    290   // transform * quaternion
    291   t0.rotate(q1);
    292   t1 = t1 * q1;
    293   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    294 
    295   // translation * quaternion
    296   t0.translate(v1).rotate(q1);
    297   t1 = t1 * (Translation3(v1) * q1);
    298   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    299 
    300   // scaling * quaternion
    301   t0.scale(v1).rotate(q1);
    302   t1 = t1 * (Scaling3(v1) * q1);
    303   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    304 
    305   // quaternion * transform
    306   t0.prerotate(q1);
    307   t1 = q1 * t1;
    308   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    309 
    310   // quaternion * translation
    311   t0.rotate(q1).translate(v1);
    312   t1 = t1 * (q1 * Translation3(v1));
    313   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    314 
    315   // quaternion * scaling
    316   t0.rotate(q1).scale(v1);
    317   t1 = t1 * (q1 * Scaling3(v1));
    318   VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
    319 
    320   // translation * vector
    321   t0.setIdentity();
    322   t0.translate(v0);
    323   VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1);
    324 
    325   // scaling * vector
    326   t0.setIdentity();
    327   t0.scale(v0);
    328   VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1);
    329 
    330   // test transform inversion
    331   t0.setIdentity();
    332   t0.translate(v0);
    333   t0.linear().setRandom();
    334   VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse());
    335   t0.setIdentity();
    336   t0.translate(v0).rotate(q1);
    337   VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse());
    338 
    339   // test extract rotation and scaling
    340   t0.setIdentity();
    341   t0.translate(v0).rotate(q1).scale(v1);
    342   VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1);
    343 
    344   Matrix3 mat_rotation, mat_scaling;
    345   t0.setIdentity();
    346   t0.translate(v0).rotate(q1).scale(v1);
    347   t0.computeRotationScaling(&mat_rotation, &mat_scaling);
    348   VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
    349   VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
    350   VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
    351   t0.computeScalingRotation(&mat_scaling, &mat_rotation);
    352   VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
    353   VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
    354   VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
    355 
    356   // test casting
    357   eigen2_Transform<float,3> t1f = t1.template cast<float>();
    358   VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
    359   eigen2_Transform<double,3> t1d = t1.template cast<double>();
    360   VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
    361 
    362   Translation3 tr1(v0);
    363   eigen2_Translation<float,3> tr1f = tr1.template cast<float>();
    364   VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
    365   eigen2_Translation<double,3> tr1d = tr1.template cast<double>();
    366   VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
    367 
    368   Scaling3 sc1(v0);
    369   eigen2_Scaling<float,3> sc1f = sc1.template cast<float>();
    370   VERIFY_IS_APPROX(sc1f.template cast<Scalar>(),sc1);
    371   eigen2_Scaling<double,3> sc1d = sc1.template cast<double>();
    372   VERIFY_IS_APPROX(sc1d.template cast<Scalar>(),sc1);
    373 
    374   eigen2_Quaternion<float> q1f = q1.template cast<float>();
    375   VERIFY_IS_APPROX(q1f.template cast<Scalar>(),q1);
    376   eigen2_Quaternion<double> q1d = q1.template cast<double>();
    377   VERIFY_IS_APPROX(q1d.template cast<Scalar>(),q1);
    378 
    379   eigen2_AngleAxis<float> aa1f = aa1.template cast<float>();
    380   VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
    381   eigen2_AngleAxis<double> aa1d = aa1.template cast<double>();
    382   VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
    383 
    384   eigen2_Rotation2D<Scalar> r2d1(ei_random<Scalar>());
    385   eigen2_Rotation2D<float> r2d1f = r2d1.template cast<float>();
    386   VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
    387   eigen2_Rotation2D<double> r2d1d = r2d1.template cast<double>();
    388   VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
    389 
    390   m = q1;
    391 //   m.col(1) = Vector3(0,ei_random<Scalar>(),ei_random<Scalar>()).normalized();
    392 //   m.col(0) = Vector3(-1,0,0).normalized();
    393 //   m.col(2) = m.col(0).cross(m.col(1));
    394   #define VERIFY_EULER(I,J,K, X,Y,Z) { \
    395     Vector3 ea = m.eulerAngles(I,J,K); \
    396     Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \
    397     VERIFY_IS_APPROX(m,  Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \
    398   }
    399   VERIFY_EULER(0,1,2, X,Y,Z);
    400   VERIFY_EULER(0,1,0, X,Y,X);
    401   VERIFY_EULER(0,2,1, X,Z,Y);
    402   VERIFY_EULER(0,2,0, X,Z,X);
    403 
    404   VERIFY_EULER(1,2,0, Y,Z,X);
    405   VERIFY_EULER(1,2,1, Y,Z,Y);
    406   VERIFY_EULER(1,0,2, Y,X,Z);
    407   VERIFY_EULER(1,0,1, Y,X,Y);
    408 
    409   VERIFY_EULER(2,0,1, Z,X,Y);
    410   VERIFY_EULER(2,0,2, Z,X,Z);
    411   VERIFY_EULER(2,1,0, Z,Y,X);
    412   VERIFY_EULER(2,1,2, Z,Y,Z);
    413 
    414   // colwise/rowwise cross product
    415   mat3.setRandom();
    416   Vector3 vec3 = Vector3::Random();
    417   Matrix3 mcross;
    418   int i = ei_random<int>(0,2);
    419   mcross = mat3.colwise().cross(vec3);
    420   VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));
    421   mcross = mat3.rowwise().cross(vec3);
    422   VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));
    423 
    424 
    425 }
    426 
    427 void test_eigen2_geometry_with_eigen2_prefix()
    428 {
    429   std::cout << "eigen2 support: " << EIGEN2_SUPPORT_STAGE << std::endl;
    430   for(int i = 0; i < g_repeat; i++) {
    431     CALL_SUBTEST_1( geometry<float>() );
    432     CALL_SUBTEST_2( geometry<double>() );
    433   }
    434 }
    435