1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: UnitTestTriangleIntersection.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 <algorithm>
17 #include <array>
18 #include <cmath>
19 #include <sstream>
20
21 #include "vtkLine.h"
22 #include "vtkMath.h"
23 #include "vtkMinimalStandardRandomSequence.h"
24 #include "vtkSmartPointer.h"
25 #include "vtkTriangle.h"
26
27 #define VISUAL_DEBUG 0
28
29 #ifdef VISUAL_DEBUG
30 #include <vtkActor.h>
31 #include <vtkCellArray.h>
32 #include <vtkDoubleArray.h>
33 #include <vtkPointData.h>
34 #include <vtkPolyData.h>
35 #include <vtkPolyDataMapper.h>
36 #include <vtkProperty.h>
37 #include <vtkRenderWindow.h>
38 #include <vtkRenderWindowInteractor.h>
39 #include <vtkRenderer.h>
40
41 namespace
42 {
DrawTriangles(double * p1,double * q1,double * r1,double * p2,double * q2,double * r2)43 void DrawTriangles(double* p1, double* q1, double* r1, double* p2, double* q2, double* r2)
44 {
45 // Create a triangle
46 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
47 vtkIdType pid[6];
48 pid[0] = points->InsertNextPoint(p1[0], p1[1], p1[2]);
49 pid[1] = points->InsertNextPoint(q1[0], q1[1], q1[2]);
50 pid[2] = points->InsertNextPoint(r1[0], r1[1], r1[2]);
51 pid[3] = points->InsertNextPoint(p2[0], p2[1], p2[2]);
52 pid[4] = points->InsertNextPoint(q2[0], q2[1], q2[2]);
53 pid[5] = points->InsertNextPoint(r2[0], r2[1], r2[2]);
54
55 vtkSmartPointer<vtkCellArray> verts = vtkSmartPointer<vtkCellArray>::New();
56 for (int i = 0; i < 6; i++)
57 {
58 verts->InsertNextCell(1, &pid[i]);
59 }
60
61 vtkSmartPointer<vtkTriangle> triangle1 = vtkSmartPointer<vtkTriangle>::New();
62 triangle1->GetPointIds()->SetId(0, 0);
63 triangle1->GetPointIds()->SetId(1, 1);
64 triangle1->GetPointIds()->SetId(2, 2);
65
66 vtkSmartPointer<vtkTriangle> triangle2 = vtkSmartPointer<vtkTriangle>::New();
67 triangle2->GetPointIds()->SetId(0, 3);
68 triangle2->GetPointIds()->SetId(1, 4);
69 triangle2->GetPointIds()->SetId(2, 5);
70
71 vtkSmartPointer<vtkCellArray> triangles = vtkSmartPointer<vtkCellArray>::New();
72 triangles->InsertNextCell(triangle1);
73 triangles->InsertNextCell(triangle2);
74
75 vtkSmartPointer<vtkDoubleArray> pointIds = vtkSmartPointer<vtkDoubleArray>::New();
76 pointIds->SetNumberOfTuples(6);
77 pointIds->SetTuple1(0, 0.);
78 pointIds->SetTuple1(1, 1.);
79 pointIds->SetTuple1(2, 2.);
80 pointIds->SetTuple1(3, 3.);
81 pointIds->SetTuple1(4, 4.);
82 pointIds->SetTuple1(5, 5.);
83
84 // Create a polydata object
85 vtkSmartPointer<vtkPolyData> trianglePolyData = vtkSmartPointer<vtkPolyData>::New();
86
87 // Add the geometry and topology to the polydata
88 trianglePolyData->SetPoints(points);
89 trianglePolyData->SetVerts(verts);
90 trianglePolyData->SetPolys(triangles);
91 trianglePolyData->GetPointData()->SetScalars(pointIds);
92
93 // Create mapper and actor
94 vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
95 mapper->SetInputData(trianglePolyData);
96 mapper->SetScalarRange(0., 5.);
97 vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
98 actor->SetMapper(mapper);
99 actor->GetProperty()->SetPointSize(5);
100
101 // Create a renderer, render window, and an interactor
102 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
103 vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
104 renderWindow->AddRenderer(renderer);
105 vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
106 vtkSmartPointer<vtkRenderWindowInteractor>::New();
107 renderWindowInteractor->SetRenderWindow(renderWindow);
108
109 // Add the actors to the scene
110 renderer->AddActor(actor);
111 renderer->SetBackground(.1, .2, .4); // Background color dark blue
112
113 // Render and interact
114 renderWindow->Render();
115 renderWindowInteractor->Start();
116 }
117 }
118
119 #endif
120
121 namespace
122 {
123 const double EPSILON = 1.e-6;
124
125 const int VTK_NO_INTERSECTION = 0;
126 const int VTK_YES_INTERSECTION = 1;
127
128 typedef vtkMinimalStandardRandomSequence vtkRandom;
129
TriangleToString(double * t1,double * t2,double * t3)130 std::string TriangleToString(double* t1, double* t2, double* t3)
131 {
132 std::stringstream stream;
133 stream << "(" << t1[0] << "," << t1[1] << "," << t1[2] << ") (" << t2[0] << "," << t2[1] << ","
134 << t2[2] << ") (" << t3[0] << "," << t3[1] << "," << t3[2] << ")";
135 return stream.str();
136 }
137
ProjectPointOntoPlane(double * o,double * n,double * p)138 void ProjectPointOntoPlane(double* o, double* n, double* p)
139 {
140 // Project point p onto a plane that crosses through point o and has normal n.
141
142 double pMinuso[3];
143 vtkMath::Subtract(p, o, pMinuso);
144
145 double dot = vtkMath::Dot(pMinuso, n);
146
147 for (int i = 0; i < 3; i++)
148 {
149 p[i] -= dot * n[i];
150 }
151 }
152
GeneratePointInPlane(vtkRandom * seq,double * o,double * n,double * p)153 void GeneratePointInPlane(vtkRandom* seq, double* o, double* n, double* p)
154 {
155 // Generate a point p that lies in a plane that crosses through point o and
156 // has normal n.
157
158 for (int i = 0; i < 3; i++)
159 {
160 seq->Next();
161 p[i] = -1. + 2. * seq->GetValue();
162 }
163
164 ProjectPointOntoPlane(o, n, p);
165 }
166
ReflectPointThroughPlane(double * o,double * n,double * p)167 void ReflectPointThroughPlane(double* o, double* n, double* p)
168 {
169 // Reflect point p through a plane that crosses through point o and has normal
170 // n.
171
172 double dot = 0.;
173 for (int i = 0; i < 3; i++)
174 {
175 dot += (p[i] - o[i]) * n[i];
176 }
177
178 for (int i = 0; i < 3; i++)
179 {
180 p[i] -= dot * n[i];
181 }
182 }
183
GeneratePointInHalfPlane(vtkRandom * seq,double * o,double * n,double * o2,double * n2,double * p)184 void GeneratePointInHalfPlane(
185 vtkRandom* seq, double* o, double* n, double* o2, double* n2, double* p)
186 {
187 // Generate a point p that lies in a plane that crosses through point o, has
188 // normal n, and lies on the positive side of the halfspace defined by point
189 // o1 and normal n2.
190
191 GeneratePointInPlane(seq, o, n, p);
192
193 double pMinuso2[3];
194 vtkMath::Subtract(p, o2, pMinuso2);
195
196 if (vtkMath::Dot(n2, pMinuso2) < 0.)
197 {
198 ReflectPointThroughPlane(o2, n2, p);
199 }
200 }
201
GenerateTriangleInPlane(vtkRandom * seq,double * o,double * n,double * t1,double * t2,double * t3)202 void GenerateTriangleInPlane(
203 vtkRandom* seq, double* o, double* n, double* t1, double* t2, double* t3)
204 {
205 do
206 {
207 GeneratePointInPlane(seq, o, n, t1);
208 GeneratePointInPlane(seq, o, n, t2);
209 GeneratePointInPlane(seq, o, n, t3);
210 } while (vtkTriangle::TriangleArea(t1, t2, t3) < EPSILON);
211 }
212
GenerateTriangleInHalfPlane(vtkRandom * seq,double * o,double * n,double * o2,double * n2,double * t1,double * t2,double * t3)213 void GenerateTriangleInHalfPlane(
214 vtkRandom* seq, double* o, double* n, double* o2, double* n2, double* t1, double* t2, double* t3)
215 {
216 do
217 {
218 GeneratePointInHalfPlane(seq, o, n, o2, n2, t1);
219 GeneratePointInHalfPlane(seq, o, n, o2, n2, t2);
220 GeneratePointInHalfPlane(seq, o, n, o2, n2, t3);
221 } while (vtkTriangle::TriangleArea(t1, t2, t3) < EPSILON);
222 }
223
RandomSphere(vtkRandom * seq,const double radius,const double * offset,double * value)224 void RandomSphere(vtkRandom* seq, const double radius, const double* offset, double* value)
225 {
226 // Generate a point on a sphere.
227
228 seq->Next();
229 double theta = 2. * vtkMath::Pi() * seq->GetValue();
230 seq->Next();
231 double phi = vtkMath::Pi() * seq->GetValue();
232 value[0] = radius * cos(theta) * sin(phi) + offset[0];
233 value[1] = radius * sin(theta) * sin(phi) + offset[1];
234 value[2] = radius * cos(phi) + offset[2];
235 }
236
TestNegativeResult(vtkRandom * seq,unsigned nTests)237 int TestNegativeResult(vtkRandom* seq, unsigned nTests)
238 {
239 double origin[3] = { 0., 0., 0. };
240 double n1[3], n2[3], o1[3], t1[3][3], t2[3][3];
241
242 for (unsigned test = 0; test < nTests; test++)
243 {
244 RandomSphere(seq, 1, origin, n1);
245 RandomSphere(seq, 1, origin, n2);
246
247 for (int i = 0; i < 3; i++)
248 {
249 seq->Next();
250 o1[i] = seq->GetValue();
251 }
252
253 GenerateTriangleInPlane(seq, o1, n1, t1[0], t1[1], t1[2]);
254 double dividingPlaneOrigin[3];
255 for (int i = 0; i < 3; i++)
256 {
257 dividingPlaneOrigin[i] = t1[0][i] + EPSILON * n1[i];
258 }
259 GenerateTriangleInHalfPlane(seq, o1, n2, dividingPlaneOrigin, n1, t2[0], t2[1], t2[2]);
260
261 int returnValue = vtkTriangle::TrianglesIntersect(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
262
263 if (returnValue != VTK_NO_INTERSECTION)
264 {
265 std::cout << "Triangle " << TriangleToString(t1[0], t1[1], t1[2]) << std::endl;
266 std::cout << " intersects " << TriangleToString(t2[0], t2[1], t2[2]) << " and shouldn't."
267 << std::endl;
268 #ifdef VISUAL_DEBUG
269 DrawTriangles(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
270 #endif
271 return EXIT_FAILURE;
272 }
273 }
274
275 return EXIT_SUCCESS;
276 }
277
TestCoplanarNegativeResult(vtkRandom * seq,unsigned nTests)278 int TestCoplanarNegativeResult(vtkRandom* seq, unsigned nTests)
279 {
280 double origin[3] = { 0., 0., 0. };
281 double n1[3], n2[3], nn2[3], o1[3], o2[3], t1[3][3], t2[3][3];
282
283 for (unsigned test = 0; test < nTests; test++)
284 {
285 RandomSphere(seq, 1, origin, n1);
286 RandomSphere(seq, 1, origin, n2);
287
288 n1[0] = n1[1] = 0.;
289 n1[2] = 1.;
290
291 n2[0] = 1.;
292 n2[1] = n2[2] = 0.;
293
294 double dot = vtkMath::Dot(n1, n2);
295
296 for (int i = 0; i < 3; i++)
297 {
298 n2[i] -= dot * n1[i];
299 nn2[i] = -1. * n2[i];
300 seq->Next();
301 o1[i] = seq->GetValue();
302 }
303
304 o1[0] = o1[1] = o1[2] = 1.;
305
306 GeneratePointInPlane(seq, o1, n1, o2);
307
308 o2[0] = o2[1] = 0.;
309 o2[2] = 1.;
310
311 double dividingPlaneOrigin[3];
312 for (int i = 0; i < 3; i++)
313 {
314 dividingPlaneOrigin[i] = o2[i] + 10000. * EPSILON * nn2[i];
315 }
316
317 GenerateTriangleInHalfPlane(seq, o1, n1, o2, n2, t1[0], t1[1], t1[2]);
318 GenerateTriangleInHalfPlane(seq, o1, n1, dividingPlaneOrigin, nn2, t2[0], t2[1], t2[2]);
319
320 int returnValue = vtkTriangle::TrianglesIntersect(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
321
322 if (returnValue != VTK_NO_INTERSECTION)
323 {
324 std::cout << "Triangle " << TriangleToString(t1[0], t1[1], t1[2]) << std::endl;
325 std::cout << " intersects " << TriangleToString(t2[0], t2[1], t2[2]) << " and shouldn't."
326 << std::endl;
327 #ifdef VISUAL_DEBUG
328 DrawTriangles(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
329 #endif
330 return EXIT_FAILURE;
331 }
332 }
333
334 return EXIT_SUCCESS;
335 }
336
ProjectAlongRay(vtkRandom * seq,double * x0,double * x1,double * p)337 void ProjectAlongRay(vtkRandom* seq, double* x0, double* x1, double* p)
338 {
339 // Assign point p a value along the ray originating at x0 and passing through
340 // x1. The resulting line segment (x0, p) will cross through x1.
341
342 double n[3];
343 vtkMath::Subtract(x1, x0, n);
344 vtkMath::Normalize(n);
345
346 seq->Next();
347 double len = seq->GetValue();
348 for (int i = 0; i < 3; i++)
349 {
350 p[i] = x1[i] + len * n[i];
351 }
352 }
353
GenerateOverlappingSegments(vtkRandom * seq,double * p1,double * p2,double * x1,double * x2,double * y1,double * y2)354 void GenerateOverlappingSegments(
355 vtkRandom* seq, double* p1, double* p2, double* x1, double* x2, double* y1, double* y2)
356 {
357 // Given a line through (p1,p2), generate line segments (x1,x2) and (y1,y2)
358 // that lie on the line and overlap.
359
360 std::vector<double> random(4, 0.);
361 for (int i = 0; i < 4; i++)
362 {
363 seq->Next();
364 random[i] = seq->GetValue();
365 }
366 std::sort(random.begin(), random.end());
367
368 seq->Next();
369 double sequence = seq->GetValue();
370
371 double par[4]; // parametric values for x1,x2,y1,y2
372
373 if (sequence < .25)
374 {
375 par[0] = random[0];
376 par[1] = random[2];
377 par[2] = random[1];
378 par[3] = random[3];
379 }
380 else if (sequence < .5)
381 {
382 par[0] = random[2];
383 par[1] = random[0];
384 par[2] = random[3];
385 par[3] = random[1];
386 }
387 else if (sequence < .75)
388 {
389 par[0] = random[0];
390 par[1] = random[3];
391 par[2] = random[1];
392 par[3] = random[2];
393 }
394 else
395 {
396 par[0] = random[1];
397 par[1] = random[2];
398 par[2] = random[0];
399 par[3] = random[3];
400 }
401
402 for (int i = 0; i < 3; i++)
403 {
404 x1[i] = p1[i] + par[0] * p2[i];
405 x2[i] = p1[i] + par[1] * p2[i];
406 y1[i] = p1[i] + par[2] * p2[i];
407 y2[i] = p1[i] + par[3] * p2[i];
408 }
409 }
410
RandomPoint(vtkRandom * seq,double * p)411 void RandomPoint(vtkRandom* seq, double* p)
412 {
413 // Set p to be a random point in the box (-1,1) x (-1,1) x (-1,1).
414 for (int i = 0; i < 3; i++)
415 {
416 seq->Next();
417 p[i] = -1. + 2. * seq->GetValue();
418 }
419 }
420
TestPositiveResult(vtkRandom * seq,unsigned nTests)421 int TestPositiveResult(vtkRandom* seq, unsigned nTests)
422 {
423 double p1[3], p2[3], l1[2][3], l2[2][3], t1[3][3], t2[3][3];
424
425 for (unsigned test = 0; test < nTests; test++)
426 {
427 RandomPoint(seq, p1);
428 RandomPoint(seq, p2);
429 RandomPoint(seq, t1[0]);
430 RandomPoint(seq, t2[0]);
431
432 GenerateOverlappingSegments(seq, p1, p2, l1[0], l1[1], l2[0], l2[1]);
433
434 ProjectAlongRay(seq, t1[0], l1[0], t1[1]);
435 ProjectAlongRay(seq, t1[0], l1[1], t1[2]);
436 ProjectAlongRay(seq, t2[0], l2[0], t2[1]);
437 ProjectAlongRay(seq, t2[0], l2[1], t2[2]);
438
439 int returnValue = vtkTriangle::TrianglesIntersect(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
440
441 if (returnValue != VTK_YES_INTERSECTION)
442 {
443 std::cout << "Triangle " << TriangleToString(t1[0], t1[1], t1[2]) << std::endl;
444 std::cout << " does not intersect " << TriangleToString(t2[0], t2[1], t2[2]) << " and should."
445 << std::endl;
446 #ifdef VISUAL_DEBUG
447 DrawTriangles(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
448 #endif
449 return EXIT_FAILURE;
450 }
451 }
452
453 return EXIT_SUCCESS;
454 }
455
TestCoplanarPositiveResult(vtkRandom * seq,unsigned nTests)456 int TestCoplanarPositiveResult(vtkRandom* seq, unsigned nTests)
457 {
458 double p1[3], p2[3], l1[2][3], l2[2][3], t1[3][3], t2[3][3], orgn[3], n[3];
459 double v1[3], v2[3];
460
461 for (unsigned test = 0; test < nTests; test++)
462 {
463 RandomPoint(seq, p1);
464 RandomPoint(seq, p2);
465 RandomPoint(seq, t1[0]);
466 RandomPoint(seq, t2[0]);
467
468 GenerateOverlappingSegments(seq, p1, p2, l1[0], l1[1], l2[0], l2[1]);
469
470 ProjectAlongRay(seq, t1[0], l1[0], t1[1]);
471 ProjectAlongRay(seq, t1[0], l1[1], t1[2]);
472 ProjectAlongRay(seq, t2[0], l2[0], t2[1]);
473 ProjectAlongRay(seq, t2[0], l2[1], t2[2]);
474
475 RandomPoint(seq, orgn);
476
477 if (vtkTriangle::TriangleArea(t1[0], t1[1], t1[2]) <
478 vtkTriangle::TriangleArea(t2[0], t2[1], t2[2]))
479 {
480 for (unsigned i = 0; i < 3; i++)
481 {
482 v1[i] = t1[1][i] - t1[0][i];
483 v2[i] = t1[2][i] - t1[0][i];
484 }
485 vtkMath::Cross(v1, v2, n);
486 }
487 else
488 {
489 for (unsigned i = 0; i < 3; i++)
490 {
491 v1[i] = t2[1][i] - t2[0][i];
492 v2[i] = t2[2][i] - t2[0][i];
493 }
494 vtkMath::Cross(v1, v2, n);
495 }
496 vtkMath::Normalize(n);
497
498 for (unsigned i = 0; i < 3; i++)
499 {
500 ProjectPointOntoPlane(orgn, n, t1[i]);
501 ProjectPointOntoPlane(orgn, n, t2[i]);
502 }
503
504 int returnValue = vtkTriangle::TrianglesIntersect(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
505
506 if (returnValue != VTK_YES_INTERSECTION)
507 {
508 std::cout << "Triangle " << TriangleToString(t1[0], t1[1], t1[2]) << std::endl;
509 std::cout << " does not intersect " << TriangleToString(t2[0], t2[1], t2[2]) << " and should."
510 << std::endl;
511 return EXIT_FAILURE;
512 }
513 }
514
515 return EXIT_SUCCESS;
516 }
517
factorial(int n)518 int factorial(int n)
519 {
520 return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
521 }
522
TestReciprocalResult(vtkRandom * seq,unsigned nTests)523 int TestReciprocalResult(vtkRandom* seq, unsigned nTests)
524 {
525 std::array<std::array<double, 3>, 6> p;
526
527 nTests /= factorial(6);
528
529 for (unsigned test = 0; test < nTests; test++)
530 {
531 for (int i = 0; i < 6; i++)
532 {
533 RandomPoint(seq, &p[i][0]);
534 }
535 std::sort(std::begin(p), std::end(p));
536 do
537 {
538 int returnValue1 =
539 vtkTriangle::TrianglesIntersect(&p[0][0], &p[1][0], &p[2][0], &p[3][0], &p[4][0], &p[5][0]);
540 int returnValue2 =
541 vtkTriangle::TrianglesIntersect(&p[3][0], &p[4][0], &p[5][0], &p[0][0], &p[1][0], &p[2][0]);
542
543 if (returnValue1 != returnValue2)
544 {
545 std::cout << "Triangles " << TriangleToString(&p[0][0], &p[1][0], &p[2][0]) << " and "
546 << TriangleToString(&p[3][0], &p[4][0], &p[5][0])
547 << " disagree about intersection." << std::endl;
548 std::cout << "return values: " << returnValue1 << " " << returnValue2 << std::endl;
549 #ifdef VISUAL_DEBUG
550 DrawTriangles(&p[0][0], &p[1][0], &p[2][0], &p[3][0], &p[4][0], &p[5][0]);
551 #endif
552 return EXIT_FAILURE;
553 }
554 } while (std::next_permutation(std::begin(p), std::end(p)));
555 }
556
557 return EXIT_SUCCESS;
558 }
559
TestIssue17092()560 int TestIssue17092()
561 {
562 // An instance where triangle intersection failed was reported here:
563 // https://gitlab.kitware.com/vtk/vtk/-/issues/17092. It was fixed here:
564 // https://gitlab.kitware.com/vtk/vtk/-/merge_requests/3886
565
566 double t1[3][3] = { { 0., 0., 0. }, { 5., 0., 0. }, { 0., 5., 0. } };
567 double t2[3][3] = { { 10., 5., 0. }, { 5., 10., 0. }, { 1., 1., 0. } };
568
569 int returnValue = vtkTriangle::TrianglesIntersect(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
570
571 if (returnValue != VTK_YES_INTERSECTION)
572 {
573 std::cout << "Triangle " << TriangleToString(t1[0], t1[1], t1[2]) << std::endl;
574 std::cout << " does not intersect " << TriangleToString(t2[0], t2[1], t2[2]) << " and should."
575 << std::endl;
576 return EXIT_FAILURE;
577 }
578
579 return EXIT_SUCCESS;
580 }
581
TestMR4529()582 int TestMR4529()
583 {
584 // An instance where triangle intersection failed (along with its fix) was
585 // reported here: https://gitlab.kitware.com/vtk/vtk/-/merge_requests/4529
586
587 double t1[3][3] = { { 1.751, -.993, 0. }, { -3.021, 2.885, 0. }, { 4.14, -4.025, 0. } };
588 double t2[3][3] = { { 1.751, -.5, 0. }, { 1.751, 1.326, 0. }, { -3.382, 2.276, 0. } };
589
590 int returnValue = vtkTriangle::TrianglesIntersect(t1[0], t1[1], t1[2], t2[0], t2[1], t2[2]);
591
592 if (returnValue != VTK_YES_INTERSECTION)
593 {
594 std::cout << "Triangle " << TriangleToString(t1[0], t1[1], t1[2]) << std::endl;
595 std::cout << " does not intersect " << TriangleToString(t2[0], t2[1], t2[2]) << " and should."
596 << std::endl;
597 return EXIT_FAILURE;
598 }
599
600 return EXIT_SUCCESS;
601 }
602
TestTriangleIntersection(vtkRandom * seq,unsigned nTests)603 int TestTriangleIntersection(vtkRandom* seq, unsigned nTests)
604 {
605 if (TestPositiveResult(seq, nTests) == EXIT_FAILURE)
606 {
607 return EXIT_FAILURE;
608 }
609 if (TestNegativeResult(seq, nTests) == EXIT_FAILURE)
610 {
611 return EXIT_FAILURE;
612 }
613 if (TestCoplanarPositiveResult(seq, nTests) == EXIT_FAILURE)
614 {
615 return EXIT_FAILURE;
616 }
617 if (TestCoplanarNegativeResult(seq, nTests) == EXIT_FAILURE)
618 {
619 return EXIT_FAILURE;
620 }
621 if (TestReciprocalResult(seq, nTests) == EXIT_FAILURE)
622 {
623 return EXIT_FAILURE;
624 }
625 if (TestIssue17092() == EXIT_FAILURE)
626 {
627 return EXIT_FAILURE;
628 }
629 if (TestMR4529() == EXIT_FAILURE)
630 {
631 return EXIT_FAILURE;
632 }
633 return EXIT_SUCCESS;
634 }
635 }
636
UnitTestTriangleIntersection(int,char * [])637 int UnitTestTriangleIntersection(int, char*[])
638 {
639 vtkRandom* sequence = vtkRandom::New();
640
641 sequence->SetSeed(2);
642
643 const unsigned nTest = 1.e5;
644
645 std::cout << "Testing vtkTriangle::TriangleIntersection" << std::endl;
646 if (TestTriangleIntersection(sequence, nTest) == EXIT_FAILURE)
647 {
648 return EXIT_FAILURE;
649 }
650
651 sequence->Delete();
652 return EXIT_SUCCESS;
653 }
654