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.
 
 
 
 
 
 

1178 lines
34 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkImplicitModeller.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 "vtkImplicitModeller.h"
#include "vtkCell.h"
#include "vtkCellLocator.h"
#include "vtkClipPolyData.h"
#include "vtkCommand.h"
#include "vtkFloatArray.h"
#include "vtkGenericCell.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkMultiThreader.h"
#include "vtkMutexLock.h"
#include "vtkObjectFactory.h"
#include "vtkPlane.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkRectilinearGrid.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkStructuredGrid.h"
#include "vtkUnstructuredGrid.h"
#include "vtkImageIterator.h"
#include "vtkImageProgressIterator.h"
#include <math.h>
vtkCxxRevisionMacro(vtkImplicitModeller, "$Revision: 1.98 $");
vtkStandardNewMacro(vtkImplicitModeller);
struct vtkImplicitModellerAppendInfo
{
vtkImplicitModeller *Modeller;
vtkDataSet **Input;
double MaximumDistance;
};
//----------------------------------------------------------------------------
// Construct with sample dimensions=(50,50,50), and so that model bounds are
// automatically computed from the input. Capping is turned on with CapValue
// equal to a large positive number.
vtkImplicitModeller::vtkImplicitModeller()
{
this->MaximumDistance = 0.1;
this->ModelBounds[0] = 0.0;
this->ModelBounds[1] = 0.0;
this->ModelBounds[2] = 0.0;
this->ModelBounds[3] = 0.0;
this->ModelBounds[4] = 0.0;
this->ModelBounds[5] = 0.0;
this->BoundsComputed = 0;
this->SampleDimensions[0] = 50;
this->SampleDimensions[1] = 50;
this->SampleDimensions[2] = 50;
this->Capping = 1;
this->OutputScalarType = VTK_FLOAT;
this->CapValue = this->GetScalarTypeMax( this->OutputScalarType );
this->ScaleToMaximumDistance = 0; // only used for non-float output type
this->DataAppended = 0;
this->AdjustBounds = 1;
this->AdjustDistance = 0.0125;
this->ProcessMode = VTK_CELL_MODE;
this->LocatorMaxLevel = 5;
this->Threader = vtkMultiThreader::New();
this->NumberOfThreads = this->Threader->GetNumberOfThreads();
}
vtkImplicitModeller::~vtkImplicitModeller()
{
if (this->Threader)
{
this->Threader->Delete();
}
}
void vtkImplicitModeller::SetOutputScalarType(int type)
{
double scalarMax;
vtkDebugMacro(<< this->GetClassName() << " (" << this <<
"): setting OutputScalarType to " << type);
scalarMax = this->GetScalarTypeMax(type);
if (scalarMax) // legal type
{
int modified = 0;
if (this->CapValue != scalarMax)
{
this->CapValue = scalarMax;
modified = 1;
}
if (this->OutputScalarType != type)
{
this->OutputScalarType = type;
modified = 1;
}
if (modified)
{
this->Modified();
}
}
}
void vtkImplicitModeller::SetCapValue(double value)
{
vtkDebugMacro(<< this->GetClassName() << " (" << this <<
"): setting CapValue to " << value);
// clamp to between 0 and max for scalar type
double max = this->GetScalarTypeMax(this->OutputScalarType);
if (this->CapValue != (value < 0 ? 0 : (value > max ? max : value)))
{
this->CapValue = (value < 0 ? 0 : (value > max ? max : value));
this->Modified();
}
}
double vtkImplicitModeller::GetScalarTypeMax(int type)
{
switch (type)
{
case VTK_UNSIGNED_CHAR: return (double)VTK_UNSIGNED_CHAR_MAX;
case VTK_CHAR: return (double)VTK_CHAR_MAX;
case VTK_UNSIGNED_SHORT: return (double)VTK_UNSIGNED_SHORT_MAX;
case VTK_SHORT: return (double)VTK_SHORT_MAX;
case VTK_UNSIGNED_INT: return (double)VTK_UNSIGNED_INT_MAX;
case VTK_INT: return (double)VTK_INT_MAX;
case VTK_UNSIGNED_LONG: return (double)VTK_UNSIGNED_LONG_MAX;
case VTK_LONG: return (double)VTK_LONG_MAX;
case VTK_FLOAT: return (double)VTK_FLOAT_MAX;
case VTK_DOUBLE: return (double)VTK_DOUBLE_MAX;
default: return 0;
}
}
//----------------------------------------------------------------------------
// Initialize the filter for appending data. You must invoke the
// StartAppend() method before doing successive Appends(). It's also a
// good idea to manually specify the model bounds; otherwise the input
// bounds for the data will be used.
void vtkImplicitModeller::StartAppend()
{
this->StartAppend(0);
}
void vtkImplicitModeller::StartAppend(int internal)
{
vtkIdType numPts;
vtkIdType i;
double maxDistance;
if (!internal)
{
// we must call update information because we can't be sure that
// it has been called.
this->UpdateInformation();
}
this->GetOutput()->SetUpdateExtent(this->GetOutput()->GetWholeExtent());
vtkDebugMacro(<< "Initializing data");
this->AllocateOutputData(this->GetOutput());
this->UpdateProgress(0.0);
this->DataAppended = 1;
numPts = this->SampleDimensions[0] * this->SampleDimensions[1]
* this->SampleDimensions[2];
// initialize output to CapValue at each location
maxDistance = this->CapValue;
vtkDataArray *newScalars = this->GetOutput()->GetPointData()->GetScalars();
for (i=0; i<numPts; i++)
{
newScalars->SetComponent(i, 0, maxDistance);
}
}
template <class OT>
void SetOutputDistance(double distance, OT *outputValue, double capValue, double scaleFactor)
{
// for now, just doing "normal" cast... could consider doing round?
if (scaleFactor) // need to scale the distance
{
*outputValue = static_cast<OT>(distance * scaleFactor);
}
else
{
if (capValue && distance > capValue) // clamping iff non-float type
{
distance = capValue;
}
*outputValue = static_cast<OT>(distance);
}
}
// Convert distance as stored in output (could be scaled and/or non-double
// type) to double distance with correct scaling
void ConvertToDoubleDistance(double inDistance, double &distance,
double &distance2, double scaleFactor)
{
if (scaleFactor)
{
distance = inDistance * scaleFactor;
}
else
{
distance = inDistance;
}
distance2 = distance * distance;
}
//----------------------------------------------------------------------------
// Templated append for VTK_VOXEL_MODE process mode and any type of output data
template <class OT>
void vtkImplicitModellerAppendExecute(vtkImplicitModeller *self,
vtkDataSet *input, vtkImageData *outData,
int outExt[6], double maxDistance,
vtkCellLocator *locator, int id, OT *)
{
int i, j, k;
int subId;
vtkIdType cellId;
double pcoords[3];
double *spacing, *origin;
double maxDistance2 = maxDistance * maxDistance;
double x[3], prevDistance, prevDistance2, distance2, betterDistance;
double closestPoint[3], mDist;
// allocate weights for the EvaluatePosition
double *weights = new double[input->GetMaxCellSize()];
// Traverse each voxel; using CellLocator to find the closest point
vtkGenericCell *cell = vtkGenericCell::New();
spacing = outData->GetSpacing();
origin = outData->GetOrigin();
vtkImageProgressIterator<OT> outIt(outData, outExt, self, id);
// so we know how to scale if desired
double scaleFactor = 0; // 0 used to indicate not scaling
double toDoubleScaleFactor = 0; // 0 used to indicate not scaling
double capValue = 0; // 0 used to indicate not clamping (float or double)
if (self->GetOutputScalarType() != VTK_FLOAT &&
self->GetOutputScalarType() != VTK_DOUBLE)
{
capValue = self->GetCapValue();
if (self->GetScaleToMaximumDistance())
{
scaleFactor = capValue / maxDistance;
toDoubleScaleFactor = maxDistance / capValue;
}
}
int testIndex = 0;
for (k = outExt[4]; k <= outExt[5]; k++)
{
x[2] = spacing[2] * k + origin[2];
for (j = outExt[2]; j <= outExt[3]; j++)
{
cellId = -1;
x[1] = spacing[1] * j + origin[1];
OT* outSI = outIt.BeginSpan();
for (i = outExt[0]; i <= outExt[1]; i++, testIndex++)
{
x[0] = spacing[0] * i + origin[0];
ConvertToDoubleDistance(*outSI, prevDistance, prevDistance2,
toDoubleScaleFactor);
betterDistance = -1;
if (cellId != -1)
{
cell->EvaluatePosition(x, closestPoint, subId, pcoords,
distance2, weights);
if (distance2 <= maxDistance2 && distance2 < prevDistance2)
{
mDist = sqrt(distance2);
betterDistance = mDist;
}
else if (prevDistance2 < maxDistance2)
{
mDist = prevDistance;
}
else
{
mDist = maxDistance;
}
}
else if (prevDistance2 < maxDistance2)
{
mDist = prevDistance;
}
else
{
mDist = maxDistance;
}
if (locator->FindClosestPointWithinRadius(x, mDist,
closestPoint, cell, cellId, subId, distance2) )
{
if(distance2 <= prevDistance2)
{
betterDistance = sqrt(distance2);
}
}
else
{
cellId = -1;
}
if (betterDistance != -1)
{
SetOutputDistance(betterDistance, outSI, capValue, scaleFactor);
}
outSI++;
}
outIt.NextSpan();
}
}
cell->Delete();
delete [] weights;
}
//----------------------------------------------------------------------------
// This is the multithreaded piece of the append when doing per voxel
// processing - it is called once for each thread, with each thread
// taking a different slab of the output to work on. The acutal work is done
// in vtkImplicitModellerAppendExecute; here we just setup for the per voxel
// processing.
static VTK_THREAD_RETURN_TYPE vtkImplicitModeller_ThreadedAppend( void *arg )
{
int threadCount;
int threadId;
vtkImplicitModellerAppendInfo *userData;
vtkImageData *output;
double maxDistance;
int i;
double *bounds, adjBounds[6];
double *spacing;
double *origin;
int slabSize, slabMin, slabMax;
int outExt[6];
threadId = ((vtkMultiThreader::ThreadInfo *)(arg))->ThreadID;
threadCount = ((vtkMultiThreader::ThreadInfo *)(arg))->NumberOfThreads;
userData = (vtkImplicitModellerAppendInfo *)
(((vtkMultiThreader::ThreadInfo *)(arg))->UserData);
if (userData->Input[threadId] == NULL)
{
return VTK_THREAD_RETURN_VALUE;
}
maxDistance = userData->MaximumDistance;
output = userData->Modeller->GetOutput();
spacing = output->GetSpacing();
origin = output->GetOrigin();
int *sampleDimensions = userData->Modeller->GetSampleDimensions();
if (!output->GetPointData()->GetScalars())
{
vtkGenericWarningMacro("Sanity check failed.");
return VTK_THREAD_RETURN_VALUE;
}
// break up into slabs based on threadId and threadCount
slabSize = sampleDimensions[2] / threadCount;
if (slabSize == 0) // in case threadCount > sampleDimensions[2]
{
slabSize = 1;
}
slabMin = threadId * slabSize;
if (slabMin >= sampleDimensions[2])
{
return VTK_THREAD_RETURN_VALUE;
}
slabMax = slabMin + slabSize - 1;
if (threadId == threadCount - 1)
{
slabMax = sampleDimensions[2] - 1;
}
bounds = userData->Input[threadId]->GetBounds();
for (i=0; i<3; i++)
{
adjBounds[2*i] = bounds[2*i] - maxDistance;
adjBounds[2*i+1] = bounds[2*i+1] + maxDistance;
}
// compute dimensional bounds in data set
for (i = 0; i < 3; i++)
{
outExt[i*2] = (int) ((double)(adjBounds[2*i] - origin[i]) /
spacing[i]);
outExt[i*2+1] = (int) ((double)(adjBounds[2*i+1] - origin[i]) /
spacing[i]);
if (outExt[i*2] < 0)
{
outExt[i*2] = 0;
}
if (outExt[i*2+1] >= sampleDimensions[i])
{
outExt[i*2+1] = sampleDimensions[i] - 1;
}
}
// input not close enough to effect this slab
if (outExt[4] > slabMax || outExt[5] < slabMin)
{
return VTK_THREAD_RETURN_VALUE;
}
// adjust min/max to match slab
if (outExt[4] < slabMin)
{
outExt[4] = slabMin;
}
if (outExt[5] > slabMax)
{
outExt[5] = slabMax;
}
vtkCellLocator *locator = vtkCellLocator::New();
// Set up the cell locator.
// If AutomaticOff, then NumberOfCellsPerBucket only used for allocating
// memory. If AutomaticOn, then NumberOfCellsPerBucket is used to guess
// the depth for the uniform octree required to support
// NumberOfCellsPerBucket (assuming uniform distribution of cells).
locator->SetDataSet( userData->Input[threadId] );
locator->AutomaticOff();
locator->SetMaxLevel( userData->Modeller->GetLocatorMaxLevel() );
locator->SetNumberOfCellsPerBucket( 1 );
locator->CacheCellBoundsOn();
locator->BuildLocator();
switch (userData->Modeller->GetOutputScalarType())
{
vtkTemplateMacro(
vtkImplicitModellerAppendExecute(
userData->Modeller,
userData->Input[threadId], output, outExt,
userData->MaximumDistance, locator, threadId,
static_cast<VTK_TT *>(0)));
default:
vtkGenericWarningMacro("Execute: Unknown output ScalarType");
return VTK_THREAD_RETURN_VALUE;
}
locator->Delete();
return VTK_THREAD_RETURN_VALUE;
}
//----------------------------------------------------------------------------
// Templated append for VTK_CELL_MODE process mode and any type of output data
template <class OT>
void vtkImplicitModellerAppendExecute(vtkImplicitModeller *self,
vtkDataSet *input, vtkImageData *outData,
double maxDistance, OT *)
{
int i, j, k, updateTime;
vtkIdType cellNum;
double *bounds, adjBounds[6];
double pcoords[3];
int outExt[6];
double x[3], prevDistance2, distance, distance2;
int subId;
double closestPoint[3];
double *weights=new double[input->GetMaxCellSize()];
double maxDistance2;
double *spacing, *origin;
spacing = outData->GetSpacing();
origin = outData->GetOrigin();
maxDistance2 = maxDistance * maxDistance;
int *sampleDimensions = self->GetSampleDimensions();
// so we know how to scale if desired
double scaleFactor = 0; // 0 used to indicate not scaling
double toDoubleScaleFactor = 0; // 0 used to indicate not scaling
double capValue = 0; // 0 used to indicate not clamping (float or double)
if (self->GetOutputScalarType() != VTK_FLOAT &&
self->GetOutputScalarType() != VTK_DOUBLE)
{
capValue = self->GetCapValue();
if (self->GetScaleToMaximumDistance())
{
scaleFactor = capValue / maxDistance;
toDoubleScaleFactor = maxDistance / capValue;
}
}
//
// Traverse all cells; computing distance function on volume points.
//
vtkCell *cell;
updateTime = input->GetNumberOfCells() / 50; // update every 2%
if (updateTime < 1)
{
updateTime = 1;
}
for (cellNum=0; cellNum < input->GetNumberOfCells(); cellNum++)
{
cell = input->GetCell(cellNum);
bounds = cell->GetBounds();
for (i=0; i<3; i++)
{
adjBounds[2*i] = bounds[2*i] - maxDistance;
adjBounds[2*i+1] = bounds[2*i+1] + maxDistance;
}
// compute dimensional bounds in data set
for (i = 0; i < 3; i++)
{
outExt[i*2] = (int) ((double)(adjBounds[2*i] - origin[i]) /
spacing[i]);
outExt[i*2 + 1] = (int) ((double)(adjBounds[2*i+1] - origin[i]) /
spacing[i]);
if (outExt[i*2] < 0)
{
outExt[i*2] = 0;
}
if (outExt[i*2 + 1] >= sampleDimensions[i])
{
outExt[i*2 + 1] = sampleDimensions[i] - 1;
}
}
vtkImageIterator<OT> outIt(outData, outExt);
for (k = outExt[4]; k <= outExt[5]; k++)
{
x[2] = spacing[2] * k + origin[2];
for (j = outExt[2]; j <= outExt[3]; j++)
{
x[1] = spacing[1] * j + origin[1];
OT* outSI = outIt.BeginSpan();
for (i = outExt[0]; i <= outExt[1]; i++)
{
x[0] = spacing[0] * i + origin[0];
ConvertToDoubleDistance(*outSI, distance, prevDistance2,
toDoubleScaleFactor);
// union combination of distances
if ( cell->EvaluatePosition(x, closestPoint, subId, pcoords,
distance2, weights) != -1 && distance2 < prevDistance2 &&
distance2 <= maxDistance2 )
{
distance = sqrt(distance2);
SetOutputDistance(distance, outSI, capValue, scaleFactor);
}
outSI++;
}
outIt.NextSpan();
}
}
if (cellNum % updateTime == 0)
{
self->UpdateProgress(double(cellNum + 1) / input->GetNumberOfCells());
}
}
delete [] weights;
}
// Append a data set to the existing output. To use this function,
// you'll have to invoke the StartAppend() method before doing
// successive appends. It's also a good idea to specify the model
// bounds; otherwise the input model bounds is used. When you've
// finished appending, use the EndAppend() method.
void vtkImplicitModeller::Append(vtkDataSet *input)
{
vtkDebugMacro(<< "Appending data");
vtkImageData *output = this->GetOutput();
if ( !this->BoundsComputed )
{
this->ComputeModelBounds(input);
}
if (this->ProcessMode == VTK_CELL_MODE)
{
if (!output->GetPointData()->GetScalars())
{
vtkErrorMacro("Sanity check failed.");
return;
}
switch (this->OutputScalarType)
{
vtkTemplateMacro(
vtkImplicitModellerAppendExecute( this,
input,
output,
this->InternalMaxDistance,
static_cast<VTK_TT *>(0)));
}
}
else
{
vtkImplicitModellerAppendInfo info;
double minZ, maxZ;
int slabMin, slabMax, slabSize, i;
vtkClipPolyData **minClipper = NULL, **maxClipper = NULL;
vtkPlane ** minPlane = NULL, **maxPlane = NULL;
double *spacing, *origin;
spacing = output->GetSpacing();
origin = output->GetOrigin();
// Use a MultiThreader here, splitting the volume into slabs to be processed
// by the separate threads
// Set the number of threads to use,
// then set the execution method and do it.
this->Threader->SetNumberOfThreads( this->NumberOfThreads );
// set up the info object for the thread
info.Modeller = this;
info.MaximumDistance = this->InternalMaxDistance;
info.Input = new vtkDataSet* [this->NumberOfThreads];
if (this->NumberOfThreads == 1)
{
info.Input[0] = input;
}
else
{
// if not PolyData, then copy the input for each thread
if ( input->GetDataObjectType() != VTK_POLY_DATA )
{
for (i = 0; i < this->NumberOfThreads; i++)
{
switch( input->GetDataObjectType() )
{
case VTK_STRUCTURED_GRID:
info.Input[i] = vtkStructuredGrid::New();
break;
case VTK_IMAGE_DATA:
info.Input[i] = vtkImageData::New();
break;
case VTK_UNSTRUCTURED_GRID:
info.Input[i] = vtkUnstructuredGrid::New();
break;
case VTK_RECTILINEAR_GRID:
info.Input[i] = vtkRectilinearGrid::New();
break;
default:
vtkErrorMacro(<<"Unexpected DataSet type!");
return;
}
info.Input[i]->CopyStructure(input);
}
}
else // break up the input data into slabs to help ensure thread safety
{
minClipper = new vtkClipPolyData* [this->NumberOfThreads];
maxClipper = new vtkClipPolyData* [this->NumberOfThreads];
minPlane = new vtkPlane* [this->NumberOfThreads];
maxPlane = new vtkPlane* [this->NumberOfThreads];
slabSize = this->SampleDimensions[2] / this->NumberOfThreads;
if (slabSize == 0) // in case threadCount > SampleDimensions[2]
{
slabSize = 1;
}
for (i = 0; i < this->NumberOfThreads; i++)
{
//////////////////////////////////////////////////
// do the 1st clip
slabMin = i * slabSize;
if (slabMin >= this->SampleDimensions[2])
{
break;
}
// get/clip input cells in this slab + maxDistance+
minZ = spacing[2] * slabMin + origin[2] - this->InternalMaxDistance*1.00001;
if (minZ < this->ModelBounds[4])
{
minZ = this->ModelBounds[4];
}
minPlane[i] = vtkPlane::New();
minPlane[i]->SetNormal(0.0, 0.0, -1.0);
minPlane[i]->SetOrigin(0.0, 0.0, minZ);
minClipper[i] = vtkClipPolyData::New();
minClipper[i]->SetInput((vtkPolyData *)input);
minClipper[i]->SetClipFunction(minPlane[i]);
minClipper[i]->SetValue( 0.0 );
minClipper[i]->InsideOutOn();
minClipper[i]->Update();
if ( minClipper[i]->GetOutput()->GetNumberOfCells() == 0 )
{
info.Input[i] = NULL;
maxPlane[i] = NULL;
continue;
}
minClipper[i]->ReleaseDataFlagOn();
//////////////////////////////////////////////////
// do the 2nd clip
slabMax = slabMin + slabSize - 1;
if (i == this->NumberOfThreads - 1)
{
slabMax = this->SampleDimensions[2] - 1;
}
maxZ = spacing[2] * slabMax + origin[2] + this->InternalMaxDistance*1.00001;
if (maxZ > this->ModelBounds[5])
{
maxZ = this->ModelBounds[5];
}
maxPlane[i] = vtkPlane::New();
maxPlane[i]->SetNormal(0.0, 0.0, 1.0);
maxPlane[i]->SetOrigin(0.0, 0.0, maxZ);
maxClipper[i] = vtkClipPolyData::New();
maxClipper[i]->SetInput(minClipper[i]->GetOutput());
maxClipper[i]->SetClipFunction(maxPlane[i]);
maxClipper[i]->SetValue( 0.0 );
maxClipper[i]->InsideOutOn();
maxClipper[i]->Update();
if ( maxClipper[i]->GetOutput()->GetNumberOfCells() == 0 )
{
info.Input[i] = NULL;
}
else
{
info.Input[i] = maxClipper[i]->GetOutput();
}
}
}
}
this->Threader->SetSingleMethod( vtkImplicitModeller_ThreadedAppend,
(void *)&info);
this->Threader->SingleMethodExecute();
// cleanup
if (this->NumberOfThreads > 1)
{
if ( input->GetDataObjectType() != VTK_POLY_DATA )
{
for (i = 0; i < this->NumberOfThreads; i++)
{
info.Input[i]->Delete();
}
}
else
{
for (i = 0; i < this->NumberOfThreads; i++)
{
minPlane[i]->Delete();
minClipper[i]->Delete();
if (maxPlane[i])
{
maxPlane[i]->Delete();
maxClipper[i]->Delete();
}
}
delete [] minPlane;
delete [] maxPlane;
delete [] minClipper;
delete [] maxClipper;
}
}
delete [] info.Input;
}
}
//----------------------------------------------------------------------------
// Method completes the append process (does the capping if requested).
void vtkImplicitModeller::EndAppend()
{
vtkDataArray *newScalars;
vtkDebugMacro(<< "End append");
if (!(newScalars =this->GetOutput()->GetPointData()->GetScalars()))
{
vtkErrorMacro("Sanity check failed.");
return;
}
if ( this->Capping )
{
this->Cap(newScalars);
}
this->UpdateProgress(1.0);
}
//----------------------------------------------------------------------------
int vtkImplicitModeller::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];
vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->OutputScalarType, 1);
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
0, this->SampleDimensions[0]-1,
0, this->SampleDimensions[1]-1,
0, this->SampleDimensions[2]-1);
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);
return 1;
}
//----------------------------------------------------------------------------
int vtkImplicitModeller::RequestData(
vtkInformation* vtkNotUsed( request ),
vtkInformationVector** inputVector,
vtkInformationVector* vtkNotUsed( outputVector ))
{
// get the input
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
vtkDataSet *input = vtkDataSet::SafeDownCast(
inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkDebugMacro(<< "Executing implicit model");
if (input == NULL)
{
// we do not want to release the data because user might
// have called Append ...
return 0;
}
this->StartAppend(1);
this->Append(input);
this->EndAppend();
return 1;
}
// Compute ModelBounds from input geometry.
double vtkImplicitModeller::ComputeModelBounds(vtkDataSet *input)
{
double *bounds, maxDist;
int i;
vtkImageData *output=this->GetOutput();
double tempd[3];
// compute model bounds if not set previously
if ( this->ModelBounds[0] >= this->ModelBounds[1] ||
this->ModelBounds[2] >= this->ModelBounds[3] ||
this->ModelBounds[4] >= this->ModelBounds[5] )
{
if (input != NULL)
{
bounds = input->GetBounds();
}
else
{
vtkDataSet *dsInput = vtkDataSet::SafeDownCast(this->GetInput());
if (dsInput != NULL)
{
bounds = dsInput->GetBounds();
}
else
{
vtkErrorMacro(
<< "An input must be specified to Compute the model bounds.");
return VTK_FLOAT_MAX;
}
}
}
else
{
bounds = this->ModelBounds;
}
for (maxDist=0.0, i=0; i<3; i++)
{
if ( (bounds[2*i+1] - bounds[2*i]) > maxDist )
{
maxDist = bounds[2*i+1] - bounds[2*i];
}
}
// adjust bounds so model fits strictly inside (only if not set previously)
if ( this->AdjustBounds )
{
for (i=0; i<3; i++)
{
this->ModelBounds[2*i] = bounds[2*i] - maxDist*this->AdjustDistance;
this->ModelBounds[2*i+1] = bounds[2*i+1] + maxDist*this->AdjustDistance;
}
}
else // to handle problem case where bounds not specified and AdjustBounds
// not on; will be setting ModelBounds to self if previosusly set
{
for (i=0; i<3; i++)
{
this->ModelBounds[2*i] = bounds[2*i];
this->ModelBounds[2*i+1] = bounds[2*i+1];
}
}
maxDist *= this->MaximumDistance;
// Set volume origin and data spacing
output->SetOrigin(this->ModelBounds[0],
this->ModelBounds[2],
this->ModelBounds[4]);
for (i=0; i<3; i++)
{
tempd[i] = (this->ModelBounds[2*i+1] - this->ModelBounds[2*i])
/ (this->SampleDimensions[i] - 1);
}
output->SetSpacing(tempd);
vtkInformation *outInfo = this->GetExecutive()->GetOutputInformation(0);
outInfo->Set(vtkDataObject::ORIGIN(),this->ModelBounds[0],
this->ModelBounds[2], this->ModelBounds[4]);
outInfo->Set(vtkDataObject::SPACING(),tempd,3);
this->BoundsComputed = 1;
this->InternalMaxDistance = maxDist;
return maxDist;
}
//----------------------------------------------------------------------------
// Set the i-j-k dimensions on which to sample the distance function.
void vtkImplicitModeller::SetSampleDimensions(int i, int j, int k)
{
int dim[3];
dim[0] = i;
dim[1] = j;
dim[2] = k;
this->SetSampleDimensions(dim);
}
//----------------------------------------------------------------------------
void vtkImplicitModeller::SetSampleDimensions(int dim[3])
{
int dataDim, i;
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] )
{
if ( dim[0]<1 || dim[1]<1 || dim[2]<1 )
{
vtkErrorMacro (<< "Bad Sample Dimensions, retaining previous values");
return;
}
for (dataDim=0, i=0; i<3 ; i++)
{
if (dim[i] > 1)
{
dataDim++;
}
}
if ( dataDim < 3 )
{
vtkErrorMacro(<<"Sample dimensions must define a volume!");
return;
}
for ( i=0; i<3; i++)
{
this->SampleDimensions[i] = dim[i];
}
this->Modified();
}
}
//----------------------------------------------------------------------------
void vtkImplicitModeller::Cap(vtkDataArray *s)
{
int i,j,k;
int idx;
int d01=this->SampleDimensions[0]*this->SampleDimensions[1];
// i-j planes
k = 0;
for (j=0; j<this->SampleDimensions[1]; j++)
{
for (i=0; i<this->SampleDimensions[0]; i++)
{
s->SetComponent(i+j*this->SampleDimensions[0],0, this->CapValue);
}
}
k = this->SampleDimensions[2] - 1;
idx = k*d01;
for (j=0; j<this->SampleDimensions[1]; j++)
{
for (i=0; i<this->SampleDimensions[0]; i++)
{
s->SetComponent(idx+i+j*this->SampleDimensions[0], 0, this->CapValue);
}
}
// j-k planes
i = 0;
for (k=0; k<this->SampleDimensions[2]; k++)
{
for (j=0; j<this->SampleDimensions[1]; j++)
{
s->SetComponent(j*this->SampleDimensions[0]+k*d01,0,this->CapValue);
}
}
i = this->SampleDimensions[0] - 1;
for (k=0; k<this->SampleDimensions[2]; k++)
{
for (j=0; j<this->SampleDimensions[1]; j++)
{
s->SetComponent(i+j*this->SampleDimensions[0]+k*d01,0, this->CapValue);
}
}
// i-k planes
j = 0;
for (k=0; k<this->SampleDimensions[2]; k++)
{
for (i=0; i<this->SampleDimensions[0]; i++)
{
s->SetComponent(i+k*d01,0, this->CapValue);
}
}
j = this->SampleDimensions[1] - 1;
idx = j*this->SampleDimensions[0];
for (k=0; k<this->SampleDimensions[2]; k++)
{
for (i=0; i<this->SampleDimensions[0]; i++)
{
s->SetComponent(idx+i+k*d01,0, this->CapValue);
}
}
}
//----------------------------------------------------------------------------
const char *vtkImplicitModeller::GetProcessModeAsString()
{
if (this->ProcessMode == VTK_CELL_MODE)
{
return "PerCell";
}
else
{
return "PerVoxel";
}
}
//----------------------------------------------------------------------------
int vtkImplicitModeller::FillInputPortInformation(
int vtkNotUsed( port ), vtkInformation* info)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
return 1;
}
//----------------------------------------------------------------------------
int vtkImplicitModeller::ProcessRequest(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
// If we have no input then we will not generate the output because
// the user already called StartAppend/Append/EndAppend.
if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA_NOT_GENERATED()))
{
if(inputVector[0]->GetNumberOfInformationObjects() == 0)
{
vtkInformation* outInfo = outputVector->GetInformationObject(0);
outInfo->Set(vtkDemandDrivenPipeline::DATA_NOT_GENERATED(), 1);
}
return 1;
}
else if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
{
if(inputVector[0]->GetNumberOfInformationObjects() == 0)
{
return 1;
}
}
return this->Superclass::ProcessRequest(request, inputVector, outputVector);
}
void vtkImplicitModeller::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Maximum Distance: " << this->MaximumDistance << "\n";
os << indent << "OutputScalarType: " << this->OutputScalarType << "\n";
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 << "ScaleToMaximumDistance: " << (this->ScaleToMaximumDistance ? "On\n" : "Off\n");
os << indent << "AdjustBounds: " << (this->AdjustBounds ? "On\n" : "Off\n");
os << indent << "Adjust Distance: " << this->AdjustDistance << "\n";
os << indent << "Process Mode: " << this->ProcessMode << "\n";
os << indent << "Locator Max Level: " << this->LocatorMaxLevel << "\n";
os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");
os << indent << "Cap Value: " << this->CapValue << "\n";
os << indent << "Process Mode: " << this->GetProcessModeAsString() << endl;
os << indent << "Number Of Threads (for PerVoxel mode): " << this->NumberOfThreads << endl;
}