1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    BoxClipTriangulate.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 /*----------------------------------------------------------------------------
17  Copyright (c) Sandia Corporation
18  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
19 ----------------------------------------------------------------------------*/
20 
21 // This test makes sure that vtkBoxClipDataSet correctly triangulates all cell
22 // types.
23 
24 #include "vtkBoxClipDataSet.h"
25 #include "vtkCellArray.h"
26 #include "vtkDataSetSurfaceFilter.h"
27 #include "vtkDoubleArray.h"
28 #include "vtkMath.h"
29 #include "vtkPoints.h"
30 #include "vtkPolyData.h"
31 #include "vtkTriangle.h"
32 #include "vtkUnstructuredGrid.h"
33 
34 #include "vtkExtractEdges.h"
35 #include "vtkPolyDataMapper.h"
36 #include "vtkActor.h"
37 #include "vtkRenderer.h"
38 #include "vtkRenderWindow.h"
39 #include "vtkRenderWindowInteractor.h"
40 
41 #include "vtkSmartPointer.h"
42 #define VTK_CREATE(type, var) \
43   vtkSmartPointer<type> var = vtkSmartPointer<type>::New()
44 
45 #include <time.h>
46 
47 #include <vector>
48 
49 const int NumPoints = 13;
50 const double PointData[NumPoints*3] = {
51   0.0, 0.0, 0.0,
52   0.0, 1.0, 0.0,
53   1.0, 0.0, 0.0,
54   1.0, 1.0, 0.0,
55   2.0, 0.0, 0.0,
56   2.0, 1.0, 0.0,
57 
58   0.0, 0.0, 1.0,
59   0.0, 1.0, 1.0,
60   1.0, 0.0, 1.0,
61   1.0, 1.0, 1.0,
62   2.0, 0.0, 1.0,
63   2.0, 1.0, 1.0,
64   2.0, 0.5, 1.0
65 };
66 
67 
68 const vtkIdType NumTriStripCells = 1;
69 const vtkIdType TriStripCells[] = {
70   6, 1, 0, 3, 2, 5, 4
71 };
72 
73 const vtkIdType NumQuadCells = 2;
74 const vtkIdType QuadCells[] = {
75   4, 0, 2, 3, 1,
76   4, 2, 4, 5, 3
77 };
78 
79 const vtkIdType NumPixelCells = 2;
80 const vtkIdType PixelCells[] = {
81   4, 0, 2, 1, 3,
82   4, 2, 4, 3, 5
83 };
84 
85 const vtkIdType NumPolyCells = 3;
86 const vtkIdType PolyCells[] = {
87   4, 0, 2, 3, 1,
88   3, 2, 4, 5,
89   5, 6, 8, 12, 9, 7
90 };
91 
92 
93 const vtkIdType NumHexCells = 2;
94 const vtkIdType HexCells[] = {
95   8, 6, 8, 2, 0, 7, 9, 3, 1,
96   8, 4, 2, 8, 10, 5, 3, 9, 11
97 };
98 const vtkIdType NumExpectedHexSurfacePolys = 20;
99 
100 const vtkIdType NumVoxelCells = 2;
101 const vtkIdType VoxelCells[] = {
102   8, 0, 2, 1, 3, 6, 8, 7, 9,
103   8, 10, 8, 11, 9, 4, 2, 5, 3
104 };
105 const vtkIdType NumExpectedVoxelSurfacePolys = 20;
106 
107 const vtkIdType NumWedgeCells = 4;
108 const vtkIdType WedgeCells[] = {
109   6, 0, 1, 2, 6, 7, 8,
110   6, 7, 8, 9, 1, 2, 3,
111   6, 8, 11, 9, 2, 5, 3,
112   6, 2, 5, 4, 8, 11, 10
113 };
114 const vtkIdType NumExpectedWedgeSurfacePolys = 20;
115 
116 const vtkIdType NumPyramidCells = 2;
117 const vtkIdType PyramidCells[] = {
118   5, 8, 9, 3, 2, 0,
119   5, 2, 3, 9, 8, 12
120 };
121 const vtkIdType NumExpectedPyramidSurfacePolys = 8;
122 
123 class BoxClipTriangulateFailed { };
124 
125 //-----------------------------------------------------------------------------
126 
CheckWinding(vtkBoxClipDataSet * alg)127 static void CheckWinding(vtkBoxClipDataSet* alg)
128 {
129   alg->Update();
130   vtkUnstructuredGrid* data = alg->GetOutput();
131 
132   vtkPoints *points = data->GetPoints();
133 
134   vtkCellArray *cells = data->GetCells();
135   cells->InitTraversal();
136 
137   vtkIdType npts, *pts;
138   while (cells->GetNextCell(npts, pts))
139     {
140     if (npts != 4)
141       {
142       std::cout << "Weird.  I got something that is not a tetrahedra." << std::endl;
143       continue;
144       }
145 
146     double p0[3], p1[3], p2[3], p3[3];
147     points->GetPoint(pts[0], p0);
148     points->GetPoint(pts[1], p1);
149     points->GetPoint(pts[2], p2);
150     points->GetPoint(pts[3], p3);
151 
152     // If the winding is correct, the normal to triangle p0,p1,p2 should point
153     // towards p3.
154     double v0[3], v1[3];
155     v0[0] = p1[0] - p0[0];    v0[1] = p1[1] - p0[1];    v0[2] = p1[2] - p0[2];
156     v1[0] = p2[0] - p0[0];    v1[1] = p2[1] - p0[1];    v1[2] = p2[2] - p0[2];
157 
158     double n[3];
159     vtkMath::Cross(v0, v1, n);
160 
161     double d[3];
162     d[0] = p3[0] - p0[0];    d[1] = p3[1] - p0[1];    d[2] = p3[2] - p0[2];
163 
164     if (vtkMath::Dot(n, d) < 0)
165       {
166       std::cout << "Found a tetrahedra with bad winding." << std::endl;
167       throw BoxClipTriangulateFailed();
168       }
169     }
170 }
171 
172 //-----------------------------------------------------------------------------
173 
BuildInput(int type,vtkIdType numcells,const vtkIdType * cells)174 static vtkSmartPointer<vtkUnstructuredGrid> BuildInput(int type,
175                                                        vtkIdType numcells,
176                                                        const vtkIdType *cells)
177 {
178   vtkIdType i;
179 
180   VTK_CREATE(vtkUnstructuredGrid, input);
181 
182   // Randomly shuffle the points to possibly test various tessellations.
183   // Make a map from original point orderings to new point orderings.
184   std::vector<vtkIdType> idMap;
185   std::vector<vtkIdType> idsLeft;
186 
187   for (i = 0; i < NumPoints; i++)
188     {
189     idsLeft.push_back(i);
190     }
191 
192   while (!idsLeft.empty())
193     {
194     vtkIdType next
195       = vtkMath::Round(vtkMath::Random(-0.49, idsLeft.size() - 0.51));
196     std::vector<vtkIdType>::iterator nextp = idsLeft.begin() + next;
197     idMap.push_back(*nextp);
198     idsLeft.erase(nextp, nextp + 1);
199     }
200 
201   // Build shuffled points.
202   VTK_CREATE(vtkPoints, points);
203   points->SetNumberOfPoints(NumPoints);
204   for (i = 0; i < NumPoints; i++)
205     {
206     points->SetPoint(idMap[i], PointData + 3*i);
207     }
208   input->SetPoints(points);
209 
210   // Add the cells with indices properly mapped.
211   VTK_CREATE(vtkIdList, ptIds);
212   const vtkIdType *c = cells;
213   for (i = 0; i < numcells; i++)
214     {
215     vtkIdType npts = *c;  c++;
216     ptIds->Initialize();
217     for (vtkIdType j = 0; j < npts; j++)
218       {
219       ptIds->InsertNextId(idMap[*c]);
220       c++;
221       }
222     input->InsertNextCell(type, ptIds);
223     }
224 
225   return input;
226 }
227 
228 //-----------------------------------------------------------------------------
229 
Check2DPrimitive(int type,vtkIdType numcells,const vtkIdType * cells)230 static void Check2DPrimitive(int type, vtkIdType numcells,
231                              const vtkIdType *cells)
232 {
233   vtkSmartPointer<vtkUnstructuredGrid> input
234     = BuildInput(type, numcells, cells);
235 
236   VTK_CREATE(vtkBoxClipDataSet, clipper);
237   clipper->SetInputData(input);
238   // Clip nothing.
239   clipper->SetBoxClip(0.0, 2.0, 0.0, 1.0, 0.0, 1.0);
240   clipper->Update();
241 
242   vtkUnstructuredGrid *output = clipper->GetOutput();
243 
244   if (output->GetNumberOfCells() < 1)
245     {
246     std::cout << "Output has no cells!" << std::endl;
247     throw BoxClipTriangulateFailed();
248     }
249 
250   // Check to make sure all the normals point in the z direction.
251   vtkCellArray *outCells = output->GetCells();
252   outCells->InitTraversal();
253   vtkIdType npts, *pts;
254   while (outCells->GetNextCell(npts, pts))
255     {
256     if (npts != 3)
257       {
258       std::cout << "Got a primitive that is not a triangle!" << std::endl;
259       throw BoxClipTriangulateFailed();
260       }
261 
262     double n[3];
263     vtkTriangle::ComputeNormal(output->GetPoints(), npts, pts, n);
264     if ((n[0] > 0.1) || (n[1] > 0.1) || (n[2] < 0.9))
265       {
266       std::cout << "Primitive is facing the wrong way!" << std::endl;
267       throw BoxClipTriangulateFailed();
268       }
269     }
270 }
271 
272 //-----------------------------------------------------------------------------
273 
Check3DPrimitive(int type,vtkIdType numcells,const vtkIdType * cells,vtkIdType numSurfacePolys)274 static void Check3DPrimitive(int type, vtkIdType numcells,
275                              const vtkIdType *cells, vtkIdType numSurfacePolys)
276 {
277   vtkSmartPointer<vtkUnstructuredGrid> input
278     = BuildInput(type, numcells, cells);
279 
280   VTK_CREATE(vtkBoxClipDataSet, clipper);
281   clipper->SetInputData(input);
282   // Clip nothing.
283   clipper->SetBoxClip(0.0, 2.0, 0.0, 1.0, 0.0, 1.0);
284   clipper->Update();
285 
286   vtkUnstructuredGrid *output = clipper->GetOutput();
287 
288   if (output->GetNumberOfCells() < 1)
289     {
290     std::cout << "Output has no cells!" << std::endl;
291     throw BoxClipTriangulateFailed();
292     }
293 
294 #if 0
295   VTK_CREATE(vtkExtractEdges, edges);
296   edges->SetInput(output);
297   VTK_CREATE(vtkPolyDataMapper, mapper);
298   mapper->SetInputConnection(0, edges->GetOutputPort(0));
299   VTK_CREATE(vtkActor, actor);
300   actor->SetMapper(mapper);
301   VTK_CREATE(vtkRenderer, renderer);
302   renderer->AddActor(actor);
303   VTK_CREATE(vtkRenderWindow, renwin);
304   renwin->AddRenderer(renderer);
305   VTK_CREATE(vtkRenderWindowInteractor, iren);
306   iren->SetRenderWindow(renwin);
307   renwin->Render();
308   iren->Start();
309 #endif
310 
311   CheckWinding(clipper);
312 
313   VTK_CREATE(vtkDataSetSurfaceFilter, surface);
314   surface->SetInputConnection(clipper->GetOutputPort());
315   surface->Update();
316 
317   if (surface->GetOutput()->GetNumberOfCells() != numSurfacePolys)
318     {
319     std::cout << "Expected " << numSurfacePolys << " triangles on the surface, got "
320          << surface->GetOutput()->GetNumberOfCells() << std::endl;
321     throw BoxClipTriangulateFailed();
322     }
323 }
324 
325 //-----------------------------------------------------------------------------
326 
BoxClipTriangulate(int,char * [])327 int BoxClipTriangulate(int, char *[])
328 {
329   long seed = time(NULL);
330   std::cout << "Random seed = " << seed << std::endl;
331   vtkMath::RandomSeed(seed);
332   vtkMath::Random();
333   vtkMath::Random();
334   vtkMath::Random();
335 
336   try
337     {
338     std::cout << "Checking triangle strip." << std::endl;
339     Check2DPrimitive(VTK_TRIANGLE_STRIP, NumTriStripCells, TriStripCells);
340 
341     std::cout << "Checking quadrilaterals." << std::endl;
342     Check2DPrimitive(VTK_QUAD, NumQuadCells, QuadCells);
343 
344     std::cout << "Checking pixels." << std::endl;
345     Check2DPrimitive(VTK_PIXEL, NumPixelCells, PixelCells);
346 
347     std::cout << "Checking polygons." << std::endl;
348     Check2DPrimitive(VTK_POLYGON, NumPolyCells, PolyCells);
349 
350     std::cout << "Checking hexahedrons." << std::endl;
351     Check3DPrimitive(VTK_HEXAHEDRON, NumHexCells, HexCells,
352                      NumExpectedHexSurfacePolys);
353 
354     std::cout << "Checking voxels." << std::endl;
355     Check3DPrimitive(VTK_VOXEL, NumVoxelCells, VoxelCells,
356                      NumExpectedVoxelSurfacePolys);
357 
358     std::cout << "Checking wedges." << std::endl;
359     Check3DPrimitive(VTK_WEDGE, NumWedgeCells, WedgeCells,
360                      NumExpectedWedgeSurfacePolys);
361 
362     std::cout << "Checking pyramids." << std::endl;
363     Check3DPrimitive(VTK_PYRAMID, NumPyramidCells, PyramidCells,
364                      NumExpectedPyramidSurfacePolys);
365     }
366   catch (BoxClipTriangulateFailed)
367     {
368     return EXIT_FAILURE;
369     }
370 
371   return EXIT_SUCCESS;
372 }
373