Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

gfx/Triangle3.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Triangle3.cpp 1030 2004-02-11 20:46:17Z jungd $
00019   $Revision: 1.3 $
00020   $Date: 2004-02-11 15:46:17 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <math.h>
00026 
00027 #include <gfx/Triangle3>
00028 #include <gfx/Plane>
00029 
00030 using gfx::Triangle3;
00031 using gfx::Point3;
00032 using gfx::Segment3;
00033 using gfx::Plane;
00034 
00035 
00036 Real Triangle3::distanceTo(const Point3& p) const
00037 {
00038   return Vector3(p-pointClosestTo(p)).length();
00039 }
00040 
00041   
00042 // this implementation and its explanation was basically ripped from the XEngine code by Martin Ecker
00043 //  (email: martin.ecker@liwest.at - see http://xengine.sourceforge.net )
00044 // it looks a lot like the Magic Software algorithm ( http://www.magic-software.com )
00045 /*
00046         Given a point P and a triangle T(s, t) = B + s * E0 + t * E1 with s and t 
00047         in [0, 1] and s + t <= 1 we want to find the closest distance of P to T.
00048         We want to find the values (s, t) that gives us the closest point on
00049         the triangle to P. To do so we have to minimze the squared-distance function
00050                 Q(s, t) = |T - P|^2
00051         This function is quadratic in s and t and is of the form
00052                 Q(s, t) = as^2 + 2bst + ct^2 + 2ds + 2et + f
00053         with
00054                 a = E0 * E0
00055                 b = E0 * E1
00056                 c = E1 * E1
00057                 d = E0 * (B - P)
00058                 e = -E1 * (B - P)
00059                 f = (B - P) * (B - P)
00060         Quadratics are classified by the sign of the determinant 
00061                 ac - b^2 = (E0 * E0) * (E1 * E1) - (E0 * E1)^2 = |E0 x E1|^2 > 0
00062         The determinant is always > 0 since E0 and E1 are linearly independent
00063         and thus the cross product of the two vectors always yields a nonzero
00064         vector.
00065         The minimum of Q(s, t) either occurs at an interior point or at a
00066         boundary of the domain of T(s, t). So we minimize Q(s, t) by determining
00067         the gradient dQ(s, t) and calculating s and t where dQ = (0, 0)
00068                 dQ(s, t) = (2as + 2bt + 2d, 2bs + 2ct + 2e) = (0, 0)
00069         which is at
00070                 s = (be - cd) / (ac - b^2)
00071                 t = (bd - ae) / (ac - b^2)
00072         If (s, t) is an interior point we have found the minimum. Otherwise
00073         we must determine the correct boundary of the triangle where the
00074         minimum occurs. Consider the following figure:
00075 
00076            t
00077            
00078         \ 2|
00079          \ |
00080           \|
00081            |\
00082            | \  1
00083            |  \
00084          3 | 0 \
00085            |    \
00086         --------------- s
00087          4 | 5    \ 6
00088            |       \
00089            |        \
00090 
00091         If (s, t) is in region 0 we have found the minimum. If (s, t) is
00092         in region 1 we intersect the graph with the plane s + t = 1 and
00093         get the parabola F(s) = Q(s, 1 - s) for s in [0, 1] as curve of 
00094         intersection that we can minimize. Either the minimum occurs at
00095         F'(s) = 0 or at an end point where s = 0 or s = 1. Regions 3 and
00096         5 are handled similarly.
00097         If (s, t) is in region 2 the minimum could be on the edge s + t = 1
00098         or s = 0. Because the global minimum occurs in region 2 the gradient
00099         at the corner (0, 1) cannot point inside the triangle.
00100         If dQ = (Qs, Qt) with Qs and Qt being the respective partial derivatives
00101         of Q, it must be that (0, -1) * dQ(0, 1) and (1, -1) * dQ(0, 1)
00102         cannot both be negative and the signs of these values can be used
00103         to determine the correct edge. (0, -1) and (1, -1) are direction vectors
00104         for the edges s = 0 and s + t = 1. Similar arguments apply to
00105         regions 4 and 6.
00106 */
00107 Point3 Triangle3::pointClosestTo(const Point3& p) const
00108 {
00109   Real s, t;
00110   Real ds=0; // squared distance
00111   // express triangle as T(s, t) = B + s * E0 + t * E1 with s and t in [0, 1] and s + t <= 1.
00112   Point3  tp = p2(); // triangle 'point' - B
00113   Vector3 e0 = p1() - tp; // triangle E0
00114   Vector3 e1 = p3() - tp; // triangle E1
00115 
00116   Vector3 diff = tp - p;
00117   Real a = dot(e0,e0);
00118   Real b = dot(e0,e1);
00119   Real c = dot(e1,e1);
00120   Real d = dot(e0,diff);
00121   Real e = dot(e1,diff);
00122   Real f = dot(diff,diff);
00123   Real det = Math::abs(a * c - Math::sqr(b));
00124   s = b * e - c * d;
00125   t = b * d - a * e;
00126   
00127   if (s + t <= det) {           // s + t <= 1?
00128     if (s < 0) {
00129       if (t < 0) {
00130         // region 4
00131         // minimum could be on edge s = 0 or t = 0 depending on the signs of
00132         // Qs and Qt for dQ(0, 0) = (2d, 2e)
00133         // s = 0: (0, 1) * dQ(0, 0) = (0, 1) * (2d, 2e) = 2e    if < 0 then minimum on s = 0
00134         // t = 0: (1, 0) * dQ(0, 0) = (1, 0) * (2d, 2e) = 2d    if < 0 then minimum on t = 0
00135         if (d < 0) {            // Qs(0, 0) < 0 ?
00136           // find minimum on edge t = 0, so minimize
00137           // F(s) = Q(s, 0) = as^2 + 2ds + f
00138           // F'(s) = 2as + 2d = 0 ==> s = -d / a
00139           // since Q(s, 0) < Q(0, 0) for s > 0 we can omit the test for s > 0
00140           t = 0;
00141           if (-d > a) {         // s > 1?
00142             s = 1;
00143             ds = a + 2 * d + f;
00144           }
00145           else {
00146             s = -d / a;
00147             ds = d * s + f;
00148           }
00149         }
00150         else {
00151           // find minimum on edge s = 0, so minimize
00152           // F(t) = Q(0, t) = ct^2 + 2et + f
00153           // F'(t) = 2ct + 2e = 0 ==> t = -e / c
00154           s = 0;
00155           if (e >= 0) {                 // t < 0 ?
00156             t = 0;
00157             ds = f;
00158           }
00159           else if (-e > c) {    // t > 1 ?
00160             t = 1;
00161             ds = c + 2 * e + f;
00162           }
00163           else {
00164             t = -e / c;
00165             ds = c * t + f;
00166           }
00167         }
00168       }
00169       else {
00170         // region 3
00171         // we must find the minimum on the edge s = 0, so we minimize
00172         // F(t) = Q(0, t) = ct^2 + 2et + f
00173         // F'(t) = 2ct + 2e = 0 ==> t = -e / c
00174         s = 0;
00175         if (e >= 0) {                   // t < 0 ?
00176           t = 0;
00177           ds = f;
00178         }
00179         else if (-e > c) {      // t > 1 ?
00180           t = 1;
00181           ds = c + 2 * e + f;
00182         }
00183         else {
00184           t = -e / c;
00185           ds = c * t + f;
00186         }
00187       }
00188     }
00189     else if (t < 0) {
00190       // region 5
00191       // find minimum on the edge t = 0, so we minimize
00192       // F(s) = Q(s, 0) = as^2 + 2ds + f
00193       // F'(s) = 2as + 2d = 0 ==> s = -d / a
00194       t = 0;
00195       if (d >= 0) {             // s < 0?
00196         s = 0;
00197         ds = f;
00198       }
00199       if (-d > a) {             // s > 1?
00200         s = 1;
00201         ds = a + 2 * d + f;
00202       }
00203       else {
00204         s = -d / a;
00205         ds = d * s + f;
00206       }
00207     }
00208     else {
00209       // region 0
00210       // we have an interior point, so just use s and t in 
00211       // Q(s, t) = as^2 + 2bst + ct^2 + 2ds + 2et + f
00212       det = 1 / det;
00213       s *= det;
00214       t *= det;
00215       ds = f + s * (a * s + 2 * (b * t + 2 * d)) + t * (c * t + 2 * e);
00216     }
00217   }
00218   else {        // s + t > 1
00219     if (s < 0) {
00220       // region 2
00221       // minimum could be on edge s = 0 or s + t = 1, depending on the sign of
00222       // s = 0: (0, -1) * dQ(0, 1) = (0, -1) * (2b + 2d, 2c + 2e) = -2 * (c + e)                if < 0 then minimum on s = 0
00223       // s + t = 1: (1, -1) * dQ(0, 1) = (1, -1) * (2b + 2d, 2c + 2e) = 2 * ((b + d) - (c + e))         if < 0 then minimum is on s + t = 1
00224       
00225       Real bd = b + d;
00226       Real ce = c + e;
00227       if (bd < ce) {
00228         // minimum on s + t = 1
00229         // F(s) = Q(s, 1 - s) = (a - 2b + c)s^2 + 2(b - c + d - e)s + c + 2e + f
00230         // F'(s) = 2(a - 2b + c)s + 2(b - c + d - e) = 0 ==> s = (c + e - b - d) / (a - 2b + c)
00231         Real temp = ce - bd;
00232         Real temp2 = a - 2 * b + c;
00233         if (temp > temp2) {             // s > 1?
00234           s = 1;
00235           t = 0;
00236           ds = a + 2 * d + f;
00237         }
00238         else {
00239           s = temp / temp2;
00240           t = 1 - s;
00241           ds = f + s * (a + 2 * (b * t + d)) + t * (c * t + 2 * e);
00242         }
00243       }
00244       else {
00245         // minimum on s = 0, so we minimize
00246         // F(t) = Q(0, t) = ct^2 + 2et + f
00247         // F'(t) = 2ct + 2e = 0 ==> t = -e / c
00248         s = 0;
00249         if (e >= 0) {                   // t < 0 ?
00250           t = 0;
00251           ds = f;
00252         }
00253         else if (-e > c) {      // t > 1 ?
00254           t = 1;
00255           ds = c + 2 * e + f;
00256         }
00257         else {
00258           t = -e / c;
00259           ds = c * t + f;
00260         }
00261       }
00262     }
00263     else if (t < 0) {
00264       // region 6
00265       // minimum could be on edge s + t = 1 or t = 0
00266       // t = 0: (-1, 0) * dQ(1, 0) = (-1, 0) * (2a + 2d, 2b + 2e) = -2 * (a + d)                if < 0 then minimum on t = 0
00267       // s + t = 1: (-1, 1) * dQ(1, 0) = (-1, 1) * (2a + 2d, 2b + 2e) = -2 * (a + d) + 2 * (b + e)              if < 0 then minimum on s + t = 1
00268       Real ad = a + d;
00269       Real be = b + e;
00270       if (be < ad) {
00271         // minimum is on s + t = 1
00272         // F(t) = Q(1 - t, t) = (a - 2b + c)t^2 + 2(b - a - d + e)t + a + 2d + f
00273         // F'(t) = 2(a - 2b + c)t + 2(b - a - d + e) = 0 ==> t = (a + d - b - e) / (a - 2b + c)
00274         Real temp = ad - be;
00275         Real temp2 = a - 2 * b + c;
00276         if (temp > temp2) {             // t > 1?
00277           t = 1;
00278           s = 0;
00279           ds = c + 2 * e + f;
00280         }
00281         else {
00282           t = temp / temp2;
00283           s = 1 - t;
00284           ds = f + s * (a + 2 * (b * t + d)) + t * (c * t + 2 * e);
00285         }
00286       }
00287       else {
00288         // minimum is on t = 0, so we minimize
00289         // F(s) = Q(s, 0) = as^2 + 2ds + f
00290         // F'(s) = 2as + 2d = 0 ==> s = -d / a
00291         t = 0;
00292         if (d >= 0) {           // s < 0?
00293           s = 0;
00294           ds = f;
00295         }
00296         if (-d > a) {           // s > 1?
00297           s = 1;
00298           ds = a + 2 * d + f;
00299         }
00300         else {
00301           s = -d / a;
00302           ds = d * s + f;
00303         }
00304       }
00305     }
00306     else {
00307       // region 1
00308       // minimum on edge s + t = 1 so we minimize
00309       // F(s) = Q(s, 1 - s) = (a - 2b + c)s^2 + 2(b - c + d - e)s + c + 2e + f
00310       // F'(s) = 2(a - 2b + c)s + 2(b - c + d - e) = 0 ==> s = (c + e - b - d) / (a - 2b + c)
00311       Real temp = c + e - b - d;
00312       if (temp < 0) {           // s < 0?
00313         s = 0;
00314         t = 1;
00315         ds = c + 2 * e + f;
00316       }
00317       else {
00318         Real temp2 = a - 2 * b + c;
00319         if (temp > temp2)               // s > 1?
00320         {
00321           s = 1;
00322           t = 0;
00323           ds = a + 2 * d + f;
00324         }
00325         else {
00326           s = temp / temp2;
00327           t = 1 - s;
00328           ds = f + s * (a + 2 * (b * t + d)) + t * (c * t + 2 * e);
00329         }
00330       }
00331     }
00332   }
00333   
00334   
00335   ds = Math::abs(ds);
00336   return tp + s * e0 + t * e1;
00337 }
00338 
00339 
00340 
00341 
00342 
00343 // this implementation and its explanation was basically ripped from the XEngine code by Martin Ecker
00344 //  (email: martin.ecker@liwest.at - see http://xengine.sourceforge.net )
00345 // it looks a lot like the Magic Software algorithm ( http://www.magic-software.com )
00346 /* 
00347         The problem of computing the minimal squared distance between a segment and
00348         a triangle is very similar to the one of calculating the distance between
00349         a line and a triangle.
00350         However the domain for the parameter r of the segment this time is r in [0, 1].
00351         Therefore we get more regions when partitioning the space spanned by (s, t, r)
00352         into regions. 
00353         Consider the following two figures:
00354 
00355            t                           t
00356            
00357         \ 2|                           |       |
00358          \ |                      3n-2n|  3-2  |3p-2p
00359           \|                           |       |
00360            |\                  --------|-----------------
00361            | \                         |       |
00362            |  \                        |       |
00363          3 | 0 \  1            3n-0n-1n| 3-0-1 |3p-0p-1p
00364            |    \                      |       |
00365         ---r----------- s      --------s----------------- r
00366            |      \                    |       |
00367          4 | 5     \ 6            4n-5n|  4-5  |4p-5p
00368            |        \                  |       |
00369 
00370         The first figure shows a cut with the s-t plane and shows the regions
00371         we got with line-to-triangle distance calculation. The second figure
00372         shows a cut with the t-r plane and shows the new regions we get since
00373         the prism that represents region 0 is no longer an infinite prism but
00374         a finite prism along the positive r-axis where r in [0, 1]. 
00375         The 7 regions where r < 0 have the same names as the regions where r
00376         is in [0, 1] except that they have an additional letter n for negative.
00377         The 7 regions where r > 1 have the same names as the regions where r
00378         is in [0, 1] except that they have an additional letter p for positive.
00379 */
00380 Segment3 Triangle3::shortestSegmentBetween(const Segment3& seg, Real& ds) const
00381 {
00382   Real s, t, r;
00383   ds=0; // distance squared
00384 
00385   // express triangle as T(s, t) = B + s * E0 + t * E1 with s and t in [0, 1] and s + t <= 1.
00386   Point3  tp = _p2; // triangle 'point' - B
00387   Vector3 e0 = _p1 - _p2; // triangle edge 0
00388   Vector3 e1 = _p3 - _p2; // triangle edge 1
00389   Vector3 diff = _p2 - seg.s;
00390   Vector3 segdir = seg.e-seg.s; // seg direction
00391   Point3 p1,p2; // between segment end-points
00392   Real a00 = dot(e0,e0);
00393   Real a11 = dot(e1,e1);
00394   Real a22 = dot(segdir,segdir);
00395   Real a01 = dot(e0,e1);
00396   Real a02 = -dot(e0,segdir);
00397   Real a12 = -dot(e1,segdir);
00398   Real b0 = dot(e0,diff);
00399   Real b1 = dot(e1,diff);
00400   Real b2 = -dot(segdir,diff);
00401   
00402   // cofactors for calculating the determinant and later on to invert A
00403   Real cf00 = a11 * a22 - a12 * a12;
00404   Real cf01 = a02 * a12 - a22 * a01;
00405   Real cf02 = a01 * a12 - a02 * a11;
00406   Real det = a00 * cf00 + a01 * cf01 + a02 * cf02;
00407   
00408   if (Math::abs(det) >= consts::epsilon)                // det != 0?
00409   {
00410     // to be able to invert A we need some more cofactors
00411     Real cf11 = a00 * a22 - a02 * a02;
00412     Real cf12 = a02 * a01 - a00 * a12;
00413     Real cf22 = a00 * a11 - a01 * a01;
00414     
00415     det = 1 / det;
00416     s = (-b0 * cf00 - b1 * cf01 - b2 * cf02) * det;
00417     t = (-b0 * cf01 - b1 * cf11 - b2 * cf12) * det;
00418     r = (-b0 * cf02 - b1 * cf12 - b2 * cf22) * det;
00419     
00420     if (s + t <= 1) {
00421       if (s < 0) {
00422         if (t < 0) {
00423           // region 4 or 4n or 4p
00424           // the minimum is either on face s = 0 or t = 0 or r = 0/1
00425           Segment3 segment1(_p2, _p1);
00426           Segment3 segment2(_p2, _p3);
00427           Segment3 sb1(segment1.shortestSegmentBetween(seg));
00428           Segment3 sb2(segment2.shortestSegmentBetween(seg));
00429           Real ds1 = sb1.norm();
00430           Real ds2 = sb2.norm();
00431           if (ds1 < ds2) {
00432             ds = ds1;
00433             p1 = sb1.s; p2 = sb1.e;
00434           }
00435           else {
00436             ds = ds2;
00437             p1 = sb2.s; p2 = sb2.e;
00438           }
00439         }
00440         else {
00441           // region 3 or 3n or 3p
00442           // the minimum is on the face s = 0 or r = 0/1
00443           Segment3 sb = seg.shortestSegmentBetween(Segment3(_p2, _p3), ds);
00444           p1 = sb.e; p2 = sb.s;
00445         }
00446       }
00447       else if (t < 0) {
00448         // region 5 or 5n or 5p
00449         // the minimum is on the face t = 0 or r = 0/1
00450         Segment3 sb = seg.shortestSegmentBetween(Segment3(_p2, _p1), ds);
00451         p1 = sb.e; p2 = sb.s;
00452       }
00453       else if (r >= 0 && r <= 1) {
00454         // region 0
00455         Real c = dot(diff,diff);
00456         ds = s * (a00 * s + 2 * (a01 * t + a02 * r + b0)) + 
00457         t * (a11 * t + 2 * (a12 * r + b1)) +
00458         r * (a22 * r + 2 * b2) + c;
00459         
00460         p1 = seg.s + r * segdir;
00461         p2 = tp + s * e0 + t * e1;
00462       }                 
00463     }
00464     else {
00465       if (s < 0) {
00466         // region 1 or 2n or 2p
00467         // the minimum is either on the face s = 0 or s + t = 1 or r = 0/1
00468         Segment3 segment1(_p2, _p3);
00469         Segment3 segment2(_p1, _p3);
00470         Segment3 sb1(segment1.shortestSegmentBetween(seg));
00471         Segment3 sb2(segment1.shortestSegmentBetween(seg));
00472         Real ds1 = sb1.norm();
00473         Real ds2 = sb2.norm();
00474         if (ds1 < ds2) {
00475           ds = ds1;
00476           p1 = sb1.s; p2 = sb1.e;
00477         }
00478         else {
00479           ds = ds2;
00480           p1 = sb2.s; p2 = sb2.e;
00481         }
00482       }
00483       else if (t < 0) {
00484         // region 6n
00485         // the minimum is either on the face t = 0 or s + t = 1 or r = 0/1
00486         Segment3 segment1(_p2, _p1);
00487         Segment3 segment2(_p1, _p3);
00488         Segment3 sb1(segment1.shortestSegmentBetween(seg));
00489         Segment3 sb2(segment1.shortestSegmentBetween(seg));
00490         Real ds1 = sb1.norm();
00491         Real ds2 = sb2.norm();
00492         if (ds1 < ds2) {
00493           ds = ds1;
00494           p1 = sb1.s; p2 = sb1.e;
00495         }
00496         else {
00497           ds = ds2;
00498           p1 = sb2.s; p2 = sb2.e;
00499         }
00500       }
00501       else {
00502         // region 1 or 1n or 1p
00503         // minimum is on face s + t = 1 or r = 0/1
00504         Segment3 segment1(_p1, _p3);
00505         Segment3 sb = segment1.shortestSegmentBetween(seg, ds);
00506         p1 = sb.s; p2 = sb.e;
00507       }
00508     }
00509     
00510     // if r outside [0, 1] the minimum might be on r = 0 or r = 1
00511     if (r < 0 || r > 1) {
00512       // determine squared distance from start-point or end-point of the segment to the triangle
00513       // this is for face r = 0 or r = 1 depending on the value of r
00514       Point3 p1temp, p2temp;
00515       Real distTemp;
00516       if (r < 0) {
00517         Segment3 sb(pointClosestTo(seg.s), seg.s);
00518         distTemp = sb.norm();
00519         p1temp = sb.s; p2temp = sb.e;
00520       }
00521       else {
00522         Segment3 sb(pointClosestTo(seg.e), seg.e);
00523         distTemp = sb.norm();
00524         p1temp = sb.s; p2temp = sb.e;
00525       }
00526       if (distTemp < ds || (s >= 0 && t >= 0)) {        // the part after || is for region 0n or 0p where the minimum is on r = 0 or r = 1
00527         ds = distTemp;
00528         p1 = p1temp;
00529         p2 = p2temp;
00530       }
00531     }
00532   }
00533   else {
00534     // segment and triangle are parallel, so we'll just compute the minimum 
00535     // distance of the segment to each of the three triangle edges and of the segment end-points to the triangle
00536     Segment3 segment1(_p2, _p1);
00537     Segment3 segment2(_p2, _p3);
00538     Segment3 segment3(_p1, _p3);
00539     Segment3 sb1(segment1.shortestSegmentBetween(seg));
00540     Segment3 sb2(segment2.shortestSegmentBetween(seg));
00541     Segment3 sb3(segment3.shortestSegmentBetween(seg));
00542     Real ds1 = sb1.norm();
00543     Real ds2 = sb2.norm();
00544     Real ds3 = sb3.norm();
00545     if (ds1 < ds2) {
00546       if (ds1 < ds3) {
00547         ds = ds1;
00548         p1 = sb1.s; p2 = sb1.e;
00549       }
00550       else {
00551         ds = ds3;
00552         p1 = sb3.s; p2 = sb3.e;
00553       }
00554     }
00555     else { // ds2 < ds1
00556       if (ds2 < ds3) {
00557         ds = ds2;
00558         p1 = sb2.s; p2 = sb2.e;
00559       }
00560       else {
00561         ds = ds3;
00562         p1 = sb3.s; p2 = sb3.e;
00563       }
00564     }
00565     
00566     Point3 p1temp, p2temp;
00567     Segment3 sbp(pointClosestTo(seg.s), seg.s);
00568     Real distTemp = sbp.norm();
00569     p1temp = sbp.s; p2temp = sbp.e;
00570     if (distTemp < ds) {
00571       ds = distTemp;
00572       p1 = p1temp;
00573       p2 = p2temp;
00574     }
00575     Segment3 sbp2(pointClosestTo(seg.e), seg.e);
00576     distTemp = sbp2.norm();
00577     p1temp = sbp2.s; p2temp = sbp2.e;
00578     if (distTemp < ds) {
00579       ds = distTemp;
00580       p1 = p1temp;
00581       p2 = p2temp;
00582     }
00583   }
00584   
00585   
00586   ds = Math::abs(ds);
00587 
00588   //Assert(this->contains(p1)); // can fail is interpenetration
00589   //Assert(seg.contains(p2));
00590   
00591   return Segment3(p1,p2);
00592 }
00593 
00594 
00595 
00596 Segment3 Triangle3::shortestSegmentBetween(const Triangle3& t) const
00597 {
00598   // compare the shortest distance between each edge of this with t
00599   //  and each edge of t with this
00600   Segment3 t11(p1(), p2());
00601   Segment3 t12(p2(), p3());
00602   Segment3 t13(p3(), p1());
00603   
00604   Segment3 t21(t.p1(), t.p2());
00605   Segment3 t22(t.p2(), t.p3());
00606   Segment3 t23(t.p3(), t.p1());
00607 
00608   Segment3 seg = shortestSegmentBetween(t21);
00609   Segment3 shortest = seg;
00610   
00611   seg = shortestSegmentBetween(t22);
00612   if (seg.norm() < shortest.norm()) shortest = seg;
00613   
00614   seg = shortestSegmentBetween(t23);
00615   if (seg.norm() < shortest.norm()) shortest = seg;
00616   
00617   seg = t.shortestSegmentBetween(t11);
00618   if (seg.norm() < shortest.norm()) shortest = seg;
00619 
00620   seg = t.shortestSegmentBetween(t12);
00621   if (seg.norm() < shortest.norm()) shortest = seg;
00622 
00623   seg = t.shortestSegmentBetween(t13);
00624   if (seg.norm() < shortest.norm()) shortest = seg;
00625 
00626   return shortest;
00627 }
00628   
00629   
00630 Real Triangle3::distanceTo(const Triangle3& t) const
00631 {
00632   return shortestSegmentBetween(t).length();
00633 }
00634 
00635 
00636 
00637 
00638 
00639 
00640 
00641 
00642 // helper class for computing triangle intersections
00643 namespace gfx {
00644 
00645 class TriangleDesc : public Triangle3
00646 {
00647 public:
00648   TriangleDesc(const Triangle3& t, const Plane& p)
00649     : Triangle3(t) 
00650   {
00651     const Vector3& n=p.normal;
00652     Vector3 a(base::abs(n.x),base::abs(n.y),base::abs(n.z));
00653     if (a.x>a.y) {
00654       if (a.x>a.z) { i1=2; i2=3; }
00655       else         { i1=1; i2=2; }
00656     }
00657     else {
00658       if (a.y>a.z) { i1=1; i2=3; }
00659       else         { i1=1; i2=2; }
00660     }
00661   }
00662   
00663   bool pointInTri(const Vector3& P) const
00664   {
00665     const Point3& v1( (*this)[1] );
00666     const Point3& v2( (*this)[2] );
00667     const Point3& v3( (*this)[3] );
00668     Vector3 u(P[i1]-v1[i1],
00669               v2[i1]-v1[i1],
00670               v3[i1]-v1[i1]);
00671     Vector3 v(P[i2]-v1[i2],
00672               v2[i2]-v1[i2],
00673               v3[i2]-v1[i2]);
00674     Real a,b;
00675     if (u.y==0.0) {
00676       b=u.x/u.z;
00677       if (b>=0.0 && b<=1.0) a=(v.x-b*v.z)/v.y;
00678       else return false;
00679     }
00680     else {
00681       b=(v.x*u.y-u.x*v.y)/(v.z*u.y-u.z*v.y);
00682       if (b>=0.0 && b<=1.0) a=(u.x-b*u.z)/u.y;
00683       else return false;
00684     }
00685     return (a>=0 && (a+b)<=1);
00686   }
00687   
00688   // A more forgiving version
00689   const Point3& operator[] (Int i) const throw()
00690   {
00691     SInt zi = i-1;
00692     if (zi<0) zi += 3;
00693     zi = zi%3;
00694     
00695     switch (zi) {
00696     case 0: return at(1);
00697     case 1: return at(2);
00698     case 2: return at(3);
00699     default: return at(1); // never
00700     }
00701   }
00702         
00703   Int i1,i2;
00704 };
00705   
00706 }// gfx
00707 
00708 using gfx::TriangleDesc;
00709 
00710 
00711 // 
00712 // Some 'C' triangle intersection code
00713 //
00714 // The implementation of Triangle follows at the bottom
00715 
00716 
00717 
00718 
00719 /* Triangle/triangle intersection test routine,
00720  * by Tomas Moller, 1997.
00721  * See article "A Fast Triangle-Triangle Intersection Test",
00722  * Journal of Graphics Tools, 2(2), 1997
00723  * updated: 2001-06-20 (added line of intersection)
00724  *
00725  * int tri_tri_intersect(Real V0[3],Real V1[3],Real V2[3],
00726  *                       Real U0[3],Real U1[3],Real U2[3])
00727  *
00728  * parameters: vertices of triangle 1: V0,V1,V2
00729  *             vertices of triangle 2: U0,U1,U2
00730  * result    : returns 1 if the triangles intersect, otherwise 0
00731  *
00732  * Here is a version withouts divisions (a little faster)
00733  * int NoDivTriTriIsect(Real V0[3],Real V1[3],Real V2[3],
00734  *                      Real U0[3],Real U1[3],Real U2[3]);
00735  * 
00736  * This version computes the line of intersection as well (if they are not coplanar):
00737  * int tri_tri_intersect_with_isectline(Real V0[3],Real V1[3],Real V2[3], 
00738  *                                      Real U0[3],Real U1[3],Real U2[3],int *coplanar,
00739  *                                      Real isectpt1[3],Real isectpt2[3]);
00740  * coplanar returns whether the tris are coplanar
00741  * isectpt1, isectpt2 are the endpoints of the line of intersection
00742  */
00743 
00744 
00745 #define FABS(x) (base::abs(x))        /* implement as is fastest on your machine */
00746 
00747 /* if USE_EPSILON_TEST is true then we do a check: 
00748          if |dv|<EPSILON then dv=0.0;
00749    else no check is done (which is less robust)
00750 */
00751 #define USE_EPSILON_TEST TRUE  
00752 #define EPSILON 0.000001
00753 
00754 
00755 /* some macros */
00756 #define CROSS(dest,v1,v2)                      \
00757               dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
00758               dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
00759               dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
00760 
00761 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
00762 
00763 #define SUB(dest,v1,v2) dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; 
00764 
00765 #define ADD(dest,v1,v2) dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; 
00766 
00767 #define MULT(dest,v,factor) dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2];
00768 
00769 #define SET(dest,src) dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; 
00770 
00771 /* sort so that a<=b */
00772 #define SORT(a,b)       \
00773              if(a>b)    \
00774              {          \
00775                Real c; \
00776                c=a;     \
00777                a=b;     \
00778                b=c;     \
00779              }
00780 
00781 #define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \
00782               isect0=VV0+(VV1-VV0)*D0/(D0-D1);    \
00783               isect1=VV0+(VV2-VV0)*D0/(D0-D2);
00784 
00785 
00786 #define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \
00787   if(D0D1>0.0f)                                         \
00788   {                                                     \
00789     /* here we know that D0D2<=0.0 */                   \
00790     /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
00791     ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1);          \
00792   }                                                     \
00793   else if(D0D2>0.0f)                                    \
00794   {                                                     \
00795     /* here we know that d0d1<=0.0 */                   \
00796     ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1);          \
00797   }                                                     \
00798   else if(D1*D2>0.0f || D0!=0.0f)                       \
00799   {                                                     \
00800     /* here we know that d0d1<=0.0 or that D0!=0.0 */   \
00801     ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1);          \
00802   }                                                     \
00803   else if(D1!=0.0f)                                     \
00804   {                                                     \
00805     ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1);          \
00806   }                                                     \
00807   else if(D2!=0.0f)                                     \
00808   {                                                     \
00809     ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1);          \
00810   }                                                     \
00811   else                                                  \
00812   {                                                     \
00813     /* triangles are coplanar */                        \
00814     return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);      \
00815   }
00816 
00817 
00818 
00819 /* this edge to edge test is based on Franlin Antonio's gem:
00820    "Faster Line Segment Intersection", in Graphics Gems III,
00821    pp. 199-202 */ 
00822 #define EDGE_EDGE_TEST(V0,U0,U1)                      \
00823   Bx=U0[i0]-U1[i0];                                   \
00824   By=U0[i1]-U1[i1];                                   \
00825   Cx=V0[i0]-U0[i0];                                   \
00826   Cy=V0[i1]-U0[i1];                                   \
00827   f=Ay*Bx-Ax*By;                                      \
00828   d=By*Cx-Bx*Cy;                                      \
00829   if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))  \
00830   {                                                   \
00831     e=Ax*Cy-Ay*Cx;                                    \
00832     if(f>0)                                           \
00833     {                                                 \
00834       if(e>=0 && e<=f) return 1;                      \
00835     }                                                 \
00836     else                                              \
00837     {                                                 \
00838       if(e<=0 && e>=f) return 1;                      \
00839     }                                                 \
00840   }                                
00841 
00842 #define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \
00843 {                                              \
00844   Real Ax,Ay,Bx,By,Cx,Cy,e,d,f;               \
00845   Ax=V1[i0]-V0[i0];                            \
00846   Ay=V1[i1]-V0[i1];                            \
00847   /* test edge U0,U1 against V0,V1 */          \
00848   EDGE_EDGE_TEST(V0,U0,U1);                    \
00849   /* test edge U1,U2 against V0,V1 */          \
00850   EDGE_EDGE_TEST(V0,U1,U2);                    \
00851   /* test edge U2,U1 against V0,V1 */          \
00852   EDGE_EDGE_TEST(V0,U2,U0);                    \
00853 }
00854 
00855 #define POINT_IN_TRI(V0,U0,U1,U2)           \
00856 {                                           \
00857   Real a,b,c,d0,d1,d2;                     \
00858   /* is T1 completly inside T2? */          \
00859   /* check if V0 is inside tri(U0,U1,U2) */ \
00860   a=U1[i1]-U0[i1];                          \
00861   b=-(U1[i0]-U0[i0]);                       \
00862   c=-a*U0[i0]-b*U0[i1];                     \
00863   d0=a*V0[i0]+b*V0[i1]+c;                   \
00864                                             \
00865   a=U2[i1]-U1[i1];                          \
00866   b=-(U2[i0]-U1[i0]);                       \
00867   c=-a*U1[i0]-b*U1[i1];                     \
00868   d1=a*V0[i0]+b*V0[i1]+c;                   \
00869                                             \
00870   a=U0[i1]-U2[i1];                          \
00871   b=-(U0[i0]-U2[i0]);                       \
00872   c=-a*U2[i0]-b*U2[i1];                     \
00873   d2=a*V0[i0]+b*V0[i1]+c;                   \
00874   if(d0*d1>0.0)                             \
00875   {                                         \
00876     if(d0*d2>0.0) return 1;                 \
00877   }                                         \
00878 }
00879 
00880 int coplanar_tri_tri(Real N[3],Real V0[3],Real V1[3],Real V2[3],
00881                      Real U0[3],Real U1[3],Real U2[3])
00882 {
00883    Real A[3];
00884    short i0,i1;
00885    /* first project onto an axis-aligned plane, that maximizes the area */
00886    /* of the triangles, compute indices: i0,i1. */
00887    A[0]=fabs(N[0]);
00888    A[1]=fabs(N[1]);
00889    A[2]=fabs(N[2]);
00890    if(A[0]>A[1])
00891    {
00892       if(A[0]>A[2])  
00893       {
00894           i0=1;      /* A[0] is greatest */
00895           i1=2;
00896       }
00897       else
00898       {
00899           i0=0;      /* A[2] is greatest */
00900           i1=1;
00901       }
00902    }
00903    else   /* A[0]<=A[1] */
00904    {
00905       if(A[2]>A[1])
00906       {
00907           i0=0;      /* A[2] is greatest */
00908           i1=1;                                           
00909       }
00910       else
00911       {
00912           i0=0;      /* A[1] is greatest */
00913           i1=2;
00914       }
00915     }               
00916                 
00917     /* test all edges of triangle 1 against the edges of triangle 2 */
00918     EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2);
00919     EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2);
00920     EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2);
00921                 
00922     /* finally, test if tri1 is totally contained in tri2 or vice versa */
00923     POINT_IN_TRI(V0,U0,U1,U2);
00924     POINT_IN_TRI(U0,V0,V1,V2);
00925 
00926     return 0;
00927 }
00928 
00929 
00930 int tri_tri_intersect(Real V0[3],Real V1[3],Real V2[3],
00931                       Real U0[3],Real U1[3],Real U2[3])
00932 {
00933   Real E1[3],E2[3];
00934   Real N1[3],N2[3],d1,d2;
00935   Real du0,du1,du2,dv0,dv1,dv2;
00936   Real D[3];
00937   Real isect1[2], isect2[2];
00938   Real du0du1,du0du2,dv0dv1,dv0dv2;
00939   short index;
00940   Real vp0,vp1,vp2;
00941   Real up0,up1,up2;
00942   Real b,c,max;
00943 
00944   /* compute plane equation of triangle(V0,V1,V2) */
00945   SUB(E1,V1,V0);
00946   SUB(E2,V2,V0);
00947   CROSS(N1,E1,E2);
00948   d1=-DOT(N1,V0);
00949   /* plane equation 1: N1.X+d1=0 */
00950 
00951   /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
00952   du0=DOT(N1,U0)+d1;
00953   du1=DOT(N1,U1)+d1;
00954   du2=DOT(N1,U2)+d1;
00955 
00956   /* coplanarity robustness check */
00957 #if USE_EPSILON_TEST==TRUE
00958   if(fabs(du0)<EPSILON) du0=0.0;
00959   if(fabs(du1)<EPSILON) du1=0.0;
00960   if(fabs(du2)<EPSILON) du2=0.0;
00961 #endif
00962   du0du1=du0*du1;
00963   du0du2=du0*du2;
00964 
00965   if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
00966     return 0;                    /* no intersection occurs */
00967 
00968   /* compute plane of triangle (U0,U1,U2) */
00969   SUB(E1,U1,U0);
00970   SUB(E2,U2,U0);
00971   CROSS(N2,E1,E2);
00972   d2=-DOT(N2,U0);
00973   /* plane equation 2: N2.X+d2=0 */
00974 
00975   /* put V0,V1,V2 into plane equation 2 */
00976   dv0=DOT(N2,V0)+d2;
00977   dv1=DOT(N2,V1)+d2;
00978   dv2=DOT(N2,V2)+d2;
00979 
00980 #if USE_EPSILON_TEST==TRUE
00981   if(fabs(dv0)<EPSILON) dv0=0.0;
00982   if(fabs(dv1)<EPSILON) dv1=0.0;
00983   if(fabs(dv2)<EPSILON) dv2=0.0;
00984 #endif
00985 
00986   dv0dv1=dv0*dv1;
00987   dv0dv2=dv0*dv2;
00988         
00989   if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
00990     return 0;                    /* no intersection occurs */
00991 
00992   /* compute direction of intersection line */
00993   CROSS(D,N1,N2);
00994 
00995   /* compute and index to the largest component of D */
00996   max=fabs(D[0]);
00997   index=0;
00998   b=fabs(D[1]);
00999   c=fabs(D[2]);
01000   if(b>max) max=b,index=1;
01001   if(c>max) max=c,index=2;
01002 
01003   /* this is the simplified projection onto L*/
01004   vp0=V0[index];
01005   vp1=V1[index];
01006   vp2=V2[index];
01007   
01008   up0=U0[index];
01009   up1=U1[index];
01010   up2=U2[index];
01011 
01012   /* compute interval for triangle 1 */
01013   COMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,isect1[0],isect1[1]);
01014 
01015   /* compute interval for triangle 2 */
01016   COMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,isect2[0],isect2[1]);
01017 
01018   SORT(isect1[0],isect1[1]);
01019   SORT(isect2[0],isect2[1]);
01020 
01021   if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
01022   return 1;
01023 }
01024 
01025 
01026 #define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \
01027 { \
01028         if(D0D1>0.0f) \
01029         { \
01030                 /* here we know that D0D2<=0.0 */ \
01031             /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
01032                 A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \
01033         } \
01034         else if(D0D2>0.0f)\
01035         { \
01036                 /* here we know that d0d1<=0.0 */ \
01037             A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \
01038         } \
01039         else if(D1*D2>0.0f || D0!=0.0f) \
01040         { \
01041                 /* here we know that d0d1<=0.0 or that D0!=0.0 */ \
01042                 A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \
01043         } \
01044         else if(D1!=0.0f) \
01045         { \
01046                 A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \
01047         } \
01048         else if(D2!=0.0f) \
01049         { \
01050                 A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \
01051         } \
01052         else \
01053         { \
01054                 /* triangles are coplanar */ \
01055                 return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \
01056         } \
01057 }
01058 
01059 
01060 
01061 int NoDivTriTriIsect(Real V0[3],Real V1[3],Real V2[3],
01062                      Real U0[3],Real U1[3],Real U2[3])
01063 {
01064   Real E1[3],E2[3];
01065   Real N1[3],N2[3],d1,d2;
01066   Real du0,du1,du2,dv0,dv1,dv2;
01067   Real D[3];
01068   Real isect1[2], isect2[2];
01069   Real du0du1,du0du2,dv0dv1,dv0dv2;
01070   short index;
01071   Real vp0,vp1,vp2;
01072   Real up0,up1,up2;
01073   Real bb,cc,max;
01074   Real a,b,c,x0,x1;
01075   Real d,e,f,y0,y1;
01076   Real xx,yy,xxyy,tmp;
01077 
01078   /* compute plane equation of triangle(V0,V1,V2) */
01079   SUB(E1,V1,V0);
01080   SUB(E2,V2,V0);
01081   CROSS(N1,E1,E2);
01082   d1=-DOT(N1,V0);
01083   /* plane equation 1: N1.X+d1=0 */
01084 
01085   /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
01086   du0=DOT(N1,U0)+d1;
01087   du1=DOT(N1,U1)+d1;
01088   du2=DOT(N1,U2)+d1;
01089 
01090   /* coplanarity robustness check */
01091 #if USE_EPSILON_TEST==TRUE
01092   if(FABS(du0)<EPSILON) du0=0.0;
01093   if(FABS(du1)<EPSILON) du1=0.0;
01094   if(FABS(du2)<EPSILON) du2=0.0;
01095 #endif
01096   du0du1=du0*du1;
01097   du0du2=du0*du2;
01098 
01099   if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
01100     return 0;                    /* no intersection occurs */
01101 
01102   /* compute plane of triangle (U0,U1,U2) */
01103   SUB(E1,U1,U0);
01104   SUB(E2,U2,U0);
01105   CROSS(N2,E1,E2);
01106   d2=-DOT(N2,U0);
01107   /* plane equation 2: N2.X+d2=0 */
01108 
01109   /* put V0,V1,V2 into plane equation 2 */
01110   dv0=DOT(N2,V0)+d2;
01111   dv1=DOT(N2,V1)+d2;
01112   dv2=DOT(N2,V2)+d2;
01113 
01114 #if USE_EPSILON_TEST==TRUE
01115   if(FABS(dv0)<EPSILON) dv0=0.0;
01116   if(FABS(dv1)<EPSILON) dv1=0.0;
01117   if(FABS(dv2)<EPSILON) dv2=0.0;
01118 #endif
01119 
01120   dv0dv1=dv0*dv1;
01121   dv0dv2=dv0*dv2;
01122 
01123   if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
01124     return 0;                    /* no intersection occurs */
01125 
01126   /* compute direction of intersection line */
01127   CROSS(D,N1,N2);
01128 
01129   /* compute and index to the largest component of D */
01130   max=(Real)FABS(D[0]);
01131   index=0;
01132   bb=(Real)FABS(D[1]);
01133   cc=(Real)FABS(D[2]);
01134   if(bb>max) max=bb,index=1;
01135   if(cc>max) max=cc,index=2;
01136 
01137   /* this is the simplified projection onto L*/
01138   vp0=V0[index];
01139   vp1=V1[index];
01140   vp2=V2[index];
01141 
01142   up0=U0[index];
01143   up1=U1[index];
01144   up2=U2[index];
01145 
01146   /* compute interval for triangle 1 */
01147   NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1);
01148 
01149   /* compute interval for triangle 2 */
01150   NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1);
01151 
01152   xx=x0*x1;
01153   yy=y0*y1;
01154   xxyy=xx*yy;
01155 
01156   tmp=a*xxyy;
01157   isect1[0]=tmp+b*x1*yy;
01158   isect1[1]=tmp+c*x0*yy;
01159 
01160   tmp=d*xxyy;
01161   isect2[0]=tmp+e*xx*y1;
01162   isect2[1]=tmp+f*xx*y0;
01163 
01164   SORT(isect1[0],isect1[1]);
01165   SORT(isect2[0],isect2[1]);
01166 
01167   if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
01168   return 1;
01169 }
01170 
01171 /* sort so that a<=b */
01172 #define SORT2(a,b,smallest)       \
01173              if(a>b)       \
01174              {             \
01175                Real c;    \
01176                c=a;        \
01177                a=b;        \
01178                b=c;        \
01179                smallest=1; \
01180              }             \
01181              else smallest=0;
01182 
01183 
01184 inline void isect2(Real VTX0[3],Real VTX1[3],Real VTX2[3],Real VV0,Real VV1,Real VV2,
01185             Real D0,Real D1,Real D2,Real *isect0,Real *isect1,Real isectpoint0[3],Real isectpoint1[3]) 
01186 {
01187   Real tmp=D0/(D0-D1);          
01188   Real diff[3];
01189   *isect0=VV0+(VV1-VV0)*tmp;         
01190   SUB(diff,VTX1,VTX0);              
01191   MULT(diff,diff,tmp);               
01192   ADD(isectpoint0,diff,VTX0);        
01193   tmp=D0/(D0-D2);                    
01194   *isect1=VV0+(VV2-VV0)*tmp;          
01195   SUB(diff,VTX2,VTX0);                   
01196   MULT(diff,diff,tmp);                 
01197   ADD(isectpoint1,VTX0,diff);          
01198 }
01199 
01200 
01201 
01202 inline int compute_intervals_isectline(Real VERT0[3],Real VERT1[3],Real VERT2[3],
01203                                        Real VV0,Real VV1,Real VV2,Real D0,Real D1,Real D2,
01204                                        Real D0D1,Real D0D2,Real *isect0,Real *isect1,
01205                                        Real isectpoint0[3],Real isectpoint1[3])
01206 {
01207   if(D0D1>0.0f)                                        
01208   {                                                    
01209     /* here we know that D0D2<=0.0 */                  
01210     /* that is D0, D1 are on the same side, D2 on the other or on the plane */
01211     isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1);
01212   } 
01213   else if(D0D2>0.0f)                                   
01214     {                                                   
01215     /* here we know that d0d1<=0.0 */             
01216     isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1);
01217   }                                                  
01218   else if(D1*D2>0.0f || D0!=0.0f)   
01219   {                                   
01220     /* here we know that d0d1<=0.0 or that D0!=0.0 */
01221     isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1);   
01222   }                                                  
01223   else if(D1!=0.0f)                                  
01224   {                                               
01225     isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); 
01226   }                                         
01227   else if(D2!=0.0f)                                  
01228   {                                                   
01229     isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1);     
01230   }                                                 
01231   else                                               
01232   {                                                   
01233     /* triangles are coplanar */    
01234     return 1;
01235   }
01236   return 0;
01237 }
01238 
01239 #define COMPUTE_INTERVALS_ISECTLINE(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1,isectpoint0,isectpoint1) \
01240   if(D0D1>0.0f)                                         \
01241   {                                                     \
01242     /* here we know that D0D2<=0.0 */                   \
01243     /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
01244     isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1);          \
01245   }                                                     
01246 #if 0
01247   else if(D0D2>0.0f)                                    \
01248   {                                                     \
01249     /* here we know that d0d1<=0.0 */                   \
01250     isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1);          \
01251   }                                                     \
01252   else if(D1*D2>0.0f || D0!=0.0f)                       \
01253   {                                                     \
01254     /* here we know that d0d1<=0.0 or that D0!=0.0 */   \
01255     isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,&isect0,&isect1,isectpoint0,isectpoint1);          \
01256   }                                                     \
01257   else if(D1!=0.0f)                                     \
01258   {                                                     \
01259     isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1);          \
01260   }                                                     \
01261   else if(D2!=0.0f)                                     \
01262   {                                                     \
01263     isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1);          \
01264   }                                                     \
01265   else                                                  \
01266   {                                                     \
01267     /* triangles are coplanar */                        \
01268     coplanar=1;                                         \
01269     return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);      \
01270   }
01271 #endif
01272 
01273 int tri_tri_intersect_with_isectline(Real V0[3],Real V1[3],Real V2[3],
01274                                      Real U0[3],Real U1[3],Real U2[3],int *coplanar,
01275                                      Real isectpt1[3],Real isectpt2[3])
01276 {
01277   Real E1[3],E2[3];
01278   Real N1[3],N2[3],d1,d2;
01279   Real du0,du1,du2,dv0,dv1,dv2;
01280   Real D[3];
01281   Real isect1[2], isect2[2];
01282   Real isectpointA1[3],isectpointA2[3];
01283   Real isectpointB1[3],isectpointB2[3];
01284   Real du0du1,du0du2,dv0dv1,dv0dv2;
01285   short index;
01286   Real vp0,vp1,vp2;
01287   Real up0,up1,up2;
01288   Real b,c,max;
01289   //  Real tmp,diff[3];
01290   int smallest1,smallest2;
01291   
01292   /* compute plane equation of triangle(V0,V1,V2) */
01293   SUB(E1,V1,V0);
01294   SUB(E2,V2,V0);
01295   CROSS(N1,E1,E2);
01296   d1=-DOT(N1,V0);
01297   /* plane equation 1: N1.X+d1=0 */
01298 
01299   /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
01300   du0=DOT(N1,U0)+d1;
01301   du1=DOT(N1,U1)+d1;
01302   du2=DOT(N1,U2)+d1;
01303 
01304   /* coplanarity robustness check */
01305 #if USE_EPSILON_TEST==TRUE
01306   if(fabs(du0)<EPSILON) du0=0.0;
01307   if(fabs(du1)<EPSILON) du1=0.0;
01308   if(fabs(du2)<EPSILON) du2=0.0;
01309 #endif
01310   du0du1=du0*du1;
01311   du0du2=du0*du2;
01312 
01313   if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
01314     return 0;                    /* no intersection occurs */
01315 
01316   /* compute plane of triangle (U0,U1,U2) */
01317   SUB(E1,U1,U0);
01318   SUB(E2,U2,U0);
01319   CROSS(N2,E1,E2);
01320   d2=-DOT(N2,U0);
01321   /* plane equation 2: N2.X+d2=0 */
01322 
01323   /* put V0,V1,V2 into plane equation 2 */
01324   dv0=DOT(N2,V0)+d2;
01325   dv1=DOT(N2,V1)+d2;
01326   dv2=DOT(N2,V2)+d2;
01327 
01328 #if USE_EPSILON_TEST==TRUE
01329   if(fabs(dv0)<EPSILON) dv0=0.0;
01330   if(fabs(dv1)<EPSILON) dv1=0.0;
01331   if(fabs(dv2)<EPSILON) dv2=0.0;
01332 #endif
01333 
01334   dv0dv1=dv0*dv1;
01335   dv0dv2=dv0*dv2;
01336         
01337   if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
01338     return 0;                    /* no intersection occurs */
01339 
01340   /* compute direction of intersection line */
01341   CROSS(D,N1,N2);
01342 
01343   /* compute and index to the largest component of D */
01344   max=fabs(D[0]);
01345   index=0;
01346   b=fabs(D[1]);
01347   c=fabs(D[2]);
01348   if(b>max) max=b,index=1;
01349   if(c>max) max=c,index=2;
01350 
01351   /* this is the simplified projection onto L*/
01352   vp0=V0[index];
01353   vp1=V1[index];
01354   vp2=V2[index];
01355   
01356   up0=U0[index];
01357   up1=U1[index];
01358   up2=U2[index];
01359 
01360   /* compute interval for triangle 1 */
01361   *coplanar=compute_intervals_isectline(V0,V1,V2,vp0,vp1,vp2,dv0,dv1,dv2,
01362                                        dv0dv1,dv0dv2,&isect1[0],&isect1[1],isectpointA1,isectpointA2);
01363   if(*coplanar) return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);     
01364 
01365 
01366   /* compute interval for triangle 2 */
01367   compute_intervals_isectline(U0,U1,U2,up0,up1,up2,du0,du1,du2,
01368                               du0du1,du0du2,&isect2[0],&isect2[1],isectpointB1,isectpointB2);
01369 
01370   SORT2(isect1[0],isect1[1],smallest1);
01371   SORT2(isect2[0],isect2[1],smallest2);
01372 
01373   if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
01374 
01375   /* at this point, we know that the triangles intersect */
01376 
01377   if(isect2[0]<isect1[0])
01378   {
01379     if(smallest1==0) { SET(isectpt1,isectpointA1); }
01380     else { SET(isectpt1,isectpointA2); }
01381 
01382     if(isect2[1]<isect1[1])
01383     {
01384       if(smallest2==0) { SET(isectpt2,isectpointB2); }
01385       else { SET(isectpt2,isectpointB1); }
01386     }
01387     else
01388     {
01389       if(smallest1==0) { SET(isectpt2,isectpointA2); }
01390       else { SET(isectpt2,isectpointA1); }
01391     }
01392   }
01393   else
01394   {
01395     if(smallest2==0) { SET(isectpt1,isectpointB1); }
01396     else { SET(isectpt1,isectpointB2); }
01397 
01398     if(isect2[1]>isect1[1])
01399     {
01400       if(smallest1==0) { SET(isectpt2,isectpointA2); }
01401       else { SET(isectpt2,isectpointA1); }      
01402     }
01403     else
01404     {
01405       if(smallest2==0) { SET(isectpt2,isectpointB2); }
01406       else { SET(isectpt2,isectpointB1); } 
01407     }
01408   }
01409   return 1;
01410 }
01411 
01412 
01413 
01414 
01415 //
01416 // class Triangle3 implementation
01417 //
01418 
01419 
01420 bool Triangle3::intersect(const Triangle3& t) const
01421 {
01422   const Triangle3& t2(*this);
01423 
01424   // C doesn't know about const
01425   Real* t1p1 = const_cast<Real*>(t.p1().c_array());
01426   Real* t1p2 = const_cast<Real*>(t.p2().c_array());
01427   Real* t1p3 = const_cast<Real*>(t.p3().c_array());
01428   Real* t2p1 = const_cast<Real*>(t2.p1().c_array());
01429   Real* t2p2 = const_cast<Real*>(t2.p2().c_array());
01430   Real* t2p3 = const_cast<Real*>(t2.p3().c_array());
01431 
01432   return (bool)NoDivTriTriIsect(t1p1,t1p2,t1p3,
01433                                 t2p1,t2p2,t2p3);
01434 
01435   /* Old code to compute intersection point
01436   const Triangle& t1(*this);
01437   const Triangle& t2(t);
01438   Plane p1(t1);
01439   Int other_side=0;
01440   {
01441     Real f1=p1.classify(t2[1]);
01442     Real f2=p1.classify(t2[2]);
01443     Real f3=p1.classify(t2[3]);
01444     Real f12=f1*f2;
01445     Real f23=f2*f3;
01446     if (f12>0.0 && f23>0.0) return Vector3::zero;
01447     other_side=(f12<0.0?(f23<0.0?1:0):2);
01448   }
01449   Plane p2(t2);
01450   Vector3 n12(p1.normal+p2.normal);
01451   TriangleDesc td2(t2,p2);
01452   const Vector3& a2=td2[other_side+2];
01453   const Vector3& b2=td2[other_side+1];
01454   const Vector3& c2=td2[other_side+3];
01455   Real t21=-(p1.d+p2.d+a2*n12)/((b2-a2)*n12);
01456   TriangleDesc td1(t1,p1);
01457   Vector3 P21(a2+t21*(b2-a2));
01458   if (td1.pointInTri(P21)) return P21;
01459   Real t22=-(p1.d+p2.d+c2*n12)/((b2-c2)*n12);
01460   Vector3 P22(c2+t22*(b2-c2));
01461   if (td1.pointInTri(P22)) return P22;
01462   
01463   {
01464     Real f1=p2.classify(t1[1]);
01465     Real f2=p2.classify(t1[2]);
01466     Real f3=p2.classify(t1[3]);
01467     Real f12=f1*f2;
01468     Real f23=f2*f3;
01469     if (f12>0.0 && f23>0.0) return Vector3::zero;
01470     other_side=(f12<0.0?(f23<0.0?1:0):2);
01471   }
01472   const Vector3& a1=td1[other_side+2];
01473   const Vector3& b1=td1[other_side+1];
01474   const Vector3& c1=td1[other_side+3];
01475   Real t11=-(p1.d+p2.d+a1*n12)/((b1-a1)*n12);
01476   Vector3 P11(a1+t11*(b1-a1));
01477   if (td2.pointInTri(P11)) return P11;
01478   Real t12=-(p1.d+p2.d+c1*n12)/((b1-c1)*n12);
01479   Vector3 P12(c1+t12*(b1-c1));
01480   if (td2.pointInTri(P12)) return P12;
01481   return Point3::zero;
01482   */
01483 }
01484 
01485 
01486 bool Triangle3::contact(const Triangle3& t, Contact& contact) const
01487 {
01488   const Triangle3& t2(*this);
01489 
01490   // C doesn't know about const
01491   Real* t1p1 = const_cast<Real*>(t.p1().c_array());
01492   Real* t1p2 = const_cast<Real*>(t.p2().c_array());
01493   Real* t1p3 = const_cast<Real*>(t.p3().c_array());
01494   Real* t2p1 = const_cast<Real*>(t2.p1().c_array());
01495   Real* t2p2 = const_cast<Real*>(t2.p2().c_array());
01496   Real* t2p3 = const_cast<Real*>(t2.p3().c_array());
01497 
01498   int coplanar = 0;
01499   Point3 i1, i2;
01500   int intersected = tri_tri_intersect_with_isectline(t1p1,t1p2,t1p3,
01501                                                      t2p1,t2p2,t2p3,
01502                                                      &coplanar, 
01503                                                      i1.c_array(), i2.c_array());
01504   if (!intersected) {
01505     contact.type = Contact::None;
01506     return false;
01507   }
01508   
01509     if (!coplanar) {
01510     if (i1.equals(i2)) {
01511       contact.type = Contact::Point;
01512       contact.point = i1;
01513       contact.depth = 0;
01514   }
01515     else {
01516       contact.type = Contact::Segment;
01517       contact.segment = Segment3(i1,i2);
01518       //!!! calculate depth
01519       contact.depth = 0;
01520     }
01521   }
01522   else { // co-planar triangles
01523     
01524     // First check the common case, where one triangle in completely
01525     //  inside the other
01526 
01527     
01528 
01529 
01530   }
01531 
01532   return true;
01533 }

Generated on Thu Jul 29 15:56:20 2004 for OpenSim by doxygen 1.3.6