00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <utility>
00021 #include <cfloat>
00022
00023 #include <archon/math/quartic_solve.H>
00024 #include <archon/math/geometry.H>
00025
00026 using namespace std;
00027
00028 namespace Archon
00029 {
00030 namespace Math
00031 {
00032 bool intersect(const Ray3 &ray, const Plane3 &plane, bool frontToBackOnly, double *dist)
00033 {
00034 double k = dot(plane.normal, ray.direction);
00035 if(k == 0 || k > 0 && frontToBackOnly) return false;
00036 if(dist)
00037 {
00038 k = (plane.dist + dot(plane.normal, ray.origin)) / -k;
00039 if(k <= 0) return false;
00040
00041
00042 *dist = k;
00043 }
00044 return true;
00045 }
00046
00047 int intersect(const Ray3 &ray, const Box3 &box, double &dist)
00048 {
00049
00050 if(ray.direction[0] == 0 &&
00051 (ray.origin[0] <= box.lowerCorner[0] ||
00052 ray.origin[0] >= box.upperCorner[0])) return 0;
00053 double distNear = (box.lowerCorner[0] - ray.origin[0]) / ray.direction[0];
00054 double distFar = (box.upperCorner[0] - ray.origin[0]) / ray.direction[0];
00055 int whereNear = 1;
00056 int whereFar = 2;
00057 if(distNear > distFar)
00058 {
00059 swap(distNear, distFar);
00060 swap(whereNear, whereFar);
00061 }
00062 if(distFar <= 0) return 0;
00063
00064
00065 if(ray.direction[1] == 0 &&
00066 (ray.origin[1] <= box.lowerCorner[1] ||
00067 ray.origin[1] >= box.upperCorner[1])) return 0;
00068 double d1 = (box.lowerCorner[1] - ray.origin[1]) / ray.direction[1];
00069 double d2 = (box.upperCorner[1] - ray.origin[1]) / ray.direction[1];
00070 int w1 = 3;
00071 int w2 = 4;
00072 if(d1 > d2)
00073 {
00074 swap(d1, d2);
00075 swap(w1, w2);
00076 }
00077 if(d1 > distNear)
00078 {
00079 distNear = d1;
00080 whereNear = w1;
00081 }
00082 if(d2 < distFar)
00083 {
00084 distFar = d2;
00085 whereFar = w2;
00086 }
00087 if(distFar <= 0 || distNear >= distFar) return 0;
00088
00089
00090 if(ray.direction[2] == 0 &&
00091 (ray.origin[2] <= box.lowerCorner[2] ||
00092 ray.origin[2] >= box.upperCorner[2])) return 0;
00093 d1 = (box.lowerCorner[2] - ray.origin[2]) / ray.direction[2];
00094 d2 = (box.upperCorner[2] - ray.origin[2]) / ray.direction[2];
00095 w1 = 5;
00096 w2 = 6;
00097 if(d1 > d2)
00098 {
00099 swap(d1, d2);
00100 swap(w1, w2);
00101 }
00102 if(d1 > distNear)
00103 {
00104 distNear = d1;
00105 whereNear = w1;
00106 }
00107 if(d2 < distFar)
00108 {
00109 distFar = d2;
00110 whereFar = w2;
00111 }
00112 if(distFar <= 0 || distNear >= distFar) return 0;
00113
00114
00115 if(distNear <= 0) return 0;
00116
00117 dist = distNear;
00118 return whereNear;
00119 }
00120
00121 bool intersect(const Ray3 &ray, const Sphere3 &sphere, double &dist)
00122 {
00123 Vector3 rp = ray.origin;
00124 rp -= sphere.center;
00125 const double b = -dot(ray.direction, ray.origin);
00126 if(b <= 0) return false;
00127 const double a = ray.direction.squareSum();
00128 const double c = ray.origin.squareSum() - sphere.radius * sphere.radius;
00129 if(c <= 0) return false;
00130 const double d = b*b - a*c;
00131 if(d < 0) return false;
00132 dist = (b - sqrt(d)) / a;
00133 return true;
00134 }
00135
00136 int intersectCylinder(const Ray3 &ray, double height, double radius,
00137 double &dist, bool side, bool top, bool bottom,
00138 bool enterOnly)
00139 {
00140 const Vector3 rd = ray.direction;
00141 const Vector3 rp = ray.origin;
00142 const double a = 2 * (rd[0] * rd[0] + rd[2] * rd[2]);
00143 const double b = -2 * (rd[0] * rp[0] + rd[2] * rp[2]);
00144 const double c = (rp[0] * rp[0] + rp[2] * rp[2]) - radius * radius;
00145 const double d = b * b - 2 * a * c;
00146
00147 if(d < 0) return 0;
00148
00149 const double sqrt_d = sqrt(d);
00150
00151
00152 const double t = a==0 ? -numeric_limits<double>::max() : (b - sqrt_d) / a;
00153
00154
00155 const double h = height/2;
00156
00157 if(h>=0)
00158 {
00159 const double y = rp[1] + rd[1] * t;
00160
00161
00162
00163 if(y < -h)
00164 {
00165 const double t2 = a==0 ? numeric_limits<double>::max() : (b + sqrt_d) / a;
00166 if(t2 <= 0) return 0;
00167 const double y2 = rp[1] + t2 * rd[1];
00168 if(y2 < -h) return 0;
00169 if(bottom)
00170 {
00171 if(rp[1] < -h)
00172 {
00173
00174 dist = (-h - rp[1]) / rd[1];
00175 return 2;
00176 }
00177 }
00178 if(enterOnly) return 0;
00179
00180 if(y2 <= h)
00181 {
00182 if(!side) return 0;
00183
00184 dist = t2;
00185 return 1;
00186 }
00187 if(!top || rp[1] >= h) return 0;
00188
00189 dist = (h - rp[1]) / rd[1];
00190 return 3;
00191 }
00192
00193
00194
00195 if(y > h)
00196 {
00197 const double t2 = a==0 ? numeric_limits<double>::max() : (b + sqrt_d) / a;
00198 if(t2 <= 0) return 0;
00199 const double y2 = rp[1] + t2 * rd[1];
00200 if(y2 > h) return 0;
00201 if(top)
00202 {
00203 if(rp[1] > h)
00204 {
00205
00206 dist = (h - rp[1]) / rd[1];
00207 return 3;
00208 }
00209 }
00210 if(enterOnly) return 0;
00211
00212 if(y2 >= -h)
00213 {
00214 if(!side) return 0;
00215
00216 dist = t2;
00217 return 1;
00218 }
00219 if(!bottom || rp[1] <= -h) return 0;
00220
00221 dist = (-h - rp[1]) / rd[1];
00222 return 2;
00223 }
00224 }
00225
00226
00227
00228
00229 if(side && t>0)
00230 {
00231
00232 dist = t;
00233 return 1;
00234 }
00235
00236 if(enterOnly) return 0;
00237
00238 const double t2 = a==0 ? numeric_limits<double>::max() : (b + sqrt_d) / a;
00239 if(t2 <= 0) return 0;
00240 if(h>=0)
00241 {
00242 const double y2 = rp[1] + t2 * rd[1];
00243 if(y2 < -h)
00244 {
00245 if(!bottom || rp[1] <= -h) return 0;
00246
00247 dist = (-h - rp[1]) / rd[1];
00248 return 2;
00249 }
00250 if(y2 > h)
00251 {
00252 if(!top || rp[1] >= h) return 0;
00253
00254 dist = (h - rp[1]) / rd[1];
00255 return 3;
00256 }
00257 }
00258
00259 if(!side) return 0;
00260
00261
00262 dist = t2;
00263 return 1;
00264 }
00265
00266 int intersectCone(const Ray3 &ray, double height, double bottomRadius,
00267 double &dist, bool side, bool bottom,
00268 bool enterOnly)
00269 {
00270 Vector3 rd = ray.direction;
00271 Vector3 rp = ray.origin;
00272
00273
00274
00275
00276
00277 rp[1] = (0.5 - rp[1]/height) * bottomRadius;
00278 rd[1] = - rd[1]/height * bottomRadius;
00279
00280 double a = 2 * (rd[0] * rd[0] + rd[2] * rd[2] - rd[1] * rd[1]);
00281 double b = -2 * (rd[0] * rp[0] + rd[2] * rp[2] - rd[1] * rp[1]);
00282 double c = rp[0] * rp[0] + rp[2] * rp[2] - rp[1] * rp[1];
00283
00284 if(a > 0)
00285 {
00286 double d = b * b - 2 * a * c;
00287
00288 if(d < 0) return 0;
00289
00290 double sqrt_d = sqrt(d);
00291
00292
00293 double t = (b - sqrt_d) / a;
00294
00295
00296 double y = rp[1] + rd[1] * t;
00297
00298
00299
00300
00301
00302
00303 if(y < 0) return 0;
00304
00305
00306
00307 if(y > bottomRadius)
00308 {
00309 double t2 = (b + sqrt_d) / a;
00310 if(t2 <= 0) return 0;
00311 double y2 = rp[1] + t2 * rd[1];
00312 if(y2 > bottomRadius) return 0;
00313
00314
00315 if(bottom)
00316 {
00317 if(rp[1] > bottomRadius)
00318 {
00319
00320 dist = (bottomRadius - rp[1]) / rd[1];
00321 return 2;
00322 }
00323 }
00324
00325 if(enterOnly || !side) return 0;
00326
00327 dist = t2;
00328 return 1;
00329 }
00330
00331
00332
00333
00334 if(side)
00335 {
00336 if(t>0)
00337 {
00338
00339 dist = t;
00340 return 1;
00341 }
00342 }
00343 if(enterOnly) return 0;
00344
00345 double t2 = (b + sqrt_d) / a;
00346 if(t2 <= 0) return 0;
00347 double y2 = rp[1] + t2 * rd[1];
00348 if(y2 > bottomRadius)
00349 {
00350
00351 if(!bottom || rp[1] >= bottomRadius) return 0;
00352
00353 dist = (bottomRadius - rp[1]) / rd[1];
00354 return 2;
00355 }
00356
00357 if(!side) return 0;
00358
00359
00360 dist = t2;
00361 return 1;
00362 }
00363
00364
00365
00366
00367 if(rd[1] > 0)
00368 {
00369
00370
00371 double t;
00372
00373 if(a == 0)
00374 {
00375 if(b < 0) return 0;
00376 if(b == 0)
00377 {
00378 if(c != 0) return 0;
00379 t = -rp[1] / rd[1];
00380 }
00381 else t = c / b;
00382 }
00383 else t = (b - sqrt(b * b - 2 * a * c)) / a;
00384
00385 if(t <= 0)
00386 {
00387
00388 if(rp[1] >= bottomRadius) return 0;
00389 }
00390 else
00391 {
00392 double y = rp[1] + rd[1] * t;
00393 if(y > bottomRadius) return 0;
00394 if(side)
00395 {
00396 dist = t;
00397 return 1;
00398 }
00399 }
00400
00401
00402 if(enterOnly || !bottom) return 0;
00403 dist = (bottomRadius - rp[1]) / rd[1];
00404 return 2;
00405 }
00406
00407
00408
00409
00410 double t;
00411
00412 if(a == 0)
00413 {
00414 if(b > 0) return 0;
00415 if(b == 0)
00416 {
00417 if(c != 0) return 0;
00418 t = -rp[1] / rd[1];
00419 }
00420 else t = c / b;
00421 }
00422 else t = (b + sqrt(b * b - 2 * a * c)) / a;
00423
00424 if(t <= 0) return 0;
00425 double y = rp[1] + rd[1] * t;
00426 if(y > bottomRadius) return 0;
00427 if(rp[1] > bottomRadius && bottom)
00428 {
00429 dist = (bottomRadius - rp[1]) / rd[1];
00430 return 2;
00431 }
00432
00433 if(enterOnly || !side) return 0;
00434 dist = t;
00435 return 1;
00436 }
00437
00531 bool intersectTorus(const Ray3 &ray, double majorRadius, double minorRadius,
00532 double &dist, bool surfaceOrigin, bool extToIntOnly)
00533 {
00534 const double l = ray.direction.length();
00535 Vector3 d = ray.direction;
00536 d /= l;
00537 const Vector3 &p = ray.origin;
00538
00539 const double spx = p[0]*p[0];
00540 const double spy = p[1]*p[1];
00541 const double spz = p[2]*p[2];
00542
00543 const double dpx = d[0]*p[0];
00544 const double dpy = d[1]*p[1];
00545 const double dpz = d[2]*p[2];
00546
00547 const double dp = dpx + dpy + dpz;
00548
00549 const double sma = majorRadius*majorRadius;
00550
00551 const double a = spx + spy + spz - minorRadius*minorRadius;
00552 const double b = a + sma;
00553
00554 const double k3 = 4*dp;
00555 const double k2 = 2*(2*dp*dp + a - sma*(1 - 2*d[1]*d[1]));
00556 const double k1 = 4*(dp*a - sma*(dp - 2*dpy));
00557 const double k0 = b*b - 4*sma*(spx + spz);
00558
00559
00560
00561 double roots[4];
00562 const int numberOfRealRoots =
00563 Math::quarticSolve(k3, k2, k1, k0, roots);
00564
00565 if(numberOfRealRoots == 0) return false;
00566
00567
00568
00569 if(surfaceOrigin)
00570 {
00571 int minAbs = -1;
00572 for(int i=0; i<numberOfRealRoots; ++i)
00573 if(minAbs == -1 || fabs(roots[i]) < fabs(roots[minAbs])) minAbs = i;
00574 roots[minAbs] = 0;
00575 }
00576
00577
00578 int numberOfPositiveRoots = 0;
00579 for(int i=0; i<numberOfRealRoots; ++i)
00580 if(roots[i] > 0) roots[numberOfPositiveRoots++] = roots[i];
00581
00582 if(numberOfPositiveRoots == 0) return false;
00583
00584 if(extToIntOnly)
00585 {
00586 switch(numberOfPositiveRoots)
00587 {
00588 case 1:
00589 return false;
00590 case 2:
00591 dist = min(roots[0], roots[1]) / l;
00592 return true;
00593 case 3:
00594
00595 if(roots[0] > roots[1]) swap(roots[0], roots[1]);
00596 dist = (roots[2] < roots[0] ? roots[0] :
00597 roots[2] > roots[1] ? roots[1] : roots[2]) / l;
00598 return true;
00599 }
00600 }
00601 else
00602 {
00603 switch(numberOfPositiveRoots)
00604 {
00605 case 1:
00606 dist = roots[0] / l;
00607 return true;
00608 case 2:
00609 dist = min(roots[0], roots[1]) / l;
00610 return true;
00611 case 3:
00612 dist = min(min(roots[0], roots[1]), roots[2]) / l;
00613 return true;
00614 }
00615 }
00616
00617
00618 dist = min(min(roots[0], roots[1]), min(roots[2], roots[3])) / l;
00619 return true;
00620 }
00621
00622
00623
00624
00625
00626
00627 Vector3 intersect(const Plane3 &p1, const Plane3 &p2, const Plane3 &p3)
00628 {
00629 Vector3 v1 = p2.normal;
00630 v1 *= p3.normal;
00631
00632 double bundo = dot(p1.normal, v1);
00633 if(bundo == 0)
00634 bundo = numeric_limits<double>::min();
00635
00636 Vector3 v2 = p2.normal;
00637 v2 *= p3.dist;
00638 Vector3 v3 = p3.normal;
00639 v3 *= p2.dist;
00640 v2 -= v3;
00641
00642 v2 *= p1.normal;
00643 v1 *= p1.dist;
00644 v2 -= v1;
00645 v2 /= bundo;
00646
00647 return v2;
00648 }
00649 }
00650 }