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