Biomechanical Joint Model
 Author: Anderson Maciel

intersect_tri.cpp

Go to the documentation of this file.
00001 /*@#---------------------------------------------------------------------------
00002  PROJECT            : PHD THESIS
00003  MODULE             : PHYSICALLY-BASED DEFORMATION
00004 
00005  FILE               : intersect_tri.C
00006  CREATION DATE      : Thu Sep  2 09:52:30 MDT 1999
00007  CREATION AUTHOR(S) : aubel
00008  ------------------------------------------------------------------------------
00009  KEYWORD(S)         : Ray-triangle intersection
00010  DEFINED TYPE(S)    : 
00011  RELATED TYPE(S)    : 
00012 
00013  FUNCTIONALITY      : Compute the intersection of a ray and a triangle
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 <iostream>
00024 //#include <vector>
00025 #include <algorithm>
00026 
00027 #include <LinAlg/vecarray.h>
00028 #include "ray.h"
00029 #include <list>
00030 
00031 
00032 // Calculates the intersection of the line defined by an origin orig and a
00033 // direction dir with triangle [v0,v1,v2].
00034 // If the line intercepts the triangle, true is returned.
00035 // When true is returned,  t,u,v will satisfy:
00036 //  (1-u-v).v0 + u.v1 + v.v2 = (1-t).orig + t.(orig+dir) = intersection point,
00037 // so that u,v indicates a parametric distance from the vertices and t a
00038 // parametric distance that can be used to determine if the segment
00039 // [orig,orig+dist] intersects in fact the triangle.
00040 // Note that t can be negative.
00041 // Original code : http://www.acm.org/jgt/papers/MollerTrumbore97/
00042 bool 
00043 intersect_triangle ( const VEC &orig, const VEC &dir,
00044                      const VEC &v0, const VEC &v1, const VEC &v2,
00045                      REAL &t, REAL &u, REAL &v )
00046 {
00047    VEC edge1 = v1 - v0;        // find vectors for two edges sharing v0 
00048    VEC edge2 = v2 - v0;
00049 
00050    // begin calculating determinant - also used to calculate U parameter 
00051    VEC pvec = cross_prod(dir, edge2);
00052 
00053    REAL det = dot_prod(edge1, pvec);  // if determinant is near zero, ray lies in plane of 
00054 
00055    if (fabs(det) < epsilon) 
00056    { 
00057        return false; 
00058    }
00059    REAL inv_det = 1.0 / det;
00060 
00061    VEC tvec = orig - v0;                     // calculate distance from v0 to ray origin 
00062    u = dot_prod(tvec, pvec) * inv_det;       // calculate U parameter and test bounds 
00063    if ( u<0.0 || u>1.0 ) 
00064    { 
00065        return false; 
00066    }
00067 
00068    VEC qvec = cross_prod(tvec, edge1);            // prepare to test V parameter 
00069    v = dot_prod(dir, qvec) * inv_det;        // calculate V parameter and test bounds 
00070    if ( v<0.0 || u+v>1.0 ) 
00071    { 
00072        return false; 
00073    }
00074    t = dot_prod(edge2,qvec) * inv_det;       // calculate t, ray intersects triangle 
00075 
00076    return true;
00077 }
00078 
00079 //
00080 // For a point X, look for m closest points from list Y within a specified radius.  
00081 // The accepted template types are containers of VECs : VECArray, vector<VEC>, list<VEC> etc.
00082 //
00083 vector<int> find_closest(const VEC &X, const VECArray &Y, int m, REAL radius)
00084 {
00085    vector<int> closest;
00086    // use squared radius to avoid square roots in loop
00087    REAL r2 = (radius >= infinity)? infinity : radius*radius;
00088 
00089    while (closest.size() < m)
00090    {
00091       REAL min_dist=infinity;
00092       int closest_node=-1;
00093          
00094       for (int j=0; j<Y.size(); j++)
00095       {
00096          // skip points already chosen 
00097          if (find(closest.begin(), closest.end(), j) != closest.end()) continue;
00098 
00099          REAL dist = VEC(Y[j] - X).norm2();
00100          if (dist < min_dist && dist <= r2)
00101          {
00102             min_dist = dist;
00103             closest_node = j;          
00104          }
00105       }
00106       // no more close node ?
00107       if (closest_node == -1) break;
00108       
00109       closest.push_back(closest_node);
00110    }
00111    return closest;
00112 }
00113 
00114 // Project a point X onto a mesh defined by a list of vertices, triangle normals
00115 // and a list of triangles, which is a continuous list (no separator between triangles) 
00116 // of indices into the vertices list. Therefore, trilist's size must be a multiple of 3.
00117 // The projection is defined as the point on the mesh closest to X.
00118 //
00119 // The returned values is the index(*3) of the triangle that contains P = projection of X, 
00120 // while u,v indicates P's barycentric coordinates in the triangle: (1-u-v).V0 + u.V1 + v.V2 
00121 //
00122 // The accepted template types are containers of VECs : VECArray, vector<VEC>, list<VEC> etc.
00123 //
00124 // The projection is  found by taking the minimum of the:
00125 // i) distance to every vertex of the mesh
00126 // ii) distance to every triangle of the mesh 
00127 // The distance to a triangle is computed as follows: a ray is cast from start point X with
00128 // a direction colinear to the triangle's normal. If a triangle-ray intersection exists, then
00129 // we use the distance from the intersection point to X. Otherwise, it's infinity.
00130 
00131 int project_on_mesh_tmp(const VEC &X, const VECArray &vertlist, 
00132                        const VECArray &normlist, const vector<int> &trilist, 
00133                        REAL &u, REAL &v, VEC &P)
00134 {
00135    // extract vertices actually in use (those referenced by the triangles list)
00136    // start by removing all duplicates from list of vertices indices
00137    list<int> tmp(trilist.size());
00138    copy(trilist.begin(), trilist.end(), tmp.begin());
00139    tmp.sort(); tmp.unique();
00140    VECArray V(tmp.size());
00141    int i=0; vector<int> no_dup;
00142    for (list<int>::const_iterator vtx = tmp.begin(); vtx != tmp.end(); ++vtx)
00143    {
00144       V[i++] = vertlist[*vtx];
00145       no_dup.push_back(*vtx);
00146    } 
00147 
00148    // find closest vertex to X and its index
00149    int closest_vtx = find_closest(X, V, 1).front();
00150    int idx_closest_vtx = no_dup[closest_vtx];
00151    P = V[closest_vtx];
00152    REAL min_dist = VEC(P - X).norm2();
00153 
00154    vector<int> closest_tris;  // indices of triangles that contain the closest vertex
00155 
00156    // find closest triangle
00157    i=0;
00158    int idx_closest_tri = -1;
00159    for (vector<int>::const_iterator tri = trilist.begin(); tri != trilist.end(); i++)
00160    {
00161       int p[3]; // store three indices of triangle here
00162       REAL t , u_, v_;
00163       bool has_closest_vtx = false;
00164 
00165       // loop on each vertex of triangle
00166       for (int k=0; k<3; k++)
00167       {
00168          p[k] = *tri++;
00169          if ( p[k] == idx_closest_vtx ) has_closest_vtx=true;
00170       }
00171       if ( has_closest_vtx ) closest_tris.push_back(i*3);
00172       
00173       if ( intersect_triangle (X, normlist[i], vertlist[p[0]], vertlist[p[1]], vertlist[p[2]], 
00174                                t, u_, v_ ) == true )
00175       {
00176          VEC D = t * normlist[i];
00177          if ( REAL d=D.norm2() < min_dist)
00178          {
00179             min_dist = d;
00180             idx_closest_tri = i*3;
00181             P = X + D;
00182             u = u_; v = v_;
00183          }
00184       }
00185    }
00186    
00187    // is closest vertex closer than the closest triangle?
00188    if ( idx_closest_tri == -1)
00189    {
00190       // yes, then pick up among all triangles that contain the closest vertex, 
00191       // the closest triangle (using the barycenters)
00192       VECArray barycenters(closest_tris.size());
00193       for (int k=0; k<closest_tris.size(); k++)
00194       {
00195          vector<int>::const_iterator tri = trilist.begin() + closest_tris[k];
00196          barycenters[k] = vertlist[*tri++] + vertlist[*tri++] + vertlist[*tri++];
00197          barycenters[k] /= 3;
00198       }
00199       int closest_barycenter = find_closest(X, barycenters, 1).front();
00200       idx_closest_tri = closest_tris[closest_barycenter];
00201       // there remains to compute the parametric u,v
00202       if (trilist[idx_closest_tri] == idx_closest_vtx) u=v=0;
00203       else
00204       { 
00205          if (trilist[idx_closest_tri+1] == idx_closest_vtx) { u=1; v=0; }
00206          else { u=0; v=1; }
00207       }
00208    }
00209    return idx_closest_tri;
00210 }
00211 
00212 
00213 // normals are automatically computed by the function
00214 // The accepted template types are containers of VECs : VECArray, vector<VEC>, list<VEC> etc.
00215 // and containers of ints for the triangle list
00216 int project_on_mesh(const VEC &X, const  VECArray &vertlist, const vector<int> &trilist,
00217                        REAL &u, REAL &v, VEC &P)
00218 {  
00219    assert(trilist.size()%3 == 0);
00220 
00221    // compute normals to triangles first
00222    VECArray normlist(trilist.size());   
00223    int i=0; 
00224    VEC V1(dimspace), V2(dimspace);
00225    for (vector<int>::const_iterator tri = trilist.begin(); tri != trilist.end(); i++)
00226    {    
00227       int p0 = *tri++;  
00228       int p1 = *tri++;  
00229       int p2 = *tri++;    
00230       V1 = vertlist[p1] - vertlist[p0];
00231       V2 = vertlist[p2] - vertlist[p0];
00232       normlist[i] = cross_prod(V1,V2); // no need to normalize
00233    }
00234 
00235    return project_on_mesh_tmp(X, vertlist, normlist, trilist, u, v, P);
00236 }
00237 
00238 

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