Commit c71de9de authored by Will Schroeder's avatar Will Schroeder
Browse files

Initial revision

parent 8f6cd006
/*=========================================================================
Program: Visualization Library
Module: SweptSur.hh
Language: C++
Date: $Date$
Version: $Revision$
This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994
=========================================================================*/
// .NAME vtkSweptSurface - given a path and input geometry generate an (implicit) representation of a swept surface
// .SECTION Description
// vtkSweptSurface is a filter that is used to create a surface defined by
// moving a part along a path. In this implementation the path is defined as
// a list of transformation matrices (vtkTransform), and the part geometry is
// implicitly defined using a volume (i.e., distance scalars in structured
// point dataset). The input to the filter is the geometry (i.e., a
// structured point dataset) and the output is a structured point dataset
// (i.e., an implicit representation of the swept surface). If you wish to
// generate a polygonal representation of swept surface you will have to
// use a contouring filter (e.g., vtkMarchingCubes). (You may also wish to
// use vtkDecimate to reduce mesh size).
// The swept surface algorithm can be summarized as follows. A geometry
// (i.e. the input) is swept along a path (list of transforms). At each point
// on the path the input is re-sampled into a volume using a union operation.
// (Union means that the minumum scalar value is retained - minimum distance
// value for example). At the end an implicit representation of the swept
// surface is defined.
#ifndef __vtkSweptSurface_h
#define __vtkSweptSurface_h
#include "SPt2SPtF.hh"
#include "TransC.hh"
class vtkSweptSurface : public vtkStructuredPointsToStructuredPointsFilter
{
public:
vtkSweptSurface();
~vtkSweptSurface() {};
char *GetClassName() {return "vtkSweptSurface";};
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Specify i-j-k dimensions to sample input with. The higher the resolution
// the lower the error but the greater the processing time.
vtkSetVector3Macro(SampleDimensions,int);
vtkGetVectorMacro(SampleDimensions,int,3);
// Description:
// Specify a path (i.e., list of transforms) that the input moves along. At
// least two transforms must be used to define a path.
vtkSetObjectMacro(Transforms, vtkTransformCollection);
vtkGetObjectMacro(Transforms, vtkTransformCollection);
// Description:
// Voxels are initialized to this value. By default a large floating point
// value is used since the scalar values are assumed to be a distance
// function.
vtkSetMacro(FillValue,float);
vtkGetMacro(FillValue,float);
// Description:
// Value specifies/controls interpolation between the nodes (i.e.,
// transforms) defining the path. A positive value indicates the number
// of steps to take between transforms (i.e., interpolation is performed).
// A negative value indicates that no interpolation to be performed, that is,
// only the points defined at each transform are used (interpolation not
// performed). A zero value indicates that automatic interpolation is to be
// performed, that is, interpolation is computed so that potential errors
// fall below the error bounds defined in the text. By default, automatic
// computation is performed (Interpolation = 0).
vtkSetMacro(Interpolation,int);
vtkGetMacro(Interpolation,int);
// Description:
// Description:
// The outer boundary of the sampling volume can be capped (i.e., assigned
// fill value). This will "close" the implicit model if the geometry
// approaches close to or passes through the boundary of the volume (i.e.,
// defined by ModelBounds instance variable). Capping turns on/off this
// capability. By default capping is on.
vtkSetMacro(Capping,int);
vtkGetMacro(Capping,int);
vtkBooleanMacro(Capping,int);
void SetModelBounds(float *bounds);
void SetModelBounds(float xmin, float xmax, float ymin, float ymax, float zmin, float zmax);
vtkGetVectorMacro(ModelBounds,float,6);
//overload to check trnasformation matrices
unsigned long int GetMTime();
protected:
void Execute();
void ComputeBounds();
int ComputeNumberOfSteps(vtkTransform *t1, vtkTransform *t2);
void SampleInput(vtkMatrix4x4& m, int inDim[3], float inOrigin[3],
float inAr[3], vtkScalars *in, vtkScalars *out);
void Cap(vtkFloatScalars *s);
int SampleDimensions[3];
float FillValue;
float ModelBounds[6];
int Interpolation;
int Capping;
vtkTransformCollection *Transforms;
};
#endif
/*=========================================================================
Program: Visualization Library
Module: SweptSur.cc
Language: C++
Date: $Date$
Version: $Revision$
This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994
=========================================================================*/
#include "SweptSur.hh"
#include "Actor.hh"
#include "Voxel.hh"
// Description:
// Construct object with SampleDimensions = (50,50,50), FillValue =
// LARGE_FLOAT, ModelBounds=(0,0,0,0,0,0) (i.e, bounds will be
// computed automatically), and Capping turned on.
vtkSweptSurface::vtkSweptSurface()
{
this->ModelBounds[0] = 0.0; //compute automatically
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->SampleDimensions[0] = 50;
this->SampleDimensions[1] = 50;
this->SampleDimensions[2] = 50;
this->Interpolation = 0;
this->FillValue = LARGE_FLOAT;
this->Transforms = NULL;
this->Capping = 1;
}
// Description:
// Define the volume (in world coordinates) in which the sampling is to occur.
// Make sure that the volume is large enough to accomodate the motion of the
// geometry along the path. If the model bounds are set to all zero values, the
// model bounds will be computed automatically from the input and path.
void vtkSweptSurface::SetModelBounds(float *bounds)
{
vtkSweptSurface::SetModelBounds(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
}
void vtkSweptSurface::SetModelBounds(float xmin, float xmax, float ymin, float ymax, float zmin, float zmax)
{
if (this->ModelBounds[0] != xmin || this->ModelBounds[1] != xmax ||
this->ModelBounds[2] != ymin || this->ModelBounds[3] != ymax ||
this->ModelBounds[4] != zmin || this->ModelBounds[5] != zmax )
{
float length;
this->Modified();
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->Origin[0] = xmin;
this->Origin[1] = ymin;
this->Origin[2] = zmin;
if ( (length = xmax - xmin) == 0.0 ) length = 1.0;
this->AspectRatio[0] = 1.0;
this->AspectRatio[1] = (ymax - ymin) / length;
this->AspectRatio[2] = (zmax - zmin) / length;
}
}
void vtkSweptSurface::Execute()
{
int i, numPts, numOutPts;
float ar[3];
vtkPointData *pd;
vtkScalars *inScalars, *newScalars;
vtkStructuredPoints *input=(vtkStructuredPoints *)this->Input;
float inAr[3], inOrigin[3];
int inDim[3];
int numSteps, stepNum;
int numTransforms, transNum;
vtkActor a;
vtkTransform *t1, *t2;
float time;
float position[3], position1[3], position2[3];
float orientation[3], orientation1[3], orientation2[3];
vtkDebugMacro(<<"Creating swept surface");
this->Initialize();
// make sure there is input
pd = this->Input->GetPointData();
inScalars = pd->GetScalars();
if ( (numPts=this->Input->GetNumberOfPoints()) < 1 ||
inScalars == NULL )
{
vtkErrorMacro(<<"No input scalars defined!");
return;
}
// check that path is defined
if ( this->Transforms == NULL )
{
vtkErrorMacro(<<"No path defined!");
return;
}
if ( (numTransforms=this->Transforms->GetNumberOfItems()) < 2 )
{
vtkErrorMacro(<<"At least two transforms are required to define path!");
return;
}
this->SetDimensions(this->SampleDimensions);
// if bounds are not specified, compute bounds from path
if (this->ModelBounds[0] >= this->ModelBounds[1] ||
this->ModelBounds[2] >= this->ModelBounds[3] ||
this->ModelBounds[4] >= this->ModelBounds[5])
{
this->ComputeBounds();
}
input->GetDimensions(inDim);
input->GetAspectRatio(inAr);
input->GetOrigin(inOrigin);
//
// Allocate data. Scalar "type" is same as input.
//
numOutPts = this->Dimensions[0] * this->Dimensions[1] * this->Dimensions[2];
newScalars = inScalars->MakeObject(numOutPts);
for (i = 0; i < numOutPts; i++) newScalars->SetScalar(i,this->FillValue);
//
// Sample data at each point in path
//
this->Transforms->InitTraversal();
t2 = this->Transforms->GetNextItem();
t2->Push();
t2->Inverse();
for (transNum=0; transNum < (numTransforms-1); transNum++)
{
vtkDebugMacro(<<"Injecting between transforms "<< transNum+1 <<" and "
<< transNum+2);
t1 = t2;
t2 = this->Transforms->GetNextItem();
t2->Push();
t2->Inverse();
//
// Loop over all points (i.e., voxels), transform into input coordinate system,
// and obtain interpolated value. Then perform union operation.
//
if ( this->Interpolation > 0 ) numSteps = this->Interpolation;
else if ( this->Interpolation < 0 ) numSteps = 1;
else numSteps = this->ComputeNumberOfSteps(t1,t2);
for (stepNum=0; stepNum < numSteps; stepNum++)
{
// linearly interpolate position and orientation
time = stepNum / numSteps;
for (i=0; i<3; i++)
{
position1[i] = position2[i];
orientation1[i] = orientation2[i];
}
t2->GetPosition(position2[0], position2[1], position2[2]);
t2->GetOrientation(orientation2[0], orientation2[1], orientation2[2]);
for (i=0; i<3; i++)
{
position[i] = position1[i] + time*(position2[i] - position1[i]);
orientation[i] = orientation1[i] + time*(orientation2[i] - orientation1[i]);
}
a.SetPosition(position);
a.SetOrientation(orientation);
this->SampleInput(a.GetMatrix(), inDim, inOrigin, inAr,
inScalars, newScalars);
}
t1->Pop();
}
//finish off last step
a.SetPosition(position2);
a.SetOrientation(orientation2);
this->SampleInput(a.GetMatrix(), inDim, inOrigin, inAr,
inScalars, newScalars);
t2->Pop();
// Update ourselves and release memory
this->PointData.SetScalars(newScalars);
newScalars->Delete();
}
void vtkSweptSurface::SampleInput(vtkMatrix4x4& m, int inDim[3],
float inOrigin[3], float inAr[3],
vtkScalars *inScalars, vtkScalars *outScalars)
{
int i, j, k, ii;
int inSliceSize=inDim[0]*inDim[1];
int sliceSize=this->SampleDimensions[0]*this->SampleDimensions[1];
float x[3], loc[3], newScalar, scalar;
static vtkVoxel voxel;
static vtkIdList idList(8);
static vtkFloatScalars voxelScalars(8);
int kOffset, jOffset, dim[3], idx;
float xTrans[3], weights[8];
for (k=0; k<this->SampleDimensions[2]; k++)
{
kOffset = k*sliceSize;
x[2] = this->Origin[2] + k * this->AspectRatio[2];
for (j=0; j<this->SampleDimensions[1]; j++)
{
jOffset = j*this->SampleDimensions[0];
x[1] = this->Origin[1] + k * this->AspectRatio[1];
for (i=0; i<this->SampleDimensions[0]; i++)
{
x[0] = this->Origin[0] + k * this->AspectRatio[0];
// transform into local space
m.PointMultiply(x,xTrans);
// determine which voxel point falls in.
for (ii=0; ii<3; ii++)
{
loc[ii] = (xTrans[ii]-inOrigin[ii]) / inAr[ii];
dim[ii] = (int)loc[ii];
}
//check and make sure point is inside
if ( loc[0] >= 0.0 && loc[1] >= 0.0 && loc[2] >= 0.0 &&
dim[0] < inDim[0] && dim[1] < inDim[1] && dim[2] < inDim[2] )
{
//get scalar values
idx = dim[0] + dim[1]*inDim[0] + dim[2]*inSliceSize;
idList.SetId(0,idx);
idList.SetId(1,idx+1);
idList.SetId(2,idx+1 + inDim[0]);
idList.SetId(3,idx + inDim[0]);
idList.SetId(0,idx + sliceSize);
idList.SetId(1,idx+1 + sliceSize);
idList.SetId(2,idx+1 + inDim[0] + sliceSize);
idList.SetId(3,idx + inDim[0] + sliceSize);
inScalars->GetScalars(idList,voxelScalars);
for (ii=0; ii<3; ii) loc[ii] = loc[ii] - dim[ii];
voxel.InterpolationFunctions(loc,weights);
for (newScalar=0.0, ii=0; ii<8; ii++)
newScalar += voxelScalars.GetScalar(ii) * weights[ii];
scalar = outScalars->GetScalar((idx=i+jOffset+kOffset));
if ( newScalar < scalar ) //union operation
outScalars->SetScalar(idx,newScalar);
}
}
}
}
}
unsigned long int vtkSweptSurface::GetMTime()
{
unsigned long int mtime=this->GetMTime();
unsigned long int transMtime;
vtkTransform *t;
for (this->Transforms->InitTraversal(); t = this->Transforms->GetNextItem(); )
{
transMtime = t->GetMTime();
if ( transMtime > mtime ) mtime = transMtime;
}
return mtime;
}
// compute model bounds from geometry and path
void vtkSweptSurface::ComputeBounds()
{
}
void vtkSweptSurface::Cap(vtkFloatScalars *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->SetScalar(i+j*this->SampleDimensions[1], this->FillValue);
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->SetScalar(idx+i+j*this->SampleDimensions[1], this->FillValue);
// j-k planes
i = 0;
for (k=0; k<this->SampleDimensions[2]; k++)
for (j=0; j<this->SampleDimensions[1]; j++)
s->SetScalar(j*this->SampleDimensions[0]+k*d01, this->FillValue);
i = this->SampleDimensions[0] - 1;
for (k=0; k<this->SampleDimensions[2]; k++)
for (j=0; j<this->SampleDimensions[1]; j++)
s->SetScalar(i+j*this->SampleDimensions[0]+k*d01, this->FillValue);
// i-k planes
j = 0;
for (k=0; k<this->SampleDimensions[2]; k++)
for (i=0; i<this->SampleDimensions[0]; i++)
s->SetScalar(i+k*d01, this->FillValue);
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->SetScalar(idx+i+k*d01, this->FillValue);
}
void vtkSweptSurface::PrintSelf(ostream& os, vtkIndent indent)
{
vtkStructuredPointsToStructuredPointsFilter::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 << "Fill Value:" << this->FillValue << "\n";
os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");
if ( this->Transforms )
{
os << indent << "Number of Transforms: " << this->Transforms->GetNumberOfItems() << "\n";
}
else
{
os << indent << "No transform defined!\n";
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment