[vtkusers] Using vtkTriangleFilter to reduce concave polygons to convex

Alex Southern mrapsouthern at gmail.com
Mon Jul 2 05:50:50 EDT 2012


Hi, Thank you for your suggestions, I figured it out below. For some 
reason, which one of you is probably aware of, the vtkTriangleFilter 
does not behave in an intuitive way when you provide only one polygon. 
An example of this is given by the original code I posted.

Bill's suggestion of randomly perturbing the points in each axial 
direction by a small amount, although I have not tried it, I am safe to 
assume it works. Presumably this is related to the fact that the points 
are no longer in the same axial plane. I also tried using a 
vtkTriangleFilter on a more complex 3D model that was defined by both 
convex (not triangles) and concave polygons, using Paraview to apply the 
Triangulate filter (vtkTriangleFilter), it worked perfectly well.

For my needs I want to triangulate a single potentially "bad"polygon and 
keep track of which triangles belonged to which polygon. As I explained, 
vtkTriangleFilter did not behave well under these conditions. Therefore, 
replacing vtkTriangleFilter with vtkDelaunay2D does the trick.

This was probably already known or obvious to most, in any case, there 
it is.

Thanks for you time.
A.

#include <vtkVersion.h>
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkCubeSource.h>
#include <vtkPolyData.h>
#include <vtkCellArray.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPointData.h>
#include <vtkDelaunay2D.h>

using namespace std;

int main()
{

     vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
     vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
     vtkSmartPointer<vtkDelaunay2D> triFilter = vtkSmartPointer<vtkDelaunay2D>::New();
     vtkSmartPointer<vtkPolyData> pd1 = vtkSmartPointer<vtkPolyData>::New();
     vtkPolyData *pd2;

     // Generate a concave polygon that is NOT flat (in one plane)
     pts->InsertNextPoint( 1.00, 2.48, 0.00 );
     pts->InsertNextPoint( 1.00, 0.00, 0.00 );
     pts->InsertNextPoint( 1.00, 1.24, 0.29 );
     pts->InsertNextPoint( 0.00, 0.00, 0.00 );
     pts->InsertNextPoint( 0.00, 2.48, 0.00 );
     int p[5] = {0, 1, 2, 3, 4};
     cellArray->InsertNextCell(5,p);

     pd1->SetPoints( pts );
     pd1->SetPolys( cellArray );

     triFilter->SetInput( pd1 );
     triFilter->Update();
     pd2 = triFilter->GetOutput();

     //  // Create a renderer, render window, and interactor
     vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
     vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
     vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

     renderWindow->AddRenderer(renderer);
     renderWindowInteractor->SetRenderWindow(renderWindow);

     // map filtered data
     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();

     mapper->SetInput( pd2 );  // change to pd1 to see bad polygon
     actor->SetMapper( mapper );
     renderer->AddActor( actor );

     renderer->SetBackground(.5, .1, .1);

     //// Render and interact
     renderWindow->Render();
     renderWindowInteractor->Start();

  return 0;
}




On 6/30/2012 7:07 PM, Bill Lorensen wrote:
> Here's a not so elegant solution. It perturbs each point by a small
> random number, does the triangulation and then reassigns the original
> points to the polydata.
>
> #include <vtkVersion.h>
> #include <vtkSmartPointer.h>
> #include <vtkActor.h>
> #include <vtkCubeSource.h>
> #include <vtkPolyData.h>
> #include <vtkCellArray.h>
> #include <vtkPolyDataMapper.h>
> #include <vtkRenderWindow.h>
> #include <vtkRenderWindowInteractor.h>
> #include <vtkRenderer.h>
> #include <vtkPointData.h>
> #include <vtkTriangleFilter.h>
> #include <vtkMath.h>
>
> using namespace std;
>
> int main()
> {
>     vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
>     vtkSmartPointer<vtkPoints> ptsDelta = vtkSmartPointer<vtkPoints>::New();
>     vtkSmartPointer<vtkCellArray> cellArray =
> vtkSmartPointer<vtkCellArray>::New();
>
>     vtkSmartPointer<vtkTriangleFilter> triFilter =
> vtkSmartPointer<vtkTriangleFilter>::New();
>     vtkSmartPointer<vtkPolyData> pd1 = vtkSmartPointer<vtkPolyData>::New();
>     vtkPolyData *pd2;
>
>     // Generate a concave polygon that is NOT flat (i.e. not in one plane)
>     pts->InsertNextPoint( 1.00, 2.48, 0.00 );
>     pts->InsertNextPoint( 1.00, 0.00, 0.00 );
>     pts->InsertNextPoint( 1.00, 1.24, 0.29 );
>     pts->InsertNextPoint( 0.00, 0.00, 0.00 );
>     pts->InsertNextPoint( 0.00, 2.4801, 0.00 );
>     int p[5] = {0, 1, 2, 3, 4};
>     cellArray->InsertNextCell(5,p);
>
>     for (unsigned int i = 0; i < pts->GetNumberOfPoints(); ++i)
>       {
>       double x, y, z;
>       x = pts->GetPoint(i)[0] + vtkMath::Random(0.0, .00001);
>       y = pts->GetPoint(i)[1] + vtkMath::Random(0.0, .00001);
>       z = pts->GetPoint(i)[2] + vtkMath::Random(0.0, .00001);
>       ptsDelta->InsertNextPoint(x, y, z);
>       }
>     pd1->SetPoints( ptsDelta );
>     pd1->SetPolys( cellArray );
>
>
>
> #if VTK_MAJOR_VERSION <= 5
>     triFilter->SetInput( pd1 );
> #else
>     triFilter->SetInputData( pd1 );
> #endif
>     triFilter->Update();
>     pd2 = triFilter->GetOutput();
>     pd2->SetPoints(pts);
>
>     // Create a renderer, render window, and interactor
>     vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
>     vtkSmartPointer<vtkRenderWindow> renderWindow =
> vtkSmartPointer<vtkRenderWindow>::New();
>     vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
> vtkSmartPointer<vtkRenderWindowInteractor>::New();
>
>     renderWindow->AddRenderer(renderer);
>     renderWindowInteractor->SetRenderWindow(renderWindow);
>
>     // map filtered data
>     vtkSmartPointer<vtkPolyDataMapper> mapper =
> vtkSmartPointer<vtkPolyDataMapper>::New();
>     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
>
> #if VTK_MAJOR_VERSION <= 5
>     mapper->SetInput( pd2 );  // change to pd1 to see bad polygon
> #else
>     mapper->SetInputData( pd2 );  // change to pd1 to see bad polygon
> #endif
>     actor->SetMapper( mapper );
>     renderer->AddActor( actor );
>
>     renderer->SetBackground(.5, .1, .1);
>
>     //// Render and interact
>     renderWindow->Render();
>     renderWindowInteractor->Start();
>
>   return 0;
> }





More information about the vtkusers mailing list