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 #ifndef itkVersor_hxx
19 #define itkVersor_hxx
20 
21 #include "itkVersor.h"
22 #include "itkNumericTraits.h"
23 #include "itkMath.h"
24 #include <vnl/vnl_det.h>
25 
26 namespace itk
27 {
28 /** Constructor to initialize entire vector to one value. */
29 template< typename T >
30 Versor< T >
Versor()31 ::Versor() :
32   m_X(NumericTraits< T >::ZeroValue()),
33   m_Y(NumericTraits< T >::ZeroValue()),
34   m_Z(NumericTraits< T >::ZeroValue()),
35   m_W(NumericTraits< T >::OneValue())
36 {}
37 
38 /** Copy Constructor */
39 template< typename T >
40 Versor< T >
Versor(const Self & v)41 ::Versor(const Self & v)
42 {
43   m_X = v.m_X;
44   m_Y = v.m_Y;
45   m_Z = v.m_Z;
46   m_W = v.m_W;
47 }
48 
49 /** Assignment Operator */
50 template< typename T >
51 const Versor< T > &
52 Versor< T >
operator =(const Self & v)53 ::operator=(const Self & v)
54 {
55   m_X = v.m_X;
56   m_Y = v.m_Y;
57   m_Z = v.m_Z;
58   m_W = v.m_W;
59   return *this;
60 }
61 
62 /** Set to an identity transform */
63 template< typename T >
64 void
65 Versor< T >
SetIdentity()66 ::SetIdentity()
67 {
68   m_X = NumericTraits< T >::ZeroValue();
69   m_Y = NumericTraits< T >::ZeroValue();
70   m_Z = NumericTraits< T >::ZeroValue();
71   m_W = NumericTraits< T >::OneValue();
72 }
73 
74 /** Return a vnl_quaternion */
75 template< typename T >
76 vnl_quaternion< T >
77 Versor< T >
GetVnlQuaternion() const78 ::GetVnlQuaternion() const
79 {
80   return vnl_quaternion< T >(m_X, m_Y, m_Z, m_W);
81 }
82 
83 /** Assignment and Composition Operator */
84 template< typename T >
85 const Versor< T > &
86 Versor< T >
operator *=(const Self & v)87 ::operator*=(const Self & v)
88 {
89   const double mx =  m_W * v.m_X - m_Z * v.m_Y + m_Y * v.m_Z + m_X * v.m_W;
90   const double my =  m_Z * v.m_X + m_W * v.m_Y - m_X * v.m_Z + m_Y * v.m_W;
91   const double mz = -m_Y * v.m_X + m_X * v.m_Y + m_W * v.m_Z + m_Z * v.m_W;
92   const double mw = -m_X * v.m_X - m_Y * v.m_Y - m_Z * v.m_Z + m_W * v.m_W;
93 
94   m_X = mx;
95   m_Y = my;
96   m_Z = mz;
97   m_W = mw;
98 
99   return *this;
100 }
101 
102 /** Composition Operator */
103 template< typename T >
104 Versor< T >
105 Versor< T >
operator *(const Self & v) const106 ::operator*(const Self & v) const
107 {
108   Self result;
109 
110   result.m_X =  m_W * v.m_X - m_Z * v.m_Y + m_Y * v.m_Z + m_X * v.m_W;
111   result.m_Y =  m_Z * v.m_X + m_W * v.m_Y - m_X * v.m_Z + m_Y * v.m_W;
112   result.m_Z = -m_Y * v.m_X + m_X * v.m_Y + m_W * v.m_Z + m_Z * v.m_W;
113   result.m_W = -m_X * v.m_X - m_Y * v.m_Y - m_Z * v.m_Z + m_W * v.m_W;
114 
115   return result;
116 }
117 
118 /** Division and Assignment Operator */
119 template< typename T >
120 const Versor< T > &
121 Versor< T >
operator /=(const Self & v)122 ::operator/=(const Self & v)
123 {
124   const double mx = -m_W * v.m_X + m_Z * v.m_Y - m_Y * v.m_Z + m_X * v.m_W;
125   const double my = -m_Z * v.m_X - m_W * v.m_Y + m_X * v.m_Z + m_Y * v.m_W;
126   const double mz =  m_Y * v.m_X - m_X * v.m_Y - m_W * v.m_Z + m_Z * v.m_W;
127   const double mw =  m_X * v.m_X + m_Y * v.m_Y + m_Z * v.m_Z + m_W * v.m_W;
128 
129   m_X = mx;
130   m_Y = my;
131   m_Z = mz;
132   m_W = mw;
133 
134   return *this;
135 }
136 
137 /** Division Operator  */
138 template< typename T >
139 Versor< T >
140 Versor< T >
operator /(const Self & v) const141 ::operator/(const Self & v) const
142 {
143   Self result;
144 
145   result.m_X = -m_W * v.m_X + m_Z * v.m_Y - m_Y * v.m_Z + m_X * v.m_W;
146   result.m_Y = -m_Z * v.m_X - m_W * v.m_Y + m_X * v.m_Z + m_Y * v.m_W;
147   result.m_Z =  m_Y * v.m_X - m_X * v.m_Y - m_W * v.m_Z + m_Z * v.m_W;
148   result.m_W =  m_X * v.m_X + m_Y * v.m_Y + m_Z * v.m_Z + m_W * v.m_W;
149 
150   return result;
151 }
152 
153 /** Comparison operator */
154 template< typename T >
155 bool
156 Versor< T >
operator !=(const Self & v) const157 ::operator!=(const Self & v) const
158 {
159   return !( *this == v );
160 }
161 
162 /** Comparison operator */
163 template< typename T >
164 bool
165 Versor< T >
operator ==(const Self & v) const166 ::operator==(const Self & v) const
167 {
168   // Evaluate the quaternion ratio between them
169   Self ratio = *this * v.GetReciprocal();
170 
171   const typename itk::NumericTraits< T >::AccumulateType
172   square = ratio.m_W * ratio.m_W;
173 
174   const double epsilon = 1e-300;
175 
176   if ( std::fabs(1.0f - square) < epsilon )
177     {
178     return true;
179     }
180 
181   return false;
182 }
183 
184 /** Get Conjugate */
185 template< typename T >
186 Versor< T >
187 Versor< T >
GetConjugate() const188 ::GetConjugate() const
189 {
190   Self result;
191 
192   result.m_X = -m_X;
193   result.m_Y = -m_Y;
194   result.m_Z = -m_Z;
195   result.m_W =  m_W;
196 
197   return result;
198 }
199 
200 /** Get Reciprocal */
201 template< typename T >
202 Versor< T >
203 Versor< T >
GetReciprocal() const204 ::GetReciprocal() const
205 {
206   Self result;
207 
208   result.m_X = -m_X;
209   result.m_Y = -m_Y;
210   result.m_Z = -m_Z;
211   result.m_W =  m_W;
212 
213   return result;
214 }
215 
216 /** Get Tensor part */
217 template< typename T >
218 typename Versor< T >::ValueType
219 Versor< T >
GetTensor() const220 ::GetTensor() const
221 {
222   const auto tensor = static_cast< ValueType >(
223       std::sqrt(m_X * m_X + m_Y * m_Y + m_Z * m_Z + m_W * m_W) );
224 
225   return tensor;
226 }
227 
228 /** Normalize */
229 template< typename T >
230 void
231 Versor< T >
Normalize()232 ::Normalize()
233 {
234   const ValueType tensor = this->GetTensor();
235 
236   if ( std::fabs(tensor) < 1e-20 )
237     {
238     ExceptionObject except;
239     except.SetDescription("Attempt to normalize a \
240                            itk::Versor with zero tensor");
241     except.SetLocation(__FILE__);
242     throw except;
243     }
244   m_X /= tensor;
245   m_Y /= tensor;
246   m_Z /= tensor;
247   m_W /= tensor;
248 }
249 
250 /** Get Axis */
251 template< typename T >
252 typename Versor< T >::VectorType
253 Versor< T >
GetAxis() const254 ::GetAxis() const
255 {
256   VectorType axis;
257 
258   const auto ax = static_cast< RealType >( m_X );
259   const auto ay = static_cast< RealType >( m_Y );
260   const auto az = static_cast< RealType >( m_Z );
261 
262   const RealType vectorNorm = std::sqrt(ax * ax  +  ay * ay  +  az * az);
263 
264   if ( vectorNorm == NumericTraits< RealType >::ZeroValue() )
265     {
266     axis[0] = NumericTraits< T >::ZeroValue();
267     axis[1] = NumericTraits< T >::ZeroValue();
268     axis[2] = NumericTraits< T >::ZeroValue();
269     }
270   else
271     {
272     axis[0] = m_X / vectorNorm;
273     axis[1] = m_Y / vectorNorm;
274     axis[2] = m_Z / vectorNorm;
275     }
276 
277   return axis;
278 }
279 
280 /** Get Right part */
281 template< typename T >
282 typename Versor< T >::VectorType
283 Versor< T >
GetRight() const284 ::GetRight() const
285 {
286   VectorType axis;
287 
288   axis[0] = m_X;
289   axis[1] = m_Y;
290   axis[2] = m_Z;
291 
292   return axis;
293 }
294 
295 /** Get Scalar part */
296 template< typename T >
297 typename Versor< T >::ValueType
298 Versor< T >
GetScalar() const299 ::GetScalar() const
300 {
301   return m_W;
302 }
303 
304 /** Get Angle (in radians) */
305 template< typename T >
306 typename Versor< T >::ValueType
307 Versor< T >
GetAngle() const308 ::GetAngle() const
309 {
310   const auto ax = static_cast< RealType >( m_X );
311   const auto ay = static_cast< RealType >( m_Y );
312   const auto az = static_cast< RealType >( m_Z );
313 
314   const RealType vectorNorm = std::sqrt(ax * ax  +  ay * ay  +  az * az);
315 
316   const ValueType angle = 2.0 * std::atan2( vectorNorm, static_cast< RealType >( m_W ) );
317 
318   return angle;
319 }
320 
321 /** Get the Square root of the unit quaternion */
322 template< typename T >
323 Versor< T >
324 Versor< T >
SquareRoot() const325 ::SquareRoot() const
326 {
327   const ValueType newScalar = std::sqrt( static_cast< double >( 1.0 + m_W ) );
328   const double    sqrtOfTwo    = std::sqrt(2.0f);
329 
330   const double factor = 1.0f / ( newScalar * sqrtOfTwo );
331 
332   Self result;
333 
334   result.m_X = m_X * factor;
335   result.m_Y = m_Y * factor;
336   result.m_Z = m_Z * factor;
337   result.m_W = newScalar / sqrtOfTwo;
338 
339   return result;
340 }
341 
342 /** Compute the Exponential of the quaternion */
343 template< typename T >
344 Versor< T >
345 Versor< T >
Exponential(ValueType exponent) const346 ::Exponential(ValueType exponent) const
347 {
348   Self result;
349 
350   result.Set(this->GetAxis(),
351              this->GetAngle() * exponent);
352 
353   return result;
354 }
355 
356 /** Set Axis and Angle (in radians) */
357 template< typename T >
358 void
359 Versor< T >
Set(const VectorType & axis,ValueType angle)360 ::Set(const VectorType & axis, ValueType angle)
361 {
362   const RealType vectorNorm = axis.GetNorm();
363   if ( Math::FloatAlmostEqual<T>(vectorNorm, 0.0) )
364     {
365     ExceptionObject except;
366     except.SetDescription("Attempt to set rotation axis with zero norm");
367     except.SetLocation(__FILE__);
368     throw except;
369     }
370 
371   const RealType cosangle2 = std::cos(angle / 2.0);
372   const RealType sinangle2 = std::sin(angle / 2.0);
373 
374   const RealType factor = sinangle2 / vectorNorm;
375 
376   m_X = axis[0] * factor;
377   m_Y = axis[1] * factor;
378   m_Z = axis[2] * factor;
379 
380   m_W = cosangle2;
381 }
382 
383 /**  Set using an orthogonal matrix. */
384 template< typename T >
385 void
386 Versor< T >
Set(const MatrixType & mat)387 ::Set(const MatrixType & mat)
388 {
389   //const double epsilon = 1e-30;
390   //Keep the epsilon value large enough so that the alternate routes of
391   //computing the quaternion are used to within floating point precision of the
392   //math to be used.  Using 1e-30 results in degenerate matries for rotations
393   //near itk::Math::pi due to imprecision of the math.  0.5/std::sqrt(trace) is
394   //not accurate to 1e-30, so the resulting matrices would have very large
395   //errors.  By decreasing this epsilon value to a higher tolerance, the
396   //alternate stable methods for conversion are used.
397   //
398   //The use of std::numeric_limits< T >::epsilon() was not consistent with
399   //the rest of the ITK toolkit with respect to epsilon values for
400   //determining rotational orthogonality, and it occasionally
401   //prevented the conversion between different rigid transform types.
402 
403   const T epsilon = Self::Epsilon(); // vnl_sqrt( std::numeric_limits< T >::epsilon() );
404   // Use a slightly less epsilon for detecting difference
405   const T epsilonDiff = Self::Epsilon(); //std::numeric_limits< T >::epsilon() * 10.0;
406 
407   const vnl_matrix< T > m( mat.GetVnlMatrix() );
408 
409   //check for orthonormality and that it isn't a reflection
410   const vnl_matrix_fixed< T, 3, 3 > & I = m*m.transpose();
411   if( std::abs( I[0][1] ) > epsilon || std::abs( I[0][2] ) > epsilon ||
412     std::abs( I[1][0] ) > epsilon || std::abs( I[1][2] ) > epsilon ||
413     std::abs( I[2][0] ) > epsilon || std::abs( I[2][1] ) > epsilon ||
414     std::abs( I[0][0] - itk::NumericTraits<T>::OneValue() ) > epsilonDiff ||
415     std::abs( I[1][1] - itk::NumericTraits<T>::OneValue() ) > epsilonDiff ||
416     std::abs( I[2][2] - itk::NumericTraits<T>::OneValue() ) > epsilonDiff ||
417     vnl_det( I ) < 0 )
418     {
419     itkGenericExceptionMacro(<< "The following matrix does not represent rotation to within an epsion of "
420       << epsilon << "." << std::endl
421       << m << std::endl
422       << "det(m * m transpose) is: " << vnl_det(I) << std::endl
423       << "m * m transpose is:" << std::endl
424       << I << std::endl);
425     }
426 
427   const double trace = m(0, 0) + m(1, 1) + m(2, 2) + 1.0;
428 
429   if ( trace > epsilon )
430     {
431     const double s = 0.5 / std::sqrt(trace);
432     m_W = 0.25 / s;
433     m_X = ( m(2, 1) - m(1, 2) ) * s;
434     m_Y = ( m(0, 2) - m(2, 0) ) * s;
435     m_Z = ( m(1, 0) - m(0, 1) ) * s;
436     }
437   else
438     {
439     if ( m(0, 0) > m(1, 1) && m(0, 0) > m(2, 2) )
440       {
441       const double s = 2.0 * std::sqrt( 1.0 + m(0, 0) - m(1, 1) - m(2, 2) );
442       m_X = 0.25 * s;
443       m_Y = ( m(0, 1) + m(1, 0) ) / s;
444       m_Z = ( m(0, 2) + m(2, 0) ) / s;
445       m_W = ( m(1, 2) - m(2, 1) ) / s;
446       }
447     else
448       {
449       if ( m(1, 1) > m(2, 2) )
450         {
451         const double s = 2.0 * std::sqrt( 1.0 + m(1, 1) - m(0, 0) - m(2, 2) );
452         m_X = ( m(0, 1) + m(1, 0) ) / s;
453         m_Y = 0.25 * s;
454         m_Z = ( m(1, 2) + m(2, 1) ) / s;
455         m_W = ( m(0, 2) - m(2, 0) ) / s;
456         }
457       else
458         {
459         const double s = 2.0 * std::sqrt( 1.0 + m(2, 2) - m(0, 0) - m(1, 1) );
460         m_X = ( m(0, 2) + m(2, 0) ) / s;
461         m_Y = ( m(1, 2) + m(2, 1) ) / s;
462         m_Z = 0.25 * s;
463         m_W = ( m(0, 1) - m(1, 0) ) / s;
464         }
465       }
466     }
467   this->Normalize();
468 }
469 
470 /** Set right Part (in radians) */
471 template< typename T >
472 void
473 Versor< T >
Set(const VectorType & axis)474 ::Set(const VectorType & axis)
475 {
476   const ValueType sinangle2 =  axis.GetNorm();
477   if ( sinangle2 > NumericTraits< ValueType >::OneValue() )
478     {
479     ExceptionObject exception;
480     exception.SetDescription("Trying to initialize a Versor with " \
481                              "a vector whose magnitude is greater than 1");
482     exception.SetLocation("itk::Versor::Set( const VectorType )");
483     throw exception;
484     }
485 
486   const ValueType cosangle2 =  std::sqrt(NumericTraits< double >::OneValue() - sinangle2 * sinangle2);
487 
488   m_X = axis[0];
489   m_Y = axis[1];
490   m_Z = axis[2];
491 
492   m_W = cosangle2;
493 }
494 
495 /** Set the Versor from four components.
496  *  After assignment, the quaternion is normalized
497  *  in order to get a consistent Versor (unit quaternion). */
498 template< typename T >
499 void
500 Versor< T >
Set(T x,T y,T z,T w)501 ::Set(T x, T y, T z, T w)
502 {
503   //
504   // We assume in this class that the W component is always non-negative.
505   // The rotation represented by a Versor remains unchanged if all its
506   // four components are negated simultaneously. Therefore, if we are
507   // requested to initialize a Versor with a negative W, we negate the
508   // signs of all the components.
509   //
510   if ( w < 0.0 )
511     {
512     m_X = -x;
513     m_Y = -y;
514     m_Z = -z;
515     m_W = -w;
516     }
517   else
518     {
519     m_X = x;
520     m_Y = y;
521     m_Z = z;
522     m_W = w;
523     }
524   this->Normalize();
525 }
526 
527 /** Set from a vnl_quaternion
528  *  After assignment, the quaternion is normalized
529  *  in order to get a consistent Versor (unit quaternion). */
530 template< typename T >
531 void
532 Versor< T >
Set(const VnlQuaternionType & quaternion)533 ::Set(const VnlQuaternionType & quaternion)
534 {
535   m_X = quaternion.x();
536   m_Y = quaternion.y();
537   m_Z = quaternion.z();
538   m_W = quaternion.r();
539   this->Normalize();
540 }
541 
542 /** Set rotation around X axis */
543 template< typename T >
544 void
545 Versor< T >
SetRotationAroundX(ValueType angle)546 ::SetRotationAroundX(ValueType angle)
547 {
548   const ValueType sinangle2 = std::sin(angle / 2.0);
549   const ValueType cosangle2 = std::cos(angle / 2.0);
550 
551   m_X = sinangle2;
552   m_Y = NumericTraits< T >::ZeroValue();
553   m_Z = NumericTraits< T >::ZeroValue();
554   m_W = cosangle2;
555 }
556 
557 /** Set rotation around Y axis  */
558 template< typename T >
559 void
560 Versor< T >
SetRotationAroundY(ValueType angle)561 ::SetRotationAroundY(ValueType angle)
562 {
563   const ValueType sinangle2 = std::sin(angle / 2.0);
564   const ValueType cosangle2 = std::cos(angle / 2.0);
565 
566   m_X = NumericTraits< T >::ZeroValue();
567   m_Y = sinangle2;
568   m_Z = NumericTraits< T >::ZeroValue();
569   m_W = cosangle2;
570 }
571 
572 /**  Set rotation around Z axis  */
573 template< typename T >
574 void
575 Versor< T >
SetRotationAroundZ(ValueType angle)576 ::SetRotationAroundZ(ValueType angle)
577 {
578   const ValueType sinangle2 = std::sin(angle / 2.0);
579   const ValueType cosangle2 = std::cos(angle / 2.0);
580 
581   m_X = NumericTraits< T >::ZeroValue();
582   m_Y = NumericTraits< T >::ZeroValue();
583   m_Z = sinangle2;
584   m_W = cosangle2;
585 }
586 
587 namespace {
588   template< typename InputVectorType, typename ValueType, typename OutputVectorType >
localTransformVectorMath(const InputVectorType & VectorObject,const ValueType & inputX,const ValueType & inputY,const ValueType & inputZ,const ValueType & inputW)589     inline const OutputVectorType localTransformVectorMath(const InputVectorType & VectorObject,
590       const ValueType & inputX,
591       const ValueType & inputY,
592       const ValueType & inputZ,
593       const ValueType & inputW)
594       {
595       const ValueType xx = inputX * inputX;
596       const ValueType yy = inputY * inputY;
597       const ValueType zz = inputZ * inputZ;
598       const ValueType xy = inputX * inputY;
599       const ValueType xz = inputX * inputZ;
600       const ValueType xw = inputX * inputW;
601       const ValueType yz = inputY * inputZ;
602       const ValueType yw = inputY * inputW;
603       const ValueType zw = inputZ * inputW;
604 
605       const ValueType mxx = 1.0 - 2.0 * ( yy + zz );
606       const ValueType myy = 1.0 - 2.0 * ( xx + zz );
607       const ValueType mzz = 1.0 - 2.0 * ( xx + yy );
608       const ValueType mxy = 2.0 * ( xy - zw );
609       const ValueType mxz = 2.0 * ( xz + yw );
610       const ValueType myx = 2.0 * ( xy + zw );
611       const ValueType mzx = 2.0 * ( xz - yw );
612       const ValueType mzy = 2.0 * ( yz + xw );
613       const ValueType myz = 2.0 * ( yz - xw );
614 
615       OutputVectorType result;
616       result[0] = mxx * VectorObject[0] + mxy * VectorObject[1] + mxz * VectorObject[2];
617       result[1] = myx * VectorObject[0] + myy * VectorObject[1] + myz * VectorObject[2];
618       result[2] = mzx * VectorObject[0] + mzy * VectorObject[1] + mzz * VectorObject[2];
619       return result;
620       }
621 }
622 
623 /** Transform a Vector */
624 template< typename T >
625 typename Versor< T >::VectorType
626 Versor< T >
Transform(const VectorType & v) const627 ::Transform(const VectorType & v) const
628 {
629   return localTransformVectorMath<VectorType,T,typename Versor< T >::VectorType>(v,this->m_X,this->m_Y,this->m_Z,this->m_W);
630 }
631 
632 /** Transform a CovariantVector
633  *  given that this is an orthogonal transformation
634  *  CovariantVectors are transformed as vectors. */
635 template< typename T >
636 typename Versor< T >::CovariantVectorType
637 Versor< T >
Transform(const CovariantVectorType & v) const638 ::Transform(const CovariantVectorType & v) const
639 {
640   return localTransformVectorMath<CovariantVectorType,T,typename Versor< T >::CovariantVectorType>(v,this->m_X,this->m_Y,this->m_Z,this->m_W);
641 }
642 
643 /** Transform a Point */
644 template< typename T >
645 typename Versor< T >::PointType
646 Versor< T >
Transform(const PointType & v) const647 ::Transform(const PointType & v) const
648 {
649   return localTransformVectorMath<PointType,T,typename Versor< T >::PointType>(v,this->m_X,this->m_Y,this->m_Z,this->m_W);
650 }
651 
652 /** Transform a VnlVector */
653 template< typename T >
654 typename Versor< T >::VnlVectorType
655 Versor< T >
Transform(const VnlVectorType & v) const656 ::Transform(const VnlVectorType & v) const
657 {
658   return localTransformVectorMath<VnlVectorType,T,typename Versor< T >::VnlVectorType>(v,this->m_X,this->m_Y,this->m_Z,this->m_W);
659 }
660 
661 /** Get Matrix representation */
662 template< typename T >
663 Matrix< T, 3, 3 >
664 Versor< T >
GetMatrix() const665 ::GetMatrix() const
666 {
667   Matrix< T, 3, 3 > matrix;
668 
669   const RealType xx = m_X * m_X;
670   const RealType yy = m_Y * m_Y;
671   const RealType zz = m_Z * m_Z;
672   const RealType xy = m_X * m_Y;
673   const RealType xz = m_X * m_Z;
674   const RealType xw = m_X * m_W;
675   const RealType yz = m_Y * m_Z;
676   const RealType yw = m_Y * m_W;
677   const RealType zw = m_Z * m_W;
678 
679   matrix[0][0] = 1.0 - 2.0 * ( yy + zz );
680   matrix[1][1] = 1.0 - 2.0 * ( xx + zz );
681   matrix[2][2] = 1.0 - 2.0 * ( xx + yy );
682   matrix[0][1] = 2.0 * ( xy - zw );
683   matrix[0][2] = 2.0 * ( xz + yw );
684   matrix[1][0] = 2.0 * ( xy + zw );
685   matrix[2][0] = 2.0 * ( xz - yw );
686   matrix[2][1] = 2.0 * ( yz + xw );
687   matrix[1][2] = 2.0 * ( yz - xw );
688 
689   return matrix;
690 }
691 } // end namespace itk
692 
693 #endif
694