arbeit
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

VolSlicer.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------
00002 //
00003 //   Joe Kniss
00004 //     6-17-03
00005 //                   ________    ____   ___ 
00006 //                  |        \  /    | /  /
00007 //                  +---+     \/     |/  /
00008 //                  +--+|  |\    /|     < 
00009 //                  |  ||  | \  / |  |\  \ 
00010 //                  |      |  \/  |  | \  \ 
00011 //                   \_____|      |__|  \__\
00012 //                       Copyright  2003 
00013 //                      Joe Michael Kniss
00014 //                   <<< jmk@cs.utah.edu >>>
00015 //               "All Your Base are Belong to Us"
00016 //-------------------------------------------------------------------------
00017 
00018 //VolSlicer.cpp
00019 
00020 /// A base class for slicing a volume.  More generaly, generating
00021 ///  volume samples.  A strategy for "VolRenBase". 
00022 /// Also implements the standard volume slicer.
00023 
00024 #include "VolSlicer.h"
00025 #include <iostream>
00026 
00027 using namespace gutz;
00028 using namespace std;
00029 
00030 ///////////////////////////////////////////////////////////////////////////
00031 /// 3D Slicing Vector Aligned
00032 ///////////////////////////////////////////////////////////////////////////
00033 
00034 void VolSlicer::slice(mat4f        mv,   //model view matrix
00035                       VolytopeSP   vt,   //convex polytope with edge info
00036                       VolSamplesSP vs,   //storage for slice data
00037                       vec3f        axis) //axis to slice along eye-space coords
00038 {
00039 
00040    arrayw1v3f vo = vt->getVerts();     //Verts of polytope in model-space
00041    arrayw1v3f tx = vt->getTcoords();   //Texture coordinates of polytope
00042    arrayo1v3f rv(vo.size(),vec3f(0)); //for the "Rotated Volume" (in eye-space)
00043 
00044    axis.normalize();  // can't be sure that the slice axis is a unit vector
00045 
00046    float maxval = -1000000000;  //used for testing for the
00047    float minval = +1000000000;  // nearest/farthes volume verticies
00048 
00049    //inverse model view matrix
00050    mat4f mvinv(mv.inv());       //inverse view matrix
00051 
00052    vec3f sn(mvinv.tdir(axis));  //slice plane normal in model-space
00053    sn.normalize();              // make sure it is a unit vector
00054 
00055    //reference point for slicing in eye-space
00056    vec3f eref(-axis*1000);
00057 
00058    //int  vnear = 0, vfar = 0;
00059    int  vnear,vfar;
00060 
00061    //translate model to world coords (view space) & find nearest/farthest points
00062    for(int i=0; i<vo.size(); ++i)
00063    {   
00064       rv[i] = mv.tpoint(vo[i]);           //Model -> eye space
00065       float dfr = (rv[i] - eref).norm();  // distance from reference
00066       if(maxval < dfr)                    // set if farthest point
00067       {
00068          maxval = dfr;
00069          vfar = i;
00070       }
00071       if(minval > dfr)                    // set if nearest point
00072       {                   
00073          minval = dfr;
00074          vnear = i; 
00075       }
00076    }
00077 
00078    if( (vnear == -1) || (vfar == -1) )
00079    {
00080      cerr << "VolSlicer::slice, invalid volume coordinates, check transforms that "
00081           << " generate the model view matrix!! " << endl;
00082      return;
00083    }
00084 
00085    //now compute the reference point in model-space
00086    vec3f mref = -sn * 1000;  //1000 out from (0,0,0) allong the negative slice plane normal
00087 
00088    //find the nearest slicing point (the closest sample)
00089    vec3f vec2near = (vo[vnear] - mref).dot(sn) * sn;    // the vector from reference to near along sn
00090    float sts = float((int)(vec2near.norm()/_sampleSpace)); // # of samples from reference to start
00091    vec3f nearPoint = sts*_sampleSpace * sn + mref;      // the sample nearest the reference point
00092 
00093    //find the farthest slicing point (same process as near point)
00094    vec3f vec2far = (vo[vfar] - mref).dot(sn) * sn;   // the vector from reference to far along sn
00095    float stf = float((int)(vec2far.norm()/_sampleSpace)+1);   // # of samples form reference to start
00096    vec3f farPoint = stf*_sampleSpace * sn + mref;         // the sample farthest from the reference point
00097 
00098    //distance to sample
00099    float dist = (nearPoint - farPoint).norm();
00100 
00101    //number of samples
00102    int samples = (int)(dist / _sampleSpace) + 1;
00103 
00104    //err(" #samples =", samples);
00105 
00106    //amount to move between samples
00107    vec3f delta = sn*_sampleSpace;
00108 
00109    //starting point for slicing
00110    vec3f sp = nearPoint;
00111 
00112    //slice data
00113    //vec3f poly[8];   // stores edge intersections (model-space)
00114    //vec3f tcoord[8]; // stores texture intersections (texture-space)
00115 
00116    arrayw1v2i edg = vt->getEdges();
00117 
00118    arrayo1v3f  veye(edg.size(),vec3f(0));  // stores transformed (eye-space) edge intersections
00119 
00120    arrayw1v3f   vout = vs->getVertAttrib()->getArray();
00121    arrayw1v4f   tout = vs->getTCoordAttrib()->getArray();
00122    arrayw1v3ui  iout = vs->getIdxAttrib()->getArray();
00123    arrayw1v2ui  pout = vs->getRangeAttrib()->getArray();
00124 
00125    int vStart = 0; //index of the first vertex in a new primitive
00126    int iStart = 0; //index of the first triangle index in a new primitive
00127 
00128 
00129 
00130    // could possibly benefit from optimization
00131    for(int i = 0 ; i < samples; ++i)
00132    { //for each slice
00133 
00134       sp += delta;
00135 
00136       int edges = 0; 
00137       //now check each edge of the volume for intersection with.. 
00138       //the plane defined by sp & sn
00139 
00140       //intersect the slice plane with the edges of our polytope
00141       for(int ne=0; ne < edg.size(); ++ne)
00142       {
00143          int v0 = edg[ne].v0;
00144          int v1 = edg[ne].v1;
00145          edges += intersect(vo[v0], vo[v1], tx[v0], tx[v1], rv[v0], rv[v1], sp, sn,
00146             vout[vStart+edges], tout[vStart+edges], veye[edges]);
00147       }
00148 
00149       //compute convex hull and sort, a little piece of magic from:
00150       // B.M.E. Moret & H.D. Shapiro "P to NP" pp. 453
00151 
00152       arrayo1i order(edges,0);
00153       //int *order = new int[edges]; //order of vertices
00154       vec3f ecen(0,0,0);            //center of all intersections (eye-space)
00155       vec3f mcen(0,0,0);            //           ''               (model-space)         
00156       vec3f tcen(0,0,0);            //           ''               (texture-space)
00157 
00158       for( int j=0; j<edges; j++)  //find the center of the points by averaging
00159       { 
00160          order[j] = j;           //set the initial order
00161          ecen += veye[j];       // & compute the centers
00162          mcen += vout[vStart+j];
00163          tcen += tout[vStart+j];
00164       }         
00165       ecen  *= 1.0f/(float)edges;
00166       mcen  *= 1.0f/(float)edges;
00167       tcen  *= 1.0f/(float)edges;
00168 
00169       for(int vi=0; vi<edges-1; vi++)  //for each vertex
00170       {          
00171          float theta = -10;            //find one with largest angle from center.. 
00172          int next = vi;               //the next nearest vertex
00173          for ( int k= vi; k<edges; k++)
00174          { 
00175             //... and check angle made between other edges
00176             vec3f dv(veye[order[k]] - ecen);
00177             if( (dv.x == ecen.x) && (dv.y == ecen.y))
00178             { //same as center? 
00179                next = k;
00180                //cout << "VolRenBase::Warning::degenerate slice" << endl;
00181                break; //out of this for-loop
00182             }
00183 
00184             //simply compute : y/(abs(x) + abs(y))
00185             float tt = (dv.y)/(mm_abs(dv.x) + mm_abs(dv.y));
00186 
00187             if( dv.x < 0.0f )      //check quadrants 2&3
00188             {
00189                tt = (float)(2.0f - tt);       
00190             }
00191             else if( dv.y < 0.0f ) //check quadrant 4
00192             {
00193                tt = (float)(4.0f + tt);       
00194             }
00195 
00196             if( theta < tt )
00197             {  //grab the max theta
00198                next = k;
00199                theta = tt;
00200             }
00201          } //end for(k) angle checking
00202 
00203          // I am not sure wich is worse: swapping 3 vectors for every edge
00204          // or: using an array to index into another array??? hmmm....
00205          //   should have payed more attention in class
00206          int tmp = order[vi];
00207          order[vi] = order[next];
00208          order[next] = tmp;               
00209       } //end for(j) edge /angle sort
00210 
00211 
00212       //now generate triangles for this slice, could be moved to the sort above
00213       //add the center of the slice to the verticies and texture coordinates
00214       vout[vStart+edges]   = mcen;
00215       tout[vStart+edges]   = tcen;
00216 
00217       //fill the index array based on the sort we did above
00218       for(int tri = 0; tri < edges; ++tri)
00219       {
00220          //iout[iStart + tri].x = vStart + order[tri];
00221          //iout[iStart + tri].y = vStart + order[((tri + 1) % edges)];
00222          //iout[iStart + tri].z = vStart + edges;
00223 
00224          iout[iStart + tri].z = vStart + order[tri];
00225          iout[iStart + tri].x = vStart + order[((tri + 1) % edges)];
00226          iout[iStart + tri].y = vStart + edges;
00227       }
00228 
00229       pout[i].v0 = iStart;
00230       pout[i].v1 = iStart + edges;
00231 
00232       vStart += edges + 1;
00233       iStart += edges;
00234 
00235    }// end for(i) each slice
00236 
00237    //err("num verts ", vStart);
00238    //err("num tris", iStart);
00239 
00240    vs->getVertAttrib()->setSize(vStart);
00241    vs->getTCoordAttrib()->setSize(vStart);
00242    vs->getIdxAttrib()->setSize(iStart);
00243    vs->getRangeAttrib()->setSize(samples);
00244 
00245 }
00246 
00247 //============================================================ INTERSECT
00248 //======================================================================
00249 
00250 int VolSlicer::intersect(
00251                          const vec3f &m0, const vec3f &m1, //line end points (model-space)
00252                          const vec3f &t0, const vec3f &t1, //texture for line end points (texture-space)
00253                          const vec3f &e0, const vec3f &e1, //view-space line end points (eye-space)
00254                          const vec3f &sp, const vec3f &sn, //plane point & plane norm  (in model-space)
00255                          vec3f &pnew,  vec4f &tnew, vec3f &vnew) //new values (respectively)
00256 {
00257    float t = sn.dot(sp - m0) / sn.dot(m1 - m0);
00258 
00259    //note if the denominator is zero t is a NAN so we should have no problems?
00260    //probably not because NAN isn't between 0 & 1
00261 
00262    if( (t>=0) && (t<=1) )
00263    {
00264       pnew = m0 + t*(m1 - m0);
00265       tnew = t0 + t*(t1 - t0);
00266       vnew = e0 + t*(e1 - e0);
00267       return 1;
00268    }
00269    return 0;
00270 } 

Send questions, comments, and bug reports to:
jmk