Biomechanical Joint Model
 Author: Anderson Maciel

build.cpp

Go to the documentation of this file.
00001 /*************************************************************************\
00002 
00003   Copyright 1995 The University of North Carolina at Chapel Hill.
00004   All Rights Reserved.
00005 
00006   Permission to use, copy, modify and distribute this software and its
00007   documentation for educational, research and non-profit purposes, without
00008    fee, and without a written agreement is hereby granted, provided that the
00009   above copyright notice and the following three paragraphs appear in all
00010   copies.
00011 
00012   IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL BE
00013   LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
00014   CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE
00015   USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
00016   OF NORTH CAROLINA HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
00017   DAMAGES.
00018 
00019   THE UNIVERSITY OF NORTH CAROLINA SPECIFICALLY DISCLAIM ANY
00020   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00021   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE
00022   PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
00023   NORTH CAROLINA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
00024   UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00025 
00026   The authors may be contacted via:
00027 
00028   US Mail:             S. Gottschalk
00029                        Department of Computer Science
00030                        Sitterson Hall, CB #3175
00031                        University of N. Carolina
00032                        Chapel Hill, NC 27599-3175
00033 
00034   Phone:               (919)962-1749
00035 
00036   EMail:              {gottscha}@cs.unc.edu
00037 
00038 
00039 \**************************************************************************/
00040 
00041 
00042 #include "RAPID_version.H"
00043 
00044 static char rapidtag_data[] = "RAPIDTAG  file: "__FILE__"    date: "__DATE__"    time: "__TIME__;
00045 
00046 // to silence the compiler's complaints about unreferenced identifiers.
00047 static void r1(char *f){  r1(f);  r1(rapidtag_data);  r1(rapid_version);}
00048 
00049 
00050 #include "RAPID.H"
00051 #include "matvec.H"
00052 #include "moments.H"
00053 #include "obb.H"
00054 
00055 extern int RAPID_initialized;
00056 void RAPID_initialize();
00057 
00058 int
00059 RAPID_model::BeginModel()
00060 {
00061   int bs = build_state;
00062   
00063   if (!RAPID_initialized) RAPID_initialize();
00064   
00065   // free whatever storage we had.  Remember, it's okay to delete null
00066   // pointers in C++, so we don't have to check them first.
00067   delete [] b;   b = 0;
00068   num_boxes_alloced = 0;
00069   delete [] tris;   tris = 0;
00070   num_tris = 0;
00071   num_tris_alloced = 0;
00072 
00073   build_state = RAPID_BUILD_STATE_BEGIN;
00074   
00075   if (bs == RAPID_BUILD_STATE_CONST) return RAPID_OK;
00076 
00077   if (bs == RAPID_BUILD_STATE_PROCESSED) return RAPID_OK;
00078 
00079   if (bs == RAPID_BUILD_STATE_BEGIN) 
00080     return RAPID_ERR_BUILD_OUT_OF_SEQUENCE;
00081   
00082   if (bs == RAPID_BUILD_STATE_ADDTRI) 
00083     return RAPID_ERR_BUILD_OUT_OF_SEQUENCE;
00084 
00085   return RAPID_OK;
00086 }
00087 
00088 int
00089 RAPID_model::EndModel()
00090 {
00091   if (!RAPID_initialized) RAPID_initialize();
00092 
00093   if (num_tris == 0)
00094     {
00095       return RAPID_ERR_BUILD_EMPTY_MODEL;
00096     }
00097 
00098   int myrc = build_hierarchy();
00099   if (myrc == RAPID_OK)
00100     {
00101       // only change to processed state if successful.
00102       build_state = RAPID_BUILD_STATE_PROCESSED;
00103       return RAPID_OK;
00104     }
00105   else return myrc;
00106 
00107 }
00108 
00109 int
00110 RAPID_model::AddTri(const double *p1, const double *p2, const double *p3, int id)
00111 {
00112   if (!RAPID_initialized) RAPID_initialize();
00113 
00114   int myrc = RAPID_OK; // we'll return this unless a problem is found
00115 
00116   if (build_state == RAPID_BUILD_STATE_PROCESSED)
00117     {
00118       // client forgot to call BeginModel() before calling AddTri().
00119       return RAPID_ERR_BUILD_OUT_OF_SEQUENCE;
00120     }
00121   
00122   // first make sure that we haven't filled up our allocation.
00123   // if we have, allocate a new array of twice the size, and copy
00124   // the old data to it.
00125 
00126   if (num_tris == num_tris_alloced)
00127     {
00128       // decide on new size -- accounting for first time, where none are 
00129       // allocated
00130       int n = num_tris_alloced*2;
00131       if (n == 0) n = 1;
00132 
00133       // make new array, and copy the old one to it
00134       tri *t = new tri[n];
00135 
00136       // if we can't get any more space, return an error
00137       if (!t)
00138         {
00139           // we are leaving the model unchanged.
00140           return RAPID_ERR_MODEL_OUT_OF_MEMORY;
00141         }
00142       
00143       int i;
00144       for(i=0; i<num_tris; i++) t[i] = tris[i]; 
00145 
00146       // free the old array and reassign.  
00147       delete [] tris;
00148       tris = t;
00149       
00150       // update the allocation counter.
00151       num_tris_alloced = n;
00152     }
00153 
00154   // now copy the new tri into the array
00155   tris[num_tris].p1[0] = p1[0];
00156   tris[num_tris].p1[1] = p1[1];
00157   tris[num_tris].p1[2] = p1[2];
00158   tris[num_tris].p2[0] = p2[0];
00159   tris[num_tris].p2[1] = p2[1];
00160   tris[num_tris].p2[2] = p2[2];
00161   tris[num_tris].p3[0] = p3[0];
00162   tris[num_tris].p3[1] = p3[1];
00163   tris[num_tris].p3[2] = p3[2];
00164   tris[num_tris].id = id;
00165 
00166   // update the counter
00167   num_tris++;
00168 
00169   return myrc;
00170 }
00171 
00172 
00173 
00174 // not a full sort -- just makes column 1 the largest
00175 int
00176 eigen_and_sort1(double evecs[3][3], double cov[3][3])
00177 {
00178   double t;
00179   double evals[3];
00180   int n;
00181 
00182   n = Meigen(evecs, evals, cov);
00183   
00184   if (evals[2] > evals[0])
00185     {
00186       if (evals[2] > evals[1])
00187         {
00188           // 2 is largest, swap with column 0
00189           t = evecs[0][2]; 
00190           evecs[0][2] = evecs[0][0]; 
00191           evecs[0][0] = t;
00192           t = evecs[1][2]; 
00193           evecs[1][2] = evecs[1][0]; 
00194           evecs[1][0] = t;
00195           t = evecs[2][2]; 
00196           evecs[2][2] = evecs[2][0]; 
00197           evecs[2][0] = t;
00198         }
00199       else
00200         {
00201           // 1 is largest, swap with column 0
00202           t = evecs[0][1]; 
00203           evecs[0][1] = evecs[0][0]; 
00204           evecs[0][0] = t;
00205           t = evecs[1][1]; 
00206           evecs[1][1] = evecs[1][0]; 
00207           evecs[1][0] = t;
00208           t = evecs[2][1]; 
00209           evecs[2][1] = evecs[2][0]; 
00210           evecs[2][0] = t;
00211         }
00212     }
00213   else
00214     {
00215       if (evals[0] > evals[1])
00216         {
00217           // 0 is largest, do nothing
00218         }
00219       else
00220         {
00221           // 1 is largest
00222           t = evecs[0][1]; 
00223           evecs[0][1] = evecs[0][0]; 
00224           evecs[0][0] = t;
00225           t = evecs[1][1]; 
00226           evecs[1][1] = evecs[1][0]; 
00227           evecs[1][0] = t;
00228           t = evecs[2][1]; 
00229           evecs[2][1] = evecs[2][0]; 
00230           evecs[2][0] = t;
00231         }
00232     }
00233 
00234   // we are returning the number of iterations Meigen took.
00235   // too many iterations means our chosen orientation is bad.
00236   return n; 
00237 }
00238 
00239 
00240 inline
00241 void
00242 minmax(double &mn, double &mx, double v)
00243 {
00244   if (v < mn) mn = v;
00245   else if (v > mx) mx = v;
00246 }
00247 
00248 
00249 static moment *RAPID_moment = 0;
00250 static tri *RAPID_tri = 0;
00251 static box *RAPID_boxes = 0;
00252 static int RAPID_boxes_inited = 0;
00253 
00254 
00255 /*
00256 
00257   There are <n> tri structures in an array starting at <t>.
00258   
00259   We are told that the mean point is <mp> and the orientation
00260   for the parent box will be <or>.  The split axis is to be the 
00261   vector given by <ax>.
00262 
00263   <or>, <ax>, and <mp> are model space coordinates.
00264 
00265 */
00266 
00267 
00268 
00269 int
00270 RAPID_model::build_hierarchy()
00271 {
00272   // allocate the boxes and set the box list globals
00273 
00274   num_boxes_alloced = num_tris * 2;
00275   b = new box[num_boxes_alloced];
00276   if (b == 0) return RAPID_ERR_MODEL_OUT_OF_MEMORY;
00277   RAPID_boxes = b;
00278   RAPID_boxes_inited = 1;   // we are in process of initializing b[0].
00279   
00280   // Determine initial orientation, mean point, and splitting axis.
00281 
00282   int i; 
00283   accum M;
00284   
00285   //  double F1[3];
00286   //  double S1[6];
00287   double C[3][3];
00288   
00289   RAPID_moment = new moment[num_tris]; 
00290   if (RAPID_moment == 0)
00291     {
00292       delete [] b;
00293       return RAPID_ERR_MODEL_OUT_OF_MEMORY;
00294     }
00295   compute_moments(RAPID_moment, tris, num_tris);
00296 
00297   clear_accum(M);  
00298   for(i=0; i<num_tris; i++)
00299     accum_moment(M, RAPID_moment[i]);
00300   
00301   mean_from_accum(b[0].pT, M);
00302   covariance_from_accum(C, M);
00303   
00304   eigen_and_sort1(b[0].pR, C);
00305 
00306   // create the index list
00307   int *t = new int[num_tris];
00308   if (t == 0)
00309     {
00310       delete [] b;
00311       delete [] RAPID_moment;
00312       return RAPID_ERR_MODEL_OUT_OF_MEMORY;
00313     }
00314   for(i=0; i<num_tris; i++) t[i] = i;
00315 
00316   // set the tri pointer
00317   RAPID_tri = tris;
00318   
00319   // do the build
00320   int rc = b[0].split_recurse(t, num_tris);
00321   if (rc != RAPID_OK)
00322     {
00323       delete [] b;
00324       delete [] RAPID_moment;
00325       delete [] t;
00326       return RAPID_ERR_MODEL_OUT_OF_MEMORY;
00327     }
00328   
00329   // free the moment list
00330   delete [] RAPID_moment;  RAPID_moment = 0;
00331 
00332   // null the tri pointer
00333   RAPID_tri = 0;
00334   
00335   // free the index list
00336   delete [] t;
00337 
00338   return RAPID_OK;
00339 }
00340 
00341 
00342 
00343 inline
00344 void
00345 reaccum_moments(accum &A, int *t, int n)
00346 {
00347   clear_accum(A);
00348   for(int i=0; i<n; i++)
00349       accum_moment(A, RAPID_moment[t[i]]);
00350 }
00351 
00352 
00353 int
00354 box::split_recurse(int *t, int n)
00355 {
00356   // The orientation for the parent box is already assigned to this->pR.
00357   // The axis along which to split will be column 0 of this->pR.
00358   // The mean point is passed in on this->pT.
00359 
00360   // When this routine completes, the position and orientation in model
00361   // space will be established, as well as its dimensions.  Child boxes
00362   // will be constructed and placed in the parent's CS.
00363 
00364   if (n == 1)
00365     {
00366       return split_recurse(t);
00367     }
00368   
00369   // walk along the tris for the box, and do the following:
00370   //   1. collect the max and min of the vertices along the axes of <or>.
00371   //   2. decide which group the triangle goes in, performing appropriate swap.
00372   //   3. accumulate the mean point and covariance data for that triangle.
00373 
00374   accum M1, M2;
00375   double C[3][3];
00376   double c[3];
00377   double minval[3], maxval[3];
00378 
00379   int rc;   // for return code on procedure calls.
00380   int in;
00381   tri *ptr;
00382   int i;
00383   double axdmp;
00384   int n1 = 0;  // The number of tris in group 1.  
00385   // Group 2 will have n - n1 tris.
00386 
00387   // project approximate mean point onto splitting axis, and get coord.
00388   axdmp = (pR[0][0] * pT[0] + pR[1][0] * pT[1] + pR[2][0] * pT[2]);
00389 
00390   clear_accum(M1);
00391   clear_accum(M2);
00392 
00393   MTxV(c, pR, RAPID_tri[t[0]].p1);
00394   minval[0] = maxval[0] = c[0];
00395   minval[1] = maxval[1] = c[1];
00396   minval[2] = maxval[2] = c[2];
00397   for(i=0; i<n; i++)
00398     {
00399       in = t[i];
00400       ptr = RAPID_tri + in;
00401       
00402       MTxV(c, pR, ptr->p1);
00403       minmax(minval[0], maxval[0], c[0]);
00404       minmax(minval[1], maxval[1], c[1]);
00405       minmax(minval[2], maxval[2], c[2]);
00406 
00407       MTxV(c, pR, ptr->p2);
00408       minmax(minval[0], maxval[0], c[0]);
00409       minmax(minval[1], maxval[1], c[1]);
00410       minmax(minval[2], maxval[2], c[2]);
00411 
00412       MTxV(c, pR, ptr->p3);
00413       minmax(minval[0], maxval[0], c[0]);
00414       minmax(minval[1], maxval[1], c[1]);
00415       minmax(minval[2], maxval[2], c[2]);
00416 
00417       // grab the mean point of the in'th triangle, project
00418       // it onto the splitting axis (1st column of pR) and
00419       // see where it lies with respect to axdmp.
00420       mean_from_moment(c, RAPID_moment[in]);
00421       
00422       if (((pR[0][0]*c[0] + pR[1][0]*c[1] + pR[2][0]*c[2]) < axdmp)
00423           && ((n!=2)) || ((n==2) && (i==0)))    
00424         {
00425           // accumulate first and second order moments for group 1
00426           accum_moment(M1, RAPID_moment[in]);
00427 
00428           // put it in group 1 by swapping t[i] with t[n1]
00429           int temp = t[i];
00430           t[i] = t[n1];
00431           t[n1] = temp;
00432           n1++;
00433         }
00434       else
00435         {
00436           // accumulate first and second order moments for group 2
00437           accum_moment(M2, RAPID_moment[in]);
00438 
00439           // leave it in group 2
00440           // do nothing...it happens by default
00441         }
00442     }
00443 
00444   // done using this->pT as a mean point.
00445 
00446 
00447   // error check!
00448   if ((n1 == 0) || (n1 == n))
00449     {
00450       // our partitioning has failed: all the triangles fell into just
00451       // one of the groups.  So, we arbitrarily partition them into
00452       // equal parts, and proceed.
00453 
00454       n1 = n/2;
00455       
00456       // now recompute accumulated stuff
00457       reaccum_moments(M1, t, n1);
00458       reaccum_moments(M2, t + n1, n - n1);
00459     }
00460 
00461   // With the max and min data, determine the center point and dimensions
00462   // of the parent box.
00463 
00464   c[0] = (minval[0] + maxval[0])*0.5;
00465   c[1] = (minval[1] + maxval[1])*0.5;
00466   c[2] = (minval[2] + maxval[2])*0.5;
00467 
00468   pT[0] = c[0] * pR[0][0] + c[1] * pR[0][1] + c[2] * pR[0][2];
00469   pT[1] = c[0] * pR[1][0] + c[1] * pR[1][1] + c[2] * pR[1][2];
00470   pT[2] = c[0] * pR[2][0] + c[1] * pR[2][1] + c[2] * pR[2][2];
00471   d[0] = (maxval[0] - minval[0])*0.5;
00472   d[1] = (maxval[1] - minval[1])*0.5;
00473   d[2] = (maxval[2] - minval[2])*0.5;
00474 
00475   // allocate new boxes
00476   P = RAPID_boxes + RAPID_boxes_inited++;
00477   N = RAPID_boxes + RAPID_boxes_inited++;
00478 
00479   // Compute the orienations for the child boxes (eigenvectors of
00480   // covariance matrix).  Select the direction of maximum spread to be
00481   // the split axis for each child.
00482   
00483   double tR[3][3];
00484   
00485   if (n1 > 1)
00486     {
00487       mean_from_accum(P->pT, M1);
00488       covariance_from_accum(C, M1);
00489 
00490       if (eigen_and_sort1(tR, C) > 30)
00491         {
00492           // unable to find an orientation.  We'll just pick identity.
00493           Midentity(tR);
00494         }
00495 
00496       McM(P->pR, tR);
00497       if ((rc = P->split_recurse(t, n1)) != RAPID_OK) return rc;
00498     }
00499   else
00500     {
00501       if ((rc = P->split_recurse(t)) != RAPID_OK) return rc;
00502     }
00503   McM(C, P->pR);  MTxM(P->pR, pR, C);   // and F1
00504   VmV(c, P->pT, pT);  MTxV(P->pT, pR, c);
00505   
00506   if ((n-n1) > 1)
00507     {      
00508       mean_from_accum(N->pT, M2);
00509       covariance_from_accum (C, M2);
00510 
00511       if (eigen_and_sort1(tR, C) > 30)
00512         {
00513           // unable to find an orientation.  We'll just pick identity.
00514           Midentity(tR);
00515         }
00516       
00517       McM(N->pR, tR);
00518       if ((rc = N->split_recurse(t + n1, n - n1)) != RAPID_OK) return rc;
00519     }
00520   else
00521     {
00522       if ((rc = N->split_recurse(t+n1)) != RAPID_OK) return rc;
00523     }
00524   McM(C, N->pR); MTxM(N->pR, pR, C);
00525   VmV(c, N->pT, pT);  MTxV(N->pT, pR, c);  
00526 
00527   return RAPID_OK;
00528 }
00529 
00530 int
00531 box::split_recurse(int *t)
00532 {
00533   // For a single triangle, orientation is easily determined.
00534   // The major axis is parallel to the longest edge.
00535   // The minor axis is normal to the triangle.
00536   // The in-between axis is determine by these two.
00537 
00538   // this->pR, this->d, and this->pT are set herein.
00539 
00540   P = N = 0;
00541   tri *ptr = RAPID_tri + t[0];
00542 
00543   // Find the major axis: parallel to the longest edge.
00544   double u12[3], u23[3], u31[3];
00545 
00546   // First compute the squared-lengths of each edge
00547   VmV(u12, ptr->p1, ptr->p2);  
00548   double d12 = VdotV(u12,u12);
00549   VmV(u23, ptr->p2, ptr->p3);  
00550   double d23 = VdotV(u23,u23);
00551   VmV(u31, ptr->p3, ptr->p1);  
00552   double d31 = VdotV(u31,u31);
00553 
00554   // Find the edge of longest squared-length, normalize it to
00555   // unit length, and put result into a0.
00556   double a0[3];
00557   double l;  
00558   if (d12 > d23)
00559     {
00560       if (d12 > d31)
00561         {
00562           l = 1.0 / sqrt(d12); 
00563           a0[0] = u12[0] * l; 
00564           a0[1] = u12[1] * l;
00565           a0[2] = u12[2] * l;
00566         }
00567       else 
00568         {
00569           l = 1.0 / sqrt(d31);
00570           a0[0] = u31[0] * l;
00571           a0[1] = u31[1] * l;
00572           a0[2] = u31[2] * l;
00573         }
00574     }
00575   else 
00576     {
00577       if (d23 > d31)
00578         {
00579           l = 1.0 / sqrt(d23);
00580           a0[0] = u23[0] * l;
00581           a0[1] = u23[1] * l;
00582           a0[2] = u23[2] * l;
00583         }
00584       else
00585         {
00586           l = 1.0 / sqrt(d31);
00587           a0[0] = u31[0] * l;
00588           a0[1] = u31[1] * l;
00589           a0[2] = u31[2] * l;
00590         }
00591     }
00592 
00593   // Now compute unit normal to triangle, and put into a2.
00594   double a2[3];
00595   VcrossV(a2, u12, u23);
00596   l = 1.0 / Vlength(a2);  a2[0] *= l;  a2[1] *= l;  a2[2] *= l;
00597 
00598   // a1 is a2 cross a0.
00599   double a1[3];
00600   VcrossV(a1, a2, a0);
00601 
00602   // Now make the columns of this->pR the vectors a0, a1, and a2.
00603   pR[0][0] = a0[0];  pR[0][1] = a1[0];  pR[0][2] = a2[0];
00604   pR[1][0] = a0[1];  pR[1][1] = a1[1];  pR[1][2] = a2[1];
00605   pR[2][0] = a0[2];  pR[2][1] = a1[2];  pR[2][2] = a2[2];
00606   
00607   // Now compute the maximum and minimum extents of each vertex 
00608   // along each of the box axes.  From this we will compute the 
00609   // box center and box dimensions.
00610   double minval[3], maxval[3];
00611   double c[3];
00612   
00613   MTxV(c, pR, ptr->p1);
00614   minval[0] = maxval[0] = c[0];
00615   minval[1] = maxval[1] = c[1];
00616   minval[2] = maxval[2] = c[2];
00617 
00618   MTxV(c, pR, ptr->p2);
00619   minmax(minval[0], maxval[0], c[0]);
00620   minmax(minval[1], maxval[1], c[1]);
00621   minmax(minval[2], maxval[2], c[2]);
00622   
00623   MTxV(c, pR, ptr->p3);
00624   minmax(minval[0], maxval[0], c[0]);
00625   minmax(minval[1], maxval[1], c[1]);
00626   minmax(minval[2], maxval[2], c[2]);
00627   
00628   // With the max and min data, determine the center point and dimensions
00629   // of the box
00630   c[0] = (minval[0] + maxval[0])*0.5;
00631   c[1] = (minval[1] + maxval[1])*0.5;
00632   c[2] = (minval[2] + maxval[2])*0.5;
00633 
00634   pT[0] = c[0] * pR[0][0] + c[1] * pR[0][1] + c[2] * pR[0][2];
00635   pT[1] = c[0] * pR[1][0] + c[1] * pR[1][1] + c[2] * pR[1][2];
00636   pT[2] = c[0] * pR[2][0] + c[1] * pR[2][1] + c[2] * pR[2][2];
00637 
00638   d[0] = (maxval[0] - minval[0])*0.5;
00639   d[1] = (maxval[1] - minval[1])*0.5;
00640   d[2] = (maxval[2] - minval[2])*0.5;
00641   
00642   // Assign the one triangle to this box
00643   trp = ptr;
00644 
00645   return RAPID_OK;
00646 }

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