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 = nullptr;
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 = nullptr;
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] = this->DoublePoint[1] = this->DoublePoint[2] = this->DoublePoint[3] = 0.0;
37 
38   // save the original matrix MTime as part of a hack to support legacy code
39   this->MatrixUpdateMTime = this->Matrix->GetMTime();
40 }
41 
42 //------------------------------------------------------------------------------
~vtkTransform()43 vtkTransform::~vtkTransform()
44 {
45   this->SetInput(nullptr);
46 
47   if (this->Concatenation)
48   {
49     this->Concatenation->Delete();
50   }
51   if (this->Stack)
52   {
53     this->Stack->Delete();
54   }
55 }
56 
57 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)58 void vtkTransform::PrintSelf(ostream& os, vtkIndent indent)
59 {
60   this->Update();
61 
62   this->Superclass::PrintSelf(os, indent);
63   os << indent << "Input: (" << this->Input << ")\n";
64   os << indent << "InverseFlag: " << this->GetInverseFlag() << "\n";
65   os << indent << "NumberOfConcatenatedTransforms: " << this->GetNumberOfConcatenatedTransforms()
66      << "\n";
67   if (this->GetNumberOfConcatenatedTransforms() != 0)
68   {
69     int n = this->GetNumberOfConcatenatedTransforms();
70     for (int i = 0; i < n; i++)
71     {
72       vtkLinearTransform* t = this->GetConcatenatedTransform(i);
73       os << indent << "    " << i << ": " << t->GetClassName() << " at " << t << "\n";
74     }
75   }
76 
77   os << indent << "DoublePoint: "
78      << "( " << this->DoublePoint[0] << ", " << this->DoublePoint[1] << ", " << this->DoublePoint[2]
79      << ", " << this->DoublePoint[3] << ")\n";
80 
81   os << indent << "Point: "
82      << "( " << this->Point[0] << ", " << this->Point[1] << ", " << this->Point[2] << ", "
83      << this->Point[3] << ")\n";
84 }
85 
86 //------------------------------------------------------------------------------
Identity()87 void vtkTransform::Identity()
88 {
89   this->Concatenation->Identity();
90 
91   // support for the legacy hack in InternalUpdate
92   if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
93   {
94     this->Matrix->Identity();
95   }
96 
97   this->Modified();
98 }
99 
100 //------------------------------------------------------------------------------
Inverse()101 void vtkTransform::Inverse()
102 {
103   this->Concatenation->Inverse();
104 
105   // for the legacy hack in InternalUpdate
106   if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
107   {
108     this->Matrix->Invert();
109   }
110 
111   this->Modified();
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 == nullptr)
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 = nullptr;
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 != nullptr);
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 = !this->Concatenation->GetTransform(i)->IsA("vtkSimpleTransform");
174     }
175     // do the legacy hack only if we have no input transforms
176     doTheLegacyHack = !isPipelined;
177   }
178 
179   // copy matrix from input
180   if (this->Input)
181   {
182     this->Matrix->DeepCopy(this->Input->GetMatrix());
183     // if inverse flag is set, invert the matrix
184     if (this->Concatenation->GetInverseFlag())
185     {
186       this->Matrix->Invert();
187     }
188   }
189   else if (doTheLegacyHack)
190   {
191     vtkWarningMacro("InternalUpdate: doing hack to support legacy code.  "
192                     "This is deprecated in VTK 4.2.  May be removed in a "
193                     "future version.");
194     // this heuristic works perfectly if GetMatrix() or GetMatrixPointer()
195     // was called immediately prior to the matrix modifications
196     // (fortunately, this is almost always the case)
197     if (this->Matrix->GetMTime() > this->Concatenation->GetMaxMTime())
198     { // don't apply operations that occurred after matrix modification
199       nPreTransforms = nTransforms = 0;
200     }
201   }
202   else
203   { // otherwise, we start with the identity transform as our base
204     this->Matrix->Identity();
205   }
206 
207   // concatenate PreTransforms
208   for (i = nPreTransforms - 1; i >= 0; i--)
209   {
210     vtkHomogeneousTransform* transform =
211       static_cast<vtkHomogeneousTransform*>(this->Concatenation->GetTransform(i));
212     vtkMatrix4x4::Multiply4x4(this->Matrix, transform->GetMatrix(), this->Matrix);
213   }
214 
215   // concatenate PostTransforms
216   for (i = nPreTransforms; i < nTransforms; i++)
217   {
218     vtkHomogeneousTransform* transform =
219       static_cast<vtkHomogeneousTransform*>(this->Concatenation->GetTransform(i));
220     vtkMatrix4x4::Multiply4x4(transform->GetMatrix(), this->Matrix, this->Matrix);
221   }
222 
223   if (doTheLegacyHack)
224   { // the transform operations have been incorporated into the matrix,
225     // so delete them
226     this->Concatenation->Identity();
227   }
228   else
229   { // having this in the 'else' forces the legacy flag to be sticky
230     this->MatrixUpdateMTime = this->Matrix->GetMTime();
231   }
232 }
233 
234 //------------------------------------------------------------------------------
Concatenate(vtkLinearTransform * transform)235 void vtkTransform::Concatenate(vtkLinearTransform* transform)
236 {
237   if (transform->CircuitCheck(this))
238   {
239     vtkErrorMacro("Concatenate: this would create a circular reference.");
240     return;
241   }
242   this->Concatenation->Concatenate(transform);
243   this->Modified();
244 }
245 
246 //------------------------------------------------------------------------------
SetInput(vtkLinearTransform * input)247 void vtkTransform::SetInput(vtkLinearTransform* input)
248 {
249   if (this->Input == input)
250   {
251     return;
252   }
253   if (input && input->CircuitCheck(this))
254   {
255     vtkErrorMacro("SetInput: this would create a circular reference.");
256     return;
257   }
258   if (this->Input)
259   {
260     this->Input->Delete();
261   }
262   this->Input = input;
263   if (this->Input)
264   {
265     this->Input->Register(this);
266   }
267   this->Modified();
268 }
269 
270 //------------------------------------------------------------------------------
CircuitCheck(vtkAbstractTransform * transform)271 int vtkTransform::CircuitCheck(vtkAbstractTransform* transform)
272 {
273   if (this->vtkLinearTransform::CircuitCheck(transform) ||
274     (this->Input && this->Input->CircuitCheck(transform)))
275   {
276     return 1;
277   }
278 
279   int n = this->Concatenation->GetNumberOfTransforms();
280   for (int i = 0; i < n; i++)
281   {
282     if (this->Concatenation->GetTransform(i)->CircuitCheck(transform))
283     {
284       return 1;
285     }
286   }
287 
288   return 0;
289 }
290 
291 //------------------------------------------------------------------------------
MakeTransform()292 vtkAbstractTransform* vtkTransform::MakeTransform()
293 {
294   return vtkTransform::New();
295 }
296 
297 //------------------------------------------------------------------------------
GetMTime()298 vtkMTimeType vtkTransform::GetMTime()
299 {
300   vtkMTimeType mtime = this->vtkLinearTransform::GetMTime();
301   vtkMTimeType mtime2;
302 
303   // checking the matrix MTime is part of the legacy hack in InternalUpdate
304   if ((mtime2 = this->Matrix->GetMTime()) > this->MatrixUpdateMTime)
305   {
306     if (mtime2 > mtime)
307     {
308       mtime = mtime2;
309     }
310   }
311 
312   if (this->Input)
313   {
314     mtime2 = this->Input->GetMTime();
315     if (mtime2 > mtime)
316     {
317       mtime = mtime2;
318     }
319   }
320   mtime2 = this->Concatenation->GetMaxMTime();
321   if (mtime2 > mtime)
322   {
323     return mtime2;
324   }
325   return mtime;
326 }
327 
328 //------------------------------------------------------------------------------
329 // Get the x, y, z orientation angles from the transformation matrix as an
330 // array of three floating point values.
GetOrientation(double orientation[3],vtkMatrix4x4 * amatrix)331 void vtkTransform::GetOrientation(double orientation[3], vtkMatrix4x4* amatrix)
332 {
333 #define VTK_AXIS_EPSILON 0.001
334 #define VTK_ORTHO_EPSILON 4e-16
335   int i;
336 
337   // convenient access to matrix
338   double(*matrix)[4] = amatrix->Element;
339   double ortho[3][3];
340 
341   for (i = 0; i < 3; i++)
342   {
343     ortho[0][i] = matrix[0][i];
344     ortho[1][i] = matrix[1][i];
345     ortho[2][i] = matrix[2][i];
346   }
347   if (vtkMath::Determinant3x3(ortho) < 0)
348   {
349     ortho[0][2] = -ortho[0][2];
350     ortho[1][2] = -ortho[1][2];
351     ortho[2][2] = -ortho[2][2];
352   }
353 
354   // Check whether matrix is orthogonal
355   double r1 = vtkMath::Dot(ortho[0], ortho[1]);
356   double r2 = vtkMath::Dot(ortho[0], ortho[2]);
357   double r3 = vtkMath::Dot(ortho[1], ortho[2]);
358 
359   // Orthogonalize the matrix if it isn't already orthogonal
360   if ((r1 * r1) + (r2 * r2) + (r3 * r3) > (VTK_ORTHO_EPSILON * VTK_ORTHO_EPSILON))
361   {
362     vtkMath::Orthogonalize3x3(ortho, ortho);
363   }
364 
365   // compute the max scale as we need that for the epsilon test
366   double scale0 = vtkMath::Norm(ortho[0]);
367   double scale1 = vtkMath::Norm(ortho[1]);
368   double maxScale = vtkMath::Norm(ortho[2]);
369   maxScale = maxScale >= scale0 ? maxScale : scale0;
370   maxScale = maxScale >= scale1 ? maxScale : scale1;
371   if (maxScale == 0.0)
372   {
373     orientation[0] = 0.0;
374     orientation[1] = 0.0;
375     orientation[2] = 0.0;
376     return;
377   }
378 
379   // first rotate about y axis
380   double x2 = ortho[2][0];
381   double y2 = ortho[2][1];
382   double z2 = ortho[2][2];
383 
384   double x3 = ortho[1][0];
385   double y3 = ortho[1][1];
386   double z3 = ortho[1][2];
387 
388   double d1 = sqrt(x2 * x2 + z2 * z2);
389 
390   double cosTheta, sinTheta;
391   if (d1 < VTK_AXIS_EPSILON * maxScale)
392   {
393     cosTheta = 1.0;
394     sinTheta = 0.0;
395   }
396   else
397   {
398     cosTheta = z2 / d1;
399     sinTheta = x2 / d1;
400   }
401 
402   double theta = atan2(sinTheta, cosTheta);
403   orientation[1] = -vtkMath::DegreesFromRadians(theta);
404 
405   // now rotate about x axis
406   double d = sqrt(x2 * x2 + y2 * y2 + z2 * z2);
407 
408   double sinPhi, cosPhi;
409   if (d < VTK_AXIS_EPSILON * maxScale)
410   {
411     sinPhi = 0.0;
412     cosPhi = 1.0;
413   }
414   else if (d1 < VTK_AXIS_EPSILON * maxScale)
415   {
416     sinPhi = y2 / d;
417     cosPhi = z2 / d;
418   }
419   else
420   {
421     sinPhi = y2 / d;
422     cosPhi = (x2 * x2 + z2 * z2) / (d1 * d);
423   }
424 
425   double phi = atan2(sinPhi, cosPhi);
426   orientation[0] = vtkMath::DegreesFromRadians(phi);
427 
428   // finally, rotate about z
429   double x3p = x3 * cosTheta - z3 * sinTheta;
430   double y3p = -sinPhi * sinTheta * x3 + cosPhi * y3 - sinPhi * cosTheta * z3;
431   double d2 = sqrt(x3p * x3p + y3p * y3p);
432 
433   double cosAlpha, sinAlpha;
434   if (d2 < VTK_AXIS_EPSILON * maxScale)
435   {
436     cosAlpha = 1.0;
437     sinAlpha = 0.0;
438   }
439   else
440   {
441     cosAlpha = y3p / d2;
442     sinAlpha = x3p / d2;
443   }
444 
445   double alpha = atan2(sinAlpha, cosAlpha);
446   orientation[2] = vtkMath::DegreesFromRadians(alpha);
447 }
448 
449 //------------------------------------------------------------------------------
450 // Get the x, y, z orientation angles from the transformation matrix as an
451 // array of three floating point values.
GetOrientation(double orientation[3])452 void vtkTransform::GetOrientation(double orientation[3])
453 {
454   this->Update();
455   this->GetOrientation(orientation, this->Matrix);
456 }
457 
458 //------------------------------------------------------------------------------
459 // vtkTransform::GetOrientationWXYZ
GetOrientationWXYZ(double wxyz[4])460 void vtkTransform::GetOrientationWXYZ(double wxyz[4])
461 {
462   int i;
463 
464   this->Update();
465   // convenient access to matrix
466   double(*matrix)[4] = this->Matrix->Element;
467   double ortho[3][3];
468 
469   for (i = 0; i < 3; i++)
470   {
471     ortho[0][i] = matrix[0][i];
472     ortho[1][i] = matrix[1][i];
473     ortho[2][i] = matrix[2][i];
474   }
475   if (vtkMath::Determinant3x3(ortho) < 0)
476   {
477     ortho[0][2] = -ortho[0][2];
478     ortho[1][2] = -ortho[1][2];
479     ortho[2][2] = -ortho[2][2];
480   }
481 
482   vtkMath::Matrix3x3ToQuaternion(ortho, wxyz);
483 
484   // calc the return value wxyz
485   double mag = sqrt(wxyz[1] * wxyz[1] + wxyz[2] * wxyz[2] + wxyz[3] * wxyz[3]);
486 
487   if (mag != 0.0)
488   {
489     wxyz[0] = 2.0 * vtkMath::DegreesFromRadians(atan2(mag, wxyz[0]));
490     wxyz[1] /= mag;
491     wxyz[2] /= mag;
492     wxyz[3] /= mag;
493   }
494   else
495   {
496     wxyz[0] = 0.0;
497     wxyz[1] = 0.0;
498     wxyz[2] = 0.0;
499     wxyz[3] = 1.0;
500   }
501 }
502 
503 //------------------------------------------------------------------------------
504 // Return the position from the current transformation matrix as an array
505 // of three floating point numbers. This is simply returning the translation
506 // component of the 4x4 matrix.
GetPosition(double position[3])507 void vtkTransform::GetPosition(double position[3])
508 {
509   this->Update();
510 
511   position[0] = this->Matrix->Element[0][3];
512   position[1] = this->Matrix->Element[1][3];
513   position[2] = this->Matrix->Element[2][3];
514 }
515 
516 //------------------------------------------------------------------------------
517 // Return the x, y, z scale factors of the current transformation matrix as
518 // an array of three float numbers.
GetScale(double scale[3])519 void vtkTransform::GetScale(double scale[3])
520 {
521   this->Update();
522 
523   // convenient access to matrix
524   double(*matrix)[4] = this->Matrix->Element;
525   double U[3][3], VT[3][3];
526 
527   for (int i = 0; i < 3; i++)
528   {
529     U[0][i] = matrix[0][i];
530     U[1][i] = matrix[1][i];
531     U[2][i] = matrix[2][i];
532   }
533 
534   vtkMath::SingularValueDecomposition3x3(U, U, scale, VT);
535 }
536 
537 //------------------------------------------------------------------------------
538 // Return the inverse of the current transformation matrix.
GetInverse(vtkMatrix4x4 * inverse)539 void vtkTransform::GetInverse(vtkMatrix4x4* inverse)
540 {
541   vtkMatrix4x4::Invert(this->GetMatrix(), inverse);
542 }
543 
544 //------------------------------------------------------------------------------
545 // Obtain the transpose of the current transformation matrix.
GetTranspose(vtkMatrix4x4 * transpose)546 void vtkTransform::GetTranspose(vtkMatrix4x4* transpose)
547 {
548   vtkMatrix4x4::Transpose(this->GetMatrix(), transpose);
549 }
550