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.
477 lines
13 KiB
477 lines
13 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkTransformToGrid.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 "vtkTransformToGrid.h"
|
|
|
|
#include "vtkAbstractTransform.h"
|
|
#include "vtkIdentityTransform.h"
|
|
#include "vtkImageData.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
|
|
vtkCxxRevisionMacro(vtkTransformToGrid, "$Revision: 1.21 $");
|
|
vtkStandardNewMacro(vtkTransformToGrid);
|
|
|
|
vtkCxxSetObjectMacro(vtkTransformToGrid,Input,vtkAbstractTransform);
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkTransformToGrid::vtkTransformToGrid()
|
|
{
|
|
this->Input = NULL;
|
|
|
|
this->GridScalarType = VTK_DOUBLE;
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
this->GridExtent[2*i] = this->GridExtent[2*i+1] = 0;
|
|
this->GridOrigin[i] = 0.0;
|
|
this->GridSpacing[i] = 1.0;
|
|
}
|
|
|
|
this->DisplacementScale = 1.0;
|
|
this->DisplacementShift = 0.0;
|
|
this->SetNumberOfInputPorts(0);
|
|
this->SetNumberOfOutputPorts(1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkTransformToGrid::~vtkTransformToGrid()
|
|
{
|
|
this->SetInput(static_cast<vtkAbstractTransform*>(0));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkTransformToGrid::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
int i;
|
|
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Input: (" << this->Input << ")\n";
|
|
|
|
os << indent << "GridSpacing: (" << this->GridSpacing[0];
|
|
for (i = 1; i < 3; ++i)
|
|
{
|
|
os << ", " << this->GridSpacing[i];
|
|
}
|
|
os << ")\n";
|
|
|
|
os << indent << "GridOrigin: (" << this->GridOrigin[0];
|
|
for (i = 1; i < 3; ++i)
|
|
{
|
|
os << ", " << this->GridOrigin[i];
|
|
}
|
|
os << ")\n";
|
|
|
|
os << indent << "GridExtent: (" << this->GridExtent[0];
|
|
for (i = 1; i < 6; ++i)
|
|
{
|
|
os << ", " << this->GridExtent[i];
|
|
}
|
|
os << ")\n";
|
|
|
|
os << indent << "GridScalarType: " <<
|
|
vtkImageScalarTypeNameMacro(this->GridScalarType) << "\n";
|
|
|
|
this->UpdateShiftScale();
|
|
|
|
os << indent << "DisplacementScale: " << this->DisplacementScale << "\n";
|
|
os << indent << "DisplacementShift: " << this->DisplacementShift << "\n";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// This method returns the largest data that can be generated.
|
|
void vtkTransformToGrid::RequestInformation (
|
|
vtkInformation * vtkNotUsed(request),
|
|
vtkInformationVector ** vtkNotUsed( inputVector ),
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
// get the info objects
|
|
vtkInformation* outInfo = outputVector->GetInformationObject(0);
|
|
|
|
|
|
if (this->GetInput() == NULL)
|
|
{
|
|
vtkErrorMacro("Missing input");
|
|
return;
|
|
}
|
|
|
|
// update the transform, maybe in the future make transforms part of the
|
|
// pipeline
|
|
this->Input->Update();
|
|
|
|
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
|
|
this->GridExtent,6);
|
|
outInfo->Set(vtkDataObject::SPACING(),this->GridSpacing,3);
|
|
outInfo->Set(vtkDataObject::ORIGIN(),this->GridOrigin,3);
|
|
vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->GridScalarType, 3);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Return the maximum absolute displacement of the transform over
|
|
// the entire grid extent -- this is extremely robust and extremely
|
|
// inefficient, it should be possible to do much better than this.
|
|
void vtkTransformToGridMinMax(vtkTransformToGrid *self, int extent[6],
|
|
double &minDisplacement, double &maxDisplacement)
|
|
{
|
|
vtkAbstractTransform *transform = self->GetInput();
|
|
transform->Update();
|
|
|
|
if (!transform)
|
|
{
|
|
minDisplacement = -1.0;
|
|
maxDisplacement = +1.0;
|
|
return;
|
|
}
|
|
|
|
double *spacing = self->GetGridSpacing();
|
|
double *origin = self->GetGridOrigin();
|
|
|
|
maxDisplacement = -1e37;
|
|
minDisplacement = +1e37;
|
|
|
|
double point[3],newPoint[3],displacement;
|
|
|
|
for (int k = extent[4]; k <= extent[5]; k++)
|
|
{
|
|
point[2] = k*spacing[2] + origin[2];
|
|
for (int j = extent[2]; j <= extent[3]; j++)
|
|
{
|
|
point[1] = j*spacing[1] + origin[1];
|
|
for (int i = extent[0]; i <= extent[1]; i++)
|
|
{
|
|
point[0] = i*spacing[0] + origin[0];
|
|
|
|
transform->InternalTransformPoint(point,newPoint);
|
|
|
|
for (int l = 0; l < 3; l++)
|
|
{
|
|
displacement = newPoint[l] - point[l];
|
|
|
|
if (displacement > maxDisplacement)
|
|
{
|
|
maxDisplacement = displacement;
|
|
}
|
|
|
|
if (displacement < minDisplacement)
|
|
{
|
|
minDisplacement = displacement;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkTransformToGrid::UpdateShiftScale()
|
|
{
|
|
int gridType = this->GridScalarType;
|
|
|
|
// nothing to do for double or double
|
|
if (gridType == VTK_DOUBLE || gridType == VTK_DOUBLE)
|
|
{
|
|
this->DisplacementShift = 0.0;
|
|
this->DisplacementScale = 1.0;
|
|
vtkDebugMacro(<< "displacement (scale, shift) = (" <<
|
|
this->DisplacementScale << ", " <<
|
|
this->DisplacementShift << ")");
|
|
return;
|
|
}
|
|
|
|
// check mtime
|
|
if (this->ShiftScaleTime.GetMTime() > this->GetMTime())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// get the maximum displacement
|
|
double minDisplacement, maxDisplacement;
|
|
vtkTransformToGridMinMax(this,this->GridExtent,
|
|
minDisplacement,
|
|
maxDisplacement);
|
|
|
|
vtkDebugMacro(<< "displacement (min, max) = (" <<
|
|
minDisplacement << ", " << maxDisplacement << ")");
|
|
|
|
double typeMin,typeMax;
|
|
|
|
switch (gridType)
|
|
{
|
|
case VTK_SHORT:
|
|
typeMin = VTK_SHORT_MIN;
|
|
typeMax = VTK_SHORT_MAX;
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
typeMin = VTK_UNSIGNED_SHORT_MIN;
|
|
typeMax = VTK_UNSIGNED_SHORT_MAX;
|
|
break;
|
|
case VTK_CHAR:
|
|
typeMin = VTK_CHAR_MIN;
|
|
typeMax = VTK_CHAR_MAX;
|
|
break;
|
|
case VTK_UNSIGNED_CHAR:
|
|
typeMin = VTK_UNSIGNED_CHAR_MIN;
|
|
typeMax = VTK_UNSIGNED_CHAR_MAX;
|
|
break;
|
|
default:
|
|
vtkErrorMacro(<< "UpdateShiftScale: Unknown input ScalarType");
|
|
return;
|
|
}
|
|
|
|
this->DisplacementScale = ((maxDisplacement - minDisplacement)/
|
|
(typeMax - typeMin));
|
|
this->DisplacementShift = ((typeMax*minDisplacement-typeMin*maxDisplacement)/
|
|
(typeMax - typeMin));
|
|
|
|
if (this->DisplacementScale == 0.0)
|
|
{
|
|
this->DisplacementScale = 1.0;
|
|
}
|
|
|
|
vtkDebugMacro(<< "displacement (scale, shift) = (" <<
|
|
this->DisplacementScale << ", " <<
|
|
this->DisplacementShift << ")");
|
|
|
|
this->ShiftScaleTime.Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// macros to ensure proper round-to-nearest behaviour
|
|
|
|
inline void vtkGridRound(double val, unsigned char& rnd)
|
|
{
|
|
rnd = (unsigned char)(val+0.5f);
|
|
}
|
|
|
|
inline void vtkGridRound(double val, char& rnd)
|
|
{
|
|
rnd = (char)((val+128.5f)-128);
|
|
}
|
|
|
|
inline void vtkGridRound(double val, short& rnd)
|
|
{
|
|
rnd = (short)((int)(val+32768.5f)-32768);
|
|
}
|
|
|
|
inline void vtkGridRound(double val, unsigned short& rnd)
|
|
{
|
|
rnd = (unsigned short)(val+0.5f);
|
|
}
|
|
|
|
inline void vtkGridRound(double val, double& rnd)
|
|
{
|
|
rnd = (double)(val);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template<class T>
|
|
void vtkTransformToGridExecute(vtkTransformToGrid *self,
|
|
vtkImageData *grid, T *gridPtr, int extent[6],
|
|
double shift, double scale, int id)
|
|
{
|
|
vtkAbstractTransform *transform = self->GetInput();
|
|
int isIdentity = 0;
|
|
if (transform == 0)
|
|
{
|
|
transform = vtkIdentityTransform::New();
|
|
isIdentity = 1;
|
|
}
|
|
|
|
double *spacing = grid->GetSpacing();
|
|
double *origin = grid->GetOrigin();
|
|
vtkIdType *increments = grid->GetIncrements();
|
|
|
|
double invScale = 1.0/scale;
|
|
|
|
double point[3];
|
|
double newPoint[3];
|
|
|
|
T *gridPtr0 = gridPtr;
|
|
|
|
unsigned long count = 0;
|
|
unsigned long target = (unsigned long)
|
|
((extent[5]-extent[4]+1)*(extent[3]-extent[2]+1)/50.0);
|
|
target++;
|
|
|
|
for (int k = extent[4]; k <= extent[5]; k++)
|
|
{
|
|
point[2] = k*spacing[2] + origin[2];
|
|
T *gridPtr1 = gridPtr0;
|
|
|
|
for (int j = extent[2]; j <= extent[3]; j++)
|
|
{
|
|
|
|
if (id == 0)
|
|
{
|
|
if (count % target == 0)
|
|
{
|
|
self->UpdateProgress(count/(50.0*target));
|
|
}
|
|
count++;
|
|
}
|
|
|
|
point[1] = j*spacing[1] + origin[1];
|
|
gridPtr = gridPtr1;
|
|
|
|
for (int i = extent[0]; i <= extent[1]; i++)
|
|
{
|
|
point[0] = i*spacing[0] + origin[0];
|
|
|
|
transform->InternalTransformPoint(point,newPoint);
|
|
|
|
vtkGridRound((newPoint[0] - point[0] - shift)*invScale,*gridPtr++);
|
|
vtkGridRound((newPoint[1] - point[1] - shift)*invScale,*gridPtr++);
|
|
vtkGridRound((newPoint[2] - point[2] - shift)*invScale,*gridPtr++);
|
|
}
|
|
|
|
gridPtr1 += increments[1];
|
|
}
|
|
|
|
gridPtr0 += increments[2];
|
|
}
|
|
|
|
if (isIdentity)
|
|
{
|
|
transform->Delete();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkTransformToGrid::RequestData(
|
|
vtkInformation* vtkNotUsed( request ),
|
|
vtkInformationVector** vtkNotUsed( inputVector ),
|
|
vtkInformationVector* outputVector)
|
|
{
|
|
// get the data object
|
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
|
vtkImageData *grid = vtkImageData::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
grid->SetExtent(
|
|
outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()));
|
|
grid->AllocateScalars();
|
|
int *extent = grid->GetExtent();
|
|
|
|
double *gridPtr = (double *)grid->GetScalarPointerForExtent(extent);
|
|
int gridType = grid->GetScalarType();
|
|
|
|
this->UpdateShiftScale();
|
|
|
|
double scale = this->DisplacementScale;
|
|
double shift = this->DisplacementShift;
|
|
|
|
int id = 0;
|
|
|
|
switch (gridType)
|
|
{
|
|
case VTK_DOUBLE:
|
|
vtkTransformToGridExecute(this, grid, (double *)(gridPtr), extent,
|
|
shift,scale,id);
|
|
break;
|
|
case VTK_SHORT:
|
|
vtkTransformToGridExecute(this, grid, (short *)(gridPtr), extent,
|
|
shift,scale,id);
|
|
break;
|
|
case VTK_UNSIGNED_SHORT:
|
|
vtkTransformToGridExecute(this, grid, (unsigned short *)(gridPtr),extent,
|
|
shift,scale,id);
|
|
break;
|
|
case VTK_CHAR:
|
|
vtkTransformToGridExecute(this, grid, (char *)(gridPtr), extent,
|
|
shift,scale,id);
|
|
break;
|
|
case VTK_UNSIGNED_CHAR:
|
|
vtkTransformToGridExecute(this, grid, (unsigned char *)(gridPtr), extent,
|
|
shift,scale,id);
|
|
break;
|
|
default:
|
|
vtkErrorMacro(<< "Execute: Unknown input ScalarType");
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned long vtkTransformToGrid::GetMTime()
|
|
{
|
|
unsigned long mtime = this->Superclass::GetMTime();
|
|
|
|
if (this->Input)
|
|
{
|
|
unsigned long mtime2 = this->Input->GetMTime();
|
|
if (mtime2 > mtime)
|
|
{
|
|
mtime = mtime2;
|
|
}
|
|
}
|
|
|
|
return mtime;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkTransformToGrid::ProcessRequest(vtkInformation* request,
|
|
vtkInformationVector** inputVector,
|
|
vtkInformationVector* outputVector)
|
|
{
|
|
// generate the data
|
|
if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
|
|
{
|
|
this->RequestData(request, inputVector, outputVector);
|
|
return 1;
|
|
}
|
|
|
|
// execute information
|
|
if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
|
|
{
|
|
this->RequestInformation(request, inputVector, outputVector);
|
|
// after executing set the origin and spacing from the
|
|
// info
|
|
int i;
|
|
for (i = 0; i < this->GetNumberOfOutputPorts(); ++i)
|
|
{
|
|
vtkInformation* info = outputVector->GetInformationObject(i);
|
|
vtkImageData *output =
|
|
vtkImageData::SafeDownCast(info->Get(vtkDataObject::DATA_OBJECT()));
|
|
// if execute info didn't set origin and spacing then we set them
|
|
if (!info->Has(vtkDataObject::ORIGIN()))
|
|
{
|
|
info->Set(vtkDataObject::ORIGIN(),0,0,0);
|
|
info->Set(vtkDataObject::SPACING(),1,1,1);
|
|
}
|
|
if (output)
|
|
{
|
|
output->SetOrigin(info->Get(vtkDataObject::ORIGIN()));
|
|
output->SetSpacing(info->Get(vtkDataObject::SPACING()));
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return this->Superclass::ProcessRequest(request, inputVector, outputVector);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkImageData* vtkTransformToGrid::GetOutput()
|
|
{
|
|
return vtkImageData::SafeDownCast(this->GetOutputDataObject(0));
|
|
}
|
|
|
|
int vtkTransformToGrid::FillOutputPortInformation(
|
|
int vtkNotUsed(port), vtkInformation* info)
|
|
{
|
|
// now add our info
|
|
info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkImageData");
|
|
return 1;
|
|
}
|
|
|