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