00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00037 #include "fcl/broadphase/broadphase_dynamic_AABB_tree_array.h"
00038
00039 namespace fcl
00040 {
00041
00042 void DynamicAABBTreeCollisionManager_Array::registerObjects(const std::vector<CollisionObject*>& other_objs)
00043 {
00044 if(size() > 0)
00045 {
00046 BroadPhaseCollisionManager::registerObjects(other_objs);
00047 }
00048 else
00049 {
00050 DynamicAABBNode* leaves = new DynamicAABBNode[other_objs.size()];
00051 table.rehash(other_objs.size());
00052 for(size_t i = 0, size = other_objs.size(); i < size; ++i)
00053 {
00054 leaves[i].bv = other_objs[i]->getAABB();
00055 leaves[i].parent = dtree.NULL_NODE;
00056 leaves[i].children[1] = dtree.NULL_NODE;
00057 leaves[i].data = other_objs[i];
00058 table[other_objs[i]] = i;
00059 }
00060
00061 int n_leaves = other_objs.size();
00062
00063 dtree.init(leaves, n_leaves, tree_init_level);
00064
00065 setup_ = true;
00066 }
00067 }
00068
00069 void DynamicAABBTreeCollisionManager_Array::registerObject(CollisionObject* obj)
00070 {
00071 size_t node = dtree.insert(obj->getAABB(), obj);
00072 table[obj] = node;
00073 }
00074
00075 void DynamicAABBTreeCollisionManager_Array::unregisterObject(CollisionObject* obj)
00076 {
00077 size_t node = table[obj];
00078 table.erase(obj);
00079 dtree.remove(node);
00080 }
00081
00082 void DynamicAABBTreeCollisionManager_Array::setup()
00083 {
00084 if(!setup_)
00085 {
00086 int num = dtree.size();
00087 if(num == 0)
00088 {
00089 setup_ = true;
00090 return;
00091 }
00092
00093 int height = dtree.getMaxHeight();
00094
00095
00096 if(height - std::log((FCL_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level)
00097 dtree.balanceIncremental(tree_incremental_balance_pass);
00098 else
00099 dtree.balanceTopdown();
00100
00101 setup_ = true;
00102 }
00103 }
00104
00105
00106 void DynamicAABBTreeCollisionManager_Array::update()
00107 {
00108 for(DynamicAABBTable::const_iterator it = table.begin(), end = table.end(); it != end; ++it)
00109 {
00110 CollisionObject* obj = it->first;
00111 size_t node = it->second;
00112 dtree.getNodes()[node].bv = obj->getAABB();
00113 }
00114
00115 dtree.refit();
00116 setup_ = false;
00117
00118 setup();
00119 }
00120
00121 void DynamicAABBTreeCollisionManager_Array::update_(CollisionObject* updated_obj)
00122 {
00123 DynamicAABBTable::const_iterator it = table.find(updated_obj);
00124 if(it != table.end())
00125 {
00126 size_t node = it->second;
00127 if(!dtree.getNodes()[node].bv.equal(updated_obj->getAABB()))
00128 dtree.update(node, updated_obj->getAABB());
00129 }
00130 setup_ = false;
00131 }
00132
00133 void DynamicAABBTreeCollisionManager_Array::update(CollisionObject* updated_obj)
00134 {
00135 update_(updated_obj);
00136 setup();
00137 }
00138
00139 void DynamicAABBTreeCollisionManager_Array::update(const std::vector<CollisionObject*>& updated_objs)
00140 {
00141 for(size_t i = 0, size = updated_objs.size(); i < size; ++i)
00142 update_(updated_objs[i]);
00143 setup();
00144 }
00145
00146 bool DynamicAABBTreeCollisionManager_Array::collisionRecurse(DynamicAABBNode* nodes1, size_t root1_id,
00147 DynamicAABBNode* nodes2, size_t root2_id,
00148 void* cdata, CollisionCallBack callback) const
00149 {
00150 DynamicAABBNode* root1 = nodes1 + root1_id;
00151 DynamicAABBNode* root2 = nodes2 + root2_id;
00152 if(root1->isLeaf() && root2->isLeaf())
00153 {
00154 if(!root1->bv.overlap(root2->bv)) return false;
00155 return callback(static_cast<CollisionObject*>(root1->data), static_cast<CollisionObject*>(root2->data), cdata);
00156 }
00157
00158 if(!root1->bv.overlap(root2->bv)) return false;
00159
00160 if(root2->isLeaf() || (!root1->isLeaf() && (root1->bv.size() > root2->bv.size())))
00161 {
00162 if(collisionRecurse(nodes1, root1->children[0], nodes2, root2_id, cdata, callback))
00163 return true;
00164 if(collisionRecurse(nodes1, root1->children[1], nodes2, root2_id, cdata, callback))
00165 return true;
00166 }
00167 else
00168 {
00169 if(collisionRecurse(nodes1, root1_id, nodes2, root2->children[0], cdata, callback))
00170 return true;
00171 if(collisionRecurse(nodes1, root1_id, nodes2, root2->children[1], cdata, callback))
00172 return true;
00173 }
00174 return false;
00175 }
00176
00177 bool DynamicAABBTreeCollisionManager_Array::collisionRecurse(DynamicAABBNode* nodes, size_t root_id, CollisionObject* query, void* cdata, CollisionCallBack callback) const
00178 {
00179 DynamicAABBNode* root = nodes + root_id;
00180 if(root->isLeaf())
00181 {
00182 if(!root->bv.overlap(query->getAABB())) return false;
00183 return callback(static_cast<CollisionObject*>(root->data), query, cdata);
00184 }
00185
00186 if(!root->bv.overlap(query->getAABB())) return false;
00187
00188 int select_res = implementation_array::select(query->getAABB(), root->children[0], root->children[1], nodes);
00189
00190 if(collisionRecurse(nodes, root->children[select_res], query, cdata, callback))
00191 return true;
00192
00193 if(collisionRecurse(nodes, root->children[1-select_res], query, cdata, callback))
00194 return true;
00195
00196 return false;
00197 }
00198
00199 bool DynamicAABBTreeCollisionManager_Array::selfCollisionRecurse(DynamicAABBNode* nodes, size_t root_id, void* cdata, CollisionCallBack callback) const
00200 {
00201 DynamicAABBNode* root = nodes + root_id;
00202 if(root->isLeaf()) return false;
00203
00204 if(selfCollisionRecurse(nodes, root->children[0], cdata, callback))
00205 return true;
00206
00207 if(selfCollisionRecurse(nodes, root->children[1], cdata, callback))
00208 return true;
00209
00210 if(collisionRecurse(nodes, root->children[0], nodes, root->children[1], cdata, callback))
00211 return true;
00212
00213 return false;
00214 }
00215
00216 bool DynamicAABBTreeCollisionManager_Array::distanceRecurse(DynamicAABBNode* nodes1, size_t root1_id,
00217 DynamicAABBNode* nodes2, size_t root2_id,
00218 void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const
00219 {
00220 DynamicAABBNode* root1 = nodes1 + root1_id;
00221 DynamicAABBNode* root2 = nodes2 + root2_id;
00222 if(root1->isLeaf() && root2->isLeaf())
00223 {
00224 CollisionObject* root1_obj = static_cast<CollisionObject*>(root1->data);
00225 CollisionObject* root2_obj = static_cast<CollisionObject*>(root2->data);
00226 return callback(root1_obj, root2_obj, cdata, min_dist);
00227 }
00228
00229 if(root2->isLeaf() || (!root1->isLeaf() && (root1->bv.size() > root2->bv.size())))
00230 {
00231 FCL_REAL d1 = root2->bv.distance((nodes1 + root1->children[0])->bv);
00232 FCL_REAL d2 = root2->bv.distance((nodes1 + root1->children[1])->bv);
00233
00234 if(d2 < d1)
00235 {
00236 if(d2 < min_dist)
00237 {
00238 if(distanceRecurse(nodes1, root1->children[1], nodes2, root2_id, cdata, callback, min_dist))
00239 return true;
00240 }
00241
00242 if(d1 < min_dist)
00243 {
00244 if(distanceRecurse(nodes1, root1->children[0], nodes2, root2_id, cdata, callback, min_dist))
00245 return true;
00246 }
00247 }
00248 else
00249 {
00250 if(d1 < min_dist)
00251 {
00252 if(distanceRecurse(nodes1, root1->children[0], nodes2, root2_id, cdata, callback, min_dist))
00253 return true;
00254 }
00255
00256 if(d2 < min_dist)
00257 {
00258 if(distanceRecurse(nodes1, root1->children[1], nodes2, root2_id, cdata, callback, min_dist))
00259 return true;
00260 }
00261 }
00262 }
00263 else
00264 {
00265 FCL_REAL d1 = root1->bv.distance((nodes2 + root2->children[0])->bv);
00266 FCL_REAL d2 = root1->bv.distance((nodes2 + root2->children[1])->bv);
00267
00268 if(d2 < d1)
00269 {
00270 if(d2 < min_dist)
00271 {
00272 if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[1], cdata, callback, min_dist))
00273 return true;
00274 }
00275
00276 if(d1 < min_dist)
00277 {
00278 if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[0], cdata, callback, min_dist))
00279 return true;
00280 }
00281 }
00282 else
00283 {
00284 if(d1 < min_dist)
00285 {
00286 if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[0], cdata, callback, min_dist))
00287 return true;
00288 }
00289
00290 if(d2 < min_dist)
00291 {
00292 if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[1], cdata, callback, min_dist))
00293 return true;
00294 }
00295 }
00296 }
00297
00298 return false;
00299 }
00300
00301 bool DynamicAABBTreeCollisionManager_Array::distanceRecurse(DynamicAABBNode* nodes, size_t root_id, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const
00302 {
00303 DynamicAABBNode* root = nodes + root_id;
00304 if(root->isLeaf())
00305 {
00306 CollisionObject* root_obj = static_cast<CollisionObject*>(root->data);
00307 return callback(root_obj, query, cdata, min_dist);
00308 }
00309
00310 FCL_REAL d1 = query->getAABB().distance((nodes + root->children[0])->bv);
00311 FCL_REAL d2 = query->getAABB().distance((nodes + root->children[1])->bv);
00312
00313 if(d2 < d1)
00314 {
00315 if(d2 < min_dist)
00316 {
00317 if(distanceRecurse(nodes, root->children[1], query, cdata, callback, min_dist))
00318 return true;
00319 }
00320
00321 if(d1 < min_dist)
00322 {
00323 if(distanceRecurse(nodes, root->children[0], query, cdata, callback, min_dist))
00324 return true;
00325 }
00326 }
00327 else
00328 {
00329 if(d1 < min_dist)
00330 {
00331 if(distanceRecurse(nodes, root->children[0], query, cdata, callback, min_dist))
00332 return true;
00333 }
00334
00335 if(d2 < min_dist)
00336 {
00337 if(distanceRecurse(nodes, root->children[1], query, cdata, callback, min_dist))
00338 return true;
00339 }
00340 }
00341
00342 return false;
00343 }
00344
00345 bool DynamicAABBTreeCollisionManager_Array::selfDistanceRecurse(DynamicAABBNode* nodes, size_t root_id, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const
00346 {
00347 DynamicAABBNode* root = nodes + root_id;
00348 if(root->isLeaf()) return false;
00349
00350 if(selfDistanceRecurse(nodes, root->children[0], cdata, callback, min_dist))
00351 return true;
00352
00353 if(selfDistanceRecurse(nodes, root->children[1], cdata, callback, min_dist))
00354 return true;
00355
00356 if(distanceRecurse(nodes, root->children[0], nodes, root->children[1], cdata, callback, min_dist))
00357 return true;
00358
00359 return false;
00360 }
00361
00362 bool collisionRecurse_(DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback)
00363 {
00364 DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id;
00365 if(root1->isLeaf() && !root2->hasChildren())
00366 {
00367 CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data);
00368 if(!tree2->isNodeFree(root2) && !obj1->isFree())
00369 {
00370 OBB obb1, obb2;
00371 convertBV(root1->bv, Transform3f(), obb1);
00372 convertBV(root2_bv, tf2, obb2);
00373
00374 if(obb1.overlap(obb2))
00375 {
00376 Box* box = new Box();
00377 Transform3f box_tf;
00378 constructBox(root2_bv, tf2, *box, box_tf);
00379
00380 box->cost_density = root2->getOccupancy();
00381 box->threshold_occupied = tree2->getOccupancyThres();
00382
00383 CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf);
00384 return callback(obj1, &obj2, cdata);
00385 }
00386 else return false;
00387 }
00388 else return false;
00389 }
00390
00391 OBB obb1, obb2;
00392 convertBV(root1->bv, Transform3f(), obb1);
00393 convertBV(root2_bv, tf2, obb2);
00394
00395 if(tree2->isNodeFree(root2) || !obb1.overlap(obb2)) return false;
00396
00397 if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size())))
00398 {
00399 if(collisionRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback))
00400 return true;
00401 if(collisionRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback))
00402 return true;
00403 }
00404 else
00405 {
00406 for(unsigned int i = 0; i < 8; ++i)
00407 {
00408 if(root2->childExists(i))
00409 {
00410 const OcTree::OcTreeNode* child = root2->getChild(i);
00411 AABB child_bv;
00412 computeChildBV(root2_bv, i, child_bv);
00413
00414 if(collisionRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback))
00415 return true;
00416 }
00417 }
00418 }
00419
00420 return false;
00421 }
00422
00423 bool collisionRecurse_(DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, CollisionCallBack callback)
00424 {
00425 DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id;
00426 if(root1->isLeaf() && !root2->hasChildren())
00427 {
00428 CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data);
00429 if(!tree2->isNodeFree(root2))
00430 {
00431 const AABB& root_bv_t = translate(root2_bv, tf2);
00432 if(root1->bv.overlap(root_bv_t))
00433 {
00434 Box* box = new Box();
00435 Transform3f box_tf;
00436 constructBox(root2_bv, tf2, *box, box_tf);
00437
00438 box->cost_density = root2->getOccupancy();
00439 box->threshold_occupied = tree2->getOccupancyThres();
00440
00441 CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf);
00442 return callback(obj1, &obj2, cdata);
00443 }
00444 else return false;
00445 }
00446 else return false;
00447 }
00448
00449 const AABB& root_bv_t = translate(root2_bv, tf2);
00450 if(tree2->isNodeFree(root2) || !root1->bv.overlap(root_bv_t)) return false;
00451
00452 if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size())))
00453 {
00454 if(collisionRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback))
00455 return true;
00456 if(collisionRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback))
00457 return true;
00458 }
00459 else
00460 {
00461 for(unsigned int i = 0; i < 8; ++i)
00462 {
00463 if(root2->childExists(i))
00464 {
00465 const OcTree::OcTreeNode* child = root2->getChild(i);
00466 AABB child_bv;
00467 computeChildBV(root2_bv, i, child_bv);
00468
00469 if(collisionRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback))
00470 return true;
00471 }
00472 }
00473 }
00474
00475 return false;
00476 }
00477
00478
00479
00480 bool DynamicAABBTreeCollisionManager_Array::collisionRecurse(DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) const
00481 {
00482 if(tf2.getQuatRotation().isIdentity())
00483 return collisionRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback);
00484 else
00485 return collisionRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2, cdata, callback);
00486 }
00487
00488
00489 bool distanceRecurse_(DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist)
00490 {
00491 DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id;
00492 if(root1->isLeaf() && !root2->hasChildren())
00493 {
00494 if(tree2->isNodeOccupied(root2))
00495 {
00496 Box* box = new Box();
00497 Transform3f box_tf;
00498 constructBox(root2_bv, tf2, *box, box_tf);
00499 CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf);
00500 return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist);
00501 }
00502 else return false;
00503 }
00504
00505 if(!tree2->isNodeOccupied(root2)) return false;
00506
00507 if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size())))
00508 {
00509 AABB aabb2;
00510 convertBV(root2_bv, tf2, aabb2);
00511
00512 FCL_REAL d1 = aabb2.distance((nodes1 + root1->children[0])->bv);
00513 FCL_REAL d2 = aabb2.distance((nodes1 + root1->children[1])->bv);
00514
00515 if(d2 < d1)
00516 {
00517 if(d2 < min_dist)
00518 {
00519 if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00520 return true;
00521 }
00522
00523 if(d1 < min_dist)
00524 {
00525 if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00526 return true;
00527 }
00528 }
00529 else
00530 {
00531 if(d1 < min_dist)
00532 {
00533 if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00534 return true;
00535 }
00536
00537 if(d2 < min_dist)
00538 {
00539 if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00540 return true;
00541 }
00542 }
00543 }
00544 else
00545 {
00546 for(unsigned int i = 0; i < 8; ++i)
00547 {
00548 if(root2->childExists(i))
00549 {
00550 const OcTree::OcTreeNode* child = root2->getChild(i);
00551 AABB child_bv;
00552 computeChildBV(root2_bv, i, child_bv);
00553
00554 AABB aabb2;
00555 convertBV(child_bv, tf2, aabb2);
00556 FCL_REAL d = root1->bv.distance(aabb2);
00557
00558 if(d < min_dist)
00559 {
00560 if(distanceRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback, min_dist))
00561 return true;
00562 }
00563 }
00564 }
00565 }
00566
00567 return false;
00568 }
00569
00570
00571 bool distanceRecurse_(DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist)
00572 {
00573 DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id;
00574 if(root1->isLeaf() && !root2->hasChildren())
00575 {
00576 if(tree2->isNodeOccupied(root2))
00577 {
00578 Box* box = new Box();
00579 Transform3f box_tf;
00580 constructBox(root2_bv, tf2, *box, box_tf);
00581 CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf);
00582 return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist);
00583 }
00584 else return false;
00585 }
00586
00587 if(!tree2->isNodeOccupied(root2)) return false;
00588
00589 if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size())))
00590 {
00591 const AABB& aabb2 = translate(root2_bv, tf2);
00592
00593 FCL_REAL d1 = aabb2.distance((nodes1 + root1->children[0])->bv);
00594 FCL_REAL d2 = aabb2.distance((nodes1 + root1->children[1])->bv);
00595
00596 if(d2 < d1)
00597 {
00598 if(d2 < min_dist)
00599 {
00600 if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00601 return true;
00602 }
00603
00604 if(d1 < min_dist)
00605 {
00606 if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00607 return true;
00608 }
00609 }
00610 else
00611 {
00612 if(d1 < min_dist)
00613 {
00614 if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00615 return true;
00616 }
00617
00618 if(d2 < min_dist)
00619 {
00620 if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist))
00621 return true;
00622 }
00623 }
00624 }
00625 else
00626 {
00627 for(unsigned int i = 0; i < 8; ++i)
00628 {
00629 if(root2->childExists(i))
00630 {
00631 const OcTree::OcTreeNode* child = root2->getChild(i);
00632 AABB child_bv;
00633 computeChildBV(root2_bv, i, child_bv);
00634
00635 const AABB& aabb2 = translate(child_bv, tf2);
00636 FCL_REAL d = root1->bv.distance(aabb2);
00637
00638 if(d < min_dist)
00639 {
00640 if(distanceRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback, min_dist))
00641 return true;
00642 }
00643 }
00644 }
00645 }
00646
00647 return false;
00648 }
00649
00650 bool DynamicAABBTreeCollisionManager_Array::distanceRecurse(DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const
00651 {
00652 if(tf2.getQuatRotation().isIdentity())
00653 return distanceRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback, min_dist);
00654 else
00655 return distanceRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2, cdata, callback, min_dist);
00656 }
00657
00658
00659 }