Biomechanical Joint Model
 Author: Anderson Maciel

bbox.cpp

Go to the documentation of this file.
00001 /*@#---------------------------------------------------------------------------
00002  PROJECT            : PHD THESIS
00003  MODULE             : PHYSICALLY-BASED DEFORMATION
00004 
00005  FILE               : bbox.C
00006  CREATION DATE      : Fri Dec 10 11:58:19 MET 1999
00007  CREATION AUTHOR(S) : aubel 
00008  ------------------------------------------------------------------------------
00009  KEYWORD(S)         : bounding box
00010  DEFINED TYPE(S)    : 
00011  RELATED TYPE(S)    : 
00012 
00013  FUNCTIONALITY      : Bounding Box class to avoid relying on Inventor's bboxes
00014  ------------------------------------------------------------------------------
00015  LANGAGE            : Ansi C++
00016  SYSTEM             : UNIX V 6.x / SGI
00017  GRAPHIC LIBRARY    : SGI  
00018  ------------------------------------------------------------------------------
00019  PROJECT DIRECTOR   : D. THALMANN
00020  LAB                : EPFL- LIG
00021  --------------------------------------------------------------------------#@*/
00022 
00023 #include "bbox.h"
00024 
00025 
00026 void 
00027 BBox::extendBy(const VEC &X)
00028 {
00029    assert(X.dim()==n_);
00030    
00031    if (empty==true)
00032    {
00033       UR = LL = X;
00034       empty = false;
00035    }
00036    else
00037    {
00038       for (int k=0; k<n_; k++) 
00039       {
00040          if (X[k]<LL[k]) LL[k] = X[k];
00041          else if (X[k]>UR[k]) UR[k] = X[k];
00042       }
00043    }
00044 }
00045 
00046 void
00047 BBox::extendBy(const BBox &bb)
00048 {
00049    if (bb.isEmpty()) return;
00050 
00051    VEC V1(bb.getMin()), V2(bb.getMax());
00052    VEC Y(n_);
00053  
00054    // for each vertex of BBox
00055    for (int p=0; p<(0x2<<n_); p++)
00056    {     
00057       for (int k=0; k<n_; k++) 
00058          Y[k] = ( p &(0x1<<k) )? V1[k] : V2[k];      
00059       extendBy(Y);
00060    }
00061 }
00062 
00063 void
00064 BBox::scale(REAL factor)
00065 {
00066    // get center
00067    VEC C = 0.5*(LL + UR);
00068    // get dim with scaling
00069    REAL mid_scale = 0.5 * factor;
00070    VEC D = mid_scale*(UR - LL);
00071    LL = C-D;
00072    UR = C+D;
00073 }
00074 
00075 bool
00076 BBox::intersectedBy(const BBox &bb) const
00077 {
00078    VEC D(bb.getDim());
00079    for (int p=0; p<(2<<n_); p++)
00080    {
00081       VEC P(bb.getMin());           
00082       for (int k=0; k<n_; k++) 
00083       {
00084          if (p & (0x1<<k)) P[k] += D[k];
00085       }
00086       if ( contains(P) ) return true;
00087    }
00088    return false;
00089 }
00090 
00091 // modified from Graphics Gems I pp. 736
00092 bool
00093 BBox::intersectedBy(Ray &ray) const
00094 {
00095    static const int RIGHT = 0;
00096    static const int LEFT = 1;
00097    static const int MIDDLE = 2;
00098     
00099    bool inside = true;
00100    REAL candidatePlane[dimspace]; // n_ = 2 or 3, so is always <= dimspace
00101    int  quadrant[dimspace];
00102    int  whichPlane, i;
00103    REAL maxT[dimspace];
00104 
00105    REAL O[3], D[3],P[3];
00106    for (i=0;i<3;i++) { O[i] = ray.O[i]; D[i] = ray.D[i]; };
00107 
00108    for (i=0; i<n_; i++)
00109    {
00110       if (O[i] < LL[i])
00111       {
00112          quadrant[i] = LEFT;
00113          candidatePlane[i] = LL[i];
00114          inside = false;
00115       }
00116       else if (O[i] > UR[i])
00117       {
00118          quadrant[i] = RIGHT;
00119          candidatePlane[i] = UR[i];
00120          inside = false;
00121       }
00122       else quadrant[i] = MIDDLE;
00123    }
00124 
00125    if (inside) 
00126    {
00127       if ( ray.segment == true)
00128       {
00129          VEC newO = ray.O + ray.D;
00130          if ( contains(newO) ) return false;
00131 
00132          // test with reverse ray        
00133          Ray rray(newO, -ray.D);
00134          rray.segment = true;
00135          if (intersectedBy(rray))
00136          {
00137             ray.t = 1 - rray.t;
00138             ray.P = rray.P;
00139             return true;
00140          }
00141          else cout << "Fatal error: could not find intersection in BBox::intersectedBy\n";
00142          return false;
00143       }
00144       else
00145       {
00146          // test with reverse ray
00147          REAL Dnorm = ray.D.norm();
00148          REAL coeff = 2*getDim().norm() / Dnorm;
00149          Ray rray(ray.O + coeff*ray.D, -ray.D); 
00150          if (!intersectedBy(rray))
00151          {
00152             // last remaining possibility, ray.O is on one of the bbox faces
00153             bool found  = false;
00154             for (i=0; !found && i<n_; i++)
00155             {
00156                if (fabs(O[i]-LL[i]) < epsilon)
00157                   found = true;
00158                if (fabs(O[i]-UR[i]) < epsilon)
00159                   found = true;
00160             }
00161             if (!found)
00162             {
00163                cout << "Fatal error: couldn't find intersection in BBox::intersectedBy\n";
00164                return false;
00165             }
00166             rray.P = ray.O;
00167          }
00168          ray.P = rray.P;
00169          ray.t = VEC(ray.P - ray.O).norm() / Dnorm;
00170          return ray.t >= 0;
00171       }
00172    }
00173    
00174    // Calculate T distances to candidate planes
00175    for (i = 0; i < n_; i++)
00176       if (quadrant[i] != MIDDLE && D[i] !=0.)
00177          maxT[i] = (candidatePlane[i]-O[i]) / D[i];
00178       else
00179          maxT[i] = -1.;
00180 
00181    // Get largest of the maxT's for final choice of intersection
00182    whichPlane = 0;
00183    for (i = 1; i < n_; i++)
00184       if (maxT[whichPlane] < maxT[i])
00185          whichPlane = i;
00186 
00187 
00188    // Check final candidate actually inside box
00189    if (maxT[whichPlane] < 0.) return (false);
00190    if (ray.segment == true && maxT[whichPlane] > 1.) return false;
00191    ray.t = maxT[whichPlane];
00192 
00193    for (i = 0; i < n_; i++)
00194       if (whichPlane != i) {
00195          P[i] = O[i] + maxT[whichPlane] *D[i];
00196          if ( P[i] > UR[i] || P[i] < LL[i] )
00197             return (false);      // outside box
00198       }else {
00199          P[i] = candidatePlane[i];
00200       }
00201    ray.P = VEC(3,P);
00202    return (true);                          // ray hits box
00203 }       
00204 
00205 
00206 // intersection with a triangle
00207 // algorithm simplified from Graphics Gems III pp.236
00208 bool 
00209 BBox::intersectedBy(const VEC &V0, const VEC &V1, const VEC &V2) const
00210 {
00211    // start with a simple acceptance test
00212    if (contains(V0) || contains(V1) || contains(V2) ) return true;
00213 
00214    // test if all 3 vertices of triangle not on the same "side" of bbox
00215    // simple rejection test
00216    for (int i=0; i<n_; i++)
00217    {
00218       if ( (V0[i] - LL[i] < 0) && (V1[i] - LL[i] < 0) && (V2[i] - LL[i] < 0) )
00219          return false;
00220 
00221       if ( (V0[i] - UR[i] > 0) && (V1[i] - UR[i] > 0) && (V2[i] - UR[i] > 0) )
00222          return false;
00223    }
00224       
00225    // ok, it's not a simple case
00226    Ray ray(V0, V1-V0);
00227    ray.segment = true;
00228    if ( intersectedBy(ray) ) return true;
00229 
00230    ray.O = V1; ray.D = V2-V1;
00231    if ( intersectedBy(ray) ) return true;
00232 
00233    ray.O = V2; ray.D = V0-V2;
00234    if ( intersectedBy(ray) ) return true;
00235 
00236    // it's really not a simple case!
00237    // we still have to test whether the diagonals of the cube intersect the triangle
00238    
00239    REAL t,u,v;
00240    VEC P0 (LL), P1 (UR);
00241    if ( intersect_triangle(P0, P1-P0, V0, V1, V2, t, u, v) && t>=0 && t<=1) return true;
00242 
00243    swap(P0[1], P1[1]);
00244    if ( intersect_triangle(P0, P1-P0, V0, V1, V2, t, u, v) && t>=0 && t<=1) return true;
00245 
00246    swap(P0[0], P1[0]);
00247    if ( intersect_triangle(P0, P1-P0, V0, V1, V2, t, u, v) && t>=0 && t<=1) return true;
00248 
00249    swap(P0[1], P1[1]);
00250    return ( intersect_triangle(P0, P1-P0, V0, V1, V2, t, u, v) && t>=0 && t<=1);
00251 }
00252 
00253 BBoxHierarchy::~BBoxHierarchy()
00254 {
00255    for (vector<BBoxHierarchy*>::iterator it=bboxlist.begin(); it!=bboxlist.end(); ++it)
00256       delete (*it);
00257 }
00258 
00259 // handle triangles only as input
00260 void
00261 BBoxHierarchy::createHierarchy(const VECArray &coords, const vector<int> &tris, 
00262                                int num_tris_max, int level)
00263 {   
00264    // check which triangles are inside
00265    for (int i=0; i<tris.size(); i+=3)
00266    {
00267       if (bb.intersectedBy(coords[tris[i+0]], coords[tris[i+1]], coords[tris[i+2]]))
00268       {  
00269          triangles.push_back(i);
00270       }
00271    }
00272 
00273 //    cout << " level = "<< level << " with bbox " << bb.getMin() << " " << bb.getDim()
00274 //      << " has " << triangles.size() << " tris. Max allowed = " 
00275 //      << num_tris_max << endl;
00276 
00277    // if too many triangles, subdivise
00278    // do not permit more than 6 levels of recursion as a security
00279    if ( level<5 && triangles.size() > num_tris_max )
00280    {
00281       VEC O = bb.getMin();
00282       VEC D = bb.getDim()/2;
00283 
00284       // for each octree
00285       for (int p=0;p<8;p++)
00286       {
00287          VEC newO = O;
00288          for (int k=0; k<3; k++) 
00289          {
00290             if (p & (0x1<<k)) newO[k] += D[k];
00291          }
00292 
00293          // recursive process
00294          BBoxHierarchy *smallerbb = new BBoxHierarchy(newO, newO+D, level+1);            
00295          smallerbb->createHierarchy(coords, tris, num_tris_max, level+1);
00296 
00297          if (smallerbb->getNumTriangles() > 0)
00298             bboxlist.push_back(smallerbb);
00299          else 
00300             delete smallerbb;    
00301       }
00302    }     
00303 }
00304 
00305 
00306 void
00307 BBoxHierarchy::getPotentialTriangles(Ray &ray, vector<int> &trilist) const
00308 {   
00309    bool force = bb.contains(ray.O) && bb.contains(ray.O+ray.D);
00310 
00311    if ( force || bb.intersectedBy(ray) )
00312    {
00313       if (bboxlist.empty() == false)
00314       {
00315          for (vector<BBoxHierarchy*>::const_iterator bb_it = bboxlist.begin();
00316               bb_it != bboxlist.end(); bb_it++)
00317          {
00318             (*bb_it)->getPotentialTriangles(ray, trilist);
00319          }
00320       }
00321       else 
00322       {
00323          if (trilist.empty() == true)
00324          {
00325             trilist.insert(trilist.end(), triangles.begin(), triangles.end());
00326             return;
00327          }
00328          
00329          int prev_size = trilist.size();
00330 
00331          // for each tri. check it hasn't been inserted before
00332          for (vector<int>::const_iterator tri_it = triangles.begin();
00333               tri_it != triangles.end(); tri_it++)
00334          {
00335             int i=0;
00336             for (; i<prev_size && *tri_it != trilist[i]; i++);
00337             if (i == prev_size) trilist.push_back(*tri_it);
00338          }
00339       }
00340    }
00341 }
00342 
00343 const BBoxHierarchy*
00344 BBoxHierarchy::getSmallestBBox(const VEC &X, int m) const
00345 {
00346    if ( !bb.contains(X) ) return NULL;
00347    
00348    for (vector<BBoxHierarchy*>::const_iterator bb_it=bboxlist.begin();
00349         bb_it != bboxlist.end(); ++bb_it)
00350    {
00351       if ( (*bb_it)->bb.contains(X) && (*bb_it)->getNumTriangles()>=m ) 
00352          return (*bb_it)->getSmallestBBox(X, m);
00353    }
00354 
00355    return this;      
00356 }

Generated on Thu Dec 1 10:13:32 2005 for COME - Biomechanical Joint Model by  doxygen 1.4.5