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