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