00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef _GMTL_INTERSECTION_H_
00036 #define _GMTL_INTERSECTION_H_
00037
00038 #include <algorithm>
00039 #include <gmtl/AABox.h>
00040 #include <gmtl/Point.h>
00041 #include <gmtl/Sphere.h>
00042 #include <gmtl/Vec.h>
00043 #include <gmtl/Plane.h>
00044 #include <gmtl/VecOps.h>
00045 #include <gmtl/Math.h>
00046 #include <gmtl/Ray.h>
00047 #include <gmtl/LineSeg.h>
00048 #include <gmtl/Tri.h>
00049
00050 namespace gmtl
00051 {
00061 template<class DATA_TYPE>
00062 bool intersect(const AABox<DATA_TYPE>& box1, const AABox<DATA_TYPE>& box2)
00063 {
00064
00065 if (box1.getMin()[0] > box2.getMax()[0]) return false;
00066 if (box1.getMin()[1] > box2.getMax()[1]) return false;
00067 if (box1.getMin()[2] > box2.getMax()[2]) return false;
00068
00069 if (box2.getMin()[0] > box1.getMax()[0]) return false;
00070 if (box2.getMin()[1] > box1.getMax()[1]) return false;
00071 if (box2.getMin()[2] > box1.getMax()[2]) return false;
00072
00073
00074 return true;
00075 }
00076
00086 template<class DATA_TYPE>
00087 bool intersect( const AABox<DATA_TYPE>& box, const Point<DATA_TYPE, 3>& point )
00088 {
00089
00090 if (box.getMin()[0] > point[0]) return false;
00091 if (box.getMin()[1] > point[1]) return false;
00092 if (box.getMin()[2] > point[2]) return false;
00093
00094 if (point[0] > box.getMax()[0]) return false;
00095 if (point[1] > box.getMax()[1]) return false;
00096 if (point[2] > box.getMax()[2]) return false;
00097
00098
00099 return true;
00100 }
00101
00116 template<class DATA_TYPE>
00117 bool intersect( const AABox<DATA_TYPE>& box1, const Vec<DATA_TYPE, 3>& path1,
00118 const AABox<DATA_TYPE>& box2, const Vec<DATA_TYPE, 3>& path2,
00119 DATA_TYPE& firstContact, DATA_TYPE& secondContact )
00120 {
00121
00122
00123
00124
00125
00126
00127 Vec<DATA_TYPE, 3> path = path2 - path1;
00128
00129
00130 Vec<DATA_TYPE, 3> overlap1(DATA_TYPE(0), DATA_TYPE(0), DATA_TYPE(0));
00131
00132
00133 Vec<DATA_TYPE, 3> overlap2(DATA_TYPE(1), DATA_TYPE(1), DATA_TYPE(1));
00134
00135
00136 if (intersect(box1, box2))
00137 {
00138 firstContact = secondContact = DATA_TYPE(0);
00139 return true;
00140 }
00141
00142
00143 for (int i=0; i<3; ++i)
00144 {
00145 if ((box1.getMax()[i] < box2.getMin()[i]) && (path[i] < DATA_TYPE(0)))
00146 {
00147 overlap1[i] = (box1.getMax()[i] - box2.getMin()[i]) / path[i];
00148 }
00149 else if ((box2.getMax()[i] < box1.getMin()[i]) && (path[i] > DATA_TYPE(0)))
00150 {
00151 overlap1[i] = (box1.getMin()[i] - box2.getMax()[i]) / path[i];
00152 }
00153
00154 if ((box2.getMax()[i] > box1.getMin()[i]) && (path[i] < DATA_TYPE(0)))
00155 {
00156 overlap2[i] = (box1.getMin()[i] - box2.getMax()[i]) / path[i];
00157 }
00158 else if ((box1.getMax()[i] > box2.getMin()[i]) && (path[i] > DATA_TYPE(0)))
00159 {
00160 overlap2[i] = (box1.getMax()[i] - box2.getMin()[i]) / path[i];
00161 }
00162 }
00163
00164
00165 firstContact = Math::Max(overlap1[0], overlap1[1], overlap1[2]);
00166
00167
00168 secondContact = Math::Min(overlap2[0], overlap2[1], overlap2[2]);
00169
00170
00171
00172 return firstContact <= secondContact;
00173 }
00174
00189 template<class DATA_TYPE>
00190 bool intersect(const Sphere<DATA_TYPE>& sph1, const Vec<DATA_TYPE, 3>& path1,
00191 const Sphere<DATA_TYPE>& sph2, const Vec<DATA_TYPE, 3>& path2,
00192 DATA_TYPE& firstContact, DATA_TYPE& secondContact)
00193 {
00194
00195
00196
00197
00198
00199
00200 const Vec<DATA_TYPE, 3> path = path2 - path1;
00201
00202
00203 const Vec<DATA_TYPE, 3> start_offset = sph2.getCenter() - sph1.getCenter();
00204
00205
00206 const DATA_TYPE radius_sum = sph1.getRadius() + sph2.getRadius();
00207
00208
00209 const DATA_TYPE a = dot(path, path);
00210
00211
00212 const DATA_TYPE b = DATA_TYPE(2) * dot(path, start_offset);
00213
00214
00215 const DATA_TYPE c = dot(start_offset, start_offset) - radius_sum * radius_sum;
00216
00217
00218 if (dot(start_offset, start_offset) <= radius_sum * radius_sum)
00219 {
00220 firstContact = secondContact = DATA_TYPE(0);
00221 return true;
00222 }
00223
00224
00225 if (Math::quadraticFormula(firstContact, secondContact, a, b, c))
00226 {
00227
00228 if (firstContact > secondContact)
00229 {
00230 std::swap(firstContact, secondContact);
00231 return true;
00232 }
00233 }
00234
00235 return false;
00236 }
00237
00247 template<class DATA_TYPE>
00248 bool intersect(const AABox<DATA_TYPE>& box, const Sphere<DATA_TYPE>& sph)
00249 {
00250 DATA_TYPE dist_sqr = DATA_TYPE(0);
00251
00252
00253 for (int i=0; i<3; ++i)
00254 {
00255 if (sph.getCenter()[i] < box.getMin()[i])
00256 {
00257 DATA_TYPE s = sph.getCenter()[i] - box.getMin()[i];
00258 dist_sqr += s*s;
00259 }
00260 else if (sph.getCenter()[i] > box.getMax()[i])
00261 {
00262 DATA_TYPE s = sph.getCenter()[i] - box.getMax()[i];
00263 dist_sqr += s*s;
00264 }
00265 }
00266
00267 return dist_sqr <= (sph.getRadius()*sph.getRadius());
00268 }
00269
00279 template<class DATA_TYPE>
00280 bool intersect(const Sphere<DATA_TYPE>& sph, const AABox<DATA_TYPE>& box)
00281 {
00282 return intersect(box, sph);
00283 }
00284
00291 template<class DATA_TYPE>
00292 bool intersect( const Sphere<DATA_TYPE>& sphere, const Point<DATA_TYPE, 3>& point )
00293 {
00294 gmtl::Vec<DATA_TYPE, 3> offset = point - sphere.getCenter();
00295 DATA_TYPE dist = lengthSquared( offset ) - sphere.getRadius() * sphere.getRadius();
00296
00297
00298 return dist <= 0;
00299 }
00300
00310 template<typename T>
00311 inline bool intersect( const Sphere<T>& sphere, const Ray<T>& ray, int& numhits, float& t0, float& t1 )
00312 {
00313 numhits = -1;
00314
00315
00316 Vec<T, 3> offset = ray.getOrigin() - sphere.getCenter();
00317 T a = lengthSquared( ray.getDir() );
00318 T b = dot( offset, ray.getDir() );
00319 T c = lengthSquared( offset ) - sphere.getRadius() * sphere.getRadius();
00320
00321
00322 T discriminant = b * b - a * c;
00323 if (discriminant < 0.0f)
00324 {
00325 numhits = 0;
00326 return false;
00327 }
00328 else if (discriminant > 0.0f)
00329 {
00330 T root = Math::sqrt( discriminant );
00331 T invA = T(1) / a;
00332 t0 = (-b - root) * invA;
00333 t1 = (-b + root) * invA;
00334
00335
00336
00337 if (t0 >= T(0))
00338 {
00339 numhits = 2;
00340 return true;
00341 }
00342 else if (t1 >= 0.0f)
00343 {
00344 numhits = 1;
00345 t0 = t1;
00346 return true;
00347 }
00348 else
00349 {
00350 numhits = 0;
00351 return false;
00352 }
00353 }
00354 else
00355 {
00356 t0 = -b / a;
00357 if (t0 >= T(0))
00358 {
00359 numhits = 1;
00360 return true;
00361 }
00362 else
00363 {
00364 numhits = 0;
00365 return false;
00366 }
00367 }
00368 }
00369
00370
00371
00372
00373
00374
00375 template<typename T>
00376 inline bool intersect( const Sphere<T>& sphere, const LineSeg<T>& lineseg, int& numhits, float& t0, float& t1 )
00377 {
00378 if (intersect( sphere, Ray<T>( lineseg ), numhits, t0, t1 ))
00379 {
00380
00381 while (0 < numhits && 1.0f < t0)
00382 {
00383 --numhits;
00384 t0 = t1;
00385 }
00386 if (2 == numhits && 1.0f < t1)
00387 {
00388 --numhits;
00389 }
00390 return 0 < numhits;
00391 }
00392 else
00393 {
00394 return false;
00395 }
00396 }
00397
00408 template<class DATA_TYPE>
00409 bool intersect( const Plane<DATA_TYPE>& plane, const Ray<DATA_TYPE>& ray, DATA_TYPE& t )
00410 {
00411 Vec<DATA_TYPE, 3> N( plane.getNormal() );
00412 t = dot( N, N * plane.getOffset() - ray.getOrigin() ) / dot( N, ray.getDir() );
00413 return (DATA_TYPE)0 <= t && t <= (DATA_TYPE)1.0;
00414 }
00415
00428 template<class DATA_TYPE>
00429 bool intersect( const Tri<DATA_TYPE>& tri, const Ray<DATA_TYPE>& ray,
00430 float& u, float& v, float& t )
00431 {
00432 const float EPSILON = (DATA_TYPE)0.00001;
00433 Vec<DATA_TYPE, 3> edge1, edge2, tvec, pvec, qvec;
00434 float det,inv_det;
00435
00436
00437 edge1 = tri[1] - tri[0];
00438 edge2 = tri[2] - tri[0];
00439
00440
00441 gmtl::cross( pvec, ray.getDir(), edge2 );
00442
00443
00444 det = gmtl::dot( edge1, pvec );
00445
00446 if (det < EPSILON)
00447 return false;
00448
00449
00450 tvec = ray.getOrigin() - tri[0];
00451
00452
00453 u = gmtl::dot( tvec, pvec );
00454 if (u < 0.0 || u > det)
00455 return false;
00456
00457
00458 gmtl::cross( qvec, tvec, edge1 );
00459
00460
00461 v = gmtl::dot( ray.getDir(), qvec );
00462 if (v < 0.0 || u + v > det)
00463 return false;
00464
00465
00466 t = gmtl::dot( edge2, qvec );
00467 inv_det = ((DATA_TYPE)1.0) / det;
00468 t *= inv_det;
00469 u *= inv_det;
00470 v *= inv_det;
00471
00472
00473 return t >= (DATA_TYPE)0;
00474 }
00475
00488 template<class DATA_TYPE>
00489 bool intersect( const Tri<DATA_TYPE>& tri, const LineSeg<DATA_TYPE>& lineseg,
00490 float& u, float& v, float& t )
00491 {
00492 const DATA_TYPE eps = (DATA_TYPE)0.0001010101;
00493 DATA_TYPE l = length( lineseg.getDir() );
00494 if (eps < l)
00495 {
00496 Ray<DATA_TYPE> temp( lineseg.getOrigin(), lineseg.getDir() / l );
00497 bool result = intersect( tri, temp, u, v, t );
00498 t /= lineseg.getLength();
00499 return result && t <= (DATA_TYPE)1.0;
00500 }
00501 else
00502 return false;
00503 }
00504 }
00505
00506
00507
00508 #endif