vtkCleanPolyData could add degenerate cells to wrong cell arrays if respective convert options are OFF
The ConvertLinesToPoints, ConvertPolysToLines and ConvertStripsToPolys options in vtkCleanPolyData do not behave correctly. If those are set to OFF, degenerated cells may still get added to the wrong cell array, i.e. a degenerated triangle could be added as a line to the poly cell array.
The following code demonstrates the issue:
vtkSmartPointer<vtkPolyData> construct_lines()
{
vtkIdType ptIds[4];
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(0.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 1.0, 0.0);
// Lines
vtkSmartPointer<vtkCellArray> degeneratedLines = vtkSmartPointer<vtkCellArray>::New();
// Construct a non-degenerated line (0, 1)
ptIds[0] = 0;
ptIds[1] = 1;
degeneratedLines->InsertNextCell(2, ptIds);
// Construct a line (0, 0) degenerated to a vertex
ptIds[0] = 0;
ptIds[1] = 0;
degeneratedLines->InsertNextCell(2, ptIds);
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
polydata->SetLines(degeneratedLines);
assert(polydata->GetNumberOfLines() == 2);
return polydata;
}
vtkSmartPointer<vtkPolyData> construct_polys()
{
vtkIdType ptIds[4];
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(0.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 1.0, 0.0);
// Polys
vtkSmartPointer<vtkCellArray> degeneratedPolys = vtkSmartPointer<vtkCellArray>::New();
// Construct a non-degenerated triangle (0, 1, 2)
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 2;
degeneratedPolys->InsertNextCell(3, ptIds);
// Construct a triangle (0, 0, 0) degenerated to a vertex
ptIds[0] = 0;
ptIds[1] = 0;
ptIds[2] = 0;
degeneratedPolys->InsertNextCell(3, ptIds);
// Construct a triangle (0, 1, 1) degenerated to a line
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 1;
degeneratedPolys->InsertNextCell(3, ptIds);
// Construct a quad (1, 1, 1, 1) degenerated to a vertex
ptIds[0] = 1;
ptIds[1] = 1;
ptIds[2] = 1;
ptIds[3] = 1;
degeneratedPolys->InsertNextCell(4, ptIds);
// Construct a quad (0, 1, 1, 0) degenerated to a line
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 1;
ptIds[3] = 0;
degeneratedPolys->InsertNextCell(4, ptIds);
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
polydata->SetPolys(degeneratedPolys);
assert(polydata->GetNumberOfPolys() == 5);
return polydata;
}
vtkSmartPointer<vtkPolyData> construct_strips()
{
vtkIdType ptIds[4];
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint(0.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 0.0, 0.0);
points->InsertNextPoint(1.0, 1.0, 0.0);
points->InsertNextPoint(0.0, 1.0, 0.0);
// Strips
vtkSmartPointer<vtkCellArray> degeneratedStrips = vtkSmartPointer<vtkCellArray>::New();
// Construct a non-degenerated strip (0, 1, 2, 3)
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 2;
ptIds[3] = 3;
degeneratedStrips->InsertNextCell(4, ptIds);
// Construct a strip (0, 1, 2, 2) degenerated to a triangle
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 2;
ptIds[3] = 2;
degeneratedStrips->InsertNextCell(4, ptIds);
// Construct a strip (0, 1, 1, 1) degenerated to a line
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 1;
ptIds[3] = 1;
degeneratedStrips->InsertNextCell(4, ptIds);
// Construct a strip (2, 2, 2, 2) degenerated to a vertex
ptIds[0] = 2;
ptIds[1] = 2;
ptIds[2] = 2;
ptIds[3] = 2;
degeneratedStrips->InsertNextCell(4, ptIds);
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
polydata->SetStrips(degeneratedStrips);
assert(polydata->GetNumberOfStrips() == 4);
return polydata;
}
int main()
{
// First test degenerate conversions
vtkSmartPointer<vtkCleanPolyData> clean = vtkSmartPointer<vtkCleanPolyData>::New();
clean->PointMergingOff();
clean->ConvertLinesToPointsOn();
clean->ConvertPolysToLinesOn();
clean->ConvertStripsToPolysOn();
auto lines = construct_lines();
clean->SetInputData(lines);
clean->Update();
// Input had 1 non-degenerated line and 1 degenerated line
// Output should have 1 line and a 1 vertex
auto linesout = clean->GetOutput();
assert(linesout->GetNumberOfVerts() == 1);
assert(linesout->GetNumberOfLines() == 1);
assert(linesout->GetNumberOfPolys() == 0);
assert(linesout->GetNumberOfStrips() == 0);
auto polys = construct_polys();
clean->SetInputData(polys);
clean->Update();
// Input had 1 non-degenerated poly, 2 polys degenerated to a vertex and 2 polys degenerated to a line
// Output should have 1 poly, 2 vertices and 2 lines
auto polysout = clean->GetOutput();
assert(polysout->GetNumberOfVerts() == 2);
assert(polysout->GetNumberOfLines() == 2);
assert(polysout->GetNumberOfPolys() == 1);
assert(polysout->GetNumberOfStrips() == 0);
auto strips = construct_strips();
clean->SetInputData(strips);
clean->Update();
// Input had 1 non-degenerated strip, 1 strip degenerated to a triangle, 1 strip degenerated to a line and 1 degenerated to a vertex
// Output should have 1 strip, 1 poly, 1 line and 1 vertex
auto stripsout = clean->GetOutput();
assert(stripsout->GetNumberOfVerts() == 1);
assert(stripsout->GetNumberOfLines() == 1);
assert(stripsout->GetNumberOfPolys() == 1);
assert(stripsout->GetNumberOfStrips() == 1);
// Now test degenerate elimination
clean->ConvertLinesToPointsOff();
clean->ConvertPolysToLinesOff();
clean->ConvertStripsToPolysOff();
clean->SetInputData(lines);
clean->Update();
// Input had 1 non-degenerated line and 1 degenerated line
// Output should have 1 line
auto linesout2 = clean->GetOutput();
assert(linesout2->GetNumberOfVerts() == 0);
assert(linesout2->GetNumberOfLines() == 1); // FAIL: Will have two lines of which one is a vertex
assert(linesout2->GetNumberOfPolys() == 0);
assert(linesout2->GetNumberOfStrips() == 0);
clean->SetInputData(polys);
clean->Update();
// Input had 1 non-degenerated poly, 2 polys degenerated to a vertex and 2 polys degenerated to a line
// Output should have 1 poly
auto polysout2 = clean->GetOutput();
assert(polysout2->GetNumberOfVerts() == 0);
assert(polysout2->GetNumberOfLines() == 0);
assert(polysout2->GetNumberOfPolys() == 1); // FAIL: Will have 5 polygons of which 4 are degenerated
assert(polysout2->GetNumberOfStrips() == 0);
clean->SetInputData(strips);
clean->Update();
// Input had 1 non-degenerated strip, 1 strip degenerated to a triangle, 1 strip degenerated to a line and 1 degenerated to a vertex
// Output should have 1 strip
auto stripsout2 = clean->GetOutput();
assert(stripsout2->GetNumberOfVerts() == 0);
assert(stripsout2->GetNumberOfLines() == 0);
assert(stripsout2->GetNumberOfPolys() == 0);
assert(stripsout2->GetNumberOfStrips() == 1); // FAIL: Will have 4 strips of which 3 are degenerated
}