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
non_projective_only()15 template<typename Scalar, int Mode, int Options> void non_projective_only()
16 {
17 /* this test covers the following files:
18 Cross.h Quaternion.h, Transform.cpp
19 */
20 typedef Matrix<Scalar,2,2> Matrix2;
21 typedef Matrix<Scalar,3,3> Matrix3;
22 typedef Matrix<Scalar,4,4> Matrix4;
23 typedef Matrix<Scalar,2,1> Vector2;
24 typedef Matrix<Scalar,3,1> Vector3;
25 typedef Matrix<Scalar,4,1> Vector4;
26 typedef Quaternion<Scalar> Quaternionx;
27 typedef AngleAxis<Scalar> AngleAxisx;
28 typedef Transform<Scalar,2,Mode,Options> Transform2;
29 typedef Transform<Scalar,3,Mode,Options> Transform3;
30 typedef Transform<Scalar,2,Isometry,Options> Isometry2;
31 typedef Transform<Scalar,3,Isometry,Options> Isometry3;
32 typedef typename Transform3::MatrixType MatrixType;
33 typedef DiagonalMatrix<Scalar,2> AlignedScaling2;
34 typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
35 typedef Translation<Scalar,2> Translation2;
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(M_PI), Scalar(M_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
transformations()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 typedef Matrix<Scalar,2,2> Matrix2;
92 typedef Matrix<Scalar,3,3> Matrix3;
93 typedef Matrix<Scalar,4,4> Matrix4;
94 typedef Matrix<Scalar,2,1> Vector2;
95 typedef Matrix<Scalar,3,1> Vector3;
96 typedef Matrix<Scalar,4,1> Vector4;
97 typedef Quaternion<Scalar> Quaternionx;
98 typedef AngleAxis<Scalar> AngleAxisx;
99 typedef Transform<Scalar,2,Mode,Options> Transform2;
100 typedef Transform<Scalar,3,Mode,Options> Transform3;
101 typedef Transform<Scalar,2,Isometry,Options> Isometry2;
102 typedef Transform<Scalar,3,Isometry,Options> Isometry3;
103 typedef typename Transform3::MatrixType MatrixType;
104 typedef DiagonalMatrix<Scalar,2> AlignedScaling2;
105 typedef DiagonalMatrix<Scalar,3> AlignedScaling3;
106 typedef Translation<Scalar,2> Translation2;
107 typedef Translation<Scalar,3> Translation3;
108
109 Vector3 v0 = Vector3::Random(),
110 v1 = Vector3::Random();
111 Matrix3 matrot1, m;
112
113 Scalar a = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
114 Scalar s0 = internal::random<Scalar>();
115
116 VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0);
117 VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0);
118 VERIFY_IS_APPROX(internal::cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0));
119 m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint();
120 VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized()));
121 VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m);
122
123 Quaternionx q1, q2;
124 q1 = AngleAxisx(a, v0.normalized());
125 q2 = AngleAxisx(a, v1.normalized());
126
127 // rotation matrix conversion
128 matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX())
129 * AngleAxisx(Scalar(0.2), Vector3::UnitY())
130 * AngleAxisx(Scalar(0.3), Vector3::UnitZ());
131 VERIFY_IS_APPROX(matrot1 * v1,
132 AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix()
133 * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix()
134 * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1)));
135
136 // angle-axis conversion
137 AngleAxisx aa = AngleAxisx(q1);
138 VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
139 VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
140
141 aa.fromRotationMatrix(aa.toRotationMatrix());
142 VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1);
143 VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1);
144
145 // AngleAxis
146 VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(),
147 Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix());
148
149 AngleAxisx aa1;
150 m = q1.toRotationMatrix();
151 aa1 = m;
152 VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(),
153 Quaternionx(m).toRotationMatrix());
154
155 // Transform
156 // TODO complete the tests !
157 a = 0;
158 while (internal::abs(a)<Scalar(0.1))
159 a = internal::random<Scalar>(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI));
160 q1 = AngleAxisx(a, v0.normalized());
161 Transform3 t0, t1, t2;
162
163 // first test setIdentity() and Identity()
164 t0.setIdentity();
165 VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
166 t0.matrix().setZero();
167 t0 = Transform3::Identity();
168 VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity());
169
170 t0.setIdentity();
171 t1.setIdentity();
172 v1 << 1, 2, 3;
173 t0.linear() = q1.toRotationMatrix();
174 t0.pretranslate(v0);
175 t0.scale(v1);
176 t1.linear() = q1.conjugate().toRotationMatrix();
177 t1.prescale(v1.cwiseInverse());
178 t1.translate(-v0);
179
180 VERIFY((t0 * t1).matrix().isIdentity(test_precision<Scalar>()));
181
182 t1.fromPositionOrientationScale(v0, q1, v1);
183 VERIFY_IS_APPROX(t1.matrix(), t0.matrix());
184
185 t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix());
186 t1.setIdentity(); t1.scale(v0).rotate(q1);
187 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
188
189 t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1));
190 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
191
192 VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix());
193 VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix());
194
195 // More transform constructors, operator=, operator*=
196
197 Matrix3 mat3 = Matrix3::Random();
198 Matrix4 mat4;
199 mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose();
200 Transform3 tmat3(mat3), tmat4(mat4);
201 if(Mode!=int(AffineCompact))
202 tmat4.matrix()(3,3) = Scalar(1);
203 VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix());
204
205 Scalar a3 = internal::random<Scalar>(-Scalar(M_PI), Scalar(M_PI));
206 Vector3 v3 = Vector3::Random().normalized();
207 AngleAxisx aa3(a3, v3);
208 Transform3 t3(aa3);
209 Transform3 t4;
210 t4 = aa3;
211 VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
212 t4.rotate(AngleAxisx(-a3,v3));
213 VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
214 t4 *= aa3;
215 VERIFY_IS_APPROX(t3.matrix(), t4.matrix());
216
217 v3 = Vector3::Random();
218 Translation3 tv3(v3);
219 Transform3 t5(tv3);
220 t4 = tv3;
221 VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
222 t4.translate(-v3);
223 VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
224 t4 *= tv3;
225 VERIFY_IS_APPROX(t5.matrix(), t4.matrix());
226
227 AlignedScaling3 sv3(v3);
228 Transform3 t6(sv3);
229 t4 = sv3;
230 VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
231 t4.scale(v3.cwiseInverse());
232 VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity());
233 t4 *= sv3;
234 VERIFY_IS_APPROX(t6.matrix(), t4.matrix());
235
236 // matrix * transform
237 VERIFY_IS_APPROX((t3.matrix()*t4).matrix(), (t3*t4).matrix());
238
239 // chained Transform product
240 VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix());
241
242 // check that Transform product doesn't have aliasing problems
243 t5 = t4;
244 t5 = t5*t5;
245 VERIFY_IS_APPROX(t5, t4*t4);
246
247 // 2D transformation
248 Transform2 t20, t21;
249 Vector2 v20 = Vector2::Random();
250 Vector2 v21 = Vector2::Random();
251 for (int k=0; k<2; ++k)
252 if (internal::abs(v21[k])<Scalar(1e-3)) v21[k] = Scalar(1e-3);
253 t21.setIdentity();
254 t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
255 VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
256 t21.pretranslate(v20).scale(v21).matrix());
257
258 t21.setIdentity();
259 t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
260 VERIFY( (t20.fromPositionOrientationScale(v20,a,v21)
261 * (t21.prescale(v21.cwiseInverse()).translate(-v20))).matrix().isIdentity(test_precision<Scalar>()) );
262
263 // Transform - new API
264 // 3D
265 t0.setIdentity();
266 t0.rotate(q1).scale(v0).translate(v0);
267 // mat * aligned scaling and mat * translation
268 t1 = (Matrix3(q1) * AlignedScaling3(v0)) * Translation3(v0);
269 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
270 t1 = (Matrix3(q1) * Eigen::Scaling(v0)) * Translation3(v0);
271 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
272 t1 = (q1 * Eigen::Scaling(v0)) * Translation3(v0);
273 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
274 // mat * transformation and aligned scaling * translation
275 t1 = Matrix3(q1) * (AlignedScaling3(v0) * Translation3(v0));
276 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
277
278
279 t0.setIdentity();
280 t0.scale(s0).translate(v0);
281 t1 = Eigen::Scaling(s0) * Translation3(v0);
282 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
283 t0.prescale(s0);
284 t1 = Eigen::Scaling(s0) * t1;
285 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
286
287 t0 = t3;
288 t0.scale(s0);
289 t1 = t3 * Eigen::Scaling(s0,s0,s0);
290 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
291 t0.prescale(s0);
292 t1 = Eigen::Scaling(s0,s0,s0) * t1;
293 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
294
295
296 t0.setIdentity();
297 t0.prerotate(q1).prescale(v0).pretranslate(v0);
298 // translation * aligned scaling and transformation * mat
299 t1 = (Translation3(v0) * AlignedScaling3(v0)) * Transform3(q1);
300 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
301 // scaling * mat and translation * mat
302 t1 = Translation3(v0) * (AlignedScaling3(v0) * Transform3(q1));
303 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
304
305 t0.setIdentity();
306 t0.scale(v0).translate(v0).rotate(q1);
307 // translation * mat and aligned scaling * transformation
308 t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1));
309 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
310 // transformation * aligned scaling
311 t0.scale(v0);
312 t1 *= AlignedScaling3(v0);
313 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
314 // transformation * translation
315 t0.translate(v0);
316 t1 = t1 * Translation3(v0);
317 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
318 // translation * transformation
319 t0.pretranslate(v0);
320 t1 = Translation3(v0) * t1;
321 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
322
323 // transform * quaternion
324 t0.rotate(q1);
325 t1 = t1 * q1;
326 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
327
328 // translation * quaternion
329 t0.translate(v1).rotate(q1);
330 t1 = t1 * (Translation3(v1) * q1);
331 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
332
333 // aligned scaling * quaternion
334 t0.scale(v1).rotate(q1);
335 t1 = t1 * (AlignedScaling3(v1) * q1);
336 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
337
338 // quaternion * transform
339 t0.prerotate(q1);
340 t1 = q1 * t1;
341 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
342
343 // quaternion * translation
344 t0.rotate(q1).translate(v1);
345 t1 = t1 * (q1 * Translation3(v1));
346 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
347
348 // quaternion * aligned scaling
349 t0.rotate(q1).scale(v1);
350 t1 = t1 * (q1 * AlignedScaling3(v1));
351 VERIFY_IS_APPROX(t0.matrix(), t1.matrix());
352
353 // test transform inversion
354 t0.setIdentity();
355 t0.translate(v0);
356 t0.linear().setRandom();
357 Matrix4 t044 = Matrix4::Zero();
358 t044(3,3) = 1;
359 t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
360 VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
361 t0.setIdentity();
362 t0.translate(v0).rotate(q1);
363 t044 = Matrix4::Zero();
364 t044(3,3) = 1;
365 t044.block(0,0,t0.matrix().rows(),4) = t0.matrix();
366 VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t044.inverse().block(0,0,t0.matrix().rows(),4));
367
368 Matrix3 mat_rotation, mat_scaling;
369 t0.setIdentity();
370 t0.translate(v0).rotate(q1).scale(v1);
371 t0.computeRotationScaling(&mat_rotation, &mat_scaling);
372 VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling);
373 VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
374 VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
375 t0.computeScalingRotation(&mat_scaling, &mat_rotation);
376 VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation);
377 VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity());
378 VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1));
379
380 // test casting
381 Transform<float,3,Mode> t1f = t1.template cast<float>();
382 VERIFY_IS_APPROX(t1f.template cast<Scalar>(),t1);
383 Transform<double,3,Mode> t1d = t1.template cast<double>();
384 VERIFY_IS_APPROX(t1d.template cast<Scalar>(),t1);
385
386 Translation3 tr1(v0);
387 Translation<float,3> tr1f = tr1.template cast<float>();
388 VERIFY_IS_APPROX(tr1f.template cast<Scalar>(),tr1);
389 Translation<double,3> tr1d = tr1.template cast<double>();
390 VERIFY_IS_APPROX(tr1d.template cast<Scalar>(),tr1);
391
392 AngleAxis<float> aa1f = aa1.template cast<float>();
393 VERIFY_IS_APPROX(aa1f.template cast<Scalar>(),aa1);
394 AngleAxis<double> aa1d = aa1.template cast<double>();
395 VERIFY_IS_APPROX(aa1d.template cast<Scalar>(),aa1);
396
397 Rotation2D<Scalar> r2d1(internal::random<Scalar>());
398 Rotation2D<float> r2d1f = r2d1.template cast<float>();
399 VERIFY_IS_APPROX(r2d1f.template cast<Scalar>(),r2d1);
400 Rotation2D<double> r2d1d = r2d1.template cast<double>();
401 VERIFY_IS_APPROX(r2d1d.template cast<Scalar>(),r2d1);
402
403 t20 = Translation2(v20) * (Rotation2D<Scalar>(s0) * Scaling(s0));
404 t21 = Translation2(v20) * Rotation2D<Scalar>(s0) * Scaling(s0);
405 VERIFY_IS_APPROX(t20,t21);
406 }
407
transform_alignment()408 template<typename Scalar> void transform_alignment()
409 {
410 typedef Transform<Scalar,3,Projective,AutoAlign> Projective3a;
411 typedef Transform<Scalar,3,Projective,DontAlign> Projective3u;
412
413 EIGEN_ALIGN16 Scalar array1[16];
414 EIGEN_ALIGN16 Scalar array2[16];
415 EIGEN_ALIGN16 Scalar array3[16+1];
416 Scalar* array3u = array3+1;
417
418 Projective3a *p1 = ::new(reinterpret_cast<void*>(array1)) Projective3a;
419 Projective3u *p2 = ::new(reinterpret_cast<void*>(array2)) Projective3u;
420 Projective3u *p3 = ::new(reinterpret_cast<void*>(array3u)) Projective3u;
421
422 p1->matrix().setRandom();
423 *p2 = *p1;
424 *p3 = *p1;
425
426 VERIFY_IS_APPROX(p1->matrix(), p2->matrix());
427 VERIFY_IS_APPROX(p1->matrix(), p3->matrix());
428
429 VERIFY_IS_APPROX( (*p1) * (*p1), (*p2)*(*p3));
430
431 #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY
432 if(internal::packet_traits<Scalar>::Vectorizable)
433 VERIFY_RAISES_ASSERT((::new(reinterpret_cast<void*>(array3u)) Projective3a));
434 #endif
435 }
436
transform_products()437 template<typename Scalar, int Dim, int Options> void transform_products()
438 {
439 typedef Matrix<Scalar,Dim+1,Dim+1> Mat;
440 typedef Transform<Scalar,Dim,Projective,Options> Proj;
441 typedef Transform<Scalar,Dim,Affine,Options> Aff;
442 typedef Transform<Scalar,Dim,AffineCompact,Options> AffC;
443
444 Proj p; p.matrix().setRandom();
445 Aff a; a.linear().setRandom(); a.translation().setRandom();
446 AffC ac = a;
447
448 Mat p_m(p.matrix()), a_m(a.matrix());
449
450 VERIFY_IS_APPROX((p*p).matrix(), p_m*p_m);
451 VERIFY_IS_APPROX((a*a).matrix(), a_m*a_m);
452 VERIFY_IS_APPROX((p*a).matrix(), p_m*a_m);
453 VERIFY_IS_APPROX((a*p).matrix(), a_m*p_m);
454 VERIFY_IS_APPROX((ac*a).matrix(), a_m*a_m);
455 VERIFY_IS_APPROX((a*ac).matrix(), a_m*a_m);
456 VERIFY_IS_APPROX((p*ac).matrix(), p_m*a_m);
457 VERIFY_IS_APPROX((ac*p).matrix(), a_m*p_m);
458 }
459
test_geo_transformations()460 void test_geo_transformations()
461 {
462 for(int i = 0; i < g_repeat; i++) {
463 CALL_SUBTEST_1(( transformations<double,Affine,AutoAlign>() ));
464 CALL_SUBTEST_1(( non_projective_only<double,Affine,AutoAlign>() ));
465
466 CALL_SUBTEST_2(( transformations<float,AffineCompact,AutoAlign>() ));
467 CALL_SUBTEST_2(( non_projective_only<float,AffineCompact,AutoAlign>() ));
468 CALL_SUBTEST_2(( transform_alignment<float>() ));
469
470 CALL_SUBTEST_3(( transformations<double,Projective,AutoAlign>() ));
471 CALL_SUBTEST_3(( transformations<double,Projective,DontAlign>() ));
472 CALL_SUBTEST_3(( transform_alignment<double>() ));
473
474 CALL_SUBTEST_4(( transformations<float,Affine,RowMajor|AutoAlign>() ));
475 CALL_SUBTEST_4(( non_projective_only<float,Affine,RowMajor>() ));
476
477 CALL_SUBTEST_5(( transformations<double,AffineCompact,RowMajor|AutoAlign>() ));
478 CALL_SUBTEST_5(( non_projective_only<double,AffineCompact,RowMajor>() ));
479
480 CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|AutoAlign>() ));
481 CALL_SUBTEST_6(( transformations<double,Projective,RowMajor|DontAlign>() ));
482
483
484 CALL_SUBTEST_7(( transform_products<double,3,RowMajor|AutoAlign>() ));
485 CALL_SUBTEST_7(( transform_products<float,2,AutoAlign>() ));
486 }
487 }
488