1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkTransform.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkTransform.h"
16 #include "vtkMath.h"
17 #include "vtkObjectFactory.h"
18 
19 #include <cstdlib>
20 
21 vtkStandardNewMacro(vtkTransform);
22 
23 //----------------------------------------------------------------------------
vtkTransform()24 vtkTransform::vtkTransform()
25 {
26   this->Input = NULL;
27 
28   // most of the functionality is provided by the concatenation
29   this->Concatenation = vtkTransformConcatenation::New();
30 
31   // the stack will be allocated the first time Push is called
32   this->Stack = NULL;
33 
34   // initialize the legacy 'Point' info
35   this->Point[0] = this->Point[1] = this->Point[2] = this->Point[3] = 0.0;
36   this->DoublePoint[0] =
37     this->DoublePoint[1] = this->DoublePoint[2] = this->DoublePoint[3] = 0.0;
38 
39   // save the original matrix MTime as part of a hack to support legacy code
40   this->MatrixUpdateMTime = this->Matrix->GetMTime();
41 }
42 
43 //----------------------------------------------------------------------------
~vtkTransform()44 vtkTransform::~vtkTransform()
45 {
46   this->SetInput(NULL);
47 
48   if (this->Concatenation)
49     {
50     this->Concatenation->Delete();
51     }
52   if (this->Stack)
53     {
54     this->Stack->Delete();
55     }
56 }
57 
58 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)59 void vtkTransform::PrintSelf(ostream& os, vtkIndent indent)
60 {
61   this->Update();
62 
63   this->Superclass::PrintSelf(os, indent);
64   os << indent << "Input: (" << this->Input << ")\n";
65   os << indent << "InverseFlag: " << this->GetInverseFlag() << "\n";
66   os << indent << "NumberOfConcatenatedTransforms: " <<
67     this->GetNumberOfConcatenatedTransforms() << "\n";
68   if (this->GetNumberOfConcatenatedTransforms() != 0)
69     {
70     int n = this->GetNumberOfConcatenatedTransforms();
71     for (int i = 0; i < n; i++)
72       {
73       vtkLinearTransform *t = this->GetConcatenatedTransform(i);
74       os << indent << "    " << i << ": " << t->GetClassName() << " at " <<
75          t << "\n";
76       }
77     }
78 
79   os << indent << "DoublePoint: " << "( " <<
80      this->DoublePoint[0] << ", " << this->DoublePoint[1] << ", " <<
81      this->DoublePoint[2] << ", " << this->DoublePoint[3] << ")\n";
82 
83   os << indent << "Point: " << "( " <<
84      this->Point[0] << ", " << this->Point[1] << ", " <<
85      this->Point[2] << ", " << this->Point[3] << ")\n";
86 }
87 
88 //----------------------------------------------------------------------------
Identity()89 void vtkTransform::Identity()
90 {
91   this->Concatenation->Identity();
92   this->Modified();
93 
94   // support for the legacy hack in InternalUpdate
95   if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
96     {
97     this->Matrix->Identity();
98     }
99 }
100 
101 //----------------------------------------------------------------------------
Inverse()102 void vtkTransform::Inverse()
103 {
104   this->Concatenation->Inverse();
105   this->Modified();
106 
107   // for the legacy hack in InternalUpdate
108   if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
109     {
110     this->Matrix->Invert();
111     }
112 }
113 
114 //----------------------------------------------------------------------------
InternalDeepCopy(vtkAbstractTransform * gtrans)115 void vtkTransform::InternalDeepCopy(vtkAbstractTransform *gtrans)
116 {
117   vtkTransform *transform = static_cast<vtkTransform *>(gtrans);
118 
119   // copy the input
120   this->SetInput(transform->Input);
121 
122   // copy the concatenation
123   this->Concatenation->DeepCopy(transform->Concatenation);
124 
125   // copy the stack
126   if (transform->Stack)
127     {
128     if (this->Stack == NULL)
129       {
130       this->Stack = vtkTransformConcatenationStack::New();
131       }
132     this->Stack->DeepCopy(transform->Stack);
133     }
134   else
135     {
136     if (this->Stack)
137       {
138       this->Stack->Delete();
139       this->Stack = NULL;
140       }
141     }
142 
143   // legacy stuff: copy Point and DoublePoint
144   for (int j = 0; j < 3; j++)
145     {
146     this->Point[j] = transform->Point[j];
147     this->DoublePoint[j] = transform->DoublePoint[j];
148     }
149 
150   // to support the legacy hack in InternalUpdate
151   this->Matrix->DeepCopy(transform->Matrix);
152   this->MatrixUpdateMTime = this->Matrix->GetMTime();
153 }
154 
155 //----------------------------------------------------------------------------
InternalUpdate()156 void vtkTransform::InternalUpdate()
157 {
158   int i;
159   int nTransforms = this->Concatenation->GetNumberOfTransforms();
160   int nPreTransforms = this->Concatenation->GetNumberOfPreTransforms();
161 
162   // check to see whether someone has been fooling around with our matrix
163   int doTheLegacyHack = 0;
164   if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
165     {
166     vtkDebugMacro(<<"InternalUpdate: this->Matrix was modified by something other than 'this'");
167 
168     // check to see if we have any inputs or concatenated transforms
169     int isPipelined = (this->Input != 0);
170     for (i = 0; i < nTransforms && !isPipelined; i++)
171       { // the vtkSimpleTransform is just a matrix placeholder,
172         // it is not a real transform
173       isPipelined =
174         !this->Concatenation->GetTransform(i)->IsA("vtkSimpleTransform");
175       }
176     // do the legacy hack only if we have no input transforms
177     doTheLegacyHack = !isPipelined;
178     }
179 
180   // copy matrix from input
181   if (this->Input)
182     {
183     this->Matrix->DeepCopy(this->Input->GetMatrix());
184     // if inverse flag is set, invert the matrix
185     if (this->Concatenation->GetInverseFlag())
186       {
187       this->Matrix->Invert();
188       }
189     }
190   else if (doTheLegacyHack)
191     {
192     vtkWarningMacro("InternalUpdate: doing hack to support legacy code.  "
193                     "This is deprecated in VTK 4.2.  May be removed in a "
194                     "future version.");
195     // this heuristic works perfectly if GetMatrix() or GetMatrixPointer()
196     // was called immediately prior to the matrix modifications
197     // (fortunately, this is almost always the case)
198     if (this->Matrix->GetMTime() > this->Concatenation->GetMaxMTime())
199       { // don't apply operations that occurred after matrix modification
200       nPreTransforms = nTransforms = 0;
201       }
202     }
203   else
204     {  // otherwise, we start with the identity transform as our base
205     this->Matrix->Identity();
206     }
207 
208   // concatenate PreTransforms
209   for (i = nPreTransforms-1; i >= 0; i--)
210     {
211     vtkHomogeneousTransform *transform =
212       static_cast<vtkHomogeneousTransform *>(this->Concatenation->GetTransform(i));
213     vtkMatrix4x4::Multiply4x4(this->Matrix,transform->GetMatrix(),
214                               this->Matrix);
215     }
216 
217   // concatenate PostTransforms
218   for (i = nPreTransforms; i < nTransforms; i++)
219     {
220     vtkHomogeneousTransform *transform =
221       static_cast<vtkHomogeneousTransform *>(this->Concatenation->GetTransform(i));
222     vtkMatrix4x4::Multiply4x4(transform->GetMatrix(),this->Matrix,
223                               this->Matrix);
224     }
225 
226   if (doTheLegacyHack)
227     { // the transform operations have been incorporated into the matrix,
228       // so delete them
229     this->Concatenation->Identity();
230     }
231   else
232     { // having this in the 'else' forces the legacy flag to be sticky
233     this->MatrixUpdateMTime = this->Matrix->GetMTime();
234     }
235 }
236 
237 //----------------------------------------------------------------------------
Concatenate(vtkLinearTransform * transform)238 void vtkTransform::Concatenate(vtkLinearTransform *transform)
239 {
240   if (transform->CircuitCheck(this))
241     {
242     vtkErrorMacro("Concatenate: this would create a circular reference.");
243     return;
244     }
245   this->Concatenation->Concatenate(transform);
246   this->Modified();
247 }
248 
249 //----------------------------------------------------------------------------
SetInput(vtkLinearTransform * input)250 void vtkTransform::SetInput(vtkLinearTransform *input)
251 {
252   if (this->Input == input)
253     {
254     return;
255     }
256   if (input && input->CircuitCheck(this))
257     {
258     vtkErrorMacro("SetInput: this would create a circular reference.");
259     return;
260     }
261   if (this->Input)
262     {
263     this->Input->Delete();
264     }
265   this->Input = input;
266   if (this->Input)
267     {
268     this->Input->Register(this);
269     }
270   this->Modified();
271 }
272 
273 //----------------------------------------------------------------------------
CircuitCheck(vtkAbstractTransform * transform)274 int vtkTransform::CircuitCheck(vtkAbstractTransform *transform)
275 {
276   if (this->vtkLinearTransform::CircuitCheck(transform) ||
277       (this->Input && this->Input->CircuitCheck(transform)))
278     {
279     return 1;
280     }
281 
282   int n = this->Concatenation->GetNumberOfTransforms();
283   for (int i = 0; i < n; i++)
284     {
285     if (this->Concatenation->GetTransform(i)->CircuitCheck(transform))
286       {
287       return 1;
288       }
289     }
290 
291   return 0;
292 }
293 
294 //----------------------------------------------------------------------------
MakeTransform()295 vtkAbstractTransform *vtkTransform::MakeTransform()
296 {
297   return vtkTransform::New();
298 }
299 
300 //----------------------------------------------------------------------------
GetMTime()301 unsigned long vtkTransform::GetMTime()
302 {
303   unsigned long mtime = this->vtkLinearTransform::GetMTime();
304   unsigned long mtime2;
305 
306   // checking the matrix MTime is part of the legacy hack in InternalUpdate
307   if ((mtime2 = this->Matrix->GetMTime()) > this->MatrixUpdateMTime)
308     {
309     if (mtime2 > mtime)
310       {
311       mtime = mtime2;
312       }
313     }
314 
315   if (this->Input)
316     {
317     mtime2 = this->Input->GetMTime();
318     if (mtime2 > mtime)
319       {
320       mtime = mtime2;
321       }
322     }
323   mtime2 = this->Concatenation->GetMaxMTime();
324   if (mtime2 > mtime)
325     {
326     return mtime2;
327     }
328   return mtime;
329 }
330 
331 //----------------------------------------------------------------------------
332 // Get the x, y, z orientation angles from the transformation matrix as an
333 // array of three floating point values.
GetOrientation(double orientation[3],vtkMatrix4x4 * amatrix)334 void vtkTransform::GetOrientation(double orientation[3],
335                                   vtkMatrix4x4 *amatrix)
336 {
337 #define VTK_AXIS_EPSILON 0.001
338 #define VTK_ORTHO_EPSILON 4e-16
339   int i;
340 
341   // convenient access to matrix
342   double (*matrix)[4] = amatrix->Element;
343   double ortho[3][3];
344 
345   for (i = 0; i < 3; i++)
346     {
347     ortho[0][i] = matrix[0][i];
348     ortho[1][i] = matrix[1][i];
349     ortho[2][i] = matrix[2][i];
350     }
351   if (vtkMath::Determinant3x3(ortho) < 0)
352     {
353     ortho[0][2] = -ortho[0][2];
354     ortho[1][2] = -ortho[1][2];
355     ortho[2][2] = -ortho[2][2];
356     }
357 
358   // Check whether matrix is orthogonal
359   double r1 = vtkMath::Dot(ortho[0],ortho[1]);
360   double r2 = vtkMath::Dot(ortho[0],ortho[2]);
361   double r3 = vtkMath::Dot(ortho[1],ortho[2]);
362 
363   // Orthogonalize the matrix if it isn't already orthogonal
364   if ((r1*r1) + (r2*r2) + (r3*r3) > (VTK_ORTHO_EPSILON*VTK_ORTHO_EPSILON))
365     {
366     vtkMath::Orthogonalize3x3(ortho, ortho);
367     }
368 
369   // first rotate about y axis
370   double x2 = ortho[2][0];
371   double y2 = ortho[2][1];
372   double z2 = ortho[2][2];
373 
374   double x3 = ortho[1][0];
375   double y3 = ortho[1][1];
376   double z3 = ortho[1][2];
377 
378   double d1 = sqrt(x2*x2 + z2*z2);
379 
380   double cosTheta, sinTheta;
381   if (d1 < VTK_AXIS_EPSILON)
382     {
383     cosTheta = 1.0;
384     sinTheta = 0.0;
385     }
386   else
387     {
388     cosTheta = z2/d1;
389     sinTheta = x2/d1;
390     }
391 
392   double theta = atan2(sinTheta, cosTheta);
393   orientation[1] = - vtkMath::DegreesFromRadians( theta );
394 
395   // now rotate about x axis
396   double d = sqrt(x2*x2 + y2*y2 + z2*z2);
397 
398   double sinPhi, cosPhi;
399   if (d < VTK_AXIS_EPSILON)
400     {
401     sinPhi = 0.0;
402     cosPhi = 1.0;
403     }
404   else if (d1 < VTK_AXIS_EPSILON)
405     {
406     sinPhi = y2/d;
407     cosPhi = z2/d;
408     }
409   else
410     {
411     sinPhi = y2/d;
412     cosPhi = (x2*x2 + z2*z2)/(d1*d);
413     }
414 
415   double phi = atan2(sinPhi, cosPhi);
416   orientation[0] = vtkMath::DegreesFromRadians( phi );
417 
418   // finally, rotate about z
419   double x3p = x3*cosTheta - z3*sinTheta;
420   double y3p = - sinPhi*sinTheta*x3 + cosPhi*y3 - sinPhi*cosTheta*z3;
421   double d2 = sqrt(x3p*x3p + y3p*y3p);
422 
423   double cosAlpha, sinAlpha;
424   if (d2 < VTK_AXIS_EPSILON)
425     {
426     cosAlpha = 1.0;
427     sinAlpha = 0.0;
428     }
429   else
430     {
431     cosAlpha = y3p/d2;
432     sinAlpha = x3p/d2;
433     }
434 
435   double alpha = atan2(sinAlpha, cosAlpha);
436   orientation[2] = vtkMath::DegreesFromRadians( alpha );
437 }
438 
439 //----------------------------------------------------------------------------
440 // Get the x, y, z orientation angles from the transformation matrix as an
441 // array of three floating point values.
GetOrientation(double orientation[3])442 void vtkTransform::GetOrientation(double orientation[3])
443 {
444   this->Update();
445   this->GetOrientation(orientation, this->Matrix);
446 }
447 
448 //----------------------------------------------------------------------------
449 // vtkTransform::GetOrientationWXYZ
GetOrientationWXYZ(double wxyz[4])450 void vtkTransform::GetOrientationWXYZ(double wxyz[4])
451 {
452   int i;
453 
454   this->Update();
455   // convenient access to matrix
456   double (*matrix)[4] = this->Matrix->Element;
457   double ortho[3][3];
458 
459   for (i = 0; i < 3; i++)
460     {
461     ortho[0][i] = matrix[0][i];
462     ortho[1][i] = matrix[1][i];
463     ortho[2][i] = matrix[2][i];
464     }
465   if (vtkMath::Determinant3x3(ortho) < 0)
466     {
467     ortho[0][2] = -ortho[0][2];
468     ortho[1][2] = -ortho[1][2];
469     ortho[2][2] = -ortho[2][2];
470     }
471 
472   vtkMath::Matrix3x3ToQuaternion(ortho, wxyz);
473 
474   // calc the return value wxyz
475  double mag = sqrt( wxyz[1] * wxyz[1] + wxyz[2] * wxyz[2] + wxyz[3] * wxyz[3] );
476 
477   if ( mag )
478     {
479     wxyz[0] = 2. * vtkMath::DegreesFromRadians( acos( wxyz[0] ) );
480     wxyz[1] /= mag;
481     wxyz[2] /= mag;
482     wxyz[3] /= mag;
483     }
484   else
485     {
486     wxyz[0] = 0.0;
487     wxyz[1] = 0.0;
488     wxyz[2] = 0.0;
489     wxyz[3] = 1.0;
490     }
491 }
492 
493 
494 //----------------------------------------------------------------------------
495 // Return the position from the current transformation matrix as an array
496 // of three floating point numbers. This is simply returning the translation
497 // component of the 4x4 matrix.
GetPosition(double position[3])498 void vtkTransform::GetPosition(double position[3])
499 {
500   this->Update();
501 
502   position[0] = this->Matrix->Element[0][3];
503   position[1] = this->Matrix->Element[1][3];
504   position[2] = this->Matrix->Element[2][3];
505 }
506 
507 //----------------------------------------------------------------------------
508 // Return the x, y, z scale factors of the current transformation matrix as
509 // an array of three float numbers.
GetScale(double scale[3])510 void vtkTransform::GetScale(double scale[3])
511 {
512   this->Update();
513 
514   // convenient access to matrix
515   double (*matrix)[4] = this->Matrix->Element;
516   double U[3][3], VT[3][3];
517 
518   for (int i = 0; i < 3; i++)
519     {
520     U[0][i] = matrix[0][i];
521     U[1][i] = matrix[1][i];
522     U[2][i] = matrix[2][i];
523     }
524 
525   vtkMath::SingularValueDecomposition3x3(U, U, scale, VT);
526 }
527 
528 //----------------------------------------------------------------------------
529 // Return the inverse of the current transformation matrix.
GetInverse(vtkMatrix4x4 * inverse)530 void vtkTransform::GetInverse(vtkMatrix4x4 *inverse)
531 {
532   vtkMatrix4x4::Invert(this->GetMatrix(),inverse);
533 }
534 
535 //----------------------------------------------------------------------------
536 // Obtain the transpose of the current transformation matrix.
GetTranspose(vtkMatrix4x4 * transpose)537 void vtkTransform::GetTranspose(vtkMatrix4x4 *transpose)
538 {
539   vtkMatrix4x4::Transpose(this->GetMatrix(),transpose);
540 }
541 
542