1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    UnitTestPlanesIntersection.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 #include "vtkSmartPointer.h"
17 #include "vtkPlanesIntersection.h"
18 
19 #include "vtkTetra.h"
20 #include "vtkPoints.h"
21 #include "vtkBoundingBox.h"
22 #include "vtkRegularPolygonSource.h"
23 #include "vtkDoubleArray.h"
24 #include "vtkMath.h"
25 #include "vtkTestErrorObserver.h"
26 
27 #include <sstream>
28 static vtkSmartPointer<vtkTetra> MakeTetra();
29 
UnitTestPlanesIntersection(int,char * [])30 int UnitTestPlanesIntersection(int, char*[])
31 {
32   int status = 0;
33   {
34   vtkSmartPointer<vtkPlanesIntersection> aPlanes =
35     vtkSmartPointer<vtkPlanesIntersection>::New();
36   std::cout << "  Testing Print of an PlanesIntersection...";
37   std::ostringstream planesPrint;
38   aPlanes->Print(planesPrint);
39   std::cout << "PASSED" << std::endl;
40   }
41 
42   {
43   std::cout << "  Testing Convert3DCell...";
44   vtkSmartPointer<vtkTetra> aTetra = MakeTetra();
45   vtkPlanesIntersection *aPlanes =
46     vtkPlanesIntersection::Convert3DCell(aTetra);
47   if (aTetra->GetNumberOfFaces() != aPlanes->GetNumberOfPlanes())
48   {
49     status++;
50     std::cout << "FAILED" << std::endl;
51   }
52   else
53   {
54     std::cout << "PASSED" << std::endl;
55   }
56   aPlanes->Delete();
57   }
58 
59   {
60   std::cout << "  Testing Region Vertices...";
61   vtkSmartPointer<vtkTetra> aTetra = MakeTetra();
62   vtkPlanesIntersection *aPlanes =
63     vtkPlanesIntersection::Convert3DCell(aTetra);
64   int numVertices = aPlanes->GetNumberOfRegionVertices();
65   if (numVertices != 4)
66   {
67     std::cout << " GetNumberOfRegionVertices() got " << numVertices
68               << " but expected 4 ";
69     std::cout << "FAILED" << std::endl;
70     ++status;
71   }
72   else
73   {
74     std::cout << "PASSED" << std::endl;
75   }
76   aPlanes->Delete();
77   }
78 
79   {
80   std::cout << "  Testing PolygonIntersectsBBox...";
81   int status4 = 0;
82   vtkBoundingBox bbox1(-10, 10, -10, 10, -10, 10);
83 
84   // create a polygon
85   vtkSmartPointer<vtkRegularPolygonSource> polygon =
86     vtkSmartPointer<vtkRegularPolygonSource>::New();
87   polygon->SetNumberOfSides(15);
88   double center[3] = {0.0, 0.0, 0.0};
89   double radius = 10.0;
90   polygon->SetCenter(center);
91   polygon->SetRadius(radius);
92   polygon->Update();
93   double bounds[6];
94   bbox1.GetBounds(bounds);
95 
96   int result = vtkPlanesIntersection::PolygonIntersectsBBox(
97     bounds,
98     polygon->GetOutput()->GetPoints());
99   if (result == 0)
100   {
101     ++status4;
102     std::cout << " PolygonIntersectsBBox() fails bbox contains ";
103   }
104 
105   // bbox outside
106   vtkBoundingBox bbox3(100, 200, 100, 200, 100, 200);
107   bbox3.GetBounds(bounds);
108 
109   result = vtkPlanesIntersection::PolygonIntersectsBBox(
110     bounds,
111     polygon->GetOutput()->GetPoints());
112   if (result != 0)
113   {
114     ++status4;
115     std::cout << " PolygonIntersectsBBox() fils bbox outside ";
116   }
117 
118   // bbox straddles
119   vtkBoundingBox bbox2(0, 200, 0, 200, 0, 200);
120   bbox2.GetBounds(bounds);
121 
122   result = vtkPlanesIntersection::PolygonIntersectsBBox(
123     bounds,
124     polygon->GetOutput()->GetPoints());
125   if (result != 0)
126   {
127     ++status4;
128     std::cout << " PolygonIntersectsBBox() fils bbox outside ";
129   }
130 
131   if (status4)
132   {
133     std::cout << "FAILED" << std::endl;
134   }
135   else
136   {
137     std::cout << "PASSED" << std::endl;
138   }
139   }
140 
141   {
142   std::cout << "  Testing IntersectsRegion...";
143   int status2 = 0;
144   vtkBoundingBox bbox(-10, 10, -10, 10, -10, 10);
145   double xmin, xmax, ymin, ymax, zmin, zmax;
146   bbox.GetMinPoint(xmin, ymin, zmin);
147   bbox.GetMaxPoint(xmax, ymax, zmax);
148 
149   vtkSmartPointer<vtkPoints> points =
150     vtkSmartPointer<vtkPoints>::New();
151 
152   points->InsertNextPoint(xmin, ymin, zmin);
153   points->InsertNextPoint(xmax, ymin, zmin);
154   points->InsertNextPoint(xmax, ymax, zmin);
155   points->InsertNextPoint(xmin, ymax, zmin);
156 
157   points->InsertNextPoint(xmin, ymin, zmax);
158   points->InsertNextPoint(xmax, ymin, zmax);
159   points->InsertNextPoint(xmax, ymax, zmax);
160   points->InsertNextPoint(xmin, ymax, zmax);
161 
162   vtkSmartPointer<vtkTetra> aTetra = MakeTetra();
163   vtkPlanesIntersection *aPlanes =
164     vtkPlanesIntersection::Convert3DCell(aTetra);
165   std::ostringstream planesPrint;
166   aPlanes->Print(planesPrint);
167 
168   if (aPlanes->IntersectsRegion(points) == 0)
169   {
170     ++status2;
171   }
172   points->SetPoint(0, -.01, -.01, -.01);
173   points->SetPoint(1, .01, -.01, -.01);
174   points->SetPoint(2, .01, .01, -.01);
175   points->SetPoint(3, -.01, .01, -.01);
176 
177   points->SetPoint(4, -.01, -.01, .01);
178   points->SetPoint(5, .01, -.01, .01);
179   points->SetPoint(6, .01, .01, .01);
180   points->SetPoint(7, -.01, .01, .01);
181   points->Modified();
182   // box is entirely inside
183   if (aPlanes->IntersectsRegion(points) != 1)
184   {
185     ++status2;
186   }
187 
188   points->SetPoint(0, 1000.0, 1000.0, 1000.0);
189   points->SetPoint(1, 2000.0, 1000.0, 1000.0);
190   points->SetPoint(2, 2000.0, 2000.0, 1000.0);
191   points->SetPoint(3, 1000.0, 2000.0, 1000.0);
192 
193   points->SetPoint(4, 1000.0, 1000.0, 2000.0);
194   points->SetPoint(5, 2000.0, 1000.0, 2000.0);
195   points->SetPoint(6, 2000.0, 2000.0, 2000.0);
196   points->SetPoint(7, 1000.0, 2000.0, 2000.0);
197   points->Modified();
198 
199   // box is entirely outside
200   if (aPlanes->IntersectsRegion(points) != 0)
201   {
202     std::cout << "Box entirely outside failed ";
203     ++status2;
204   }
205   points->SetPoint(0, 0.0, 0.0, 0.0);
206   points->SetPoint(1, 10.0, 0.0, 0.0);
207   points->SetPoint(2, 10.0, 10.0, 0.0);
208   points->SetPoint(3, 0.0, 10.0, 0.0);
209 
210   points->SetPoint(4, 0.0, 0.0, 10.0);
211   points->SetPoint(5, 10.0, 0.0, 10.0);
212   points->SetPoint(6, 10.0, 10.0, 10.0);
213   points->SetPoint(7, 0.0, 10.0, 10.0);
214   points->Modified();
215 
216   // box straddles region
217   if (aPlanes->IntersectsRegion(points) != 1)
218   {
219     std::cout << "Box straddling region failed ";
220     ++status2;
221   }
222 
223   aPlanes->Delete();
224   if (status2)
225   {
226     std::cout << "FAILED" << std::endl;
227     ++status;
228   }
229   else
230   {
231     std::cout << "PASSED" << std::endl;
232   }
233   }
234 
235   {
236   std::cout << "  Testing Set/GetRegionVertices...";
237   int status3 = 0;
238 
239   vtkSmartPointer<vtkTetra> aTetra = MakeTetra();
240   vtkPlanesIntersection *aPlanes =
241     vtkPlanesIntersection::Convert3DCell(aTetra);
242   int numberOfRegionVertices = aPlanes->GetNumRegionVertices();
243   std::vector<double> regionVertices(numberOfRegionVertices * 3);
244 
245   int got = aPlanes->GetRegionVertices(
246     &(*regionVertices.begin()),
247     numberOfRegionVertices);
248   if (got != numberOfRegionVertices)
249   {
250     ++status3;
251     std::cout << " GetRegionVertices() got " << got
252               << " but expected " << numberOfRegionVertices << " ";
253   }
254   aPlanes->SetRegionVertices(
255     &(*regionVertices.begin()),
256     numberOfRegionVertices);
257   // Repeat to exercise Delete()
258   aPlanes->SetRegionVertices(
259     &(*regionVertices.begin()),
260     numberOfRegionVertices);
261 
262  // Ask for fewer region vertices
263   got = aPlanes->GetRegionVertices(
264     &(*regionVertices.begin()),
265     1);
266   if (got != 1)
267   {
268     ++status3;
269     std::cout << " GetRegionVertices() got " << got
270               << " but expected 1 ";
271   }
272 
273   vtkSmartPointer<vtkPlanesIntersection> regionPlane =
274     vtkSmartPointer<vtkPlanesIntersection>::New();
275   vtkSmartPointer<vtkPoints> rpoints =
276     vtkSmartPointer<vtkPoints>::New();
277   rpoints->InsertNextPoint  (-1.0, 0.0, 0.0);
278   rpoints->InsertNextPoint  (1.0, 0.0, 0.0);
279   rpoints->InsertNextPoint  (0.0, -1.0, 0.0);
280   rpoints->InsertNextPoint  (0.0, 1.0, 0.0);
281   rpoints->InsertNextPoint  (0.0, 0.0, -1.0);
282   rpoints->InsertNextPoint  (0.0, 0.0, 1.0);
283   regionPlane->SetRegionVertices(rpoints);
284 
285   // Repeat to test Delete()
286   regionPlane->SetRegionVertices(rpoints);
287 
288   vtkSmartPointer<vtkTest::ErrorObserver>  errorObserver =
289     vtkSmartPointer<vtkTest::ErrorObserver>::New();
290   double v;
291   vtkSmartPointer<vtkPlanesIntersection> empty =
292     vtkSmartPointer<vtkPlanesIntersection>::New();
293   empty->AddObserver(vtkCommand::ErrorEvent, errorObserver);
294   empty->GetRegionVertices(&v, 0);
295   status3 += errorObserver->CheckErrorMessage("invalid region");
296 
297   if (status3)
298   {
299     ++status;
300     std::cout << "FAILED" << std::endl;
301   }
302   else
303   {
304     std::cout << "PASSED" << std::endl;
305   }
306   aPlanes->Delete();
307   }
308 
309   {
310   std::cout << "  Testing SetRegionVertices...";
311   int status5 = 0;
312   vtkSmartPointer<vtkPlanesIntersection> aPlanes =
313     vtkSmartPointer<vtkPlanesIntersection>::New();
314   vtkSmartPointer<vtkPoints> points =
315     vtkSmartPointer<vtkPoints>::New();
316   vtkSmartPointer<vtkDoubleArray> normals =
317     vtkSmartPointer<vtkDoubleArray>::New();
318   normals->SetNumberOfComponents(3);
319 
320   points->InsertNextPoint  (-1.0, 0.0, 0.0);
321   normals->InsertNextTuple3(-1.0, 0.0, 0.0);
322   points->InsertNextPoint  (1.0, 0.0, 0.0);
323   normals->InsertNextTuple3(1.0, 0.0, 0.0);
324   points->InsertNextPoint  (0.0, -1.0, 0.0);
325   normals->InsertNextTuple3(0.0, -1.0, 0.0);
326   points->InsertNextPoint  (0.0, 1.0, 0.0);
327   normals->InsertNextTuple3(0.0, 1.0, 0.0);
328   points->InsertNextPoint  (0.0, 0.0, -1.0);
329   normals->InsertNextTuple3(0.0, 0.0, -1.0);
330   points->InsertNextPoint  (0.0, 0.0, 1.0);
331   normals->InsertNextTuple3(0.0, 0.0, 1.0);
332   aPlanes->SetPoints(points);
333   aPlanes->SetNormals(normals);
334 
335   int numberOfRegionVertices = aPlanes->GetNumRegionVertices();
336   if (numberOfRegionVertices != 8)
337   {
338     ++status5;
339     std::cout << " GetNumRegionVertices() got " << numberOfRegionVertices
340               << " but expected 8 ";
341   }
342   std::vector<double> regionVertices(numberOfRegionVertices * 3);
343 
344   aPlanes->GetRegionVertices(
345     &(*regionVertices.begin()),
346     numberOfRegionVertices);
347   aPlanes->SetRegionVertices(
348     &(*regionVertices.begin()),
349     numberOfRegionVertices);
350 
351   if (status5)
352   {
353     ++status;
354     std::cout << "FAILED" << std::endl;
355   }
356   else
357   {
358     std::cout << "PASSED" << std::endl;
359   }
360   }
361 
362   {
363   std::cout << "  Testing IntersectsRegion Errors...";
364   vtkSmartPointer<vtkTest::ErrorObserver>  errorObserver =
365     vtkSmartPointer<vtkTest::ErrorObserver>::New();
366 
367   vtkBoundingBox bbox(-10, 10, -10, 10, -10, 10);
368   double xmin, xmax, ymin, ymax, zmin, zmax;
369   bbox.GetMinPoint(xmin, ymin, zmin);
370   bbox.GetMaxPoint(xmax, ymax, zmax);
371 
372   vtkSmartPointer<vtkPoints> points =
373     vtkSmartPointer<vtkPoints>::New();
374 
375   points->InsertNextPoint(xmin, ymin, zmin);
376   points->InsertNextPoint(xmax, ymin, zmin);
377   points->InsertNextPoint(xmax, ymax, zmin);
378   points->InsertNextPoint(xmin, ymax, zmin);
379 
380   points->InsertNextPoint(xmin, ymin, zmax);
381   points->InsertNextPoint(xmax, ymin, zmax);
382   points->InsertNextPoint(xmax, ymax, zmax);
383   points->InsertNextPoint(xmin, ymax, zmax);
384 
385   // empty planes
386   vtkSmartPointer<vtkPlanesIntersection> empty =
387     vtkSmartPointer<vtkPlanesIntersection>::New();
388   empty->AddObserver(vtkCommand::ErrorEvent, errorObserver);
389 
390   int status1 = 0;
391   if (empty->IntersectsRegion(points) != 0)
392   {
393     ++status1;
394     std::cout << "FAILED" << std::endl;
395   }
396   else
397   {
398   status1 += errorObserver->CheckErrorMessage("invalid region - less than 4 planes");
399   }
400 
401   // Invalid Region
402   vtkSmartPointer<vtkPlanesIntersection> invalidRegion =
403     vtkSmartPointer<vtkPlanesIntersection>::New();
404   invalidRegion->AddObserver(vtkCommand::ErrorEvent, errorObserver);
405 
406   vtkSmartPointer<vtkPoints> npoints =
407     vtkSmartPointer<vtkPoints>::New();
408   vtkSmartPointer<vtkDoubleArray> normals =
409     vtkSmartPointer<vtkDoubleArray>::New();
410   normals->SetNumberOfComponents(3);
411 
412   npoints->InsertNextPoint  (-1.0, 0.0, 0.0);
413   normals->InsertNextTuple3(-1.0, 0.0, 0.0);
414   npoints->InsertNextPoint  (-1.0, 0.0, 0.0);
415   normals->InsertNextTuple3(-1.0, 0.0, 0.0);
416   npoints->InsertNextPoint  (-1.0, 0.0, 0.0);
417   normals->InsertNextTuple3(-1.0, 0.0, 0.0);
418   npoints->InsertNextPoint  (-1.0, 0.0, 0.0);
419   normals->InsertNextTuple3(-1.0, 0.0, 0.0);
420   invalidRegion->SetPoints(npoints);
421   invalidRegion->SetNormals(normals);
422 
423   if (invalidRegion->IntersectsRegion(points) != 0)
424   {
425     ++status1;
426     std::cout << "FAILED" << std::endl;
427   }
428   else
429   {
430   status1 += errorObserver->CheckErrorMessage("Invalid region: zero-volume intersection");
431   }
432   vtkSmartPointer<vtkPlanesIntersection> invalidBox =
433     vtkSmartPointer<vtkPlanesIntersection>::New();
434   invalidBox->AddObserver(vtkCommand::ErrorEvent, errorObserver);
435 
436   vtkSmartPointer<vtkPoints> points2 =
437     vtkSmartPointer<vtkPoints>::New();
438   vtkSmartPointer<vtkDoubleArray> normals2 =
439     vtkSmartPointer<vtkDoubleArray>::New();
440   normals2->SetNumberOfComponents(3);
441 
442   points2->InsertNextPoint  (-1.0, 0.0, 0.0);
443   normals2->InsertNextTuple3(-1.0, 0.0, 0.0);
444   points2->InsertNextPoint  (1.0, 0.0, 0.0);
445   normals2->InsertNextTuple3(1.0, 0.0, 0.0);
446   points2->InsertNextPoint  (0.0, -1.0, 0.0);
447   normals2->InsertNextTuple3(0.0, -1.0, 0.0);
448   points2->InsertNextPoint  (0.0, 1.0, 0.0);
449   normals2->InsertNextTuple3(0.0, 1.0, 0.0);
450   points2->InsertNextPoint  (0.0, 0.0, -1.0);
451   normals2->InsertNextTuple3(0.0, 0.0, -1.0);
452   points2->InsertNextPoint  (0.0, 0.0, 1.0);
453   normals2->InsertNextTuple3(0.0, 0.0, 1.0);
454   invalidBox->SetPoints(points2);
455   invalidBox->SetNormals(normals2);
456 
457   vtkSmartPointer<vtkPoints> badBox =
458     vtkSmartPointer<vtkPoints>::New();
459 
460   badBox->InsertNextPoint(xmin, ymin, zmin);
461   badBox->InsertNextPoint(xmax, ymin, zmin);
462   badBox->InsertNextPoint(xmax, ymax, zmin);
463   badBox->InsertNextPoint(xmin, ymax, zmin);
464 
465   badBox->InsertNextPoint(xmin, ymin, zmax);
466   badBox->InsertNextPoint(xmax, ymin, zmax);
467   badBox->InsertNextPoint(xmax, ymax, zmax);
468 
469   if (invalidBox->IntersectsRegion(badBox) != 0)
470   {
471     ++status1;
472     std::cout << "FAILED" << std::endl;
473   }
474   else
475   {
476     status1 += errorObserver->CheckErrorMessage("invalid box");
477   }
478 
479   if (status1)
480   {
481     ++status;
482     std::cout << "FAILED" << std::endl;
483   }
484   else
485   {
486     std::cout << "PASSED" << std::endl;
487   }
488   }
489 
490   if (status)
491   {
492     return EXIT_FAILURE;
493   }
494   else
495   {
496     return EXIT_SUCCESS;
497   }
498 }
499 
500 
MakeTetra()501 vtkSmartPointer<vtkTetra> MakeTetra()
502 {
503   vtkSmartPointer<vtkTetra> aTetra =
504     vtkSmartPointer<vtkTetra>::New();
505   aTetra->GetPointIds()->SetId(0,0);
506   aTetra->GetPointIds()->SetId(1,1);
507   aTetra->GetPointIds()->SetId(2,2);
508   aTetra->GetPointIds()->SetId(3,3);
509   aTetra->GetPoints()->SetPoint(0, -1.0, -1.0, -1.0);
510   aTetra->GetPoints()->SetPoint(1,  1.0, -1.0, -1.0);
511   aTetra->GetPoints()->SetPoint(2,  0.0,  1.0, -1.0);
512   aTetra->GetPoints()->SetPoint(3,  0.5,  0.5,  1.0);
513   return aTetra;
514 }
515