geometry.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
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; // backface culling!!
00036       if(dist)
00037       {
00038         k = (plane.dist + dot(plane.normal, ray.origin)) / -k;
00039         if(k <= 0) return false; // The ray either originates on the
00040                                  // plane or originates on the same
00041                                  // side as it extends to.
00042         *dist = k;
00043       }
00044       return true;
00045     }
00046 
00047     int intersect(const Ray3 &ray, const Box3 &box, double &dist)
00048     {
00049       // X slab
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; // The ray origin is behind the X slab
00063 
00064       // Y slab
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       // Z slab
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       // If we accept interior ray origination we should return distFar instead of sying no!
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; // The ray extends away
00127       const double a = ray.direction.squareSum();
00128       const double c = ray.origin.squareSum() - sphere.radius * sphere.radius;
00129       if(c <= 0) return false; // The ray originates inside
00130       const double d = b*b - a*c;
00131       if(d < 0) return false; // No solutions
00132       dist = (b - sqrt(d)) / a; // distFar would be (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; // No real solutions
00148 
00149       const double sqrt_d = sqrt(d);
00150 
00151       // Get the smallest of the two sollutions
00152       const double t = a==0 ? -numeric_limits<double>::max() : (b - sqrt_d) / a;
00153       // Note that if b < 0 then t < 0 since a >= 0
00154 
00155       const double h = height/2;
00156 
00157       if(h>=0)
00158       {
00159         const double y = rp[1] + rd[1] * t;
00160 
00161         // First intersection with infinite extension of cylinder is
00162         // below the bottom cap
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; // No hit since no sollution is positive
00167           const double y2 = rp[1] + t2 * rd[1];
00168           if(y2 < -h) return 0; // No hit since both intersections occure below the bottom cap
00169           if(bottom)
00170           {
00171             if(rp[1] < -h)
00172             {
00173               // Intersection with bottom cap from outside
00174               dist = (-h - rp[1]) / rd[1];
00175               return 2;
00176             }
00177           }
00178           if(enterOnly) return 0;
00179           // Assume non-solid
00180           if(y2 <= h)
00181           {
00182             if(!side) return 0;
00183             // Intersection with side from inside via missing bottom cap
00184             dist = t2;
00185             return 1;
00186           }
00187           if(!top || rp[1] >= h) return 0;
00188           // Intersection with top cap from inside via missing bottom cap
00189           dist = (h - rp[1]) / rd[1];
00190           return 3;
00191         }
00192 
00193         // First intersection with infinite extension of cylinder is
00194         // above the top cap
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; // No hit since no sollution is positive
00199           const double y2 = rp[1] + t2 * rd[1];
00200           if(y2 > h) return 0; // No hit since both intersections occure above the top cap
00201           if(top)
00202           {
00203             if(rp[1] > h)
00204             {
00205               // Intersection with top cap from outside
00206               dist = (h - rp[1]) / rd[1];
00207               return 3;
00208             }
00209           }
00210           if(enterOnly) return 0;
00211           // Assume non-solid
00212           if(y2 >= -h)
00213           {
00214             if(!side) return 0;
00215             // Intersection with side from inside via missing top cap
00216             dist = t2;
00217             return 1;
00218           }
00219           if(!bottom || rp[1] <= -h) return 0;
00220           // Intersection with bottom cap from inside via missing top cap
00221           dist = (-h - rp[1]) / rd[1];
00222           return 2;
00223         }
00224       }
00225 
00226       // First intersection with infinite extension of cylinder is
00227       // between the two caps
00228 
00229       if(side && t>0)
00230       {
00231         // Intersection with side from outside
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; // No hit since no sollution is positive
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           // Intersection with bottom cap from inside via side
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           // Intersection with top cap from inside via side
00254           dist = (h - rp[1]) / rd[1];     
00255           return 3;
00256         }
00257       }
00258 
00259       if(!side) return 0;
00260 
00261       // Intersection with side from inside via side
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       // Transform the ray into the space where the cone becomes
00274       // coincident with the upper nappe of the canonical infinite
00275       // double cone revolving around the y-axis and with apex at the
00276       // origin.
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; // No real solutions
00289 
00290         double sqrt_d = sqrt(d);
00291 
00292         // Get the smallest of the two sollutions
00293         double t = (b - sqrt_d) / a;
00294         // Note that if b < 0 then t < 0 since a > 0
00295 
00296         double y = rp[1] + rd[1] * t;
00297 
00298         // First intersection with infinite extension of the double cone
00299         // is below the apex, but since a > 0 this means that both
00300         // intersections occur on the lower nappe. Since the lower nappe
00301         // is not part of the original cone, it means that there is no
00302         // intersection in this case.
00303         if(y < 0) return 0;
00304 
00305         // First intersection with the infinite extension of the double cone is
00306         // above the cap
00307         if(y > bottomRadius)
00308         {
00309           double t2 = (b + sqrt_d) / a;
00310           if(t2 <= 0) return 0; // No hit since no sollution is positive
00311           double y2 = rp[1] + t2 * rd[1];
00312           if(y2 > bottomRadius) return 0; // No hit since both intersections occure above the cap
00313 
00314           // Ray is extending downwards
00315           if(bottom)
00316           {
00317             if(rp[1] > bottomRadius)
00318             {
00319               // Intersection with cap from outside
00320               dist = (bottomRadius - rp[1]) / rd[1];
00321               return 2;
00322             }
00323           }
00324 
00325           if(enterOnly || !side) return 0;
00326           // Intersection with side from inside via missing cap
00327           dist = t2;
00328           return 1;
00329         }
00330 
00331         // The first intersection with the infinite extension of the
00332         // cone is between the apex and the cap
00333 
00334         if(side)
00335         {
00336           if(t>0)
00337           {
00338             // Intersection with side from outside
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; // No hit since no sollution is positive
00347         double y2 = rp[1] + t2 * rd[1];
00348         if(y2 > bottomRadius)
00349         {
00350           // Ray is extending upwards
00351           if(!bottom || rp[1] >= bottomRadius) return 0;
00352           // Intersection with cap from inside via side
00353           dist = (bottomRadius - rp[1]) / rd[1];
00354           return 2;
00355         }
00356 
00357         if(!side) return 0;
00358 
00359         // Intersection with side from inside via side
00360         dist = t2;
00361         return 1;
00362       }
00363 
00364 
00365       // a <= 0
00366 
00367       if(rd[1] > 0)
00368       {
00369         // Ray extends upward
00370 
00371         double t;
00372 
00373         if(a == 0)
00374         {
00375           if(b < 0) return 0; // Ray-line hits lower nappe only
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           // Ray originates inside the upper nappe
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; // Intersection is above the cap
00394           if(side)
00395           {
00396             dist = t;
00397             return 1;
00398           }
00399         }
00400 
00401         // Intersection with cap from inside via missing side
00402         if(enterOnly || !bottom) return 0;
00403         dist = (bottomRadius - rp[1]) / rd[1];
00404         return 2;
00405       }
00406 
00407       // rd[1] < 0
00408       // Ray extends downwards
00409 
00410       double t;
00411 
00412       if(a == 0)
00413       {
00414         if(b > 0) return 0; // Ray-line hits lower nappe only
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; // Ray originates below upper upper nappe
00425       double y = rp[1] + rd[1] * t;
00426       if(y > bottomRadius) return 0; // Intersection is above the cap
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       // Solve: u^4 + k3 u^3 + k2 u^2 + k1 u + k0 = 0
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       // If we know that the ray originates from the surface then we
00568       // know that the root closest to zero should be regarded as zero
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       // Get rid of non-positive roots
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           // Find the middle root
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       // numberOfPositiveRoots == 4
00618       dist = min(min(roots[0], roots[1]), min(roots[2], roots[3])) / l;
00619       return true;
00620     }
00621 
00622     /*
00623      * Sources:
00624      *  http://www.ittc.co.jp/us/cadl/us_cadl.htm
00625      *  http://geometryalgorithms.com/Archive/algorithm_0104/algorithm_0104.htm
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(); // Just prevent division by zero
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 }

Generated on Sun Jul 30 22:55:43 2006 for Archon by  doxygen 1.4.4