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.
283 lines
8.4 KiB
283 lines
8.4 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkApproximatingSubdivisionFilter.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 "vtkApproximatingSubdivisionFilter.h"
|
|
|
|
#include "vtkCell.h"
|
|
#include "vtkCellArray.h"
|
|
#include "vtkCellData.h"
|
|
#include "vtkEdgeTable.h"
|
|
#include "vtkIdList.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkPolyData.h"
|
|
#include "vtkUnsignedCharArray.h"
|
|
|
|
vtkCxxRevisionMacro(vtkApproximatingSubdivisionFilter, "$Revision: 1.30 $");
|
|
|
|
// Construct object with number of subdivisions set to 1.
|
|
vtkApproximatingSubdivisionFilter::vtkApproximatingSubdivisionFilter()
|
|
{
|
|
this->NumberOfSubdivisions = 1;
|
|
}
|
|
|
|
int vtkApproximatingSubdivisionFilter::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()));
|
|
|
|
vtkIdType numCells, numPts;
|
|
int level;
|
|
vtkPoints *outputPts;
|
|
|
|
vtkCellArray *outputPolys;
|
|
vtkPointData *outputPD;
|
|
vtkCellData *outputCD;
|
|
vtkIntArray *edgeData;
|
|
|
|
vtkDebugMacro(<< "Generating subdivision surface using approximating scheme");
|
|
numPts=input->GetNumberOfPoints();
|
|
numCells=input->GetNumberOfCells();
|
|
|
|
if (numPts < 1 || numCells < 1)
|
|
{
|
|
vtkErrorMacro(<<"No data to approximate!");
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Initialize and check input
|
|
//
|
|
|
|
vtkPolyData *inputDS = vtkPolyData::New();
|
|
inputDS->CopyStructure (input);
|
|
inputDS->GetPointData()->PassData(input->GetPointData());
|
|
inputDS->GetCellData()->PassData(input->GetCellData());
|
|
|
|
int abort=0;
|
|
for (level = 0; level < this->NumberOfSubdivisions && !abort; level++)
|
|
{
|
|
this->UpdateProgress((double)(level+1)/this->NumberOfSubdivisions);
|
|
abort = this->GetAbortExecute();
|
|
|
|
// Generate topology for the input dataset
|
|
inputDS->BuildLinks();
|
|
|
|
numCells = inputDS->GetNumberOfCells ();
|
|
numPts = inputDS->GetNumberOfPoints();
|
|
|
|
// The points for the subdivisions will
|
|
// include even points (computed from old points) and
|
|
// odd points (inserted on edges)
|
|
outputPts = vtkPoints::New();
|
|
outputPts->Allocate (numPts);
|
|
|
|
// Copy pointdata structure from input
|
|
outputPD = vtkPointData::New();
|
|
outputPD->CopyAllocate(inputDS->GetPointData(),2*inputDS->GetNumberOfPoints());
|
|
|
|
// Copy celldata structure from input
|
|
outputCD = vtkCellData::New();
|
|
outputCD->CopyAllocate(inputDS->GetCellData(),4*numCells);
|
|
|
|
// Create triangles
|
|
outputPolys = vtkCellArray::New();
|
|
outputPolys->Allocate(outputPolys->EstimateSize(4*numCells,3));
|
|
|
|
// Create an array to hold new location indices
|
|
edgeData = vtkIntArray::New();
|
|
edgeData->SetNumberOfComponents(3);
|
|
edgeData->SetNumberOfTuples(numCells);
|
|
|
|
this->GenerateSubdivisionPoints (inputDS, edgeData, outputPts, outputPD);
|
|
this->GenerateSubdivisionCells (inputDS, edgeData, outputPolys, outputCD);
|
|
|
|
// start the next iteration with the input set to the output we just created
|
|
edgeData->Delete();
|
|
inputDS->Delete();
|
|
inputDS = vtkPolyData::New();
|
|
inputDS->SetPoints(outputPts); outputPts->Delete();
|
|
inputDS->SetPolys(outputPolys); outputPolys->Delete();
|
|
inputDS->GetPointData()->PassData(outputPD); outputPD->Delete();
|
|
inputDS->GetCellData()->PassData(outputCD); outputCD->Delete();
|
|
inputDS->Squeeze();
|
|
} // each level
|
|
|
|
// Get rid of ghost cells if we have to.
|
|
unsigned char* ghostLevels=0;
|
|
|
|
vtkCellData* cd = inputDS->GetCellData();
|
|
if (cd)
|
|
{
|
|
vtkDataArray* temp = cd->GetArray("vtkGhostLevels");
|
|
if (temp)
|
|
{
|
|
ghostLevels = ((vtkUnsignedCharArray*)temp)->GetPointer(0);
|
|
}
|
|
}
|
|
int updateGhostLevel = output->GetUpdateGhostLevel();
|
|
|
|
output->SetPoints(inputDS->GetPoints());
|
|
output->SetPolys(inputDS->GetPolys());
|
|
output->GetPointData()->PassData(inputDS->GetPointData());
|
|
output->GetCellData()->PassData(inputDS->GetCellData());
|
|
|
|
if (input->GetGhostLevel() > updateGhostLevel && ghostLevels != NULL)
|
|
{
|
|
output->RemoveGhostCells(updateGhostLevel+1);
|
|
}
|
|
|
|
inputDS->Delete();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int vtkApproximatingSubdivisionFilter::FindEdge (vtkPolyData *mesh,
|
|
vtkIdType cellId,
|
|
vtkIdType p1, vtkIdType p2,
|
|
vtkIntArray *edgeData,
|
|
vtkIdList *cellIds)
|
|
{
|
|
|
|
int edgeId = 0;
|
|
vtkIdType currentCellId = 0;
|
|
vtkIdType i;
|
|
int numEdges;
|
|
vtkIdType tp1, tp2;
|
|
vtkCell *cell;
|
|
|
|
// get all the cells that use the edge (except for cellId)
|
|
mesh->GetCellEdgeNeighbors (cellId, p1, p2, cellIds);
|
|
|
|
// find the edge that has the point we are looking for
|
|
for ( i=0; i < cellIds->GetNumberOfIds(); i++)
|
|
{
|
|
currentCellId = cellIds->GetId(i);
|
|
cell = mesh->GetCell(currentCellId);
|
|
numEdges = cell->GetNumberOfEdges();
|
|
tp1 = cell->GetPointId(2);
|
|
tp2 = cell->GetPointId(0);
|
|
for (edgeId=0; edgeId < numEdges; edgeId++)
|
|
{
|
|
if ( (tp1 == p1 && tp2 == p2) ||
|
|
(tp2 == p1 && tp1 == p2))
|
|
{
|
|
break;
|
|
}
|
|
tp1 = tp2;
|
|
tp2 = cell->GetPointId(edgeId + 1);
|
|
}
|
|
}
|
|
// found the edge, return the stored value
|
|
return (int) edgeData->GetComponent(currentCellId,edgeId);
|
|
}
|
|
|
|
vtkIdType vtkApproximatingSubdivisionFilter::InterpolatePosition (
|
|
vtkPoints *inputPts, vtkPoints *outputPts,
|
|
vtkIdList *stencil, double *weights)
|
|
{
|
|
double xx[3], x[3];
|
|
vtkIdType i;
|
|
int j;
|
|
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
x[j] = 0.0;
|
|
}
|
|
|
|
for (i = 0; i < stencil->GetNumberOfIds(); i++)
|
|
{
|
|
inputPts->GetPoint(stencil->GetId(i), xx);
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
x[j] += xx[j] * weights[i];
|
|
}
|
|
}
|
|
return outputPts->InsertNextPoint (x);
|
|
}
|
|
|
|
|
|
void vtkApproximatingSubdivisionFilter::GenerateSubdivisionCells (
|
|
vtkPolyData *inputDS, vtkIntArray *edgeData, vtkCellArray *outputPolys,
|
|
vtkCellData *outputCD)
|
|
{
|
|
vtkIdType numCells = inputDS->GetNumberOfCells();
|
|
vtkIdType cellId, newId, id;
|
|
vtkIdType npts;
|
|
vtkIdType *pts;
|
|
double edgePts[3];
|
|
vtkIdType newCellPts[3];
|
|
vtkCellData *inputCD = inputDS->GetCellData();
|
|
|
|
// Now create new cells from existing points and generated edge points
|
|
for (cellId=0; cellId < numCells; cellId++)
|
|
{
|
|
if ( inputDS->GetCellType(cellId) != VTK_TRIANGLE )
|
|
{
|
|
continue;
|
|
}
|
|
// get the original point ids and the ids stored as edge data
|
|
inputDS->GetCellPoints(cellId, npts, pts);
|
|
edgeData->GetTuple(cellId, edgePts);
|
|
|
|
id = 0;
|
|
newCellPts[id++] = pts[0];
|
|
newCellPts[id++] = (int) edgePts[1];
|
|
newCellPts[id++] = (int) edgePts[0];
|
|
newId = outputPolys->InsertNextCell (3, newCellPts);
|
|
outputCD->CopyData (inputCD, cellId, newId);
|
|
|
|
id = 0;
|
|
newCellPts[id++] = (int) edgePts[1];
|
|
newCellPts[id++] = pts[1];
|
|
newCellPts[id++] = (int) edgePts[2];
|
|
newId = outputPolys->InsertNextCell (3, newCellPts);
|
|
outputCD->CopyData (inputCD, cellId, newId);
|
|
|
|
id = 0;
|
|
newCellPts[id++] = (int) edgePts[2];
|
|
newCellPts[id++] = pts[2];
|
|
newCellPts[id++] = (int) edgePts[0];
|
|
newId = outputPolys->InsertNextCell (3, newCellPts);
|
|
outputCD->CopyData (inputCD, cellId, newId);
|
|
|
|
id = 0;
|
|
newCellPts[id++] = (int) edgePts[1];
|
|
newCellPts[id++] = (int) edgePts[2];
|
|
newCellPts[id++] = (int) edgePts[0];
|
|
newId = outputPolys->InsertNextCell (3, newCellPts);
|
|
outputCD->CopyData (inputCD, cellId, newId);
|
|
}
|
|
}
|
|
|
|
void vtkApproximatingSubdivisionFilter::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Number of subdivisions: "
|
|
<< this->NumberOfSubdivisions << endl;
|
|
}
|
|
|
|
|
|
|