core/vgl/vgl_triangle_3d.cxx
Go to the documentation of this file.
00001 #include "vgl_triangle_3d.h"
00002 //:
00003 // \file
00004 // \brief Some helpful functions when working with triangles
00005 // \author Kieran O'Mahony
00006 // \date 21 June 2007
00007 
00008 #include <vcl_limits.h>
00009 #include <vgl/vgl_distance.h>
00010 #include <vgl/vgl_intersection.h>
00011 #include <vgl/vgl_line_3d_2_points.h>
00012 #include <vgl/vgl_plane_3d.h>
00013 #include <vgl/vgl_point_3d.h>
00014 #include <vgl/vgl_vector_3d.h>
00015 #include <vgl/vgl_closest_point.h>
00016 
00017 
00018 // Define a file-scope vgl_nan constant
00019 static const double vgl_nan = vcl_sqrt(-1.0);
00020 static const double sqrteps = vcl_sqrt(vcl_numeric_limits<double>::epsilon());
00021 static const double pi = 3.14159265358979323846;
00022 
00023 //=======================================================================
00024 //: Check for coincident edges of triangles a and b
00025 //  \return a vector of the coincident edges
00026 vcl_vector<vcl_pair<unsigned,unsigned> > vgl_triangle_3d_coincident_edges(
00027   const vgl_point_3d<double>& a_p1,
00028   const vgl_point_3d<double>& a_p2,
00029   const vgl_point_3d<double>& a_p3,
00030   const vgl_point_3d<double>& b_p1,
00031   const vgl_point_3d<double>& b_p2,
00032   const vgl_point_3d<double>& b_p3)
00033 {
00034   vcl_vector<vcl_pair<unsigned,unsigned> > coinc_edges;
00035 
00036   //create some convenient arrays for looping
00037   vgl_point_3d<double> a[3] = {a_p1, a_p2, a_p3};
00038   vgl_point_3d<double> b[3] = {b_p1, b_p2, b_p3};
00039   vcl_pair<unsigned,unsigned> e[3] = { vcl_make_pair(0,1),
00040                                        vcl_make_pair(1,2),
00041                                        vcl_make_pair(2,0) };
00042 
00043   // Test each edge j of triangle a against each edge i of triangle b.
00044   for (unsigned j = 0; j < 3; ++j)
00045   {
00046     for (unsigned i = 0; i < 3; ++i)
00047     {
00048       //check if one edge is entirely contained within the other and vice versa
00049 
00050       double e1_len = length(a[e[j].first] - a[e[j].second]);
00051       double b1_dist = length(a[e[j].first] - b[e[i].first]) +
00052         length(a[e[j].second] - b[e[i].first]);
00053       double b2_dist = length(a[e[j].first] - b[e[i].second]) +
00054         length(a[e[j].second] - b[e[i].second]);
00055 
00056       double e2_len = length(b[e[i].first] - b[e[i].second]);
00057       double a1_dist = length(b[e[i].first] - a[e[j].first]) +
00058         length(b[e[i].second] - a[e[j].first]);
00059       double a2_dist = length(b[e[i].first] - a[e[j].second]) +
00060         length(b[e[i].second] - a[e[j].second]);
00061 
00062       if ((vcl_fabs(e1_len - b1_dist) < sqrteps &&
00063            vcl_fabs(e1_len - b2_dist) < sqrteps) ||
00064           (vcl_fabs(e2_len - a1_dist) < sqrteps &&
00065            vcl_fabs(e2_len - a2_dist) < sqrteps))
00066       {
00067         coinc_edges.push_back(vcl_make_pair(j,i));
00068         break;
00069       }
00070     }
00071   }
00072 
00073   return coinc_edges;
00074 }
00075 
00076 //=======================================================================
00077 //: Check if the given point is inside the triangle
00078 //  The triangle is represented by its vertices \a p1, \a p2, \a p3
00079 //  \return true if point is inside
00080 bool vgl_triangle_3d_test_inside(const vgl_point_3d<double>& i_pnt,
00081                                  const vgl_point_3d<double>& p1,
00082                                  const vgl_point_3d<double>& p2,
00083                                  const vgl_point_3d<double>& p3 )
00084 {
00085   //firstly perform some degeracy checks
00086   if (collinear(p1,p2,p3))
00087   { //the triangle is degenerate - its vertices are collinear
00088 
00089     if (p1==p2&&p2==p3&&p1==p3)
00090     { //all its vertices are the same
00091       return i_pnt == p1;
00092     }
00093 
00094     return vgl_line_segment_3d<double>(p1,p2).contains(i_pnt) ||
00095            vgl_line_segment_3d<double>(p2,p3).contains(i_pnt) ||
00096            vgl_line_segment_3d<double>(p1,p3).contains(i_pnt);
00097   }
00098 
00099   // use badouel's algorithm ( a barycentric method)
00100   // based on the code & paper found at http://jgt.akpeters.com/papers/MollerTrumbore97/
00101 
00102   // Project to 2d plane, to avoid a degenerate result get
00103   // the plane normal and identify the largest (abs) x,y or z component
00104   vgl_plane_3d<double> plane(p1,p2,p3);
00105 
00106   //the point needs to be in the triangles plane
00107   if (vcl_fabs(vgl_distance(plane,i_pnt)) > sqrteps)
00108     return false;
00109 
00110   vgl_vector_3d<double> norm = plane.normal();
00111   norm.set(vcl_fabs(norm.x()),vcl_fabs(norm.y()),vcl_fabs(norm.z()));
00112 
00113   unsigned i1 = 0; // Default is z.
00114   unsigned i2 = 1;
00115   if (norm.y()>=norm.x() && norm.y()>=norm.z())
00116   {
00117     i2 = 2; // Max component is y
00118   }
00119   else if (norm.x()>=norm.y() && norm.x()>=norm.z())
00120   {
00121     i1 = 2; // Max component is x
00122   }
00123 
00124   double point[3] = {i_pnt.x(), i_pnt.y(), i_pnt.z()};
00125   double vert0[3] = {p1.x(), p1.y(), p1.z()};
00126   double vert1[3] = {p2.x(), p2.y(), p2.z()};
00127   double vert2[3] = {p3.x(), p3.y(), p3.z()};
00128 
00129   double beta = 0.0;
00130   double alpha = 0.0;
00131 
00132   //compute the barycentric vectors....& ignore numerical roundoff errors
00133   double u0 = (vcl_fabs(point[i1]) < sqrteps ? 0 : point[i1]) - (vcl_fabs(vert0[i1]) < sqrteps ? 0 : vert0[i1]);
00134   double v0 = (vcl_fabs(point[i2]) < sqrteps ? 0 : point[i2]) - (vcl_fabs(vert0[i2]) < sqrteps ? 0 : vert0[i2]);
00135 
00136   double u1 = (vcl_fabs(vert1[i1]) < sqrteps ? 0 : vert1[i1]) - (vcl_fabs(vert0[i1]) < sqrteps ? 0 : vert0[i1]);
00137   double u2 = (vcl_fabs(vert2[i1]) < sqrteps ? 0 : vert2[i1]) - (vcl_fabs(vert0[i1]) < sqrteps ? 0 : vert0[i1]);
00138   double v1 = (vcl_fabs(vert1[i2]) < sqrteps ? 0 : vert1[i2]) - (vcl_fabs(vert0[i2]) < sqrteps ? 0 : vert0[i2]);
00139   double v2 = (vcl_fabs(vert2[i2]) < sqrteps ? 0 : vert2[i2]) - (vcl_fabs(vert0[i2]) < sqrteps ? 0 : vert0[i2]);
00140 
00141   // calculate and compare barycentric coordinates
00142   if (u1 == 0)
00143   {    // uncommon case
00144     beta = u0 / u2;
00145     if (beta < -sqrteps/*0*/ || beta > 1+sqrteps)
00146       return false;
00147     alpha = (v0 - beta * v2) / v1;
00148   }
00149   else
00150   {      // common case
00151     beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
00152     if (beta < -sqrteps/*0*/ || beta > 1+sqrteps)
00153       return false;
00154     alpha = (u0 - beta * u2) / u1;
00155   }
00156 
00157   return alpha        >=    -sqrteps /*0*/
00158       && alpha + beta <= 1.0+sqrteps;
00159 }
00160 
00161 //=======================================================================
00162 //: Check if point \a i_pnt is inside the triangle
00163 //  The triangle is represented by its vertices \a p1, \a p2, \a p3
00164 //  \return true if point is inside
00165 //
00166 //  \note this method uses the less efficient 'angles' method which requires 3 calls to acos()
00167 bool vgl_triangle_3d_test_inside_simple(const vgl_point_3d<double>& i_pnt,
00168                                         const vgl_point_3d<double>& p1,
00169                                         const vgl_point_3d<double>& p2,
00170                                         const vgl_point_3d<double>& p3 )
00171 {
00172   vgl_vector_3d<double> vec1 = normalized(i_pnt - p1);
00173   vgl_vector_3d<double> vec2 = normalized(i_pnt - p2);
00174   vgl_vector_3d<double> vec3 = normalized(i_pnt - p3);
00175 
00176   double int_ang = vcl_acos(dot_product(vec1,vec2)) + vcl_acos(dot_product(vec2,vec3)) + vcl_acos(dot_product(vec3,vec1));
00177   double test_val = vcl_fabs(int_ang-(2*pi));
00178 
00179   return test_val < sqrteps;
00180 }
00181 
00182 //! Are D and E on opposite sides of the plane that touches A, B, C
00183 // \returns Skew if on same side, None if not, and Coplanar if D is on
00184 // plane ABC
00185 static vgl_triangle_3d_intersection_t same_side(
00186   const vgl_point_3d<double>& A,
00187   const vgl_point_3d<double>& B,
00188   const vgl_point_3d<double>& C,
00189   const vgl_point_3d<double>& D,
00190   const vgl_point_3d<double>& E)
00191 {
00192   vgl_vector_3d<double> b = B - A;
00193   vgl_vector_3d<double> c = C - A;
00194 
00195   vgl_vector_3d<double> n = cross_product(b, c);
00196 
00197   vgl_vector_3d<double> d = D - A;
00198   double d_dot = dot_product(d, n);
00199   vgl_vector_3d<double> e = E - A;
00200   double e_dot = dot_product(e, n);
00201 
00202   if (vcl_abs(d_dot) < vcl_sqrt(
00203                                 vcl_numeric_limits<double>::epsilon()) *
00204       vcl_max(1.0e-100, vcl_max(vcl_sqrt(A.x()*A.x()+A.y()*A.y()+A.z()*A.z()),
00205                                 vcl_sqrt(D.x()*D.x()+D.y()*D.y()+D.z()*D.z()) ) ) )
00206   {
00207     return Coplanar;
00208   }
00209 
00210   if (d_dot * e_dot >= 0)
00211     return Skew;
00212   else
00213     return None;
00214 }
00215 
00216 
00217 //=======================================================================
00218 //: Compute the intersection point between the line segment and triangle
00219 //  The triangle is represented by its vertices \a p1, \a p2, \a p3
00220 //  \return intersection type
00221 vgl_triangle_3d_intersection_t vgl_triangle_3d_line_intersection(
00222   const vgl_line_segment_3d<double>& line,
00223   const vgl_point_3d<double>& p1,
00224   const vgl_point_3d<double>& p2,
00225   const vgl_point_3d<double>& p3,
00226   vgl_point_3d<double>& i_pnt,
00227   bool ignore_coplanar/*=false*/)
00228 {
00229   vgl_point_3d<double> line_p1 = line.point1();
00230   vgl_point_3d<double> line_p2 = line.point2();
00231 
00232   // perform some degeneracy checks on the line and triangle
00233   if (line_p1 == line_p2)
00234   { //the line is degnerate - it has zero length
00235     if (!ignore_coplanar && vgl_triangle_3d_test_inside(line_p1,p1,p2,p3))
00236       return Coplanar;
00237 
00238     return None;
00239   }
00240 
00241   if (collinear(p1,p2,p3))
00242   { //the triangle is degenerate - it's points are collinear
00243     if (p1==p2&&p2==p3&&p1==p3)
00244     { //all its vertices are the same
00245       return !ignore_coplanar && line.contains(p1) ? Coplanar : None;
00246     }
00247 
00248     vgl_line_3d_2_points<double> i_line(line_p1,line_p2);
00249     if ( !ignore_coplanar && (
00250         ( p1!=p2 && concurrent(vgl_line_3d_2_points<double>(p1,p2), i_line) &&
00251           vgl_intersection(line,vgl_line_segment_3d<double>(p1,p2),i_pnt) ) ||
00252         ( p2!=p3 && concurrent(vgl_line_3d_2_points<double>(p2,p3), i_line) &&
00253           vgl_intersection(line,vgl_line_segment_3d<double>(p2,p3),i_pnt) ) ||
00254         ( p1!=p3 && concurrent(vgl_line_3d_2_points<double>(p1,p3), i_line) &&
00255           vgl_intersection(line,vgl_line_segment_3d<double>(p1,p3),i_pnt) ) ) )
00256     {
00257       return Coplanar;
00258     }
00259 
00260     return None;
00261   }
00262 
00263   vgl_triangle_3d_intersection_t rv1 = same_side(line.point1(), p1, p2, p3, line.point2());
00264   if (rv1 == None) return None;
00265 
00266   vgl_triangle_3d_intersection_t rv2 = same_side(line.point1(), p2, p3, p1, line.point2());
00267   if (rv2 == None) return None;
00268 
00269   vgl_triangle_3d_intersection_t rv3 = same_side(line.point1(), p3, p1, p2, line.point2());
00270   if (rv3 == None) return None;
00271 
00272   if (rv1 == Coplanar || rv2 == Coplanar || rv3==Coplanar)
00273   {
00274     if (ignore_coplanar)
00275       return None;
00276     //coplanar line - uncommon case
00277 
00278     //check each triangle edge.
00279     //behaviour is to return the first found intersetion point
00280     vgl_line_3d_2_points<double> i_line(line_p1,line_p2);
00281     vgl_line_segment_3d<double> edge1(p1,p2);
00282 
00283     vgl_point_3d<double> test_pt;
00284     if (concurrent(vgl_line_3d_2_points<double>(p1,p2),i_line) &&
00285         vgl_intersection(edge1,line,test_pt))
00286     {
00287       i_pnt = test_pt;
00288       return Coplanar;
00289     }
00290     vgl_line_segment_3d<double> edge2(p1,p3);
00291     if (concurrent(vgl_line_3d_2_points<double>(p1,p3),i_line) &&
00292         vgl_intersection(edge2,line,test_pt))
00293     {
00294       i_pnt = test_pt;
00295       return Coplanar;
00296     }
00297     vgl_line_segment_3d<double> edge3(p2,p3);
00298     if (concurrent(vgl_line_3d_2_points<double>(p2,p3),i_line) &&
00299         vgl_intersection(edge3,line,test_pt))
00300     {
00301       i_pnt = test_pt;
00302       return Coplanar;
00303     }
00304 
00305     //special case of line completely contained within the triangle
00306     if (vgl_triangle_3d_test_inside(line_p2, p1, p2, p3))
00307     {
00308       i_pnt.set(vgl_nan, vgl_nan, vgl_nan);
00309       return Coplanar;
00310     }
00311 
00312     return None;
00313   }
00314 
00315   if (same_side(p1, p2, p3, line_p1, line_p2) == Skew)
00316     return None;
00317 
00318   i_pnt = vgl_intersection(vgl_line_3d_2_points<double>(line_p1, line_p2),
00319                            vgl_plane_3d<double>(p1, p2, p3) );
00320   return Skew;
00321 }
00322 
00323 //=======================================================================
00324 //: compute the intersection line of the given triangles
00325 //  \see vgl_triangle_3d_triangle_intersection()
00326 //  \note an intesection line is not computed for a coplanar intersection
00327 vgl_triangle_3d_intersection_t vgl_triangle_3d_triangle_intersection(
00328   const vgl_point_3d<double>& a_p1,
00329   const vgl_point_3d<double>& a_p2,
00330   const vgl_point_3d<double>& a_p3,
00331   const vgl_point_3d<double>& b_p1,
00332   const vgl_point_3d<double>& b_p2,
00333   const vgl_point_3d<double>& b_p3,
00334   vgl_line_segment_3d<double>& i_line)
00335 {
00336   // triangle intersection algorithm based on code & paper
00337   // found at http://jgt.akpeters.com/papers/Moller97/
00338 
00339   //sanity check for degenerate triangles
00340   if (collinear(a_p1,a_p2,a_p3))
00341   {
00342     if (a_p1 == a_p2 && a_p2==a_p3 && a_p1 == a_p3)
00343     {
00344       if (vgl_triangle_3d_test_inside(a_p1,b_p1,b_p2,b_p3))
00345       {
00346         i_line.set(a_p1,a_p1);
00347         return Coplanar;
00348       }
00349       return None;
00350     }
00351 
00352     vgl_triangle_3d_intersection_t ret = None;
00353     vgl_point_3d<double> i_pnt;
00354     if ( ( a_p1 != a_p2 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p1,a_p2), b_p1,b_p2,b_p3,i_pnt)) != None ) ||
00355          ( a_p2 != a_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p2,a_p3), b_p1,b_p2,b_p3,i_pnt)) != None ) ||
00356          ( a_p1 != a_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p1,a_p3), b_p1,b_p2,b_p3,i_pnt)) != None ) )
00357     {
00358       i_line.set(i_pnt,i_pnt);
00359       return ret;
00360     }
00361 
00362     return None;
00363   }
00364   if (collinear(b_p1,b_p2,b_p3))
00365   {
00366     if (b_p1 == b_p2 && b_p2==b_p3 && b_p1 == b_p3)
00367     {
00368       if (vgl_triangle_3d_test_inside(b_p1,a_p1,a_p2,a_p3))
00369       {
00370         i_line.set(b_p1,b_p1);
00371         return Coplanar;
00372       }
00373       return None;
00374     }
00375 
00376     vgl_triangle_3d_intersection_t ret = None;
00377     vgl_point_3d<double> i_pnt;
00378     if ( ( b_p1 != b_p2 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(b_p1,b_p2), a_p1,a_p2,a_p3,i_pnt)) != None ) ||
00379          ( b_p2 != b_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(b_p2,b_p3), a_p1,a_p2,a_p3,i_pnt)) != None ) ||
00380          ( b_p1 != b_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(b_p1,b_p3), a_p1,a_p2,a_p3,i_pnt)) != None ) )
00381     {
00382       i_line.set(i_pnt,i_pnt);
00383       return ret;
00384     }
00385 
00386     return None;
00387   }
00388   //computing intersection of triangles a and b
00389 
00390   vgl_vector_3d<double> edge1,edge2;
00391   vgl_vector_3d<double> a_norm, b_norm, int_line;
00392   //vgl_vector_3d<double> int_line;
00393   double a_d, b_d;
00394   double d_b[3], d_a[3];
00395   double isect1[2], isect2[2];
00396   double d_b1d_b2, d_b1d_b3, d_a1d_a2, d_a1d_a3;
00397 
00398   double p_a[3];
00399   double p_b[3];
00400   bool coplanar = false;
00401 
00402   double TRI_TRI_EPS = 1000000*vcl_numeric_limits<double>::epsilon();
00403 
00404   //Firstly check if each triangle intersects
00405   // the plane of the other
00406 
00407   //construct plane equation of triangle a
00408   edge1 = a_p2 - a_p1;
00409   edge2 = a_p3 - a_p1;
00410 
00411   a_norm = normalized(cross_product(edge1, edge2));
00412   a_d = -( a_norm.x()*a_p1.x() + a_norm.y()*a_p1.y() +a_norm.z()*a_p1.z() );
00413   //vgl_plane_3d<double> a_plane(a_p1,a_p2,a_p3);
00414 
00415   // get signed distance of triangle b to triangle a's plane
00416   d_b[0] = ( a_norm.x()*b_p1.x() + a_norm.y()*b_p1.y() + a_norm.z()*b_p1.z() ) + a_d;
00417   d_b[1] = ( a_norm.x()*b_p2.x() + a_norm.y()*b_p2.y() + a_norm.z()*b_p2.z() ) + a_d;
00418   d_b[2] = ( a_norm.x()*b_p3.x() + a_norm.y()*b_p3.y() + a_norm.z()*b_p3.z() ) + a_d;
00419 #if 0
00420   d_b[0] = (a_plane.nx()*b_p1.x() + a_plane.ny()*b_p1.y() + a_plane.nz()*b_p1.z() ) + a_plane.d();
00421   d_b[1] = (a_plane.nx()*b_p2.x() + a_plane.ny()*b_p2.y() + a_plane.nz()*b_p2.z() ) + a_plane.d();
00422   d_b[2] = (a_plane.nx()*b_p3.x() + a_plane.ny()*b_p3.y() + a_plane.nz()*b_p3.z() ) + a_plane.d();
00423 #endif // 0
00424 
00425   // coplanarity robustness check
00426   if (vcl_fabs(d_b[0]) < TRI_TRI_EPS) d_b[0] = 0.0;
00427   if (vcl_fabs(d_b[1]) < TRI_TRI_EPS) d_b[1] = 0.0;
00428   if (vcl_fabs(d_b[2]) < TRI_TRI_EPS) d_b[2] = 0.0;
00429 
00430   d_b1d_b2 = d_b[0]*d_b[1];
00431   d_b1d_b3 = d_b[0]*d_b[2];
00432 
00433   // all distances same sign => no intersection
00434   if (d_b1d_b2 > 0 && d_b1d_b3 > 0)
00435   {
00436     return None;
00437   }
00438 
00439   //construct plane equation of triangle b
00440   edge1 = b_p2 - b_p1;
00441   edge2 = b_p3 - b_p1;
00442 
00443   b_norm = normalized(cross_product(edge1,edge2));
00444   b_d = -( b_norm.x()*b_p1.x() + b_norm.y()*b_p1.y() + b_norm.z()*b_p1.z() );
00445   //vgl_plane_3d<double> b_plane(b_p1,b_p2,b_p3);
00446 
00447   // get signed distance of triangle a to triangle b's plane
00448   d_a[0] = ( b_norm.x()*a_p1.x() + b_norm.y()*a_p1.y() + b_norm.z()*a_p1.z() ) + b_d;
00449   d_a[1] = ( b_norm.x()*a_p2.x() + b_norm.y()*a_p2.y() + b_norm.z()*a_p2.z() ) + b_d;
00450   d_a[2] = ( b_norm.x()*a_p3.x() + b_norm.y()*a_p3.y() + b_norm.z()*a_p3.z() ) + b_d;
00451 #if 0
00452   d_a[0] = (b_plane.nx()*a_p1.x() + b_plane.ny()*a_p1.y() + b_plane.nz()*a_p1.z() ) + b_plane.d();
00453   d_a[1] = (b_plane.nx()*a_p2.x() + b_plane.ny()*a_p2.y() + b_plane.nz()*a_p2.z() ) + b_plane.d();
00454   d_a[2] = (b_plane.nx()*a_p3.x() + b_plane.ny()*a_p3.y() + b_plane.nz()*a_p3.z() ) + b_plane.d();
00455 #endif // 0
00456 
00457   // coplanarity robustness check
00458   if (vcl_fabs(d_a[0]) < TRI_TRI_EPS) d_a[0] = 0.0;
00459   if (vcl_fabs(d_a[1]) < TRI_TRI_EPS) d_a[1] = 0.0;
00460   if (vcl_fabs(d_a[2]) < TRI_TRI_EPS) d_a[2] = 0.0;
00461 
00462   d_a1d_a2 = d_a[0]*d_a[1];
00463   d_a1d_a3 = d_a[0]*d_a[2];
00464 
00465   // all distances same sign => no intersection
00466   if (d_a1d_a2 > 0 && d_a1d_a3 > 0)
00467   {
00468     return None;
00469   }
00470 
00471   // Now know triangles contain
00472   // the line of their planes intersection.
00473   // So...compute each triangles interval of the intersection
00474   // line and determine if they overlap i.e. if the triangles intersect
00475 
00476   // compute direction of intersection line
00477   int_line = cross_product(a_norm,b_norm);
00478   //int_line = cross_product(a_plane.normal(),b_plane.normal());
00479 
00480   // largest component of int_line?
00481   // to get a simplified 2D projection
00482   int_line.set(vcl_fabs(int_line.x()),vcl_fabs(int_line.y()),vcl_fabs(int_line.z()));
00483 
00484   if (int_line.y()>=int_line.x() && int_line.y()>=int_line.z())
00485   { // Max component is y
00486     p_a[0] = a_p1.y();
00487     p_a[1] = a_p2.y();
00488     p_a[2] = a_p3.y();
00489 
00490     p_b[0] = b_p1.y();
00491     p_b[1] = b_p2.y();
00492     p_b[2] = b_p3.y();
00493   }
00494   else if (int_line.x()>=int_line.y() && int_line.x()>=int_line.z())
00495   { // Max component is x
00496     p_a[0] = a_p1.x();
00497     p_a[1] = a_p2.x();
00498     p_a[2] = a_p3.x();
00499 
00500     p_b[0] = b_p1.x();
00501     p_b[1] = b_p2.x();
00502     p_b[2] = b_p3.x();
00503   }
00504   else { // Max component is z
00505     p_a[0] = a_p1.z();
00506     p_a[1] = a_p2.z();
00507     p_a[2] = a_p3.z();
00508 
00509     p_b[0] = b_p1.z();
00510     p_b[1] = b_p2.z();
00511     p_b[2] = b_p3.z();
00512   }
00513 
00514   int a_ival[3] = {0,1,2};
00515   // compute interval for triangle a
00516   if (d_a1d_a2 > 0) //a1, a2 on same side of b's plane, a3 on the other side
00517   {
00518     a_ival[0] = 2;
00519     a_ival[1] = 0;
00520     a_ival[2] = 1;
00521   }
00522   else if (d_a1d_a3 > 0) //a1, a3 on same side of b's plane, a2 on the other side
00523   {
00524     a_ival[0] = 1;
00525     a_ival[1] = 0;
00526     a_ival[2] = 2;
00527   }
00528   else if (d_a[1]*d_a[2] > 0 || d_a[0] != 0)
00529   {
00530     a_ival[0] = 0;
00531     a_ival[1] = 1;
00532     a_ival[2] = 2;
00533   }
00534   else if (d_a[1] != 0)
00535   {
00536     a_ival[0] = 1;
00537     a_ival[1] = 0;
00538     a_ival[2] = 2;
00539   }
00540   else if (d_a[2] != 0)
00541   {
00542     a_ival[0] = 2;
00543     a_ival[1] = 0;
00544     a_ival[2] = 1;
00545   }
00546   else
00547   {
00548     // triangles are coplanar
00549     coplanar = true;
00550   }
00551 
00552   int b_ival[3] = {0,1,2};
00553   if (!coplanar)
00554   {
00555     // compute interval for triangle b
00556     if (d_b1d_b2 > 0) //b1, b2 on same side of a's plane, b3 on the other side
00557     {
00558       b_ival[0] = 2;
00559       b_ival[1] = 0;
00560       b_ival[2] = 1;
00561     }
00562     else if (d_b1d_b3 > 0) //b1, b3 on same side of a's plane, b2 on the other side
00563     {
00564       b_ival[0] = 1;
00565       b_ival[1] = 0;
00566       b_ival[2] = 2;
00567     }
00568     else if (d_b[1]*d_b[2] > 0 || d_b[0] != 0)
00569     {
00570       b_ival[0] = 0;
00571       b_ival[1] = 1;
00572       b_ival[2] = 2;
00573     }
00574     else if (d_b[1] != 0)
00575     {
00576       b_ival[0] = 1;
00577       b_ival[1] = 0;
00578       b_ival[2] = 2;
00579     }
00580     else if (d_b[2] != 0)
00581     {
00582       b_ival[0] = 2;
00583       b_ival[1] = 0;
00584       b_ival[2] = 1;
00585     }
00586     else
00587     {
00588       coplanar = true;
00589     }
00590   }
00591 
00592   //special case when triangles are coplanar
00593   if (coplanar)
00594   {
00595     //check if they intersect in their common plane
00596     vgl_point_3d<double> i_pnt1, i_pnt2, i_pnt3;
00597     bool isect1 = vgl_triangle_3d_line_intersection(
00598       vgl_line_segment_3d<double>(a_p1,a_p2), b_p1, b_p2, b_p3, i_pnt1) != None;
00599     bool isect2 = vgl_triangle_3d_line_intersection(
00600       vgl_line_segment_3d<double>(a_p2,a_p3), b_p1, b_p2, b_p3, i_pnt2) != None;
00601     bool isect3 = vgl_triangle_3d_line_intersection(
00602       vgl_line_segment_3d<double>(a_p3,a_p1), b_p1, b_p2, b_p3, i_pnt3) != None;
00603 
00604     if ( isect1 || isect2 || isect3 )
00605     {
00606       i_line.set( isect1 ? i_pnt1 : (isect2 ? i_pnt2 : i_pnt3),
00607                   isect1 && isect2 ? i_pnt2 : (isect1 || isect2) && isect3 ? i_pnt3 :
00608                   (isect1 ? i_pnt1 : (isect2 ? i_pnt2 : i_pnt3)) );
00609       return Coplanar;
00610     }
00611 
00612     // finally, test if triangle a is totally contained in triangle b or vice versa
00613     if (vgl_triangle_3d_test_inside(a_p1, b_p1, b_p2, b_p3) ||
00614         vgl_triangle_3d_test_inside(b_p1, a_p1, a_p2, a_p3))
00615     {
00616       i_line.set(vgl_point_3d<double> (vgl_nan, vgl_nan, vgl_nan),vgl_point_3d<double> (vgl_nan,vgl_nan,vgl_nan));
00617       return Coplanar;
00618     }
00619 
00620     return None;
00621   }
00622 
00623   vgl_point_3d<double> i_pnts[4];
00624   //intersection line interval for triangle a
00625   double tmp = d_a[a_ival[0]]/(d_a[a_ival[0]]-d_a[a_ival[1]]);
00626   isect1[0] = p_a[a_ival[0]] + (p_a[a_ival[1]] - p_a[a_ival[0]])*tmp;
00627   vgl_point_3d<double> a_vs[] = {a_p1,a_p2,a_p3};
00628   vgl_vector_3d<double> diff = a_vs[a_ival[1]] - a_vs[a_ival[0]];
00629   diff *= tmp;
00630   i_pnts[0] = a_vs[a_ival[0]] + diff  ;
00631 
00632   tmp = d_a[a_ival[0]]/(d_a[a_ival[0]]-d_a[a_ival[2]]);
00633   isect1[1] = p_a[a_ival[0]] + (p_a[a_ival[2]] - p_a[a_ival[0]])*tmp;
00634   diff = a_vs[a_ival[2]] - a_vs[a_ival[0]];
00635   diff *= tmp;
00636   i_pnts[1] = a_vs[a_ival[0]] + diff;
00637 
00638   //intersection line interval for triangle b
00639   tmp = d_b[b_ival[0]]/(d_b[b_ival[0]] - d_b[b_ival[1]]);
00640   isect2[0] = p_b[b_ival[0]] + (p_b[b_ival[1]] - p_b[b_ival[0]])*tmp;
00641   vgl_point_3d<double> b_vs[] = {b_p1,b_p2,b_p3};
00642   diff = b_vs[b_ival[1]] - b_vs[b_ival[0]];
00643   diff *= tmp;
00644   i_pnts[2] = b_vs[b_ival[0]] + diff ;
00645 
00646   tmp = d_b[b_ival[0]]/(d_b[b_ival[0]]-d_b[b_ival[2]]);
00647   isect2[1] = p_b[b_ival[0]] + (p_b[b_ival[2]] - p_b[b_ival[0]])*tmp;
00648   diff = b_vs[b_ival[2]] - b_vs[b_ival[0]];
00649   diff *= tmp;
00650   i_pnts[3] = b_vs[b_ival[0]] + diff;
00651 
00652   unsigned smallest1 = 0;
00653   if (isect1[0] > isect1[1])
00654   {
00655     tmp = isect1[0];
00656     isect1[0]= isect1[1];
00657     isect1[1] = tmp;
00658     smallest1 = 1;
00659   }
00660   unsigned smallest2 = 0;
00661   if (isect2[0] > isect2[1])
00662   {
00663     tmp = isect2[0];
00664     isect2[0]= isect2[1];
00665     isect2[1] = tmp;
00666     smallest2 = 1;
00667   }
00668 
00669   if (isect1[1] < isect2[0] || isect2[1] < isect1[0])
00670   {
00671     return None; //no intersection
00672   }
00673 
00674   unsigned i_pt1,i_pt2;
00675   //find the correct intersection line
00676   if (isect2[0]<isect1[0])
00677   {
00678     if (smallest1==0)
00679     {
00680       i_pt1 = 0;
00681     }
00682     else
00683     {
00684       i_pt1 = 1;
00685     }
00686 
00687     if (isect2[1]<isect1[1])
00688     {
00689       if (smallest2==0)
00690       {
00691         i_pt2 = 3;
00692       }
00693       else
00694       {
00695         i_pt2 = 2;
00696       }
00697     }
00698     else
00699     {
00700       if (smallest1==0)
00701       {
00702         i_pt2 = 1;
00703       }
00704       else
00705       {
00706         i_pt2 = 0;
00707       }
00708     }
00709   }
00710   else
00711   {
00712     if (smallest2==0)
00713     {
00714       i_pt1 = 2;
00715     }
00716     else
00717     {
00718       i_pt1 = 3;
00719     }
00720 
00721     if (isect2[1]>isect1[1])
00722     {
00723       if (smallest1==0)
00724       {
00725         i_pt2 = 1;
00726       }
00727       else
00728       {
00729         i_pt2 = 0;
00730       }
00731     }
00732     else
00733     {
00734       if (smallest2==0)
00735       {
00736         i_pt2 = 3;
00737       }
00738       else
00739       {
00740         i_pt2 = 2;
00741       }
00742     }
00743   }
00744 
00745   i_line.set(i_pnts[i_pt1],i_pnts[i_pt2]);
00746   return Skew;
00747 }
00748 
00749 //=======================================================================
00750 //: Compute if the given triangles a and b intersect
00751 //  The triangle are represented by their respective vertices \a a_p1, \a a_p2, \a a_p3
00752 //  and \a b_p1, \a b_p2, \a b_p3
00753 //  \return intersection type
00754 vgl_triangle_3d_intersection_t vgl_triangle_3d_triangle_intersection(
00755   const vgl_point_3d<double>& a_p1,
00756   const vgl_point_3d<double>& a_p2,
00757   const vgl_point_3d<double>& a_p3,
00758   const vgl_point_3d<double>& b_p1,
00759   const vgl_point_3d<double>& b_p2,
00760   const vgl_point_3d<double>& b_p3)
00761 {
00762   // triangle intersection algorithm based on code & paper
00763   // found at http://jgt.akpeters.com/papers/Moller97/
00764 
00765   //sanity check for degenerate triangles
00766   if (collinear(a_p1,a_p2,a_p3))
00767   {
00768     if (a_p1 == a_p2 && a_p2==a_p3 && a_p1 == a_p3)
00769     {
00770       if (vgl_triangle_3d_test_inside(a_p1,b_p1,b_p2,b_p3))
00771         return Coplanar;
00772       return None;
00773     }
00774 
00775     vgl_triangle_3d_intersection_t ret = None;
00776     vgl_point_3d<double> i_pnt;
00777     if ( ( a_p1 != a_p2 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p1,a_p2), b_p1,b_p2,b_p3,i_pnt)) != None ) ||
00778          ( a_p2 != a_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p2,a_p3), b_p1,b_p2,b_p3,i_pnt)) != None ) ||
00779          ( a_p1 != a_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p1,a_p3), b_p1,b_p2,b_p3,i_pnt)) != None ) )
00780       return ret;
00781 
00782     return None;
00783   }
00784   if (collinear(b_p1,b_p2,b_p3))
00785   {
00786     if (b_p1 == b_p2 && b_p2==b_p3 && b_p1 == b_p3)
00787     {
00788       if (vgl_triangle_3d_test_inside(b_p1,a_p1,a_p2,a_p3))
00789         return Coplanar;
00790       return None;
00791     }
00792 
00793     vgl_triangle_3d_intersection_t ret = None;
00794     vgl_point_3d<double> i_pnt;
00795     if ( ( b_p1 != b_p2 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(b_p1,b_p2), a_p1,a_p2,a_p3,i_pnt)) != None ) ||
00796          ( b_p2 != b_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(b_p2,b_p3), a_p1,a_p2,a_p3,i_pnt)) != None ) ||
00797          ( b_p1 != b_p3 && (ret = vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(b_p1,b_p3), a_p1,a_p2,a_p3,i_pnt)) != None ) )
00798       return ret;
00799 
00800     return None;
00801   }
00802 
00803   //computing intersection of triangles a and b
00804 
00805   vgl_vector_3d<double> edge1,edge2;
00806   vgl_vector_3d<double> a_norm, b_norm, int_line;
00807 //  vgl_vector_3d<double> int_line;
00808 
00809   double a_d, b_d;
00810   double d_b1, d_b2, d_b3, d_a1, d_a2, d_a3;
00811   double isect1[2], isect2[2];
00812   double d_b1d_b2, d_b1d_b3, d_a1d_a2, d_a1d_a3;
00813 
00814   double p_a1, p_a2, p_a3;
00815   double p_b1, p_b2, p_b3;
00816   bool coplanar = false;
00817 
00818   double a, b, c, x0, x1;
00819   double d, e, f, y0, y1;
00820   double xx, yy, xxyy, tmp;
00821   double TRI_TRI_EPS = 100000*vcl_numeric_limits<double>::epsilon();
00822 
00823   //Firstly check if each triangle intersects
00824   // the plane of the other
00825 
00826   //construct plane equation of triangle a
00827   edge1 = a_p2 - a_p1;
00828   edge2 = a_p3 - a_p1;
00829 
00830   a_norm = normalized(cross_product(edge1, edge2));
00831 
00832   a_d = -( a_norm.x()*a_p1.x() + a_norm.y()*a_p1.y() +a_norm.z()*a_p1.z() );
00833   //vgl_plane_3d<double> a_plane(a_p1,a_p2,a_p3);
00834 
00835   // get signed distance of triangle b to triangle a's plane
00836   d_b1 = ( a_norm.x()*b_p1.x() + a_norm.y()*b_p1.y() + a_norm.z()*b_p1.z() ) + a_d;
00837   d_b2 = ( a_norm.x()*b_p2.x() + a_norm.y()*b_p2.y() + a_norm.z()*b_p2.z() ) + a_d;
00838   d_b3 = ( a_norm.x()*b_p3.x() + a_norm.y()*b_p3.y() + a_norm.z()*b_p3.z() ) + a_d;
00839 #if 0
00840   d_b1 = (a_plane.nx()*b_p1.x() + a_plane.ny()*b_p1.y() + a_plane.nz()*b_p1.z() ) + a_plane.d();
00841   d_b2 = (a_plane.nx()*b_p2.x() + a_plane.ny()*b_p2.y() + a_plane.nz()*b_p2.z() ) + a_plane.d();
00842   d_b3 = (a_plane.nx()*b_p3.x() + a_plane.ny()*b_p3.y() + a_plane.nz()*b_p3.z() ) + a_plane.d();
00843 #endif // 0
00844 
00845   // coplanarity robustness check
00846   if (vcl_fabs(d_b1) < TRI_TRI_EPS) d_b1 = 0.0;
00847   if (vcl_fabs(d_b2) < TRI_TRI_EPS) d_b2 = 0.0;
00848   if (vcl_fabs(d_b3) < TRI_TRI_EPS) d_b3 = 0.0;
00849 
00850   d_b1d_b2 = d_b1*d_b2;
00851   d_b1d_b3 = d_b1*d_b3;
00852 
00853   // all distances same sign => no intersection
00854   if (d_b1d_b2 > 0 && d_b1d_b3 > 0)
00855   {
00856     return None;
00857   }
00858 
00859   //construct plane equation of triangle b
00860   edge1 = b_p2 - b_p1;
00861   edge2 = b_p3 - b_p1;
00862 
00863   b_norm = normalized(cross_product(edge1,edge2));
00864 
00865   b_d = -( b_norm.x()*b_p1.x() + b_norm.y()*b_p1.y() + b_norm.z()*b_p1.z() );
00866   //vgl_plane_3d<double> b_plane(b_p1,b_p2,b_p3);
00867 
00868   // get signed distance of triangle a to triangle b's plane
00869   d_a1 = ( b_norm.x()*a_p1.x() + b_norm.y()*a_p1.y() + b_norm.z()*a_p1.z() ) + b_d;
00870   d_a2 = ( b_norm.x()*a_p2.x() + b_norm.y()*a_p2.y() + b_norm.z()*a_p2.z() ) + b_d;
00871   d_a3 = ( b_norm.x()*a_p3.x() + b_norm.y()*a_p3.y() + b_norm.z()*a_p3.z() ) + b_d;
00872 #if 0
00873   d_a1 = (b_plane.nx()*a_p1.x() + b_plane.ny()*a_p1.y() + b_plane.nz()*a_p1.z() ) + b_plane.d();
00874   d_a2 = (b_plane.nx()*a_p2.x() + b_plane.ny()*a_p2.y() + b_plane.nz()*a_p2.z() ) + b_plane.d();
00875   d_a3 = (b_plane.nx()*a_p3.x() + b_plane.ny()*a_p3.y() + b_plane.nz()*a_p3.z() ) + b_plane.d();
00876 #endif // 0
00877 
00878   // coplanarity robustness check
00879   if (vcl_fabs(d_a1) < TRI_TRI_EPS) d_a1 = 0.0;
00880   if (vcl_fabs(d_a2) < TRI_TRI_EPS) d_a2 = 0.0;
00881   if (vcl_fabs(d_a3) < TRI_TRI_EPS) d_a3 = 0.0;
00882 
00883   d_a1d_a2 = d_a1*d_a2;
00884   d_a1d_a3 = d_a1*d_a3;
00885 
00886   // all distances same sign => no intersection
00887   if (d_a1d_a2 > 0 && d_a1d_a3 > 0)
00888   {
00889     return None;
00890   }
00891 
00892   // Now know triangles contain
00893   // the line of their planes intersection.
00894   // So...compute each triangles interval of the intersection
00895   // line and determine if they overlap i.e. if the triangles intersect
00896 
00897   // compute direction of intersection line
00898   int_line = cross_product(a_norm,b_norm);
00899   //int_line = cross_product(a_plane.normal(),b_plane.normal());
00900 
00901   // largest component of int_line?
00902   // to get a simplified 2D projection
00903   int_line.set(vcl_fabs(int_line.x()),vcl_fabs(int_line.y()),vcl_fabs(int_line.z()));
00904 
00905   if (int_line.y()>=int_line.x() && int_line.y()>=int_line.z())
00906   { // Max component is y
00907     p_a1 = a_p1.y();
00908     p_a2 = a_p2.y();
00909     p_a3 = a_p3.y();
00910 
00911     p_b1 = b_p1.y();
00912     p_b2 = b_p2.y();
00913     p_b3 = b_p3.y();
00914   }
00915   else if (int_line.x()>=int_line.y() && int_line.x()>=int_line.z())
00916   { // Max component is x
00917     p_a1 = a_p1.x();
00918     p_a2 = a_p2.x();
00919     p_a3 = a_p3.x();
00920 
00921     p_b1 = b_p1.x();
00922     p_b2 = b_p2.x();
00923     p_b3 = b_p3.x();
00924   }
00925   else { // Max component is z
00926     p_a1 = a_p1.z();
00927     p_a2 = a_p2.z();
00928     p_a3 = a_p3.z();
00929 
00930     p_b1 = b_p1.z();
00931     p_b2 = b_p2.z();
00932     p_b3 = b_p3.z();
00933   }
00934 
00935   // compute interval for triangle a
00936   if (d_a1d_a2 > 0) //a1, a2 on same side of b's plane, a3 on the other side
00937   {
00938     a = p_a3;
00939     b = (p_a1-p_a3)*d_a3;
00940     c = (p_a2-p_a3)*d_a3;
00941 
00942     x0 = d_a3-d_a1;
00943     x1 = d_a3-d_a2;
00944   }
00945   else if (d_a1d_a3 > 0) //a1, a3 on same side of b's plane, a2 on the other side
00946   {
00947     a = p_a2;
00948     b = (p_a1-p_a2)*d_a2;
00949     c = (p_a3-p_a2)*d_a2;
00950 
00951     x0 = d_a2-d_a1;
00952     x1 = d_a2-d_a3;
00953   }
00954   else if (d_a2*d_a3 > 0 || d_a1 != 0)
00955   {
00956     a = p_a1;
00957     b = (p_a2-p_a1)*d_a1;
00958     c = (p_a3-p_a1)*d_a1;
00959 
00960     x0 = d_a1-d_a2;
00961     x1 = d_a1-d_a3;
00962   }
00963   else if (d_a2 != 0)
00964   {
00965     a = p_a2;
00966     b = (p_a1-p_a2)*d_a2;
00967     c = (p_a3-p_a2)*d_a2;
00968 
00969     x0 = d_a2-d_a1;
00970     x1 = d_a2-d_a3;
00971   }
00972   else if (d_a3 != 0)
00973   {
00974     a = p_a3;
00975     b = (p_a1-p_a3)*d_a3;
00976     c = (p_a2-p_a3)*d_a3;
00977 
00978     x0 = d_a3-d_a1;
00979     x1 = d_a3-d_a2;
00980   }
00981   else
00982   {
00983     // triangles are coplanar
00984     coplanar = true;
00985   }
00986 
00987   if (!coplanar)
00988   {
00989     // compute interval for triangle b
00990     if (d_b1d_b2 > 0) //b1, b2 on same side of a's plane, b3 on the other side
00991     {
00992       d = p_b3;
00993       e = (p_b1-p_b3)*d_b3;
00994       f = (p_b2-p_b3)*d_b3;
00995 
00996       y0 = d_b3-d_b1;
00997       y1 = d_b3-d_b2;
00998     }
00999     else if (d_b1d_b3 > 0) //b1, b3 on same side of a's plane, b2 on the other side
01000     {
01001       d = p_b2;
01002       e=(p_b1-p_b2)*d_b2;
01003       f=(p_b3-p_b2)*d_b2;
01004 
01005       y0=d_b2-d_b1;
01006       y1=d_b2-d_b3;
01007     }
01008     else if (d_b2*d_b3 > 0 || d_b1 != 0)
01009     {
01010       d = p_b1;
01011       e = (p_b2-p_b1)*d_b1;
01012       f = (p_b3-p_b1)*d_b1;
01013 
01014       y0 = d_b1-d_b2;
01015       y1 = d_b1-d_b3;
01016     }
01017     else if (d_b2 != 0)
01018     {
01019       d = p_b2;
01020       e = (p_b1-p_b2)*d_b2;
01021       f = (p_b3-p_b2)*d_b2;
01022 
01023       y0 = d_b2-d_b1;
01024       y1 = d_b2-d_b3;
01025     }
01026     else if (d_b3 != 0)
01027     {
01028       d = p_b3;
01029       e = (p_b1-p_b3)*d_b3;
01030       f = (p_b2-p_b3)*d_b3;
01031 
01032       y0 = d_b3-d_b1;
01033       y1 = d_b3-d_b2;
01034     }
01035     else
01036     {
01037       coplanar = true;
01038     }
01039   }
01040 
01041   //special case when triangles are coplanar
01042   if (coplanar)
01043   {
01044     //check if they intersect in their common plane
01045     vgl_point_3d<double> i_pnt;
01046     if (vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p1,a_p2), b_p1, b_p2, b_p3, i_pnt) ||
01047         vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p2,a_p3), b_p1, b_p2, b_p3, i_pnt) ||
01048         vgl_triangle_3d_line_intersection(vgl_line_segment_3d<double>(a_p3,a_p1), b_p1, b_p2, b_p3, i_pnt) )
01049     {
01050       return Coplanar;
01051     }
01052 
01053     // finally, test if triangle a is totally contained in triangle b or vice versa
01054     if (vgl_triangle_3d_test_inside(a_p1, b_p1, b_p2, b_p3) ||
01055         vgl_triangle_3d_test_inside(b_p1, a_p1, a_p2, a_p3))
01056     {
01057       return Coplanar;
01058     }
01059 
01060     return None;
01061   }
01062 
01063   // finally, test if the triangles respective intervals
01064   // of the intersection line overlap
01065   xx = x0*x1;
01066   yy = y0*y1;
01067   xxyy = xx*yy;
01068 
01069   tmp = a*xxyy;
01070   isect1[0] = tmp+b*x1*yy;
01071   isect1[1] = tmp+c*x0*yy;
01072 
01073   tmp = d*xxyy;
01074   isect2[0] = tmp+e*xx*y1;
01075   isect2[1] = tmp+f*xx*y0;
01076 
01077   if (isect1[0] > isect1[1])
01078   {
01079     tmp = isect1[0];
01080     isect1[0] = isect1[1];
01081     isect1[1] = tmp;
01082   }
01083 
01084   if (isect2[0] > isect2[1])
01085   {
01086     tmp = isect2[0];
01087     isect2[0] = isect2[1];
01088     isect2[1] = tmp;
01089   }
01090 
01091   if (isect1[1] < isect2[0] || isect2[1] < isect1[0])
01092   {
01093     return None;
01094   }
01095 
01096   return Skew;
01097 }
01098 
01099 //=======================================================================
01100 //: Compute the line of intersection of the given triangle and plane
01101 //  The triangle is represented by its vertices \a p1, \a p2, \a p3
01102 //  \return intersection type
01103 //  \note an intersection line is not defined (vgl_vgl_nan) for a coplanar intersection
01104 vgl_triangle_3d_intersection_t vgl_triangle_3d_plane_intersection(
01105   const vgl_point_3d<double>& p1,
01106   const vgl_point_3d<double>& p2,
01107   const vgl_point_3d<double>& p3,
01108   const vgl_plane_3d<double>& i_plane,
01109   vgl_line_segment_3d<double>& i_line)
01110 {
01111   //Firstly check if the triangle actually intersects the plane
01112   // by computing the signed distance of its vertices to the plane
01113 
01114   //all we care about is the sign of the distance
01115   double p1_d = i_plane.nx()*p1.x() + i_plane.ny()*p1.y() + i_plane.nz()*p1.z() + i_plane.d();
01116   double p2_d = i_plane.nx()*p2.x() + i_plane.ny()*p2.y() + i_plane.nz()*p2.z() + i_plane.d();
01117   double p3_d = i_plane.nx()*p3.x() + i_plane.ny()*p3.y() + i_plane.nz()*p3.z() + i_plane.d();
01118 
01119   // coplanarity robustness check
01120   if (vcl_fabs(p1_d) < sqrteps) p1_d = 0.0;
01121   if (vcl_fabs(p2_d) < sqrteps) p2_d = 0.0;
01122   if (vcl_fabs(p3_d) < sqrteps) p3_d = 0.0;
01123 
01124   vgl_line_3d_2_points<double> edge;
01125 
01126   if (p1_d*p2_d > 0 && p1_d*p3_d > 0) // all distances strictly same sign => no intersection
01127   {
01128     i_line.set(vgl_point_3d<double>(),vgl_point_3d<double>());
01129     return None;
01130   }
01131   else if (p1_d == 0 && p2_d == 0 && p3_d == 0) //triangle lies in plane
01132   {
01133     vgl_point_3d<double> i_pnt1; i_pnt1.set(vgl_nan, vgl_nan, vgl_nan);
01134     i_line.set(i_pnt1,i_pnt1);
01135     return Coplanar;
01136   }
01137   else if (p1_d*p2_d > 0) //p1, p2 on same side, p3 on the other
01138   {
01139     edge.set(p1,p3);
01140     vgl_point_3d<double> i_pnt1 = vgl_intersection(edge, i_plane);
01141     edge.set(p2,p3);
01142     vgl_point_3d<double> i_pnt2 = vgl_intersection(edge, i_plane);
01143     i_line.set(i_pnt1,i_pnt2);
01144   }
01145   else if (p1_d*p3_d > 0) //p1, p3 on same side, p2 on the other
01146   {
01147     edge.set(p1,p2);
01148     vgl_point_3d<double> i_pnt1 = vgl_intersection(edge, i_plane);
01149     edge.set(p3,p2);
01150     vgl_point_3d<double> i_pnt2 = vgl_intersection(edge, i_plane);
01151     i_line.set(i_pnt1,i_pnt2);
01152   }
01153   else if (p2_d*p3_d > 0) //p2, p3 on same side, p1 on the other
01154   {
01155     edge.set(p2,p1);
01156     vgl_point_3d<double> i_pnt1 = vgl_intersection(edge, i_plane);
01157     edge.set(p3,p1);
01158     vgl_point_3d<double> i_pnt2 = vgl_intersection(edge, i_plane);
01159     i_line.set(i_pnt1,i_pnt2);
01160   }
01161   else if (p1_d == 0 && p2_d == 0) //edge p1,p2 in plane
01162   {
01163     i_line.set(p1,p2);
01164   }
01165   else if (p1_d == 0 && p3_d == 0) //edge p1,p3 in plane
01166   {
01167     i_line.set(p1,p3);
01168   }
01169   else if (p3_d == 0 && p2_d == 0) //edge p2,p3 in plane
01170   {
01171     i_line.set(p2,p3);
01172   }
01173   else if (p1_d == 0) //just p1 in plane
01174   {
01175     edge.set(p3,p2);
01176     vgl_point_3d<double> i_pnt2 = vgl_intersection(edge, i_plane);
01177     i_line.set(p1,i_pnt2);
01178   }
01179   else if (p2_d == 0) //just p2 in plane
01180   {
01181     edge.set(p3,p1);
01182     vgl_point_3d<double> i_pnt2 = vgl_intersection(edge, i_plane);
01183     i_line.set(p2,i_pnt2);
01184   }
01185   else if (p3_d == 0) //just p3 in plane
01186   {
01187     edge.set(p2,p1);
01188     vgl_point_3d<double> i_pnt2 = vgl_intersection(edge, i_plane);
01189     i_line.set(p3,i_pnt2);
01190   }
01191   return Skew;
01192 }
01193 
01194 
01195 //=======================================================================
01196 // Compute the closest point on a triangle to a reference point
01197 //=======================================================================
01198 vgl_point_3d<double> vgl_triangle_3d_closest_point(
01199   const vgl_point_3d<double>& q,
01200   const vgl_point_3d<double>& p1,
01201   const vgl_point_3d<double>& p2,
01202   const vgl_point_3d<double>& p3)
01203 {
01204   // Handle degenerate case.
01205   if (p1 == p2)
01206   {
01207     if (p2 == p3) return p3;
01208     return vgl_closest_point(vgl_line_3d_2_points<double>(p3, p1), q);
01209   }
01210   if (p2 == p3)
01211     return vgl_closest_point(vgl_line_3d_2_points<double>(p1, p2), q);
01212   if (p3 == p1)
01213     return vgl_closest_point(vgl_line_3d_2_points<double>(p2, p3), q);
01214 
01215   // Construct a plane from the 3 vertices of the triangle
01216   vgl_plane_3d<double> plane(p1,  p2, p3);
01217 
01218   // Find the closest point on the whole plane to the test point
01219   vgl_point_3d<double> cp = vgl_closest_point<double>(plane, q);
01220 
01221   // Is this closest point inside the triangle ?
01222   if (vgl_triangle_3d_test_inside(cp, p1, p2, p3))
01223   {
01224     return cp;
01225   }
01226   else
01227   {
01228     // Find the nearest point on the triangle's boundary by testing each edge
01229 
01230     // Edge 1
01231     double cp1x, cp1y, cp1z;
01232     vgl_closest_point_to_linesegment(
01233       cp1x, cp1y, cp1z,
01234       p1.x(), p1.y(), p1.z(),
01235       p2.x(), p2.y(), p2.z(),
01236       q.x(), q.y(), q.z());
01237     vgl_point_3d<double> cp1(cp1x, cp1y, cp1z);
01238     double d1 = vgl_distance(cp1, q);
01239 
01240     // Edge 2
01241     double cp2x, cp2y, cp2z;
01242     vgl_closest_point_to_linesegment(
01243       cp2x, cp2y, cp2z,
01244       p2.x(), p2.y(), p2.z(),
01245       p3.x(), p3.y(), p3.z(),
01246       q.x(), q.y(), q.z());
01247     vgl_point_3d<double> cp2(cp2x, cp2y, cp2z);
01248     double d2 = vgl_distance(cp2, q);
01249 
01250     // Edge 3
01251     double cp3x, cp3y, cp3z;
01252     vgl_closest_point_to_linesegment(
01253       cp3x, cp3y, cp3z,
01254       p1.x(), p1.y(), p1.z(),
01255       p3.x(), p3.y(), p3.z(),
01256       q.x(), q.y(), q.z());
01257     vgl_point_3d<double> cp3(cp3x, cp3y, cp3z);
01258     double d3 = vgl_distance(cp3, q);
01259 
01260     // Identify nearest edge and return closest point on that edge.
01261     if (d1<=d2 && d1<=d3)
01262       return cp1;
01263     else if (d2<=d1 && d2<=d3)
01264       return cp2;
01265     else
01266       return cp3;
01267   }
01268 }
01269 
01270 
01271 //=======================================================================
01272 // Compute the distance to the closest point on a triangle from a reference point.
01273 //=======================================================================
01274 double vgl_triangle_3d_distance(const vgl_point_3d<double>& q,
01275                                 const vgl_point_3d<double>& p1,
01276                                 const vgl_point_3d<double>& p2,
01277                                 const vgl_point_3d<double>& p3)
01278 {
01279   vgl_point_3d<double> c = vgl_triangle_3d_closest_point(q, p1, p2, p3);
01280   return vgl_distance(c, q);
01281 }
01282 
01283 //=======================================================================
01284 //: Check if the two triangles are coplanar
01285 //  The triangles are represented by their respective vertices \a a_p1, \a a_p2, \a a_p3
01286 //  and \a b_p1, \a b_p2, \a b_p3
01287 bool vgl_triangle_3d_triangle_coplanar(
01288                             const vgl_point_3d<double>& a_p1,
01289                             const vgl_point_3d<double>& a_p2,
01290                             const vgl_point_3d<double>& a_p3,
01291                             const vgl_point_3d<double>& b_p1,
01292                             const vgl_point_3d<double>& b_p2,
01293                             const vgl_point_3d<double>& b_p3)
01294 {
01295   return coplanar(a_p1,b_p1,b_p2,b_p3)
01296       && coplanar(a_p2,b_p1,b_p2,b_p3)
01297       && coplanar(a_p3,b_p1,b_p2,b_p3);
01298 }
01299 
01300 //=======================================================================
01301 //: Compute the area of a triangle
01302 //  The triangle is represented by its vertices \a p1, \a p2, \a p3
01303 double vgl_triangle_3d_area(const vgl_point_3d<double> &p0,
01304                             const vgl_point_3d<double> &p1,
01305                             const vgl_point_3d<double> &p2 )
01306 {
01307   vgl_vector_3d<double> edge_vector0;
01308   edge_vector0 = p0 - p1;
01309   vgl_vector_3d<double> edge_vector1;
01310   edge_vector1 = p0 - p2;
01311 
01312   vgl_vector_3d<double> area_vector;
01313   area_vector = cross_product( edge_vector0, edge_vector1 );
01314 
01315   double area;
01316   area = area_vector.length();
01317   area /= 2;
01318 
01319   return area;
01320 }
01321 
01322 //=======================================================================
01323 //: Compute the aspect ration of a triangle
01324 //  The triangle is represented by its vertices \a p1, \a p2, \a p3
01325 double vgl_triangle_3d_aspect_ratio(
01326   const vgl_point_3d<double> &p0,
01327   const vgl_point_3d<double> &p1,
01328   const vgl_point_3d<double> &p2 )
01329 {
01330   return vgl_triangle_3d_longest_side( p0, p1, p2 ) / vgl_triangle_3d_shortest_side( p0, p1, p2 );
01331 }
01332