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