Biomechanical Joint Model
 Author: Anderson Maciel

marching_cubes.cpp

Go to the documentation of this file.
00001 /*@#---------------------------------------------------------------------------
00002  PROJECT            : PHD THESIS
00003  MODULE             : PHYSICALLY-BASED DEFORMATION
00004 
00005  FILE               : marching_cubes.C
00006  CREATION DATE      : Thu Nov 11 11:30:03 MET 1999
00007  CREATION AUTHOR(S) : aubel 
00008  ------------------------------------------------------------------------------
00009  KEYWORD(S)         : marching cubes, voxelisation, volume
00010  DEFINED TYPE(S)    : 
00011  RELATED TYPE(S)    : 
00012 
00013  FUNCTIONALITY      : 
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 #include "marching_cubes.h"
00023 #include "hash_map.h"
00024 #include "primitive.h"
00025 #include <math.h>
00026 #include <vector>  
00027 #include <list>
00028 
00029 #include <time.h>
00030 
00031 //namespace MarchingCubes {
00032 
00033 // Freely adapted from basic code written by Paul Bourke 
00034 // http://www.swin.edu.au/astronomy/pbourke/modelling/polygonise/
00035 
00036 // LL = lower left corner of BBox, UR = upper right corner...
00037 idx3
00038 marchingCubes::findSeedVoxel()
00039 {
00040    Ray ray;
00041    float inc_x = (UR[0]-LL[0])/64.0;
00042    float inc_y = (UR[1]-LL[1])/64.0;
00043    VEC M = 0.5*(UR+LL);
00044     
00045    ray.O[2] = LL[2]; // correct in Z
00046    ray.D[0] = ray.D[1] = 0; ray.D[2] = UR[2]-LL[2];    // ray along +Z
00047    ray.segment = true;
00048 
00049    while ( inc_x < (UR[0]-LL[0])/2 )
00050    {
00051       // ray-casting starts from center because of increased chances of hitting the surface
00052       for (float i=-inc_x; i<=inc_x; i += inc_x)
00053       {
00054          ray.O[0] = i + M[0];
00055 
00056          if (ray.O[0] <= LL[0] || ray.O[0] >= UR[0]) break;
00057          for (float j=-inc_y; j<=inc_y; j += inc_y)
00058          {
00059             ray.O[1] = j + M[1];
00060 
00061             bool found=false;
00062             REAL tmin = infinity;
00063             for (int k=0; k<primlist.size(); k++)
00064             {          
00065                if ( primlist[k]->intersectedBy(ray) && ray.t < tmin) 
00066                {
00067                   tmin = ray.t;
00068                   found = true;
00069                }
00070             }
00071             if (found)
00072             { 
00073                // construct voxel-cube that encompasses that (intersection) point
00074                // this'll be our starting cube
00075                ray.P = ray.O + tmin * ray.D;
00076                cout << "intersection found for ray " << ray.P << endl; 
00077                VEC D = (ray.P - LL)/res;
00078                // printf("Starting voxel index=[%d,%d,%d]\n",(int)D[0], (int)D[1], (int)D[2]); getchar();
00079                return idx3((int)D[0], (int)D[1], (int)D[2]);   
00080             }
00081             else cout << "warning: intersection not found for ray " << ray.O << endl; 
00082          }
00083       }
00084       inc_x *= 2;
00085       inc_y *= 2;
00086    }
00087        
00088    cout << "\nFatal error: could not find any intersection by ray-casting for marching cubes\n";
00089    return idx3();
00090 }
00091 
00092 /*
00093 static void
00094 printCube(GridCell &cube)
00095 {
00096    for (int i=0; i<cube.val[0].size(); i++)
00097       for (int p=0; p<8; p++)
00098       {
00099          cout << cube.p[p] << " has density " << cube.val[p][i];
00100          cout << endl;
00101       }
00102 
00103 }
00104 */
00105 
00106 // given a cube whose vertices have associated density values, create
00107 // a triangulation (at most 5 triangles)
00108 int
00109 marchingCubes::polygonise(GridCell &cube)
00110 {
00111 
00112 #include "tables.cpp"
00113 
00114 // printCube(cube);
00115 
00116    // for each vertex of cube the corresponding bit in cubeindex
00117    //  is set to one iff it is outside of ALL primitives
00118    int cubeindex=0;
00119    for (int p=0, bit=1; p<8; p++, bit<<=1)
00120    {
00121       bool outside = true;
00122       for (int k=0; k<primlist.size() && outside; k++)
00123          if (cube.val[p][k] >= 0) outside = false;
00124 
00125       if ( outside ) cubeindex |= bit;
00126    }
00127 
00128    if (edgeTable[cubeindex] == 0) 
00129       return faceTable[cubeindex];
00130 
00131 
00132    int index[12];
00133    static VEC V(3), N(3);
00134 
00135    // Find the vertices (and their normals) where the surface intersects the cube
00136    // Always check first intersection has not been calculated before
00137 
00138    // check 12 edges
00139    int i;
00140    for (int bit2=1, i=0; i<12; bit2 <<= 1, i++)
00141    {
00142       if (edgeTable[cubeindex] & bit2)
00143       {
00144          // index of each vertex of current edge
00145          int idx1 = cubeEdges[i][0];
00146          int idx2 = cubeEdges[i][1];
00147 
00148          Edge &edge = edges[cube.indices[idx1]+cube.indices[idx2]];
00149          // has intersection already been computed ?
00150          if (edge.done == false)
00151          {      
00152             for (int k=0; k<primlist.size(); k++)
00153             {
00154                // is primitive intersecting this edge?
00155                if (cube.val[idx1][k]*cube.val[idx2][k] <= 0)
00156                {                  
00157                   primlist[k]->findIntersection(cube.p[idx1], cube.p[idx2], 
00158                                                 cube.val[idx1][k], cube.val[idx2][k], V, N);
00159 
00160                   // now check if the point found is outside all other primitives
00161                   bool outside=true;
00162                   for (int j=0; outside && j<primlist.size(); j++)
00163                   {
00164                      // skip the current primitive
00165                      if (j == k) continue;
00166 
00167                      // skip primitives that do not intersect this edge
00168                      if (cube.val[idx1][j]*cube.val[idx2][j] > 0) continue;
00169                      
00170                      outside = primlist[j]->outside(V);
00171                   }
00172                   
00173                   // look no further?
00174                   if (outside == true) break;
00175                }
00176             }
00177             vertlist.push_back(V);
00178             normlist.push_back(N);
00179             edge.done = true;
00180             index[i] = edge.vtx_idx = vertlist.size()-1;            
00181          }          
00182          else index[i] = edge.vtx_idx;
00183       }
00184    }
00185 
00186    // Create the triangles
00187    for (i=0;triTable[cubeindex][i]!=-1;i+=3) 
00188    {
00189       Triangle tri;
00190       for (int k=0; k<3; k++)
00191       {
00192          int idx = triTable[cubeindex][i+k];
00193          tri.indices[k] = index[idx];
00194       }
00195       trilist.push_back(tri);
00196    }
00197 
00198    return(faceTable[cubeindex]);   
00199 }
00200 
00201 
00202 void
00203 marchingCubes::computeVoxelFieldValues(GridCell &cell, const idx3 &id)
00204                         
00205 {
00206    static unsigned int tab[8][3] = 
00207    {
00208       {0,0,0},{1,0,0},{1,0,1},{0,0,1},
00209       {0,1,0},{1,1,0},{1,1,1},{0,1,1}
00210    };
00211 
00212    //   cout<<"Voxel coord:"<<endl;
00213    // test for all 8 vertices of cube
00214    for (int p=0; p<8; p++)
00215    {
00216       int x = tab[p][0];
00217       int y = tab[p][1];
00218       int z = tab[p][2];
00219      
00220       idx3 id_vtx(id.i+x, id.j+y, id.k+z);
00221       Voxel &voxel = surf[id_vtx];
00222     
00223       // compute, if necessary, pos and field value
00224       if (voxel.field_values.empty())
00225       {
00226          for (int i=0; i<3; i++) 
00227             voxel.X[i] = LL[i] + id_vtx[i]*res;
00228 
00229          for (int k=0; k<primlist.size(); k++)
00230             voxel.field_values.push_back(primlist[k]->getDistance(voxel.X));
00231       }         
00232 #if 0
00233       std::cout<<"["<<id_vtx<<"]="<<voxel.X<<std::endl;
00234 #endif
00235       cell.p[p] = voxel.X;
00236       cell.val[p] = voxel.field_values;
00237       cell.indices[p] = id_vtx;
00238    }
00239 }
00240 
00241 
00242 // voxlist = voxels to test; this list grows continuously until all voxels belonging to 
00243 // the surface have been tested.
00244 // vertlist = resulting list of vertices
00245 // trilist = resulting list of triangles
00246 void
00247 marchingCubes::constructSurface(list<idx3> &voxlist)
00248 {
00249 
00250    VEC D = (UR-LL)/res;
00251    //   cout<<"Size of the bbox cube:"<<int(D[0])<<","<<int(D[1])<<","<<int(D[2])<<endl;
00252 
00253    while (voxlist.empty() == false)
00254    {
00255       idx3 id = voxlist.front();
00256       //      std::cout<<"Current voxel Id="<<id<<std::endl; getchar();
00257       if (surf[id].done == false)
00258       {  
00259          GridCell cell;
00260          computeVoxelFieldValues(cell, id);
00261          surf[id].done = true;
00262    
00263          // add new vertices
00264          if (int faces = polygonise(cell) )
00265          {
00266             // possibly add new voxel
00267             if (faces & 1)
00268             {
00269                idx3 id_adj(id); id_adj.k--;
00270                if (id_adj.k>=0 && surf[id_adj].done == false) voxlist.push_back(id_adj);
00271             }
00272             // possibly add new voxel
00273             if (faces & 2)
00274             {
00275                idx3 id_adj(id); id_adj.k++;
00276                if (id_adj.k<=(int)D[2] && surf[id_adj].done == false) voxlist.push_back(id_adj);
00277             }
00278 
00279             // possibly add new voxel
00280             if (faces & 4)
00281             {
00282                idx3 id_adj(id); id_adj.j--;
00283                if (id_adj.j>=0 && surf[id_adj].done == false) voxlist.push_back(id_adj);
00284             }
00285 
00286             // possibly add new voxel
00287             if (faces & 8)
00288             {
00289                idx3 id_adj(id); id_adj.j++;
00290                if (id_adj.j<=(int)D[1] && surf[id_adj].done == false) voxlist.push_back(id_adj);
00291             }   
00292  
00293             // possibly add new voxel
00294             if (faces & 16)
00295             {
00296                idx3 id_adj(id); id_adj.i--;
00297                if (id_adj.i>=0 && surf[id_adj].done == false) voxlist.push_back(id_adj);
00298             }
00299 
00300             // possibly add new voxel
00301             if (faces & 32)
00302             {
00303                idx3 id_adj(id); id_adj.i++;
00304                if (id_adj.i<=(int)D[0] && surf[id_adj].done == false) voxlist.push_back(id_adj);
00305             }   
00306          }
00307       }
00308       voxlist.pop_front();
00309    }
00310 }
00311 
00312 
00313 marchingCubes::marchingCubes( vector<Primitive*> primitives, REAL resolution)/*
00314    : vertlist(), normlist(), trilist(), surf(), edges(),
00315      LL(dimspace), UR(dimspace), res(resolution), primlist(primitives)*/
00316 {  
00317    clock_t start=clock(), finish;
00318    
00319    // find bounding box
00320    BBox bb;
00321    for (int k=0; k<primlist.size(); k++) bb.extendBy( primlist[k]->getBoundingBox() );
00322    bb.scale(1.05);
00323    LL = bb.getMin();
00324    UR = bb.getMax();  
00325 #if 0
00326    std::cout<<"LL "<<LL<<std::endl;
00327    std::cout<<"UR "<<UR<<std::endl;
00328    getchar();
00329 #endif
00330      
00331    if (VEC(UR-LL).norm2() < epsilon){ 
00332      cout << " LL = " << LL << " UR = " << UR << endl;
00333      cout << "Error: found a bounding box with dimensions equal to 0 for marching cubes\n";
00334    }
00335    else
00336    {
00337       // find seed cube  by ray-casting
00338       idx3 id_start = findSeedVoxel();
00339       list<idx3> voxlist(1, id_start);
00340       constructSurface(voxlist);
00341 
00342       finish = clock();
00343       cout << "voxelisation took " << 
00344          (double)(finish-start)/(double)CLOCKS_PER_SEC << " seconds to execute\n";
00345       cout << "NVerts  :"<<vertlist.size()<<endl;
00346       cout << "NFacets :"<<trilist.size()<<endl; 
00347    }
00348 }
00349 //}

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