|
ORTS
|
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 \**************************************************************************/