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