ORTS

sr_bv_tree_query.cpp

Go to the documentation of this file.
00001 /* Note: this code was adapted from the PQP library; 
00002    their copyright notice can be found at the end of this file. */
00003 
00004 # ifdef WIN32
00005 # include <sr_bv_tree_query.h>
00006 # else
00007 # include <SR/sr_bv_tree_query.h>
00008 # endif
00009 
00010 
00011 //====================== SrBvTreeQuery ======================
00012 
00013 SrBvTreeQuery::SrBvTreeQuery ()
00014  {
00015    init ();
00016  }
00017 
00018 void SrBvTreeQuery::init ()
00019  {
00020    _num_bv_tests = 0;
00021    _num_tri_tests = 0;
00022    _pairs.size(0);
00023    _pairs.compress();
00024    _dist = 0;
00025    _rel_err = _abs_err = 0;
00026    _closer_than_tolerance = false;
00027    _toler = 0;
00028  }
00029 
00030 inline void setmv ( srbvmat m, srbvvec v, const SrMat& srm )
00031  {
00032    # define SRM(i) (srbvreal)(srm[i])
00033    // here we pass from column-major to line-major order:
00034    m[0][0]=SRM(0); m[1][0]=SRM(1); m[2][0]=SRM(2);
00035    m[0][1]=SRM(4); m[1][1]=SRM(5); m[2][1]=SRM(6);
00036    m[0][2]=SRM(8); m[1][2]=SRM(9); m[2][2]=SRM(10);
00037    v[0]=SRM(12); v[1]=SRM(13); v[2]=SRM(14);
00038    # undef SRM
00039  }
00040 
00041 
00042 bool SrBvTreeQuery::collide ( const SrMat& m1, const SrBvTree* t1,
00043                               const SrMat& m2, const SrBvTree* t2 )
00044  {
00045    srbvmat R1, R2;
00046    srbvvec T1, T2;
00047    setmv ( R1, T1, m1 );
00048    setmv ( R2, T2, m2 );
00049    collide ( R1, T1, t1, R2, T2, t2, CollideFirstContact );
00050    return _pairs.size()>0? true:false;
00051  }
00052 
00053 int SrBvTreeQuery::collide_all ( const SrMat& m1, const SrBvTree* t1,
00054                                  const SrMat& m2, const SrBvTree* t2 )
00055  {
00056    srbvmat R1, R2;
00057    srbvvec T1, T2;
00058    setmv ( R1, T1, m1 );
00059    setmv ( R2, T2, m2 );
00060    collide ( R1, T1, t1, R2, T2, t2, CollideAllContacts );
00061    return _pairs.size();
00062  }
00063 
00064 float SrBvTreeQuery::distance ( const SrMat& m1, SrBvTree* t1,
00065                                 const SrMat& m2, SrBvTree* t2,
00066                                 float rel_err, float abs_err )
00067  {
00068    srbvmat R1, R2;
00069    srbvvec T1, T2;
00070    setmv ( R1, T1, m1 );
00071    setmv ( R2, T2, m2 );
00072    _distance ( R1, T1, t1, R2, T2, t2, rel_err, abs_err );
00073    _srp1.set ( _p1 );
00074    _srp2.set ( _p2 );
00075    return distance();
00076  }
00077 
00078 bool SrBvTreeQuery::tolerance ( const SrMat& m1, SrBvTree* t1,
00079                                 const SrMat& m2, SrBvTree* t2,
00080                                 float tolerance )
00081  {
00082    srbvmat R1, R2;
00083    srbvvec T1, T2;
00084    setmv ( R1, T1, m1 );
00085    setmv ( R2, T2, m2 );
00086    return SrBvTreeQuery::tolerance ( R1, T1, t1, R2, T2, t2, tolerance );
00087  }
00088 
00089 float SrBvTreeQuery::greedy_distance ( const SrMat& m1, SrBvTree* t1,
00090                                        const SrMat& m2, SrBvTree* t2, float delta )
00091  {
00092    srbvmat R1, R2;
00093    srbvvec T1, T2;
00094    setmv ( R1, T1, m1 );
00095    setmv ( R2, T2, m2 );
00096    return SrBvTreeQuery::greedy_distance ( R1, T1, t1, R2, T2, t2, delta );
00097  }
00098 
00099 //====================== static functions ======================
00100 
00101 inline srbvreal max ( srbvreal a, srbvreal b, srbvreal c )
00102 {
00103   srbvreal t = a;
00104   if (b > t) t = b;
00105   if (c > t) t = c;
00106   return t;
00107 }
00108 
00109 inline srbvreal min ( srbvreal a, srbvreal b, srbvreal c )
00110 {
00111   srbvreal t = a;
00112   if (b < t) t = b;
00113   if (c < t) t = c;
00114   return t;
00115 }
00116 
00117 static int project6 ( srbvreal *ax, 
00118          srbvreal *p1, srbvreal *p2, srbvreal *p3, 
00119          srbvreal *q1, srbvreal *q2, srbvreal *q3 )
00120 {
00121   using namespace SrBvMath;
00122   srbvreal P1 = VdotV(ax, p1);
00123   srbvreal P2 = VdotV(ax, p2);
00124   srbvreal P3 = VdotV(ax, p3);
00125   srbvreal Q1 = VdotV(ax, q1);
00126   srbvreal Q2 = VdotV(ax, q2);
00127   srbvreal Q3 = VdotV(ax, q3);
00128   
00129   srbvreal mx1 = max(P1, P2, P3);
00130   srbvreal mn1 = min(P1, P2, P3);
00131   srbvreal mx2 = max(Q1, Q2, Q3);
00132   srbvreal mn2 = min(Q1, Q2, Q3);
00133 
00134   if (mn1 > mx2) return 0;
00135   if (mn2 > mx1) return 0;
00136   return 1;
00137 }
00138 
00139 // very robust triangle intersection test
00140 // uses no divisions
00141 // works on coplanar triangles
00142 static int TriContact( 
00143            const srbvreal *P1, const srbvreal *P2, const srbvreal *P3,
00144            const srbvreal *Q1, const srbvreal *Q2, const srbvreal *Q3 )
00145 {
00146   // One triangle is (p1,p2,p3).  Other is (q1,q2,q3).
00147   // Edges are (e1,e2,e3) and (f1,f2,f3).
00148   // Normals are n1 and m1
00149   // Outwards are (g1,g2,g3) and (h1,h2,h3).
00150   //  
00151   // We assume that the triangle vertices are in the same coordinate system.
00152   //
00153   // First thing we do is establish a new c.s. so that p1 is at (0,0,0).
00154 
00155   srbvreal p1[3], p2[3], p3[3];
00156   srbvreal q1[3], q2[3], q3[3];
00157   srbvreal e1[3], e2[3], e3[3];
00158   srbvreal f1[3], f2[3], f3[3];
00159   srbvreal g1[3], g2[3], g3[3];
00160   srbvreal h1[3], h2[3], h3[3];
00161   srbvreal n1[3], m1[3];
00162 
00163   srbvreal ef11[3], ef12[3], ef13[3];
00164   srbvreal ef21[3], ef22[3], ef23[3];
00165   srbvreal ef31[3], ef32[3], ef33[3];
00166   
00167   p1[0] = P1[0] - P1[0];  p1[1] = P1[1] - P1[1];  p1[2] = P1[2] - P1[2];
00168   p2[0] = P2[0] - P1[0];  p2[1] = P2[1] - P1[1];  p2[2] = P2[2] - P1[2];
00169   p3[0] = P3[0] - P1[0];  p3[1] = P3[1] - P1[1];  p3[2] = P3[2] - P1[2];
00170   
00171   q1[0] = Q1[0] - P1[0];  q1[1] = Q1[1] - P1[1];  q1[2] = Q1[2] - P1[2];
00172   q2[0] = Q2[0] - P1[0];  q2[1] = Q2[1] - P1[1];  q2[2] = Q2[2] - P1[2];
00173   q3[0] = Q3[0] - P1[0];  q3[1] = Q3[1] - P1[1];  q3[2] = Q3[2] - P1[2];
00174   
00175   e1[0] = p2[0] - p1[0];  e1[1] = p2[1] - p1[1];  e1[2] = p2[2] - p1[2];
00176   e2[0] = p3[0] - p2[0];  e2[1] = p3[1] - p2[1];  e2[2] = p3[2] - p2[2];
00177   e3[0] = p1[0] - p3[0];  e3[1] = p1[1] - p3[1];  e3[2] = p1[2] - p3[2];
00178 
00179   f1[0] = q2[0] - q1[0];  f1[1] = q2[1] - q1[1];  f1[2] = q2[2] - q1[2];
00180   f2[0] = q3[0] - q2[0];  f2[1] = q3[1] - q2[1];  f2[2] = q3[2] - q2[2];
00181   f3[0] = q1[0] - q3[0];  f3[1] = q1[1] - q3[1];  f3[2] = q1[2] - q3[2];
00182   
00183   using namespace SrBvMath;
00184 
00185   VcrossV(n1, e1, e2);
00186   VcrossV(m1, f1, f2);
00187 
00188   VcrossV(g1, e1, n1);
00189   VcrossV(g2, e2, n1);
00190   VcrossV(g3, e3, n1);
00191   VcrossV(h1, f1, m1);
00192   VcrossV(h2, f2, m1);
00193   VcrossV(h3, f3, m1);
00194 
00195   VcrossV(ef11, e1, f1);
00196   VcrossV(ef12, e1, f2);
00197   VcrossV(ef13, e1, f3);
00198   VcrossV(ef21, e2, f1);
00199   VcrossV(ef22, e2, f2);
00200   VcrossV(ef23, e2, f3);
00201   VcrossV(ef31, e3, f1);
00202   VcrossV(ef32, e3, f2);
00203   VcrossV(ef33, e3, f3);
00204   
00205   // now begin the series of tests
00206 
00207   if (!project6(n1, p1, p2, p3, q1, q2, q3)) return 0;
00208   if (!project6(m1, p1, p2, p3, q1, q2, q3)) return 0;
00209   
00210   if (!project6(ef11, p1, p2, p3, q1, q2, q3)) return 0;
00211   if (!project6(ef12, p1, p2, p3, q1, q2, q3)) return 0;
00212   if (!project6(ef13, p1, p2, p3, q1, q2, q3)) return 0;
00213   if (!project6(ef21, p1, p2, p3, q1, q2, q3)) return 0;
00214   if (!project6(ef22, p1, p2, p3, q1, q2, q3)) return 0;
00215   if (!project6(ef23, p1, p2, p3, q1, q2, q3)) return 0;
00216   if (!project6(ef31, p1, p2, p3, q1, q2, q3)) return 0;
00217   if (!project6(ef32, p1, p2, p3, q1, q2, q3)) return 0;
00218   if (!project6(ef33, p1, p2, p3, q1, q2, q3)) return 0;
00219 
00220   if (!project6(g1, p1, p2, p3, q1, q2, q3)) return 0;
00221   if (!project6(g2, p1, p2, p3, q1, q2, q3)) return 0;
00222   if (!project6(g3, p1, p2, p3, q1, q2, q3)) return 0;
00223   if (!project6(h1, p1, p2, p3, q1, q2, q3)) return 0;
00224   if (!project6(h2, p1, p2, p3, q1, q2, q3)) return 0;
00225   if (!project6(h3, p1, p2, p3, q1, q2, q3)) return 0;
00226 
00227   return 1;
00228 }
00229 
00230 /**************************/
00231 /******* COLLIDE **********/
00232 /**************************/
00233 
00234 void SrBvTreeQuery::collide (
00235             srbvmat R1, srbvvec T1, const SrBvTree* o1,
00236             srbvmat R2, srbvvec T2, const SrBvTree* o2,
00237             CollideFlag flag )
00238 {
00239   // clear the data:
00240   _num_bv_tests = 0;
00241   _num_tri_tests = 0;
00242   _pairs.size(0);
00243 
00244   // make sure that the models are built:
00245   if ( o1->nodes()==0 || o2->nodes()==0 ) return;
00246 
00247   // Okay, compute what transform [R,T] that takes us from cs1 to cs2.
00248   // [R,T] = [R1,T1]'[R2,T2] = [R1',-R1'T][R2,T2] = [R1'R2, R1'(T2-T1)]
00249   // First compute the rotation part, then translation part
00250   using namespace SrBvMath;
00251   MTxM(_R,R1,R2);
00252   srbvvec Ttemp;
00253   VmV(Ttemp, T2, T1);  
00254   MTxV(_T, R1, Ttemp);
00255   
00256   // compute the transform from o1->child(0) to o2->child(0)
00257   srbvmat Rtemp, R;
00258   srbvvec T;
00259   MxM(Rtemp,_R,o2->const_child(0)->R);
00260   MTxM(R,o1->const_child(0)->R,Rtemp);
00261   MxVpV(Ttemp,_R,o2->const_child(0)->To,_T);
00262   VmV(Ttemp,Ttemp,o1->const_child(0)->To);
00263   MTxV(T,o1->const_child(0)->R,Ttemp);
00264 
00265   // now start with both top level BVs  
00266   _collide_recurse ( R, T, o1, 0, o2, 0, flag );
00267 }
00268 
00269 float SrBvTreeQuery::greedy_distance ( srbvmat R1, srbvvec T1, SrBvTree* o1,
00270                                        srbvmat R2, srbvvec T2, SrBvTree* o2, float delta )
00271  {
00272   using namespace SrBvMath;
00273   MTxM(_R,R1,R2);
00274   double Ttemp[3];
00275   VmV(Ttemp, T2, T1);  
00276   MTxV(_T, R1, Ttemp);
00277   
00278   _num_bv_tests = 0;
00279   _num_tri_tests = 0;
00280 
00281   srbvmat Rtemp, R;
00282   srbvvec T;
00283 
00284   MxM(Rtemp,_R,o2->child(0)->R);
00285   MTxM(R,o1->child(0)->R,Rtemp);
00286   
00287   MxVpV(Ttemp,_R,o2->child(0)->Tr,_T);
00288   VmV(Ttemp,Ttemp,o1->child(0)->Tr);
00289   MTxV(T,o1->child(0)->R,Ttemp);
00290 
00291   // first, see if top-level BVs are separated
00292   _num_bv_tests += 1;
00293   srbvreal d = SrBv::distance(R, T, o1->child(0), o2->child(0));
00294 
00295   // if we already found separation don't bother recursing to refine it
00296   if ( float(d) > delta )
00297     return (float)d;
00298   else // if top-level BVs are not separated, recurse
00299     return (float)_greedy_distance_recurse(R,T,o1,0,o2,0,delta);
00300  }
00301 
00302 //====================== private methods ======================
00303 
00304 inline
00305 srbvreal
00306 TriDistance(srbvreal R[3][3], srbvreal T[3], const SrBvTri *t1, const SrBvTri *t2,
00307             srbvreal p[3], srbvreal q[3])
00308 {
00309   // transform tri 2 into same space as tri 1
00310 
00311   srbvreal tri1[3][3], tri2[3][3];
00312   using namespace SrBvMath;
00313   VcV(tri1[0], t1->p1);
00314   VcV(tri1[1], t1->p2);
00315   VcV(tri1[2], t1->p3);
00316   MxVpV(tri2[0], R, t2->p1, T);
00317   MxVpV(tri2[1], R, t2->p2, T);
00318   MxVpV(tri2[2], R, t2->p3, T);
00319                                 
00320   return TriDist(p,q,tri1,tri2);
00321 }
00322 
00323 void SrBvTreeQuery::_collide_recurse (
00324                srbvmat R, srbvvec T, // b2 relative to b1
00325                const SrBvTree* o1, int b1, 
00326                const SrBvTree* o2, int b2, int flag)
00327 {
00328   // first thing, see if we're overlapping
00329 
00330   _num_bv_tests++;
00331 
00332   if ( !SrBv::overlap(R,T,o1->const_child(b1), o2->const_child(b2))) return;
00333 
00334   // if we are, see if we test triangles next
00335 
00336   bool l1 = o1->const_child(b1)->leaf();
00337   bool l2 = o2->const_child(b2)->leaf();
00338   using namespace SrBvMath;
00339 
00340   if (l1 && l2) 
00341   {
00342     _num_tri_tests++;
00343 
00344     // transform the points in b2 into space of b1, then compare
00345     const SrBvTri *t1 = o1->tri(-o1->const_child(b1)->first_child - 1);
00346     const SrBvTri *t2 = o2->tri(-o2->const_child(b2)->first_child - 1);
00347     srbvreal q1[3], q2[3], q3[3];
00348     const srbvreal *p1 = t1->p1;
00349     const srbvreal *p2 = t1->p2;
00350     const srbvreal *p3 = t1->p3;    
00351     MxVpV(q1, _R, t2->p1, _T);
00352     MxVpV(q2, _R, t2->p2, _T);
00353     MxVpV(q3, _R, t2->p3, _T);
00354     if (TriContact(p1, p2, p3, q1, q2, q3)) 
00355     { // add this to result
00356       _pairs.push() = t1->id;
00357       _pairs.push() = t2->id;
00358     }
00359     return;
00360   }
00361 
00362   // we dont, so decide whose children to visit next
00363 
00364   srbvreal sz1 = o1->const_child(b1)->size();
00365   srbvreal sz2 = o2->const_child(b2)->size();
00366 
00367   srbvreal Rc[3][3],Tc[3],Ttemp[3];
00368     
00369   if (l2 || (!l1 && (sz1 > sz2)))
00370   {
00371     int c1 = o1->const_child(b1)->first_child;
00372     int c2 = c1 + 1;
00373 
00374     MTxM(Rc,o1->const_child(c1)->R,R);
00375     VmV(Ttemp,T,o1->const_child(c1)->To);
00376     MTxV(Tc,o1->const_child(c1)->R,Ttemp);
00377     _collide_recurse(Rc,Tc,o1,c1,o2,b2,flag);
00378 
00379     if ( flag==CollideFirstContact && _pairs.size()>0 ) return;
00380 
00381     MTxM(Rc,o1->const_child(c2)->R,R);
00382     VmV(Ttemp,T,o1->const_child(c2)->To);
00383     MTxV(Tc,o1->const_child(c2)->R,Ttemp);
00384     _collide_recurse(Rc,Tc,o1,c2,o2,b2,flag);
00385   }
00386   else 
00387   {
00388     int c1 = o2->const_child(b2)->first_child;
00389     int c2 = c1 + 1;
00390 
00391     MxM(Rc,R,o2->const_child(c1)->R);
00392     MxVpV(Tc,R,o2->const_child(c1)->To,T);
00393     _collide_recurse(Rc,Tc,o1,b1,o2,c1,flag);
00394 
00395     if ( flag==CollideFirstContact && _pairs.size()>0 ) return;
00396 
00397     MxM(Rc,R,o2->const_child(c2)->R);
00398     MxVpV(Tc,R,o2->const_child(c2)->To,T);
00399     _collide_recurse(Rc,Tc,o1,b1,o2,c2,flag);
00400   }
00401 }
00402 
00403 /***************************/
00404 /******* DISTANCE **********/
00405 /***************************/
00406 void SrBvTreeQuery::_distance ( srbvmat R1, srbvvec T1, SrBvTree* o1,
00407                                 srbvmat R2, srbvvec T2, SrBvTree* o2,
00408                                 srbvreal rel_err, srbvreal abs_err )
00409  {
00410   // init data:
00411   _dist = 0;
00412   _num_bv_tests = 0;
00413   _num_tri_tests = 0;
00414   _abs_err = abs_err;
00415   _rel_err = rel_err;
00416 
00417   // make sure that the models are built:
00418   if ( o1->nodes()==0 || o2->nodes()==0 ) return;
00419 
00420   // Okay, compute what transform [R,T] that takes us from cs2 to cs1.
00421   // [R,T] = [R1,T1]'[R2,T2] = [R1',-R1'T][R2,T2] = [R1'R2, R1'(T2-T1)]
00422   // First compute the rotation part, then translation part
00423   using namespace SrBvMath;
00424 
00425   MTxM(_R,R1,R2);
00426   srbvreal Ttemp[3];
00427   VmV(Ttemp, T2, T1);  
00428   MTxV(_T, R1, Ttemp);
00429   
00430   // establish initial upper bound using last triangles which 
00431   // provided the minimum distance
00432   srbvvec p,q;
00433   _dist = TriDistance(_R,_T,o1->_last_tri,o2->_last_tri,p,q);
00434   VcV(_p1,p);
00435   VcV(_p2,q);
00436   
00437   // compute the transform from o1->child(0) to o2->child(0)
00438   srbvreal Rtemp[3][3], R[3][3], T[3];
00439 
00440   MxM(Rtemp,_R,o2->const_child(0)->R);
00441   MTxM(R,o1->const_child(0)->R,Rtemp);
00442   
00443   MxVpV(Ttemp,_R,o2->const_child(0)->Tr,_T);
00444   VmV(Ttemp,Ttemp,o1->const_child(0)->Tr);
00445   MTxV(T,o1->const_child(0)->R,Ttemp);
00446 
00447   _distance_recurse(R,T,o1,0,o2,0);    
00448 
00449   // res->p2 is in cs 1 ; transform it to cs 2
00450   srbvvec u;
00451   VmV(u, _p2, _T);
00452   MTxV(_p2, _R, u);
00453  }
00454 
00455 void SrBvTreeQuery::_distance_recurse (
00456                 srbvmat R, srbvvec T, // b2 relative to b1
00457                 SrBvTree* o1, int b1,
00458                 SrBvTree* o2, int b2 )
00459 {
00460   using namespace SrBvMath;
00461 
00462   srbvreal sz1 = o1->const_child(b1)->size();
00463   srbvreal sz2 = o2->const_child(b2)->size();
00464   bool l1 = o1->const_child(b1)->leaf();
00465   bool l2 = o2->const_child(b2)->leaf();
00466 
00467   if ( l1 && l2 )
00468   { // both leaves.  Test the triangles beneath them.
00469     _num_tri_tests++;
00470 
00471     srbvreal p[3], q[3];
00472 
00473     SrBvTri *t1 = &o1->_tris[-o1->child(b1)->first_child - 1];
00474     SrBvTri *t2 = &o2->_tris[-o2->child(b2)->first_child - 1];
00475 
00476     srbvreal d = TriDistance(_R,_T,t1,t2,p,q);
00477   
00478     if ( d<_dist ) 
00479     {
00480       _dist = d;
00481 
00482       VcV(_p1, p);         // p already in c.s. 1
00483       VcV(_p2, q);         // q must be transformed 
00484                                // into c.s. 2 later
00485       o1->_last_tri = t1;
00486       o2->_last_tri = t2;
00487     }
00488     return;
00489   }
00490 
00491   // First, perform distance tests on the children. Then traverse 
00492   // them recursively, but test the closer pair first, the further 
00493   // pair second.
00494 
00495   int a1,a2,c1,c2;  // new bv tests 'a' and 'c'
00496   srbvreal R1[3][3], T1[3], R2[3][3], T2[3], Ttemp[3];
00497 
00498   if (l2 || (!l1 && (sz1 > sz2)))
00499   {
00500     // visit the children of b1
00501 
00502     a1 = o1->child(b1)->first_child;
00503     a2 = b2;
00504     c1 = o1->child(b1)->first_child+1;
00505     c2 = b2;
00506     
00507     MTxM(R1,o1->const_child(a1)->R,R);
00508     VmV(Ttemp,T,o1->const_child(a1)->Tr);
00509     MTxV(T1,o1->const_child(a1)->R,Ttemp);
00510 
00511     MTxM(R2,o1->const_child(c1)->R,R);
00512     VmV(Ttemp,T,o1->const_child(c1)->Tr);
00513     MTxV(T2,o1->const_child(c1)->R,Ttemp);
00514   }
00515   else 
00516   {
00517     // visit the children of b2
00518     a1 = b1;
00519     a2 = o2->child(b2)->first_child;
00520     c1 = b1;
00521     c2 = o2->child(b2)->first_child+1;
00522 
00523     MxM(R1,R,o2->const_child(a2)->R);
00524     MxVpV(T1,R,o2->const_child(a2)->Tr,T);
00525 
00526     MxM(R2,R,o2->const_child(c2)->R);
00527     MxVpV(T2,R,o2->const_child(c2)->Tr,T);
00528   }
00529 
00530   _num_bv_tests += 2;
00531 
00532   srbvreal d1 = SrBv::distance(R1, T1, o1->const_child(a1), o2->const_child(a2));
00533   srbvreal d2 = SrBv::distance(R2, T2, o1->const_child(c1), o2->const_child(c2));
00534 
00535   if (d2 < d1)
00536   {
00537     if ((d2 < (_dist - _abs_err)) || 
00538         (d2*(1 + _rel_err) < _dist)) 
00539     {      
00540       _distance_recurse(R2, T2, o1, c1, o2, c2);      
00541     }
00542 
00543     if ((d1 < (_dist - _abs_err)) || 
00544         (d1*(1 + _rel_err) < _dist)) 
00545     {      
00546       _distance_recurse(R1, T1, o1, a1, o2, a2);
00547     }
00548   }
00549   else 
00550   {
00551     if ((d1 < (_dist - _abs_err)) || 
00552         (d1*(1 + _rel_err) < _dist)) 
00553     {      
00554       _distance_recurse(R1, T1, o1, a1, o2, a2);
00555     }
00556 
00557     if ((d2 < (_dist - _abs_err)) || 
00558         (d2*(1 + _rel_err) < _dist)) 
00559     {      
00560       _distance_recurse(R2, T2, o1, c1, o2, c2);      
00561     }
00562   }
00563 }
00564 
00565 /***************************/
00566 /******* TOLERANCE *********/
00567 /***************************/
00568 
00569 void SrBvTreeQuery::_tolerance (  srbvmat R1, srbvvec T1, SrBvTree* o1,
00570                                   srbvmat R2, srbvvec T2, SrBvTree* o2,
00571                                   srbvreal tolerance )
00572 {
00573   using namespace SrBvMath;
00574 
00575   // init data:
00576 //  _dist = 0;
00577   _num_bv_tests = 0;
00578   _num_tri_tests = 0;
00579   if ( tolerance<0 ) tolerance=0.0;
00580   _toler = tolerance;
00581   _closer_than_tolerance = false;
00582 
00583   // make sure that the models are built:
00584   if ( o1->nodes()==0 || o2->nodes()==0 ) return;
00585   
00586   // Compute the transform [R,T] that takes us from cs2 to cs1.
00587   // [R,T] = [R1,T1]'[R2,T2] = [R1',-R1'T][R2,T2] = [R1'R2, R1'(T2-T1)]
00588 
00589   MTxM(_R,R1,R2);
00590   srbvreal Ttemp[3];
00591   VmV(Ttemp, T2, T1);
00592   MTxV(_T, R1, Ttemp);
00593 
00594   // compute the transform from o1->child(0) to o2->child(0)
00595   srbvreal Rtemp[3][3], R[3][3], T[3];
00596 
00597   MxM(Rtemp,_R,o2->child(0)->R);
00598   MTxM(R,o1->child(0)->R,Rtemp);
00599   MxVpV(Ttemp,_R,o2->child(0)->Tr,_T);
00600   VmV(Ttemp,Ttemp,o1->child(0)->Tr);
00601   MTxV(T,o1->child(0)->R,Ttemp);
00602 
00603   // find a distance lower bound for trivial reject
00604 
00605   srbvreal d = SrBv::distance(R, T, o1->child(0), o2->child(0));
00606   
00607   if ( d <= _toler )
00608   { _tolerance_recurse ( R, T, o1, 0, o2, 0 );
00609   }
00610 
00611   // res->p2 is in cs 1 ; transform it to cs 2
00612   srbvreal u[3];
00613   VmV(u, _p2, _T);
00614   MTxV(_p2, _R, u);
00615 }
00616 
00617 void SrBvTreeQuery::_tolerance_recurse 
00618                     ( srbvmat R, srbvvec T,
00619                       SrBvTree* o1, int b1,
00620                       SrBvTree* o2, int b2 )
00621 {
00622   using namespace SrBvMath;
00623 
00624   srbvreal sz1 = o1->child(b1)->size();
00625   srbvreal sz2 = o2->child(b2)->size();
00626   int l1 = o1->child(b1)->leaf();
00627   int l2 = o2->child(b2)->leaf();
00628 
00629   if (l1 && l2) 
00630   {
00631     // both leaves - find if tri pair within tolerance
00632     
00633     _num_tri_tests++;
00634 
00635     srbvreal p[3], q[3];
00636 
00637     SrBvTri *t1 = &o1->_tris[-o1->child(b1)->first_child - 1];
00638     SrBvTri *t2 = &o2->_tris[-o2->child(b2)->first_child - 1];
00639 
00640     srbvreal d = TriDistance(_R,_T,t1,t2,p,q);
00641     
00642     if ( d<=_toler )  
00643     {  
00644       // triangle pair distance less than tolerance
00645       _closer_than_tolerance = true;
00646       _dist = d;
00647       VcV(_p1, p);         // p already in c.s. 1
00648       VcV(_p2, q);         // q must be transformed into c.s. 2 later
00649     }
00650     return;
00651   }
00652 
00653   int a1,a2,c1,c2;  // new bv tests 'a' and 'c'
00654   srbvreal R1[3][3], T1[3], R2[3][3], T2[3], Ttemp[3];
00655 
00656   if (l2 || (!l1 && (sz1 > sz2)))
00657   {
00658     // visit the children of b1
00659 
00660     a1 = o1->child(b1)->first_child;
00661     a2 = b2;
00662     c1 = o1->child(b1)->first_child+1;
00663     c2 = b2;
00664     
00665     MTxM(R1,o1->child(a1)->R,R);
00666     VmV(Ttemp,T,o1->child(a1)->Tr);
00667     MTxV(T1,o1->child(a1)->R,Ttemp);
00668 
00669     MTxM(R2,o1->child(c1)->R,R);
00670     VmV(Ttemp,T,o1->child(c1)->Tr);
00671     MTxV(T2,o1->child(c1)->R,Ttemp);
00672   }
00673   else 
00674   {
00675     // visit the children of b2
00676 
00677     a1 = b1;
00678     a2 = o2->child(b2)->first_child;
00679     c1 = b1;
00680     c2 = o2->child(b2)->first_child+1;
00681 
00682     MxM(R1,R,o2->child(a2)->R);
00683     MxVpV(T1,R,o2->child(a2)->Tr,T);
00684     MxM(R2,R,o2->child(c2)->R);
00685     MxVpV(T2,R,o2->child(c2)->Tr,T);
00686   }
00687 
00688   _num_bv_tests += 2;
00689 
00690   srbvreal d1 = SrBv::distance(R1, T1, o1->child(a1), o2->child(a2));
00691   srbvreal d2 = SrBv::distance(R2, T2, o1->child(c1), o2->child(c2));
00692 
00693   if (d2 < d1) 
00694   {
00695     if (d2 <= _toler) _tolerance_recurse( R2, T2, o1, c1, o2, c2);
00696     if (_closer_than_tolerance) return;
00697     if (d1 <= _toler) _tolerance_recurse( R1, T1, o1, a1, o2, a2);
00698   }
00699   else 
00700   {
00701     if (d1 <= _toler) _tolerance_recurse( R1, T1, o1, a1, o2, a2);
00702     if (_closer_than_tolerance) return;
00703     if (d2 <= _toler) _tolerance_recurse( R2, T2, o1, c1, o2, c2);
00704   }
00705 }
00706 
00707 
00708 srbvreal SrBvTreeQuery::_greedy_distance_recurse ( 
00709                         srbvmat R, srbvvec T, SrBvTree* o1, int b1,
00710                         SrBvTree* o2, int b2, srbvreal delta )
00711 {
00712   using namespace SrBvMath;
00713 
00714   int l1 = o1->child(b1)->leaf();
00715   int l2 = o2->child(b2)->leaf();
00716 
00717   if (l1 && l2)
00718   {
00719     // both leaves.  return their distance
00720     _num_tri_tests++;
00721 
00722     double p[3], q[3];
00723 
00724     const SrBvTri *t1 = o1->tri(-o1->child(b1)->first_child - 1);
00725     const SrBvTri *t2 = o2->tri(-o2->child(b2)->first_child - 1);
00726 
00727     return TriDistance(_R,_T,t1,t2,p,q);  
00728   }
00729 
00730   // First, perform distance tests on the children. Then traverse 
00731   // them recursively, but test the closer pair first, the further 
00732   // pair second.
00733 
00734   int a1,a2,c1,c2;  // new bv tests 'a' and 'c'
00735   double R1[3][3], T1[3], R2[3][3], T2[3], Ttemp[3];
00736 
00737   srbvreal sz1 = o1->child(b1)->size();
00738   srbvreal sz2 = o2->child(b2)->size();
00739 
00740   if (l2 || (!l1 && (sz1 > sz2)))
00741   {
00742     // visit the children of b1
00743 
00744     a1 = o1->child(b1)->first_child;
00745     a2 = b2;
00746     c1 = o1->child(b1)->first_child+1;
00747     c2 = b2;
00748     
00749     MTxM(R1,o1->child(a1)->R,R);
00750     VmV(Ttemp,T,o1->child(a1)->Tr);
00751     MTxV(T1,o1->child(a1)->R,Ttemp);
00752 
00753     MTxM(R2,o1->child(c1)->R,R);
00754     VmV(Ttemp,T,o1->child(c1)->Tr);
00755     MTxV(T2,o1->child(c1)->R,Ttemp);
00756   }
00757   else 
00758   {
00759     // visit the children of b2
00760 
00761     a1 = b1;
00762     a2 = o2->child(b2)->first_child;
00763     c1 = b1;
00764     c2 = o2->child(b2)->first_child+1;
00765 
00766     MxM(R1,R,o2->child(a2)->R);
00767     MxVpV(T1,R,o2->child(a2)->Tr,T);
00768 
00769     MxM(R2,R,o2->child(c2)->R);
00770     MxVpV(T2,R,o2->child(c2)->Tr,T);
00771   }
00772 
00773   double d1 = SrBv::distance(R1, T1, o1->child(a1), o2->child(a2));
00774   double d2 = SrBv::distance(R2, T2, o1->child(c1), o2->child(c2));
00775   _num_bv_tests += 2;
00776 
00777   // if we already found separation, don't further recurse to refine it
00778   double min_d1d2 = (d1 < d2) ? d1 : d2;
00779   if ( min_d1d2 > delta )
00780     return min_d1d2;
00781 
00782   // else recurse
00783   if (d2 < d1) // and thus at least d2 <= delta (d1 maybe too)
00784   {
00785     srbvreal alpha = _greedy_distance_recurse(R2, T2, o1, c1, o2, c2, delta);
00786     
00787     if ( alpha > delta ) {
00788       if ( d1 > delta )
00789     return (alpha < d1)? alpha: d1;
00790       srbvreal beta = _greedy_distance_recurse(R1, T1, o1, a1, o2, a2, delta);
00791       if ( beta > delta )
00792     return (alpha < beta)? alpha: beta;
00793     }
00794     return 0;
00795   }
00796   else // at least d1 <= delta (d2 maybe too)
00797   {
00798     srbvreal alpha = _greedy_distance_recurse(R1, T1, o1, a1, o2, a2, delta);
00799 
00800     if ( alpha > delta ) {
00801       if ( d2 > delta )
00802     return (alpha < d2)? alpha: d2;
00803       srbvreal beta = _greedy_distance_recurse(R2, T2, o1, c1, o2, c2, delta);
00804       if ( beta > delta )
00805     return (alpha < beta)? alpha: beta;
00806     }
00807     return 0;
00808   }
00809 }
00810 
00811 /*************************************************************************\
00812   Copyright 1999 The University of North Carolina at Chapel Hill.
00813   All Rights Reserved.
00814 
00815   Permission to use, copy, modify and distribute this software and its
00816   documentation for educational, research and non-profit purposes, without
00817   fee, and without a written agreement is hereby granted, provided that the
00818   above copyright notice and the following three paragraphs appear in all
00819   copies.
00820 
00821   IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL BE
00822   LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
00823   CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE
00824   USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY
00825   OF NORTH CAROLINA HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
00826   DAMAGES.
00827 
00828   THE UNIVERSITY OF NORTH CAROLINA SPECIFICALLY DISCLAIM ANY
00829   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00830   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE
00831   PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
00832   NORTH CAROLINA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
00833   UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00834 
00835   The authors may be contacted via:
00836 
00837   US Mail:             S. Gottschalk, E. Larsen
00838                        Department of Computer Science
00839                        Sitterson Hall, CB #3175
00840                        University of N. Carolina
00841                        Chapel Hill, NC 27599-3175
00842   Phone:               (919)962-1749
00843   EMail:               geom@cs.unc.edu
00844 \**************************************************************************/


Generated on Fri May 18 2012 03:02:47 for ORTS by Doxygen1.7.3