You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
547 lines
16 KiB
C++
547 lines
16 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkSampleFunction.cxx
|
|
|
|
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 "vtkSampleFunction.h"
|
|
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkGarbageCollector.h"
|
|
#include "vtkImageData.h"
|
|
#include "vtkImplicitFunction.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkSMPTools.h"
|
|
|
|
vtkStandardNewMacro(vtkSampleFunction);
|
|
vtkCxxSetObjectMacro(vtkSampleFunction,ImplicitFunction,vtkImplicitFunction);
|
|
|
|
// The heart of the algorithm plus interface to the SMP tools.
|
|
template <class T>
|
|
class vtkSampleFunctionAlgorithm
|
|
{
|
|
public:
|
|
vtkImplicitFunction *ImplicitFunction;
|
|
T *Scalars;
|
|
float *Normals;
|
|
vtkIdType Extent[6];
|
|
vtkIdType Dims[3];
|
|
vtkIdType SliceSize;
|
|
double Origin[3];
|
|
double Spacing[3];
|
|
double CapValue;
|
|
|
|
// Contructor
|
|
vtkSampleFunctionAlgorithm();
|
|
|
|
// Interface between VTK and templated functions
|
|
static void SampleAcrossImage(vtkSampleFunction *self, vtkImageData *output,
|
|
int extent[6], T *scalars, float *normals);
|
|
|
|
// Cap the boundaries with the specified cap value (if requested).
|
|
void Cap();
|
|
|
|
// Interface implicit function computation to SMP tools.
|
|
template <class TT> class FunctionValueOp
|
|
{
|
|
public:
|
|
FunctionValueOp(vtkSampleFunctionAlgorithm<TT> *algo)
|
|
{ this->Algo = algo;}
|
|
vtkSampleFunctionAlgorithm *Algo;
|
|
|
|
void operator() (vtkIdType k, vtkIdType end)
|
|
{
|
|
double x[3];
|
|
vtkIdType *extent=this->Algo->Extent;
|
|
vtkIdType i, j, jOffset, kOffset;
|
|
for ( ; k < end; ++k)
|
|
{
|
|
x[2] = this->Algo->Origin[2] + k*this->Algo->Spacing[2];
|
|
kOffset = (k-extent[4]) * this->Algo->SliceSize;
|
|
for (j=extent[2]; j<=extent[3]; ++j)
|
|
{
|
|
x[1] = this->Algo->Origin[1] + j*this->Algo->Spacing[1];
|
|
jOffset = (j-extent[2])*this->Algo->Dims[0];
|
|
for (i=extent[0]; i<=extent[1]; ++i)
|
|
{
|
|
x[0] = this->Algo->Origin[0] + i*this->Algo->Spacing[0];
|
|
this->Algo->Scalars[(i-extent[0])+jOffset+kOffset] =
|
|
static_cast<TT>(this->Algo->ImplicitFunction->FunctionValue(x));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Interface implicit function graadient computation to SMP tools.
|
|
template <class TT> class FunctionGradientOp
|
|
{
|
|
public:
|
|
FunctionGradientOp(vtkSampleFunctionAlgorithm<TT> *algo)
|
|
{ this->Algo = algo;}
|
|
vtkSampleFunctionAlgorithm *Algo;
|
|
|
|
void operator() (vtkIdType k, vtkIdType end)
|
|
{
|
|
double x[3], n[3];
|
|
float *nPtr;
|
|
vtkIdType *extent=this->Algo->Extent;
|
|
vtkIdType i, j, jOffset, kOffset;
|
|
for ( ; k < end; ++k)
|
|
{
|
|
x[2] = this->Algo->Origin[2] + k*this->Algo->Spacing[2];
|
|
kOffset = (k-extent[4]) * this->Algo->SliceSize;
|
|
for (j=extent[2]; j<=extent[3]; ++j)
|
|
{
|
|
x[1] = this->Algo->Origin[1] + j*this->Algo->Spacing[1];
|
|
jOffset = (j-extent[2]) * this->Algo->Dims[0];
|
|
for (i=extent[0]; i<=extent[1]; ++i)
|
|
{
|
|
x[0] = this->Algo->Origin[0] + i*this->Algo->Spacing[0];
|
|
this->Algo->ImplicitFunction->FunctionGradient(x,n);
|
|
vtkMath::Normalize(n);
|
|
nPtr = this->Algo->Normals + 3*((i-extent[0])+jOffset+kOffset);
|
|
nPtr[0] = static_cast<TT>(-n[0]);
|
|
nPtr[1] = static_cast<TT>(-n[1]);
|
|
nPtr[2] = static_cast<TT>(-n[2]);
|
|
}//i
|
|
}//j
|
|
}//k
|
|
}
|
|
};
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Initialized mainly to eliminate compiler warnings.
|
|
template <class T> vtkSampleFunctionAlgorithm<T>::
|
|
vtkSampleFunctionAlgorithm():Scalars(NULL),Normals(NULL)
|
|
{
|
|
for (int i=0; i<3; ++i)
|
|
{
|
|
this->Extent[2*i] = this->Extent[2*i+1] = 0;
|
|
this->Dims[i] = 0;
|
|
this->Origin[i] = this->Spacing[i] = 0.0;
|
|
}
|
|
this->SliceSize = 0;
|
|
this->CapValue = 0.0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Templated class is glue between VTK and templated algorithms.
|
|
template <class T> void vtkSampleFunctionAlgorithm<T>::
|
|
SampleAcrossImage(vtkSampleFunction *self, vtkImageData *output,
|
|
int extent[6], T *scalars, float *normals)
|
|
{
|
|
// Populate data into local storage
|
|
vtkSampleFunctionAlgorithm<T> algo;
|
|
algo.ImplicitFunction = self->GetImplicitFunction();
|
|
algo.Scalars = scalars;
|
|
algo.Normals = normals;
|
|
for (int i=0; i<3; ++i)
|
|
{
|
|
algo.Extent[2*i] = extent[2*i];
|
|
algo.Extent[2*i+1] = extent[2*i+1];
|
|
algo.Dims[i] = extent[2*i+1] - extent[2*i] + 1;
|
|
}
|
|
algo.SliceSize = algo.Dims[0]*algo.Dims[1];
|
|
output->GetOrigin(algo.Origin);
|
|
output->GetSpacing(algo.Spacing);
|
|
algo.CapValue = self->GetCapValue();
|
|
|
|
// Okay now generate samples using SMP tools
|
|
FunctionValueOp<T> values(&algo);
|
|
vtkSMPTools::For(extent[4],extent[5]+1, values);
|
|
|
|
// If requested, generate normals
|
|
if ( algo.Normals )
|
|
{
|
|
FunctionGradientOp<T> gradient(&algo);
|
|
vtkSMPTools::For(extent[4],extent[5]+1, gradient);
|
|
}
|
|
|
|
// If requested, cap boundaries
|
|
if ( self->GetCapping() )
|
|
{
|
|
algo.Cap();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Cap the boundaries of the volume if requested.
|
|
template <class T> void vtkSampleFunctionAlgorithm<T>::Cap()
|
|
{
|
|
vtkIdType i,j,k;
|
|
vtkIdType idx;
|
|
|
|
// i-j planes
|
|
//k = this->Extent[4];
|
|
for (j=this->Extent[2]; j<=this->Extent[3]; j++)
|
|
{
|
|
for (i=this->Extent[0]; i<=this->Extent[1]; i++)
|
|
{
|
|
this->Scalars[i+j*this->Dims[0]] = this->CapValue;
|
|
}
|
|
}
|
|
|
|
idx = this->Extent[5]*this->SliceSize;
|
|
for (j=this->Extent[2]; j<=this->Extent[3]; j++)
|
|
{
|
|
for (i=this->Extent[0]; i<=this->Extent[1]; i++)
|
|
{
|
|
this->Scalars[idx+i+j*this->Dims[0]] = this->CapValue;
|
|
}
|
|
}
|
|
|
|
// j-k planes
|
|
//i = this->Extent[0];
|
|
for (k=this->Extent[4]; k<=this->Extent[5]; k++)
|
|
{
|
|
for (j=this->Extent[2]; j<=this->Extent[3]; j++)
|
|
{
|
|
this->Scalars[j*this->Dims[0]+k*this->SliceSize] =
|
|
this->CapValue;
|
|
}
|
|
}
|
|
|
|
i = this->Extent[1];
|
|
for (k=this->Extent[4]; k<=this->Extent[5]; k++)
|
|
{
|
|
for (j=this->Extent[2]; j<=this->Extent[3]; j++)
|
|
{
|
|
this->Scalars[i+j*this->Dims[0]+k*this->SliceSize] =
|
|
this->CapValue;
|
|
}
|
|
}
|
|
|
|
// i-k planes
|
|
//j = this->Extent[2];
|
|
for (k=this->Extent[4]; k<=this->Extent[5]; k++)
|
|
{
|
|
for (i=this->Extent[0]; i<=this->Extent[1]; i++)
|
|
{
|
|
this->Scalars[i+k*this->SliceSize] = this->CapValue;
|
|
}
|
|
}
|
|
|
|
j = this->Extent[3];
|
|
idx = j*this->Dims[0];
|
|
for (k=this->Extent[4]; k<=this->Extent[5]; k++)
|
|
{
|
|
for (i=this->Extent[0]; i<=this->Extent[1]; i++)
|
|
{
|
|
this->Scalars[idx+i+k*this->SliceSize] = this->CapValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Okay define the VTK class proper
|
|
vtkSampleFunction::vtkSampleFunction()
|
|
{
|
|
this->ModelBounds[0] = -1.0;
|
|
this->ModelBounds[1] = 1.0;
|
|
this->ModelBounds[2] = -1.0;
|
|
this->ModelBounds[3] = 1.0;
|
|
this->ModelBounds[4] = -1.0;
|
|
this->ModelBounds[5] = 1.0;
|
|
|
|
this->SampleDimensions[0] = 50;
|
|
this->SampleDimensions[1] = 50;
|
|
this->SampleDimensions[2] = 50;
|
|
|
|
this->Capping = 0;
|
|
this->CapValue = VTK_DOUBLE_MAX;
|
|
|
|
this->ImplicitFunction = NULL;
|
|
|
|
this->ComputeNormals = 1;
|
|
this->OutputScalarType = VTK_DOUBLE;
|
|
|
|
this->ScalarArrayName=0;
|
|
this->SetScalarArrayName("scalars");
|
|
|
|
this->NormalArrayName=0;
|
|
this->SetNormalArrayName("normals");
|
|
|
|
this->SetNumberOfInputPorts(0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkSampleFunction::~vtkSampleFunction()
|
|
{
|
|
this->SetImplicitFunction(NULL);
|
|
this->SetScalarArrayName(NULL);
|
|
this->SetNormalArrayName(NULL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Specify the dimensions of the data on which to sample.
|
|
void vtkSampleFunction::SetSampleDimensions(int i, int j, int k)
|
|
{
|
|
int dim[3];
|
|
|
|
dim[0] = i;
|
|
dim[1] = j;
|
|
dim[2] = k;
|
|
|
|
this->SetSampleDimensions(dim);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Specify the dimensions of the data on which to sample.
|
|
void vtkSampleFunction::SetSampleDimensions(int dim[3])
|
|
{
|
|
vtkDebugMacro(<< " setting SampleDimensions to (" << dim[0] << "," << dim[1] << "," << dim[2] << ")");
|
|
|
|
if ( dim[0] != this->SampleDimensions[0] ||
|
|
dim[1] != this->SampleDimensions[1] ||
|
|
dim[2] != this->SampleDimensions[2] )
|
|
{
|
|
for ( int i=0; i<3; i++)
|
|
{
|
|
this->SampleDimensions[i] = (dim[i] > 0 ? dim[i] : 1);
|
|
}
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Set the bounds of the model.
|
|
void vtkSampleFunction::SetModelBounds(const double bounds[6])
|
|
{
|
|
this->SetModelBounds(bounds[0], bounds[1],
|
|
bounds[2], bounds[3],
|
|
bounds[4], bounds[5]);
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkSampleFunction::SetModelBounds(double xMin, double xMax,
|
|
double yMin, double yMax,
|
|
double zMin, double zMax)
|
|
{
|
|
vtkDebugMacro(<< " setting ModelBounds to ("
|
|
<< "(" << xMin << "," << xMax << "), "
|
|
<< "(" << yMin << "," << yMax << "), "
|
|
<< "(" << zMin << "," << zMax << "), ");
|
|
if ((xMin > xMax) ||
|
|
(yMin > yMax) ||
|
|
(zMin > zMax))
|
|
{
|
|
vtkErrorMacro("Invalid bounds: "
|
|
<< "(" << xMin << "," << xMax << "), "
|
|
<< "(" << yMin << "," << yMax << "), "
|
|
<< "(" << zMin << "," << zMax << ")"
|
|
<< " Bound mins cannot be larger that bound maxs");
|
|
return;
|
|
}
|
|
if (xMin != this->ModelBounds[0] ||
|
|
xMax != this->ModelBounds[1] ||
|
|
yMin != this->ModelBounds[2] ||
|
|
yMax != this->ModelBounds[3] ||
|
|
zMin != this->ModelBounds[4] ||
|
|
zMax != this->ModelBounds[5])
|
|
{
|
|
this->ModelBounds[0] = xMin;
|
|
this->ModelBounds[1] = xMax;
|
|
this->ModelBounds[2] = yMin;
|
|
this->ModelBounds[3] = yMax;
|
|
this->ModelBounds[4] = zMin;
|
|
this->ModelBounds[5] = zMax;
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkSampleFunction::RequestInformation (
|
|
vtkInformation * vtkNotUsed(request),
|
|
vtkInformationVector ** vtkNotUsed( inputVector ),
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
// get the info objects
|
|
vtkInformation* outInfo = outputVector->GetInformationObject(0);
|
|
|
|
int i;
|
|
double ar[3], origin[3];
|
|
|
|
int wExt[6];
|
|
wExt[0] = 0; wExt[2] = 0; wExt[4] = 0;
|
|
wExt[1] = this->SampleDimensions[0]-1;
|
|
wExt[3] = this->SampleDimensions[1]-1;
|
|
wExt[5] = this->SampleDimensions[2]-1;
|
|
|
|
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wExt, 6);
|
|
|
|
for (i=0; i < 3; i++)
|
|
{
|
|
origin[i] = this->ModelBounds[2*i];
|
|
if ( this->SampleDimensions[i] <= 1 )
|
|
{
|
|
ar[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
ar[i] = (this->ModelBounds[2*i+1] - this->ModelBounds[2*i])
|
|
/ (this->SampleDimensions[i] - 1);
|
|
}
|
|
}
|
|
outInfo->Set(vtkDataObject::ORIGIN(),origin,3);
|
|
outInfo->Set(vtkDataObject::SPACING(),ar,3);
|
|
|
|
vtkDataObject::
|
|
SetPointDataActiveScalarInfo(outInfo,this->OutputScalarType,1);
|
|
|
|
outInfo->Set(vtkAlgorithm::CAN_PRODUCE_SUB_EXTENT(), 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Produce the data.
|
|
void vtkSampleFunction::
|
|
ExecuteDataWithInformation(vtkDataObject *outp, vtkInformation *outInfo)
|
|
{
|
|
vtkFloatArray *newNormals=NULL;
|
|
float *normals=NULL;
|
|
|
|
vtkImageData *output=this->GetOutput();
|
|
int* extent =
|
|
this->GetExecutive()->GetOutputInformation(0)->Get(
|
|
vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
|
|
|
|
output->SetExtent(extent);
|
|
output = this->AllocateOutputData(outp, outInfo);
|
|
vtkDataArray *newScalars =output->GetPointData()->GetScalars();
|
|
vtkIdType numPts = newScalars->GetNumberOfTuples();
|
|
|
|
vtkDebugMacro(<< "Sampling implicit function");
|
|
|
|
// Initialize self; create output objects
|
|
//
|
|
if ( !this->ImplicitFunction )
|
|
{
|
|
vtkErrorMacro(<<"No implicit function specified");
|
|
return;
|
|
}
|
|
|
|
if ( this->ComputeNormals )
|
|
{
|
|
newNormals = vtkFloatArray::New();
|
|
newNormals->SetNumberOfComponents(3);
|
|
newNormals->SetNumberOfTuples(numPts);
|
|
normals = newNormals->WritePointer(0,numPts);
|
|
}
|
|
|
|
void *ptr = output->GetArrayPointerForExtent(newScalars, extent);
|
|
switch (newScalars->GetDataType())
|
|
{
|
|
vtkTemplateMacro(vtkSampleFunctionAlgorithm<VTK_TT>::
|
|
SampleAcrossImage(this, output, extent, (VTK_TT *)ptr,
|
|
normals));
|
|
}
|
|
|
|
newScalars->SetName(this->ScalarArrayName);
|
|
|
|
// Update self
|
|
//
|
|
if (newNormals)
|
|
{
|
|
// For an unknown reason yet, if the following line is not commented out,
|
|
// it will make ImplicitSum, TestBoxFunction and TestDiscreteMarchingCubes
|
|
// to fail.
|
|
newNormals->SetName(this->NormalArrayName);
|
|
output->GetPointData()->SetNormals(newNormals);
|
|
newNormals->Delete();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkMTimeType vtkSampleFunction::GetMTime()
|
|
{
|
|
vtkMTimeType mTime=this->Superclass::GetMTime();
|
|
vtkMTimeType impFuncMTime;
|
|
|
|
if ( this->ImplicitFunction != NULL )
|
|
{
|
|
impFuncMTime = this->ImplicitFunction->GetMTime();
|
|
mTime = ( impFuncMTime > mTime ? impFuncMTime : mTime );
|
|
}
|
|
|
|
return mTime;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkSampleFunction::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", "
|
|
<< this->SampleDimensions[1] << ", "
|
|
<< this->SampleDimensions[2] << ")\n";
|
|
os << indent << "ModelBounds: \n";
|
|
os << indent << " Xmin,Xmax: (" << this->ModelBounds[0]
|
|
<< ", " << this->ModelBounds[1] << ")\n";
|
|
os << indent << " Ymin,Ymax: (" << this->ModelBounds[2]
|
|
<< ", " << this->ModelBounds[3] << ")\n";
|
|
os << indent << " Zmin,Zmax: (" << this->ModelBounds[4]
|
|
<< ", " << this->ModelBounds[5] << ")\n";
|
|
|
|
os << indent << "OutputScalarType: " << this->OutputScalarType << "\n";
|
|
|
|
if ( this->ImplicitFunction )
|
|
{
|
|
os << indent << "Implicit Function: " << this->ImplicitFunction << "\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "No Implicit function defined\n";
|
|
}
|
|
|
|
os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");
|
|
os << indent << "Cap Value: " << this->CapValue << "\n";
|
|
|
|
os << indent << "Compute Normals: " << (this->ComputeNormals ? "On\n" : "Off\n");
|
|
|
|
os << indent << "ScalarArrayName: ";
|
|
if(this->ScalarArrayName!=0)
|
|
{
|
|
os << this->ScalarArrayName << endl;
|
|
}
|
|
else
|
|
{
|
|
os << "(none)" << endl;
|
|
}
|
|
|
|
os << indent << "NormalArrayName: ";
|
|
if(this->NormalArrayName!=0)
|
|
{
|
|
os << this->NormalArrayName << endl;
|
|
}
|
|
else
|
|
{
|
|
os << "(none)" << endl;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkSampleFunction::ReportReferences(vtkGarbageCollector* collector)
|
|
{
|
|
this->Superclass::ReportReferences(collector);
|
|
vtkGarbageCollectorReport(collector, this->ImplicitFunction,
|
|
"ImplicitFunction");
|
|
}
|