Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

RT_Prim.cc

Go to the documentation of this file.
00001 /*
00002     File:       RT_Prim.cc
00003 
00004     Function:   Implements various ray-trace primitives
00005 
00006     Author:     Andrew Willmott
00007 
00008     Notes:      
00009 */
00010 
00011 #include "RT_Prim.h"
00012 #include "gcl/VecUtil.h"
00013 
00014 // --- Triangle methods -------------------------------------------------------
00015 
00016 
00017 Int RT_Prim::gStamp = 1;
00018 Int RT_Object::gStamp = 1;
00019 
00020 Void RT_Tri::Init(Int v1, Int v2, Int v3, RT_Object *obj, Int triID)
00021 {
00022     v[0] = v1;
00023     v[1] = v2;
00024     v[2] = v3;
00025     flags = 0;
00026     stamp = 0;
00027     primType = rt_triangle;
00028     object = obj;
00029     id = triID;
00030 }
00031 
00032 #define CROSS_X_3(a, b, c)  ((a[1] - b[1]) * (c[2] - b[2]) \
00033                              - (a[2] - b[2]) * (c[1] - b[1]))
00034 //  returns (a - b) x (c - a) . (1, 0, 0)
00035 #define CROSS_Y_3(a, b, c)  ((a[2] - b[2]) * (c[0] - b[0]) \
00036                              - (a[0] - b[0]) * (c[2] - b[2]))
00037 //  returns (a - b) x (c - a) . (0, 1, 0)
00038 #define CROSS_Z_3(a, b, c)  ((a[0] - b[0]) * (c[1] - b[1]) \
00039                              - (a[1] - b[1]) * (c[0] - b[0]))
00040 //  returns (a - b) x (c - a) . (0, 0, 1)
00041 
00042 static const GCLReal kEdgeFuzz = 0.0;   
00043 static const GCLReal kNegEdgeFuzz = -kEdgeFuzz; 
00044 
00045 Bool RT_Tri::PointIsInside(Point& point)
00046 {
00047     Point*  points = object->points;
00048     Int     i0 = v[0],  i1 = v[1], i2 = v[2];
00049     GCLReal temp, a, b;
00050     
00051 #ifdef RT_TRI_CACHE 
00052     // Time stamp object so we can reuse this intersection test if necessary.
00053 
00054     Stamp();
00055 #endif
00056 
00057     flags &= ~TRI_HIT;
00058     
00059     //  Given a point lying in the plane of the triangle, we return false
00060     //  if it lies outside the triangle, and its barycentric coordinates if it
00061     //  lies inside.
00062 
00063     temp = normal[normMajorAxis];
00064     
00065     switch(normMajorAxis)
00066     {
00067     case 0:
00068         a = CROSS_X_3(points[i2], points[i1], point) / temp;
00069         if (a < kEdgeFuzz)  return(false);
00070 
00071         b = CROSS_X_3(points[i0], points[i2], point) / temp;
00072         if (b < kEdgeFuzz)  return(false);
00073 
00074         a = 1.0 - a - b;
00075         if (a < kEdgeFuzz)  return(false);
00076         
00077         flags |= TRI_HIT;
00078         return(true);
00079 
00080     case 1:
00081         a = CROSS_Y_3(points[i2], points[i1], point) / temp;    
00082         if (a < kEdgeFuzz)  return(false);
00083 
00084         b = CROSS_Y_3(points[i0], points[i2], point) / temp;        
00085         if (b < kEdgeFuzz)  return(false);
00086 
00087         a = 1.0 - a - b;
00088         if (a < kEdgeFuzz)  return(false);
00089 
00090         flags |= TRI_HIT;
00091         return(true);
00092 
00093     case 2:
00094         a = CROSS_Z_3(points[i2], points[i1], point) / temp;
00095         if (a < kEdgeFuzz)  return(false);
00096 
00097         b = CROSS_Z_3(points[i0], points[i2], point) / temp;
00098         if (b < kEdgeFuzz)  return(false);
00099 
00100         a = 1.0 - a - b;
00101         if (a < kEdgeFuzz)  return(false);
00102         
00103         flags |= TRI_HIT;
00104         return(true);
00105     }
00106     
00107     return(true);   // to keep the compiler happy.
00108 }
00109 
00110 Void RT_Tri::FindBaryCoords(Point& point, Vector &coords)
00111 {
00112     Point*  points = object->points;
00113     Int     i0 = v[0],  i1 = v[1], i2 = v[2];
00114     GCLReal temp;
00115     
00116 #ifdef RT_TRI_CACHE 
00117     // Time stamp object so we can reuse this intersection test if necessary.
00118 
00119     Stamp();
00120 #endif
00121 
00122     flags &= ~TRI_HIT;
00123     
00124     //  Given a point lying in the plane of the triangle, we return false
00125     //  if it lies outside the triangle, and its barycentric coordinates if it
00126     //  lies inside.
00127 
00128     temp = normal[normMajorAxis];
00129 
00130     switch(normMajorAxis)
00131     {
00132     case 0:
00133         coords[0] = CROSS_X_3(points[i2], points[i1], point) / temp;
00134         coords[1] = CROSS_X_3(points[i0], points[i2], point) / temp;
00135         coords[2] = 1.0 - coords[0] - coords[1];
00136         return;
00137 
00138     case 1:
00139         coords[0] = CROSS_Y_3(points[i2], points[i1], point) / temp;    
00140         coords[1] = CROSS_Y_3(points[i0], points[i2], point) / temp;        
00141         coords[2] = 1.0 - coords[0] - coords[1];
00142         return;
00143 
00144     case 2:
00145         coords[0] = CROSS_Z_3(points[i2], points[i1], point) / temp;        
00146         coords[1] = CROSS_Z_3(points[i0], points[i2], point) / temp;        
00147         coords[2] = 1.0 - coords[0] - coords[1];
00148         return;
00149     }
00150 }
00151 
00152 
00153 Void RT_Tri::UpdateBounds(Point& min, Point& max)
00154 // Use the tri's vertices to update the given min & max bounds.
00155 {
00156     Int     i;
00157     Point   *points = object->points;
00158         
00159     for (i = 0; i < 3; i++)
00160         ::UpdateBounds(points[v[i]], min, max);
00161 }
00162 
00163 Void RT_Tri::MakeNormal()
00164 {
00165     GCLReal xf,  yf,  zf;
00166     Point*  points = object->points;
00167         
00168     // Calculate face normal & other info
00169     
00170     CalcTriAreaNormal(points[v[0]], points[v[1]], points[v[2]], normal);
00171     
00172     d = -dot(normal, points[v[2]]);
00173  
00174     xf = abs(normal[0]);
00175     yf = abs(normal[1]);
00176     zf = abs(normal[2]);
00177 
00178     if (xf > yf)
00179     {
00180         if (xf > zf)
00181             normMajorAxis = 0;
00182         else
00183             normMajorAxis = 2;
00184     }
00185     else 
00186     {
00187         if (yf > zf)
00188             normMajorAxis = 1;
00189         else
00190             normMajorAxis = 2;
00191     }
00192     
00193     area = 0.5 * len(normal);
00194 }
00195 
00196 
00197 // --- RT_Sphere methods ------------------------------------------------------
00198 
00199 Void RT_Sphere::Init(const Point &c, GCLReal r, RT_Object *obj, Int genID)
00200 {
00201     centre = c;
00202     radius = r;
00203     sqrRad = sqr(r);
00204     area = vl_pi * sqrRad;
00205     primType = rt_gen;
00206     object = obj;
00207     id = genID;
00208 }
00209 
00210 
00211 Bool RT_Sphere::Intersect(Point &start, Vector &dir, GCLReal tMin, GCLReal tMax)
00212 // Assumes dir is normalised.
00213 {
00214     Vector  v = centre - start;
00215     GCLReal b = dot(v, dir);
00216     GCLReal disc = sqr(b) - sqrlen(v) + sqrRad;
00217     GCLReal t0;
00218     
00219     flags &= ~TRI_HIT;
00220 
00221     //  Root must be smaller than current value of t...
00222     //  and larger than tMin
00223     
00224     if (disc <= 0.0)
00225         return(false);      // no intersection
00226 
00227     disc = sqrt(disc);
00228     t0 = b - disc;          // 1st root
00229     
00230     if (t0 >= tMin && t0 < tMax)
00231     {
00232         hitT = t0;
00233         flags |= TRI_HIT;
00234         return(true);
00235     }
00236     
00237     t0 = b + disc;          // 2nd root
00238 
00239     if (t0 >= tMin && t0 < tMax)
00240     {
00241         hitT = t0;
00242         flags |= TRI_HIT;
00243         return(true);
00244     }
00245     
00246     return(false);          // intersection is behind
00247 }
00248 
00249 Void RT_Sphere::UpdateBounds(Point &min, Point &max)
00250 {
00251     Point   sMin, sMax;
00252 
00253     FindBounds(sMin, sMax);
00254     FindMinElts(sMin, min, min);    
00255     FindMaxElts(sMax, max, max);    
00256 }
00257 
00258 Void RT_Sphere::FindBounds(Point &min, Point &max)
00259 {
00260     max.MakeBlock(radius);
00261     min = centre - max;
00262     max += centre;
00263 }
00264 
00265 
00266 // --- RT_Object methods -------------------------------------------------------
00267 
00268 
00269 Void RT_Object::Init(Int numTris, Int numGens)
00270 {
00271     SELF.numTris = numTris;
00272     SELF.numGens = numGens;
00273     if (numTris == 0)
00274         tris = 0;
00275     else
00276         tris = new RT_Tri[numTris];
00277     if (numGens == 0)
00278         gens = 0;
00279     else
00280         gens = new RT_GenPtr[numGens];
00281 
00282     points = 0;
00283     numPoints = 0;
00284     normals = 0;
00285     numNormals = 0;
00286 
00287     tag = 1;
00288     id = 0;
00289 }
00290 
00291 Void RT_Object::Setup()
00292 {
00293     Int     i;
00294 
00295     for (i = 0; i < numTris; i++)
00296     {
00297         tris[i].object = this;
00298         tris[i].MakeNormal();
00299     }
00300 }
00301 
00302 Void RT_Object::Free()
00303 {
00304     Int i;
00305 
00306     for (i = 0; i < numGens; i++)
00307         delete gens[i];
00308 
00309     delete[] tris;
00310     delete[] gens;
00311     delete[] points;
00312     delete[] normals;
00313 }

Generated at Sat Aug 5 00:26:54 2000 for Radiator by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000