1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18
19 /**
20 *
21 * This program illustrates the use of Versors
22 *
23 * Versors are Unit Quaternions used to represent
24 * rotations.
25 *
26 */
27
28 #include "itkVersor.h"
29 #include <iostream>
30
TestCreateRotationMatrixFromAngles(const double alpha,const double beta,const double gamma)31 itk::Matrix<double,3,3> TestCreateRotationMatrixFromAngles(const double alpha, const double beta, const double gamma)
32 {
33 //alpha is rotate the X axis -- Attitude
34 //beta is rotate the Y axis -- Bank
35 //gamma is rotate the Z axis -- Heading
36 const double ca=std::cos(alpha);
37 const double sa=std::sin(alpha);
38 const double cb=std::cos(beta);
39 const double sb=std::sin(beta);
40 const double cg=std::cos(gamma);
41 const double sg=std::sin(gamma);
42
43 itk::Matrix<double,3,3> R;
44
45 R(0,0)=cb*cg; R(0,1)=-ca*sg+sa*sb*cg; R(0,2)=sa*sg+ca*sb*cg;
46 R(1,0)=cb*sg; R(1,1)=ca*cg+sa*sb*sg; R(1,2)=-sa*cg+ca*sb*sg;
47 R(2,0)=-sb; R(2,1)=sa*cb; R(2,2)=ca*cb;
48 itk::Matrix<double,3,3>::InternalMatrixType test =
49 R.GetVnlMatrix() * R.GetTranspose();
50 if( !test.is_identity( 1.0e-10 ) )
51 {
52 std::cout << "Computed matrix is not orthogonal!!!" << std::endl;
53 std::cout << R << std::endl;
54 }
55 return R;
56 }
57
58
TestCreateRotationVersorFromAngles(const double alpha,const double beta,const double gamma)59 itk::Versor<double> TestCreateRotationVersorFromAngles(const double alpha, const double beta, const double gamma)
60 {
61 //http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
62 //psi = alpha is rotate the X axis -- Attitude
63 //theta= beta is rotate the Y axis -- Bank
64 //phi= gamma is rotate the Z axis -- Heading
65 const double cha=std::cos(alpha*0.5);
66 const double chb=std::cos(beta*0.5);
67 const double chg=std::cos(gamma*0.5);
68 const double sha=std::sin(alpha*0.5);
69 const double shb=std::sin(beta*0.5);
70 const double shg=std::sin(gamma*0.5);
71
72 vnl_vector_fixed<double,4> q;
73 q[0]=cha*chb*chg+sha*shb*shg;
74 q[1]=sha*chb*chg-cha*shb*shg;
75 q[2]=cha*shb*chg+sha*chb*shg;
76 q[3]=cha*chb*shg-sha*shb*chg;
77
78 itk::Versor<double> v;
79 v.Set(q[1],q[2],q[3],q[0]);
80 std::cout << "versor: " << v << std::endl;
81 return v;
82 }
83
84 /**
85 * This test that the conversion to and from Rotation Matrix and
86 * Versor produces consistent results.
87 */
RotationMatrixToVersorTest()88 int RotationMatrixToVersorTest()
89 {
90 int errorCount=0;
91 //const double onedegree=1e-10*itk::Math::pi/180.0;
92 const double onedegree=itk::Math::pi/180.0;
93 //const double td=180.0/itk::Math::pi;
94 double centers[6];
95 centers[0]=0;
96 centers[1]=itk::Math::pi*0.25;
97 centers[2]=itk::Math::pi*0.5;
98 centers[3]=itk::Math::pi;
99 centers[4]=itk::Math::pi*1.5;
100 centers[5]=itk::Math::pi*2.0;
101
102 constexpr double steps = 0;
103 const double small_degree_steps=onedegree/1000.0; //1/1000 of a degree
104 for(double center : centers)
105 {
106 for(double alpha=center-steps*small_degree_steps; alpha <= center+steps*small_degree_steps; alpha += small_degree_steps)
107 {
108 for(double beta=center-steps*small_degree_steps; beta <= center+steps*small_degree_steps; beta += small_degree_steps)
109 {
110 for(double gamma=center-steps*small_degree_steps; gamma <= center+steps*small_degree_steps; gamma += small_degree_steps)
111 {
112 itk::Matrix<double,3,3> MR=TestCreateRotationMatrixFromAngles(alpha, beta, gamma);
113 itk::Versor<double> VR=TestCreateRotationVersorFromAngles(alpha, beta, gamma);
114
115 itk::Point<double,3> testPoint;
116 testPoint[0]=-1020.27;
117 testPoint[1]=3.21;
118 testPoint[2]=1000.786432;
119
120 itk::Versor<double> VFROMMR;
121 VFROMMR.Set(MR);
122 itk::Matrix<double,3,3> VRMatrix = VR.GetMatrix();
123 const itk::Point<double,3> newMRtestPoint=(MR)*testPoint;
124 const itk::Point<double,3> newVRtestPoint=(VRMatrix)*testPoint;
125
126 const itk::Point<double,3> newVRFROMMRPoint=(VFROMMR.GetMatrix())*testPoint;
127 const itk::Point<double,3> newVRFROMMRTransformPoint=VFROMMR.Transform(testPoint);
128
129 const double error_newMRtestPoint_newVRtestPoint=(newMRtestPoint-newVRtestPoint).GetNorm();
130 const double error_newMRtestPoint_newVRFROMMRPoint=(newMRtestPoint-newVRFROMMRPoint).GetNorm();
131 const double error_newVRFROMMRPoint_newVRFROMMRTransformPoint=(newVRFROMMRPoint-newVRFROMMRTransformPoint).GetNorm();
132
133 const double maxAllowedPointError=1e-5;
134 if( ( error_newMRtestPoint_newVRtestPoint + error_newMRtestPoint_newVRFROMMRPoint
135 + error_newVRFROMMRPoint_newVRFROMMRTransformPoint) > maxAllowedPointError)
136 {
137 std::cout << "(alpha,beta,gamma)= (" << alpha << ","<< beta << "," << gamma << ")" << std::endl;
138
139 std::cout << newMRtestPoint << " " << newVRtestPoint << " " << newVRFROMMRPoint << " " << newVRFROMMRTransformPoint << std::endl;
140 std::cout << "ERRORS: " << error_newMRtestPoint_newVRtestPoint << " "
141 << error_newMRtestPoint_newVRFROMMRPoint << " "
142 << error_newVRFROMMRPoint_newVRFROMMRTransformPoint << std::endl;
143 std::cout << "MR=\n"<< MR << "\nVR=\n" << VR.GetMatrix() << "\nVFROMMR=\n" << VFROMMR.GetMatrix() << std::endl;
144 errorCount++;
145 }
146
147 }
148 }
149 }
150 }
151 return errorCount;
152 }
153
154 //-------------------------
155 //
156 // Main code
157 //
158 //-------------------------
itkVersorTest(int,char * [])159 int itkVersorTest(int, char* [] )
160 {
161
162 using ValueType = double;
163
164 const ValueType epsilon = 1e-12;
165
166 // Versor type
167 using VersorType = itk::Versor< ValueType >;
168
169 // Vector type
170 using VectorType = VersorType::VectorType;
171
172 // Point type
173 using PointType = VersorType::PointType;
174
175 // Covariant Vector type
176 using CovariantVectorType = VersorType::CovariantVectorType;
177
178 // VnlVector type
179 using VnlVectorType = VersorType::VnlVectorType;
180
181 // VnlQuaternion type
182 using VnlQuaternionType = VersorType::VnlQuaternionType;
183
184 // Matrix type
185 using MatrixType = VersorType::MatrixType;
186
187 {
188 std::cout << "Test default constructor... ";
189 VersorType qa;
190 if( std::abs(qa.GetX()) > epsilon )
191 {
192 std::cout << "Error ! " << std::endl;
193 return EXIT_FAILURE;
194 }
195 if( std::abs(qa.GetY()) > epsilon )
196 {
197 std::cout << "Error ! " << std::endl;
198 return EXIT_FAILURE;
199 }
200 if( std::abs(qa.GetZ()) > epsilon )
201 {
202 std::cout << "Error ! " << std::endl;
203 return EXIT_FAILURE;
204 }
205 if( std::abs(qa.GetW()-1.0) > epsilon )
206 {
207 std::cout << "Error ! " << std::endl;
208 return EXIT_FAILURE;
209 }
210 std::cout << " PASSED !" << std::endl;
211 }
212
213
214 {
215 std::cout << "Test initialization and GetMatrix()... ";
216 VersorType qa;
217 qa.SetIdentity();
218 MatrixType ma = qa.GetMatrix();
219 std::cout << "Matrix = " << std::endl;
220 std::cout << ma << std::endl;
221 }
222
223 {
224 std::cout << "Test for setting Axis (0,0,0) and Angle...";
225 VersorType qa;
226 VectorType xa;
227 xa[0] = 0.0;
228 xa[1] = 0.0;
229 xa[2] = 0.0;
230 ValueType angle = 0;
231 try
232 {
233 qa.Set( xa, angle );
234 return EXIT_FAILURE;
235 } //setting the axis to (0,0,0) should throw an exception
236 catch(itk::ExceptionObject &excp)
237 {
238 std::cout << "Caught expected exception: " << excp;
239 std::cout << " PASSED !" << std::endl;
240 }
241 }
242
243 {
244 std::cout << "Test for setting Axis and Angle...";
245 VersorType qa;
246 VectorType xa;
247 xa[0] = 2.5;
248 xa[1] = 1.5;
249 xa[2] = 0.5;
250 ValueType angle = std::atan(1.0)/3.0; // 15 degrees in radians
251 qa.Set( xa, angle );
252
253 xa.Normalize();
254
255 ValueType cosangle = std::cos( angle / 2.0 );
256 ValueType sinangle = std::sin( angle / 2.0 );
257
258 VectorType xb;
259
260 xb = xa * sinangle;
261
262 if( std::abs(qa.GetX()-xb[0]) > epsilon )
263 {
264 std::cout << "Error in X ! " << std::endl;
265 return EXIT_FAILURE;
266 }
267 if( std::abs(qa.GetY()-xb[1]) > epsilon )
268 {
269 std::cout << "Error in Y ! " << std::endl;
270 return EXIT_FAILURE;
271 }
272 if( std::abs(qa.GetZ()-xb[2]) > epsilon )
273 {
274 std::cout << "Error in Z ! " << std::endl;
275 return EXIT_FAILURE;
276 }
277 if( std::abs(qa.GetW()-cosangle) > epsilon )
278 {
279 std::cout << "Error in W ! " << std::endl;
280 return EXIT_FAILURE;
281 }
282 if( std::abs(qa.GetAngle()-angle) > epsilon )
283 {
284 std::cout << "Error in Angle ! " << std::endl;
285 return EXIT_FAILURE;
286 }
287
288 std::cout << " PASSED !" << std::endl;
289 }
290
291 {
292 std::cout << "Test for setting Right part...";
293 ValueType angle = std::atan(1.0)*30.0/45.0;
294 ValueType sin2a = std::sin( angle/2.0 );
295
296 VectorType xa;
297 xa[0] = 0.7;
298 xa[1] = 0.3;
299 xa[2] = 0.1;
300
301 xa.Normalize();
302 xa *= sin2a;
303
304 VersorType qa;
305 qa.Set( xa, angle );
306 ValueType cos2a = std::cos( angle/2.0 );
307
308 if( std::abs(qa.GetW()-cos2a) > epsilon )
309 {
310 std::cout << "Error in W ! " << std::endl;
311 std::cout << "W= " << qa.GetW();
312 std::cout << " it should be " << cos2a << std::endl;
313 return EXIT_FAILURE;
314 }
315 if( std::abs(qa.GetAngle()-angle) > epsilon )
316 {
317 std::cout << "Error in Angle ! " << std::endl;
318 return EXIT_FAILURE;
319 }
320 std::cout << " PASSED !" << std::endl;
321 }
322
323 {
324 std::cout << "Test for Square Root...";
325
326 ValueType angle = std::atan(1.0)*30.0/45.0;
327 ValueType sin2a = std::sin( angle/2.0 );
328
329 VectorType xa;
330 xa[0] = 0.7;
331 xa[1] = 0.3;
332 xa[2] = 0.1;
333
334 xa.Normalize();
335 xa *= sin2a;
336
337 VersorType qa;
338 qa.Set( xa, angle );
339
340 VersorType qb;
341 qb = qa.SquareRoot();
342
343 if( std::abs( qa.GetAngle() - 2.0 * qb.GetAngle() ) > epsilon )
344 {
345 std::cout << "Error in Square Root ! " << std::endl;
346 std::cout << "Angle = " << qb.GetAngle();
347 std::cout << " it should be " << qa.GetAngle() / 2.0 << std::endl;
348 return EXIT_FAILURE;
349 }
350 std::cout << " PASSED !" << std::endl;
351 }
352
353 {
354 std::cout << "Test for Transforming a vector...";
355 VectorType xa;
356 xa[0] = 2.5;
357 xa[1] = 2.5;
358 xa[2] = 2.5;
359 ValueType angle = 8.0*std::atan(1.0)/3.0; // 120 degrees in radians
360
361 VersorType qa;
362 qa.Set( xa, angle );
363
364 VectorType::ValueType xbInit[3] = {3.0, 7.0, 9.0};
365 VectorType xb = xbInit;
366
367 VectorType xc= qa.Transform( xb );
368
369 // This rotation will just permute the axis
370 if( std::abs(xc[1]-xb[0]) > epsilon )
371 {
372 std::cout << "Error in X ! " << std::endl;
373 return EXIT_FAILURE;
374 }
375 if( std::abs(xc[2]-xb[1]) > epsilon )
376 {
377 std::cout << "Error in Y ! " << std::endl;
378 return EXIT_FAILURE;
379 }
380 if( std::abs(xc[0]-xb[2]) > epsilon )
381 {
382 std::cout << "Error in Z ! " << std::endl;
383 return EXIT_FAILURE;
384 }
385 std::cout << " PASSED !" << std::endl;
386 }
387
388 {
389 std::cout << "Test for Transforming a point...";
390 VectorType xa;
391 xa[0] = 2.5;
392 xa[1] = 2.5;
393 xa[2] = 2.5;
394 ValueType angle = 8.0*std::atan(1.0)/3.0; // 120 degrees in radians
395
396 VersorType qa;
397 qa.Set( xa, angle );
398
399 PointType::ValueType xbInit[3] = {3.0, 7.0, 9.0};
400 PointType xb = xbInit;
401
402 PointType xc = qa.Transform( xb );
403
404 // This rotation will just permute the axis
405 if( std::abs(xc[1]-xb[0]) > epsilon )
406 {
407 std::cout << "Error in X ! " << std::endl;
408 return EXIT_FAILURE;
409 }
410 if( std::abs(xc[2]-xb[1]) > epsilon )
411 {
412 std::cout << "Error in Y ! " << std::endl;
413 return EXIT_FAILURE;
414 }
415 if( std::abs(xc[0]-xb[2]) > epsilon )
416 {
417 std::cout << "Error in Z ! " << std::endl;
418 return EXIT_FAILURE;
419 }
420 std::cout << " PASSED !" << std::endl;
421 }
422
423
424 {
425 std::cout << "Test for Transforming a covariantvector...";
426 VectorType xa;
427 xa[0] = 2.5;
428 xa[1] = 2.5;
429 xa[2] = 2.5;
430 ValueType angle = 8.0*std::atan(1.0)/3.0; // 120 degrees in radians
431
432 VersorType qa;
433 qa.Set( xa, angle );
434
435 CovariantVectorType::ValueType xbInit[3] = {3.0, 7.0, 9.0};
436 CovariantVectorType xb = xbInit;
437
438 CovariantVectorType xc = qa.Transform( xb );
439
440 // This rotation will just permute the axis
441 if( std::abs(xc[1]-xb[0]) > epsilon )
442 {
443 std::cout << "Error in X ! " << std::endl;
444 return EXIT_FAILURE;
445 }
446 if( std::abs(xc[2]-xb[1]) > epsilon )
447 {
448 std::cout << "Error in Y ! " << std::endl;
449 return EXIT_FAILURE;
450 }
451 if( std::abs(xc[0]-xb[2]) > epsilon )
452 {
453 std::cout << "Error in Z ! " << std::endl;
454 return EXIT_FAILURE;
455 }
456 std::cout << " PASSED !" << std::endl;
457 }
458
459 {
460 std::cout << "Test for Transforming a vnl_vector...";
461 VectorType xa;
462 xa[0] = 2.5;
463 xa[1] = 2.5;
464 xa[2] = 2.5;
465 ValueType angle = 8.0*std::atan(1.0)/3.0; // 120 degrees in radians
466
467 VersorType qa;
468 qa.Set( xa, angle );
469
470 VnlVectorType xb;
471 xb[0] = 3.0;
472 xb[1] = 7.0;
473 xb[2] = 9.0;
474
475 VnlVectorType xc = qa.Transform( xb );
476
477 // This rotation will just permute the axis
478 if( std::abs(xc[1]-xb[0]) > epsilon )
479 {
480 std::cout << "Error in X ! " << std::endl;
481 return EXIT_FAILURE;
482 }
483 if( std::abs(xc[2]-xb[1]) > epsilon )
484 {
485 std::cout << "Error in Y ! " << std::endl;
486 return EXIT_FAILURE;
487 }
488 if( std::abs(xc[0]-xb[2]) > epsilon )
489 {
490 std::cout << "Error in Z ! " << std::endl;
491 return EXIT_FAILURE;
492 }
493 std::cout << " PASSED !" << std::endl;
494 }
495
496 {
497 std::cout << "Test for Set components operations ...";
498
499 // First, create a known versor
500 VectorType::ValueType x1Init[3] = {2.5f, 1.5f, 3.5f};
501 VectorType x1 = x1Init;
502
503 ValueType angle1 = std::atan(1.0)/3.0; // 15 degrees in radians
504
505 VersorType v1;
506 v1.Set( x1, angle1 );
507
508 // Get the components and scale them
509 ValueType scale = 5.5;
510 ValueType x = v1.GetX() * scale;
511 ValueType y = v1.GetY() * scale;
512 ValueType z = v1.GetZ() * scale;
513 ValueType w = v1.GetW() * scale;
514
515 VersorType v2;
516 v2.Set( x, y, z, w );
517
518 // Compare both versors
519 if( std::abs(v1.GetX() - v2.GetX() ) > epsilon ||
520 std::abs(v1.GetY() - v2.GetY() ) > epsilon ||
521 std::abs(v1.GetZ() - v2.GetZ() ) > epsilon ||
522 std::abs(v1.GetW() - v2.GetW() ) > epsilon )
523 {
524 std::cout << "Error in Versor Set(x,y,z,w) ! " << std::endl;
525 std::cout << "v1 = " << v1 << std::endl;
526 std::cout << "v2 = " << v2 << std::endl;
527 return EXIT_FAILURE;
528 }
529 std::cout << " PASSED !" << std::endl;
530
531 std::cout << "Test for Set quaternion ...";
532 // Get a vnl_quaternion
533 VnlQuaternionType vnlq = v1.GetVnlQuaternion();
534 vnlq *= scale;
535
536 v2.Set( vnlq );
537
538 // Compare both versors
539 if( std::abs(v1.GetX() - v2.GetX() ) > epsilon ||
540 std::abs(v1.GetY() - v2.GetY() ) > epsilon ||
541 std::abs(v1.GetZ() - v2.GetZ() ) > epsilon ||
542 std::abs(v1.GetW() - v2.GetW() ) > epsilon )
543 {
544 std::cout << "Error in Versor Set( vnl_quaternion ) ! " << std::endl;
545 std::cout << "v1 = " << v1 << std::endl;
546 std::cout << "v2 = " << v2 << std::endl;
547 return EXIT_FAILURE;
548 }
549 std::cout << " PASSED !" << std::endl;
550
551 std::cout << "Test for Set(x,y,z,w) with negative W.";
552 // Check that a negative W results in negating
553 // all the versor components.
554 x = - v1.GetX();
555 y = - v1.GetY();
556 z = - v1.GetZ();
557 w = - v1.GetW();
558
559 VersorType v3;
560 v3.Set( x, y, z, w );
561
562 // Compare both versors
563 if( std::abs( v1.GetX() - v3.GetX() ) > epsilon ||
564 std::abs( v1.GetY() - v3.GetY() ) > epsilon ||
565 std::abs( v1.GetZ() - v3.GetZ() ) > epsilon ||
566 std::abs( v1.GetW() - v3.GetW() ) > epsilon )
567 {
568 std::cout << "Error in Versor Set() with negative W ! " << std::endl;
569 std::cout << "v1 = " << v1 << std::endl;
570 std::cout << "v3 = " << v3 << std::endl;
571 return EXIT_FAILURE;
572 }
573 std::cout << " PASSED !" << std::endl;
574 }
575
576 {
577 std::cout << "Test for Reciprocal and Conjugate Operations...";
578
579 VectorType::ValueType x1Init[3] = {2.5f, 1.5f, 0.5f};
580 VectorType x1 = x1Init;
581
582 ValueType angle1 = std::atan(1.0)/3.0; // 15 degrees in radians
583
584 VectorType::ValueType x2Init[3] = {1.5f, 0.5f, 0.5f};
585 VectorType x2 = x2Init;
586
587 ValueType angle2 = std::atan(1.0)/1.0; // 45 degrees in radians
588
589 VersorType v1;
590 v1.Set( x1, angle1 );
591 VersorType v2;
592 v2.Set( x2, angle2 );
593
594 VersorType v2r = v2.GetReciprocal();
595 VersorType unit = v2 * v2r;
596
597 if( std::abs( unit.GetX() ) > epsilon ||
598 std::abs( unit.GetY() ) > epsilon ||
599 std::abs( unit.GetZ() ) > epsilon ||
600 std::abs( unit.GetW() - 1.0 ) > epsilon )
601 {
602 std::cout << "Error in Reciprocal ! " << std::endl;
603 std::cout << "Versor = " << v2 << std::endl;
604 std::cout << "Reciprocal = " << v2r << std::endl;
605 std::cout << "Product = " << unit << std::endl;
606
607 return EXIT_FAILURE;
608 }
609
610 unit = v2 / v2;
611
612 if( std::abs( unit.GetX() ) > epsilon ||
613 std::abs( unit.GetY() ) > epsilon ||
614 std::abs( unit.GetZ() ) > epsilon ||
615 std::abs( unit.GetW() - 1.0 ) > epsilon )
616 {
617 std::cout << "Error in Division ! " << std::endl;
618 std::cout << "Versor = " << v2 << std::endl;
619 std::cout << "Self Division = " << unit << std::endl;
620
621 return EXIT_FAILURE;
622 }
623
624 unit = v2;
625 unit /= v2;
626 if( std::abs( unit.GetX() ) > epsilon ||
627 std::abs( unit.GetY() ) > epsilon ||
628 std::abs( unit.GetZ() ) > epsilon ||
629 std::abs( unit.GetW() - 1.0 ) > epsilon )
630 {
631 std::cout << "Error in Division operator/= ! " << std::endl;
632 std::cout << "Versor = " << v2 << std::endl;
633 std::cout << "Self Division = " << unit << std::endl;
634
635 return EXIT_FAILURE;
636 }
637
638 x1.Normalize();
639 x2.Normalize();
640
641
642 VersorType v3= v1 * v2;
643 VersorType v4= v3 * v2r;
644
645 if( std::abs(v1.GetX() - v4.GetX() ) > epsilon ||
646 std::abs(v1.GetY() - v4.GetY() ) > epsilon ||
647 std::abs(v1.GetZ() - v4.GetZ() ) > epsilon ||
648 std::abs(v1.GetW() - v4.GetW() ) > epsilon )
649 {
650 std::cout << "Error in Versor division ! " << std::endl;
651 std::cout << "v1 = " << v1 << std::endl;
652 std::cout << "v1' = " << v4 << std::endl;
653 return EXIT_FAILURE;
654 }
655 std::cout << " PASSED !" << std::endl;
656 }
657
658
659 { // Test for the Set() matrix method
660 std::cout << "Test for Set( MatrixType ) method ..." << std::endl;
661 MatrixType mm;
662 // Setting the matrix of a 90 degrees rotation around Z
663 mm[0][0] = 0.0;
664 mm[0][1] = 1.0;
665 mm[0][2] = 0.0;
666
667 mm[1][0] = -1.0;
668 mm[1][1] = 0.0;
669 mm[1][2] = 0.0;
670
671 mm[2][0] = 0.0;
672 mm[2][1] = 0.0;
673 mm[2][2] = 1.0;
674
675 VersorType vv;
676 vv.Set( mm );
677
678 const double halfSqrtOfTwo = std::sqrt( 2.0 ) / 2.0;
679
680 if( std::abs(vv.GetX() - 0.0 ) > epsilon ||
681 std::abs(vv.GetY() - 0.0 ) > epsilon ||
682 std::abs(vv.GetZ() - (-halfSqrtOfTwo) ) > epsilon ||
683 std::abs(vv.GetW() - halfSqrtOfTwo ) > epsilon )
684 {
685 std::cout << "Error in Versor Set(Matrix) method ! " << std::endl;
686 std::cout << "vv = " << vv << std::endl;
687 return EXIT_FAILURE;
688 }
689 //matrix no longer represents a rotation
690 mm[0][0] = 1.0;
691 try
692 {
693 vv.Set( mm );
694 return EXIT_FAILURE;
695 } //should always get here, mm isn't a rotation
696 catch(itk::ExceptionObject &excp)
697 {
698 std::cout << "Caught expected exception: " << excp;
699 }
700 std::cout << " PASSED !" << std::endl;
701 }
702 {
703 std::cout << "Test for Set( MatrixType ) method with rotations that are susceptible to errors in conversion to/from the rotation matrix...";
704
705 const int RotationMatrixStabilityTestErrors=RotationMatrixToVersorTest();
706 if( RotationMatrixStabilityTestErrors > 0 )
707 {
708 std::cout << "Error in stability of converting to/from RotationMatrix with Set(Matrix) method ! " << std::endl;
709 std::cout << "Errors Found = " << RotationMatrixStabilityTestErrors << std::endl;
710 return EXIT_FAILURE;
711 }
712 std::cout << " PASSED !" << std::endl;
713
714 }
715
716 return EXIT_SUCCESS;
717
718 }
719