object.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 <float.h>
00021 #include <math.h>
00022 #include <vector>
00023 #include <float.h>
00024 
00025 #include <archon/math/geometry.H>
00026 #include <archon/math/quartic_solve.H>
00027 #include <archon/util/miniball.H>
00028 
00029 #include "object.H"
00030 
00031 #if ! defined M_PI
00032 #define M_E           2.7182818284590452353602874713526625  /* e */
00033 #define M_LOG2E       1.4426950408889634073599246810018922  /* log_2 e */
00034 #define M_LOG10E      0.4342944819032518276511289189166051  /* log_10 e */
00035 #define M_LN2         0.6931471805599453094172321214581766  /* log_e 2 */
00036 #define M_LN10        2.3025850929940456840179914546843642  /* log_e 10 */
00037 #define M_PI          3.1415926535897932384626433832795029  /* pi */
00038 #define M_PI_2        1.5707963267948966192313216916397514  /* pi/2 */
00039 #define M_PI_4        0.7853981633974483096156608458198757  /* pi/4 */
00040 #define M_1_PI        0.3183098861837906715377675267450287  /* 1/pi */
00041 #define M_2_PI        0.6366197723675813430755350534900574  /* 2/pi */
00042 #define M_2_SQRTPI    1.1283791670955125738961589031215452  /* 2/sqrt(pi) */
00043 #define M_SQRT2       1.4142135623730950488016887242096981  /* sqrt(2) */
00044 #define M_SQRT1_2     0.7071067811865475244008443621048490  /* 1/sqrt(2) */
00045 #endif
00046 
00047 namespace Archon
00048 {
00049   namespace Raytracer
00050   {
00051     using namespace Utilities;
00052     using namespace Math;
00053 
00054     inline bool leastPositiveDist(double t1, double t2, double &dist)
00055     {
00056       if(t1 > t2)
00057       {
00058         if(t1 >= 0)
00059         {
00060           dist = t2 >= 0 ? t2 : t1;
00061           return true;
00062         }
00063       }
00064       else
00065       {
00066         if(t2 >= 0)
00067         {
00068           dist = t1 >= 0 ? t1 : t2;
00069           return true;
00070         }
00071       }
00072       return false;
00073     }
00074 
00075     bool Plane::intersect(const Line3 &ray, const Object *originObject,
00076                           const Object::Part *, double &dist,
00077                           const Object::Part **p) const
00078     {
00079       /*
00080        * A ray that originates from a plane and leaves
00081        * it can never intersect it again.
00082        */
00083       if(originObject == this) return false;
00084 
00085       const double cosine = dot(normal, ray.direction);
00086       if(cosine > 0) return false; // backface culling!!
00087       dist = dot(normal, origin - ray.point) / cosine;
00088       if(p) *p = this;
00089       return true;
00090     }
00091 
00092     void Plane::map(const Vector3 &point, Vector3 &normal) const
00093     {
00094       normal = this->normal;
00095     }
00096 
00097     void Plane::map(const Vector3 &point, Vector3 &normal,
00098                     Vector2 &texturePoint) const
00099     {
00100       Vector3 p = invMap(point);
00101       texturePoint[0] = 0.5 + p[0]/2;
00102       texturePoint[1] = 0.5 - p[2]/2;
00103       normal = this->normal;
00104     }
00105 
00106     Cylinder::Cylinder(const Surface *surface, const CoordSystem3x3 &s):
00107       Object::Part(surface)
00108     {
00109       invMap.setInverseOf(s);
00110       pointToNormalMap = invMap;
00111       pointToNormalMap.basis.transpose();
00112       pointToNormalMap.basis.map(pointToNormalMap.origin);
00113       pointToNormalMap.basis *= Matrix3x3(Vector3(1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 1)) * invMap.basis;
00114       {
00115         CoordSystem3x3 s2 = s;
00116         s2.translate(Vector3(0, 1, 0));
00117         topCap = new Plane(surface, s2);
00118       }
00119       {
00120         CoordSystem3x3 s2 = s;
00121         s2.basis.scale(Vector3(1, -1, -1));
00122         s2.translate(Vector3(0, 1, 0));
00123         bottomCap = new Plane(surface, s2);
00124       }
00125     }
00126 
00127     Cylinder::~Cylinder()
00128     {
00129       delete topCap;
00130       delete bottomCap;
00131     }
00132 
00137     bool Cylinder::intersect(const Line3 &ray, const Object *originObject,
00138                              const Object::Part *, double &dist,
00139                              const Object::Part **p) const
00140     {
00141       /*
00142        * A cylinder is convex so:
00143        * A ray that originates from the surface of a cylinder
00144        * and leaves the cylinder can never intersect its surface again.
00145        */
00146       if(originObject == this) return false;
00147 
00148       const Vector3 rp = invMap(ray.point);
00149       const Vector3 rd = invMap.basis(ray.direction);
00150 
00151       const double a = 2 * (rd[0] * rd[0] + rd[2] * rd[2]);
00152       const double b = -2 * (rd[0] * rp[0] + rd[2] * rp[2]);
00153       const double c = (rp[0] * rp[0] + rp[2] * rp[2]) - 1;
00154       const double d = b * b - 2 * a * c;
00155 
00156       if(d < 0) return false; // No solutions
00157 
00158       const double sqrt_d = sqrt(d);
00159       const double t = (b - sqrt_d) / a;
00160       // Note that division by zero is fine
00161       // Note that if b < 0 then t < 0
00162 
00163       const double y = rp[1] + rd[1] * t;
00164 
00165       if(y > 1)
00166       {
00167         // Intersection with top cap
00168         const double t2 = (b + sqrt_d) / a;
00169         if(t2 < 0) return false;
00170         const double y2 = rp[1] + t2 * rd[1];
00171         if(y2 > 1) return false;
00172         dist = (1 - rp[1]) / rd[1];
00173         if(p) *p = topCap;
00174         return true;
00175       }
00176 
00177       if(y < -1)
00178       {
00179         // Intersection with bottom cap
00180         const double t2 = (b + sqrt_d) / a;
00181         if(t2 < 0) return false;
00182         const double y2 = rp[1] + t2 * rd[1];
00183         if(y2 < -1) return false;
00184         dist = (-1 - rp[1]) / rd[1];
00185         if(p) *p = bottomCap;
00186         return true;
00187       }
00188 
00189       if(b <= 0) return false;
00190 
00191       dist = t;
00192       if(p) *p = this;
00193       return true;
00194     }
00195 
00196     void Cylinder::interiorIntersect(const Line3 &ray,
00197                                      const Object::Part *,
00198                                      double &dist,
00199                                      const Object::Part *&p) const
00200     {
00201       const Vector3 rp = invMap(ray.point);
00202       const Vector3 rd = invMap.basis(ray.direction);
00203 
00204       const double a = 2 * (rd[0] * rd[0] + rd[2] * rd[2]);
00205       const double b = -2 * (rd[0] * rp[0] + rd[2] * rp[2]);
00206       const double c = (rp[0] * rp[0] + rp[2] * rp[2]) - 1;
00207       const double d = b * b - 2 * a * c;
00208 
00209       if(d < 0)
00210       {
00211         dist = 0;
00212         p = this;
00213         return;
00214       }
00215 
00216       const double sqrt_d = sqrt(d);
00217 
00218       // Because we are inside the cylinder we may assume that there is
00219       // one positive and one negative distance, we only want the
00220       // positive one which of cause is the highest one.
00221       // Note that division by zero is fine
00222       // Note that if b < 0 then t < 0
00223       const double t = (b + sqrt_d) / a;
00224 
00225       const double y = rp[1] + rd[1] * t;
00226 
00227       if(y > 1)
00228       {
00229         // Intersection with top cap
00230         dist = (1 - rp[1]) / rd[1];
00231         p = topCap;
00232         return;
00233       }
00234 
00235       if(y < -1)
00236       {
00237         // Intersection with bottom cap
00238         dist = (-1 - rp[1]) / rd[1];
00239         p = bottomCap;
00240         return;
00241       }
00242 
00243       dist = t;
00244       p = this;
00245     }
00246 
00247     void Cylinder::map(const Vector3 &point, Vector3 &normal,
00248                        Vector2 &texturePoint) const
00249     {
00250       map(point, normal);
00251 
00252       Vector3 p = invMap(point);
00253     
00254       texturePoint[0] = p[0] == 0 ? p[2] < 0 ? 0 : 0.5 :
00255         (p[0] < 0 ? 0.25 : 0.75) - atan(p[2]/p[0]) / (2 * M_PI);
00256 
00257       texturePoint[1] = 0.5 + p[1]/2;
00258     }
00259 
00260     bool Sphere::intersect(const Line3 &ray, const Object *originObject,
00261                            const Object::Part *, double &dist,
00262                            const Object::Part **p) const
00263     {
00264       /*
00265        * A ray that originates from the surface of a sphere
00266        * and leaves the sphere can never intersect its surface again.
00267        */
00268       if(originObject == this) return false;
00269 
00270       const Vector3 rp = invMap(ray.point);
00271       const Vector3 rd = invMap.basis(ray.direction);
00272       const double b = -2 * dot(rd, rp);
00273       if(b <= 0) return false;
00274       const double a = 2 * rd.squareSum();
00275       const double c = rp.squareSum() - 1;
00276       const double d = b * b - 2 * a * c;
00277       if(d < 0) return false; // No solutions
00278       dist = (b - sqrt(d)) / a;
00279       if(p) *p = this;
00280       return true;
00281     }
00282 
00283     void Sphere::interiorIntersect(const Line3 &ray,
00284                                    const Object::Part *,
00285                                    double &dist,
00286                                    const Object::Part *&p) const
00287     {
00288       const Vector3 rp = invMap(ray.point);
00289       const Vector3 rd = invMap.basis(ray.direction);
00290       const double b = -2 * dot(rd, rp);
00291       const double a = 2 * rd.squareSum();
00292       const double c = rp.squareSum() - 1;
00293       const double d = b * b - 2 * a * c;
00294       dist = d < 0 ? 0 : (b + sqrt(d)) / a;
00295       p = this;
00296     }
00297 
00298     void Sphere::map(const Vector3 &point, Vector3 &normal,
00299                      Vector2 &texturePoint) const
00300     {
00301       map(point, normal);
00302 
00303       Vector3 p = invMap(point);
00304     
00305       /*
00306        * Determine the longitude angle of the point as a value between 0
00307        * and 1 (starting and ending at the prime meridian and rising to
00308        * the east.)
00309        * Note that the longitude is actually the shortest angle between the
00310        * prime meridian and the meridian of the point.
00311        */
00312       texturePoint[0] = p[0] == 0 ? p[2] < 0 ? 0 : 0.5 :
00313         (p[0] < 0 ? 0.25 : 0.75) - atan(p[2]/p[0]) / (2 * M_PI);
00314 
00315       /*
00316        * Determine the latitude angle of the point as a value between 0
00317        * and 1 (0 beeing at the south pole and 1 beeing at the north
00318        * pole.)
00319        * Note that the latitude is actually the shortest angle between the
00320        * intersection direction and the equator plane.
00321        */
00322       texturePoint[1] = acos(-p[1]/p.length()) / M_PI;
00323     }
00324 
00325 
00416     bool Torus::intersect(const Line3 &ray, const Object *originObject,
00417                           const Object::Part *, double &dist,
00418                           const Object::Part **part) const
00419     {
00420       /*
00421        * Map the ray into the coordinate system of the torus.
00422        */
00423       Vector3 p = ray.point;
00424       invMap.map(p);
00425       Vector3 d = ray.direction;
00426       invMap.basis.map(d);
00427       const double l = d.length();
00428       d /= l;
00429 
00430       const double spx = p[0]*p[0];
00431       const double spy = p[1]*p[1];
00432       const double spz = p[2]*p[2];
00433 
00434       const double dpx = d[0]*p[0];
00435       const double dpy = d[1]*p[1];
00436       const double dpz = d[2]*p[2];
00437 
00438       const double dp  = dpx + dpy + dpz;
00439 
00440       const double sma = majorRadius*majorRadius;
00441 
00442       const double a = spx + spy + spz - minorRadius*minorRadius;
00443       const double b = a + sma;
00444 
00445       const double k3 = 4*dp;
00446       const double k2 = 2*(2*dp*dp + a - sma*(1 - 2*d[1]*d[1]));
00447       const double k1 = 4*(dp*a - sma*(dp - 2*dpy));
00448       const double k0 = b*b - 4*sma*(spx + spz);
00449 
00450       // Solve: u^4 + k3 u^3 + k2 u^2 + k1 u + k0 = 0
00451 
00452       double roots[4];
00453       const int numberOfRealRoots =
00454         Math::quarticSolve(k3, k2, k1, k0, roots);
00455 
00456       if(numberOfRealRoots == 0) return false;
00457 
00458       if(originObject == this)
00459       {
00460         int minAbs = -1;
00461         for(int i=0; i<numberOfRealRoots; ++i)
00462           if(minAbs == -1 || fabs(roots[i]) < fabs(roots[minAbs])) minAbs = i;
00463         roots[minAbs] = -1;
00464       }
00465 
00466       double minDist = 0;
00467       bool any = false;
00468       for(int i=0; i<numberOfRealRoots; ++i)
00469       {
00470         if(roots[i] > 0 && (!any || roots[i] < minDist))
00471         {
00472           minDist = roots[i];
00473           any = true;
00474         }
00475       }
00476       if(!any) return false;
00477       dist = minDist / l;
00478       if(part) *part = this;
00479       return true;
00480     }
00481 
00482     void Torus::interiorIntersect(const Line3 &ray,
00483                                   const Object::Part *,
00484                                   double &dist,
00485                                   const Object::Part *&p) const
00486     {
00487       if(!intersect(ray, this, this, dist, &p)) p = this, dist = 0;
00488     }
00489 
00490     void Torus::map(const Vector3 &point, Vector3 &normal) const
00491     {
00492       normal = point;
00493       invMap.map(normal);
00494       const double a = 1-majorRadius/sqrt(normal[0]*normal[0] + normal[2]*normal[2]);
00495       normal[0] *= a;
00496       normal[2] *= a;
00497       normalMap.map(normal);
00498       normal.normalize();
00499     }
00500 
00501     void Torus::map(const Vector3 &point, Vector3 &normal,
00502                     Vector2 &texturePoint) const
00503     {
00504       normal = point;
00505       invMap.map(normal);
00506       const double a = sqrt(normal[0]*normal[0] + normal[2]*normal[2]);
00507       const double b = a - majorRadius;
00508 
00509       texturePoint[0] = normal[0] == 0 ? normal[2] < 0 ? 0 : 0.5 :
00510         (normal[0] < 0 ? 0.25 : 0.75) - atan(normal[2]/normal[0]) / (2 * M_PI);
00511 
00512       texturePoint[1] = normal[1] == 0 ? b < 0 ? 0 : 0.5 :
00513         (normal[1] < 0 ? 0.25 : 0.75) - atan(b/normal[1]) / (2 * M_PI);
00514 
00515       const double c = b/a;
00516       normal[0] *= c;
00517       normal[2] *= c;
00518       normalMap.map(normal);
00519       normal.normalize();
00520     }
00521 
00522 
00523     Polygon::Polygon(const Surface *surface,
00524                      const std::vector<Vector3 *> &vertexList,
00525                      const Vector2 &textureVertex1,
00526                      const Vector2 &textureVertex2,
00527                      const Vector2 &textureVertex3):
00528       Object::Part(surface), vertexList(vertexList)
00529     {
00530       if(vertexList.size() < 3) ARCHON_THROW1(ArgumentException, "Too few vertices");
00531       Vector3 x = *vertexList[2];
00532       x -= *vertexList[1];
00533       Vector3 y = *vertexList[0];
00534       y -= *vertexList[1];
00535       normal = x;
00536       normal *= y;
00537       normal.normalize();
00538 
00539       if(!dynamic_cast<const Texture *>(surface)) return;
00540 
00541       // Polygon to texture map
00542       Matrix3x3 m;
00543       m.x = Vector3(textureVertex3);
00544       m.x -= Vector3(textureVertex2);
00545       m.y = Vector3(textureVertex1);
00546       m.y -= Vector3(textureVertex2);
00547       m.z = m.x;
00548       m.z *= m.y;
00549 
00550       // World to texture map
00551       m /= Matrix3x3(x, y, normal);
00552 
00553       texMapX = m.getRow1();
00554       texMapY = m.getRow2();
00555       texMapOrigin = textureVertex2;
00556       texMapOrigin -= Vector2(m(*vertexList[1]));
00557     }
00558 
00559     Polygon::Polygon(const Surface *surface,
00560                      const std::vector<Vector3 *> &vertexList,
00561                      const Vector2 &textureVertex1,
00562                      const Vector2 &textureVertex2):
00563       Object::Part(surface), vertexList(vertexList)
00564     {
00565       if(vertexList.size() < 3) ARCHON_THROW1(ArgumentException, "Too few vertices");
00566       normal = *vertexList[1];
00567       normal -= *vertexList[0];
00568       Vector3 v = *vertexList[2];
00569       v -= *vertexList[1];
00570       normal *= v;
00571       normal.normalize();
00572       /*
00573       // Texture
00574       Vector3 wX = *vertexList[1];
00575       wX -= *vertexList[0];
00576 
00577       Vector2 tX = textureVertex2;
00578       tX -= textureVertex1;
00579 
00580       scaling = tX.length() / wX.length();
00581 
00582       wX.normalize();
00583 
00584       Vector3 wY = normal;
00585       wY *= wX;
00586 
00587       tX.normalize();
00588 
00589       Vector2 tY = tX;
00590       tY.cross();
00591 
00592       Vector2 w;
00593 
00594       w = -textureVertex1;
00595       textureOrigin = (wX * dot(w, tX) + wY * dot(w, tY))/scaling +
00596       *vertexList[0];
00597 
00598       w = Vector2::unitX - textureVertex1;
00599       textureAxisX = (wX * dot(w, tX) + wY * dot(w, tY))/scaling +
00600       *vertexList[0] - textureOrigin;
00601 
00602       w = Vector2::unitY - textureVertex1;
00603       textureAxisY = (wX * dot(w, tX) + wY * dot(w, tY))/scaling +
00604       *vertexList[0] - textureOrigin;
00605 
00606       textureAxisX.normalize();
00607       textureAxisY.normalize();
00608       */
00609     }
00610 
00611     bool Polygon::intersect(const Line3 &ray, const Object *originObject,
00612                             const Object::Part *, double &dist,
00613                             const Object::Part **part) const
00614     {
00615       /*
00616        * A ray that originates from the surface of a polygon and leaves
00617        * the polygon can never intersect its polygon again.
00618        */
00619       if(originObject == this) return false;
00620 
00621       const double cosine = dot(normal, ray.direction);
00622       if(cosine > 0) return false; // backface culling!!
00623       Vector3 v, w = *vertexList.back();
00624       for(std::vector<Vector3 *>::const_iterator i=vertexList.begin();
00625           i != vertexList.end(); ++i)
00626       {
00627         v = **i;
00628         w -= v;
00629         v -= ray.point;
00630         w *= v;
00631         /*
00632          * 'w' is now the normal to the plain containing both the eye
00633          * point and the polygon edge between the current and the
00634          * previous vertex.  The direction of the normal from the plane
00635          * is away from the polygon interior.
00636          */
00637         if(dot(w, ray.direction) > 0) return false;
00638         w = **i;
00639       }
00640 
00641       if(part) *part = this;
00642       dist = dot(normal, v) / cosine;
00643       return true;
00644     }
00645 
00646     bool Polygon::backfaceIntersect(const Line3 &ray,
00647                                     const Object *originObject,
00648                                     const Object::Part *, double &dist,
00649                                     const Object::Part **part) const
00650     {
00651       /*
00652        * A ray that originates from the surface of a polygon and leaves
00653        * the polygon can never intersect its polygon again.
00654        */
00655       if(originObject == this) return false;
00656 
00657       const double cosine = dot(normal, ray.direction);
00658       if(cosine < 0) return false; // frontface culling!!
00659 
00660       Vector3 v, w = *vertexList.front();
00661       for(std::vector<Vector3 *>::const_iterator i=vertexList.end();
00662           i != vertexList.begin(); --i)
00663       {
00664         v = **(i-1);
00665         w -= v;
00666         v -= ray.point;
00667         w *= v;
00668         /*
00669          * 'w' is now the normal to the plain containing both the eye
00670          * point and the polygon edge between the current and the
00671          * previous vertex.  The direction of the normal from the plane
00672          * is away from the polygon interior.
00673          */
00674         if(dot(w, ray.direction) > 0) return false;
00675         w = **(i-1);
00676       }
00677 
00678       if(part) *part = this;
00679       dist = dot(normal, v) / cosine;
00680       return true;
00681     }
00682 
00683     void Polygon::map(const Vector3 &point, Vector3 &normal,
00684                       Vector2 &texturePoint) const
00685     {
00686       normal = this->normal;
00687 
00688       /*
00689         Vector3 p = point;
00690         p -= textureOrigin;
00691         texturePoint[0] = dot(p, textureAxisX) * scaling;
00692         texturePoint[1] = dot(p, textureAxisY) * scaling;
00693       */
00694 
00695       texturePoint[0] = dot(point, texMapX);
00696       texturePoint[1] = dot(point, texMapY);
00697       texturePoint += texMapOrigin;
00698     }
00699 
00700     ConvexPolyhedron::
00701     ConvexPolyhedron(const std::vector<Polygon *> &polygonList):
00702       polygonList(polygonList) 
00703     {
00704       // Determine the minimal bounding sphere
00705       MinimalBoundingBall<3> ball;
00706       for(std::vector<Polygon *>::const_iterator i=polygonList.begin();
00707           i != polygonList.end(); ++i)
00708       {
00709         for(std::vector<Vector3 *>::iterator j=(*i)->vertexList.begin();
00710             j != (*i)->vertexList.end(); ++j)
00711         {
00712           const Vector3 *v = *j;
00713           MinimalBoundingBall<3>::Point p;
00714           p[0]=(*v)[0];
00715           p[1]=(*v)[1];
00716           p[2]=(*v)[2];
00717           ball.check_in(p);
00718         }
00719       }
00720       ball.build();
00721       const MinimalBoundingBall<3>::Point c = ball.center();
00722       boundingVolume.center.set(c[0], c[1], c[2]);
00723       boundingVolume.radius = sqrt(ball.squared_radius());
00724     }
00725 
00726     ConvexPolyhedron::~ConvexPolyhedron()
00727     {
00728       for(std::vector<Polygon *>::iterator i=polygonList.begin();
00729           i != polygonList.end(); ++i) delete *i;
00730     }
00731 
00732     bool ConvexPolyhedron::intersect(const Line3 &ray,
00733                                      const Object *originObject,
00734                                      const Part *originPart, double &dist,
00735                                      const Object::Part **part) const
00736     {
00737       /*
00738        * A ray that originates from the surface of a convex polyhedron
00739        * and leaves the polyhedron can never intersect its surface
00740        * again. 
00741        */
00742       if(originObject == this) return false;
00743 
00744       double d1 = 0, d2 = 0;
00745       if(!Math::intersect(Ray3(ray), boundingVolume, d1))
00746         return false;
00747 
00748       bool hit = false;
00749       const Part *p1, *p2 = 0;
00750 
00751       for(std::vector<Polygon *>::const_iterator i=polygonList.begin();
00752           i != polygonList.end(); ++i)
00753         if((*i)->intersect(ray, originObject, originPart, d1, &p1) &&
00754            (!hit || d1 < d2))
00755         {
00756           d2 = d1;
00757           p2 = p1;
00758           hit = true;
00759         }
00760 
00761       if(hit)
00762       {
00763         dist = d2;
00764         if(part) *part = p2;
00765         return true;
00766       }
00767 
00768       return false;
00769     }
00770 
00771     void ConvexPolyhedron::interiorIntersect(const Line3 &ray,
00772                                              const Object::Part *originPart,
00773                                              double &dist,
00774                                              const Object::Part *&p) const
00775     {
00776       for(std::vector<Polygon *>::const_iterator i=polygonList.begin();
00777           i != polygonList.end(); ++i)
00778       {
00779         if(originPart == *i) continue;
00780         if((*i)->backfaceIntersect(ray, this, originPart, dist, &p)) return;
00781       }
00782 
00783       // In case of numeric inaccuracy.
00784       p = originPart;
00785       dist = 0;
00786     }
00787   }
00788 }

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