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.
376 lines
11 KiB
376 lines
11 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkSplineFilter.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 "vtkSplineFilter.h"
|
|
|
|
#include "vtkCardinalSpline.h"
|
|
#include "vtkCell.h"
|
|
#include "vtkCellArray.h"
|
|
#include "vtkCellData.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkPolyData.h"
|
|
|
|
vtkCxxRevisionMacro(vtkSplineFilter, "$Revision: 1.16 $");
|
|
vtkStandardNewMacro(vtkSplineFilter);
|
|
vtkCxxSetObjectMacro(vtkSplineFilter,Spline,vtkSpline);
|
|
|
|
vtkSplineFilter::vtkSplineFilter()
|
|
{
|
|
this->Subdivide = VTK_SUBDIVIDE_SPECIFIED;
|
|
this->MaximumNumberOfSubdivisions = VTK_LARGE_INTEGER;
|
|
this->NumberOfSubdivisions = 100;
|
|
this->Length = 0.1;
|
|
this->GenerateTCoords = VTK_TCOORDS_FROM_NORMALIZED_LENGTH;
|
|
this->TextureLength = 1.0;
|
|
|
|
this->Spline = vtkCardinalSpline::New();
|
|
this->TCoordMap = vtkFloatArray::New();
|
|
}
|
|
|
|
vtkSplineFilter::~vtkSplineFilter()
|
|
{
|
|
this->Spline->Delete();
|
|
this->TCoordMap->Delete();
|
|
}
|
|
|
|
int vtkSplineFilter::RequestData(
|
|
vtkInformation *vtkNotUsed(request),
|
|
vtkInformationVector **inputVector,
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
// get the info objects
|
|
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
|
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
|
|
|
// get the input and ouptut
|
|
vtkPolyData *input = vtkPolyData::SafeDownCast(
|
|
inInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
vtkPolyData *output = vtkPolyData::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
vtkPointData *pd=input->GetPointData();
|
|
vtkPointData *outPD=output->GetPointData();
|
|
vtkCellData *cd=input->GetCellData();
|
|
vtkCellData *outCD=output->GetCellData();
|
|
vtkCellArray *inLines;
|
|
|
|
vtkPoints *inPts;
|
|
vtkIdType numLines;
|
|
vtkCellArray *newLines;
|
|
vtkIdType numNewPts, numNewCells;
|
|
vtkPoints *newPts;
|
|
vtkIdType npts=0, *pts=NULL;
|
|
vtkIdType offset=0;
|
|
vtkFloatArray *newTCoords=NULL;
|
|
int abort=0;
|
|
vtkIdType inCellId, numGenPts;
|
|
int genTCoords = VTK_TCOORDS_OFF;
|
|
|
|
// Check input and initialize
|
|
//
|
|
vtkDebugMacro(<<"Splining polylines");
|
|
|
|
if ( !(inPts=input->GetPoints()) || inPts->GetNumberOfPoints() < 1 ||
|
|
!(inLines = input->GetLines()) ||
|
|
(numLines = inLines->GetNumberOfCells()) < 1 )
|
|
{
|
|
vtkWarningMacro(<< " No input data!");
|
|
return 1;
|
|
}
|
|
|
|
if ( this->Spline == NULL )
|
|
{
|
|
vtkWarningMacro(<< "Need to specify a spline!");
|
|
return 1;
|
|
}
|
|
|
|
// Create the geometry and topology
|
|
numNewPts = this->NumberOfSubdivisions * numLines;
|
|
newPts = vtkPoints::New();
|
|
newPts->Allocate(numNewPts);
|
|
newLines = vtkCellArray::New();
|
|
newLines->Allocate(newLines->EstimateSize(1,numNewPts));
|
|
|
|
// Point data
|
|
if ( (this->GenerateTCoords == VTK_TCOORDS_FROM_SCALARS &&
|
|
pd->GetScalars() != NULL) ||
|
|
(this->GenerateTCoords == VTK_TCOORDS_FROM_LENGTH ||
|
|
this->GenerateTCoords == VTK_TCOORDS_FROM_NORMALIZED_LENGTH) )
|
|
{
|
|
genTCoords = this->GenerateTCoords;
|
|
newTCoords = vtkFloatArray::New();
|
|
newTCoords->SetNumberOfComponents(2);
|
|
newTCoords->Allocate(numNewPts);
|
|
outPD->CopyTCoordsOff();
|
|
}
|
|
outPD->InterpolateAllocate(pd,numNewPts);
|
|
this->TCoordMap->Allocate(VTK_CELL_SIZE);
|
|
|
|
// Copy cell data
|
|
numNewCells = numLines;
|
|
outCD->CopyNormalsOff();
|
|
outCD->CopyAllocate(cd,numNewCells);
|
|
|
|
// Set up the splines
|
|
this->XSpline = this->Spline->NewInstance();
|
|
this->XSpline->DeepCopy(this->Spline);
|
|
this->YSpline = this->Spline->NewInstance();
|
|
this->YSpline->DeepCopy(this->Spline);
|
|
this->ZSpline = this->Spline->NewInstance();
|
|
this->ZSpline->DeepCopy(this->Spline);
|
|
|
|
// Create points along each polyline.
|
|
//
|
|
for (inCellId=0, inLines->InitTraversal();
|
|
inLines->GetNextCell(npts,pts) && !abort; inCellId++)
|
|
{
|
|
this->UpdateProgress((double)inCellId/numLines);
|
|
abort = this->GetAbortExecute();
|
|
|
|
if (npts < 2)
|
|
{
|
|
vtkWarningMacro(<< "Less than two points in line!");
|
|
continue; //skip tubing this polyline
|
|
}
|
|
|
|
// Generate the points around the polyline. The strip is not created
|
|
// if the polyline is bad.
|
|
//
|
|
this->TCoordMap->Reset();
|
|
numGenPts = this->GeneratePoints(offset, npts, pts, inPts, newPts,
|
|
pd, outPD, genTCoords, newTCoords);
|
|
if ( ! numGenPts )
|
|
{
|
|
vtkWarningMacro(<< "Could not generate points!");
|
|
continue; //skip splining
|
|
}
|
|
|
|
// Generate the polyline
|
|
//
|
|
this->GenerateLine(offset,numGenPts,inCellId,cd,outCD,newLines);
|
|
|
|
// Compute the new offset for the next polyline
|
|
offset += numGenPts;
|
|
|
|
}//for all polylines
|
|
|
|
// Update ourselves
|
|
//
|
|
this->TCoordMap->Initialize();
|
|
|
|
this->XSpline->Delete();
|
|
this->YSpline->Delete();
|
|
this->ZSpline->Delete();
|
|
|
|
output->SetPoints(newPts);
|
|
newPts->Delete();
|
|
|
|
output->SetLines(newLines);
|
|
newLines->Delete();
|
|
|
|
if ( newTCoords )
|
|
{
|
|
outPD->SetTCoords(newTCoords);
|
|
newTCoords->Delete();
|
|
}
|
|
|
|
output->Squeeze();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int vtkSplineFilter::GeneratePoints(vtkIdType offset, vtkIdType npts,
|
|
vtkIdType *pts, vtkPoints *inPts,
|
|
vtkPoints *newPts, vtkPointData *pd,
|
|
vtkPointData *outPD, int genTCoords,
|
|
vtkFloatArray *newTCoords)
|
|
{
|
|
vtkIdType i;
|
|
|
|
// Initialize the splines
|
|
this->XSpline->RemoveAllPoints();
|
|
this->YSpline->RemoveAllPoints();
|
|
this->ZSpline->RemoveAllPoints();
|
|
|
|
// Compute the length of the resulting spline
|
|
double xPrev[3], x[3], length=0.0, len, t, tc;
|
|
inPts->GetPoint(pts[0],xPrev);
|
|
for (i=1; i < npts; i++)
|
|
{
|
|
inPts->GetPoint(pts[i],x);
|
|
len = sqrt(vtkMath::Distance2BetweenPoints(x,xPrev));
|
|
if ( len <= 0.0 )
|
|
{
|
|
return 0; //failure
|
|
}
|
|
length += len;
|
|
xPrev[0]=x[0]; xPrev[1]=x[1]; xPrev[2]=x[2];
|
|
}
|
|
if ( length <= 0.0 )
|
|
{
|
|
return 0; //failure
|
|
}
|
|
|
|
// Now we insert points into the splines with the parametric coordinate
|
|
// based on (polyline) length. We keep track of the parametric coordinates
|
|
// of the points for later point interpolation.
|
|
inPts->GetPoint(pts[0],xPrev);
|
|
for (len=0,i=0; i < npts; i++)
|
|
{
|
|
inPts->GetPoint(pts[i],x);
|
|
len += sqrt(vtkMath::Distance2BetweenPoints(x,xPrev));
|
|
t = len/length;
|
|
this->TCoordMap->InsertValue(i,t);
|
|
|
|
this->XSpline->AddPoint(t,x[0]);
|
|
this->YSpline->AddPoint(t,x[1]);
|
|
this->ZSpline->AddPoint(t,x[2]);
|
|
|
|
xPrev[0]=x[0]; xPrev[1]=x[1]; xPrev[2]=x[2];
|
|
}
|
|
|
|
// Compute the number of subdivisions
|
|
vtkIdType numDivs, numNewPts;
|
|
if ( this->Subdivide == VTK_SUBDIVIDE_SPECIFIED )
|
|
{
|
|
numDivs = this->NumberOfSubdivisions;
|
|
}
|
|
else
|
|
{
|
|
numDivs = (int) (length / this->Length);
|
|
}
|
|
numDivs = ( numDivs < 1 ? 1 : (numDivs > this->MaximumNumberOfSubdivisions ?
|
|
this->MaximumNumberOfSubdivisions : numDivs));
|
|
|
|
// Now compute the new points
|
|
numNewPts = numDivs + 1;
|
|
vtkIdType idx;
|
|
double s, s0=0.0;
|
|
if ( genTCoords == VTK_TCOORDS_FROM_SCALARS )
|
|
{
|
|
s0=pd->GetScalars()->GetTuple1(pts[0]);
|
|
}
|
|
double tLo = this->TCoordMap->GetValue(0);
|
|
double tHi = this->TCoordMap->GetValue(1);
|
|
for (idx=0, i=0; i < numNewPts; i++)
|
|
{
|
|
t = (double) i / numDivs;
|
|
x[0] = this->XSpline->Evaluate(t);
|
|
x[1] = this->YSpline->Evaluate(t);
|
|
x[2] = this->ZSpline->Evaluate(t);
|
|
newPts->InsertPoint(offset+i,x);
|
|
|
|
// interpolate point data
|
|
while ( t > tHi && idx < (npts-2))
|
|
{
|
|
idx++;
|
|
tLo = this->TCoordMap->GetValue(idx);
|
|
tHi = this->TCoordMap->GetValue(idx+1);
|
|
}
|
|
tc = (t - tLo) / (tHi - tLo);
|
|
outPD->InterpolateEdge(pd,offset+i,pts[idx],pts[idx+1],tc);
|
|
|
|
// generate texture coordinates if desired
|
|
if ( genTCoords != VTK_TCOORDS_OFF )
|
|
{
|
|
if ( genTCoords == VTK_TCOORDS_FROM_NORMALIZED_LENGTH )
|
|
{
|
|
tc = t;
|
|
}
|
|
else if ( genTCoords == VTK_TCOORDS_FROM_LENGTH )
|
|
{
|
|
tc = t * length / this->TextureLength;
|
|
}
|
|
else if ( genTCoords == VTK_TCOORDS_FROM_SCALARS )
|
|
{
|
|
s = outPD->GetScalars()->GetTuple1(offset+i); //data just interpolated
|
|
tc = (s - s0) / this->TextureLength;
|
|
}
|
|
newTCoords->InsertTuple2(offset+i,tc,0.0);
|
|
} //if generating tcoords
|
|
} //for all new points
|
|
|
|
return numNewPts;
|
|
}
|
|
|
|
void vtkSplineFilter::GenerateLine(vtkIdType offset, vtkIdType npts,
|
|
vtkIdType inCellId,
|
|
vtkCellData *cd, vtkCellData *outCD,
|
|
vtkCellArray *newLines)
|
|
{
|
|
vtkIdType i, outCellId;
|
|
|
|
outCellId = newLines->InsertNextCell(npts);
|
|
outCD->CopyData(cd,inCellId,outCellId);
|
|
for (i=0; i < npts; i++)
|
|
{
|
|
newLines->InsertCellPoint(offset+i);
|
|
}
|
|
}
|
|
|
|
|
|
const char *vtkSplineFilter::GetSubdivideAsString()
|
|
{
|
|
if ( this->Subdivide == VTK_SUBDIVIDE_SPECIFIED )
|
|
{
|
|
return "Specified by Number of Subdivisions";
|
|
}
|
|
else
|
|
{
|
|
return "Specified by Length";
|
|
}
|
|
}
|
|
|
|
// Return the method of generating the texture coordinates.
|
|
const char *vtkSplineFilter::GetGenerateTCoordsAsString(void)
|
|
{
|
|
if ( this->GenerateTCoords == VTK_TCOORDS_OFF )
|
|
{
|
|
return "GenerateTCoordsOff";
|
|
}
|
|
else if ( this->GenerateTCoords == VTK_TCOORDS_FROM_SCALARS )
|
|
{
|
|
return "GenerateTCoordsFromScalar";
|
|
}
|
|
else if ( this->GenerateTCoords == VTK_TCOORDS_FROM_LENGTH )
|
|
{
|
|
return "GenerateTCoordsFromLength";
|
|
}
|
|
else
|
|
{
|
|
return "GenerateTCoordsFromNormalizedLength";
|
|
}
|
|
}
|
|
|
|
void vtkSplineFilter::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Subdivide: :" << this->GetSubdivideAsString() << "\n";
|
|
os << indent << "Maximum Number of Subdivisions: "
|
|
<< this->MaximumNumberOfSubdivisions << "\n";
|
|
os << indent << "Number of Subdivisions: "
|
|
<< this->NumberOfSubdivisions << "\n";
|
|
os << indent << "Length: " << this->Length << "\n";
|
|
os << indent << "Spline: " << this->Spline << "\n";
|
|
os << indent << "Generate TCoords: "
|
|
<< this->GetGenerateTCoordsAsString() << endl;
|
|
os << indent << "Texture Length: " << this->TextureLength << endl;
|
|
}
|
|
|
|
|