Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

539 lines
15 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkTransform.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkTransform.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include <stdlib.h>
vtkCxxRevisionMacro(vtkTransform, "$Revision: 1.106 $");
vtkStandardNewMacro(vtkTransform);
//----------------------------------------------------------------------------
vtkTransform::vtkTransform()
{
this->Input = NULL;
// most of the functionality is provided by the concatenation
this->Concatenation = vtkTransformConcatenation::New();
// the stack will be allocated the first time Push is called
this->Stack = NULL;
// initialize the legacy 'Point' info
this->Point[0] = this->Point[1] = this->Point[2] = this->Point[3] = 0.0;
this->DoublePoint[0] =
this->DoublePoint[1] = this->DoublePoint[2] = this->DoublePoint[3] = 0.0;
// save the original matrix MTime as part of a hack to support legacy code
this->MatrixUpdateMTime = this->Matrix->GetMTime();
}
//----------------------------------------------------------------------------
vtkTransform::~vtkTransform()
{
this->SetInput(NULL);
if (this->Concatenation)
{
this->Concatenation->Delete();
}
if (this->Stack)
{
this->Stack->Delete();
}
}
//----------------------------------------------------------------------------
void vtkTransform::PrintSelf(ostream& os, vtkIndent indent)
{
this->Update();
this->Superclass::PrintSelf(os, indent);
os << indent << "Input: (" << this->Input << ")\n";
os << indent << "InverseFlag: " << this->GetInverseFlag() << "\n";
os << indent << "NumberOfConcatenatedTransforms: " <<
this->GetNumberOfConcatenatedTransforms() << "\n";
if (this->GetNumberOfConcatenatedTransforms() != 0)
{
int n = this->GetNumberOfConcatenatedTransforms();
for (int i = 0; i < n; i++)
{
vtkLinearTransform *t = this->GetConcatenatedTransform(i);
os << indent << " " << i << ": " << t->GetClassName() << " at " <<
t << "\n";
}
}
os << indent << "DoublePoint: " << "( " <<
this->DoublePoint[0] << ", " << this->DoublePoint[1] << ", " <<
this->DoublePoint[2] << ", " << this->DoublePoint[3] << ")\n";
os << indent << "Point: " << "( " <<
this->Point[0] << ", " << this->Point[1] << ", " <<
this->Point[2] << ", " << this->Point[3] << ")\n";
}
//----------------------------------------------------------------------------
void vtkTransform::Identity()
{
this->Concatenation->Identity();
this->Modified();
// support for the legacy hack in InternalUpdate
if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
{
this->Matrix->Identity();
}
}
//----------------------------------------------------------------------------
void vtkTransform::Inverse()
{
this->Concatenation->Inverse();
this->Modified();
// for the legacy hack in InternalUpdate
if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
{
this->Matrix->Invert();
}
}
//----------------------------------------------------------------------------
void vtkTransform::InternalDeepCopy(vtkAbstractTransform *gtrans)
{
vtkTransform *transform = (vtkTransform *)gtrans;
// copy the input
this->SetInput(transform->Input);
// copy the concatenation
this->Concatenation->DeepCopy(transform->Concatenation);
// copy the stack
if (transform->Stack)
{
if (this->Stack == NULL)
{
this->Stack = vtkTransformConcatenationStack::New();
}
this->Stack->DeepCopy(transform->Stack);
}
else
{
if (this->Stack)
{
this->Stack->Delete();
this->Stack = NULL;
}
}
// legacy stuff: copy Point and DoublePoint
for (int j = 0; j < 3; j++)
{
this->Point[j] = transform->Point[j];
this->DoublePoint[j] = transform->DoublePoint[j];
}
// to support the legacy hack in InternalUpdate
this->Matrix->DeepCopy(transform->Matrix);
this->MatrixUpdateMTime = this->Matrix->GetMTime();
#ifndef VTK_LEGACY_REMOVE
if (transform->Matrix->GetMTime() > transform->MatrixUpdateMTime)
{ // this copies the legacy hack flag to the transform
vtkWarningMacro(<<"InternalDeepCopy: Legacy Hack deprecated in VTK 4.2. May be removed in a future version.");
this->MatrixUpdateMTime--;
}
#endif
}
//----------------------------------------------------------------------------
void vtkTransform::InternalUpdate()
{
int i;
int nTransforms = this->Concatenation->GetNumberOfTransforms();
int nPreTransforms = this->Concatenation->GetNumberOfPreTransforms();
// check to see whether someone has been fooling around with our matrix
int doTheLegacyHack = 0;
if (this->Matrix->GetMTime() > this->MatrixUpdateMTime)
{
vtkDebugMacro(<<"InternalUpdate: this->Matrix was modified by something other than 'this'");
// check to see if we have any inputs or concatenated transforms
int isPipelined = (this->Input != 0);
for (i = 0; i < nTransforms && !isPipelined; i++)
{ // the vtkSimpleTransform is just a matrix placeholder,
// it is not a real transform
isPipelined =
!this->Concatenation->GetTransform(i)->IsA("vtkSimpleTransform");
}
// do the legacy hack only if we have no input transforms
doTheLegacyHack = !isPipelined;
}
// copy matrix from input
if (this->Input)
{
this->Matrix->DeepCopy(this->Input->GetMatrix());
// if inverse flag is set, invert the matrix
if (this->Concatenation->GetInverseFlag())
{
this->Matrix->Invert();
}
}
else if (doTheLegacyHack)
{
vtkWarningMacro("InternalUpdate: doing hack to support legacy code. "
"This is deprecated in VTK 4.2. May be removed in a "
"future version.");
// this heuristic works perfectly if GetMatrix() or GetMatrixPointer()
// was called immediately prior to the matrix modifications
// (fortunately, this is almost always the case)
if (this->Matrix->GetMTime() > this->Concatenation->GetMaxMTime())
{ // don't apply operations that occurred after matrix modification
nPreTransforms = nTransforms = 0;
}
}
else
{ // otherwise, we start with the identity transform as our base
this->Matrix->Identity();
}
// concatenate PreTransforms
for (i = nPreTransforms-1; i >= 0; i--)
{
vtkHomogeneousTransform *transform =
(vtkHomogeneousTransform *)this->Concatenation->GetTransform(i);
vtkMatrix4x4::Multiply4x4(this->Matrix,transform->GetMatrix(),
this->Matrix);
}
// concatenate PostTransforms
for (i = nPreTransforms; i < nTransforms; i++)
{
vtkHomogeneousTransform *transform =
(vtkHomogeneousTransform *)this->Concatenation->GetTransform(i);
vtkMatrix4x4::Multiply4x4(transform->GetMatrix(),this->Matrix,
this->Matrix);
}
if (doTheLegacyHack)
{ // the transform operations have been incorporated into the matrix,
// so delete them
this->Concatenation->Identity();
}
else
{ // having this in the 'else' forces the legacy flag to be sticky
this->MatrixUpdateMTime = this->Matrix->GetMTime();
}
}
//----------------------------------------------------------------------------
void vtkTransform::Concatenate(vtkLinearTransform *transform)
{
if (transform->CircuitCheck(this))
{
vtkErrorMacro("Concatenate: this would create a circular reference.");
return;
}
this->Concatenation->Concatenate(transform);
this->Modified();
}
//----------------------------------------------------------------------------
void vtkTransform::SetInput(vtkLinearTransform *input)
{
if (this->Input == input)
{
return;
}
if (input && input->CircuitCheck(this))
{
vtkErrorMacro("SetInput: this would create a circular reference.");
return;
}
if (this->Input)
{
this->Input->Delete();
}
this->Input = input;
if (this->Input)
{
this->Input->Register(this);
}
this->Modified();
}
//----------------------------------------------------------------------------
int vtkTransform::CircuitCheck(vtkAbstractTransform *transform)
{
if (this->vtkLinearTransform::CircuitCheck(transform) ||
this->Input && this->Input->CircuitCheck(transform))
{
return 1;
}
int n = this->Concatenation->GetNumberOfTransforms();
for (int i = 0; i < n; i++)
{
if (this->Concatenation->GetTransform(i)->CircuitCheck(transform))
{
return 1;
}
}
return 0;
}
//----------------------------------------------------------------------------
vtkAbstractTransform *vtkTransform::MakeTransform()
{
return vtkTransform::New();
}
//----------------------------------------------------------------------------
unsigned long vtkTransform::GetMTime()
{
unsigned long mtime = this->vtkLinearTransform::GetMTime();
unsigned long mtime2;
// checking the matrix MTime is part of the legacy hack in InternalUpdate
if ((mtime2 = this->Matrix->GetMTime()) > this->MatrixUpdateMTime)
{
if (mtime2 > mtime)
{
mtime = mtime2;
}
}
if (this->Input)
{
mtime2 = this->Input->GetMTime();
if (mtime2 > mtime)
{
mtime = mtime2;
}
}
mtime2 = this->Concatenation->GetMaxMTime();
if (mtime2 > mtime)
{
return mtime2;
}
return mtime;
}
//----------------------------------------------------------------------------
// Get the x, y, z orientation angles from the transformation matrix as an
// array of three floating point values.
void vtkTransform::GetOrientation(double orientation[3],
vtkMatrix4x4 *amatrix)
{
#define VTK_AXIS_EPSILON 0.001
int i;
// convenient access to matrix
double (*matrix)[4] = amatrix->Element;
double ortho[3][3];
for (i = 0; i < 3; i++)
{
ortho[0][i] = matrix[0][i];
ortho[1][i] = matrix[1][i];
ortho[2][i] = matrix[2][i];
}
if (vtkMath::Determinant3x3(ortho) < 0)
{
ortho[0][2] = -ortho[0][2];
ortho[1][2] = -ortho[1][2];
ortho[2][2] = -ortho[2][2];
}
vtkMath::Orthogonalize3x3(ortho, ortho);
// first rotate about y axis
double x2 = ortho[2][0];
double y2 = ortho[2][1];
double z2 = ortho[2][2];
double x3 = ortho[1][0];
double y3 = ortho[1][1];
double z3 = ortho[1][2];
double d1 = sqrt(x2*x2 + z2*z2);
double cosTheta, sinTheta;
if (d1 < VTK_AXIS_EPSILON)
{
cosTheta = 1.0;
sinTheta = 0.0;
}
else
{
cosTheta = z2/d1;
sinTheta = x2/d1;
}
double theta = atan2(sinTheta, cosTheta);
orientation[1] = -theta/vtkMath::DoubleDegreesToRadians();
// now rotate about x axis
double d = sqrt(x2*x2 + y2*y2 + z2*z2);
double sinPhi, cosPhi;
if (d < VTK_AXIS_EPSILON)
{
sinPhi = 0.0;
cosPhi = 1.0;
}
else if (d1 < VTK_AXIS_EPSILON)
{
sinPhi = y2/d;
cosPhi = z2/d;
}
else
{
sinPhi = y2/d;
cosPhi = (x2*x2 + z2*z2)/(d1*d);
}
double phi = atan2(sinPhi, cosPhi);
orientation[0] = phi/vtkMath::DoubleDegreesToRadians();
// finally, rotate about z
double x3p = x3*cosTheta - z3*sinTheta;
double y3p = - sinPhi*sinTheta*x3 + cosPhi*y3 - sinPhi*cosTheta*z3;
double d2 = sqrt(x3p*x3p + y3p*y3p);
double cosAlpha, sinAlpha;
if (d2 < VTK_AXIS_EPSILON)
{
cosAlpha = 1.0;
sinAlpha = 0.0;
}
else
{
cosAlpha = y3p/d2;
sinAlpha = x3p/d2;
}
double alpha = atan2(sinAlpha, cosAlpha);
orientation[2] = alpha/vtkMath::DoubleDegreesToRadians();
}
//----------------------------------------------------------------------------
// Get the x, y, z orientation angles from the transformation matrix as an
// array of three floating point values.
void vtkTransform::GetOrientation(double orientation[3])
{
this->Update();
this->GetOrientation(orientation, this->Matrix);
}
//----------------------------------------------------------------------------
// vtkTransform::GetOrientationWXYZ
void vtkTransform::GetOrientationWXYZ(double wxyz[4])
{
int i;
this->Update();
// convenient access to matrix
double (*matrix)[4] = this->Matrix->Element;
double ortho[3][3];
for (i = 0; i < 3; i++)
{
ortho[0][i] = matrix[0][i];
ortho[1][i] = matrix[1][i];
ortho[2][i] = matrix[2][i];
}
if (vtkMath::Determinant3x3(ortho) < 0)
{
ortho[0][i] = -ortho[0][i];
ortho[1][i] = -ortho[1][i];
ortho[2][i] = -ortho[2][i];
}
vtkMath::Matrix3x3ToQuaternion(ortho, wxyz);
// calc the return value wxyz
double mag = sqrt(wxyz[1]*wxyz[1] + wxyz[2]*wxyz[2] + wxyz[3]*wxyz[3]);
if (mag)
{
wxyz[0] = 2.0*acos(wxyz[0])/vtkMath::DoubleDegreesToRadians();
wxyz[1] /= mag;
wxyz[2] /= mag;
wxyz[3] /= mag;
}
else
{
wxyz[0] = 0.0;
wxyz[1] = 0.0;
wxyz[2] = 0.0;
wxyz[3] = 1.0;
}
}
//----------------------------------------------------------------------------
// Return the position from the current transformation matrix as an array
// of three floating point numbers. This is simply returning the translation
// component of the 4x4 matrix.
void vtkTransform::GetPosition(double position[3])
{
this->Update();
position[0] = this->Matrix->Element[0][3];
position[1] = this->Matrix->Element[1][3];
position[2] = this->Matrix->Element[2][3];
}
//----------------------------------------------------------------------------
// Return the x, y, z scale factors of the current transformation matrix as
// an array of three float numbers.
void vtkTransform::GetScale(double scale[3])
{
this->Update();
// convenient access to matrix
double (*matrix)[4] = this->Matrix->Element;
double U[3][3], VT[3][3];
for (int i = 0; i < 3; i++)
{
U[0][i] = matrix[0][i];
U[1][i] = matrix[1][i];
U[2][i] = matrix[2][i];
}
vtkMath::SingularValueDecomposition3x3(U, U, scale, VT);
}
//----------------------------------------------------------------------------
// Return the inverse of the current transformation matrix.
void vtkTransform::GetInverse(vtkMatrix4x4 *inverse)
{
vtkMatrix4x4::Invert(this->GetMatrix(),inverse);
}
//----------------------------------------------------------------------------
// Obtain the transpose of the current transformation matrix.
void vtkTransform::GetTranspose(vtkMatrix4x4 *transpose)
{
vtkMatrix4x4::Transpose(this->GetMatrix(),transpose);
}