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.
 
 
 
 
 
 

491 lines
13 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkButterflySubdivisionFilter.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 "vtkButterflySubdivisionFilter.h"
#include "vtkCellArray.h"
#include "vtkEdgeTable.h"
#include "vtkIdList.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
vtkCxxRevisionMacro(vtkButterflySubdivisionFilter, "$Revision: 1.16 $");
vtkStandardNewMacro(vtkButterflySubdivisionFilter);
static double butterflyWeights[8] =
{.5, .5, .125, .125, -.0625, -.0625, -.0625, -.0625};
void vtkButterflySubdivisionFilter::GenerateSubdivisionPoints(
vtkPolyData *inputDS, vtkIntArray *edgeData, vtkPoints *outputPts,
vtkPointData *outputPD)
{
double *weights, *weights1, *weights2;
vtkIdType *pts = 0;
vtkIdType cellId, newId, i, j;
int edgeId;
vtkIdType npts = 0;
vtkIdType p1, p2;
int valence1, valence2;
vtkCellArray *inputPolys=inputDS->GetPolys();
vtkEdgeTable *edgeTable;
vtkIdList *cellIds = vtkIdList::New();
vtkIdList *p1CellIds = vtkIdList::New();
vtkIdList *p2CellIds = vtkIdList::New();
vtkIdList *stencil = vtkIdList::New();
vtkIdList *stencil1 = vtkIdList::New();
vtkIdList *stencil2 = vtkIdList::New();
vtkPoints *inputPts=inputDS->GetPoints();
vtkPointData *inputPD=inputDS->GetPointData();
weights = new double[256];
weights1 = new double[256];
weights2 = new double[256];
// Create an edge table to keep track of which edges we've processed
edgeTable = vtkEdgeTable::New();
edgeTable->InitEdgeInsertion(inputDS->GetNumberOfPoints());
// Generate new points for subdivisions surface
for (cellId=0, inputPolys->InitTraversal();
inputPolys->GetNextCell(npts, pts); cellId++)
{
if ( inputDS->GetCellType(cellId) != VTK_TRIANGLE )
{
continue;
}
p1 = pts[2];
p2 = pts[0];
for (edgeId=0; edgeId < 3; edgeId++)
{
// Do we need to create a point on this edge?
if (edgeTable->IsEdge (p1, p2) == -1)
{
outputPD->CopyData (inputPD, p1, p1);
outputPD->CopyData (inputPD, p2, p2);
edgeTable->InsertEdge (p1, p2);
inputDS->GetCellEdgeNeighbors (-1, p1, p2, cellIds);
// If this is a boundary edge. we need to use a special subdivision rule
if (cellIds->GetNumberOfIds() == 1)
{
// Compute new POsition and PointData using the same subdivision scheme
this->GenerateBoundaryStencil (p1, p2,
inputDS, stencil, weights);
} // boundary edge
else
{
// find the valence of the two points
inputDS->GetPointCells (p1, p1CellIds);
valence1 = p1CellIds->GetNumberOfIds();
inputDS->GetPointCells (p2, p2CellIds);
valence2 = p2CellIds->GetNumberOfIds();
if (valence1 == 6 && valence2 == 6)
{
this->GenerateButterflyStencil (p1, p2,
inputDS, stencil, weights);
}
else if (valence1 == 6 && valence2 != 6)
{
this->GenerateLoopStencil (p2, p1,
inputDS, stencil, weights);
}
else if (valence1 != 6 && valence2 == 6)
{
this->GenerateLoopStencil (p1, p2,
inputDS, stencil, weights);
}
else
{
// Edge connects two extraordinary vertices
this->GenerateLoopStencil (p2, p1,
inputDS, stencil1, weights1);
this->GenerateLoopStencil (p1, p2,
inputDS, stencil2, weights2);
// combine the two stencils and halve the weights
vtkIdType total = stencil1->GetNumberOfIds() +
stencil2->GetNumberOfIds();
stencil->SetNumberOfIds (total);
j = 0;
for (i = 0; i < stencil1->GetNumberOfIds(); i++)
{
stencil->InsertId(j, stencil1->GetId(i));
weights[j++] = weights1[i] * .5;
}
for (i = 0; i < stencil2->GetNumberOfIds(); i++)
{
stencil->InsertId(j, stencil2->GetId(i));
weights[j++] = weights2[i] * .5;
}
}
}
newId = this->InterpolatePosition (inputPts, outputPts, stencil, weights);
outputPD->InterpolatePoint (inputPD, newId, stencil, weights);
}
else // we have already created a point on this edge. find it
{
newId = this->FindEdge (inputDS, cellId, p1, p2, edgeData, cellIds);
}
edgeData->InsertComponent(cellId,edgeId,newId);
p1 = p2;
if (edgeId < 2)
{
p2 = pts[edgeId + 1];
}
} // each interior edge
} // each cell
// cleanup
delete [] weights; delete [] weights1; delete [] weights2;
edgeTable->Delete();
stencil->Delete (); stencil1->Delete (); stencil2->Delete ();
cellIds->Delete();
p1CellIds->Delete();
p2CellIds->Delete();
}
void vtkButterflySubdivisionFilter::GenerateLoopStencil(
vtkIdType p1, vtkIdType p2, vtkPolyData *polys, vtkIdList *stencilIds,
double *weights)
{
vtkIdList *cellIds = vtkIdList::New();
vtkCell *cell;
int j;
vtkIdType startCell, nextCell, tp2, p;
int shift[255];
int processed = 0;
int boundary = 0;
// Find another cell with this edge (we assume there is just one)
polys->GetCellEdgeNeighbors (-1, p1, p2, cellIds);
startCell = cellIds->GetId(0);
stencilIds->Reset();
stencilIds->InsertNextId (p2);
shift[0] = 0;
// Walk around the loop and get cells
nextCell = cellIds->GetId(1);
tp2 = p2;
while (nextCell != startCell)
{
cell = polys->GetCell(nextCell);
p = -1;
for (int i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p1 && cell->GetPointId(i) != tp2)
{
break;
}
}
tp2 = p;
stencilIds->InsertNextId (tp2);
processed++;
shift[processed] = processed;
polys->GetCellEdgeNeighbors (nextCell, p1, tp2, cellIds);
if (cellIds->GetNumberOfIds() != 1)
{
boundary = 1;
break;
}
nextCell = cellIds->GetId(0);
}
// If p1 or p2 is on the boundary, use the butterfly stencil with reflected vertices.
if (boundary)
{
this->GenerateButterflyStencil (p1, p2,
polys, stencilIds, weights);
cellIds->Delete();
return;
}
// Generate weights
#define VTK_PI 3.14159265358979
int K = stencilIds->GetNumberOfIds();
if (K >= 5)
{
for (j = 0; j < K; j++)
{
weights[j] = (.25 + cos (2.0 * VTK_PI * (double) shift[j] / (double) K)
+ .5 * cos (4.0 * VTK_PI * (double) shift[j] / (double) K)) / (double) K;
}
}
else if (K == 4)
{
static double weights4[4] = {3.0/8.0, 0.0, -1.0/8.0, 0.0};
weights[0] = weights4[abs(shift[0])];
weights[1] = weights4[abs(shift[1])];
weights[2] = weights4[abs(shift[2])];
weights[3] = weights4[abs(shift[3])];
}
else if (K == 3)
{
static double weights3[3] = {5.0/12.0, -1.0/12.0, -1.0/12.0};
weights[0] = weights3[abs(shift[0])];
weights[1] = weights3[abs(shift[1])];
weights[2] = weights3[abs(shift[2])];
}
else
{ // K == 2. p1 must be on a boundary edge,
cell = polys->GetCell(startCell);
p = -1;
for (int i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p1 && cell->GetPointId(i) != p2)
{
break;
}
}
p2 = p;
stencilIds->InsertNextId (p2);
weights[0] = 5.0 / 12.0;
weights[1] = -1.0 / 12.0;
weights[2] = -1.0 / 12.0;
}
// add in the extraordinary vertex
weights[stencilIds->GetNumberOfIds()] = .75;
stencilIds->InsertNextId (p1);
cellIds->Delete();
}
void vtkButterflySubdivisionFilter::GenerateBoundaryStencil(
vtkIdType p1, vtkIdType p2, vtkPolyData *polys, vtkIdList *stencilIds,
double *weights)
{
vtkIdList *cellIds = vtkIdList::New();
vtkIdType *cells;
unsigned short ncells;
vtkIdType *pts;
vtkIdType npts;
int i, j;
vtkIdType p0, p3;
// find a boundary edge that uses p1 other than the one containing p2
polys->GetPointCells (p1, ncells, cells);
p0 = -1;
for (i = 0; i < ncells && p0 == -1; i++)
{
polys->GetCellPoints (cells[i], npts, pts);
for (j = 0; j < npts; j++)
{
if (pts[j] == p1 || pts[j] == p2)
{
continue;
}
polys->GetCellEdgeNeighbors (-1, p1, pts[j], cellIds);
if (cellIds->GetNumberOfIds() == 1)
{
p0 = pts[j];
break;
}
}
}
// find a boundary edge that uses p2 other than the one containing p1
polys->GetPointCells (p2, ncells, cells);
p3 = -1;
for (i = 0; i < ncells && p3 == -1; i++)
{
polys->GetCellPoints (cells[i], npts, pts);
for (j = 0; j < npts; j++)
{
if (pts[j] == p1 || pts[j] == p2 || pts[j] == p0)
{
continue;
}
polys->GetCellEdgeNeighbors (-1, p2, pts[j], cellIds);
if (cellIds->GetNumberOfIds() == 1)
{
p3 = pts[j];
break;
}
}
}
stencilIds->SetNumberOfIds (4);
stencilIds->SetId (0, p0);
stencilIds->SetId (1, p1);
stencilIds->SetId (2, p2);
stencilIds->SetId (3, p3);
weights[0] = -.0625;
weights[1] = .5625;
weights[2] = .5625;
weights[3] = -.0625;
cellIds->Delete();
}
void vtkButterflySubdivisionFilter::GenerateButterflyStencil (
vtkIdType p1, vtkIdType p2, vtkPolyData *polys, vtkIdList *stencilIds,
double *weights)
{
vtkIdList *cellIds = vtkIdList::New();
vtkCell *cell;
int i;
vtkIdType cell0, cell1;
vtkIdType p, p3, p4, p5, p6, p7, p8;
polys->GetCellEdgeNeighbors (-1, p1, p2, cellIds);
cell0 = cellIds->GetId(0);
cell1 = cellIds->GetId(1);
cell = polys->GetCell(cell0);
p3 = -1;
for (i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p1 && cell->GetPointId(i) != p2)
{
p3 = p;
break;
}
}
cell = polys->GetCell(cell1);
p4 = -1;
for (i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p1 && cell->GetPointId(i) != p2)
{
p4 = p;
break;
}
}
polys->GetCellEdgeNeighbors (cell0, p1, p3, cellIds);
p5 = -1;
if (cellIds->GetNumberOfIds() > 0)
{
cell = polys->GetCell(cellIds->GetId(0));
for (i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p1 && cell->GetPointId(i) != p3)
{
p5 = p;
break;
}
}
}
polys->GetCellEdgeNeighbors (cell0, p2, p3, cellIds);
p6 = -1;
if (cellIds->GetNumberOfIds() > 0)
{
cell = polys->GetCell(cellIds->GetId(0));
for (i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p2 && cell->GetPointId(i) != p3)
{
p6 = p;
break;
}
}
}
polys->GetCellEdgeNeighbors (cell1, p1, p4, cellIds);
p7 = -1;
if (cellIds->GetNumberOfIds() > 0)
{
cell = polys->GetCell(cellIds->GetId(0));
for (i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p1 && cell->GetPointId(i) != p4)
{
p7 = p;
break;
}
}
}
p8 = -1;
polys->GetCellEdgeNeighbors (cell1, p2, p4, cellIds);
if (cellIds->GetNumberOfIds() > 0)
{
cell = polys->GetCell(cellIds->GetId(0));
for (i = 0; i < 3; i++)
{
if ((p = cell->GetPointId(i)) != p2 && cell->GetPointId(i) != p4)
{
p8= p;
break;
}
}
}
stencilIds->SetNumberOfIds (8);
stencilIds->SetId(0, p1);
stencilIds->SetId(1, p2);
stencilIds->SetId(2, p3);
stencilIds->SetId(3, p4);
if (p5 != -1)
{
stencilIds->SetId(4, p5);
}
else if (p4 != -1)
{
stencilIds->SetId(4, p4);
}
else
{
vtkWarningMacro (<< "bad p5, p4 " << p5 << ", " << p4);
}
if (p6 != -1)
{
stencilIds->SetId(5, p6);
}
else if (p4 != -1)
{
stencilIds->SetId(5, p4);
}
else
{
vtkWarningMacro (<< "bad p5, p4 " << p5 << ", " << p4);
}
if (p7 != -1)
{
stencilIds->SetId(6, p7);
}
else if (p3 != -1)
{
stencilIds->SetId(6, p3);
}
else
{
vtkWarningMacro (<< "bad p7, p3 " << p7 << ", " << p3);
}
if (p8 != -1)
{
stencilIds->SetId(7, p8);
}
else if (p3 != -1)
{
stencilIds->SetId(7, p3);
}
else
{
vtkWarningMacro (<< "bad p7, p8 " << p7 << ", " << p3);
}
for (i = 0; i < stencilIds->GetNumberOfIds (); i++)
{
weights[i] = butterflyWeights[i];
}
cellIds->Delete();
}