/*========================================================================= Program: Visualization Toolkit Module: UnitTestTriangleIntersection.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include #include #include #include #include "vtkMinimalStandardRandomSequence.h" #include "vtkLine.h" #include "vtkMath.h" #include "vtkSmartPointer.h" #include "vtkTriangle.h" #define VISUAL_DEBUG 0 #ifdef VISUAL_DEBUG #include #include #include #include #include #include #include #include #include #include namespace { void DrawTriangles(double* p1, double* q1, double* r1, double* p2, double* q2, double* r2) { // Create a triangle vtkSmartPointer points = vtkSmartPointer::New(); vtkIdType pid[6]; pid[0] = points->InsertNextPoint ( p1[0], p1[1], p1[2] ); pid[1] = points->InsertNextPoint ( q1[0], q1[1], q1[2] ); pid[2] = points->InsertNextPoint ( r1[0], r1[1], r1[2] ); pid[3] = points->InsertNextPoint ( p2[0], p2[1], p2[2] ); pid[4] = points->InsertNextPoint ( q2[0], q2[1], q2[2] ); pid[5] = points->InsertNextPoint ( r2[0], r2[1], r2[2] ); vtkSmartPointer verts = vtkSmartPointer::New(); for (int i=0;i<6;i++) { verts->InsertNextCell ( 1, &pid[i] ); } vtkSmartPointer triangle1 = vtkSmartPointer::New(); triangle1->GetPointIds()->SetId ( 0, 0 ); triangle1->GetPointIds()->SetId ( 1, 1 ); triangle1->GetPointIds()->SetId ( 2, 2 ); vtkSmartPointer triangle2 = vtkSmartPointer::New(); triangle2->GetPointIds()->SetId ( 0, 3 ); triangle2->GetPointIds()->SetId ( 1, 4 ); triangle2->GetPointIds()->SetId ( 2, 5 ); vtkSmartPointer triangles = vtkSmartPointer::New(); triangles->InsertNextCell ( triangle1 ); triangles->InsertNextCell ( triangle2 ); vtkSmartPointer pointIds = vtkSmartPointer::New(); pointIds->SetNumberOfTuples(6); pointIds->SetTuple1(0,0.); pointIds->SetTuple1(1,1.); pointIds->SetTuple1(2,2.); pointIds->SetTuple1(3,3.); pointIds->SetTuple1(4,4.); pointIds->SetTuple1(5,5.); // Create a polydata object vtkSmartPointer trianglePolyData = vtkSmartPointer::New(); // Add the geometry and topology to the polydata trianglePolyData->SetPoints ( points ); trianglePolyData->SetVerts ( verts ); trianglePolyData->SetPolys ( triangles ); trianglePolyData->GetPointData()->SetScalars( pointIds ); // Create mapper and actor vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputData(trianglePolyData); mapper->SetScalarRange(0.,5.); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); actor->GetProperty()->SetPointSize(5); // Create a renderer, render window, and an interactor vtkSmartPointer renderer = vtkSmartPointer::New(); vtkSmartPointer renderWindow = vtkSmartPointer::New(); renderWindow->AddRenderer(renderer); vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); renderWindowInteractor->SetRenderWindow(renderWindow); // Add the actors to the scene renderer->AddActor(actor); renderer->SetBackground(.1, .2, .4); // Background color dark blue // Render and interact renderWindow->Render(); renderWindowInteractor->Start(); } } #endif namespace { static const double EPSILON = 1.e-6; static const int VTK_NO_INTERSECTION=0; static const int VTK_YES_INTERSECTION=1; typedef vtkMinimalStandardRandomSequence vtkRandom; std::string TriangleToString(double* t1,double* t2,double* t3) { std::stringstream stream; stream << "("<Next(); p[i] = -1. + 2.*seq->GetValue(); } ProjectPointOntoPlane(o,n,p); } void ReflectPointThroughPlane(double* o, double* n, double* p) { // Reflect point p through a plane that crosses through point o and has normal // n. double dot = 0.; for (int i=0;i<3;i++) { dot += (p[i] - o[i])*n[i]; } for (int i=0;i<3;i++) { p[i] -= dot*n[i]; } } void GeneratePointInHalfPlane(vtkRandom* seq, double* o, double* n, double* o2, double* n2, double* p) { // Generate a point p that lies in a plane that crosses through point o, has // normal n, and lies on the positive side of the halfspace defined by point // o1 and normal n2. GeneratePointInPlane( seq, o, n, p ); double pMinuso2[3]; vtkMath::Subtract( p, o2, pMinuso2 ); if ( vtkMath::Dot( n2, pMinuso2 ) < 0. ) { ReflectPointThroughPlane( o2, n2, p ); } } void GenerateTriangleInPlane(vtkRandom* seq, double* o, double* n, double* t1, double* t2, double* t3) { do { GeneratePointInPlane( seq, o, n, t1 ); GeneratePointInPlane( seq, o, n, t2 ); GeneratePointInPlane( seq, o, n, t3 ); } while ( vtkTriangle::TriangleArea( t1, t2, t3 ) < EPSILON ); } void GenerateTriangleInHalfPlane(vtkRandom* seq, double* o, double* n, double* o2, double* n2, double* t1, double* t2, double* t3) { do { GeneratePointInHalfPlane( seq, o, n, o2, n2, t1 ); GeneratePointInHalfPlane( seq, o, n, o2, n2, t2 ); GeneratePointInHalfPlane( seq, o, n, o2, n2, t3 ); } while ( vtkTriangle::TriangleArea( t1, t2, t3 ) < EPSILON ); } void RandomSphere(vtkRandom* seq, const double radius, const double* offset, double* value) { // Generate a point on a sphere. seq->Next(); double theta = 2.*vtkMath::Pi()*seq->GetValue(); seq->Next(); double phi = vtkMath::Pi()*seq->GetValue(); value[0] = radius*cos(theta)*sin(phi) + offset[0]; value[1] = radius*sin(theta)*sin(phi) + offset[1]; value[2] = radius*cos(phi) + offset[2]; } int TestNegativeResult(vtkRandom* seq, unsigned nTests) { double origin[3] = {0.,0.,0.}; double n1[3], n2[3], o1[3], t1[3][3], t2[3][3]; for (unsigned test=0;testNext(); o1[i] = seq->GetValue(); } GenerateTriangleInPlane( seq, o1, n1, t1[0], t1[1], t1[2]); double dividingPlaneOrigin[3]; for (int i=0;i<3;i++) { dividingPlaneOrigin[i] = t1[0][i] + EPSILON*n1[i]; } GenerateTriangleInHalfPlane( seq, o1, n2, dividingPlaneOrigin, n1, t2[0], t2[1], t2[2]); int returnValue = vtkTriangle::TrianglesIntersect( t1[0], t1[1], t1[2], t2[0], t2[1], t2[2] ); if (returnValue != VTK_NO_INTERSECTION) { std::cout<<"Triangle "<Next(); o1[i] = seq->GetValue(); } o1[0] = o1[1] = o1[2] = 1.; GeneratePointInPlane( seq, o1, n1, o2 ); o2[0] = o2[1] = 0.; o2[2] = 1.; double dividingPlaneOrigin[3]; for (int i=0;i<3;i++) { dividingPlaneOrigin[i] = o2[i] + 10000.*EPSILON*nn2[i]; } GenerateTriangleInHalfPlane( seq, o1, n1, o2, n2, t1[0], t1[1], t1[2]); GenerateTriangleInHalfPlane( seq, o1, n1, dividingPlaneOrigin, nn2, t2[0], t2[1], t2[2]); int returnValue = vtkTriangle::TrianglesIntersect( t1[0], t1[1], t1[2], t2[0], t2[1], t2[2] ); if (returnValue != VTK_NO_INTERSECTION) { std::cout<<"Triangle "<Next(); double len = seq->GetValue(); for (int i=0;i<3;i++) { p[i] = x1[i] + len*n[i]; } } void GenerateOverlappingSegments(vtkRandom* seq, double* p1, double* p2, double* x1, double* x2, double* y1, double* y2) { // Given a line through (p1,p2), generate line segments (x1,x2) and (y1,y2) // that lie on the line and overlap. std::vector random( 4, 0. ); for (int i=0;i<4;i++) { seq->Next(); random[i] = seq->GetValue(); } std::sort( random.begin(), random.end() ); seq->Next(); double sequence = seq->GetValue(); double par[4]; // parametric values for x1,x2,y1,y2 if (sequence < .25) { par[0] = random[0]; par[1] = random[2]; par[2] = random[1]; par[3] = random[3]; } else if (sequence < .5) { par[0] = random[2]; par[1] = random[0]; par[2] = random[3]; par[3] = random[1]; } else if (sequence < .75) { par[0] = random[0]; par[1] = random[3]; par[2] = random[1]; par[3] = random[2]; } else { par[0] = random[1]; par[1] = random[2]; par[2] = random[0]; par[3] = random[3]; } for (int i=0;i<3;i++) { x1[i] = p1[i] + par[0]*p2[i]; x2[i] = p1[i] + par[1]*p2[i]; y1[i] = p1[i] + par[2]*p2[i]; y2[i] = p1[i] + par[3]*p2[i]; } } void RandomPoint(vtkRandom* seq, double* p) { // Set p to be a random point in the box (-1,1) x (-1,1) x (-1,1). for (int i=0;i<3;i++) { seq->Next(); p[i] = -1. + 2.*seq->GetValue(); } } int TestPositiveResult( vtkRandom* seq, unsigned nTests) { double p1[3], p2[3], l1[2][3], l2[2][3], t1[3][3], t2[3][3]; for (unsigned test=0;test,6> p; nTests /= factorial(6); for (unsigned test=0;testSetSeed(2); const unsigned nTest = 1.e5; std::cout<<"Testing vtkTriangle::TriangleIntersection"<Delete(); return EXIT_SUCCESS; }