00001 
00002 
00003 
00004 
00005 
00006 #ifndef _GMTL_INTERSECTION_H_
00007 #define _GMTL_INTERSECTION_H_
00008 
00009 #include <algorithm>
00010 #include <limits>
00011 #include <gmtl/AABox.h>
00012 #include <gmtl/Point.h>
00013 #include <gmtl/Sphere.h>
00014 #include <gmtl/Vec.h>
00015 #include <gmtl/Plane.h>
00016 #include <gmtl/VecOps.h>
00017 #include <gmtl/Math.h>
00018 #include <gmtl/Ray.h>
00019 #include <gmtl/LineSeg.h>
00020 #include <gmtl/Tri.h>
00021 #include <gmtl/PlaneOps.h>
00022 
00023 namespace gmtl
00024 {
00034    template<class DATA_TYPE>
00035    bool intersect(const AABox<DATA_TYPE>& box1, const AABox<DATA_TYPE>& box2)
00036    {
00037       
00038       if (box1.getMin()[0] > box2.getMax()[0])  return false;
00039       if (box1.getMin()[1] > box2.getMax()[1])  return false;
00040       if (box1.getMin()[2] > box2.getMax()[2])  return false;
00041 
00042       if (box2.getMin()[0] > box1.getMax()[0])  return false;
00043       if (box2.getMin()[1] > box1.getMax()[1])  return false;
00044       if (box2.getMin()[2] > box1.getMax()[2])  return false;
00045 
00046       
00047       return true;
00048    }
00049 
00059    template<class DATA_TYPE>
00060    bool intersect( const AABox<DATA_TYPE>& box, const Point<DATA_TYPE, 3>& point )
00061    {
00062       
00063       if (box.getMin()[0] > point[0])  return false;
00064       if (box.getMin()[1] > point[1])  return false;
00065       if (box.getMin()[2] > point[2])  return false;
00066 
00067       if (point[0] > box.getMax()[0])  return false;
00068       if (point[1] > box.getMax()[1])  return false;
00069       if (point[2] > box.getMax()[2])  return false;
00070 
00071       
00072       return true;
00073    }
00074 
00089    template<class DATA_TYPE>
00090    bool intersect( const AABox<DATA_TYPE>& box1, const Vec<DATA_TYPE, 3>& path1,
00091                    const AABox<DATA_TYPE>& box2, const Vec<DATA_TYPE, 3>& path2,
00092                    DATA_TYPE& firstContact, DATA_TYPE& secondContact )
00093    {
00094       
00095       
00096       
00097       
00098 
00099       
00100       Vec<DATA_TYPE, 3> path = path2 - path1;
00101 
00102       
00103       Vec<DATA_TYPE, 3> overlap1(DATA_TYPE(0), DATA_TYPE(0), DATA_TYPE(0));
00104 
00105       
00106       Vec<DATA_TYPE, 3> overlap2(DATA_TYPE(1), DATA_TYPE(1), DATA_TYPE(1));
00107 
00108       
00109       if (gmtl::intersect(box1, box2))
00110       {
00111          firstContact = secondContact = DATA_TYPE(0);
00112          return true;
00113       }
00114 
00115       
00116       for (int i=0; i<3; ++i)
00117       {
00118          if ((box1.getMax()[i] < box2.getMin()[i]) && (path[i] < DATA_TYPE(0)))
00119          {
00120             overlap1[i] = (box1.getMax()[i] - box2.getMin()[i]) / path[i];
00121          }
00122          else if ((box2.getMax()[i] < box1.getMin()[i]) && (path[i] > DATA_TYPE(0)))
00123          {
00124             overlap1[i] = (box1.getMin()[i] - box2.getMax()[i]) / path[i];
00125          }
00126 
00127          if ((box2.getMax()[i] > box1.getMin()[i]) && (path[i] < DATA_TYPE(0)))
00128          {
00129             overlap2[i] = (box1.getMin()[i] - box2.getMax()[i]) / path[i];
00130          }
00131          else if ((box1.getMax()[i] > box2.getMin()[i]) && (path[i] > DATA_TYPE(0)))
00132          {
00133             overlap2[i] = (box1.getMax()[i] - box2.getMin()[i]) / path[i];
00134          }
00135       }
00136 
00137       
00138       firstContact = Math::Max(overlap1[0], overlap1[1], overlap1[2]);
00139 
00140       
00141       secondContact = Math::Min(overlap2[0], overlap2[1], overlap2[2]);
00142 
00143       
00144       
00145       return firstContact <= secondContact;
00146    }
00147 
00163    template<class DATA_TYPE>
00164    bool intersectAABoxRay(const AABox<DATA_TYPE>& box,
00165                           const Ray<DATA_TYPE>& ray, DATA_TYPE& tIn,
00166                           DATA_TYPE& tOut)
00167    {
00168       tIn  = -(std::numeric_limits<DATA_TYPE>::max)();
00169       tOut = (std::numeric_limits<DATA_TYPE>::max)();
00170       DATA_TYPE t0, t1;
00171       const DATA_TYPE epsilon(0.0000001);
00172 
00173       
00174       if ( gmtl::Math::abs(ray.mDir[0]) < epsilon )
00175       {
00176          
00177          if ( ray.mOrigin[0] < box.mMin[0] || ray.mOrigin[0] > box.mMax[0] )
00178          {
00179             return false;
00180          }
00181       }
00182 
00183       
00184       if ( gmtl::Math::abs(ray.mDir[1]) < epsilon )
00185       {
00186          
00187          if ( ray.mOrigin[1] < box.mMin[1] || ray.mOrigin[1] > box.mMax[1] )
00188          {
00189             return false;
00190          }
00191       }
00192 
00193       
00194       if ( gmtl::Math::abs(ray.mDir[2]) < epsilon )
00195       {
00196          
00197          if ( ray.mOrigin[2] < box.mMin[2] || ray.mOrigin[2] > box.mMax[2] )
00198          {
00199             return false;
00200          }
00201       }
00202 
00203       
00204       t0 = (box.mMin[0] - ray.mOrigin[0]) / ray.mDir[0];
00205       t1 = (box.mMax[0] - ray.mOrigin[0]) / ray.mDir[0];
00206 
00207       if ( t0 > t1 )
00208       {
00209          std::swap(t0, t1);
00210       }
00211 
00212       if ( t0 > tIn )
00213       {
00214          tIn = t0;
00215       }
00216       if ( t1 < tOut )
00217       {
00218          tOut = t1;
00219       }
00220 
00221       if ( tIn > tOut || tOut < DATA_TYPE(0) )
00222       {
00223          return false;
00224       }
00225 
00226       
00227       t0 = (box.mMin[1] - ray.mOrigin[1]) / ray.mDir[1];
00228       t1 = (box.mMax[1] - ray.mOrigin[1]) / ray.mDir[1];
00229 
00230       if ( t0 > t1 )
00231       {
00232          std::swap(t0, t1);
00233       }
00234 
00235       if ( t0 > tIn )
00236       {
00237          tIn = t0;
00238       }
00239       if ( t1 < tOut )
00240       {
00241          tOut = t1;
00242       }
00243 
00244       if ( tIn > tOut || tOut < DATA_TYPE(0) )
00245       {
00246          return false;
00247       }
00248 
00249       
00250       t0 = (box.mMin[2] - ray.mOrigin[2]) / ray.mDir[2];
00251       t1 = (box.mMax[2] - ray.mOrigin[2]) / ray.mDir[2];
00252 
00253       if ( t0 > t1 )
00254       {
00255          std::swap(t0, t1);
00256       }
00257 
00258       if ( t0 > tIn )
00259       {
00260          tIn = t0;
00261       }
00262       if ( t1 < tOut )
00263       {
00264          tOut = t1;
00265       }
00266 
00267       if ( tIn > tOut || tOut < DATA_TYPE(0) )
00268       {
00269          return false;
00270       }
00271 
00272       return true;
00273    }
00274 
00283    template<class DATA_TYPE>
00284    bool intersect(const AABox<DATA_TYPE>& box, const LineSeg<DATA_TYPE>& seg,
00285                   unsigned int& numHits, DATA_TYPE& tIn, DATA_TYPE& tOut)
00286    {
00287       numHits = 0;
00288       bool result = intersectAABoxRay(box, seg, tIn, tOut);
00289       if (tIn < 0.0 && tOut > 1.0)
00290       {
00291      return false;
00292       }
00293       if ( result )
00294       {
00295          
00296          
00297          
00298          if ( tIn < DATA_TYPE(0) )
00299          {
00300             numHits = 1;
00301             tIn = tOut;
00302          }
00303          
00304          
00305          
00306          else if ( tOut > DATA_TYPE(1) )
00307          {
00308             numHits = 1;
00309             tOut = tIn;
00310          }
00311          
00312          
00313          else
00314          {
00315             numHits = 2;
00316          }
00317       }
00318 
00319       return result;
00320    }
00321 
00330    template<class DATA_TYPE>
00331    bool intersect(const LineSeg<DATA_TYPE>& seg, const AABox<DATA_TYPE>& box,
00332                   unsigned int& numHits, DATA_TYPE& tIn, DATA_TYPE& tOut)
00333    {
00334       return intersect(box, seg, numHits, tIn, tOut);
00335    }
00336 
00345    template<class DATA_TYPE>
00346    bool intersect(const AABox<DATA_TYPE>& box, const Ray<DATA_TYPE>& ray,
00347                   unsigned int& numHits, DATA_TYPE& tIn, DATA_TYPE& tOut)
00348    {
00349       numHits = 0;
00350 
00351       bool result = intersectAABoxRay(box, ray, tIn, tOut);
00352 
00353       if ( result )
00354       {
00355          
00356          if ( tIn < DATA_TYPE(0) )
00357          {
00358             tIn = tOut;
00359             numHits = 1;
00360          }
00361          else
00362          {
00363             numHits = 2;
00364          }
00365       }
00366 
00367       return result;
00368    }
00369 
00378    template<class DATA_TYPE>
00379    bool intersect(const Ray<DATA_TYPE>& ray, const AABox<DATA_TYPE>& box,
00380                   unsigned int& numHits, DATA_TYPE& tIn, DATA_TYPE& tOut)
00381    {
00382       return intersect(box, ray, numHits, tIn, tOut);
00383    }
00384 
00399    template<class DATA_TYPE>
00400    bool intersect(const Sphere<DATA_TYPE>& sph1, const Vec<DATA_TYPE, 3>& path1,
00401                   const Sphere<DATA_TYPE>& sph2, const Vec<DATA_TYPE, 3>& path2,
00402                   DATA_TYPE& firstContact, DATA_TYPE& secondContact)
00403    {
00404       
00405       
00406       
00407       
00408 
00409       
00410       const Vec<DATA_TYPE, 3> path = path2 - path1;
00411 
00412       
00413       const Vec<DATA_TYPE, 3> start_offset = sph2.getCenter() - sph1.getCenter();
00414 
00415       
00416       const DATA_TYPE radius_sum = sph1.getRadius() + sph2.getRadius();
00417 
00418       
00419       const DATA_TYPE a = dot(path, path);
00420 
00421       
00422       const DATA_TYPE b = DATA_TYPE(2) * dot(path, start_offset);
00423 
00424       
00425       const DATA_TYPE c = dot(start_offset, start_offset) - radius_sum * radius_sum;
00426 
00427       
00428       if (dot(start_offset, start_offset) <= radius_sum * radius_sum)
00429       {
00430          firstContact = secondContact = DATA_TYPE(0);
00431          return true;
00432       }
00433 
00434       
00435       if (Math::quadraticFormula(firstContact, secondContact, a, b, c))
00436       {
00437          
00438          if (firstContact > secondContact)
00439          {
00440             std::swap(firstContact, secondContact);
00441             return true;
00442          }
00443       }
00444 
00445       return false;
00446    }
00447 
00457    template<class DATA_TYPE>
00458    bool intersect(const AABox<DATA_TYPE>& box, const Sphere<DATA_TYPE>& sph)
00459    {
00460       DATA_TYPE dist_sqr = DATA_TYPE(0);
00461 
00462       
00463       for (int i=0; i<3; ++i)
00464       {
00465          if (sph.getCenter()[i] < box.getMin()[i])
00466          {
00467             DATA_TYPE s = sph.getCenter()[i] - box.getMin()[i];
00468             dist_sqr += s*s;
00469          }
00470          else if (sph.getCenter()[i] > box.getMax()[i])
00471          {
00472             DATA_TYPE s = sph.getCenter()[i] - box.getMax()[i];
00473             dist_sqr += s*s;
00474          }
00475       }
00476 
00477       return dist_sqr <= (sph.getRadius()*sph.getRadius());
00478    }
00479 
00489    template<class DATA_TYPE>
00490    bool intersect(const Sphere<DATA_TYPE>& sph, const AABox<DATA_TYPE>& box)
00491    {
00492       return gmtl::intersect(box, sph);
00493    }
00494 
00501    template<class DATA_TYPE>
00502    bool intersect( const Sphere<DATA_TYPE>& sphere, const Point<DATA_TYPE, 3>& point )
00503    {
00504       gmtl::Vec<DATA_TYPE, 3> offset = point - sphere.getCenter();
00505       DATA_TYPE dist = lengthSquared( offset ) - sphere.getRadius() * sphere.getRadius();
00506 
00507       
00508       return  dist <= 0;
00509    }
00510 
00521    template<typename T>
00522    inline bool intersect( const Sphere<T>& sphere, const Ray<T>& ray, int& numhits, T& t0, T& t1 )
00523    {
00524       numhits = -1;
00525 
00526       
00527       const Vec<T, 3> offset = ray.getOrigin() - sphere.getCenter();
00528       const T a = lengthSquared( ray.getDir() );
00529       const T b = dot( offset, ray.getDir() );
00530       const T c = lengthSquared( offset ) - sphere.getRadius() * sphere.getRadius();
00531 
00532 
00533 
00534       
00535       const T discriminant = b * b - a * c;
00536       if (discriminant < 0.0f)
00537       {
00538          numhits = 0;
00539          return false;
00540       }
00541       else if (discriminant > 0.0f)
00542       {
00543          T root = Math::sqrt( discriminant );
00544          T invA = T(1) / a;
00545          t0 = (-b - root) * invA;
00546          t1 = (-b + root) * invA;
00547 
00548          
00549 
00550          if (t0 >= T(0))
00551          {
00552             numhits = 2;
00553             return true;
00554          }
00555          else if (t1 >= T(0))
00556          {
00557             numhits = 1;
00558             t0 = t1;
00559             return true;
00560          }
00561          else
00562          {
00563             numhits = 0;
00564             return false;
00565          }
00566       }
00567       else
00568       {
00569          t0 = -b / a;
00570          if (t0 >= T(0))
00571          {
00572             numhits = 1;
00573             return true;
00574          }
00575          else
00576          {
00577             numhits = 0;
00578             return false;
00579          }
00580       }
00581    }
00582 
00589    template<typename T>
00590    inline bool intersect( const Sphere<T>& sphere, const LineSeg<T>& lineseg, int& numhits, T& t0, T& t1 )
00591    {
00592       if (intersect( sphere, Ray<T>( lineseg ), numhits, t0, t1 ))
00593       {
00594          
00595          while (0 < numhits && 1.0f < t0)
00596          {
00597             --numhits;
00598             t0 = t1;
00599          }
00600          if (2 == numhits && 1.0f < t1)
00601          {
00602             --numhits;
00603          }
00604          return 0 < numhits;
00605       }
00606       else
00607       {
00608          return false;
00609       }
00610    }
00611 
00622    template<typename T>
00623    inline bool intersectVolume( const Sphere<T>& sphere, const LineSeg<T>& ray, int& numhits, T& t0, T& t1 )
00624    {
00625       bool result = intersect( sphere, ray, numhits, t0, t1 );
00626       if (result && numhits == 2)
00627       {
00628          return true;
00629       }
00630       
00631       
00632       
00633       else 
00634       {
00635          const T rsq = sphere.getRadius() * sphere.getRadius();
00636          const Vec<T, 3> dist = ray.getOrigin() - sphere.getCenter();
00637          const T a = lengthSquared( dist ) - rsq;
00638          const T b = lengthSquared( gmtl::Vec<T,3>(dist + ray.getDir()) ) - rsq;
00639 
00640          bool inside1 = a <= T( 0 );
00641          bool inside2 = b <= T( 0 );
00642 
00643          
00644          if (numhits == 1 && inside1 && !inside2)
00645          {
00646             t1 = t0;
00647             t0 = T(0);
00648             numhits = 2;
00649             return true;
00650          }
00651          else if (numhits == 1 && !inside1 && inside2)
00652          {
00653             t1 = T(1);
00654             numhits = 2;
00655             return true;
00656          }
00657          
00658          else if (inside1 && inside2) 
00659          {
00660             t0 = T(0);
00661             t1 = T(1);
00662             numhits = 2;
00663             return true;
00664          }
00665       }
00666       return result;
00667    }
00668 
00679    template<typename T>
00680    inline bool intersectVolume( const Sphere<T>& sphere, const Ray<T>& ray, int& numhits, T& t0, T& t1 )
00681    {
00682       bool result = intersect( sphere, ray, numhits, t0, t1 );
00683       if (result && numhits == 2)
00684       {
00685          return true;
00686       }
00687       else
00688       {
00689          const T rsq = sphere.getRadius() * sphere.getRadius();
00690          const Vec<T, 3> dist = ray.getOrigin() - sphere.getCenter();
00691          const T a = lengthSquared( dist ) - rsq;
00692 
00693          bool inside = a <= T( 0 );
00694 
00695          
00696          if (inside)
00697          {
00698             t1 = t0;
00699             t0 = T(0);
00700             numhits = 2;
00701             return true;
00702          }
00703       }
00704       return result;
00705    }
00706 
00718    template<class DATA_TYPE>
00719    bool intersect( const Plane<DATA_TYPE>& plane, const Ray<DATA_TYPE>& ray, DATA_TYPE& t )
00720    {
00721       const DATA_TYPE eps(0.00001f);
00722 
00723       
00724       Vec<DATA_TYPE, 3> N( plane.getNormal() );
00725       DATA_TYPE denom( dot(N,ray.getDir()) );
00726       if(gmtl::Math::abs(denom) < eps)    
00727       {
00728          t = 0;
00729          if(distance(plane, ray.mOrigin) < eps)     
00730          { return true; }
00731          else
00732          { return false; }
00733       }
00734       t = dot( N, Vec<DATA_TYPE,3>(N * plane.getOffset() - ray.getOrigin()) ) / denom;
00735 
00736       return (DATA_TYPE)0 <= t;
00737    }
00738 
00749    template<class DATA_TYPE>
00750    bool intersect( const Plane<DATA_TYPE>& plane, const LineSeg<DATA_TYPE>& seg, DATA_TYPE& t )
00751    {
00752       bool res(intersect(plane, static_cast<Ray<DATA_TYPE> >(seg), t));
00753       return res && t <= (DATA_TYPE)1.0;
00754    }
00755 
00768    template<class DATA_TYPE>
00769    bool intersect( const Tri<DATA_TYPE>& tri, const Ray<DATA_TYPE>& ray,
00770                         float& u, float& v, float& t )
00771    {
00772       const float EPSILON = (DATA_TYPE)0.00001f;
00773       Vec<DATA_TYPE, 3> edge1, edge2, tvec, pvec, qvec;
00774       float det,inv_det;
00775 
00776       
00777       edge1 = tri[1] - tri[0];
00778       edge2 = tri[2] - tri[0];
00779 
00780       
00781       gmtl::cross( pvec, ray.getDir(), edge2 );
00782 
00783       
00784       det = gmtl::dot( edge1, pvec );
00785 
00786       if (det < EPSILON)
00787          return false;
00788 
00789       
00790       tvec = ray.getOrigin() - tri[0];
00791 
00792       
00793       u = gmtl::dot( tvec, pvec );
00794       if (u < 0.0 || u > det)
00795          return false;
00796 
00797       
00798       gmtl::cross( qvec, tvec, edge1 );
00799 
00800       
00801       v = gmtl::dot( ray.getDir(), qvec );
00802       if (v < 0.0 || u + v > det)
00803          return false;
00804 
00805       
00806       t = gmtl::dot( edge2, qvec );
00807       inv_det = ((DATA_TYPE)1.0) / det;
00808       t *= inv_det;
00809       u *= inv_det;
00810       v *= inv_det;
00811 
00812       
00813       return t >= (DATA_TYPE)0;
00814    }
00815 
00832    template<class DATA_TYPE>
00833    bool intersectDoubleSided(const Tri<DATA_TYPE>& tri, const Ray<DATA_TYPE>& ray,
00834                              DATA_TYPE& u, DATA_TYPE& v, DATA_TYPE& t)
00835    {
00836       const DATA_TYPE EPSILON = (DATA_TYPE)0.00001f;
00837       Vec<DATA_TYPE, 3> edge1, edge2, tvec, pvec, qvec;
00838       DATA_TYPE det, inv_det;
00839 
00840       
00841       edge1 = tri[1] - tri[0];
00842       edge2 = tri[2] - tri[0];
00843 
00844       
00845       gmtl::cross(pvec, ray.getDir(), edge2);
00846 
00847       
00848       det = gmtl::dot( edge1, pvec );
00849 
00850       if ( det < EPSILON && det > -EPSILON )
00851       {
00852          return false;
00853       }
00854 
00855       
00856       tvec = ray.getOrigin() - tri[0];
00857 
00858       
00859       inv_det = ((DATA_TYPE)1.0) / det; 
00860 
00861       
00862       u =  inv_det * gmtl::dot(tvec, pvec);
00863       if ( u < 0.0 || u > 1.0 )
00864       {
00865          return false;
00866       }
00867 
00868       
00869       gmtl::cross(qvec, tvec, edge1);
00870 
00871       
00872       v = inv_det * gmtl::dot(ray.getDir(), qvec);
00873       if (v < 0.0 || u + v > 1.0)
00874       {
00875          return false;
00876       }
00877 
00878       
00879       t = inv_det * gmtl::dot(edge2, qvec);
00880 
00881       
00882       return t >= (DATA_TYPE)0;
00883    }
00884 
00897    template<class DATA_TYPE>
00898    bool intersect( const Tri<DATA_TYPE>& tri, const LineSeg<DATA_TYPE>& lineseg,
00899                    DATA_TYPE& u, DATA_TYPE& v, DATA_TYPE& t )
00900    {
00901       const DATA_TYPE eps = (DATA_TYPE)0.0001010101;
00902       DATA_TYPE l = length( lineseg.getDir() );
00903       if (eps < l)
00904       {
00905          Ray<DATA_TYPE> temp( lineseg.getOrigin(), lineseg.getDir() );
00906          bool result = intersect( tri, temp, u, v, t );
00907          return result && t <= (DATA_TYPE)1.0;
00908       }
00909       else
00910       {  return false; }
00911    }
00912 }
00913 
00914 
00915 
00916 #endif