From 44e916dd2dcc09ebb6ccdbbf3671e383963eac84 Mon Sep 17 00:00:00 2001 From: jpan <jpan@253336fb-580f-4252-a368-f3cef5a2a82b> Date: Mon, 2 Jul 2012 22:59:52 +0000 Subject: [PATCH] fix more bugs. the new dynamicAABBTree broadphase works quite well in both distance and collision. besides the old self-collision, collision with an object, distance to an object interface, added self-distance, collision with a set of objects, distance to a set of objects. This simplifies the function in collision_detection_fcl and also makes some optimization possible. git-svn-id: https://kforge.ros.org/fcl/fcl_ros@114 253336fb-580f-4252-a368-f3cef5a2a82b --- trunk/fcl/include/fcl/broad_phase_collision.h | 284 ++---------- trunk/fcl/include/fcl/hierarchy_tree.h | 83 ++-- trunk/fcl/src/broad_phase_collision.cpp | 432 ++++++++++++++++-- 3 files changed, 474 insertions(+), 325 deletions(-) diff --git a/trunk/fcl/include/fcl/broad_phase_collision.h b/trunk/fcl/include/fcl/broad_phase_collision.h index 4228b5bc..44954b3f 100644 --- a/trunk/fcl/include/fcl/broad_phase_collision.h +++ b/trunk/fcl/include/fcl/broad_phase_collision.h @@ -71,6 +71,11 @@ typedef bool (*DistanceCallBack)(CollisionObject* o1, CollisionObject* o2, void* class BroadPhaseCollisionManager { public: + BroadPhaseCollisionManager() + { + enable_tested_set_ = false; + } + virtual ~BroadPhaseCollisionManager() {} /** \brief add objects to the manager */ @@ -121,6 +126,12 @@ public: /** \brief the number of objects managed by the manager */ virtual size_t size() const = 0; + +protected: + mutable std::set<std::pair<CollisionObject*, CollisionObject*> > tested_set; + mutable std::set<CollisionObject*> tested_set2; + mutable bool enable_tested_set_; + }; @@ -305,7 +316,7 @@ protected: // all objects in the scene - std::list<CollisionObject*> objs; + std::list<CollisionObject*> objs; // objects in the scene limit (given by scene_min and scene_max) are in the spatial hash table HashTable* hash_table; @@ -635,7 +646,6 @@ public: elist[0] = NULL; elist[1] = NULL; elist[2] = NULL; - enable_tested_set = true; } ~SaPCollisionManager() @@ -830,8 +840,7 @@ protected: bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const; -public: - bool enable_tested_set; + bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; }; @@ -1017,17 +1026,6 @@ protected: char minmax; }; - /** \brief Functor for sorting end points */ - struct SortByValue - { - bool operator()(const EndPoint& a, const EndPoint& b) const - { - if(a.value < b.value) - return true; - return false; - } - }; - /** \brief Extention interval tree's interval to SAP interval, adding more information */ struct SAPInterval : public SimpleInterval { @@ -1057,7 +1055,6 @@ protected: /** \brief tag for whether the interval tree is maintained suitably */ bool setup_; - }; @@ -1076,57 +1073,26 @@ public: max_tree_nonbalanced_level = 4; tree_incremental_balance_pass = 10; tree_topdown_balance_threshold = 128; + setup_ = false; } + + /** \brief add objects to the manager */ + void registerObjects(const std::vector<CollisionObject*>& other_objs); /** \brief add one object to the manager */ - void registerObject(CollisionObject* obj) - { - DynamicAABBNode* node = dtree.insert(obj->getAABB(), obj); - table[obj] = node; - } + void registerObject(CollisionObject* obj); /** \brief remove one object from the manager */ - void unregisterObject(CollisionObject* obj) - { - DynamicAABBNode* node = table[obj]; - table.erase(obj); - dtree.remove(node); - } + void unregisterObject(CollisionObject* obj); /** \brief initialize the manager, related with the specific type of manager */ - void setup() - { - size_t height = dtree.getMaxHeight(dtree.getRoot()); - size_t num = dtree.size(); - if(height - std::log((BVH_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level) - dtree.balanceIncremental(10); - else - dtree.balanceTopdown(tree_topdown_balance_threshold); - } + void setup(); /** \brief update the condition of manager */ - void update() - { - for(DynamicAABBTable::const_iterator it = table.begin(); it != table.end(); ++it) - { - CollisionObject* obj = it->first; - DynamicAABBNode* node = it->second; - if(!node->bv.equal(obj->getAABB())) - dtree.update(node, obj->getAABB()); - } - } + void update(); /** \brief update a specific object */ - void update(CollisionObject* obj) - { - DynamicAABBTable::const_iterator it = table.find(obj); - if(it != table.end()) - { - DynamicAABBNode* node = it->second; - if(!node->bv.equal(obj->getAABB())) - dtree.update(node, obj->getAABB()); - } - } + void update(CollisionObject* obj); /** \brief clear the manager */ void clear() @@ -1200,211 +1166,19 @@ private: HierarchyTree<AABB> dtree; boost::unordered_map<CollisionObject*, DynamicAABBNode*> table; - bool collisionRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, CollisionCallBack callback) const - { - if(root1->isLeaf() && root2->isLeaf()) - { - if(!root1->bv.overlap(root2->bv)) return false; - return callback(static_cast<CollisionObject*>(root1->data), static_cast<CollisionObject*>(root2->data), cdata); - } - - if(!root1->bv.overlap(root2->bv)) return false; - - if(root2->isLeaf() || (!root1->isLeaf() && (root1->bv.size() > root2->bv.size()))) - { - if(collisionRecurse(root1->childs[0], root2, cdata, callback)) - return true; - if(collisionRecurse(root1->childs[1], root2, cdata, callback)) - return true; - } - else - { - if(collisionRecurse(root1, root2->childs[0], cdata, callback)) - return true; - if(collisionRecurse(root1, root2->childs[1], cdata, callback)) - return true; - } - return false; - } - - bool collisionRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, CollisionCallBack callback) const - { - if(root->isLeaf()) - { - if(!root->bv.overlap(query->getAABB())) return false; - return callback(static_cast<CollisionObject*>(root->data), query, cdata); - } - - if(!root->bv.overlap(query->getAABB())) return false; - - int select_res = select(query->getAABB(), *(root->childs[0]), *(root->childs[1])); - - if(collisionRecurse(root->childs[select_res], query, cdata, callback)) - return true; - - if(collisionRecurse(root->childs[1-select_res], query, cdata, callback)) - return true; - - return false; - } - - bool selfCollisionRecurse(DynamicAABBNode* root, void* cdata, CollisionCallBack callback) const - { - if(root->isLeaf()) return false; - - if(selfCollisionRecurse(root->childs[0], cdata, callback)) - return true; - - if(selfCollisionRecurse(root->childs[1], cdata, callback)) - return true; - - if(collisionRecurse(root->childs[0], root->childs[1], cdata, callback)) - return true; - - return false; - } - - bool distanceRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const - { - if(root1->isLeaf() && root2->isLeaf()) - { - CollisionObject* root1_obj = static_cast<CollisionObject*>(root1->data); - CollisionObject* root2_obj = static_cast<CollisionObject*>(root2->data); - return callback(root1_obj, root2_obj, cdata, min_dist); - } - - if(root2->isLeaf() || (!root1->isLeaf() && (root1->bv.size() > root2->bv.size()))) - { - BVH_REAL d1 = root2->bv.distance(root1->childs[0]->bv); - BVH_REAL d2 = root2->bv.distance(root1->childs[1]->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse(root1->childs[1], root2, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse(root1->childs[0], root2, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse(root1->childs[0], root2, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse(root1->childs[1], root2, cdata, callback, min_dist)) - return true; - } - } - } - else - { - BVH_REAL d1 = root1->bv.distance(root2->childs[0]->bv); - BVH_REAL d2 = root1->bv.distance(root2->childs[1]->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse(root1, root2->childs[1], cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse(root1, root2->childs[0], cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse(root1, root2->childs[0], cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse(root1, root2->childs[1], cdata, callback, min_dist)) - return true; - } - } - } - - return false; - } - - bool distanceRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const - { - if(root->isLeaf()) - { - CollisionObject* root_obj = static_cast<CollisionObject*>(root->data); - return callback(root_obj, query, cdata, min_dist); - } - - BVH_REAL d1 = query->getAABB().distance(root->childs[0]->bv); - BVH_REAL d2 = query->getAABB().distance(root->childs[1]->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse(root->childs[1], query, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse(root->childs[0], query, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse(root->childs[0], query, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse(root->childs[1], query, cdata, callback, min_dist)) - return true; - } - } - - return false; - } + bool setup_; - bool selfDistanceRecurse(DynamicAABBNode* root, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const - { - if(root->isLeaf()) return false; + bool collisionRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, CollisionCallBack callback) const; - if(selfDistanceRecurse(root->childs[0], cdata, callback, min_dist)) - return true; + bool collisionRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, CollisionCallBack callback) const; - if(selfDistanceRecurse(root->childs[1], cdata, callback, min_dist)) - return true; + bool selfCollisionRecurse(DynamicAABBNode* root, void* cdata, CollisionCallBack callback) const; - if(distanceRecurse(root->childs[0], root->childs[1], cdata, callback, min_dist)) - return true; + bool distanceRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const; - return false; - } + bool distanceRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const; - + bool selfDistanceRecurse(DynamicAABBNode* root, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const; }; diff --git a/trunk/fcl/include/fcl/hierarchy_tree.h b/trunk/fcl/include/fcl/hierarchy_tree.h index 026a5ba8..084d4f32 100644 --- a/trunk/fcl/include/fcl/hierarchy_tree.h +++ b/trunk/fcl/include/fcl/hierarchy_tree.h @@ -189,7 +189,8 @@ public: { if(root_node) { - std::vector<NodeType*> leaves(n_leaves); + std::vector<NodeType*> leaves; + leaves.reserve(n_leaves); fetchLeaves(root_node, leaves); bottomup(leaves); root_node = leaves[0]; @@ -201,10 +202,10 @@ public: { if(root_node) { - std::vector<NodeType*> leaves(n_leaves); + std::vector<NodeType*> leaves; + leaves.reserve(n_leaves); fetchLeaves(root_node, leaves); - topdown(leaves, bu_threshold); - root_node = leaves[0]; + root_node = topdown(leaves, bu_threshold); } } @@ -274,35 +275,28 @@ public: return root_node; } -private: + NodeType*& getRoot() + { + return root_node; + } - /** \brief sort node n and its parent according to their memory position */ - NodeType* sort(NodeType* n, NodeType*& r) + void print(NodeType* root, int depth) { - NodeType* p = n->parent; - if(p > n) + if(root->isLeaf()) { - int i = indexOf(n); - int j = 1 - i; - NodeType* s = p->childs[j]; - NodeType* q = p->parent; - if(q) q->childs[indexOf(p)] = n; else r = n; - s->parent = n; - p->parent = n; - n->parent = q; - p->childs[0] = n->childs[0]; - p->childs[1] = n->childs[1]; - n->childs[0]->parent = p; - n->childs[1]->parent = p; - n->childs[i] = p; - n->childs[j] = s; - std::swap(p->bv, n->bv); - return p; + for(int i = 0; i < depth; ++i) + std::cout << " "; + std::cout << " (" << root->bv.min_[0] << ", " << root->bv.min_[1] << ", " << root->bv.min_[2] << "; " << root->bv.max_[0] << ", " << root->bv.max_[1] << ", " << root->bv.max_[2] << ")" << std::endl; + } + else + { + for(int i = 0; i < depth; ++i) + std::cout << " "; + std::cout << " (" << root->bv.min_[0] << ", " << root->bv.min_[1] << ", " << root->bv.min_[2] << "; " << root->bv.max_[0] << ", " << root->bv.max_[1] << ", " << root->bv.max_[2] << ")" << std::endl; + print(root->childs[0], depth+1); + print(root->childs[1], depth+1); } - return n; } - - /** \brief construct a tree for a set of leaves from top */ NodeType* topdown(std::vector<NodeType*>& leaves, int bu_threshold) @@ -326,7 +320,6 @@ private: ++splitcount[j][x.dot(axis[j]) > 0 ? 1 : 0]; } } - for(size_t i = 0; i < 3; ++i) { @@ -373,6 +366,34 @@ private: return leaves[0]; } +private: + + /** \brief sort node n and its parent according to their memory position */ + NodeType* sort(NodeType* n, NodeType*& r) + { + NodeType* p = n->parent; + if(p > n) + { + int i = indexOf(n); + int j = 1 - i; + NodeType* s = p->childs[j]; + NodeType* q = p->parent; + if(q) q->childs[indexOf(p)] = n; else r = n; + s->parent = n; + p->parent = n; + n->parent = q; + p->childs[0] = n->childs[0]; + p->childs[1] = n->childs[1]; + n->childs[0]->parent = p; + n->childs[1]->parent = p; + n->childs[i] = p; + n->childs[j] = s; + std::swap(p->bv, n->bv); + return p; + } + return n; + } + /** \brief construct a tree for a set of leaves from bottom */ void bottomup(std::vector<NodeType*>& leaves) @@ -499,14 +520,16 @@ private: /** \brief Delete all internal nodes and return all leaves nodes with given depth from root */ void fetchLeaves(NodeType* root, std::vector<NodeType*>& leaves, int depth = -1) { - if(!root->isLeaf() && depth) + if((!root->isLeaf()) && depth) { fetchLeaves(root->childs[0], leaves, depth-1); fetchLeaves(root->childs[1], leaves, depth-1); deleteNode(root); } else + { leaves.push_back(root); + } } static size_t indexOf(NodeType* node) diff --git a/trunk/fcl/src/broad_phase_collision.cpp b/trunk/fcl/src/broad_phase_collision.cpp index b72cb8e9..efde3b8c 100644 --- a/trunk/fcl/src/broad_phase_collision.cpp +++ b/trunk/fcl/src/broad_phase_collision.cpp @@ -560,9 +560,11 @@ bool SSaPCollisionManager::distance_(CollisionObject* obj, void* cdata, Distance dummy_vector = dummy_vector * 2 - obj->getAABB().max_; } } - if(pos_end1 != objs_x.end()) pos_start1 = pos_end1; - if(pos_end2 != objs_y.end()) pos_start2 = pos_end2; - if(pos_end3 != objs_z.end()) pos_start3 = pos_end3; + + // yes, following is wrong, will result in too large distance. + // if(pos_end1 != objs_x.end()) pos_start1 = pos_end1; + // if(pos_end2 != objs_y.end()) pos_start2 = pos_end2; + // if(pos_end3 != objs_z.end()) pos_start3 = pos_end3; } else if(status == 0) break; @@ -1122,34 +1124,51 @@ void SaPCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const } } -void SaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +bool SaPCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const { - if(size() == 0) return; - size_t axis = optimal_axis; const AABB& obj_aabb = obj->getAABB(); BVH_REAL min_val = obj_aabb.min_[axis]; BVH_REAL max_val = obj_aabb.max_[axis]; + + EndPoint dummy; + SaPAABB dummy_aabb; + dummy_aabb.cached = obj_aabb; + dummy.minmax = 1; + dummy.aabb = &dummy_aabb; - std::vector<EndPoint*>::const_iterator res_it = std::lower_bound(velist[axis].begin(), velist[axis].end(), min_val, + // compute stop_pos by binary search, this is cheaper than check it in while iteration linearly + std::vector<EndPoint*>::const_iterator res_it = std::upper_bound(velist[axis].begin(), velist[axis].end(), &dummy, boost::bind(std::less<BVH_REAL>(), boost::bind(static_cast<BVH_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _1, axis), - min_val)); - - if(res_it == velist[axis].end()) return; + boost::bind(static_cast<BVH_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _2, axis))); - EndPoint* pos = *res_it; + EndPoint* end_pos = NULL; + if(res_it != velist[axis].end()) + end_pos = *res_it; - while((pos != NULL) && (pos->getVal(axis) <= max_val)) + EndPoint* pos = elist[axis]; + + while(pos != end_pos) { - if(pos->aabb->cached.overlap(obj->getAABB())) + if((pos->minmax == 0) && (pos->aabb->hi->getVal(axis) >= min_val)) { - if(callback(obj, pos->aabb->obj, cdata)) - return; + if(pos->aabb->cached.overlap(obj->getAABB())) + if(callback(obj, pos->aabb->obj, cdata)) + return true; } pos = pos->next[axis]; } + + return false; +} + +void SaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + collide_(obj, cdata, callback); } bool SaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const @@ -1170,8 +1189,6 @@ bool SaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceC EndPoint* start_pos = elist[axis]; - std::set<CollisionObject*> tested; - while(1) { old_min_distance = min_dist; @@ -1203,14 +1220,27 @@ bool SaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceC if((pos->minmax == 0) && (pos->aabb->hi->getVal(axis) >= min_val)) { CollisionObject* curr_obj = pos->aabb->obj; - if(!enable_tested_set || (tested.find(curr_obj) == tested.end())) + if(!enable_tested_set_) { if(pos->aabb->cached.distance(obj->getAABB()) < min_dist) { if(callback(curr_obj, obj, cdata, min_dist)) return true; } - if(enable_tested_set) tested.insert(curr_obj); + } + else + { + bool not_find = (tested_set2.find(curr_obj) == tested_set2.end()); + if(not_find) + { + if(pos->aabb->cached.distance(obj->getAABB()) < min_dist) + { + if(callback(curr_obj, obj, cdata, min_dist)) + return true; + } + + tested_set2.insert(curr_obj); + } } } @@ -1294,11 +1324,20 @@ void SaPCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, vo return; } - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it) + if(this->size() < other_manager->size()) { - for(std::list<SaPAABB*>::const_iterator it2 = other_manager->AABB_arr.begin(); it2 != other_manager->AABB_arr.end(); ++it2) + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it) { - if(callback((*it)->obj, (*it2)->obj, cdata)) return; + if(other_manager->collide_((*it)->obj, cdata, callback)) + return; + } + } + else + { + for(std::list<SaPAABB*>::const_iterator it = other_manager->AABB_arr.begin(); it != other_manager->AABB_arr.end(); ++it) + { + if(collide_((*it)->obj, cdata, callback)) + return; } } } @@ -1313,14 +1352,21 @@ void SaPCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, v } BVH_REAL min_dist = std::numeric_limits<BVH_REAL>::max(); - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it) + + if(this->size() < other_manager->size()) { - for(std::list<SaPAABB*>::const_iterator it2 = other_manager->AABB_arr.begin(); it2 != other_manager->AABB_arr.end(); ++it2) + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it) { - if((*it)->obj->getAABB().distance((*it2)->obj->getAABB()) < min_dist) - { - if(callback((*it)->obj, (*it2)->obj, cdata, min_dist)) return; - } + if(other_manager->distance_((*it)->obj, cdata, callback, min_dist)) + return; + } + } + else + { + for(std::list<SaPAABB*>::const_iterator it = other_manager->AABB_arr.begin(); it != other_manager->AABB_arr.end(); ++it) + { + if(distance_((*it)->obj, cdata, callback, min_dist)) + return; } } } @@ -1339,9 +1385,9 @@ void IntervalTreeCollisionManager::unregisterObject(CollisionObject* obj) EndPoint p; p.value = obj->getAABB().min_[0]; - std::vector<EndPoint>::iterator start1 = std::lower_bound(endpoints[0].begin(), endpoints[0].end(), p, SortByValue()); + std::vector<EndPoint>::iterator start1 = std::lower_bound(endpoints[0].begin(), endpoints[0].end(), p, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); p.value = obj->getAABB().max_[0]; - std::vector<EndPoint>::iterator end1 = std::upper_bound(start1, endpoints[0].end(), p, SortByValue()); + std::vector<EndPoint>::iterator end1 = std::upper_bound(start1, endpoints[0].end(), p, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); if(start1 < end1) { @@ -1365,9 +1411,9 @@ void IntervalTreeCollisionManager::unregisterObject(CollisionObject* obj) } p.value = obj->getAABB().min_[1]; - std::vector<EndPoint>::iterator start2 = std::lower_bound(endpoints[1].begin(), endpoints[1].end(), p, SortByValue()); + std::vector<EndPoint>::iterator start2 = std::lower_bound(endpoints[1].begin(), endpoints[1].end(), p, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); p.value = obj->getAABB().max_[1]; - std::vector<EndPoint>::iterator end2 = std::upper_bound(start2, endpoints[1].end(), p, SortByValue()); + std::vector<EndPoint>::iterator end2 = std::upper_bound(start2, endpoints[1].end(), p, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); if(start2 < end2) { @@ -1392,9 +1438,9 @@ void IntervalTreeCollisionManager::unregisterObject(CollisionObject* obj) p.value = obj->getAABB().min_[2]; - std::vector<EndPoint>::iterator start3 = std::lower_bound(endpoints[2].begin(), endpoints[2].end(), p, SortByValue()); + std::vector<EndPoint>::iterator start3 = std::lower_bound(endpoints[2].begin(), endpoints[2].end(), p, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); p.value = obj->getAABB().max_[2]; - std::vector<EndPoint>::iterator end3 = std::upper_bound(start3, endpoints[2].end(), p, SortByValue()); + std::vector<EndPoint>::iterator end3 = std::upper_bound(start3, endpoints[2].end(), p, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); if(start3 < end3) { @@ -1447,9 +1493,9 @@ void IntervalTreeCollisionManager::setup() { if(!setup_) { - std::sort(endpoints[0].begin(), endpoints[0].end(), SortByValue()); - std::sort(endpoints[1].begin(), endpoints[1].end(), SortByValue()); - std::sort(endpoints[2].begin(), endpoints[2].end(), SortByValue()); + std::sort(endpoints[0].begin(), endpoints[0].end(), boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + std::sort(endpoints[1].begin(), endpoints[1].end(), boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + std::sort(endpoints[2].begin(), endpoints[2].end(), boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); for(int i = 0; i < 3; ++i) delete interval_trees[i]; @@ -1729,10 +1775,15 @@ void IntervalTreeCollisionManager::collide(void* cdata, CollisionCallBack callba void IntervalTreeCollisionManager::distance(void* cdata, DistanceCallBack callback) const { + enable_tested_set_ = true; + tested_set.clear(); BVH_REAL min_dist = std::numeric_limits<BVH_REAL>::max(); for(size_t i = 0; i < endpoints[0].size(); ++i) if(distance_(endpoints[0][i].obj, cdata, callback, min_dist)) return; + + enable_tested_set_ = false; + tested_set.clear(); } void IntervalTreeCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const @@ -1811,10 +1862,31 @@ bool IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_ SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start); if(ivl->obj != obj) { - if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) + if(!enable_tested_set_) { - if(callback(ivl->obj, obj, cdata, min_dist)) - return true; + if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) + { + if(callback(ivl->obj, obj, cdata, min_dist)) + return true; + } + } + else + { + bool not_find; + if(ivl->obj < obj) not_find = (tested_set.find(std::make_pair(ivl->obj, obj)) == tested_set.end()); + else not_find = (tested_set.find(std::make_pair(obj, ivl->obj)) == tested_set.end()); + + if(not_find) + { + if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) + { + if(callback(ivl->obj, obj, cdata, min_dist)) + return true; + } + + if(ivl->obj < obj) tested_set.insert(std::make_pair(ivl->obj, obj)); + else tested_set.insert(std::make_pair(obj, ivl->obj)); + } } } @@ -1826,5 +1898,285 @@ bool IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_ +void DynamicAABBTreeCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) +{ + if(size() > 0) + { + BroadPhaseCollisionManager::registerObjects(other_objs); + } + else + { + std::vector<DynamicAABBNode*> leaves(other_objs.size()); + for(size_t i = 0; i < other_objs.size(); ++i) + { + DynamicAABBNode* node = new DynamicAABBNode; + node->bv = other_objs[i]->getAABB(); + node->parent = NULL; + node->childs[1] = NULL; + node->data = other_objs[i]; + table[other_objs[i]] = node; + leaves[i] = node; + } + + dtree.getRoot() = dtree.topdown(leaves, tree_topdown_balance_threshold); + setup_ = true; + } +} + +void DynamicAABBTreeCollisionManager::registerObject(CollisionObject* obj) +{ + DynamicAABBNode* node = dtree.insert(obj->getAABB(), obj); + table[obj] = node; +} + +void DynamicAABBTreeCollisionManager::unregisterObject(CollisionObject* obj) +{ + DynamicAABBNode* node = table[obj]; + table.erase(obj); + dtree.remove(node); +} + +void DynamicAABBTreeCollisionManager::setup() +{ + if(!setup_) + { + size_t height = dtree.getMaxHeight(dtree.getRoot()); + size_t num = dtree.size(); + if(height - std::log((BVH_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level) + dtree.balanceIncremental(10); + else + dtree.balanceTopdown(tree_topdown_balance_threshold); + setup_ = true; + } +} + + +void DynamicAABBTreeCollisionManager::update() +{ + for(DynamicAABBTable::const_iterator it = table.begin(); it != table.end(); ++it) + { + CollisionObject* obj = it->first; + DynamicAABBNode* node = it->second; + if(!node->bv.equal(obj->getAABB())) + dtree.update(node, obj->getAABB()); + } + setup_ = false; +} + +void DynamicAABBTreeCollisionManager::update(CollisionObject* obj) +{ + DynamicAABBTable::const_iterator it = table.find(obj); + if(it != table.end()) + { + DynamicAABBNode* node = it->second; + if(!node->bv.equal(obj->getAABB())) + dtree.update(node, obj->getAABB()); + } + setup_ = false; +} + +bool DynamicAABBTreeCollisionManager::collisionRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, CollisionCallBack callback) const +{ + if(root1->isLeaf() && root2->isLeaf()) + { + if(!root1->bv.overlap(root2->bv)) return false; + return callback(static_cast<CollisionObject*>(root1->data), static_cast<CollisionObject*>(root2->data), cdata); + } + + if(!root1->bv.overlap(root2->bv)) return false; + + if(root2->isLeaf() || (!root1->isLeaf() && (root1->bv.size() > root2->bv.size()))) + { + if(collisionRecurse(root1->childs[0], root2, cdata, callback)) + return true; + if(collisionRecurse(root1->childs[1], root2, cdata, callback)) + return true; + } + else + { + if(collisionRecurse(root1, root2->childs[0], cdata, callback)) + return true; + if(collisionRecurse(root1, root2->childs[1], cdata, callback)) + return true; + } + return false; +} + +bool DynamicAABBTreeCollisionManager::collisionRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, CollisionCallBack callback) const +{ + if(root->isLeaf()) + { + if(!root->bv.overlap(query->getAABB())) return false; + return callback(static_cast<CollisionObject*>(root->data), query, cdata); + } + + if(!root->bv.overlap(query->getAABB())) return false; + + int select_res = select(query->getAABB(), *(root->childs[0]), *(root->childs[1])); + + if(collisionRecurse(root->childs[select_res], query, cdata, callback)) + return true; + + if(collisionRecurse(root->childs[1-select_res], query, cdata, callback)) + return true; + + return false; +} + +bool DynamicAABBTreeCollisionManager::selfCollisionRecurse(DynamicAABBNode* root, void* cdata, CollisionCallBack callback) const +{ + if(root->isLeaf()) return false; + + if(selfCollisionRecurse(root->childs[0], cdata, callback)) + return true; + + if(selfCollisionRecurse(root->childs[1], cdata, callback)) + return true; + + if(collisionRecurse(root->childs[0], root->childs[1], cdata, callback)) + return true; + + return false; +} + +bool DynamicAABBTreeCollisionManager::distanceRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const +{ + if(root1->isLeaf() && root2->isLeaf()) + { + CollisionObject* root1_obj = static_cast<CollisionObject*>(root1->data); + CollisionObject* root2_obj = static_cast<CollisionObject*>(root2->data); + return callback(root1_obj, root2_obj, cdata, min_dist); + } + + if(root2->isLeaf() || (!root1->isLeaf() && (root1->bv.size() > root2->bv.size()))) + { + BVH_REAL d1 = root2->bv.distance(root1->childs[0]->bv); + BVH_REAL d2 = root2->bv.distance(root1->childs[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(root1->childs[1], root2, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(root1->childs[0], root2, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(root1->childs[0], root2, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(root1->childs[1], root2, cdata, callback, min_dist)) + return true; + } + } + } + else + { + BVH_REAL d1 = root1->bv.distance(root2->childs[0]->bv); + BVH_REAL d2 = root1->bv.distance(root2->childs[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(root1, root2->childs[1], cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(root1, root2->childs[0], cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(root1, root2->childs[0], cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(root1, root2->childs[1], cdata, callback, min_dist)) + return true; + } + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager::distanceRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const +{ + if(root->isLeaf()) + { + CollisionObject* root_obj = static_cast<CollisionObject*>(root->data); + return callback(root_obj, query, cdata, min_dist); + } + + BVH_REAL d1 = query->getAABB().distance(root->childs[0]->bv); + BVH_REAL d2 = query->getAABB().distance(root->childs[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(root->childs[1], query, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(root->childs[0], query, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(root->childs[0], query, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(root->childs[1], query, cdata, callback, min_dist)) + return true; + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager::selfDistanceRecurse(DynamicAABBNode* root, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const +{ + if(root->isLeaf()) return false; + + if(selfDistanceRecurse(root->childs[0], cdata, callback, min_dist)) + return true; + + if(selfDistanceRecurse(root->childs[1], cdata, callback, min_dist)) + return true; + + if(distanceRecurse(root->childs[0], root->childs[1], cdata, callback, min_dist)) + return true; + + return false; +} } -- GitLab