diff --git a/trunk/fcl/include/fcl/BV/AABB.h b/trunk/fcl/include/fcl/BV/AABB.h index 45b78080ccd341937ec8a26b12601dc312ef0929..02066caca5c2ede771894729ac9eff71d67cb15c 100644 --- a/trunk/fcl/include/fcl/BV/AABB.h +++ b/trunk/fcl/include/fcl/BV/AABB.h @@ -69,6 +69,12 @@ public: max_ = max(a, b); } + AABB(const AABB& core, const Vec3f& delta) + { + min_ = core.min_ - delta; + max_ = core.max_ + delta; + } + /** \brief Check whether two AABB are overlap */ inline bool overlap(const AABB& other) const { @@ -186,6 +192,23 @@ public: { return min_.equal(other.min_) && max_.equal(other.max_); } + + inline AABB& expand(const Vec3f& delta) + { + min_ -= delta; + max_ += delta; + return *this; + } + + /**\brief expand the aabb by increase the 'thickness of the plate by a ratio */ + inline AABB& expand(const AABB& core, BVH_REAL ratio) + { + min_ = min_ * ratio - core.min_; + max_ = max_ * ratio - core.max_; + return *this; + } + + }; } diff --git a/trunk/fcl/include/fcl/broad_phase_collision.h b/trunk/fcl/include/fcl/broad_phase_collision.h index cb9f1a30df240f2ffbe92dd9542a5616098d4bf5..4228b5bc9728d64e5ae5981f7b8fa53e22736785 100644 --- a/trunk/fcl/include/fcl/broad_phase_collision.h +++ b/trunk/fcl/include/fcl/broad_phase_collision.h @@ -445,8 +445,7 @@ bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj, if(min_dist < std::numeric_limits<BVH_REAL>::max()) { Vec3f min_dist_delta(min_dist, min_dist, min_dist); - aabb.min_ -= min_dist_delta; - aabb.max_ += min_dist_delta; + aabb.expand(min_dist_delta); } AABB overlap_aabb; @@ -500,22 +499,15 @@ bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj, if(min_dist < old_min_distance) { Vec3f min_dist_delta(min_dist, min_dist, min_dist); - aabb.min_ = obj->getAABB().min_ - min_dist_delta; - aabb.max_ = obj->getAABB().max_ + min_dist_delta; + aabb = AABB(obj->getAABB(), min_dist_delta); status = 0; } else { if(aabb.equal(obj->getAABB())) - { - aabb.min_ -= delta; - aabb.max_ += delta; - } + aabb.expand(delta); else - { - aabb.min_ = aabb.min_ * 2 - obj->getAABB().min_; - aabb.max_ = aabb.max_ * 2 - obj->getAABB().max_; - } + aabb.expand(obj->getAABB(), 2.0); } } } @@ -643,6 +635,7 @@ public: elist[0] = NULL; elist[1] = NULL; elist[2] = NULL; + enable_tested_set = true; } ~SaPCollisionManager() @@ -834,6 +827,11 @@ protected: std::list<SaPPair> overlap_pairs; size_t optimal_axis; + + bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const; + +public: + bool enable_tested_set; }; diff --git a/trunk/fcl/src/broad_phase_collision.cpp b/trunk/fcl/src/broad_phase_collision.cpp index 4878e24345ea86ba182c9a4bfc91e800baf2b817..b72cb8e927b027668964ff78b3dedf51432f1cd3 100644 --- a/trunk/fcl/src/broad_phase_collision.cpp +++ b/trunk/fcl/src/broad_phase_collision.cpp @@ -1141,7 +1141,7 @@ void SaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCa EndPoint* pos = *res_it; - while(pos != NULL & pos->getVal(axis) <= max_val) + while((pos != NULL) && (pos->getVal(axis) <= max_val)) { if(pos->aabb->cached.overlap(obj->getAABB())) { @@ -1152,19 +1152,110 @@ void SaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCa } } -void SaPCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const +bool SaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, BVH_REAL& min_dist) const { - if(size() == 0) return; + Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; + AABB aabb = obj->getAABB(); - 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(min_dist < std::numeric_limits<BVH_REAL>::max()) + { + Vec3f min_dist_delta(min_dist, min_dist, min_dist); + aabb.expand(min_dist_delta); + } + + size_t axis = optimal_axis; + + int status = 1; + BVH_REAL old_min_distance; + + EndPoint* start_pos = elist[axis]; + + std::set<CollisionObject*> tested; + + while(1) { - if((*it)->obj->getAABB().distance(obj->getAABB()) < min_dist) + old_min_distance = min_dist; + BVH_REAL min_val = aabb.min_[axis]; + BVH_REAL max_val = aabb.max_[axis]; + + EndPoint dummy; + SaPAABB dummy_aabb; + dummy_aabb.cached = aabb; + dummy.minmax = 1; + dummy.aabb = &dummy_aabb; + + + 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), + boost::bind(static_cast<BVH_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _2, axis))); + + EndPoint* end_pos = NULL; + if(res_it != velist[axis].end()) + end_pos = *res_it; + + EndPoint* pos = start_pos; + + while(pos != end_pos) { - if(callback(obj, (*it)->obj, cdata, min_dist)) - return; + // can change to pos->aabb->hi->getVal(axis) >= min_val - min_dist, and then update start_pos to end_pos. + // but this seems slower. + 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(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); + } + } + + pos = pos->next[axis]; + } + + if(status == 1) + { + if(old_min_distance < std::numeric_limits<BVH_REAL>::max()) + { + if(min_dist < old_min_distance) break; + else + min_dist = std::numeric_limits<BVH_REAL>::max(); + } + else + { + if(min_dist < old_min_distance) + { + Vec3f min_dist_delta(min_dist, min_dist, min_dist); + aabb = AABB(obj->getAABB(), min_dist_delta); + status = 0; + } + else + { + if(aabb.equal(obj->getAABB())) + aabb.expand(delta); + else + aabb.expand(obj->getAABB(), 2.0); + } + } } + else if(status == 0) + break; } + + return false; +} + +void SaPCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + BVH_REAL min_dist = std::numeric_limits<BVH_REAL>::max(); + + distance_(obj, cdata, callback, min_dist); } void SaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const @@ -1186,16 +1277,11 @@ void SaPCollisionManager::distance(void* cdata, DistanceCallBack callback) const if(size() == 0) return; 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) { - std::list<SaPAABB*>::const_iterator it2 = it; it2++; - for(; it2 != AABB_arr.end(); ++it2) - { - if((*it)->obj->getAABB().distance((*it2)->obj->getAABB()) < min_dist) - { - if(callback((*it)->obj, (*it2)->obj, cdata, min_dist)) return; - } - } + if(distance_((*it)->obj, cdata, callback, min_dist)) + return; } } @@ -1503,8 +1589,7 @@ bool IntervalTreeCollisionManager::distance_(CollisionObject* obj, void* cdata, if(min_dist < std::numeric_limits<BVH_REAL>::max()) { Vec3f min_dist_delta(min_dist, min_dist, min_dist); - aabb.min_ -= min_dist_delta; - aabb.max_ += min_dist_delta; + aabb.expand(min_dist_delta); } int status = 1; @@ -1566,22 +1651,15 @@ bool IntervalTreeCollisionManager::distance_(CollisionObject* obj, void* cdata, if(min_dist < old_min_distance) { Vec3f min_dist_delta(min_dist, min_dist, min_dist); - aabb.min_ = obj->getAABB().min_ - min_dist_delta; - aabb.max_ = obj->getAABB().max_ + min_dist_delta; + aabb = AABB(obj->getAABB(), min_dist_delta); status = 0; } else { if(aabb.equal(obj->getAABB())) - { - aabb.min_ -= delta; - aabb.max_ += delta; - } + aabb.expand(delta); else - { - aabb.min_ = aabb.min_ * 2 - obj->getAABB().min_; - aabb.max_ = aabb.max_ * 2 - obj->getAABB().max_; - } + aabb.expand(obj->getAABB(), 2.0); } } }