diff --git a/trunk/fcl/CMakeLists.txt b/trunk/fcl/CMakeLists.txt index 458bd929138174042f7c731dc280e03b417f970c..79fc8fd57b8325d2f4ded8a30e2455258322d2f8 100644 --- a/trunk/fcl/CMakeLists.txt +++ b/trunk/fcl/CMakeLists.txt @@ -41,7 +41,7 @@ link_directories(${OCTOMAP_LIBRARY_DIRS}) add_definitions(-DUSE_SVMLIGHT=0) -add_library(${PROJECT_NAME} SHARED src/BV/AABB.cpp src/BV/OBB.cpp src/BV/RSS.cpp src/BV/kIOS.cpp src/BV/OBBRSS.cpp src/BV/kDOP.cpp src/traversal_node_base.cpp src/traversal_node_bvhs.cpp src/intersect.cpp src/motion.cpp src/BV_fitter.cpp src/BV_splitter.cpp src/BVH_model.cpp src/BVH_utility.cpp src/transform.cpp src/simple_setup.cpp src/geometric_shapes.cpp src/geometric_shapes_utility.cpp src/collision_node.cpp src/traversal_recurse.cpp src/broad_phase_collision.cpp src/collision.cpp src/collision_func_matrix.cpp src/interval_tree.cpp src/conservative_advancement.cpp src/ccd/interval.cpp src/ccd/interval_vector.cpp src/ccd/interval_matrix.cpp src/ccd/taylor_model.cpp src/ccd/taylor_vector.cpp src/ccd/taylor_matrix.cpp src/distance_func_matrix.cpp src/distance.cpp src/narrowphase/gjk.cpp src/narrowphase/gjk_libccd.cpp src/narrowphase/narrowphase.cpp src/hierarchy_tree.cpp) +add_library(${PROJECT_NAME} SHARED src/BV/AABB.cpp src/BV/OBB.cpp src/BV/RSS.cpp src/BV/kIOS.cpp src/BV/OBBRSS.cpp src/BV/kDOP.cpp src/traversal_node_base.cpp src/traversal_node_bvhs.cpp src/intersect.cpp src/motion.cpp src/BV_fitter.cpp src/BV_splitter.cpp src/BVH_model.cpp src/BVH_utility.cpp src/transform.cpp src/simple_setup.cpp src/geometric_shapes.cpp src/geometric_shapes_utility.cpp src/collision_node.cpp src/traversal_recurse.cpp src/broadphase/broadphase_bruteforce.cpp src/broadphase/broadphase_spatialhash.cpp src/broadphase/broadphase_SaP.cpp src/broadphase/broadphase_SSaP.cpp src/broadphase/broadphase_interval_tree.cpp src/broadphase/broadphase_dynamic_AABB_tree.cpp src/broadphase/broadphase_dynamic_AABB_tree_array.cpp src/collision.cpp src/collision_func_matrix.cpp src/broadphase/interval_tree.cpp src/conservative_advancement.cpp src/ccd/interval.cpp src/ccd/interval_vector.cpp src/ccd/interval_matrix.cpp src/ccd/taylor_model.cpp src/ccd/taylor_vector.cpp src/ccd/taylor_matrix.cpp src/distance_func_matrix.cpp src/distance.cpp src/narrowphase/gjk.cpp src/narrowphase/gjk_libccd.cpp src/narrowphase/narrowphase.cpp src/broadphase/hierarchy_tree.cpp) target_link_libraries(${PROJECT_NAME} ${FLANN_LIBRARIES} ${CCD_LIBRARIES} ${OCTOMAP_LIBRARIES}) diff --git a/trunk/fcl/include/fcl/BV/OBB.h b/trunk/fcl/include/fcl/BV/OBB.h index 2020b760b1258b30785a1216cd438756a0728030..92d0471e3af963eb96a1cf1e090b4eca9deda1ee 100644 --- a/trunk/fcl/include/fcl/BV/OBB.h +++ b/trunk/fcl/include/fcl/BV/OBB.h @@ -125,6 +125,10 @@ public: FCL_REAL distance(const OBB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; }; + +/// @brief Translate the OBB bv +OBB translate(const OBB& bv, const Vec3f& t); + /// @brief Check collision between two obbs, b1 is in configuration (R0, T0) and b2 is in identity. bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBB& b1, const OBB& b2); diff --git a/trunk/fcl/include/fcl/BV/OBBRSS.h b/trunk/fcl/include/fcl/BV/OBBRSS.h index 9bdf0e5273de38ed02ebad2b6f2c9695d96171d2..8925ac7d1657fe05bc194a33ea033daed055c144 100644 --- a/trunk/fcl/include/fcl/BV/OBBRSS.h +++ b/trunk/fcl/include/fcl/BV/OBBRSS.h @@ -143,6 +143,8 @@ public: } }; +/// @brief Translate the OBBRSS bv +OBBRSS translate(const OBBRSS& bv, const Vec3f& t); /// @brief Check collision between two OBBRSS, b1 is in configuration (R0, T0) and b2 is in indentity bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2); diff --git a/trunk/fcl/include/fcl/BV/RSS.h b/trunk/fcl/include/fcl/BV/RSS.h index 4a9b321dd2f05054028a607eccc2a90e2dc8725e..f0293eeb8eebc755dfd83f1d741d6487c7b8c6ec 100644 --- a/trunk/fcl/include/fcl/BV/RSS.h +++ b/trunk/fcl/include/fcl/BV/RSS.h @@ -130,6 +130,10 @@ public: }; + +/// @brief Translate the RSS bv +RSS translate(const RSS& bv, const Vec3f& t); + /// @brief distance between two RSS bounding volumes /// P and Q (optional return values) are the closest points in the rectangles, not the RSS. But the direction P - Q is the correct direction for cloest points /// Notice that P and Q are both in the local frame of the first RSS (not global frame and not even the local frame of object 1) diff --git a/trunk/fcl/include/fcl/BV/kDOP.h b/trunk/fcl/include/fcl/BV/kDOP.h index 7784f7c60ba005b178a2cc7837d5f2e71584663a..660cdfbbfd1ffbc8ca811117ce3982b6999a3ca3 100644 --- a/trunk/fcl/include/fcl/BV/kDOP.h +++ b/trunk/fcl/include/fcl/BV/kDOP.h @@ -128,9 +128,25 @@ private: /// @brief Origin's distances to N KDOP planes FCL_REAL dist_[N]; +public: + inline FCL_REAL dist(std::size_t i) const + { + return dist_[i]; + } + + inline FCL_REAL& dist(std::size_t i) + { + return dist_[i]; + } + }; + +/// @brief translate the KDOP BV +template<size_t N> +KDOP<N> translate(const KDOP<N>& bv, const Vec3f& t); + } #endif diff --git a/trunk/fcl/include/fcl/BV/kIOS.h b/trunk/fcl/include/fcl/BV/kIOS.h index bbab38bbde9c18334fd7c3efc1b420b0fcf916a2..b39dd3c67cd63c7edb43eec0108f1e2e186f8487 100644 --- a/trunk/fcl/include/fcl/BV/kIOS.h +++ b/trunk/fcl/include/fcl/BV/kIOS.h @@ -147,6 +147,10 @@ private: }; + +/// @brief Translate the kIOS BV +kIOS translate(const kIOS& bv, const Vec3f& t); + /// @brief Check collision between two kIOSs, b1 is in configuration (R0, T0) and b2 is in identity. /// @todo Not efficient bool overlap(const Matrix3f& R0, const Vec3f& T0, const kIOS& b1, const kIOS& b2); diff --git a/trunk/fcl/include/fcl/BVH_internal.h b/trunk/fcl/include/fcl/BVH_internal.h index 24f64d4a010263227af16eff1bbeecdb433fe590..2b099750ff82b889e6cb0ddb785583fdde0588de 100644 --- a/trunk/fcl/include/fcl/BVH_internal.h +++ b/trunk/fcl/include/fcl/BVH_internal.h @@ -42,46 +42,41 @@ namespace fcl { -/** \brief States for BVH construction - * empty->begun->processed ->replace_begun->processed -> ...... - * | - * |-> update_begun -> updated -> ..... - * */ - /// @brief States for BVH construction +/// empty->begun->processed ->replace_begun->processed -> ...... +/// | +/// |-> update_begun -> updated -> ..... enum BVHBuildState -{ - BVH_BUILD_STATE_EMPTY, // empty state, immediately after constructor - BVH_BUILD_STATE_BEGUN, // after beginModel(), state for adding geometry primitives - BVH_BUILD_STATE_PROCESSED, // after tree has been build, ready for cd use - BVH_BUILD_STATE_UPDATE_BEGUN, // after beginUpdateModel(), state for updating geometry primitives - BVH_BUILD_STATE_UPDATED, // after tree has been build for updated geometry, ready for ccd use - BVH_BUILD_STATE_REPLACE_BEGUN, // after beginReplaceModel(), state for replacing geometry primitives -}; + { + BVH_BUILD_STATE_EMPTY, /// empty state, immediately after constructor + BVH_BUILD_STATE_BEGUN, /// after beginModel(), state for adding geometry primitives + BVH_BUILD_STATE_PROCESSED, /// after tree has been build, ready for cd use + BVH_BUILD_STATE_UPDATE_BEGUN, /// after beginUpdateModel(), state for updating geometry primitives + BVH_BUILD_STATE_UPDATED, /// after tree has been build for updated geometry, ready for ccd use + BVH_BUILD_STATE_REPLACE_BEGUN, /// after beginReplaceModel(), state for replacing geometry primitives + }; -/** \brief Error code for BVH */ +/// @brief Error code for BVH enum BVHReturnCode -{ - BVH_OK = 0, - BVH_ERR_MODEL_OUT_OF_MEMORY = -1, - BVH_ERR_OUT_OF_MEMORY = -2, - BVH_ERR_UNPROCESSED_MODEL = -3, - BVH_ERR_BUILD_OUT_OF_SEQUENCE = -4, - BVH_ERR_BUILD_EMPTY_MODEL = -5, - BVH_ERR_BUILD_EMPTY_PREVIOUS_FRAME = -6, - BVH_ERR_UNSUPPORTED_FUNCTION = -7, - BVH_ERR_UNUPDATED_MODEL = -8, - BVH_ERR_INCORRECT_DATA = -9, - BVH_ERR_UNKNOWN = -10 -}; + { + BVH_OK = 0, /// BVH is valid + BVH_ERR_MODEL_OUT_OF_MEMORY = -1, /// Cannot allocate memory for vertices and triangles + BVH_ERR_BUILD_OUT_OF_SEQUENCE = -2, /// BVH construction does not follow correct sequence + BVH_ERR_BUILD_EMPTY_MODEL = -3, /// BVH geometry is not prepared + BVH_ERR_BUILD_EMPTY_PREVIOUS_FRAME = -4, /// BVH geometry in previous frame is not prepared + BVH_ERR_UNSUPPORTED_FUNCTION = -5, /// BVH funtion is not supported + BVH_ERR_UNUPDATED_MODEL = -6, /// BVH model update failed + BVH_ERR_INCORRECT_DATA = -7, /// BVH data is not valid + BVH_ERR_UNKNOWN = -8 /// Unknown failure + }; -/** \brief BVH model type */ +/// @brief BVH model type enum BVHModelType -{ - BVH_MODEL_UNKNOWN, - BVH_MODEL_TRIANGLES, - BVH_MODEL_POINTCLOUD -}; + { + BVH_MODEL_UNKNOWN, /// @brief unknown model type + BVH_MODEL_TRIANGLES, /// @brief triangle model + BVH_MODEL_POINTCLOUD /// @brief point cloud model + }; } diff --git a/trunk/fcl/include/fcl/BVH_model.h b/trunk/fcl/include/fcl/BVH_model.h index 67f5f0c6ed433a38faf2ae85f8aa048c1764667f..e46522720457dd17abf3d6eb7bd599e4b30b461c 100644 --- a/trunk/fcl/include/fcl/BVH_model.h +++ b/trunk/fcl/include/fcl/BVH_model.h @@ -47,33 +47,16 @@ #include <vector> #include <boost/shared_ptr.hpp> -/** \brief Main namespace */ namespace fcl { -/** \brief A class describing the bounding hierarchy of a mesh model */ +/// @brief A class describing the bounding hierarchy of a mesh model or a point cloud model (which is viewed as a degraded version of mesh) template<typename BV> class BVHModel : public CollisionGeometry { -private: - int num_tris_allocated; - int num_vertices_allocated; - int num_bvs_allocated; - int num_vertex_updated; // for ccd vertex update - unsigned int* primitive_indices; public: - - /** \brief The state of BVH building process */ - BVHBuildState build_state; - - /** \brief Split rule to split one BV node into two children */ - boost::shared_ptr<BVSplitterBase<BV> > bv_splitter; - - /** \brief Fitting rule to fit a BV node to a set of geometry primitives */ - boost::shared_ptr<BVFitterBase<BV> > bv_fitter; - - /** \brief Model type */ + /// @brief Model type described by the instance BVHModelType getModelType() const { if(num_tris && num_vertices) @@ -84,32 +67,29 @@ public: return BVH_MODEL_UNKNOWN; } - /** \brief Constructing an empty BVH */ - BVHModel() + /// @brief Constructing an empty BVH + BVHModel() : vertices(NULL), + tri_indices(NULL), + prev_vertices(NULL), + num_tris(0), + num_vertices(0), + build_state(BVH_BUILD_STATE_EMPTY), + bv_splitter(new BVSplitter<BV>(SPLIT_METHOD_MEAN)), + bv_fitter(new BVFitter<BV>()), + num_tris_allocated(0), + num_vertices_allocated(0), + num_bvs_allocated(0), + num_vertex_updated(0), + primitive_indices(NULL), + bvs(NULL), + num_bvs(0) { - vertices = NULL; - tri_indices = NULL; - bvs = NULL; - - num_tris = 0; - num_tris_allocated = 0; - num_vertices = 0; - num_vertices_allocated = 0; - num_bvs = 0; - num_bvs_allocated = 0; - - prev_vertices = NULL; - - primitive_indices = NULL; - - build_state = BVH_BUILD_STATE_EMPTY; - - bv_splitter.reset(new BVSplitter<BV>(SPLIT_METHOD_MEAN)); - bv_fitter.reset(new BVFitter<BV>()); } - BVHModel(const BVHModel& other); + /// @brief copy from another BVH + BVHModel(const BVHModel& other); + /// @brief deconstruction, delete mesh data related. ~BVHModel() { delete [] vertices; @@ -117,162 +97,185 @@ public: delete [] bvs; delete [] prev_vertices; - delete [] primitive_indices; } - /** \brief We provide getBV() and getNumBVs() because BVH may be compressed (in future), so - we must provide some flexibility here */ + /// @brief We provide getBV() and getNumBVs() because BVH may be compressed (in future), so we must provide some flexibility here - /** \brief Get the BV of index id */ + /// @brief Access the bv giving the its index const BVNode<BV>& getBV(int id) const { return bvs[id]; } - /** \brief Get the BV of index id */ + /// @brief Access the bv giving the its index BVNode<BV>& getBV(int id) { return bvs[id]; } - /** \brief Get the number of BVs */ + /// @brief Get the number of bv in the BVH int getNumBVs() const { return num_bvs; } - /** \brief Get the object type: it is a BVH */ + /// @brief Get the object type: it is a BVH OBJECT_TYPE getObjectType() const { return OT_BVH; } - /** \brief Get the BV type */ + /// @brief Get the BV type: default is unknown NODE_TYPE getNodeType() const { return BV_UNKNOWN; } - /** \brief Compute the AABB for the BVH, used for broad-phase collision */ + /// @brief Compute the AABB for the BVH, used for broad-phase collision void computeLocalAABB(); - /** \brief Geometry point data */ - Vec3f* vertices; - - /** \brief Geometry triangle index data, will be NULL for point clouds */ - Triangle* tri_indices; - - /** \brief Geometry point data in previous frame */ - Vec3f* prev_vertices; - - /** \brief Number of triangles */ - int num_tris; - - /** \brief Number of points */ - int num_vertices; - - /** \brief Begin a new BVH model */ + /// @brief Begin a new BVH model int beginModel(int num_tris = 0, int num_vertices = 0); - /** \brief Add one point in the new BVH model */ + /// @brief Add one point in the new BVH model int addVertex(const Vec3f& p); - /** \brief Add one triangle in the new BVH model */ + /// @brief Add one triangle in the new BVH model int addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3); - /** \brief Add a set of triangles in the new BVH model */ + /// @brief Add a set of triangles in the new BVH model int addSubModel(const std::vector<Vec3f>& ps, const std::vector<Triangle>& ts); - /** \brief Add a set of points in the new BVH model */ + /// @brief Add a set of points in the new BVH model int addSubModel(const std::vector<Vec3f>& ps); - /** \brief End BVH model construction, will build the bounding volume hierarchy */ + /// @brief End BVH model construction, will build the bounding volume hierarchy int endModel(); - /** \brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame) */ + /// @brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame) int beginReplaceModel(); - /** \brief Replace one point in the old BVH model */ + /// @brief Replace one point in the old BVH model int replaceVertex(const Vec3f& p); - /** \brief Replace one triangle in the old BVH model */ + /// @brief Replace one triangle in the old BVH model int replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3); - /** \brief Replace a set of points in the old BVH model */ + /// @brief Replace a set of points in the old BVH model int replaceSubModel(const std::vector<Vec3f>& ps); - /** \brief End BVH model replacement, will also refit or rebuild the bounding volume hierarchy */ + /// @brief End BVH model replacement, will also refit or rebuild the bounding volume hierarchy int endReplaceModel(bool refit = true, bool bottomup = true); - /** \brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame). - * The current frame will be saved as the previous frame in prev_vertices. - * */ + /// @brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame). + /// The current frame will be saved as the previous frame in prev_vertices. int beginUpdateModel(); - /** \brief Update one point in the old BVH model */ + /// @brief Update one point in the old BVH model int updateVertex(const Vec3f& p); - /** \brief Update one triangle in the old BVH model */ + /// @brief Update one triangle in the old BVH model int updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3); - /** \brief Update a set of points in the old BVH model */ + /// @brief Update a set of points in the old BVH model int updateSubModel(const std::vector<Vec3f>& ps); - /** \brief End BVH model update, will also refit or rebuild the bounding volume hierarchy */ + /// @brief End BVH model update, will also refit or rebuild the bounding volume hierarchy int endUpdateModel(bool refit = true, bool bottomup = true); - /** \brief Check the number of memory used */ + /// @brief Check the number of memory used int memUsage(int msg) const; + /// @brief This is a special acceleration: BVH_model default stores the BV's transform in world coordinate. However, we can also store each BV's transform related to its parent + /// BV node. When traversing the BVH, this can save one matrix transformation. void makeParentRelative() { - makeParentRelativeRecurse(0, Matrix3f::getIdentity(), Vec3f()); + Vec3f I[3] = {Vec3f(1, 0, 0), Vec3f(0, 1, 0), Vec3f(0, 0, 1)}; + makeParentRelativeRecurse(0, I, Vec3f()); } +public: + /// @brief Geometry point data + Vec3f* vertices; + + /// @brief Geometry triangle index data, will be NULL for point clouds + Triangle* tri_indices; + + /// @brief Geometry point data in previous frame + Vec3f* prev_vertices; + + /// @brief Number of triangles + int num_tris; + + /// @brief Number of points + int num_vertices; + + /// @brief The state of BVH building process + BVHBuildState build_state; + + /// @brief Split rule to split one BV node into two children + boost::shared_ptr<BVSplitterBase<BV> > bv_splitter; + + /// @brief Fitting rule to fit a BV node to a set of geometry primitives + boost::shared_ptr<BVFitterBase<BV> > bv_fitter; + private: - /** \brief Bounding volume hierarchy */ + int num_tris_allocated; + int num_vertices_allocated; + int num_bvs_allocated; + int num_vertex_updated; /// for ccd vertex update + unsigned int* primitive_indices; + + + /// @brief Bounding volume hierarchy BVNode<BV>* bvs; - /** \brief Number of BV nodes in bounding volume hierarchy */ + /// @brief Number of BV nodes in bounding volume hierarchy int num_bvs; - /** \brief Build the bounding volume hierarchy */ + /// @brief Build the bounding volume hierarchy int buildTree(); - /** \brief Refit the bounding volume hierarchy */ + /// @brief Refit the bounding volume hierarchy int refitTree(bool bottomup); - /** \brief Refit the bounding volume hierarchy in a top-down way (slow but more compact)*/ + /// @brief Refit the bounding volume hierarchy in a top-down way (slow but more compact) int refitTree_topdown(); - /** \brief Refit the bounding volume hierarchy in a bottom-up way (fast but less compact) */ + /// @brief Refit the bounding volume hierarchy in a bottom-up way (fast but less compact) int refitTree_bottomup(); - /** \brief Recursive kernel for hierarchy construction */ + /// @brief Recursive kernel for hierarchy construction int recursiveBuildTree(int bv_id, int first_primitive, int num_primitives); - /** \brief Recursive kernel for bottomup refitting */ + /// @brief Recursive kernel for bottomup refitting int recursiveRefitTree_bottomup(int bv_id); - void makeParentRelativeRecurse(int bv_id, const Matrix3f& parentR, const Vec3f& parentT) + /// @recursively compute each bv's transform related to its parent. For default BV, only the translation works. + /// For oriented BV (OBB, RSS, OBBRSS), special implementation is provided. + void makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c) { if(!bvs[bv_id].isLeaf()) { - makeParentRelativeRecurse(bvs[bv_id].first_child, bvs[bv_id].getOrientation(), bvs[bv_id].getCenter()); + makeParentRelativeRecurse(bvs[bv_id].first_child, parent_axis, bvs[bv_id].getCenter()); - makeParentRelativeRecurse(bvs[bv_id].first_child + 1, bvs[bv_id].getOrientation(), bvs[bv_id].getCenter()); + makeParentRelativeRecurse(bvs[bv_id].first_child + 1, parent_axis, bvs[bv_id].getCenter()); } - // make self parent relative - Matrix3f Rpc = parentR.transposeTimes(bvs[bv_id].getOrientation()); - bvs[bv_id].setOrientation(Rpc); - - Vec3f Tpc = bvs[bv_id].getCenter() - parentT; - bvs[bv_id].setCenter(parentR.transposeTimes(Tpc)); + bvs[bv_id].bv = translate(bvs[bv_id].bv, -parent_c); } - }; -/** Specialization of getNodeType() for BVHModel with different BV types */ +template<> +void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c); + +template<> +void BVHModel<RSS>::makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c); + +template<> +void BVHModel<OBBRSS>::makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c); + + +/// @brief Specialization of getNodeType() for BVHModel with different BV types template<> NODE_TYPE BVHModel<AABB>::getNodeType() const; diff --git a/trunk/fcl/include/fcl/BVH_utility.h b/trunk/fcl/include/fcl/BVH_utility.h index bbe39353202fdb7bdae14065b40ccf275ddabae8..70b4d976b81a885fbf520382e095020958bc9a88 100644 --- a/trunk/fcl/include/fcl/BVH_utility.h +++ b/trunk/fcl/include/fcl/BVH_utility.h @@ -44,7 +44,7 @@ namespace fcl { -/** \brief Expand the BVH bounding boxes according to uncertainty */ +/// @brief Expand the BVH bounding boxes according to the variance matrix corresponding to the data stored within each BV node template<typename BV> void BVHExpand(BVHModel<BV>& model, const Variance3f* ucs, FCL_REAL r) { @@ -71,33 +71,29 @@ void BVHExpand(BVHModel<BV>& model, const Variance3f* ucs, FCL_REAL r) } } -/** \brief Expand the BVH bounding boxes according to uncertainty, for OBB */ +/// @brief Expand the BVH bounding boxes according to the corresponding variance information, for OBB void BVHExpand(BVHModel<OBB>& model, const Variance3f* ucs, FCL_REAL r); -/** \brief Expand the BVH bounding boxes according to uncertainty, for RSS */ +/// @brief Expand the BVH bounding boxes according to the corresponding variance information, for RSS void BVHExpand(BVHModel<RSS>& model, const Variance3f* ucs, FCL_REAL r); -/** \brief Estimate the uncertainty of point clouds due to sampling procedure */ -void estimateSamplingUncertainty(Vec3f* vertices, int num_vertices, Variance3f* ucs); +/// @brief Estimate the variance of point clouds due to sampling procedure +void estimateSamplingVariance(Vec3f* vertices, int num_vertices, Variance3f* ucs); -/** \brief Compute the covariance matrix for a set or subset of points. if ts = null, then indices refer to points directly; otherwise refer to triangles */ +/// @brief Compute the covariance matrix for a set or subset of points. if ts = null, then indices refer to points directly; otherwise refer to triangles void getCovariance(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Matrix3f& M); -/** \brief Compute the RSS bounding volume parameters: radius, rectangle size and the origin. - * The bounding volume axes are known. - */ +/// @brief Compute the RSS bounding volume parameters: radius, rectangle size and the origin, given the BV axises. void getRadiusAndOriginAndRectangleSize(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Vec3f axis[3], Vec3f& origin, FCL_REAL l[2], FCL_REAL& r); -/** \brief Compute the bounding volume extent and center for a set or subset of points. - * The bounding volume axes are known. - */ +/// @brief Compute the bounding volume extent and center for a set or subset of points, given the BV axises. void getExtentAndCenter(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Vec3f axis[3], Vec3f& center, Vec3f& extent); -/** \brief Compute the center and radius for a triangle's circumcircle */ +/// @brief Compute the center and radius for a triangle's circumcircle void circumCircleComputation(const Vec3f& a, const Vec3f& b, const Vec3f& c, Vec3f& center, FCL_REAL& radius); -/** \brief Compute the maximum distance from a given center point to a point cloud */ +/// @brief Compute the maximum distance from a given center point to a point cloud FCL_REAL maximumDistance(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, const Vec3f& query); diff --git a/trunk/fcl/include/fcl/BV_fitter.h b/trunk/fcl/include/fcl/BV_fitter.h index 024391ca60d7e84d613de8926ba818d62cc31171..d88788ec07070d74f0cd7aa66492496d3de89bd0 100644 --- a/trunk/fcl/include/fcl/BV_fitter.h +++ b/trunk/fcl/include/fcl/BV_fitter.h @@ -47,11 +47,10 @@ #include "fcl/BV/OBBRSS.h" #include <iostream> -/** \brief Main namespace */ namespace fcl { -/** \brief Compute a bounding volume that fits a set of n points. */ +/// @brief Compute a bounding volume that fits a set of n points. template<typename BV> void fit(Vec3f* ps, int n, BV& bv) { @@ -74,28 +73,33 @@ template<> void fit<OBBRSS>(Vec3f* ps, int n, OBBRSS& bv); +/// @brief Interface for fitting a bv given the triangles or points inside it. template<typename BV> class BVFitterBase { public: + /// @brief Set the primitives to be processed by the fitter virtual void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) = 0; + /// @brief Set the primitives to be processed by the fitter, for deformable mesh. virtual void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) = 0; + /// @brief Compute the fitting BV virtual BV fit(unsigned int* primitive_indices, int num_primitives) = 0; + /// @brief clear the temporary data generated. virtual void clear() = 0; }; -/** \brief A class for fitting a bounding volume to a set of points */ +/// @brief The class for the default algorithm fitting a bounding volume to a set of points template<typename BV> class BVFitter : public BVFitterBase<BV> { public: - /** \brief default deconstructor */ + /// @brief default deconstructor virtual ~BVFitter() {} - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -104,7 +108,7 @@ public: type = type_; } - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting, for deformable mesh void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -113,14 +117,13 @@ public: type = type_; } - /** \brief Compute a bounding volume that fits a set of primitives (points or triangles). - * The primitive data was set by set function and primitive_indices is the primitive index relative to the data - */ + /// @brief Compute a bounding volume that fits a set of primitives (points or triangles). + /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data BV fit(unsigned int* primitive_indices, int num_primitives) { BV bv; - if(type == BVH_MODEL_TRIANGLES) /* The primitive is triangle */ + if(type == BVH_MODEL_TRIANGLES) /// The primitive is triangle { for(int i = 0; i < num_primitives; ++i) { @@ -129,7 +132,7 @@ public: bv += vertices[t[1]]; bv += vertices[t[2]]; - if(prev_vertices) /* When fitting both current and previous frame */ + if(prev_vertices) /// can fitting both current and previous frame { bv += prev_vertices[t[0]]; bv += prev_vertices[t[1]]; @@ -137,13 +140,13 @@ public: } } } - else if(type == BVH_MODEL_POINTCLOUD) /* The primitive is point */ + else if(type == BVH_MODEL_POINTCLOUD) /// The primitive is point { for(int i = 0; i < num_primitives; ++i) { bv += vertices[primitive_indices[i]]; - if(prev_vertices) /* When fitting both current and previous frame */ + if(prev_vertices) /// can fitting both current and previous frame { bv += prev_vertices[primitive_indices[i]]; } @@ -153,7 +156,7 @@ public: return bv; } - /** \brief Clear the geometry primitive data */ + /// @brief Clear the geometry primitive data void clear() { vertices = NULL; @@ -171,12 +174,12 @@ private: }; -/** \brief Specification of BVFitter for OBB bounding volume */ +/// @brief Specification of BVFitter for OBB bounding volume template<> class BVFitter<OBB> : public BVFitterBase<OBB> { public: - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -185,7 +188,7 @@ public: type = type_; } - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting, for deformable mesh void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -194,12 +197,11 @@ public: type = type_; } - /** \brief Compute a bounding volume that fits a set of primitives (points or triangles). - * The primitive data was set by set function and primitive_indices is the primitive index relative to the data. - */ + /// @brief Compute a bounding volume that fits a set of primitives (points or triangles). + /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data. OBB fit(unsigned int* primitive_indices, int num_primitives); - /** \brief Clear the geometry primitive data */ + /// brief Clear the geometry primitive data void clear() { vertices = NULL; @@ -217,12 +219,12 @@ private: }; -/** \brief Specification of BVFitter for RSS bounding volume */ +/// @brief Specification of BVFitter for RSS bounding volume template<> class BVFitter<RSS> : public BVFitterBase<RSS> { public: - /** \brief Prepare the geometry primitive data for fitting */ + /// brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -231,7 +233,7 @@ public: type = type_; } - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting, for deformable mesh void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -240,12 +242,11 @@ public: type = type_; } - /** \brief Compute a bounding volume that fits a set of primitives (points or triangles). - * The primitive data was set by set function and primitive_indices is the primitive index relative to the data. - */ + /// @brief Compute a bounding volume that fits a set of primitives (points or triangles). + /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data. RSS fit(unsigned int* primitive_indices, int num_primitives); - /** \brief Clear the geometry primitive data */ + /// @brief Clear the geometry primitive data void clear() { vertices = NULL; @@ -263,12 +264,12 @@ private: }; -/** \brief Specification of BVFitter for kIOS bounding volume */ +/// @brief Specification of BVFitter for kIOS bounding volume template<> class BVFitter<kIOS> : public BVFitterBase<kIOS> { public: - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -277,7 +278,7 @@ public: type = type_; } - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -286,12 +287,11 @@ public: type = type_; } - /** \brief Compute a bounding volume that fits a set of primitives (points or triangles). - * The primitive data was set by set function and primitive_indices is the primitive index relative to the data. - */ + /// @brief Compute a bounding volume that fits a set of primitives (points or triangles). + /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data. kIOS fit(unsigned int* primitive_indices, int num_primitives); - /** \brief Clear the geometry primitive data */ + /// @brief Clear the geometry primitive data void clear() { vertices = NULL; @@ -308,12 +308,12 @@ private: }; -/** \brief Specification of BVFitter for OBBRSS bounding volume */ +/// @brief Specification of BVFitter for OBBRSS bounding volume template<> class BVFitter<OBBRSS> : public BVFitterBase<OBBRSS> { public: - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -322,7 +322,7 @@ public: type = type_; } - /** \brief Prepare the geometry primitive data for fitting */ + /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -331,12 +331,11 @@ public: type = type_; } - /** \brief Compute a bounding volume that fits a set of primitives (points or triangles). - * The primitive data was set by set function and primitive_indices is the primitive index relative to the data. - */ + /// @brief Compute a bounding volume that fits a set of primitives (points or triangles). + /// The primitive data was set by set function and primitive_indices is the primitive index relative to the data. OBBRSS fit(unsigned int* primitive_indices, int num_primitives); - /** \brief Clear the geometry primitive data */ + /// @brief Clear the geometry primitive data void clear() { vertices = NULL; diff --git a/trunk/fcl/include/fcl/BV_node.h b/trunk/fcl/include/fcl/BV_node.h index 28ab9fe4141aef01b4786e49bb5fe46f089cdcee..534e06195bec7712d96ae990de0f694c06cad2ec 100644 --- a/trunk/fcl/include/fcl/BV_node.h +++ b/trunk/fcl/include/fcl/BV_node.h @@ -41,135 +41,91 @@ #include "fcl/vec_3f.h" #include "fcl/matrix_3f.h" -#include "fcl/BV/OBB.h" -#include "fcl/BV/RSS.h" +#include "fcl/BV.h" +#include <iostream> -/** \brief Main namespace */ namespace fcl { +/// @brief BVNodeBase encodes the tree structure for BVH struct BVNodeBase { - /** \brief An index for first child node or primitive - * If the value is positive, it is the index of the first child bv node - * If the value is negative, it is -(primitive index + 1) - * Zero is not used. - */ + /// @brief An index for first child node or primitive + /// If the value is positive, it is the index of the first child bv node + /// If the value is negative, it is -(primitive index + 1) + /// Zero is not used. int first_child; - /** \brief The start id the primitive belonging to the current node. The index is referred to the primitive_indices in BVHModel and from that - * we can obtain the primitive's index in original data indirectly. - */ + /// @brief The start id the primitive belonging to the current node. The index is referred to the primitive_indices in BVHModel and from that + /// we can obtain the primitive's index in original data indirectly. int first_primitive; - /** \brief The number of primitives belonging to the current node */ + /// @brief The number of primitives belonging to the current node int num_primitives; - /** \brief Whether current node is a leaf node (i.e. contains a primitive index */ + /// @brief Whether current node is a leaf node (i.e. contains a primitive index inline bool isLeaf() const { return first_child < 0; } - /** \brief Return the primitive index. The index is referred to the original data (i.e. vertices or tri_indices) in BVHModel */ + /// @brief Return the primitive index. The index is referred to the original data (i.e. vertices or tri_indices) in BVHModel inline int primitiveId() const { return -(first_child + 1); } - /** \brief Return the index of the first child. The index is referred to the bounding volume array (i.e. bvs) in BVHModel */ + /// @brief Return the index of the first child. The index is referred to the bounding volume array (i.e. bvs) in BVHModel inline int leftChild() const { return first_child; } - /** \brief Return the index of the second child. The index is referred to the bounding volume array (i.e. bvs) in BVHModel */ + /// @brief Return the index of the second child. The index is referred to the bounding volume array (i.e. bvs) in BVHModel inline int rightChild() const { return first_child + 1; } }; -/** \brief A class describing a bounding volume node */ +/// @brief A class describing a bounding volume node. It includes the tree structure providing in BVNodeBase and also the geometry data provided in BV template parameter. template<typename BV> struct BVNode : public BVNodeBase { - /** \brief A bounding volume */ + /// @brief bounding volume storing the geometry BV bv; - /** \brief Check whether two BVNode collide */ + /// @brief Check whether two BVNode collide bool overlap(const BVNode& other) const { return bv.overlap(other.bv); } + /// @brief Compute the distance between two BVNode. P1 and P2, if not NULL and the underlying BV supports distance, return the nearest points. FCL_REAL distance(const BVNode& other, Vec3f* P1 = NULL, Vec3f* P2 = NULL) const { return bv.distance(other.bv, P1, P2); } - Vec3f getCenter() const { return Vec3f(); } - void setCenter(const Vec3f& v) {} + /// @brief Access the center of the BV + Vec3f getCenter() const { return bv.center(); } + + /// @brief Access the orientation of the BV Matrix3f getOrientation() const { return Matrix3f::getIdentity(); } - void setOrientation(const Matrix3f& m) {} }; template<> -struct BVNode<OBB> : public BVNodeBase +inline Matrix3f BVNode<OBB>::getOrientation() const { - /** \brief A bounding volume */ - OBB bv; - - /** \brief Check whether two BVNode collide */ - bool overlap(const BVNode& other) const - { - return bv.overlap(other.bv); - } - - FCL_REAL distance(const BVNode& other, Vec3f* P1 = NULL, Vec3f* P2 = NULL) const - { - return bv.distance(other.bv, P1, P2); - } - - Vec3f getCenter() const { return bv.To; } - void setCenter(const Vec3f& v) { bv.To = v; } - Matrix3f getOrientation() const - { - Matrix3f m(bv.axis[0][0], bv.axis[1][0], bv.axis[2][0], - bv.axis[0][1], bv.axis[1][1], bv.axis[2][1], - bv.axis[0][2], bv.axis[1][2], bv.axis[2][2]); - return m; - } - void setOrientation(const Matrix3f& m) - { - bv.axis[0].setValue(m(0, 0), m(1, 0), m(2, 0)); - bv.axis[1].setValue(m(0, 1), m(1, 1), m(2, 1)); - bv.axis[2].setValue(m(0, 2), m(1, 2), m(2, 2)); - } -}; + return Matrix3f(bv.axis[0][0], bv.axis[1][0], bv.axis[2][0], + bv.axis[0][1], bv.axis[1][1], bv.axis[2][1], + bv.axis[0][2], bv.axis[1][2], bv.axis[2][2]); +} template<> -struct BVNode<RSS> : public BVNodeBase +inline Matrix3f BVNode<RSS>::getOrientation() const { - /** \brief A bounding volume */ - RSS bv; - - /** \brief Check whether two BVNode collide */ - bool overlap(const BVNode& other) const - { - return bv.overlap(other.bv); - } - - FCL_REAL distance(const BVNode& other, Vec3f* P1 = NULL, Vec3f* P2 = NULL) const - { - return bv.distance(other.bv, P1, P2); - } + return Matrix3f(bv.axis[0][0], bv.axis[1][0], bv.axis[2][0], + bv.axis[0][1], bv.axis[1][1], bv.axis[2][1], + bv.axis[0][2], bv.axis[1][2], bv.axis[2][2]); +} - Vec3f getCenter() const { return bv.Tr; } - void setCenter(const Vec3f& v) { bv.Tr = v; } - Matrix3f getOrientation() const - { - Matrix3f m(bv.axis[0][0], bv.axis[1][0], bv.axis[2][0], - bv.axis[0][1], bv.axis[1][1], bv.axis[2][1], - bv.axis[0][2], bv.axis[1][2], bv.axis[2][2]); - return m; - } +template<> +inline Matrix3f BVNode<OBBRSS>::getOrientation() const +{ + return Matrix3f(bv.obb.axis[0][0], bv.obb.axis[1][0], bv.obb.axis[2][0], + bv.obb.axis[0][1], bv.obb.axis[1][1], bv.obb.axis[2][1], + bv.obb.axis[0][2], bv.obb.axis[1][2], bv.obb.axis[2][2]); +} - void setOrientation(const Matrix3f& m) - { - bv.axis[0].setValue(m(0, 0), m(1, 0), m(2, 0)); - bv.axis[1].setValue(m(0, 1), m(1, 1), m(2, 1)); - bv.axis[2].setValue(m(0, 2), m(1, 2), m(2, 2)); - } -}; } diff --git a/trunk/fcl/include/fcl/BV_splitter.h b/trunk/fcl/include/fcl/BV_splitter.h index ae38295cca3b1d6ddb861e840718bdb3e6adf841..cde0a6e8c2658b128e869386f49f8df826615172 100644 --- a/trunk/fcl/include/fcl/BV_splitter.h +++ b/trunk/fcl/include/fcl/BV_splitter.h @@ -48,47 +48,46 @@ #include <vector> #include <iostream> -/** \brief Main namespace */ namespace fcl { -/** \brief Base class for BV splitting operation */ +/// @brief Base interface for BV splitting algorithm template<typename BV> class BVSplitterBase { public: - /** \brief Set the geometry data needed by the split rule */ + /// @brief Set the geometry data needed by the split rule virtual void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) = 0; - /** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */ + /// @brief Compute the split rule according to a subset of geometry and the corresponding BV node virtual void computeRule(const BV& bv, unsigned int* primitive_indices, int num_primitives) = 0; - /** \brief Apply the split rule on a given point */ + /// @brief Apply the split rule on a given point virtual bool apply(const Vec3f& q) const = 0; - /** \brief Clear the geometry data set before */ + /// @brief Clear the geometry data set before virtual void clear() = 0; }; +/// @brief Three types of split algorithms are provided in FCL as default enum SplitMethodType {SPLIT_METHOD_MEAN, SPLIT_METHOD_MEDIAN, SPLIT_METHOD_BV_CENTER}; -/** \brief A class describing the split rule that splits each BV node */ +/// @brief A class describing the split rule that splits each BV node template<typename BV> class BVSplitter : public BVSplitterBase<BV> { public: - BVSplitter(SplitMethodType method) + BVSplitter(SplitMethodType method) : split_method(method) { - split_method = method; } - /** \brief Default deconstructor */ + /// @brief Default deconstructor virtual ~BVSplitter() {} - /** \brief Set the geometry data needed by the split rule */ + /// @brief Set the geometry data needed by the split rule void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) { vertices = vertices_; @@ -96,32 +95,32 @@ public: type = type_; } - /** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */ + /// @brief Compute the split rule according to a subset of geometry and the corresponding BV node void computeRule(const BV& bv, unsigned int* primitive_indices, int num_primitives) { switch(split_method) { - case SPLIT_METHOD_MEAN: - computeRule_mean(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_MEDIAN: - computeRule_median(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_BV_CENTER: - computeRule_bvcenter(bv, primitive_indices, num_primitives); - break; - default: - std::cerr << "Split method not supported" << std::endl; + case SPLIT_METHOD_MEAN: + computeRule_mean(bv, primitive_indices, num_primitives); + break; + case SPLIT_METHOD_MEDIAN: + computeRule_median(bv, primitive_indices, num_primitives); + break; + case SPLIT_METHOD_BV_CENTER: + computeRule_bvcenter(bv, primitive_indices, num_primitives); + break; + default: + std::cerr << "Split method not supported" << std::endl; } } - /** \brief Apply the split rule on a given point */ + /// @brief Apply the split rule on a given point bool apply(const Vec3f& q) const { return q[split_axis] > split_value; } - /** \brief Clear the geometry data set before */ + /// @brief Clear the geometry data set before void clear() { vertices = NULL; @@ -131,18 +130,27 @@ public: private: - /** \brief The split axis */ + /// @brief The axis based on which the split decision is made. For most BV, the axis is aligned with one of the world coordinate, so only split_axis is needed. + /// For oriented node, we can use a vector to make a better split decision. int split_axis; + Vec3f split_vector; - /** \brief The split threshold */ + /// @brief The split threshold, different primitives are splitted according whether their projection on the split_axis is larger or smaller than the threshold FCL_REAL split_value; + /// @brief The mesh vertices or points handled by the splitter Vec3f* vertices; + + /// @brief The triangles handled by the splitter Triangle* tri_indices; + + /// @brief Whether the geometry is mesh or point cloud BVHModelType type; + + /// @brief The split algorithm used SplitMethodType split_method; - /** \brief Split the node from center */ + /// @brief Split algorithm 1: Split the node from center void computeRule_bvcenter(const BV& bv, unsigned int* primitive_indices, int num_primitives) { Vec3f center = bv.center(); @@ -157,7 +165,7 @@ private: split_value = center[axis]; } - /** \brief Split the node according to the mean of the data contained */ + /// @brief Split algorithm 2: Split the node according to the mean of the data contained void computeRule_mean(const BV& bv, unsigned int* primitive_indices, int num_primitives) { int axis = 2; @@ -191,7 +199,7 @@ private: split_value = sum / num_primitives; } - /** \brief Split the node according to the median of the data contained */ + /// @brief Split algorithm 3: Split the node according to the median of the data contained void computeRule_median(const BV& bv, unsigned int* primitive_indices, int num_primitives) { int axis = 2; @@ -232,295 +240,53 @@ private: }; - -/** \brief BVHSplitRule specialization for OBB */ template<> -class BVSplitter<OBB> : public BVSplitterBase<OBB> -{ -public: - - BVSplitter(SplitMethodType method) - { - split_method = method; - } - - /** \brief Set the geometry data needed by the split rule */ - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - tri_indices = tri_indices_; - type = type_; - } - - /** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */ - void computeRule(const OBB& bv, unsigned int* primitive_indices, int num_primitives) - { - switch(split_method) - { - case SPLIT_METHOD_MEAN: - computeRule_mean(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_MEDIAN: - computeRule_median(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_BV_CENTER: - computeRule_bvcenter(bv, primitive_indices, num_primitives); - break; - default: - std::cerr << "Split method not supported" << std::endl; - } - } - - /** \brief Apply the split rule on a given point */ - bool apply(const Vec3f& q) const - { - return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; - } - - /** \brief Clear the geometry data set before */ - void clear() - { - vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - /** \brief Split the node from center */ - void computeRule_bvcenter(const OBB& bv, unsigned int* primitive_indices, int num_primitives); - - /** \brief Split the node according to the mean of the data contained */ - void computeRule_mean(const OBB& bv, unsigned int* primitive_indices, int num_primitives); - - /** \brief Split the node according to the median of the data contained */ - void computeRule_median(const OBB& bv, unsigned int* primitive_indices, int num_primitives); - - FCL_REAL split_value; - Vec3f split_vector; - - Vec3f* vertices; - Triangle* tri_indices; - BVHModelType type; - SplitMethodType split_method; -}; +bool BVSplitter<OBB>::apply(const Vec3f& q) const; - -/** \brief BVHSplitRule specialization for RSS */ template<> -class BVSplitter<RSS> : public BVSplitterBase<RSS> -{ -public: +bool BVSplitter<RSS>::apply(const Vec3f& q) const; - BVSplitter(SplitMethodType method) - { - split_method = method; - } - - /** \brief Set the geometry data needed by the split rule */ - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - tri_indices = tri_indices_; - type = type_; - } - - /** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */ - void computeRule(const RSS& bv, unsigned int* primitive_indices, int num_primitives) - { - switch(split_method) - { - case SPLIT_METHOD_MEAN: - computeRule_mean(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_MEDIAN: - computeRule_median(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_BV_CENTER: - computeRule_bvcenter(bv, primitive_indices, num_primitives); - break; - default: - std::cerr << "Split method not supported" << std::endl; - } - } - - /** \brief Apply the split rule on a given point */ - bool apply(const Vec3f& q) const - { - return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; - } - - /** \brief Clear the geometry data set before */ - void clear() - { - vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - /** \brief Split the node from center */ - void computeRule_bvcenter(const RSS& bv, unsigned int* primitive_indices, int num_primitives); - - /** \brief Split the node according to the mean of the data contained */ - void computeRule_mean(const RSS& bv, unsigned int* primitive_indices, int num_primitives); - - /** \brief Split the node according to the median of the data contained */ - void computeRule_median(const RSS& bv, unsigned int* primitive_indices, int num_primitives); - - FCL_REAL split_value; - Vec3f split_vector; - - Vec3f* vertices; - Triangle* tri_indices; - BVHModelType type; - SplitMethodType split_method; -}; - - -/** \brief BVHSplitRule specialization for RSS */ template<> -class BVSplitter<kIOS> : public BVSplitterBase<kIOS> -{ -public: - - BVSplitter(SplitMethodType method) - { - split_method = method; - } - - /** \brief Set the geometry data needed by the split rule */ - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - tri_indices = tri_indices_; - type = type_; - } - - /** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */ - void computeRule(const kIOS& bv, unsigned int* primitive_indices, int num_primitives) - { - switch(split_method) - { - case SPLIT_METHOD_MEAN: - computeRule_mean(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_MEDIAN: - computeRule_median(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_BV_CENTER: - computeRule_bvcenter(bv, primitive_indices, num_primitives); - break; - default: - std::cerr << "Split method not supported" << std::endl; - } - } - - /** \brief Apply the split rule on a given point */ - bool apply(const Vec3f& q) const - { - return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; - } - - /** \brief Clear the geometry data set before */ - void clear() - { - vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - /** \brief Split the node from center */ - void computeRule_bvcenter(const kIOS& bv, unsigned int* primitive_indices, int num_primitives); - - /** \brief Split the node according to the mean of the data contained */ - void computeRule_mean(const kIOS& bv, unsigned int* primitive_indices, int num_primitives); - - /** \brief Split the node according to the median of the data contained */ - void computeRule_median(const kIOS& bv, unsigned int* primitive_indices, int num_primitives); - - FCL_REAL split_value; - Vec3f split_vector; - - Vec3f* vertices; - Triangle* tri_indices; - BVHModelType type; - SplitMethodType split_method; -}; +bool BVSplitter<kIOS>::apply(const Vec3f& q) const; template<> -class BVSplitter<OBBRSS> : public BVSplitterBase<OBBRSS> -{ -public: +bool BVSplitter<OBBRSS>::apply(const Vec3f& q) const; - BVSplitter(SplitMethodType method) - { - split_method = method; - } +template<> +void BVSplitter<OBB>::computeRule_bvcenter(const OBB& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Set the geometry data needed by the split rule */ - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - tri_indices = tri_indices_; - type = type_; - } +template<> +void BVSplitter<OBB>::computeRule_mean(const OBB& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */ - void computeRule(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives) - { - switch(split_method) - { - case SPLIT_METHOD_MEAN: - computeRule_mean(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_MEDIAN: - computeRule_median(bv, primitive_indices, num_primitives); - break; - case SPLIT_METHOD_BV_CENTER: - computeRule_bvcenter(bv, primitive_indices, num_primitives); - break; - default: - std::cerr << "Split method not supported" << std::endl; - } - } +template<> +void BVSplitter<OBB>::computeRule_median(const OBB& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Apply the split rule on a given point */ - bool apply(const Vec3f& q) const - { - return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; - } +template<> +void BVSplitter<RSS>::computeRule_bvcenter(const RSS& bv, unsigned int* primitive_indices, int num_primitives); + +template<> +void BVSplitter<RSS>::computeRule_mean(const RSS& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Clear the geometry data set before */ - void clear() - { - vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } +template<> +void BVSplitter<RSS>::computeRule_median(const RSS& bv, unsigned int* primitive_indices, int num_primitives); -private: +template<> +void BVSplitter<kIOS>::computeRule_bvcenter(const kIOS& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Split the node from center */ - void computeRule_bvcenter(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives); +template<> +void BVSplitter<kIOS>::computeRule_mean(const kIOS& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Split the node according to the mean of the data contained */ - void computeRule_mean(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives); +template<> +void BVSplitter<kIOS>::computeRule_median(const kIOS& bv, unsigned int* primitive_indices, int num_primitives); - /** \brief Split the node according to the median of the data contained */ - void computeRule_median(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives); +template<> +void BVSplitter<OBBRSS>::computeRule_bvcenter(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives); - FCL_REAL split_value; - Vec3f split_vector; +template<> +void BVSplitter<OBBRSS>::computeRule_mean(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives); - Vec3f* vertices; - Triangle* tri_indices; - BVHModelType type; - SplitMethodType split_method; -}; +template<> +void BVSplitter<OBBRSS>::computeRule_median(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives); } diff --git a/trunk/fcl/include/fcl/broad_phase_collision.h b/trunk/fcl/include/fcl/broad_phase_collision.h deleted file mode 100644 index b3d7d626ee50c98a3eebb013e2f9766ad3830535..0000000000000000000000000000000000000000 --- a/trunk/fcl/include/fcl/broad_phase_collision.h +++ /dev/null @@ -1,1646 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2011, Willow Garage, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** \author Jia Pan */ - - - -#ifndef FCL_BROAD_PHASE_COLLISION_H -#define FCL_BROAD_PHASE_COLLISION_H - -#include "fcl/collision_object.h" -#include "fcl/collision_data.h" -#include "fcl/BV/AABB.h" -#include "fcl/interval_tree.h" -#include "fcl/hierarchy_tree.h" -#include "fcl/hash.h" -#include "fcl/octree.h" -#include <vector> -#include <list> -#include <iostream> -#include <boost/unordered_map.hpp> -#include <map> -#include <boost/bind.hpp> - -namespace fcl -{ - - -/** \brief return value is whether can stop now */ -typedef bool (*CollisionCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata); - -typedef bool (*DistanceCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata, FCL_REAL& dist); - - -/** \brief Base class for broad phase collision */ -class BroadPhaseCollisionManager -{ -public: - BroadPhaseCollisionManager() - { - enable_tested_set_ = false; - } - - virtual ~BroadPhaseCollisionManager() {} - - /** \brief add objects to the manager */ - virtual void registerObjects(const std::vector<CollisionObject*>& other_objs) - { - for(size_t i = 0; i < other_objs.size(); ++i) - registerObject(other_objs[i]); - } - - /** \brief add one object to the manager */ - virtual void registerObject(CollisionObject* obj) = 0; - - /** \brief remove one object from the manager */ - virtual void unregisterObject(CollisionObject* obj) = 0; - - /** \brief initialize the manager, related with the specific type of manager */ - virtual void setup() = 0; - - /** \brief update the condition of manager */ - virtual void update() = 0; - - /** \brief update the manager by explicitly given the object updated */ - virtual void update(CollisionObject* updated_obj) - { - update(); - } - - /** \brief update the manager by explicitly given the set of objects update */ - virtual void update(const std::vector<CollisionObject*>& updated_objs) - { - update(); - } - - /** \brief clear the manager */ - virtual void clear() = 0; - - /** \brief return the objects managed by the manager */ - virtual void getObjects(std::vector<CollisionObject*>& objs) const = 0; - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - virtual void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const = 0; - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - virtual void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const = 0; - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - virtual void collide(void* cdata, CollisionCallBack callback) const = 0; - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - virtual void distance(void* cdata, DistanceCallBack callback) const = 0; - - /** \brief perform collision test with objects belonging to another manager */ - virtual void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const = 0; - - /** \brief perform distance test with objects belonging to another manager */ - virtual void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const = 0; - - /** \brief whether the manager is empty */ - virtual bool empty() const = 0; - - /** \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 bool enable_tested_set_; - - bool inTestedSet(CollisionObject* a, CollisionObject* b) const - { - if(a < b) return tested_set.find(std::make_pair(a, b)) != tested_set.end(); - else return tested_set.find(std::make_pair(b, a)) != tested_set.end(); - } - - void insertTestedSet(CollisionObject* a, CollisionObject* b) const - { - if(a < b) tested_set.insert(std::make_pair(a, b)); - else tested_set.insert(std::make_pair(b, a)); - } - -}; - - -/** \brief Brute force N-body collision manager */ -class NaiveCollisionManager : public BroadPhaseCollisionManager -{ -public: - NaiveCollisionManager() {} - - /** \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); - - /** \brief remove one object from the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief clear the manager */ - void clear(); - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const; - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; - - /** \brief whether the manager is empty */ - bool empty() const; - - /** \brief the number of objects managed by the manager */ - inline size_t size() const { return objs.size(); } - -protected: - - /** \brief objects belonging to the manager are stored in a list structure */ - std::list<CollisionObject*> objs; -}; - -/** \brief Spatial hash function: hash an AABB to a set of integer values */ -struct SpatialHash -{ - SpatialHash(const AABB& scene_limit_, FCL_REAL cell_size_) - { - cell_size = cell_size_; - scene_limit = scene_limit_; - width[0] = ceil(scene_limit.width() / cell_size); - width[1] = ceil(scene_limit.height() / cell_size); - width[2] = ceil(scene_limit.depth() / cell_size); - } - - std::vector<unsigned int> operator() (const AABB& aabb) const - { - int min_x = floor((aabb.min_[0] - scene_limit.min_[0]) / cell_size); - int max_x = ceil((aabb.max_[0] - scene_limit.min_[0]) / cell_size); - int min_y = floor((aabb.min_[1] - scene_limit.min_[1]) / cell_size); - int max_y = ceil((aabb.max_[1] - scene_limit.min_[1]) / cell_size); - int min_z = floor((aabb.min_[2] - scene_limit.min_[2]) / cell_size); - int max_z = ceil((aabb.max_[2] - scene_limit.min_[2]) / cell_size); - - std::vector<unsigned int> keys((max_x - min_x) * (max_y - min_y) * (max_z - min_z)); - int id = 0; - for(int x = min_x; x < max_x; ++x) - { - for(int y = min_y; y < max_y; ++y) - { - for(int z = min_z; z < max_z; ++z) - { - keys[id++] = x + y * width[0] + z * width[0] * width[1]; - } - } - } - return keys; - } - -private: - - FCL_REAL cell_size; - AABB scene_limit; - unsigned int width[3]; -}; - -/** \brief spatial hashing collision mananger */ -template<typename HashTable = SimpleHashTable<AABB, CollisionObject*, SpatialHash> > -class SpatialHashingCollisionManager : public BroadPhaseCollisionManager -{ -public: - SpatialHashingCollisionManager(FCL_REAL cell_size, const Vec3f& scene_min, const Vec3f& scene_max, unsigned int default_table_size = 1000) - { - scene_limit = AABB(scene_min, scene_max); - SpatialHash hasher(scene_limit, cell_size); - hash_table = new HashTable(hasher); - hash_table->init(default_table_size); - } - - ~SpatialHashingCollisionManager() - { - delete hash_table; - } - - /** \brief add one object to the manager */ - void registerObject(CollisionObject* obj); - - /** \brief remove one object from the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief update the manager by explicitly given the object updated */ - void update(CollisionObject* updated_obj); - - /** \brief update the manager by explicitly given the set of objects update */ - void update(const std::vector<CollisionObject*>& updated_objs); - - /** \brief clear the manager */ - void clear(); - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const; - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance computation between one object and all the objects belonging ot the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test for the objects belonging to the manager (i.e, N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; - - /** \brief whether the manager is empty */ - bool empty() const; - - /** \brief the number of objects managed by the manager */ - size_t size() const; - - /** \brief compute the bound for the environent */ - static void computeBound(std::vector<CollisionObject*>& objs, Vec3f& l, Vec3f& u) - { - AABB bound; - for(unsigned int i = 0; i < objs.size(); ++i) - bound += objs[i]->getAABB(); - - l = bound.min_; - u = bound.max_; - } - -protected: - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance computation between one object and all the objects belonging ot the manager */ - bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - - // all objects in the scene - 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; - // objects outside the scene limit are in another list - std::list<CollisionObject*> objs_outside_scene_limit; - - // the size of the scene - AABB scene_limit; - - std::map<CollisionObject*, AABB> obj_aabb_map; // store the map between objects and their aabbs. will make update more convenient -}; - - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::registerObject(CollisionObject* obj) -{ - objs.push_back(obj); - - const AABB& obj_aabb = obj->getAABB(); - AABB overlap_aabb; - - if(scene_limit.overlap(obj_aabb, overlap_aabb)) - { - if(!scene_limit.contain(obj_aabb)) - objs_outside_scene_limit.push_back(obj); - - hash_table->insert(overlap_aabb, obj); - } - else - objs_outside_scene_limit.push_back(obj); - - obj_aabb_map[obj] = obj_aabb; -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::unregisterObject(CollisionObject* obj) -{ - objs.remove(obj); - - const AABB& obj_aabb = obj->getAABB(); - AABB overlap_aabb; - - if(scene_limit.overlap(obj_aabb, overlap_aabb)) - { - if(!scene_limit.contain(obj_aabb)) - objs_outside_scene_limit.remove(obj); - - hash_table->remove(overlap_aabb, obj); - } - else - objs_outside_scene_limit.remove(obj); - - obj_aabb_map.erase(obj); -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::setup() -{} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::update() -{ - hash_table->clear(); - objs_outside_scene_limit.clear(); - - for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); - it != end; ++it) - { - CollisionObject* obj = *it; - const AABB& obj_aabb = obj->getAABB(); - AABB overlap_aabb; - - if(scene_limit.overlap(obj_aabb, overlap_aabb)) - { - if(!scene_limit.contain(obj_aabb)) - objs_outside_scene_limit.push_back(obj); - - hash_table->insert(overlap_aabb, obj); - } - else - objs_outside_scene_limit.push_back(obj); - - obj_aabb_map[obj] = obj_aabb; - } -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::update(CollisionObject* updated_obj) -{ - const AABB& new_aabb = updated_obj->getAABB(); - const AABB& old_aabb = obj_aabb_map[updated_obj]; - - if(!scene_limit.contain(old_aabb)) // previously not completely in scene limit - { - if(scene_limit.contain(new_aabb)) - { - std::list<CollisionObject*>::iterator find_it = std::find(objs_outside_scene_limit.begin(), - objs_outside_scene_limit.end(), - updated_obj); - - objs_outside_scene_limit.erase(find_it); - } - } - else if(!scene_limit.contain(new_aabb)) // previous completely in scenelimit, now not - objs_outside_scene_limit.push_back(updated_obj); - - AABB old_overlap_aabb; - if(scene_limit.overlap(old_aabb, old_overlap_aabb)) - hash_table->remove(old_overlap_aabb, updated_obj); - - AABB new_overlap_aabb; - if(scene_limit.overlap(new_aabb, new_overlap_aabb)) - hash_table->insert(new_overlap_aabb, updated_obj); - - obj_aabb_map[updated_obj] = new_aabb; -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::update(const std::vector<CollisionObject*>& updated_objs) -{ - for(size_t i = 0; i < updated_objs.size(); ++i) - update(updated_objs[i]); -} - - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::clear() -{ - objs.clear(); - hash_table->clear(); - objs_outside_scene_limit.clear(); - obj_aabb_map.clear(); -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::getObjects(std::vector<CollisionObject*>& objs_) const -{ - objs_.resize(objs.size()); - std::copy(objs.begin(), objs.end(), objs_.begin()); -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - collide_(obj, cdata, callback); -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - distance_(obj, cdata, callback, min_dist); -} - -template<typename HashTable> -bool SpatialHashingCollisionManager<HashTable>::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - const AABB& obj_aabb = obj->getAABB(); - AABB overlap_aabb; - - if(scene_limit.overlap(obj_aabb, overlap_aabb)) - { - if(!scene_limit.contain(obj_aabb)) - { - for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); - it != end; ++it) - { - if(obj == *it) continue; - if(callback(obj, *it, cdata)) return true; - } - } - - std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb); - for(unsigned int i = 0; i < query_result.size(); ++i) - { - if(obj == query_result[i]) continue; - if(callback(obj, query_result[i], cdata)) return true; - } - } - else - { - ; - for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); - it != end; ++it) - { - if(obj == *it) continue; - if(callback(obj, *it, cdata)) return true; - } - } - - return false; -} - -template<typename HashTable> -bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; - AABB aabb = obj->getAABB(); - if(min_dist < std::numeric_limits<FCL_REAL>::max()) - { - Vec3f min_dist_delta(min_dist, min_dist, min_dist); - aabb.expand(min_dist_delta); - } - - AABB overlap_aabb; - - int status = 1; - FCL_REAL old_min_distance; - - while(1) - { - old_min_distance = min_dist; - - if(scene_limit.overlap(aabb, overlap_aabb)) - { - if(!scene_limit.contain(aabb)) - { - for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); - it != end; ++it) - { - if(obj == *it) continue; - if(!enable_tested_set_) - { - if(obj->getAABB().distance((*it)->getAABB()) < min_dist) - if(callback(obj, *it, cdata, min_dist)) return true; - } - else - { - if(!inTestedSet(obj, *it)) - { - if(obj->getAABB().distance((*it)->getAABB()) < min_dist) - if(callback(obj, *it, cdata, min_dist)) return true; - insertTestedSet(obj, *it); - } - } - } - } - - std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb); - for(unsigned int i = 0; i < query_result.size(); ++i) - { - if(obj == query_result[i]) continue; - if(!enable_tested_set_) - { - if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist) - if(callback(obj, query_result[i], cdata, min_dist)) return true; - } - else - { - if(!inTestedSet(obj, query_result[i])) - { - if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist) - if(callback(obj, query_result[i], cdata, min_dist)) return true; - insertTestedSet(obj, query_result[i]); - } - } - } - } - else - { - for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); - it != end; ++it) - { - if(obj == *it) continue; - if(!enable_tested_set_) - { - if(obj->getAABB().distance((*it)->getAABB()) < min_dist) - if(callback(obj, *it, cdata, min_dist)) return true; - } - else - { - if(!inTestedSet(obj, *it)) - { - if(obj->getAABB().distance((*it)->getAABB()) < min_dist) - if(callback(obj, *it, cdata, min_dist)) return true; - insertTestedSet(obj, *it); - } - } - } - } - - if(status == 1) - { - if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) - break; - 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; -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::collide(void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end1 = objs.end(); - it1 != end1; ++it1) - { - const AABB& obj_aabb = (*it1)->getAABB(); - AABB overlap_aabb; - - if(scene_limit.overlap(obj_aabb, overlap_aabb)) - { - if(!scene_limit.contain(obj_aabb)) - { - for(std::list<CollisionObject*>::const_iterator it2 = objs_outside_scene_limit.begin(), end2 = objs_outside_scene_limit.end(); - it2 != end2; ++it2) - { - if(*it1 < *it2) { if(callback(*it1, *it2, cdata)) return; } - } - } - - std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb); - for(unsigned int i = 0; i < query_result.size(); ++i) - { - if(*it1 < query_result[i]) { if(callback(*it1, query_result[i], cdata)) return; } - } - } - else - { - for(std::list<CollisionObject*>::const_iterator it2 = objs_outside_scene_limit.begin(), end2 = objs_outside_scene_limit.end(); - it2 != end2; ++it2) - { - if(*it1 < *it2) { if(callback(*it1, *it2, cdata)) return; } - } - } - } -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::distance(void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - enable_tested_set_ = true; - tested_set.clear(); - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) - if(distance_(*it, cdata, callback, min_dist)) break; - - enable_tested_set_ = false; - tested_set.clear(); -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const -{ - SpatialHashingCollisionManager<HashTable>* other_manager = static_cast<SpatialHashingCollisionManager<HashTable>* >(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - collide(cdata, callback); - return; - } - - if(this->size() < other_manager->size()) - { - for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) - if(other_manager->collide_(*it, cdata, callback)) return; - } - else - { - for(std::list<CollisionObject*>::const_iterator it = other_manager->objs.begin(), end = other_manager->objs.end(); it != end; ++it) - if(collide_(*it, cdata, callback)) return; - } -} - -template<typename HashTable> -void SpatialHashingCollisionManager<HashTable>::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const -{ - SpatialHashingCollisionManager<HashTable>* other_manager = static_cast<SpatialHashingCollisionManager<HashTable>* >(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - distance(cdata, callback); - return; - } - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - if(this->size() < other_manager->size()) - { - for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) - if(other_manager->distance_(*it, cdata, callback, min_dist)) return; - } - else - { - for(std::list<CollisionObject*>::const_iterator it = other_manager->objs.begin(), end = other_manager->objs.end(); it != end; ++it) - if(distance_(*it, cdata, callback, min_dist)) return; - } -} - -template<typename HashTable> -bool SpatialHashingCollisionManager<HashTable>::empty() const -{ - return objs.empty(); -} - -template<typename HashTable> -size_t SpatialHashingCollisionManager<HashTable>::size() const -{ - return objs.size(); -} - - -/** Rigorous SAP collision manager */ -class SaPCollisionManager : public BroadPhaseCollisionManager -{ -public: - - SaPCollisionManager() - { - elist[0] = NULL; - elist[1] = NULL; - elist[2] = NULL; - - optimal_axis = 0; - } - - ~SaPCollisionManager() - { - clear(); - } - - /** \brief add objects to the manager */ - void registerObjects(const std::vector<CollisionObject*>& other_objs); - - /** \brief remove one object from the manager */ - void registerObject(CollisionObject* obj); - - /** \brief add one object to the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief update the manager by explicitly given the object updated */ - void update(CollisionObject* updated_obj); - - /** \brief update the manager by explicitly given the set of objects update */ - void update(const std::vector<CollisionObject*>& updated_objs); - - /** \brief clear the manager */ - void clear(); - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const; - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; - - /** \brief whether the manager is empty */ - bool empty() const; - - /** \brief the number of objects managed by the manager */ - inline size_t size() const { return AABB_arr.size(); } - -protected: - - struct EndPoint; - - /** \brief SAP interval for one object */ - struct SaPAABB - { - /** \brief object */ - CollisionObject* obj; - - /** \brief lower bound end point of the interval */ - EndPoint* lo; - - /** \brief higher bound end point of the interval */ - EndPoint* hi; - - /** \brief cached AABB value */ - AABB cached; - }; - - /** \brief End point for an interval */ - struct EndPoint - { - /** \brief tag for whether it is a lower bound or higher bound of an interval, 0 for lo, and 1 for hi */ - char minmax; - - /** \brief back pointer to SAP interval */ - SaPAABB* aabb; - - /** \brief the previous end point in the end point list */ - EndPoint* prev[3]; - /** \brief the next end point in the end point list */ - EndPoint* next[3]; - - /** \brief get the value of the end point */ - inline const Vec3f& getVal() const - { - if(minmax) return aabb->cached.max_; - else return aabb->cached.min_; - } - - /** \brief set the value of the end point */ - inline Vec3f& getVal() - { - if(minmax) return aabb->cached.max_; - else return aabb->cached.min_; - } - - inline FCL_REAL getVal(size_t i) const - { - if(minmax) return aabb->cached.max_[i]; - else return aabb->cached.min_[i]; - } - - inline FCL_REAL& getVal(size_t i) - { - if(minmax) return aabb->cached.max_[i]; - else return aabb->cached.min_[i]; - } - - }; - - /** \brief A pair of objects that are not culling away and should further check collision */ - struct SaPPair - { - SaPPair(CollisionObject* a, CollisionObject* b) - { - if(a < b) - { - obj1 = a; - obj2 = b; - } - else - { - obj1 = b; - obj2 = a; - } - } - - CollisionObject* obj1; - CollisionObject* obj2; - - bool operator == (const SaPPair& other) const - { - return ((obj1 == other.obj1) && (obj2 == other.obj2)); - } - }; - - /** Functor to help unregister one object */ - class isUnregistered - { - CollisionObject* obj; - - public: - isUnregistered(CollisionObject* obj_) - { - obj = obj_; - } - - bool operator() (const SaPPair& pair) - { - return (pair.obj1 == obj) || (pair.obj2 == obj); - } - }; - - /** Functor to help remove collision pairs no longer valid (i.e., should be culled away) */ - class isNotValidPair - { - CollisionObject* obj1; - CollisionObject* obj2; - - public: - isNotValidPair(CollisionObject* obj1_, CollisionObject* obj2_) - { - obj1 = obj1_; - obj2 = obj2_; - } - - bool operator() (const SaPPair& pair) - { - return (pair.obj1 == obj1) && (pair.obj2 == obj2); - } - }; - - void update_(SaPAABB* updated_aabb); - - void updateVelist() - { - for(int coord = 0; coord < 3; ++coord) - { - velist[coord].resize(size() * 2); - EndPoint* current = elist[coord]; - size_t id = 0; - while(current) - { - velist[coord][id] = current; - current = current->next[coord]; - id++; - } - } - } - - /** \brief End point list for x, y, z coordinates */ - EndPoint* elist[3]; - - /** \brief vector version of elist, for acceleration */ - std::vector<EndPoint*> velist[3]; - - /** \brief SAP interval list */ - std::list<SaPAABB*> AABB_arr; - - /** \brief The pair of objects that should further check for collision */ - std::list<SaPPair> overlap_pairs; - - size_t optimal_axis; - - std::map<CollisionObject*, SaPAABB*> obj_aabb_map; - - bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - void addToOverlapPairs(const SaPPair& p) - { - bool repeated = false; - for(std::list<SaPPair>::iterator it = overlap_pairs.begin(), end = overlap_pairs.end(); - it != end; - ++it) - { - if(*it == p) - { - repeated = true; - break; - } - } - - if(!repeated) - overlap_pairs.push_back(p); - } - - void removeFromOverlapPairs(const SaPPair& p) - { - for(std::list<SaPPair>::iterator it = overlap_pairs.begin(), end = overlap_pairs.end(); - it != end; - ++it) - { - if(*it == p) - { - overlap_pairs.erase(it); - break; - } - } - - // or overlap_pairs.remove_if(isNotValidPair(p)); - } -}; - - - - -/** Simple SAP collision manager */ -class SSaPCollisionManager : public BroadPhaseCollisionManager -{ -public: - SSaPCollisionManager() - { - setup_ = false; - } - - /** \brief remove one object from the manager */ - void registerObject(CollisionObject* obj); - - /** \brief add one object to the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief clear the manager */ - void clear(); - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const; - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; - - /** \brief whether the manager is empty */ - bool empty() const; - - /** \brief the number of objects managed by the manager */ - inline size_t size() const { return objs_x.size(); } - -protected: - /** \brief check collision between one object and a list of objects, return value is whether stop is possible */ - bool checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, - CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief check distance between one object and a list of objects, return value is whether stop is possible */ - bool checkDis(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, - CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - - bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - static inline size_t selectOptimalAxis(const std::vector<CollisionObject*>& objs_x, const std::vector<CollisionObject*>& objs_y, const std::vector<CollisionObject*>& objs_z, std::vector<CollisionObject*>::const_iterator& it_beg, std::vector<CollisionObject*>::const_iterator& it_end) - { - // simple sweep and prune method - double delta_x = (objs_x[objs_x.size() - 1])->getAABB().min_[0] - (objs_x[0])->getAABB().min_[0]; - double delta_y = (objs_x[objs_y.size() - 1])->getAABB().min_[1] - (objs_y[0])->getAABB().min_[1]; - double delta_z = (objs_z[objs_z.size() - 1])->getAABB().min_[2] - (objs_z[0])->getAABB().min_[2]; - - int axis = 0; - if(delta_y > delta_x && delta_y > delta_z) - axis = 1; - else if(delta_z > delta_y && delta_z > delta_x) - axis = 2; - - switch(axis) - { - case 0: - it_beg = objs_x.begin(); - it_end = objs_x.end(); - break; - case 1: - it_beg = objs_y.begin(); - it_end = objs_y.end(); - break; - case 2: - it_beg = objs_z.begin(); - it_end = objs_z.end(); - break; - } - - return axis; - } - - - /** \brief Objects sorted according to lower x value */ - std::vector<CollisionObject*> objs_x; - - /** \brief Objects sorted according to lower y value */ - std::vector<CollisionObject*> objs_y; - - /** \brief Objects sorted according to lower z value */ - std::vector<CollisionObject*> objs_z; - - /** \brief tag about whether the environment is maintained suitably (i.e., the objs_x, objs_y, objs_z are sorted correctly */ - bool setup_; -}; - -/** Collision manager based on interval tree */ -class IntervalTreeCollisionManager : public BroadPhaseCollisionManager -{ -public: - IntervalTreeCollisionManager() - { - setup_ = false; - for(int i = 0; i < 3; ++i) - interval_trees[i] = NULL; - } - - ~IntervalTreeCollisionManager() - { - clear(); - } - - /** \brief remove one object from the manager */ - void registerObject(CollisionObject* obj); - - /** \brief add one object to the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief update the manager by explicitly given the object updated */ - void update(CollisionObject* updated_obj); - - /** \brief update the manager by explicitly given the set of objects update */ - void update(const std::vector<CollisionObject*>& updated_objs); - - /** \brief clear the manager */ - void clear(); - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const; - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const; - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; - - /** \brief whether the manager is empty */ - bool empty() const; - - /** \brief the number of objects managed by the manager */ - inline size_t size() const { return endpoints[0].size() / 2; } - -protected: - - - /** \brief SAP end point */ - struct EndPoint - { - /** \brief object related with the end point */ - CollisionObject* obj; - - /** \brief end point value */ - FCL_REAL value; - - /** \brief tag for whether it is a lower bound or higher bound of an interval, 0 for lo, and 1 for hi */ - char minmax; - }; - - /** \brief Extention interval tree's interval to SAP interval, adding more information */ - struct SAPInterval : public SimpleInterval - { - CollisionObject* obj; - SAPInterval(double low_, double high_, CollisionObject* obj_) : SimpleInterval() - { - low = low_; - high = high_; - obj = obj_; - } - }; - - - bool checkColl(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - bool checkDist(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; - - bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - /** \brief vector stores all the end points */ - std::vector<EndPoint> endpoints[3]; - - /** \brief interval tree manages the intervals */ - IntervalTree* interval_trees[3]; - - std::map<CollisionObject*, SAPInterval*> obj_interval_maps[3]; - - /** \brief tag for whether the interval tree is maintained suitably */ - bool setup_; -}; - -class DynamicAABBTreeCollisionManager : public BroadPhaseCollisionManager -{ -public: - typedef NodeBase<AABB> DynamicAABBNode; - typedef boost::unordered_map<CollisionObject*, DynamicAABBNode*> DynamicAABBTable; - - int max_tree_nonbalanced_level; - int tree_incremental_balance_pass; - int& tree_topdown_balance_threshold; - int& tree_topdown_level; - int tree_init_level; - - bool octree_as_geometry_collide; - bool octree_as_geometry_distance; - - - DynamicAABBTreeCollisionManager() : tree_topdown_balance_threshold(dtree.bu_threshold), - tree_topdown_level(dtree.topdown_level) - { - max_tree_nonbalanced_level = 10; - tree_incremental_balance_pass = 10; - tree_topdown_balance_threshold = 2; - tree_topdown_level = 0; - tree_init_level = 0; - setup_ = false; - - // from experiment, this is the optimal setting - octree_as_geometry_collide = true; - octree_as_geometry_distance = 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); - - /** \brief remove one object from the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief update the manager by explicitly given the object updated */ - void update(CollisionObject* updated_obj); - - /** \brief update the manager by explicitly given the set of objects update */ - void update(const std::vector<CollisionObject*>& updated_objs); - - /** \brief clear the manager */ - void clear() - { - dtree.clear(); - table.clear(); - } - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const - { - objs.resize(this->size()); - std::transform(table.begin(), table.end(), objs.begin(), boost::bind(&DynamicAABBTable::value_type::first, _1)); - } - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const - { - if(size() == 0) return; - switch(obj->getCollisionGeometry()->getNodeType()) - { - case GEOM_OCTREE: - { - if(!octree_as_geometry_collide) - { - const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); - collisionRecurse(dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback); - } - else - collisionRecurse(dtree.getRoot(), obj, cdata, callback); - } - break; - default: - collisionRecurse(dtree.getRoot(), obj, cdata, callback); - } - } - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const - { - if(size() == 0) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - switch(obj->getCollisionGeometry()->getNodeType()) - { - case GEOM_OCTREE: - { - if(!octree_as_geometry_distance) - { - const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); - distanceRecurse(dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback, min_dist); - } - else - distanceRecurse(dtree.getRoot(), obj, cdata, callback, min_dist); - } - break; - default: - distanceRecurse(dtree.getRoot(), obj, cdata, callback, min_dist); - } - } - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const - { - if(size() == 0) return; - selfCollisionRecurse(dtree.getRoot(), cdata, callback); - } - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const - { - if(size() == 0) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - selfDistanceRecurse(dtree.getRoot(), cdata, callback, min_dist); - } - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const - { - DynamicAABBTreeCollisionManager* other_manager = static_cast<DynamicAABBTreeCollisionManager*>(other_manager_); - if((size() == 0) || (other_manager->size() == 0)) return; - collisionRecurse(dtree.getRoot(), other_manager->dtree.getRoot(), cdata, callback); - } - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const - { - DynamicAABBTreeCollisionManager* other_manager = static_cast<DynamicAABBTreeCollisionManager*>(other_manager_); - if((size() == 0) || (other_manager->size() == 0)) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - distanceRecurse(dtree.getRoot(), other_manager->dtree.getRoot(), cdata, callback, min_dist); - } - - /** \brief whether the manager is empty */ - bool empty() const - { - return dtree.empty(); - } - - /** \brief the number of objects managed by the manager */ - size_t size() const - { - return dtree.size(); - } - - const HierarchyTree<AABB>& getTree() const { return dtree; } - - -private: - HierarchyTree<AABB> dtree; - boost::unordered_map<CollisionObject*, DynamicAABBNode*> table; - - bool setup_; - - bool collisionRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, CollisionCallBack callback) const; - - bool collisionRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, CollisionCallBack callback) const; - - bool selfCollisionRecurse(DynamicAABBNode* root, void* cdata, CollisionCallBack callback) const; - - bool distanceRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - bool distanceRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - bool selfDistanceRecurse(DynamicAABBNode* root, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - void update_(CollisionObject* updated_obj); - - /** \brief special manager-obj collision for octree */ - bool collisionRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) const; - - bool distanceRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - -}; - - - - -class DynamicAABBTreeCollisionManager2 : public BroadPhaseCollisionManager -{ -public: - typedef alternative::NodeBase<AABB> DynamicAABBNode; - typedef boost::unordered_map<CollisionObject*, size_t> DynamicAABBTable; - - int max_tree_nonbalanced_level; - int tree_incremental_balance_pass; - int& tree_topdown_balance_threshold; - int& tree_topdown_level; - int tree_init_level; - - bool octree_as_geometry_collide; - bool octree_as_geometry_distance; - - DynamicAABBTreeCollisionManager2() : tree_topdown_balance_threshold(dtree.bu_threshold), - tree_topdown_level(dtree.topdown_level) - { - max_tree_nonbalanced_level = 10; - tree_incremental_balance_pass = 10; - tree_topdown_balance_threshold = 2; - tree_topdown_level = 0; - tree_init_level = 0; - setup_ = false; - - // from experiment, this is the optimal setting - octree_as_geometry_collide = true; - octree_as_geometry_distance = 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); - - /** \brief remove one object from the manager */ - void unregisterObject(CollisionObject* obj); - - /** \brief initialize the manager, related with the specific type of manager */ - void setup(); - - /** \brief update the condition of manager */ - void update(); - - /** \brief update the manager by explicitly given the object updated */ - void update(CollisionObject* updated_obj); - - /** \brief update the manager by explicitly given the set of objects update */ - void update(const std::vector<CollisionObject*>& updated_objs); - - /** \brief clear the manager */ - void clear() - { - dtree.clear(); - table.clear(); - } - - /** \brief return the objects managed by the manager */ - void getObjects(std::vector<CollisionObject*>& objs) const - { - objs.resize(this->size()); - std::transform(table.begin(), table.end(), objs.begin(), boost::bind(&DynamicAABBTable::value_type::first, _1)); - } - - /** \brief perform collision test between one object and all the objects belonging to the manager */ - void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const - { - if(size() == 0) return; - switch(obj->getCollisionGeometry()->getNodeType()) - { - case GEOM_OCTREE: - { - if(!octree_as_geometry_collide) - { - const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); - collisionRecurse(dtree.getNodes(), dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback); - } - else - collisionRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback); - } - break; - default: - collisionRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback); - } - } - - /** \brief perform distance computation between one object and all the objects belonging to the manager */ - void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const - { - if(size() == 0) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - switch(obj->getCollisionGeometry()->getNodeType()) - { - case GEOM_OCTREE: - { - if(!octree_as_geometry_distance) - { - const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); - distanceRecurse(dtree.getNodes(), dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback, min_dist); - } - else - distanceRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback, min_dist); - } - break; - default: - distanceRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback, min_dist); - } - } - - /** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */ - void collide(void* cdata, CollisionCallBack callback) const - { - if(size() == 0) return; - selfCollisionRecurse(dtree.getNodes(), dtree.getRoot(), cdata, callback); - } - - /** \brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) */ - void distance(void* cdata, DistanceCallBack callback) const - { - if(size() == 0) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - selfDistanceRecurse(dtree.getNodes(), dtree.getRoot(), cdata, callback, min_dist); - } - - /** \brief perform collision test with objects belonging to another manager */ - void collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const - { - DynamicAABBTreeCollisionManager2* other_manager = static_cast<DynamicAABBTreeCollisionManager2*>(other_manager_); - if((size() == 0) || (other_manager->size() == 0)) return; - collisionRecurse(dtree.getNodes(), dtree.getRoot(), other_manager->dtree.getNodes(), other_manager->dtree.getRoot(), cdata, callback); - } - - /** \brief perform distance test with objects belonging to another manager */ - void distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const - { - DynamicAABBTreeCollisionManager2* other_manager = static_cast<DynamicAABBTreeCollisionManager2*>(other_manager_); - if((size() == 0) || (other_manager->size() == 0)) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - distanceRecurse(dtree.getNodes(), dtree.getRoot(), other_manager->dtree.getNodes(), other_manager->dtree.getRoot(), cdata, callback, min_dist); - } - - /** \brief whether the manager is empty */ - bool empty() const - { - return dtree.empty(); - } - - /** \brief the number of objects managed by the manager */ - size_t size() const - { - return dtree.size(); - } - - - const alternative::HierarchyTree<AABB>& getTree() const { return dtree; } - -private: - alternative::HierarchyTree<AABB> dtree; - boost::unordered_map<CollisionObject*, size_t> table; - - bool setup_; - - bool collisionRecurse(DynamicAABBNode* nodes1, size_t root1, DynamicAABBNode* nodes2, size_t root2, void* cdata, CollisionCallBack callback) const; - - bool collisionRecurse(DynamicAABBNode* nodes, size_t root, CollisionObject* query, void* cdata, CollisionCallBack callback) const; - - bool selfCollisionRecurse(DynamicAABBNode* nodes, size_t root, void* cdata, CollisionCallBack callback) const; - - bool distanceRecurse(DynamicAABBNode* nodes1, size_t root1, DynamicAABBNode* nodes2, size_t root2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - bool distanceRecurse(DynamicAABBNode* nodes, size_t root, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - bool selfDistanceRecurse(DynamicAABBNode* nodes, size_t root, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; - - void update_(CollisionObject* updated_obj); - - /** \brief special manager-obj collision for octree */ - bool 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; - - bool 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; - - -}; - -} - -#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase.h b/trunk/fcl/include/fcl/broadphase/broadphase.h new file mode 100644 index 0000000000000000000000000000000000000000..445deaac68f7ecb1fbc8ab76326debf127a064ed --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase.h @@ -0,0 +1,160 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + + + +#ifndef FCL_BROAD_PHASE_H +#define FCL_BROAD_PHASE_H + +#include "fcl/collision_object.h" +#include <set> +#include <vector> + +namespace fcl +{ + + +/// @brief Callback for collision between two objects. Return value is whether can stop now. +typedef bool (*CollisionCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata); + +/// @brief Callback for distance between two objects, Return value is whether can stop now, also return the minimum distance till now. +typedef bool (*DistanceCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata, FCL_REAL& dist); + + +/// @brief Base class for broad phase collision. It helps to accelerate the collision/distance between N objects. Also support self collision, self distance and collision/distance with another M objects. +class BroadPhaseCollisionManager +{ +public: + BroadPhaseCollisionManager() : enable_tested_set_(false) + { + } + + virtual ~BroadPhaseCollisionManager() {} + + /// @brief add objects to the manager + virtual void registerObjects(const std::vector<CollisionObject*>& other_objs) + { + for(size_t i = 0; i < other_objs.size(); ++i) + registerObject(other_objs[i]); + } + + /// @brief add one object to the manager + virtual void registerObject(CollisionObject* obj) = 0; + + /// @brief remove one object from the manager + virtual void unregisterObject(CollisionObject* obj) = 0; + + /// @brief initialize the manager, related with the specific type of manager + virtual void setup() = 0; + + /// @brief update the condition of manager + virtual void update() = 0; + + /// @brief update the manager by explicitly given the object updated + virtual void update(CollisionObject* updated_obj) + { + update(); + } + + /// @brief update the manager by explicitly given the set of objects update + virtual void update(const std::vector<CollisionObject*>& updated_objs) + { + update(); + } + + /// @brief clear the manager + virtual void clear() = 0; + + /// @brief return the objects managed by the manager + virtual void getObjects(std::vector<CollisionObject*>& objs) const = 0; + + /// @brief perform collision test between one object and all the objects belonging to the manager + virtual void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const = 0; + + /// @brief perform distance computation between one object and all the objects belonging to the manager + virtual void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const = 0; + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + virtual void collide(void* cdata, CollisionCallBack callback) const = 0; + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + virtual void distance(void* cdata, DistanceCallBack callback) const = 0; + + /// @brief perform collision test with objects belonging to another manager + virtual void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const = 0; + + /// @brief perform distance test with objects belonging to another manager + virtual void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const = 0; + + /// @brief whether the manager is empty + virtual bool empty() const = 0; + + /// @brief the number of objects managed by the manager + virtual size_t size() const = 0; + +protected: + + /// @brief tools help to avoid repeating collision or distance callback for the pairs of objects tested before. It can be useful for some of the broadphase algorithms. + mutable std::set<std::pair<CollisionObject*, CollisionObject*> > tested_set; + mutable bool enable_tested_set_; + + bool inTestedSet(CollisionObject* a, CollisionObject* b) const + { + if(a < b) return tested_set.find(std::make_pair(a, b)) != tested_set.end(); + else return tested_set.find(std::make_pair(b, a)) != tested_set.end(); + } + + void insertTestedSet(CollisionObject* a, CollisionObject* b) const + { + if(a < b) tested_set.insert(std::make_pair(a, b)); + else tested_set.insert(std::make_pair(b, a)); + } + +}; + + +} + + +#include "fcl/broadphase/broadphase_bruteforce.h" +#include "fcl/broadphase/broadphase_spatialhash.h" +#include "fcl/broadphase/broadphase_SaP.h" +#include "fcl/broadphase/broadphase_SSaP.h" +#include "fcl/broadphase/broadphase_interval_tree.h" +#include "fcl/broadphase/broadphase_dynamic_AABB_tree.h" +#include "fcl/broadphase/broadphase_dynamic_AABB_tree_array.h" + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_SSaP.h b/trunk/fcl/include/fcl/broadphase/broadphase_SSaP.h new file mode 100644 index 0000000000000000000000000000000000000000..d72f6a81d675ebdfb2327053fca9c67ffddd3443 --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_SSaP.h @@ -0,0 +1,157 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + + +#ifndef FCL_BROAD_PHASE_SSAP_H +#define FCL_BROAD_PHASE_SSAP_H + +#include "fcl/broadphase/broadphase.h" + +namespace fcl +{ + +/// @brief Simple SAP collision manager +class SSaPCollisionManager : public BroadPhaseCollisionManager +{ +public: + SSaPCollisionManager() : setup_(false) + {} + + /// @brief remove one object from the manager + void registerObject(CollisionObject* obj); + + /// @brief add one object to the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief clear the manager + void clear(); + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const; + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance computation between one object and all the objects belonging to the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; + + /// @brief whether the manager is empty + bool empty() const; + + /// @brief the number of objects managed by the manager + inline size_t size() const { return objs_x.size(); } + +protected: + /// @brief check collision between one object and a list of objects, return value is whether stop is possible + bool checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, + CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief check distance between one object and a list of objects, return value is whether stop is possible + bool checkDis(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, + CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + static inline size_t selectOptimalAxis(const std::vector<CollisionObject*>& objs_x, const std::vector<CollisionObject*>& objs_y, const std::vector<CollisionObject*>& objs_z, std::vector<CollisionObject*>::const_iterator& it_beg, std::vector<CollisionObject*>::const_iterator& it_end) + { + /// simple sweep and prune method + double delta_x = (objs_x[objs_x.size() - 1])->getAABB().min_[0] - (objs_x[0])->getAABB().min_[0]; + double delta_y = (objs_x[objs_y.size() - 1])->getAABB().min_[1] - (objs_y[0])->getAABB().min_[1]; + double delta_z = (objs_z[objs_z.size() - 1])->getAABB().min_[2] - (objs_z[0])->getAABB().min_[2]; + + int axis = 0; + if(delta_y > delta_x && delta_y > delta_z) + axis = 1; + else if(delta_z > delta_y && delta_z > delta_x) + axis = 2; + + switch(axis) + { + case 0: + it_beg = objs_x.begin(); + it_end = objs_x.end(); + break; + case 1: + it_beg = objs_y.begin(); + it_end = objs_y.end(); + break; + case 2: + it_beg = objs_z.begin(); + it_end = objs_z.end(); + break; + } + + return axis; + } + + + /// @brief Objects sorted according to lower x value + std::vector<CollisionObject*> objs_x; + + /// @brief Objects sorted according to lower y value + std::vector<CollisionObject*> objs_y; + + /// @brief Objects sorted according to lower z value + std::vector<CollisionObject*> objs_z; + + /// @brief tag about whether the environment is maintained suitably (i.e., the objs_x, objs_y, objs_z are sorted correctly + bool setup_; +}; + + +} + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_SaP.h b/trunk/fcl/include/fcl/broadphase/broadphase_SaP.h new file mode 100644 index 0000000000000000000000000000000000000000..165fbd57ce956519de841b18209e30cb600ab23e --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_SaP.h @@ -0,0 +1,316 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#ifndef FCL_BROAD_PHASE_SAP_H +#define FCL_BROAD_PHASE_SAP_H + +#include "fcl/broadphase/broadphase.h" + +#include <map> +#include <list> + +namespace fcl +{ + +/// @brief Rigorous SAP collision manager +class SaPCollisionManager : public BroadPhaseCollisionManager +{ +public: + + SaPCollisionManager() + { + elist[0] = NULL; + elist[1] = NULL; + elist[2] = NULL; + + optimal_axis = 0; + } + + ~SaPCollisionManager() + { + clear(); + } + + /// @brief add objects to the manager + void registerObjects(const std::vector<CollisionObject*>& other_objs); + + /// @brief remove one object from the manager + void registerObject(CollisionObject* obj); + + /// @brief add one object to the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief update the manager by explicitly given the object updated + void update(CollisionObject* updated_obj); + + /// @brief update the manager by explicitly given the set of objects update + void update(const std::vector<CollisionObject*>& updated_objs); + + /// @brief clear the manager + void clear(); + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const; + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance computation between one object and all the objects belonging to the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; + + /// @brief whether the manager is empty + bool empty() const; + + /// @brief the number of objects managed by the manager + inline size_t size() const { return AABB_arr.size(); } + +protected: + + struct EndPoint; + + /// @brief SAP interval for one object + struct SaPAABB + { + /// @brief object + CollisionObject* obj; + + /// @brief lower bound end point of the interval + EndPoint* lo; + + /// @brief higher bound end point of the interval + EndPoint* hi; + + /// @brief cached AABB value + AABB cached; + }; + + /// @brief End point for an interval + struct EndPoint + { + /// @brief tag for whether it is a lower bound or higher bound of an interval, 0 for lo, and 1 for hi + char minmax; + + /// @brief back pointer to SAP interval + SaPAABB* aabb; + + /// @brief the previous end point in the end point list + EndPoint* prev[3]; + /// @brief the next end point in the end point list + EndPoint* next[3]; + + /// @brief get the value of the end point + inline const Vec3f& getVal() const + { + if(minmax) return aabb->cached.max_; + else return aabb->cached.min_; + } + + /// @brief set the value of the end point + inline Vec3f& getVal() + { + if(minmax) return aabb->cached.max_; + else return aabb->cached.min_; + } + + inline FCL_REAL getVal(size_t i) const + { + if(minmax) return aabb->cached.max_[i]; + else return aabb->cached.min_[i]; + } + + inline FCL_REAL& getVal(size_t i) + { + if(minmax) return aabb->cached.max_[i]; + else return aabb->cached.min_[i]; + } + + }; + + /// @brief A pair of objects that are not culling away and should further check collision + struct SaPPair + { + SaPPair(CollisionObject* a, CollisionObject* b) + { + if(a < b) + { + obj1 = a; + obj2 = b; + } + else + { + obj1 = b; + obj2 = a; + } + } + + CollisionObject* obj1; + CollisionObject* obj2; + + bool operator == (const SaPPair& other) const + { + return ((obj1 == other.obj1) && (obj2 == other.obj2)); + } + }; + + /// @brief Functor to help unregister one object + class isUnregistered + { + CollisionObject* obj; + + public: + isUnregistered(CollisionObject* obj_) : obj(obj_) + {} + + bool operator() (const SaPPair& pair) const + { + return (pair.obj1 == obj) || (pair.obj2 == obj); + } + }; + + /// @brief Functor to help remove collision pairs no longer valid (i.e., should be culled away) + class isNotValidPair + { + CollisionObject* obj1; + CollisionObject* obj2; + + public: + isNotValidPair(CollisionObject* obj1_, CollisionObject* obj2_) : obj1(obj1_), + obj2(obj2_) + {} + + bool operator() (const SaPPair& pair) + { + return (pair.obj1 == obj1) && (pair.obj2 == obj2); + } + }; + + void update_(SaPAABB* updated_aabb); + + void updateVelist() + { + for(int coord = 0; coord < 3; ++coord) + { + velist[coord].resize(size() * 2); + EndPoint* current = elist[coord]; + size_t id = 0; + while(current) + { + velist[coord][id] = current; + current = current->next[coord]; + id++; + } + } + } + + /// @brief End point list for x, y, z coordinates + EndPoint* elist[3]; + + /// @brief vector version of elist, for acceleration + std::vector<EndPoint*> velist[3]; + + /// @brief SAP interval list + std::list<SaPAABB*> AABB_arr; + + /// @brief The pair of objects that should further check for collision + std::list<SaPPair> overlap_pairs; + + size_t optimal_axis; + + std::map<CollisionObject*, SaPAABB*> obj_aabb_map; + + bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + void addToOverlapPairs(const SaPPair& p) + { + bool repeated = false; + for(std::list<SaPPair>::iterator it = overlap_pairs.begin(), end = overlap_pairs.end(); + it != end; + ++it) + { + if(*it == p) + { + repeated = true; + break; + } + } + + if(!repeated) + overlap_pairs.push_back(p); + } + + void removeFromOverlapPairs(const SaPPair& p) + { + for(std::list<SaPPair>::iterator it = overlap_pairs.begin(), end = overlap_pairs.end(); + it != end; + ++it) + { + if(*it == p) + { + overlap_pairs.erase(it); + break; + } + } + + // or overlap_pairs.remove_if(isNotValidPair(p)); + } +}; + + + +} + + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_bruteforce.h b/trunk/fcl/include/fcl/broadphase/broadphase_bruteforce.h new file mode 100644 index 0000000000000000000000000000000000000000..1b27ad88f753ee3bb19ff0def51770b5b4733d3d --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_bruteforce.h @@ -0,0 +1,107 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#ifndef FCL_BROAD_PHASE_BRUTE_FORCE_H +#define FCL_BROAD_PHASE_BRUTE_FORCE_H + +#include "fcl/broadphase/broadphase.h" +#include <list> + + +namespace fcl +{ + +/// @brief Brute force N-body collision manager +class NaiveCollisionManager : public BroadPhaseCollisionManager +{ +public: + NaiveCollisionManager() {} + + /// @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); + + /// @brief remove one object from the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief clear the manager + void clear(); + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const; + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance computation between one object and all the objects belonging to the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; + + /// @brief whether the manager is empty + bool empty() const; + + /// @brief the number of objects managed by the manager + inline size_t size() const { return objs.size(); } + +protected: + + /// @brief objects belonging to the manager are stored in a list structure + std::list<CollisionObject*> objs; +}; + + +} + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_dynamic_AABB_tree.h b/trunk/fcl/include/fcl/broadphase/broadphase_dynamic_AABB_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..db8b49a04045d2843a0bc2ffbb3b7f147c87b9b8 --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_dynamic_AABB_tree.h @@ -0,0 +1,243 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + + +#ifndef FCL_BROAD_PHASE_DYNAMIC_AABB_TREE_H +#define FCL_BROAD_PHASE_DYNAMIC_AABB_TREE_H + +#include "fcl/broadphase/broadphase.h" +#include "fcl/broadphase/hierarchy_tree.h" +#include "fcl/octree.h" +#include "fcl/BV.h" +#include "fcl/geometric_shapes_utility.h" +#include <boost/unordered_map.hpp> +#include <boost/bind.hpp> +#include <limits> + + +namespace fcl +{ + +class DynamicAABBTreeCollisionManager : public BroadPhaseCollisionManager +{ +public: + typedef NodeBase<AABB> DynamicAABBNode; + typedef boost::unordered_map<CollisionObject*, DynamicAABBNode*> DynamicAABBTable; + + int max_tree_nonbalanced_level; + int tree_incremental_balance_pass; + int& tree_topdown_balance_threshold; + int& tree_topdown_level; + int tree_init_level; + + bool octree_as_geometry_collide; + bool octree_as_geometry_distance; + + + DynamicAABBTreeCollisionManager() : tree_topdown_balance_threshold(dtree.bu_threshold), + tree_topdown_level(dtree.topdown_level) + { + max_tree_nonbalanced_level = 10; + tree_incremental_balance_pass = 10; + tree_topdown_balance_threshold = 2; + tree_topdown_level = 0; + tree_init_level = 0; + setup_ = false; + + // from experiment, this is the optimal setting + octree_as_geometry_collide = true; + octree_as_geometry_distance = 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); + + /// @brief remove one object from the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief update the manager by explicitly given the object updated + void update(CollisionObject* updated_obj); + + /// @brief update the manager by explicitly given the set of objects update + void update(const std::vector<CollisionObject*>& updated_objs); + + /// @brief clear the manager + void clear() + { + dtree.clear(); + table.clear(); + } + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const + { + objs.resize(this->size()); + std::transform(table.begin(), table.end(), objs.begin(), boost::bind(&DynamicAABBTable::value_type::first, _1)); + } + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const + { + if(size() == 0) return; + switch(obj->getCollisionGeometry()->getNodeType()) + { + case GEOM_OCTREE: + { + if(!octree_as_geometry_collide) + { + const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); + collisionRecurse(dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback); + } + else + collisionRecurse(dtree.getRoot(), obj, cdata, callback); + } + break; + default: + collisionRecurse(dtree.getRoot(), obj, cdata, callback); + } + } + + /// @brief perform distance computation between one object and all the objects belonging to the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const + { + if(size() == 0) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + switch(obj->getCollisionGeometry()->getNodeType()) + { + case GEOM_OCTREE: + { + if(!octree_as_geometry_distance) + { + const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); + distanceRecurse(dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback, min_dist); + } + else + distanceRecurse(dtree.getRoot(), obj, cdata, callback, min_dist); + } + break; + default: + distanceRecurse(dtree.getRoot(), obj, cdata, callback, min_dist); + } + } + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const + { + if(size() == 0) return; + selfCollisionRecurse(dtree.getRoot(), cdata, callback); + } + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const + { + if(size() == 0) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + selfDistanceRecurse(dtree.getRoot(), cdata, callback, min_dist); + } + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const + { + DynamicAABBTreeCollisionManager* other_manager = static_cast<DynamicAABBTreeCollisionManager*>(other_manager_); + if((size() == 0) || (other_manager->size() == 0)) return; + collisionRecurse(dtree.getRoot(), other_manager->dtree.getRoot(), cdata, callback); + } + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const + { + DynamicAABBTreeCollisionManager* other_manager = static_cast<DynamicAABBTreeCollisionManager*>(other_manager_); + if((size() == 0) || (other_manager->size() == 0)) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + distanceRecurse(dtree.getRoot(), other_manager->dtree.getRoot(), cdata, callback, min_dist); + } + + /// @brief whether the manager is empty + bool empty() const + { + return dtree.empty(); + } + + /// @brief the number of objects managed by the manager + size_t size() const + { + return dtree.size(); + } + + const HierarchyTree<AABB>& getTree() const { return dtree; } + + +private: + HierarchyTree<AABB> dtree; + boost::unordered_map<CollisionObject*, DynamicAABBNode*> table; + + bool setup_; + + bool collisionRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, CollisionCallBack callback) const; + + bool collisionRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, CollisionCallBack callback) const; + + bool selfCollisionRecurse(DynamicAABBNode* root, void* cdata, CollisionCallBack callback) const; + + bool distanceRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool distanceRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool selfDistanceRecurse(DynamicAABBNode* root, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + void update_(CollisionObject* updated_obj); + + /// @brief special manager-obj collision for octree + bool collisionRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) const; + + bool distanceRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + +}; + + + +} + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_dynamic_AABB_tree_array.h b/trunk/fcl/include/fcl/broadphase/broadphase_dynamic_AABB_tree_array.h new file mode 100644 index 0000000000000000000000000000000000000000..de146fe2e2730253fa57adfccd5e56c6f4c4f194 --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_dynamic_AABB_tree_array.h @@ -0,0 +1,241 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#ifndef FCL_BROAD_PHASE_DYNAMIC_AABB_TREE_ARRAY_H +#define FCL_BROAD_PHASE_DYNAMIC_AABB_TREE_ARRAY_H + +#include "fcl/broadphase/broadphase.h" +#include "fcl/broadphase/hierarchy_tree.h" +#include "fcl/octree.h" +#include "fcl/BV.h" +#include "fcl/geometric_shapes_utility.h" +#include <boost/unordered_map.hpp> +#include <boost/bind.hpp> +#include <limits> + + +namespace fcl +{ + +class DynamicAABBTreeCollisionManager_Array : public BroadPhaseCollisionManager +{ +public: + typedef implementation_array::NodeBase<AABB> DynamicAABBNode; + typedef boost::unordered_map<CollisionObject*, size_t> DynamicAABBTable; + + int max_tree_nonbalanced_level; + int tree_incremental_balance_pass; + int& tree_topdown_balance_threshold; + int& tree_topdown_level; + int tree_init_level; + + bool octree_as_geometry_collide; + bool octree_as_geometry_distance; + + DynamicAABBTreeCollisionManager_Array() : tree_topdown_balance_threshold(dtree.bu_threshold), + tree_topdown_level(dtree.topdown_level) + { + max_tree_nonbalanced_level = 10; + tree_incremental_balance_pass = 10; + tree_topdown_balance_threshold = 2; + tree_topdown_level = 0; + tree_init_level = 0; + setup_ = false; + + // from experiment, this is the optimal setting + octree_as_geometry_collide = true; + octree_as_geometry_distance = 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); + + /// @brief remove one object from the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief update the manager by explicitly given the object updated + void update(CollisionObject* updated_obj); + + /// @brief update the manager by explicitly given the set of objects update + void update(const std::vector<CollisionObject*>& updated_objs); + + /// @brief clear the manager + void clear() + { + dtree.clear(); + table.clear(); + } + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const + { + objs.resize(this->size()); + std::transform(table.begin(), table.end(), objs.begin(), boost::bind(&DynamicAABBTable::value_type::first, _1)); + } + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const + { + if(size() == 0) return; + switch(obj->getCollisionGeometry()->getNodeType()) + { + case GEOM_OCTREE: + { + if(!octree_as_geometry_collide) + { + const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); + collisionRecurse(dtree.getNodes(), dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback); + } + else + collisionRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback); + } + break; + default: + collisionRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback); + } + } + + /// @brief perform distance computation between one object and all the objects belonging to the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const + { + if(size() == 0) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + switch(obj->getCollisionGeometry()->getNodeType()) + { + case GEOM_OCTREE: + { + if(!octree_as_geometry_distance) + { + const OcTree* octree = static_cast<const OcTree*>(obj->getCollisionGeometry()); + distanceRecurse(dtree.getNodes(), dtree.getRoot(), octree, octree->getRoot(), octree->getRootBV(), obj->getTransform(), cdata, callback, min_dist); + } + else + distanceRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback, min_dist); + } + break; + default: + distanceRecurse(dtree.getNodes(), dtree.getRoot(), obj, cdata, callback, min_dist); + } + } + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const + { + if(size() == 0) return; + selfCollisionRecurse(dtree.getNodes(), dtree.getRoot(), cdata, callback); + } + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const + { + if(size() == 0) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + selfDistanceRecurse(dtree.getNodes(), dtree.getRoot(), cdata, callback, min_dist); + } + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const + { + DynamicAABBTreeCollisionManager_Array* other_manager = static_cast<DynamicAABBTreeCollisionManager_Array*>(other_manager_); + if((size() == 0) || (other_manager->size() == 0)) return; + collisionRecurse(dtree.getNodes(), dtree.getRoot(), other_manager->dtree.getNodes(), other_manager->dtree.getRoot(), cdata, callback); + } + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const + { + DynamicAABBTreeCollisionManager_Array* other_manager = static_cast<DynamicAABBTreeCollisionManager_Array*>(other_manager_); + if((size() == 0) || (other_manager->size() == 0)) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + distanceRecurse(dtree.getNodes(), dtree.getRoot(), other_manager->dtree.getNodes(), other_manager->dtree.getRoot(), cdata, callback, min_dist); + } + + /// @brief whether the manager is empty + bool empty() const + { + return dtree.empty(); + } + + /// @brief the number of objects managed by the manager + size_t size() const + { + return dtree.size(); + } + + + const implementation_array::HierarchyTree<AABB>& getTree() const { return dtree; } + +private: + implementation_array::HierarchyTree<AABB> dtree; + boost::unordered_map<CollisionObject*, size_t> table; + + bool setup_; + + bool collisionRecurse(DynamicAABBNode* nodes1, size_t root1, DynamicAABBNode* nodes2, size_t root2, void* cdata, CollisionCallBack callback) const; + + bool collisionRecurse(DynamicAABBNode* nodes, size_t root, CollisionObject* query, void* cdata, CollisionCallBack callback) const; + + bool selfCollisionRecurse(DynamicAABBNode* nodes, size_t root, void* cdata, CollisionCallBack callback) const; + + bool distanceRecurse(DynamicAABBNode* nodes1, size_t root1, DynamicAABBNode* nodes2, size_t root2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool distanceRecurse(DynamicAABBNode* nodes, size_t root, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool selfDistanceRecurse(DynamicAABBNode* nodes, size_t root, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + void update_(CollisionObject* updated_obj); + + /// @brief special manager-obj collision for octree + bool 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; + + bool 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; + + +}; + + +} + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_interval_tree.h b/trunk/fcl/include/fcl/broadphase/broadphase_interval_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..ba16940b58beafa8377b138466213fbf509ec2bd --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_interval_tree.h @@ -0,0 +1,163 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#ifndef FCL_BROAD_PHASE_INTERVAL_TREE_H +#define FCL_BROAD_PHASE_INTERVAL_TREE_H + +#include "fcl/broadphase/broadphase.h" +#include "fcl/broadphase/interval_tree.h" +#include <deque> +#include <map> + +namespace fcl +{ + +/// @brief Collision manager based on interval tree +class IntervalTreeCollisionManager : public BroadPhaseCollisionManager +{ +public: + IntervalTreeCollisionManager() : setup_(false) + { + for(int i = 0; i < 3; ++i) + interval_trees[i] = NULL; + } + + ~IntervalTreeCollisionManager() + { + clear(); + } + + /// @brief remove one object from the manager + void registerObject(CollisionObject* obj); + + /// @brief add one object to the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief update the manager by explicitly given the object updated + void update(CollisionObject* updated_obj); + + /// @brief update the manager by explicitly given the set of objects update + void update(const std::vector<CollisionObject*>& updated_objs); + + /// @brief clear the manager + void clear(); + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const; + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance computation between one object and all the objects belonging to the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; + + /// @brief whether the manager is empty + bool empty() const; + + /// @brief the number of objects managed by the manager + inline size_t size() const { return endpoints[0].size() / 2; } + +protected: + + + /// @brief SAP end point + struct EndPoint + { + /// @brief object related with the end point + CollisionObject* obj; + + /// @brief end point value + FCL_REAL value; + + /// @brief tag for whether it is a lower bound or higher bound of an interval, 0 for lo, and 1 for hi + char minmax; + }; + + /// @brief Extention interval tree's interval to SAP interval, adding more information + struct SAPInterval : public SimpleInterval + { + CollisionObject* obj; + SAPInterval(double low_, double high_, CollisionObject* obj_) : SimpleInterval() + { + low = low_; + high = high_; + obj = obj_; + } + }; + + + bool checkColl(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + bool checkDist(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + /// @brief vector stores all the end points + std::vector<EndPoint> endpoints[3]; + + /// @brief interval tree manages the intervals + IntervalTree* interval_trees[3]; + + std::map<CollisionObject*, SAPInterval*> obj_interval_maps[3]; + + /// @brief tag for whether the interval tree is maintained suitably + bool setup_; +}; + + +} + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_spatialhash.h b/trunk/fcl/include/fcl/broadphase/broadphase_spatialhash.h new file mode 100644 index 0000000000000000000000000000000000000000..48ed2c3157457a5f98615f8d37a610a717e4628b --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_spatialhash.h @@ -0,0 +1,198 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#ifndef FCL_BROAD_PHASE_SPATIAL_HASH_H +#define FCL_BROAD_PHASE_SPATIAL_HASH_H + +#include "fcl/broadphase/broadphase.h" +#include "fcl/broadphase/hash.h" +#include "fcl/BV/AABB.h" +#include <list> +#include <map> + +namespace fcl +{ + +/// @brief Spatial hash function: hash an AABB to a set of integer values +struct SpatialHash +{ + SpatialHash(const AABB& scene_limit_, FCL_REAL cell_size_) : cell_size(cell_size_), + scene_limit(scene_limit_) + { + width[0] = std::ceil(scene_limit.width() / cell_size); + width[1] = std::ceil(scene_limit.height() / cell_size); + width[2] = std::ceil(scene_limit.depth() / cell_size); + } + + std::vector<unsigned int> operator() (const AABB& aabb) const + { + int min_x = std::floor((aabb.min_[0] - scene_limit.min_[0]) / cell_size); + int max_x = std::ceil((aabb.max_[0] - scene_limit.min_[0]) / cell_size); + int min_y = std::floor((aabb.min_[1] - scene_limit.min_[1]) / cell_size); + int max_y = std::ceil((aabb.max_[1] - scene_limit.min_[1]) / cell_size); + int min_z = std::floor((aabb.min_[2] - scene_limit.min_[2]) / cell_size); + int max_z = std::ceil((aabb.max_[2] - scene_limit.min_[2]) / cell_size); + + std::vector<unsigned int> keys((max_x - min_x) * (max_y - min_y) * (max_z - min_z)); + int id = 0; + for(int x = min_x; x < max_x; ++x) + { + for(int y = min_y; y < max_y; ++y) + { + for(int z = min_z; z < max_z; ++z) + { + keys[id++] = x + y * width[0] + z * width[0] * width[1]; + } + } + } + return keys; + } + +private: + + FCL_REAL cell_size; + AABB scene_limit; + unsigned int width[3]; +}; + +/// @brief spatial hashing collision mananger +template<typename HashTable = SimpleHashTable<AABB, CollisionObject*, SpatialHash> > +class SpatialHashingCollisionManager : public BroadPhaseCollisionManager +{ +public: + SpatialHashingCollisionManager(FCL_REAL cell_size, const Vec3f& scene_min, const Vec3f& scene_max, unsigned int default_table_size = 1000) : scene_limit(AABB(scene_min, scene_max)), + hash_table(new HashTable(SpatialHash(scene_limit, cell_size))) + { + hash_table->init(default_table_size); + } + + ~SpatialHashingCollisionManager() + { + delete hash_table; + } + + /// @brief add one object to the manager + void registerObject(CollisionObject* obj); + + /// @brief remove one object from the manager + void unregisterObject(CollisionObject* obj); + + /// @brief initialize the manager, related with the specific type of manager + void setup(); + + /// @brief update the condition of manager + void update(); + + /// @brief update the manager by explicitly given the object updated + void update(CollisionObject* updated_obj); + + /// @brief update the manager by explicitly given the set of objects update + void update(const std::vector<CollisionObject*>& updated_objs); + + /// @brief clear the manager + void clear(); + + /// @brief return the objects managed by the manager + void getObjects(std::vector<CollisionObject*>& objs) const; + + /// @brief perform collision test between one object and all the objects belonging to the manager + void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance computation between one object and all the objects belonging ot the manager + void distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test for the objects belonging to the manager (i.e, N^2 self collision) + void collide(void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test for the objects belonging to the manager (i.e., N^2 self distance) + void distance(void* cdata, DistanceCallBack callback) const; + + /// @brief perform collision test with objects belonging to another manager + void collide(BroadPhaseCollisionManager* other_manager, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance test with objects belonging to another manager + void distance(BroadPhaseCollisionManager* other_manager, void* cdata, DistanceCallBack callback) const; + + /// @brief whether the manager is empty + bool empty() const; + + /// @brief the number of objects managed by the manager + size_t size() const; + + /// @brief compute the bound for the environent + static void computeBound(std::vector<CollisionObject*>& objs, Vec3f& l, Vec3f& u) + { + AABB bound; + for(unsigned int i = 0; i < objs.size(); ++i) + bound += objs[i]->getAABB(); + + l = bound.min_; + u = bound.max_; + } + +protected: + + /// @brief perform collision test between one object and all the objects belonging to the manager + bool collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const; + + /// @brief perform distance computation between one object and all the objects belonging ot the manager + bool distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const; + + + /// @brief all objects in the scene + std::list<CollisionObject*> objs; + + /// @brief objects outside the scene limit are in another list + std::list<CollisionObject*> objs_outside_scene_limit; + + /// @brief the size of the scene + AABB scene_limit; + + /// @brief store the map between objects and their aabbs. will make update more convenient + std::map<CollisionObject*, AABB> obj_aabb_map; + + /// @brief objects in the scene limit (given by scene_min and scene_max) are in the spatial hash table + HashTable* hash_table; + +}; + + +} + +#include "fcl/broadphase/broadphase_spatialhash.hxx" + + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/broadphase_spatialhash.hxx b/trunk/fcl/include/fcl/broadphase/broadphase_spatialhash.hxx new file mode 100644 index 0000000000000000000000000000000000000000..0a64039402428358096c522f7432642c835740aa --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/broadphase_spatialhash.hxx @@ -0,0 +1,458 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +namespace fcl +{ + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::registerObject(CollisionObject* obj) +{ + objs.push_back(obj); + + const AABB& obj_aabb = obj->getAABB(); + AABB overlap_aabb; + + if(scene_limit.overlap(obj_aabb, overlap_aabb)) + { + if(!scene_limit.contain(obj_aabb)) + objs_outside_scene_limit.push_back(obj); + + hash_table->insert(overlap_aabb, obj); + } + else + objs_outside_scene_limit.push_back(obj); + + obj_aabb_map[obj] = obj_aabb; +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::unregisterObject(CollisionObject* obj) +{ + objs.remove(obj); + + const AABB& obj_aabb = obj->getAABB(); + AABB overlap_aabb; + + if(scene_limit.overlap(obj_aabb, overlap_aabb)) + { + if(!scene_limit.contain(obj_aabb)) + objs_outside_scene_limit.remove(obj); + + hash_table->remove(overlap_aabb, obj); + } + else + objs_outside_scene_limit.remove(obj); + + obj_aabb_map.erase(obj); +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::setup() +{} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::update() +{ + hash_table->clear(); + objs_outside_scene_limit.clear(); + + for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); + it != end; ++it) + { + CollisionObject* obj = *it; + const AABB& obj_aabb = obj->getAABB(); + AABB overlap_aabb; + + if(scene_limit.overlap(obj_aabb, overlap_aabb)) + { + if(!scene_limit.contain(obj_aabb)) + objs_outside_scene_limit.push_back(obj); + + hash_table->insert(overlap_aabb, obj); + } + else + objs_outside_scene_limit.push_back(obj); + + obj_aabb_map[obj] = obj_aabb; + } +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::update(CollisionObject* updated_obj) +{ + const AABB& new_aabb = updated_obj->getAABB(); + const AABB& old_aabb = obj_aabb_map[updated_obj]; + + if(!scene_limit.contain(old_aabb)) // previously not completely in scene limit + { + if(scene_limit.contain(new_aabb)) + { + std::list<CollisionObject*>::iterator find_it = std::find(objs_outside_scene_limit.begin(), + objs_outside_scene_limit.end(), + updated_obj); + + objs_outside_scene_limit.erase(find_it); + } + } + else if(!scene_limit.contain(new_aabb)) // previous completely in scenelimit, now not + objs_outside_scene_limit.push_back(updated_obj); + + AABB old_overlap_aabb; + if(scene_limit.overlap(old_aabb, old_overlap_aabb)) + hash_table->remove(old_overlap_aabb, updated_obj); + + AABB new_overlap_aabb; + if(scene_limit.overlap(new_aabb, new_overlap_aabb)) + hash_table->insert(new_overlap_aabb, updated_obj); + + obj_aabb_map[updated_obj] = new_aabb; +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::update(const std::vector<CollisionObject*>& updated_objs) +{ + for(size_t i = 0; i < updated_objs.size(); ++i) + update(updated_objs[i]); +} + + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::clear() +{ + objs.clear(); + hash_table->clear(); + objs_outside_scene_limit.clear(); + obj_aabb_map.clear(); +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::getObjects(std::vector<CollisionObject*>& objs_) const +{ + objs_.resize(objs.size()); + std::copy(objs.begin(), objs.end(), objs_.begin()); +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + collide_(obj, cdata, callback); +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + distance_(obj, cdata, callback, min_dist); +} + +template<typename HashTable> +bool SpatialHashingCollisionManager<HashTable>::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + const AABB& obj_aabb = obj->getAABB(); + AABB overlap_aabb; + + if(scene_limit.overlap(obj_aabb, overlap_aabb)) + { + if(!scene_limit.contain(obj_aabb)) + { + for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); + it != end; ++it) + { + if(obj == *it) continue; + if(callback(obj, *it, cdata)) return true; + } + } + + std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb); + for(unsigned int i = 0; i < query_result.size(); ++i) + { + if(obj == query_result[i]) continue; + if(callback(obj, query_result[i], cdata)) return true; + } + } + else + { + ; + for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); + it != end; ++it) + { + if(obj == *it) continue; + if(callback(obj, *it, cdata)) return true; + } + } + + return false; +} + +template<typename HashTable> +bool SpatialHashingCollisionManager<HashTable>::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; + AABB aabb = obj->getAABB(); + if(min_dist < std::numeric_limits<FCL_REAL>::max()) + { + Vec3f min_dist_delta(min_dist, min_dist, min_dist); + aabb.expand(min_dist_delta); + } + + AABB overlap_aabb; + + int status = 1; + FCL_REAL old_min_distance; + + while(1) + { + old_min_distance = min_dist; + + if(scene_limit.overlap(aabb, overlap_aabb)) + { + if(!scene_limit.contain(aabb)) + { + for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); + it != end; ++it) + { + if(obj == *it) continue; + if(!enable_tested_set_) + { + if(obj->getAABB().distance((*it)->getAABB()) < min_dist) + if(callback(obj, *it, cdata, min_dist)) return true; + } + else + { + if(!inTestedSet(obj, *it)) + { + if(obj->getAABB().distance((*it)->getAABB()) < min_dist) + if(callback(obj, *it, cdata, min_dist)) return true; + insertTestedSet(obj, *it); + } + } + } + } + + std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb); + for(unsigned int i = 0; i < query_result.size(); ++i) + { + if(obj == query_result[i]) continue; + if(!enable_tested_set_) + { + if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist) + if(callback(obj, query_result[i], cdata, min_dist)) return true; + } + else + { + if(!inTestedSet(obj, query_result[i])) + { + if(obj->getAABB().distance(query_result[i]->getAABB()) < min_dist) + if(callback(obj, query_result[i], cdata, min_dist)) return true; + insertTestedSet(obj, query_result[i]); + } + } + } + } + else + { + for(std::list<CollisionObject*>::const_iterator it = objs_outside_scene_limit.begin(), end = objs_outside_scene_limit.end(); + it != end; ++it) + { + if(obj == *it) continue; + if(!enable_tested_set_) + { + if(obj->getAABB().distance((*it)->getAABB()) < min_dist) + if(callback(obj, *it, cdata, min_dist)) return true; + } + else + { + if(!inTestedSet(obj, *it)) + { + if(obj->getAABB().distance((*it)->getAABB()) < min_dist) + if(callback(obj, *it, cdata, min_dist)) return true; + insertTestedSet(obj, *it); + } + } + } + } + + if(status == 1) + { + if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) + break; + 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; +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::collide(void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end1 = objs.end(); + it1 != end1; ++it1) + { + const AABB& obj_aabb = (*it1)->getAABB(); + AABB overlap_aabb; + + if(scene_limit.overlap(obj_aabb, overlap_aabb)) + { + if(!scene_limit.contain(obj_aabb)) + { + for(std::list<CollisionObject*>::const_iterator it2 = objs_outside_scene_limit.begin(), end2 = objs_outside_scene_limit.end(); + it2 != end2; ++it2) + { + if(*it1 < *it2) { if(callback(*it1, *it2, cdata)) return; } + } + } + + std::vector<CollisionObject*> query_result = hash_table->query(overlap_aabb); + for(unsigned int i = 0; i < query_result.size(); ++i) + { + if(*it1 < query_result[i]) { if(callback(*it1, query_result[i], cdata)) return; } + } + } + else + { + for(std::list<CollisionObject*>::const_iterator it2 = objs_outside_scene_limit.begin(), end2 = objs_outside_scene_limit.end(); + it2 != end2; ++it2) + { + if(*it1 < *it2) { if(callback(*it1, *it2, cdata)) return; } + } + } + } +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::distance(void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + enable_tested_set_ = true; + tested_set.clear(); + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) + if(distance_(*it, cdata, callback, min_dist)) break; + + enable_tested_set_ = false; + tested_set.clear(); +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const +{ + SpatialHashingCollisionManager<HashTable>* other_manager = static_cast<SpatialHashingCollisionManager<HashTable>* >(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + collide(cdata, callback); + return; + } + + if(this->size() < other_manager->size()) + { + for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) + if(other_manager->collide_(*it, cdata, callback)) return; + } + else + { + for(std::list<CollisionObject*>::const_iterator it = other_manager->objs.begin(), end = other_manager->objs.end(); it != end; ++it) + if(collide_(*it, cdata, callback)) return; + } +} + +template<typename HashTable> +void SpatialHashingCollisionManager<HashTable>::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const +{ + SpatialHashingCollisionManager<HashTable>* other_manager = static_cast<SpatialHashingCollisionManager<HashTable>* >(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + distance(cdata, callback); + return; + } + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + if(this->size() < other_manager->size()) + { + for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) + if(other_manager->distance_(*it, cdata, callback, min_dist)) return; + } + else + { + for(std::list<CollisionObject*>::const_iterator it = other_manager->objs.begin(), end = other_manager->objs.end(); it != end; ++it) + if(distance_(*it, cdata, callback, min_dist)) return; + } +} + +template<typename HashTable> +bool SpatialHashingCollisionManager<HashTable>::empty() const +{ + return objs.empty(); +} + +template<typename HashTable> +size_t SpatialHashingCollisionManager<HashTable>::size() const +{ + return objs.size(); +} + +} diff --git a/trunk/fcl/include/fcl/hash.h b/trunk/fcl/include/fcl/broadphase/hash.h similarity index 85% rename from trunk/fcl/include/fcl/hash.h rename to trunk/fcl/include/fcl/broadphase/hash.h index b8b15c84ef0811ce3181aae18715687f79a3e14e..a54aacc3dda2b65301c1e2e6f31f15e11ce3bd99 100644 --- a/trunk/fcl/include/fcl/hash.h +++ b/trunk/fcl/include/fcl/broadphase/hash.h @@ -46,20 +46,25 @@ namespace fcl { -// HashFnc is any extended hash function: HashFnc(key) = {index1, index2, ..., } +/// @brief A simple hash table implemented as multiple buckets. HashFnc is any extended hash function: HashFnc(key) = {index1, index2, ..., } template<typename Key, typename Data, typename HashFnc> class SimpleHashTable { protected: typedef std::list<Data> Bin; + std::vector<Bin> table_; + HashFnc h_; + size_t table_size_; + public: SimpleHashTable(const HashFnc& h) : h_(h) { } + ///@ brief Init the number of bins in the hash table void init(size_t size) { if(size == 0) @@ -71,6 +76,7 @@ public: table_size_ = size; } + //// @brief Insert a key-value pair into the table void insert(Key key, Data value) { std::vector<unsigned int> indices = h_(key); @@ -79,6 +85,7 @@ public: table_[indices[i] % range].push_back(value); } + /// @brief Find the elements in the hash table whose key is the same as query key. std::vector<Data> query(Key key) const { size_t range = table_.size(); @@ -93,6 +100,7 @@ public: return std::vector<Data>(result.begin(), result.end()); } + /// @brief remove the key-value pair from the table void remove(Key key, Data value) { size_t range = table_.size(); @@ -104,6 +112,7 @@ public: } } + /// @brief clear the hash table void clear() { table_.clear(); @@ -115,7 +124,7 @@ public: template<typename U, typename V> class unordered_map_hash_table : public boost::unordered_map<U, V> {}; - +/// @brief A hash table implemented using unordered_map template<typename Key, typename Data, typename HashFnc, template<typename, typename> class TableT = unordered_map_hash_table> class SparseHashTable { @@ -128,8 +137,10 @@ protected: public: SparseHashTable(const HashFnc& h) : h_(h) {} + /// @brief Init the hash table. The bucket size is dynamically decided. void init(size_t) { table_.clear(); } + /// @brief insert one key-value pair into the hash table void insert(Key key, Data value) { std::vector<unsigned int> indices = h_(key); @@ -137,6 +148,7 @@ public: table_[indices[i]].push_back(value); } + /// @brief find the elements whose key is the same as the query std::vector<Data> query(Key key) const { std::vector<unsigned int> indices = h_(key); @@ -152,6 +164,7 @@ public: return std::vector<Data>(result.begin(), result.end()); } + /// @brief remove one key-value pair from the hash table void remove(Key key, Data value) { std::vector<unsigned int> indices = h_(key); @@ -162,6 +175,7 @@ public: } } + /// @brief clear the hash table void clear() { table_.clear(); diff --git a/trunk/fcl/include/fcl/broadphase/hierarchy_tree.h b/trunk/fcl/include/fcl/broadphase/hierarchy_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..2787f1dac34c575666564d1257cc2d2f6352a9c5 --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/hierarchy_tree.h @@ -0,0 +1,593 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#ifndef FCL_HIERARCHY_TREE_H +#define FCL_HIERARCHY_TREE_H + +#include <vector> +#include <map> +#include "fcl/BV/AABB.h" +#include "fcl/vec_3f.h" +#include "fcl/broadphase/morton.h" +#include <boost/bind.hpp> +#include <boost/iterator/zip_iterator.hpp> + +namespace fcl +{ + +/// @brief dynamic AABB tree node +template<typename BV> +struct NodeBase +{ + /// @brief the bounding volume for the node + BV bv; + + /// @brief pointer to parent node + NodeBase<BV>* parent; + + /// @brief whether is a leaf + bool isLeaf() const { return (children[1] == NULL); } + + /// @brief whether is internal node + bool isInternal() const { return !isLeaf(); } + + union + { + /// @brief for leaf node, children nodes + NodeBase<BV>* children[2]; + void* data; + }; + + /// @brief morton code for current BV + FCL_UINT32 code; + + NodeBase() + { + parent = NULL; + children[0] = NULL; + children[1] = NULL; + } +}; + + +/// @brief Compare two nodes accoording to the d-th dimension of node center +template<typename BV> +bool nodeBaseLess(NodeBase<BV>* a, NodeBase<BV>* b, int d) +{ + if(a->bv.center()[d] < b->bv.center()[d]) return true; + return false; +} + +/// @brief select from node1 and node2 which is close to a given query. 0 for node1 and 1 for node2 +template<typename BV> +size_t select(const NodeBase<BV>& query, const NodeBase<BV>& node1, const NodeBase<BV>& node2) +{ + return 0; +} + +template<> +size_t select(const NodeBase<AABB>& node, const NodeBase<AABB>& node1, const NodeBase<AABB>& node2); + +/// @brief select from node1 and node2 which is close to a given query bounding volume. 0 for node1 and 1 for node2 +template<typename BV> +size_t select(const BV& query, const NodeBase<BV>& node1, const NodeBase<BV>& node2) +{ + return 0; +} + +template<> +size_t select(const AABB& query, const NodeBase<AABB>& node1, const NodeBase<AABB>& node2); + + +/// @brief Class for hierarchy tree structure +template<typename BV> +class HierarchyTree +{ + typedef NodeBase<BV> NodeType; + typedef typename std::vector<NodeBase<BV>* >::iterator NodeVecIterator; + typedef typename std::vector<NodeBase<BV>* >::const_iterator NodeVecConstIterator; + + struct SortByMorton + { + bool operator() (NodeType* a, NodeType* b) const + { + return a->code < b->code; + } + }; + +public: + + /// @brief Create hierarchy tree with suitable setting. + /// bu_threshold decides the height of tree node to start bottom-up construction / optimization; + /// topdown_level decides different methods to construct tree in topdown manner. + /// lower level method constructs tree with better quality but is slower. + HierarchyTree(int bu_threshold_ = 16, int topdown_level_ = 0); + + ~HierarchyTree(); + + /// @brief Initialize the tree by a set of leaves using algorithm with a given level. + void init(std::vector<NodeType*>& leaves, int level = 0); + + /// @brief Insest a node + NodeType* insert(const BV& bv, void* data); + + /// @brief Remove a leaf node + void remove(NodeType* leaf); + + /// @brief Clear the tree + void clear(); + + /// @brief Whether the tree is empty + bool empty() const; + + /// @brief update one leaf node + void update(NodeType* leaf, int lookahead_level = -1); + + /// @brief update the tree when the bounding volume of a given leaf has changed + bool update(NodeType* leaf, const BV& bv); + + /// @brief update one leaf's bounding volume, with prediction + bool update(NodeType* leaf, const BV& bv, const Vec3f& vel, FCL_REAL margin); + + /// @brief update one leaf's bounding volume, with prediction + bool update(NodeType* leaf, const BV& bv, const Vec3f& vel); + + /// @brief get the max height of the tree + size_t getMaxHeight() const; + + /// @brief get the max depth of the tree + size_t getMaxDepth() const; + + /// @brief balance the tree from bottom + void balanceBottomup(); + + /// @brief balance the tree from top + void balanceTopdown(); + + /// @brief balance the tree in an incremental way + void balanceIncremental(int iterations); + + /// @brief refit the tree, i.e., when the leaf nodes' bounding volumes change, update the entire tree in a bottom-up manner + void refit(); + + /// @brief extract all the leaves of the tree + void extractLeaves(const NodeType* root, std::vector<NodeType*>& leaves) const; + + /// @brief number of leaves in the tree + size_t size() const; + + /// @brief get the root of the tree + NodeType* getRoot() const; + + NodeType*& getRoot(); + + /// @brief print the tree in a recursive way + void print(NodeType* root, int depth); + +private: + + /// @brief construct a tree for a set of leaves from bottom -- very heavy way + void bottomup(const NodeVecIterator lbeg, const NodeVecIterator lend); + + /// @brief construct a tree for a set of leaves from top + NodeType* topdown(const NodeVecIterator lbeg, const NodeVecIterator lend); + + /// @brief compute the maximum height of a subtree rooted from a given node + size_t getMaxHeight(NodeType* node) const; + + /// @brief compute the maximum depth of a subtree rooted from a given node + void getMaxDepth(NodeType* node, size_t depth, size_t& max_depth) const; + + /// @brief construct a tree from a list of nodes stored in [lbeg, lend) in a topdown manner. + /// During construction, first compute the best split axis as the axis along with the longest AABB edge. + /// Then compute the median of all nodes' center projection onto the axis and using it as the split threshold. + NodeType* topdown_0(const NodeVecIterator lbeg, const NodeVecIterator lend); + + /// @brief construct a tree from a list of nodes stored in [lbeg, lend) in a topdown manner. + /// During construction, first compute the best split thresholds for different axes as the average of all nodes' center. + /// Then choose the split axis as the axis whose threshold can divide the nodes into two parts with almost similar size. + /// This construction is more expensive then topdown_0, but also can provide tree with better quality. + NodeType* topdown_1(const NodeVecIterator lbeg, const NodeVecIterator lend); + + /// @brief init tree from leaves in the topdown manner (topdown_0 or topdown_1) + void init_0(std::vector<NodeType*>& leaves); + + /// @brief init tree from leaves using morton code. It uses morton_0, i.e., for nodes which is of depth more than the maximum bits of the morton code, + /// we use bottomup method to construct the subtree, which is slow but can construct tree with high quality. + void init_1(std::vector<NodeType*>& leaves); + + /// @brief init tree from leaves using morton code. It uses morton_0, i.e., for nodes which is of depth more than the maximum bits of the morton code, + /// we split the leaves into two parts with the same size simply using the node index. + void init_2(std::vector<NodeType*>& leaves); + + /// @brief init tree from leaves using morton code. It uses morton_2, i.e., for all nodes, we simply divide the leaves into parts with the same size simply using the node index. + void init_3(std::vector<NodeType*>& leaves); + + NodeType* mortonRecurse_0(const NodeVecIterator lbeg, const NodeVecIterator lend, const FCL_UINT32& split, int bits); + + NodeType* mortonRecurse_1(const NodeVecIterator lbeg, const NodeVecIterator lend, const FCL_UINT32& split, int bits); + + NodeType* mortonRecurse_2(const NodeVecIterator lbeg, const NodeVecIterator lend); + + /// @brief update one leaf node's bounding volume + void update_(NodeType* leaf, const BV& bv); + + /// @brief sort node n and its parent according to their memory position + NodeType* sort(NodeType* n, NodeType*& r); + + /// @brief Insert a leaf node and also update its ancestors + void insertLeaf(NodeType* root, NodeType* leaf); + + /// @brief Remove a leaf. The leaf node itself is not deleted yet, but all the unnecessary internal nodes are deleted. + /// return the node with the smallest depth and is influenced by the remove operation + NodeType* removeLeaf(NodeType* leaf); + + /// @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); + + static size_t indexOf(NodeType* node); + + /// @brief create one node (leaf or internal) + NodeType* createNode(NodeType* parent, + const BV& bv, + void* data); + + NodeType* createNode(NodeType* parent, + const BV& bv1, + const BV& bv2, + void* data); + + NodeType* createNode(NodeType* parent, + void* data); + + void deleteNode(NodeType* node); + + void recurseDeleteNode(NodeType* node); + + void recurseRefit(NodeType* node); + + static BV bounds(const std::vector<NodeType*>& leaves); + + static BV bounds(const NodeVecIterator lbeg, const NodeVecIterator lend); + +protected: + NodeType* root_node; + + size_t n_leaves; + + unsigned int opath; + + /// This is a one NodeType cache, the reason is that we need to remove a node and then add it again frequently. + NodeType* free_node; + + int max_lookahead_level; + +public: + /// @brief decide which topdown algorithm to use + int topdown_level; + + /// @brief decide the depth to use expensive bottom-up algorithm + int bu_threshold; +}; + + +template<> +bool HierarchyTree<AABB>::update(NodeBase<AABB>* leaf, const AABB& bv_, const Vec3f& vel, FCL_REAL margin); + +template<> +bool HierarchyTree<AABB>::update(NodeBase<AABB>* leaf, const AABB& bv_, const Vec3f& vel); + + +namespace implementation_array +{ + +template<typename BV> +struct NodeBase +{ + BV bv; + + union + { + size_t parent; + size_t next; + }; + + union + { + size_t children[2]; + void* data; + }; + + FCL_UINT32 code; + + bool isLeaf() const { return (children[1] == (size_t)(-1)); } + bool isInternal() const { return !isLeaf(); } +}; + + + +/// @brief Functor comparing two nodes +template<typename BV> +struct nodeBaseLess +{ + nodeBaseLess(const NodeBase<BV>* nodes_, size_t d_) : nodes(nodes_), + d(d_) + {} + + bool operator() (size_t i, size_t j) const + { + if(nodes[i].bv.center()[d] < nodes[j].bv.center()[d]) + return true; + return false; + } + +private: + + /// @brief the nodes array + const NodeBase<BV>* nodes; + + /// @brief the dimension to compare + size_t d; +}; + + +/// @brief select the node from node1 and node2 which is close to the query-th node in the nodes. 0 for node1 and 1 for node2. +template<typename BV> +size_t select(size_t query, size_t node1, size_t node2, NodeBase<BV>* nodes) +{ + return 0; +} + +template<> +size_t select(size_t query, size_t node1, size_t node2, NodeBase<AABB>* nodes); + +/// @brief select the node from node1 and node2 which is close to the query AABB. 0 for node1 and 1 for node2. +template<typename BV> +size_t select(const BV& query, size_t node1, size_t node2, NodeBase<BV>* nodes) +{ + return 0; +} + +template<> +size_t select(const AABB& query, size_t node1, size_t node2, NodeBase<AABB>* nodes); + +/// @brief Class for hierarchy tree structure +template<typename BV> +class HierarchyTree +{ + typedef NodeBase<BV> NodeType; + + struct SortByMorton + { + bool operator() (size_t a, size_t b) const + { + if((a != NULL_NODE) && (b != NULL_NODE)) + return nodes[a].code < nodes[b].code; + else if(a == NULL_NODE) + return split < nodes[b].code; + else if(b == NULL_NODE) + return nodes[a].code < split; + + return false; + } + + NodeType* nodes; + FCL_UINT32 split; + }; + +public: + /// @brief Create hierarchy tree with suitable setting. + /// bu_threshold decides the height of tree node to start bottom-up construction / optimization; + /// topdown_level decides different methods to construct tree in topdown manner. + /// lower level method constructs tree with better quality but is slower. + HierarchyTree(int bu_threshold_ = 16, int topdown_level_ = 0); + + ~HierarchyTree(); + + /// @brief Initialize the tree by a set of leaves using algorithm with a given level. + void init(NodeType* leaves, int n_leaves_, int level = 0); + + /// @brief Initialize the tree by a set of leaves using algorithm with a given level. + size_t insert(const BV& bv, void* data); + + /// @brief Remove a leaf node + void remove(size_t leaf); + + /// @brief Clear the tree + void clear(); + + /// @brief Whether the tree is empty + bool empty() const; + + /// @brief update one leaf node + void update(size_t leaf, int lookahead_level = -1); + + /// @brief update the tree when the bounding volume of a given leaf has changed + bool update(size_t leaf, const BV& bv); + + /// @brief update one leaf's bounding volume, with prediction + bool update(size_t leaf, const BV& bv, const Vec3f& vel, FCL_REAL margin); + + /// @brief update one leaf's bounding volume, with prediction + bool update(size_t leaf, const BV& bv, const Vec3f& vel); + + /// @brief get the max height of the tree + size_t getMaxHeight() const; + + /// @brief get the max depth of the tree + size_t getMaxDepth() const; + + /// @brief balance the tree from bottom + void balanceBottomup(); + + /// @brief balance the tree from top + void balanceTopdown(); + + /// @brief balance the tree in an incremental way + void balanceIncremental(int iterations); + + /// @brief refit the tree, i.e., when the leaf nodes' bounding volumes change, update the entire tree in a bottom-up manner + void refit(); + + /// @brief extract all the leaves of the tree + void extractLeaves(size_t root, NodeType*& leaves) const; + + /// @brief number of leaves in the tree + size_t size() const; + + /// @brief get the root of the tree + size_t getRoot() const; + + /// @brief get the pointer to the nodes array + NodeType* getNodes() const; + + /// @brief print the tree in a recursive way + void print(size_t root, int depth); + +private: + + /// @brief construct a tree for a set of leaves from bottom -- very heavy way + void bottomup(size_t* lbeg, size_t* lend); + + /// @brief construct a tree for a set of leaves from top + size_t topdown(size_t* lbeg, size_t* lend); + + /// @brief compute the maximum height of a subtree rooted from a given node + size_t getMaxHeight(size_t node) const; + + /// @brief compute the maximum depth of a subtree rooted from a given node + void getMaxDepth(size_t node, size_t depth, size_t& max_depth) const; + + /// @brief construct a tree from a list of nodes stored in [lbeg, lend) in a topdown manner. + /// During construction, first compute the best split axis as the axis along with the longest AABB edge. + /// Then compute the median of all nodes' center projection onto the axis and using it as the split threshold. + size_t topdown_0(size_t* lbeg, size_t* lend); + + /// @brief construct a tree from a list of nodes stored in [lbeg, lend) in a topdown manner. + /// During construction, first compute the best split thresholds for different axes as the average of all nodes' center. + /// Then choose the split axis as the axis whose threshold can divide the nodes into two parts with almost similar size. + /// This construction is more expensive then topdown_0, but also can provide tree with better quality. + size_t topdown_1(size_t* lbeg, size_t* lend); + + /// @brief init tree from leaves in the topdown manner (topdown_0 or topdown_1) + void init_0(NodeType* leaves, int n_leaves_); + + /// @brief init tree from leaves using morton code. It uses morton_0, i.e., for nodes which is of depth more than the maximum bits of the morton code, + /// we use bottomup method to construct the subtree, which is slow but can construct tree with high quality. + void init_1(NodeType* leaves, int n_leaves_); + + /// @brief init tree from leaves using morton code. It uses morton_0, i.e., for nodes which is of depth more than the maximum bits of the morton code, + /// we split the leaves into two parts with the same size simply using the node index. + void init_2(NodeType* leaves, int n_leaves_); + + /// @brief init tree from leaves using morton code. It uses morton_2, i.e., for all nodes, we simply divide the leaves into parts with the same size simply using the node index. + void init_3(NodeType* leaves, int n_leaves_); + + size_t mortonRecurse_0(size_t* lbeg, size_t* lend, const FCL_UINT32& split, int bits); + + size_t mortonRecurse_1(size_t* lbeg, size_t* lend, const FCL_UINT32& split, int bits); + + size_t mortonRecurse_2(size_t* lbeg, size_t* lend); + + /// @brief update one leaf node's bounding volume + void update_(size_t leaf, const BV& bv); + + /// @brief Insert a leaf node and also update its ancestors + void insertLeaf(size_t root, size_t leaf); + + /// @brief Remove a leaf. The leaf node itself is not deleted yet, but all the unnecessary internal nodes are deleted. + /// return the node with the smallest depth and is influenced by the remove operation + size_t removeLeaf(size_t leaf); + + /// @brief Delete all internal nodes and return all leaves nodes with given depth from root + void fetchLeaves(size_t root, NodeType*& leaves, int depth = -1); + + size_t indexOf(size_t node); + + size_t allocateNode(); + + /// @brief create one node (leaf or internal) + size_t createNode(size_t parent, + const BV& bv1, + const BV& bv2, + void* data); + + size_t createNode(size_t parent, + const BV& bv, + void* data); + + size_t createNode(size_t parent, + void* data); + + void deleteNode(size_t node); + + void recurseRefit(size_t node); + +protected: + size_t root_node; + NodeType* nodes; + size_t n_nodes; + size_t n_nodes_alloc; + + size_t n_leaves; + size_t freelist; + unsigned int opath; + + int max_lookahead_level; + +public: + /// @brief decide which topdown algorithm to use + int topdown_level; + + /// @brief decide the depth to use expensive bottom-up algorithm + int bu_threshold; + +public: + static const size_t NULL_NODE = -1; +}; + +template<typename BV> +const size_t HierarchyTree<BV>::NULL_NODE; + +} + +} + + +#include "fcl/broadphase/hierarchy_tree.hxx" + + +#endif diff --git a/trunk/fcl/include/fcl/broadphase/hierarchy_tree.hxx b/trunk/fcl/include/fcl/broadphase/hierarchy_tree.hxx new file mode 100644 index 0000000000000000000000000000000000000000..05e01cde22a9bd697f7dfb34919c3b410e8f5c97 --- /dev/null +++ b/trunk/fcl/include/fcl/broadphase/hierarchy_tree.hxx @@ -0,0 +1,1876 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +namespace fcl +{ + +template<typename BV> +HierarchyTree<BV>::HierarchyTree(int bu_threshold_, int topdown_level_) +{ + root_node = NULL; + n_leaves = 0; + free_node = NULL; + max_lookahead_level = -1; + opath = 0; + bu_threshold = bu_threshold_; + topdown_level = topdown_level_; +} + +template<typename BV> +HierarchyTree<BV>::~HierarchyTree() +{ + clear(); +} + +template<typename BV> +void HierarchyTree<BV>::init(std::vector<NodeType*>& leaves, int level) +{ + switch(level) + { + case 0: + init_0(leaves); + break; + case 1: + init_1(leaves); + break; + case 2: + init_2(leaves); + break; + case 3: + init_3(leaves); + break; + default: + init_0(leaves); + } +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::insert(const BV& bv, void* data) +{ + NodeType* leaf = createNode(NULL, bv, data); + insertLeaf(root_node, leaf); + ++n_leaves; + return leaf; +} + +template<typename BV> +void HierarchyTree<BV>::remove(NodeType* leaf) +{ + removeLeaf(leaf); + deleteNode(leaf); + --n_leaves; +} + +template<typename BV> +void HierarchyTree<BV>::clear() +{ + if(root_node) + recurseDeleteNode(root_node); + n_leaves = 0; + delete free_node; + free_node = NULL; + max_lookahead_level = -1; + opath = 0; +} + +template<typename BV> +bool HierarchyTree<BV>::empty() const +{ + return (NULL == root_node); +} + +template<typename BV> +void HierarchyTree<BV>::update(NodeType* leaf, int lookahead_level) +{ + NodeType* root = removeLeaf(leaf); + if(root) + { + if(lookahead_level > 0) + { + for(int i = 0; (i < lookahead_level) && root->parent; ++i) + root = root->parent; + } + else + root = root_node; + } + insertLeaf(root, leaf); +} + +template<typename BV> +bool HierarchyTree<BV>::update(NodeType* leaf, const BV& bv) +{ + if(leaf->bv.contain(bv)) return false; + update_(leaf, bv); + return true; +} + +template<typename BV> +bool HierarchyTree<BV>::update(NodeType* leaf, const BV& bv, const Vec3f& vel, FCL_REAL margin) +{ + if(leaf->bv.contain(bv)) return false; + update_(leaf, bv); + return true; +} + +template<typename BV> +bool HierarchyTree<BV>::update(NodeType* leaf, const BV& bv, const Vec3f& vel) +{ + if(leaf->bv.contain(bv)) return false; + update_(leaf, bv); + return true; +} + +template<typename BV> +size_t HierarchyTree<BV>::getMaxHeight() const +{ + if(!root_node) + return 0; + return getMaxHeight(root_node); +} + +template<typename BV> +size_t HierarchyTree<BV>::getMaxDepth() const +{ + if(!root_node) return 0; + + size_t max_depth; + getMaxDepth(root_node, 0, max_depth); + return max_depth; +} + +template<typename BV> +void HierarchyTree<BV>::balanceBottomup() +{ + if(root_node) + { + std::vector<NodeType*> leaves; + leaves.reserve(n_leaves); + fetchLeaves(root_node, leaves); + bottomup(leaves.begin(), leaves.end()); + root_node = leaves[0]; + } +} + +template<typename BV> +void HierarchyTree<BV>::balanceTopdown() +{ + if(root_node) + { + std::vector<NodeType*> leaves; + leaves.reserve(n_leaves); + fetchLeaves(root_node, leaves); + root_node = topdown(leaves.begin(), leaves.end()); + } +} + +template<typename BV> +void HierarchyTree<BV>::balanceIncremental(int iterations) +{ + if(iterations < 0) iterations = n_leaves; + if(root_node && (iterations > 0)) + { + for(int i = 0; i < iterations; ++i) + { + NodeType* node = root_node; + unsigned int bit = 0; + while(!node->isLeaf()) + { + node = sort(node, root_node)->children[(opath>>bit)&1]; + bit = (bit+1)&(sizeof(unsigned int) * 8-1); + } + update(node); + ++opath; + } + } +} + +template<typename BV> +void HierarchyTree<BV>::refit() +{ + if(root_node) + recurseRefit(root_node); +} + +template<typename BV> +void HierarchyTree<BV>::extractLeaves(const NodeType* root, std::vector<NodeType*>& leaves) const +{ + if(!root->isLeaf()) + { + extractLeaves(root->children[0], leaves); + extractLeaves(root->children[1], leaves); + } + else + leaves.push_back(root); +} + +template<typename BV> +size_t HierarchyTree<BV>::size() const +{ + return n_leaves; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::getRoot() const +{ + return root_node; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType*& HierarchyTree<BV>::getRoot() +{ + return root_node; +} + +template<typename BV> +void HierarchyTree<BV>::print(NodeType* root, int depth) +{ + 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; + if(root->isLeaf()) + { + } + else + { + print(root->children[0], depth+1); + print(root->children[1], depth+1); + } +} + + + +template<typename BV> +void HierarchyTree<BV>::bottomup(const NodeVecIterator lbeg, const NodeVecIterator lend) +{ + NodeVecIterator lcur_end = lend; + while(lbeg < lcur_end - 1) + { + NodeVecIterator min_it1, min_it2; + FCL_REAL min_size = std::numeric_limits<FCL_REAL>::max(); + for(NodeVecIterator it1 = lbeg; it1 < lcur_end; ++it1) + { + for(NodeVecIterator it2 = it1 + 1; it2 < lcur_end; ++it2) + { + FCL_REAL cur_size = ((*it1)->bv + (*it2)->bv).size(); + if(cur_size < min_size) + { + min_size = cur_size; + min_it1 = it1; + min_it2 = it2; + } + } + } + + NodeType* n[2] = {*min_it1, *min_it2}; + NodeType* p = createNode(NULL, n[0]->bv, n[1]->bv, NULL); + p->children[0] = n[0]; + p->children[1] = n[1]; + n[0]->parent = p; + n[1]->parent = p; + *min_it1 = p; + NodeType* tmp = *min_it2; + lcur_end--; + *min_it2 = *lcur_end; + *lcur_end = tmp; + } +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::topdown(const NodeVecIterator lbeg, const NodeVecIterator lend) +{ + switch(topdown_level) + { + case 0: + return topdown_0(lbeg, lend); + break; + case 1: + return topdown_1(lbeg, lend); + break; + default: + return topdown_0(lbeg, lend); + } +} + +template<typename BV> +size_t HierarchyTree<BV>::getMaxHeight(NodeType* node) const +{ + if(!node->isLeaf()) + { + size_t height1 = getMaxHeight(node->children[0]); + size_t height2 = getMaxHeight(node->children[1]); + return std::max(height1, height2) + 1; + } + else + return 0; +} + +template<typename BV> +void HierarchyTree<BV>::getMaxDepth(NodeType* node, size_t depth, size_t& max_depth) const +{ + if(!node->isLeaf()) + { + getMaxDepth(node->children[0], depth+1, max_depth); + getMaxDepth(node->children[1], depth+1, max_depth); + } + else + max_depth = std::max(max_depth, depth); +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::topdown_0(const NodeVecIterator lbeg, const NodeVecIterator lend) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(num_leaves > bu_threshold) + { + BV vol = (*lbeg)->bv; + for(NodeVecIterator it = lbeg + 1; it < lend; ++it) + vol += (*it)->bv; + + int best_axis = 0; + FCL_REAL extent[3] = {vol.width(), vol.height(), vol.depth()}; + if(extent[1] > extent[0]) best_axis = 1; + if(extent[2] > extent[best_axis]) best_axis = 2; + + // compute median + NodeVecIterator lcenter = lbeg + num_leaves / 2; + std::nth_element(lbeg, lcenter, lend, boost::bind(&nodeBaseLess<BV>, _1, _2, boost::ref(best_axis))); + + NodeType* node = createNode(NULL, vol, NULL); + node->children[0] = topdown_0(lbeg, lcenter); + node->children[1] = topdown_0(lcenter, lend); + node->children[0]->parent = node; + node->children[1]->parent = node; + return node; + } + else + { + bottomup(lbeg, lend); + return *lbeg; + } + } + return *lbeg; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::topdown_1(const NodeVecIterator lbeg, const NodeVecIterator lend) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(num_leaves > bu_threshold) + { + Vec3f split_p = (*lbeg)->bv.center(); + BV vol = (*lbeg)->bv; + NodeVecIterator it; + for(it = lbeg + 1; it < lend; ++it) + { + split_p += (*it)->bv.center(); + vol += (*it)->bv; + } + split_p /= (FCL_REAL)(num_leaves); + int best_axis = -1; + int bestmidp = num_leaves; + int splitcount[3][2] = {{0,0}, {0,0}, {0,0}}; + for(it = lbeg; it < lend; ++it) + { + Vec3f x = (*it)->bv.center() - split_p; + for(size_t j = 0; j < 3; ++j) + ++splitcount[j][x[j] > 0 ? 1 : 0]; + } + + for(size_t i = 0; i < 3; ++i) + { + if((splitcount[i][0] > 0) && (splitcount[i][1] > 0)) + { + int midp = std::abs(splitcount[i][0] - splitcount[i][1]); + if(midp < bestmidp) + { + best_axis = i; + bestmidp = midp; + } + } + } + + if(best_axis < 0) best_axis = 0; + + FCL_REAL split_value = split_p[best_axis]; + NodeVecIterator lcenter = lbeg; + for(it = lbeg; it < lend; ++it) + { + if((*it)->bv.center()[best_axis] < split_value) + { + NodeType* temp = *it; + *it = *lcenter; + *lcenter = temp; + ++lcenter; + } + } + + NodeType* node = createNode(NULL, vol, NULL); + node->children[0] = topdown_1(lbeg, lcenter); + node->children[1] = topdown_1(lcenter, lend); + node->children[0]->parent = node; + node->children[1]->parent = node; + return node; + } + else + { + bottomup(lbeg, lend); + return *lbeg; + } + } + return *lbeg; +} + +template<typename BV> +void HierarchyTree<BV>::init_0(std::vector<NodeType*>& leaves) +{ + clear(); + root_node = topdown(leaves.begin(), leaves.end()); + n_leaves = leaves.size(); + max_lookahead_level = -1; + opath = 0; +} + +template<typename BV> +void HierarchyTree<BV>::init_1(std::vector<NodeType*>& leaves) +{ + clear(); + + BV bound_bv; + if(leaves.size() > 0) + bound_bv = leaves[0]->bv; + for(size_t i = 1; i < leaves.size(); ++i) + bound_bv += leaves[i]->bv; + + morton_functor<FCL_UINT32> coder(bound_bv); + for(size_t i = 0; i < leaves.size(); ++i) + leaves[i]->code = coder(leaves[i]->bv.center()); + + std::sort(leaves.begin(), leaves.end(), SortByMorton()); + + root_node = mortonRecurse_0(leaves.begin(), leaves.end(), (1 << (coder.bits()-1)), coder.bits()-1); + + refit(); + n_leaves = leaves.size(); + max_lookahead_level = -1; + opath = 0; +} + +template<typename BV> +void HierarchyTree<BV>::init_2(std::vector<NodeType*>& leaves) +{ + clear(); + + BV bound_bv; + if(leaves.size() > 0) + bound_bv = leaves[0]->bv; + for(size_t i = 1; i < leaves.size(); ++i) + bound_bv += leaves[i]->bv; + + morton_functor<FCL_UINT32> coder(bound_bv); + for(size_t i = 0; i < leaves.size(); ++i) + leaves[i]->code = coder(leaves[i]->bv.center()); + + std::sort(leaves.begin(), leaves.end(), SortByMorton()); + + root_node = mortonRecurse_1(leaves.begin(), leaves.end(), (1 << (coder.bits()-1)), coder.bits()-1); + + refit(); + n_leaves = leaves.size(); + max_lookahead_level = -1; + opath = 0; +} + +template<typename BV> +void HierarchyTree<BV>::init_3(std::vector<NodeType*>& leaves) +{ + clear(); + + BV bound_bv; + if(leaves.size() > 0) + bound_bv = leaves[0]->bv; + for(size_t i = 1; i < leaves.size(); ++i) + bound_bv += leaves[i]->bv; + + morton_functor<FCL_UINT32> coder(bound_bv); + for(size_t i = 0; i < leaves.size(); ++i) + leaves[i]->code = coder(leaves[i]->bv.center()); + + std::sort(leaves.begin(), leaves.end(), SortByMorton()); + + root_node = mortonRecurse_2(leaves.begin(), leaves.end()); + + refit(); + n_leaves = leaves.size(); + max_lookahead_level = -1; + opath = 0; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::mortonRecurse_0(const NodeVecIterator lbeg, const NodeVecIterator lend, const FCL_UINT32& split, int bits) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(bits > 0) + { + NodeType dummy; + dummy.code = split; + NodeVecIterator lcenter = std::lower_bound(lbeg, lend, &dummy, SortByMorton()); + + if(lcenter == lbeg) + { + FCL_UINT32 split2 = split | (1 << (bits - 1)); + return mortonRecurse_0(lbeg, lend, split2, bits - 1); + } + else if(lcenter == lend) + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + return mortonRecurse_0(lbeg, lend, split1, bits - 1); + } + else + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + FCL_UINT32 split2 = split | (1 << (bits - 1)); + + NodeType* child1 = mortonRecurse_0(lbeg, lcenter, split1, bits - 1); + NodeType* child2 = mortonRecurse_0(lcenter, lend, split2, bits - 1); + NodeType* node = createNode(NULL, NULL); + node->children[0] = child1; + node->children[1] = child2; + child1->parent = node; + child2->parent = node; + return node; + } + } + else + { + NodeType* node = topdown(lbeg, lend); + return node; + } + } + else + return *lbeg; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::mortonRecurse_1(const NodeVecIterator lbeg, const NodeVecIterator lend, const FCL_UINT32& split, int bits) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(bits > 0) + { + NodeType dummy; + dummy.code = split; + NodeVecIterator lcenter = std::lower_bound(lbeg, lend, &dummy, SortByMorton()); + + if(lcenter == lbeg) + { + FCL_UINT32 split2 = split | (1 << (bits - 1)); + return mortonRecurse_1(lbeg, lend, split2, bits - 1); + } + else if(lcenter == lend) + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + return mortonRecurse_1(lbeg, lend, split1, bits - 1); + } + else + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + FCL_UINT32 split2 = split | (1 << (bits - 1)); + + NodeType* child1 = mortonRecurse_1(lbeg, lcenter, split1, bits - 1); + NodeType* child2 = mortonRecurse_1(lcenter, lend, split2, bits - 1); + NodeType* node = createNode(NULL, NULL); + node->children[0] = child1; + node->children[1] = child2; + child1->parent = node; + child2->parent = node; + return node; + } + } + else + { + NodeType* child1 = mortonRecurse_1(lbeg, lbeg + num_leaves / 2, 0, bits - 1); + NodeType* child2 = mortonRecurse_1(lbeg + num_leaves / 2, lend, 0, bits - 1); + NodeType* node = createNode(NULL, NULL); + node->children[0] = child1; + node->children[1] = child2; + child1->parent = node; + child2->parent = node; + return node; + } + } + else + return *lbeg; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::mortonRecurse_2(const NodeVecIterator lbeg, const NodeVecIterator lend) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + NodeType* child1 = mortonRecurse_2(lbeg, lbeg + num_leaves / 2); + NodeType* child2 = mortonRecurse_2(lbeg + num_leaves / 2, lend); + NodeType* node = createNode(NULL, NULL); + node->children[0] = child1; + node->children[1] = child2; + child1->parent = node; + child2->parent = node; + return node; + } + else + return *lbeg; +} + + +template<typename BV> +void HierarchyTree<BV>::update_(NodeType* leaf, const BV& bv) +{ + NodeType* root = removeLeaf(leaf); + if(root) + { + if(max_lookahead_level >= 0) + { + for(int i = 0; (i < max_lookahead_level) && root->parent; ++i) + root = root->parent; + } + else + root = root_node; + } + + leaf->bv = bv; + insertLeaf(root, leaf); +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::sort(NodeType* n, NodeType*& r) +{ + NodeType* p = n->parent; + if(p > n) + { + int i = indexOf(n); + int j = 1 - i; + NodeType* s = p->children[j]; + NodeType* q = p->parent; + if(q) q->children[indexOf(p)] = n; else r = n; + s->parent = n; + p->parent = n; + n->parent = q; + p->children[0] = n->children[0]; + p->children[1] = n->children[1]; + n->children[0]->parent = p; + n->children[1]->parent = p; + n->children[i] = p; + n->children[j] = s; + std::swap(p->bv, n->bv); + return p; + } + return n; +} + +template<typename BV> +void HierarchyTree<BV>::insertLeaf(NodeType* root, NodeType* leaf) +{ + if(!root_node) + { + root_node = leaf; + leaf->parent = NULL; + } + else + { + if(!root->isLeaf()) + { + do + { + root = root->children[select(*leaf, *(root->children[0]), *(root->children[1]))]; + } + while(!root->isLeaf()); + } + + NodeType* prev = root->parent; + NodeType* node = createNode(prev, leaf->bv, root->bv, NULL); + if(prev) + { + prev->children[indexOf(root)] = node; + node->children[0] = root; root->parent = node; + node->children[1] = leaf; leaf->parent = node; + do + { + if(!prev->bv.contain(node->bv)) + prev->bv = prev->children[0]->bv + prev->children[1]->bv; + else + break; + node = prev; + } while (NULL != (prev = node->parent)); + } + else + { + node->children[0] = root; root->parent = node; + node->children[1] = leaf; leaf->parent = node; + root_node = node; + } + } +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::removeLeaf(NodeType* leaf) +{ + if(leaf == root_node) + { + root_node = NULL; + return NULL; + } + else + { + NodeType* parent = leaf->parent; + NodeType* prev = parent->parent; + NodeType* sibling = parent->children[1-indexOf(leaf)]; + if(prev) + { + prev->children[indexOf(parent)] = sibling; + sibling->parent = prev; + deleteNode(parent); + while(prev) + { + BV new_bv = prev->children[0]->bv + prev->children[1]->bv; + if(!new_bv.equal(prev->bv)) + { + prev->bv = new_bv; + prev = prev->parent; + } + else break; + } + + return prev ? prev : root_node; + } + else + { + root_node = sibling; + sibling->parent = NULL; + deleteNode(parent); + return root_node; + } + } +} + +template<typename BV> +void HierarchyTree<BV>::fetchLeaves(NodeType* root, std::vector<NodeType*>& leaves, int depth) +{ + if((!root->isLeaf()) && depth) + { + fetchLeaves(root->children[0], leaves, depth-1); + fetchLeaves(root->children[1], leaves, depth-1); + deleteNode(root); + } + else + { + leaves.push_back(root); + } +} + + +template<typename BV> +size_t HierarchyTree<BV>::indexOf(NodeType* node) +{ + // node cannot be NULL + return (node->parent->children[1] == node); +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::createNode(NodeType* parent, + const BV& bv, + void* data) +{ + NodeType* node = createNode(parent, data); + node->bv = bv; + return node; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::createNode(NodeType* parent, + const BV& bv1, + const BV& bv2, + void* data) +{ + NodeType* node = createNode(parent, data); + node->bv = bv1 + bv2; + return node; +} + + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::createNode(NodeType* parent, void* data) +{ + NodeType* node = NULL; + if(free_node) + { + node = free_node; + free_node = NULL; + } + else + node = new NodeType(); + node->parent = parent; + node->data = data; + node->children[1] = 0; + return node; +} + +template<typename BV> +void HierarchyTree<BV>::deleteNode(NodeType* node) +{ + if(free_node != node) + { + delete free_node; + free_node = node; + } +} + +template<typename BV> +void HierarchyTree<BV>::recurseDeleteNode(NodeType* node) +{ + if(!node->isLeaf()) + { + recurseDeleteNode(node->children[0]); + recurseDeleteNode(node->children[1]); + } + + if(node == root_node) root_node = NULL; + deleteNode(node); +} + +template<typename BV> +void HierarchyTree<BV>::recurseRefit(NodeType* node) +{ + if(!node->isLeaf()) + { + recurseRefit(node->children[0]); + recurseRefit(node->children[1]); + node->bv = node->children[0]->bv + node->children[1]->bv; + } + else + return; +} + +template<typename BV> +BV HierarchyTree<BV>::bounds(const std::vector<NodeType*>& leaves) +{ + if(leaves.size() == 0) return BV(); + BV bv = leaves[0]->bv; + for(size_t i = 1; i < leaves.size(); ++i) + { + bv += leaves[i]->bv; + } + + return bv; +} + +template<typename BV> +BV HierarchyTree<BV>::bounds(const NodeVecIterator lbeg, const NodeVecIterator lend) +{ + if(lbeg == lend) return BV(); + BV bv = *lbeg; + for(NodeVecIterator it = lbeg + 1; it < lend; ++it) + { + bv += (*it)->bv; + } + + return bv; +} + +} + + +namespace fcl +{ +namespace implementation_array +{ + +template<typename BV> +HierarchyTree<BV>::HierarchyTree(int bu_threshold_, int topdown_level_) +{ + root_node = NULL_NODE; + n_nodes = 0; + n_nodes_alloc = 16; + nodes = new NodeType[n_nodes_alloc]; + for(size_t i = 0; i < n_nodes_alloc - 1; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + n_leaves = 0; + freelist = 0; + opath = 0; + max_lookahead_level = -1; + bu_threshold = bu_threshold_; + topdown_level = topdown_level_; +} + +template<typename BV> +HierarchyTree<BV>::~HierarchyTree() +{ + delete [] nodes; +} + +template<typename BV> +void HierarchyTree<BV>::init(NodeType* leaves, int n_leaves_, int level) +{ + switch(level) + { + case 0: + init_0(leaves, n_leaves_); + break; + case 1: + init_1(leaves, n_leaves_); + break; + case 2: + init_2(leaves, n_leaves_); + break; + case 3: + init_3(leaves, n_leaves_); + break; + default: + init_0(leaves, n_leaves_); + } +} + +template<typename BV> +void HierarchyTree<BV>::init_0(NodeType* leaves, int n_leaves_) +{ + clear(); + + n_leaves = n_leaves_; + root_node = NULL_NODE; + nodes = new NodeType[n_leaves * 2]; + memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); + freelist = n_leaves; + n_nodes = n_leaves; + n_nodes_alloc = 2 * n_leaves; + for(size_t i = n_leaves; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + + size_t* ids = new size_t[n_leaves]; + for(size_t i = 0; i < n_leaves; ++i) + ids[i] = i; + + root_node = topdown(ids, ids + n_leaves); + delete [] ids; + + opath = 0; + max_lookahead_level = -1; +} + +template<typename BV> +void HierarchyTree<BV>::init_1(NodeType* leaves, int n_leaves_) +{ + clear(); + + n_leaves = n_leaves_; + root_node = NULL_NODE; + nodes = new NodeType[n_leaves * 2]; + memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); + freelist = n_leaves; + n_nodes = n_leaves; + n_nodes_alloc = 2 * n_leaves; + for(size_t i = n_leaves; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + + + BV bound_bv; + if(n_leaves > 0) + bound_bv = nodes[0].bv; + for(size_t i = 1; i < n_leaves; ++i) + bound_bv += nodes[i].bv; + + morton_functor<FCL_UINT32> coder(bound_bv); + for(size_t i = 0; i < n_leaves; ++i) + nodes[i].code = coder(nodes[i].bv.center()); + + + size_t* ids = new size_t[n_leaves]; + for(size_t i = 0; i < n_leaves; ++i) + ids[i] = i; + + SortByMorton comp; + comp.nodes = nodes; + std::sort(ids, ids + n_leaves, comp); + root_node = mortonRecurse_0(ids, ids + n_leaves, (1 << coder.bits()-1), coder.bits()-1); + delete [] ids; + + refit(); + + opath = 0; + max_lookahead_level = -1; +} + +template<typename BV> +void HierarchyTree<BV>::init_2(NodeType* leaves, int n_leaves_) +{ + clear(); + + n_leaves = n_leaves_; + root_node = NULL_NODE; + nodes = new NodeType[n_leaves * 2]; + memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); + freelist = n_leaves; + n_nodes = n_leaves; + n_nodes_alloc = 2 * n_leaves; + for(size_t i = n_leaves; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + + + BV bound_bv; + if(n_leaves > 0) + bound_bv = nodes[0].bv; + for(size_t i = 1; i < n_leaves; ++i) + bound_bv += nodes[i].bv; + + morton_functor<FCL_UINT32> coder(bound_bv); + for(size_t i = 0; i < n_leaves; ++i) + nodes[i].code = coder(nodes[i].bv.center()); + + + size_t* ids = new size_t[n_leaves]; + for(size_t i = 0; i < n_leaves; ++i) + ids[i] = i; + + SortByMorton comp; + comp.nodes = nodes; + std::sort(ids, ids + n_leaves, comp); + root_node = mortonRecurse_1(ids, ids + n_leaves, (1 << coder.bits()-1), coder.bits()-1); + delete [] ids; + + refit(); + + opath = 0; + max_lookahead_level = -1; +} + +template<typename BV> +void HierarchyTree<BV>::init_3(NodeType* leaves, int n_leaves_) +{ + clear(); + + n_leaves = n_leaves_; + root_node = NULL_NODE; + nodes = new NodeType[n_leaves * 2]; + memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); + freelist = n_leaves; + n_nodes = n_leaves; + n_nodes_alloc = 2 * n_leaves; + for(size_t i = n_leaves; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + + + BV bound_bv; + if(n_leaves > 0) + bound_bv = nodes[0].bv; + for(size_t i = 1; i < n_leaves; ++i) + bound_bv += nodes[i].bv; + + morton_functor<FCL_UINT32> coder(bound_bv); + for(size_t i = 0; i < n_leaves; ++i) + nodes[i].code = coder(nodes[i].bv.center()); + + + size_t* ids = new size_t[n_leaves]; + for(size_t i = 0; i < n_leaves; ++i) + ids[i] = i; + + SortByMorton comp; + comp.nodes = nodes; + std::sort(ids, ids + n_leaves, comp); + root_node = mortonRecurse_2(ids, ids + n_leaves); + delete [] ids; + + refit(); + + opath = 0; + max_lookahead_level = -1; +} + +template<typename BV> +size_t HierarchyTree<BV>::insert(const BV& bv, void* data) +{ + size_t node = createNode(NULL_NODE, bv, data); + insertLeaf(root_node, node); + ++n_leaves; + return node; +} + +template<typename BV> +void HierarchyTree<BV>::remove(size_t leaf) +{ + removeLeaf(leaf); + deleteNode(leaf); + --n_leaves; +} + +template<typename BV> +void HierarchyTree<BV>::clear() +{ + delete [] nodes; + root_node = NULL_NODE; + n_nodes = 0; + n_nodes_alloc = 16; + nodes = new NodeType[n_nodes_alloc]; + for(size_t i = 0; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + n_leaves = 0; + freelist = 0; + opath = 0; + max_lookahead_level = -1; +} + +template<typename BV> +bool HierarchyTree<BV>::empty() const +{ + return (n_nodes == 0); +} + +template<typename BV> +void HierarchyTree<BV>::update(size_t leaf, int lookahead_level) +{ + size_t root = removeLeaf(leaf); + if(root != NULL_NODE) + { + if(lookahead_level > 0) + { + for(int i = 0; (i < lookahead_level) && (nodes[root].parent != NULL_NODE); ++i) + root = nodes[root].parent; + } + else + root = root_node; + } + insertLeaf(root, leaf); +} + +template<typename BV> +bool HierarchyTree<BV>::update(size_t leaf, const BV& bv) +{ + if(nodes[leaf].bv.contain(bv)) return false; + update_(leaf, bv); + return true; +} + +template<typename BV> +bool HierarchyTree<BV>::update(size_t leaf, const BV& bv, const Vec3f& vel, FCL_REAL margin) +{ + if(nodes[leaf].bv.contain(bv)) return false; + update_(leaf, bv); + return true; +} + +template<typename BV> +bool HierarchyTree<BV>::update(size_t leaf, const BV& bv, const Vec3f& vel) +{ + if(nodes[leaf].bv.contain(bv)) return false; + update_(leaf, bv); + return true; +} + +template<typename BV> +size_t HierarchyTree<BV>::getMaxHeight() const +{ + if(root_node == NULL_NODE) return 0; + + return getMaxHeight(root_node); +} + +template<typename BV> +size_t HierarchyTree<BV>::getMaxDepth() const +{ + if(root_node == NULL_NODE) return 0; + + size_t max_depth; + getMaxDepth(root_node, 0, max_depth); + return max_depth; +} + +template<typename BV> +void HierarchyTree<BV>::balanceBottomup() +{ + if(root_node != NULL_NODE) + { + NodeType* leaves = new NodeType[n_leaves]; + NodeType* leaves_ = leaves; + extractLeaves(root_node, leaves_); + root_node = NULL_NODE; + memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); + freelist = n_leaves; + n_nodes = n_leaves; + for(size_t i = n_leaves; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + + + size_t* ids = new size_t[n_leaves]; + for(size_t i = 0; i < n_leaves; ++i) + ids[i] = i; + + bottomup(ids, ids + n_leaves); + root_node = *ids; + + delete [] ids; + } +} + +template<typename BV> +void HierarchyTree<BV>::balanceTopdown() +{ + if(root_node != NULL_NODE) + { + NodeType* leaves = new NodeType[n_leaves]; + NodeType* leaves_ = leaves; + extractLeaves(root_node, leaves_); + root_node = NULL_NODE; + memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); + freelist = n_leaves; + n_nodes = n_leaves; + for(size_t i = n_leaves; i < n_nodes_alloc; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + + size_t* ids = new size_t[n_leaves]; + for(size_t i = 0; i < n_leaves; ++i) + ids[i] = i; + + root_node = topdown(ids, ids + n_leaves); + delete [] ids; + } +} + +template<typename BV> +void HierarchyTree<BV>::balanceIncremental(int iterations) +{ + if(iterations < 0) iterations = n_leaves; + if((root_node != NULL_NODE) && (iterations > 0)) + { + for(int i = 0; i < iterations; ++i) + { + size_t node = root_node; + unsigned int bit = 0; + while(!nodes[node].isLeaf()) + { + node = nodes[node].children[(opath>>bit)&1]; + bit = (bit+1)&(sizeof(unsigned int) * 8-1); + } + update(node); + ++opath; + } + } +} + +template<typename BV> +void HierarchyTree<BV>::refit() +{ + if(root_node != NULL_NODE) + recurseRefit(root_node); +} + +template<typename BV> +void HierarchyTree<BV>::extractLeaves(size_t root, NodeType*& leaves) const +{ + if(!nodes[root].isLeaf()) + { + extractLeaves(nodes[root].children[0], leaves); + extractLeaves(nodes[root].children[1], leaves); + } + else + { + *leaves = nodes[root]; + leaves++; + } +} + +template<typename BV> +size_t HierarchyTree<BV>::size() const +{ + return n_leaves; +} + +template<typename BV> +size_t HierarchyTree<BV>::getRoot() const +{ + return root_node; +} + +template<typename BV> +typename HierarchyTree<BV>::NodeType* HierarchyTree<BV>::getNodes() const +{ + return nodes; +} + +template<typename BV> +void HierarchyTree<BV>::print(size_t root, int depth) +{ + for(int i = 0; i < depth; ++i) + std::cout << " "; + NodeType* n = nodes + root; + std::cout << " (" << n->bv.min_[0] << ", " << n->bv.min_[1] << ", " << n->bv.min_[2] << "; " << n->bv.max_[0] << ", " << n->bv.max_[1] << ", " << n->bv.max_[2] << ")" << std::endl; + if(n->isLeaf()) + { + } + else + { + print(n->children[0], depth+1); + print(n->children[1], depth+1); + } +} + +template<typename BV> +size_t HierarchyTree<BV>::getMaxHeight(size_t node) const +{ + if(!nodes[node].isLeaf()) + { + size_t height1 = getMaxHeight(nodes[node].children[0]); + size_t height2 = getMaxHeight(nodes[node].children[1]); + return std::max(height1, height2) + 1; + } + else + return 0; +} + +template<typename BV> +void HierarchyTree<BV>::getMaxDepth(size_t node, size_t depth, size_t& max_depth) const +{ + if(!nodes[node].isLeaf()) + { + getMaxDepth(nodes[node].children[0], depth+1, max_depth); + getmaxDepth(nodes[node].children[1], depth+1, max_depth); + } + else + max_depth = std::max(max_depth, depth); +} + +template<typename BV> +void HierarchyTree<BV>::bottomup(size_t* lbeg, size_t* lend) +{ + size_t* lcur_end = lend; + while(lbeg < lcur_end - 1) + { + size_t* min_it1, *min_it2; + FCL_REAL min_size = std::numeric_limits<FCL_REAL>::max(); + for(size_t* it1 = lbeg; it1 < lcur_end; ++it1) + { + for(size_t* it2 = it1 + 1; it2 < lcur_end; ++it2) + { + FCL_REAL cur_size = (nodes[*it1].bv + nodes[*it2].bv).size(); + if(cur_size < min_size) + { + min_size = cur_size; + min_it1 = it1; + min_it2 = it2; + } + } + } + + size_t p = createNode(NULL_NODE, nodes[*min_it1].bv, nodes[*min_it2].bv, NULL); + nodes[p].children[0] = *min_it1; + nodes[p].children[1] = *min_it2; + nodes[*min_it1].parent = p; + nodes[*min_it2].parent = p; + *min_it1 = p; + size_t tmp = *min_it2; + lcur_end--; + *min_it2 = *lcur_end; + *lcur_end = tmp; + } +} + +template<typename BV> +size_t HierarchyTree<BV>::topdown(size_t* lbeg, size_t* lend) +{ + switch(topdown_level) + { + case 0: + return topdown_0(lbeg, lend); + break; + case 1: + return topdown_1(lbeg, lend); + break; + default: + return topdown_0(lbeg, lend); + } +} + +template<typename BV> +size_t HierarchyTree<BV>::topdown_0(size_t* lbeg, size_t* lend) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(num_leaves > bu_threshold) + { + BV vol = nodes[*lbeg].bv; + for(size_t* i = lbeg + 1; i < lend; ++i) + vol += nodes[*i].bv; + + int best_axis = 0; + FCL_REAL extent[3] = {vol.width(), vol.height(), vol.depth()}; + if(extent[1] > extent[0]) best_axis = 1; + if(extent[2] > extent[best_axis]) best_axis = 2; + + nodeBaseLess<BV> comp(nodes, best_axis); + size_t* lcenter = lbeg + num_leaves / 2; + std::nth_element(lbeg, lcenter, lend, comp); + + size_t node = createNode(NULL_NODE, vol, NULL); + nodes[node].children[0] = topdown_0(lbeg, lcenter); + nodes[node].children[1] = topdown_0(lcenter, lend); + nodes[nodes[node].children[0]].parent = node; + nodes[nodes[node].children[1]].parent = node; + return node; + } + else + { + bottomup(lbeg, lend); + return *lbeg; + } + } + return *lbeg; +} + +template<typename BV> +size_t HierarchyTree<BV>::topdown_1(size_t* lbeg, size_t* lend) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(num_leaves > bu_threshold) + { + Vec3f split_p = nodes[*lbeg].bv.center(); + BV vol = nodes[*lbeg].bv; + for(size_t* i = lbeg + 1; i < lend; ++i) + { + split_p += nodes[*i].bv.center(); + vol += nodes[*i].bv; + } + split_p /= (FCL_REAL)(num_leaves); + int best_axis = -1; + int bestmidp = num_leaves; + int splitcount[3][2] = {{0,0}, {0,0}, {0,0}}; + for(size_t* i = lbeg; i < lend; ++i) + { + Vec3f x = nodes[*i].bv.center() - split_p; + for(size_t j = 0; j < 3; ++j) + ++splitcount[j][x[j] > 0 ? 1 : 0]; + } + + for(size_t i = 0; i < 3; ++i) + { + if((splitcount[i][0] > 0) && (splitcount[i][1] > 0)) + { + int midp = std::abs(splitcount[i][0] - splitcount[i][1]); + if(midp < bestmidp) + { + best_axis = i; + bestmidp = midp; + } + } + } + + if(best_axis < 0) best_axis = 0; + + FCL_REAL split_value = split_p[best_axis]; + size_t* lcenter = lbeg; + for(size_t* i = lbeg; i < lend; ++i) + { + if(nodes[*i].bv.center()[best_axis] < split_value) + { + size_t temp = *i; + *i = *lcenter; + *lcenter = temp; + ++lcenter; + } + } + + size_t node = createNode(NULL_NODE, vol, NULL); + nodes[node].children[0] = topdown_1(lbeg, lcenter); + nodes[node].children[1] = topdown_1(lcenter, lend); + nodes[nodes[node].children[0]].parent = node; + nodes[nodes[node].children[1]].parent = node; + return node; + } + else + { + bottomup(lbeg, lend); + return *lbeg; + } + } + return *lbeg; +} + +template<typename BV> +size_t HierarchyTree<BV>::mortonRecurse_0(size_t* lbeg, size_t* lend, const FCL_UINT32& split, int bits) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(bits > 0) + { + SortByMorton comp; + comp.nodes = nodes; + comp.split = split; + size_t* lcenter = std::lower_bound(lbeg, lend, NULL_NODE, comp); + + if(lcenter == lbeg) + { + FCL_UINT32 split2 = split | (1 << (bits - 1)); + return mortonRecurse_0(lbeg, lend, split2, bits - 1); + } + else if(lcenter == lend) + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + return mortonRecurse_0(lbeg, lend, split1, bits - 1); + } + else + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + FCL_UINT32 split2 = split | (1 << (bits - 1)); + + size_t child1 = mortonRecurse_0(lbeg, lcenter, split1, bits - 1); + size_t child2 = mortonRecurse_0(lcenter, lend, split2, bits - 1); + size_t node = createNode(NULL_NODE, NULL); + nodes[node].children[0] = child1; + nodes[node].children[1] = child2; + nodes[child1].parent = node; + nodes[child2].parent = node; + return node; + } + } + else + { + size_t node = topdown(lbeg, lend); + return node; + } + } + else + return *lbeg; +} + +template<typename BV> +size_t HierarchyTree<BV>::mortonRecurse_1(size_t* lbeg, size_t* lend, const FCL_UINT32& split, int bits) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + if(bits > 0) + { + SortByMorton comp; + comp.nodes = nodes; + comp.split = split; + size_t* lcenter = std::lower_bound(lbeg, lend, NULL_NODE, comp); + + if(lcenter == lbeg) + { + FCL_UINT32 split2 = split | (1 << (bits - 1)); + return mortonRecurse_1(lbeg, lend, split2, bits - 1); + } + else if(lcenter == lend) + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + return mortonRecurse_1(lbeg, lend, split1, bits - 1); + } + else + { + FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); + FCL_UINT32 split2 = split | (1 << (bits - 1)); + + size_t child1 = mortonRecurse_1(lbeg, lcenter, split1, bits - 1); + size_t child2 = mortonRecurse_1(lcenter, lend, split2, bits - 1); + size_t node = createNode(NULL_NODE, NULL); + nodes[node].children[0] = child1; + nodes[node].children[1] = child2; + nodes[child1].parent = node; + nodes[child2].parent = node; + return node; + } + } + else + { + size_t child1 = mortonRecurse_1(lbeg, lbeg + num_leaves / 2, 0, bits - 1); + size_t child2 = mortonRecurse_1(lbeg + num_leaves / 2, lend, 0, bits - 1); + size_t node = createNode(NULL_NODE, NULL); + nodes[node].children[0] = child1; + nodes[node].children[1] = child2; + nodes[child1].parent = node; + nodes[child2].parent = node; + return node; + } + } + else + return *lbeg; +} + +template<typename BV> +size_t HierarchyTree<BV>::mortonRecurse_2(size_t* lbeg, size_t* lend) +{ + int num_leaves = lend - lbeg; + if(num_leaves > 1) + { + size_t child1 = mortonRecurse_2(lbeg, lbeg + num_leaves / 2); + size_t child2 = mortonRecurse_2(lbeg + num_leaves / 2, lend); + size_t node = createNode(NULL_NODE, NULL); + nodes[node].children[0] = child1; + nodes[node].children[1] = child2; + nodes[child1].parent = node; + nodes[child2].parent = node; + return node; + } + else + return *lbeg; +} + +template<typename BV> +void HierarchyTree<BV>::insertLeaf(size_t root, size_t leaf) +{ + if(root_node == NULL_NODE) + { + root_node = leaf; + nodes[leaf].parent = NULL_NODE; + } + else + { + if(!nodes[root].isLeaf()) + { + do + { + root = nodes[root].children[select(leaf, nodes[root].children[0], nodes[root].children[1], nodes)]; + } + while(!nodes[root].isLeaf()); + } + + size_t prev = nodes[root].parent; + size_t node = createNode(prev, nodes[leaf].bv, nodes[root].bv, NULL); + if(prev != NULL_NODE) + { + nodes[prev].children[indexOf(root)] = node; + nodes[node].children[0] = root; nodes[root].parent = node; + nodes[node].children[1] = leaf; nodes[leaf].parent = node; + do + { + if(!nodes[prev].bv.contain(nodes[node].bv)) + nodes[prev].bv = nodes[nodes[prev].children[0]].bv + nodes[nodes[prev].children[1]].bv; + else + break; + node = prev; + } while (NULL_NODE != (prev = nodes[node].parent)); + } + else + { + nodes[node].children[0] = root; nodes[root].parent = node; + nodes[node].children[1] = leaf; nodes[leaf].parent = node; + root_node = node; + } + } +} + +template<typename BV> +size_t HierarchyTree<BV>::removeLeaf(size_t leaf) +{ + if(leaf == root_node) + { + root_node = NULL_NODE; + return NULL_NODE; + } + else + { + size_t parent = nodes[leaf].parent; + size_t prev = nodes[parent].parent; + size_t sibling = nodes[parent].children[1-indexOf(leaf)]; + + if(prev != NULL_NODE) + { + nodes[prev].children[indexOf(parent)] = sibling; + nodes[sibling].parent = prev; + deleteNode(parent); + while(prev != NULL_NODE) + { + BV new_bv = nodes[nodes[prev].children[0]].bv + nodes[nodes[prev].children[1]].bv; + if(!new_bv.equal(nodes[prev].bv)) + { + nodes[prev].bv = new_bv; + prev = nodes[prev].parent; + } + else break; + } + + return (prev != NULL_NODE) ? prev : root_node; + } + else + { + root_node = sibling; + nodes[sibling].parent = NULL_NODE; + deleteNode(parent); + return root_node; + } + } +} + +template<typename BV> +void HierarchyTree<BV>::update_(size_t leaf, const BV& bv) +{ + size_t root = removeLeaf(leaf); + if(root != NULL_NODE) + { + if(max_lookahead_level >= 0) + { + for(int i = 0; (i < max_lookahead_level) && (nodes[root].parent != NULL_NODE); ++i) + root = nodes[root].parent; + } + + nodes[leaf].bv = bv; + insertLeaf(root, leaf); + } +} + +template<typename BV> +size_t HierarchyTree<BV>::indexOf(size_t node) +{ + return (nodes[nodes[node].parent].children[1] == node); +} + +template<typename BV> +size_t HierarchyTree<BV>::allocateNode() +{ + if(freelist == NULL_NODE) + { + NodeType* old_nodes = nodes; + n_nodes_alloc *= 2; + nodes = new NodeType[n_nodes_alloc]; + memcpy(nodes, old_nodes, n_nodes * sizeof(NodeType)); + delete [] old_nodes; + + for(size_t i = n_nodes; i < n_nodes_alloc - 1; ++i) + nodes[i].next = i + 1; + nodes[n_nodes_alloc - 1].next = NULL_NODE; + freelist = n_nodes; + } + + size_t node_id = freelist; + freelist = nodes[node_id].next; + nodes[node_id].parent = NULL_NODE; + nodes[node_id].children[0] = NULL_NODE; + nodes[node_id].children[1] = NULL_NODE; + ++n_nodes; + return node_id; +} + +template<typename BV> +size_t HierarchyTree<BV>::createNode(size_t parent, + const BV& bv1, + const BV& bv2, + void* data) +{ + size_t node = allocateNode(); + nodes[node].parent = parent; + nodes[node].data = data; + nodes[node].bv = bv1 + bv2; + return node; +} + +template<typename BV> +size_t HierarchyTree<BV>::createNode(size_t parent, + const BV& bv, + void* data) +{ + size_t node = allocateNode(); + nodes[node].parent = parent; + nodes[node].data = data; + nodes[node].bv = bv; + return node; +} + +template<typename BV> +size_t HierarchyTree<BV>::createNode(size_t parent, + void* data) +{ + size_t node = allocateNode(); + nodes[node].parent = parent; + nodes[node].data = data; + return node; +} + +template<typename BV> +void HierarchyTree<BV>::deleteNode(size_t node) +{ + nodes[node].next = freelist; + freelist = node; + --n_nodes; +} + +template<typename BV> +void HierarchyTree<BV>::recurseRefit(size_t node) +{ + if(!nodes[node].isLeaf()) + { + recurseRefit(nodes[node].children[0]); + recurseRefit(nodes[node].children[1]); + nodes[node].bv = nodes[nodes[node].children[0]].bv + nodes[nodes[node].children[1]].bv; + } + else + return; +} + +template<typename BV> +void HierarchyTree<BV>::fetchLeaves(size_t root, NodeType*& leaves, int depth) +{ + if((!nodes[root].isLeaf()) && depth) + { + fetchLeaves(nodes[root].children[0], leaves, depth-1); + fetchLeaves(nodes[root].children[1], leaves, depth-1); + deleteNode(root); + } + else + { + *leaves = nodes[root]; + leaves++; + } +} + + + +} +} diff --git a/trunk/fcl/include/fcl/interval_tree.h b/trunk/fcl/include/fcl/broadphase/interval_tree.h similarity index 70% rename from trunk/fcl/include/fcl/interval_tree.h rename to trunk/fcl/include/fcl/broadphase/interval_tree.h index 6624c9c6f2ff42ce8371e28f8d470f7f33a9ffb2..cab4da64e7acefbd60d49e9546117f8336b8d187 100644 --- a/trunk/fcl/include/fcl/interval_tree.h +++ b/trunk/fcl/include/fcl/broadphase/interval_tree.h @@ -41,40 +41,41 @@ #include <deque> #include <limits> -/** \brief Main namespace */ namespace fcl { -/** \brief Interval trees implemented using red-black-trees as described in - * the book Introduction_To_Algorithms_ by Cormen, Leisserson, and Rivest. - * Can be replaced in part by boost::icl::interval_set, which is only supported after boost 1.46 and does not support delete node routine. - */ - +/// @brief Interval trees implemented using red-black-trees as described in +/// the book Introduction_To_Algorithms_ by Cormen, Leisserson, and Rivest. +/// Can be replaced in part by boost::icl::interval_set, which is only supported after boost 1.46 and does not support delete node routine. struct SimpleInterval { public: - SimpleInterval() {} virtual ~SimpleInterval() {} + virtual void print() {} + /// @brief interval is defined as [low, high] double low, high; }; +/// @brief The node for interval tree class IntervalTreeNode { friend class IntervalTree; public: - /** \brief Print the interval node information: set left = nil and right = root */ + /// @brief Print the interval node information: set left = nil and right = root void print(IntervalTreeNode* left, IntervalTreeNode* right) const; - + + /// @brief Create an empty node IntervalTreeNode(); + /// @brief Create an node storing the interval IntervalTreeNode(SimpleInterval* new_interval); ~IntervalTreeNode(); protected: - + /// @brief interval stored in the node SimpleInterval* stored_interval; double key; @@ -83,7 +84,8 @@ protected: double max_high; - bool red; /* if red = false then the node is black */ + /// @brief red or black node: if red = false then the node is black + bool red; IntervalTreeNode* left; @@ -92,22 +94,9 @@ protected: IntervalTreeNode* parent; }; -/** \brief Class describes the information needed when we take the - * right branch in searching for intervals but possibly come back - * and check the left branch as well. - */ -struct it_recursion_node -{ -public: - IntervalTreeNode* start_node; - - unsigned int parent_index; - - bool try_right_branch; -}; - +struct it_recursion_node; -/** \brief Interval tree */ +/// @brief Interval tree class IntervalTree { public: @@ -116,25 +105,25 @@ public: ~IntervalTree(); - /** \brief Print the whole interval tree */ + /// @brief Print the whole interval tree void print() const; - /** \brief Delete one node of the interval tree */ + /// @brief Delete one node of the interval tree SimpleInterval* deleteNode(IntervalTreeNode* node); + /// @brief delete node stored a given interval void deleteNode(SimpleInterval* ivl); - - /** \brief Insert one node of the interval tree */ + /// @brief Insert one node of the interval tree IntervalTreeNode* insert(SimpleInterval* new_interval); - /** \brief get the predecessor of a given node */ + /// @brief get the predecessor of a given node IntervalTreeNode* getPredecessor(IntervalTreeNode* node) const; - /** \brief Get the successor of a given node */ + /// @brief Get the successor of a given node IntervalTreeNode* getSuccessor(IntervalTreeNode* node) const; - /** \brief Return result for a given query */ + /// @brief Return result for a given query std::deque<SimpleInterval*> query(double low, double high); protected: @@ -143,22 +132,22 @@ protected: IntervalTreeNode* nil; - /** \brief left rotation of tree node */ + /// @brief left rotation of tree node void leftRotate(IntervalTreeNode* node); - /** \brief right rotation of tree node */ + /// @brief right rotation of tree node void rightRotate(IntervalTreeNode* node); - /** \brief recursively insert a node */ + /// @brief recursively insert a node void recursiveInsert(IntervalTreeNode* node); - /** \brief recursively print a subtree */ + /// @brief recursively print a subtree void recursivePrint(IntervalTreeNode* node) const; - /** \brief recursively find the node corresponding to the interval */ + /// @brief recursively find the node corresponding to the interval IntervalTreeNode* recursiveSearch(IntervalTreeNode* node, SimpleInterval* ivl) const; - /** \brief Travels up to the root fixing the max_high fields after an insertion or deletion */ + /// @brief Travels up to the root fixing the max_high fields after an insertion or deletion void fixupMaxHigh(IntervalTreeNode* node); void deleteFixup(IntervalTreeNode* node); diff --git a/trunk/fcl/include/fcl/morton.h b/trunk/fcl/include/fcl/broadphase/morton.h similarity index 84% rename from trunk/fcl/include/fcl/morton.h rename to trunk/fcl/include/fcl/broadphase/morton.h index bf0004268f6fad33a156058b7c357a30b549e4b2..98eeaea722c252e8b3030ad1e8c2cb4dfea0f7b1 100644 --- a/trunk/fcl/include/fcl/morton.h +++ b/trunk/fcl/include/fcl/broadphase/morton.h @@ -44,11 +44,16 @@ namespace fcl { +/// @cond IGNORE +namespace details +{ + static inline FCL_UINT32 quantize(FCL_REAL x, FCL_UINT32 n) { return std::max(std::min((FCL_UINT32)(x * (FCL_REAL)n), FCL_UINT32(n-1)), FCL_UINT32(0)); } +/// @brief compute 30 bit morton code static inline FCL_UINT32 morton_code(FCL_UINT32 x, FCL_UINT32 y, FCL_UINT32 z) { x = (x | (x << 16)) & 0x030000FF; @@ -69,6 +74,7 @@ static inline FCL_UINT32 morton_code(FCL_UINT32 x, FCL_UINT32 y, FCL_UINT32 z) return x | (y << 1) | (z << 2); } +/// @brief compute 60 bit morton code static inline FCL_UINT64 morton_code60(FCL_UINT32 x, FCL_UINT32 y, FCL_UINT32 z) { FCL_UINT32 lo_x = x & 1023u; @@ -81,9 +87,16 @@ static inline FCL_UINT64 morton_code60(FCL_UINT32 x, FCL_UINT32 y, FCL_UINT32 z) return (FCL_UINT64(morton_code(hi_x, hi_y, hi_z)) << 30) | FCL_UINT64(morton_code(lo_x, lo_y, lo_z)); } +} +/// @endcond + + +/// @brief Functor to compute the morton code for a given AABB template<typename T> struct morton_functor {}; + +/// @brief Functor to compute 30 bit morton code for a given AABB template<> struct morton_functor<FCL_UINT32> { @@ -95,11 +108,11 @@ struct morton_functor<FCL_UINT32> FCL_UINT32 operator() (const Vec3f& point) const { - FCL_UINT32 x = quantize((point[0] - base[0]) * inv[0], 1024u); - FCL_UINT32 y = quantize((point[1] - base[1]) * inv[1], 1024u); - FCL_UINT32 z = quantize((point[2] - base[2]) * inv[2], 1024u); + FCL_UINT32 x = details::quantize((point[0] - base[0]) * inv[0], 1024u); + FCL_UINT32 y = details::quantize((point[1] - base[1]) * inv[1], 1024u); + FCL_UINT32 z = details::quantize((point[2] - base[2]) * inv[2], 1024u); - return morton_code(x, y, z); + return details::morton_code(x, y, z); } const Vec3f base; @@ -109,6 +122,7 @@ struct morton_functor<FCL_UINT32> }; +/// @brief Functor to compute 60 bit morton code for a given AABB template<> struct morton_functor<FCL_UINT64> { @@ -120,11 +134,11 @@ struct morton_functor<FCL_UINT64> FCL_UINT64 operator() (const Vec3f& point) const { - FCL_UINT32 x = quantize((point[0] - base[0]) * inv[0], 1u << 20); - FCL_UINT32 y = quantize((point[1] - base[1]) * inv[1], 1u << 20); - FCL_UINT32 z = quantize((point[2] - base[2]) * inv[2], 1u << 20); + FCL_UINT32 x = details::quantize((point[0] - base[0]) * inv[0], 1u << 20); + FCL_UINT32 y = details::quantize((point[1] - base[1]) * inv[1], 1u << 20); + FCL_UINT32 z = details::quantize((point[2] - base[2]) * inv[2], 1u << 20); - return morton_code60(x, y, z); + return details::morton_code60(x, y, z); } const Vec3f base; @@ -133,6 +147,7 @@ struct morton_functor<FCL_UINT64> size_t bits() const { return 60; } }; +/// @brief Functor to compute n bit morton code for a given AABB template<> struct morton_functor<boost::dynamic_bitset<> > { diff --git a/trunk/fcl/include/fcl/ccd/interval.h b/trunk/fcl/include/fcl/ccd/interval.h index 6a4b697fbe9c8cb98e3b6b38fa39425eb4ccc2ad..6870ba0011be5dd6027537b008d8a6bd9a77568d 100644 --- a/trunk/fcl/include/fcl/ccd/interval.h +++ b/trunk/fcl/include/fcl/ccd/interval.h @@ -44,41 +44,49 @@ namespace fcl { +/// @brief Interval class for [a, b] struct Interval { FCL_REAL i_[2]; Interval() { i_[0] = i_[1] = 0; } + explicit Interval(FCL_REAL v) { i_[0] = i_[1] = v; } + /// @brief construct interval [left, right] Interval(FCL_REAL left, FCL_REAL right) { i_[0] = left; i_[1] = right; } + /// @brief construct interval [left, right] inline void setValue(FCL_REAL a, FCL_REAL b) { i_[0] = a; i_[1] = b; } + /// @brief construct zero interval [x, x] inline void setValue(FCL_REAL x) { i_[0] = i_[1] = x; } + /// @brief access the interval endpoints: 0 for left, 1 for right end inline FCL_REAL operator [] (size_t i) const { return i_[i]; } + /// @brief access the interval endpoints: 0 for left, 1 for right end inline FCL_REAL& operator [] (size_t i) { return i_[i]; } + /// @brief whether two intervals are the same inline bool operator == (const Interval& other) const { if(i_[0] != other.i_[0]) return false; @@ -86,11 +94,13 @@ struct Interval return true; } + /// @brief add two intervals inline Interval operator + (const Interval& other) const { return Interval(i_[0] + other.i_[0], i_[1] + other.i_[1]); } + /// @brief minus another interval inline Interval operator - (const Interval& other) const { return Interval(i_[0] - other.i_[1], i_[1] - other.i_[0]); @@ -137,12 +147,12 @@ struct Interval return *this; } - /** \brief other must not contain 0 */ + /// @brief other must not contain 0 Interval operator / (const Interval& other) const; Interval& operator /= (const Interval& other); - /** \brief determine whether the intersection between intervals is empty */ + /// @brief determine whether the intersection between intervals is empty inline bool overlap(const Interval& other) const { if(i_[1] < other.i_[0]) return false; @@ -164,7 +174,7 @@ struct Interval return Interval(-i_[1], -i_[0]); } - /** \brief Return the nearest distance for points within the interval to zero */ + /// @brief Return the nearest distance for points within the interval to zero inline FCL_REAL getAbsLower() const { if(i_[0] >= 0) return i_[0]; @@ -172,7 +182,7 @@ struct Interval return -i_[1]; } - /** \brief Return the farthest distance for points within the interval to zero */ + /// @brief Return the farthest distance for points within the interval to zero inline FCL_REAL getAbsUpper() const { if(i_[0] + i_[1] >= 0) return i_[1]; @@ -187,7 +197,7 @@ struct Interval return true; } - /** \brief Compute the minimum interval contains v and original interval */ + /// @brief Compute the minimum interval contains v and original interval inline Interval& bound(FCL_REAL v) { if(v < i_[0]) i_[0] = v; @@ -196,7 +206,7 @@ struct Interval } - /** \brief Compute the minimum interval contains other and original interval */ + /// @brief Compute the minimum interval contains other and original interval inline Interval& bound(const Interval& other) { if(other.i_[0] < i_[0]) i_[0] = other.i_[0]; diff --git a/trunk/fcl/include/fcl/ccd/taylor_model.h b/trunk/fcl/include/fcl/ccd/taylor_model.h index 3249067f9aabac87cdf02249bdc3ec33adb84904..9012de5a16541431f102993ed4194c8bc485b803 100644 --- a/trunk/fcl/include/fcl/ccd/taylor_model.h +++ b/trunk/fcl/include/fcl/ccd/taylor_model.h @@ -45,7 +45,7 @@ namespace fcl struct TimeInterval { - /** \brief time interval and different powers */ + /// @brief time interval and different powers Interval t_; // [t1, t2] Interval t2_; // [t1, t2]^2 Interval t3_; // [t1, t2]^3 @@ -54,19 +54,18 @@ struct TimeInterval Interval t6_; // [t1, t2]^6 }; -/** \brief TaylorModel implements a third order Taylor model, i.e., a cubic approximation of a function - * over a time interval, with an interval remainder. - * All the operations on two Taylor models assume their time intervals are the same. - */ +/// @brief TaylorModel implements a third order Taylor model, i.e., a cubic approximation of a function +/// over a time interval, with an interval remainder. +/// All the operations on two Taylor models assume their time intervals are the same. struct TaylorModel { - /** \brief time interval */ + /// @brief time interval boost::shared_ptr<TimeInterval> time_interval_; - /** \brief Coefficients of the cubic polynomial approximation */ + /// @brief Coefficients of the cubic polynomial approximation FCL_REAL coeffs_[4]; - /** \brief interval remainder */ + /// @brief interval remainder Interval r_; void setTimeInterval(FCL_REAL l, FCL_REAL r); diff --git a/trunk/fcl/include/fcl/collision.h b/trunk/fcl/include/fcl/collision.h index df3fa31de08ff5a019b6b6350c1ec8965e794244..d91c2169f3d8c9039308bd17284b01e6cf2d4c34 100644 --- a/trunk/fcl/include/fcl/collision.h +++ b/trunk/fcl/include/fcl/collision.h @@ -42,15 +42,13 @@ #include "fcl/collision_object.h" #include "fcl/collision_data.h" -/** \brief Main namespace */ namespace fcl { -/** \brief Main collision interface: given two collision objects, and the requirements for contacts, including num of max contacts, whether perform exhaustive collision (i.e., returning - * returning all the contact points), whether return detailed contact information (i.e., normal, contact point, depth; otherwise only contact primitive id is returned), this function - * performs the collision between them. - * Return value is the number of contacts generated between the two objects. - */ +/// @brief Main collision interface: given two collision objects, and the requirements for contacts, including num of max contacts, whether perform exhaustive collision (i.e., returning +/// returning all the contact points), whether return detailed contact information (i.e., normal, contact point, depth; otherwise only contact primitive id is returned), this function +/// performs the collision between them. +/// Return value is the number of contacts generated between the two objects. template<typename NarrowPhaseSolver> std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, diff --git a/trunk/fcl/include/fcl/collision_data.h b/trunk/fcl/include/fcl/collision_data.h index 3dd5e93e9ab7f481a16f3bcb52f205453a47e34f..ebb24a58ce834a9f88755d743deddbc4557eeb27 100644 --- a/trunk/fcl/include/fcl/collision_data.h +++ b/trunk/fcl/include/fcl/collision_data.h @@ -11,45 +11,62 @@ namespace fcl { +/// @brief Contact information returned by collision struct Contact { - FCL_REAL penetration_depth; - Vec3f normal; - Vec3f pos; + /// @brief collision object 1 const CollisionGeometry* o1; + + /// @brief collision object 2 const CollisionGeometry* o2; + + /// @brief contact primitive in object 1 + /// if object 1 is mesh or point cloud, it is the triangle or point id + /// if object 1 is geometry shape, it is NONE (-1), + /// if object 1 is octree, it is the id of the cell int b1; + + + /// @brief contact primitive in object 2 + /// if object 2 is mesh or point cloud, it is the triangle or point id + /// if object 2 is geometry shape, it is NONE (-1), + /// if object 2 is octree, it is the id of the cell int b2; - + + /// @brief contact normal, pointing from o1 to o2 + Vec3f normal; + + /// @brief contact position, in world space + Vec3f pos; + + /// @brief penetration depth + FCL_REAL penetration_depth; + + + /// @brief invalid contact primitive information static const int NONE = -1; - Contact() - { - o1 = NULL; - o2 = NULL; - b1 = -1; - b2 = -1; - } + Contact() : o1(NULL), + o2(NULL), + b1(NONE), + b2(NONE) + {} - Contact(const CollisionGeometry* o1_, const CollisionGeometry* o2_, int b1_, int b2_) - { - o1 = o1_; - o2 = o2_; - b1 = b1_; - b2 = b2_; - } + Contact(const CollisionGeometry* o1_, const CollisionGeometry* o2_, int b1_, int b2_) : o1(o1_), + o2(o2_), + b1(b1_), + b2(b2_) + {} Contact(const CollisionGeometry* o1_, const CollisionGeometry* o2_, int b1_, int b2_, - const Vec3f& pos_, const Vec3f& normal_, FCL_REAL depth_) - { - o1 = o1_; - o2 = o2_; - b1 = b1_; - b2 = b2_; - normal = normal_; - pos = pos_; - penetration_depth = depth_; - } + const Vec3f& pos_, const Vec3f& normal_, FCL_REAL depth_) : o1(o1_), + o2(o2_), + b1(b1_), + b2(b2_), + normal(normal_), + pos(pos_), + penetration_depth(depth_) + {} bool operator < (const Contact& other) const { @@ -59,10 +76,16 @@ struct Contact } }; +/// @brief Cost source describes an area with a cost. The area is described by an AABB region. struct CostSource { + /// @brief aabb lower bound Vec3f aabb_min; + + /// @brief aabb upper bound Vec3f aabb_max; + + /// @brief cost density in the AABB region FCL_REAL cost_density; CostSource(const Vec3f& aabb_min_, const Vec3f& aabb_max_, FCL_REAL cost_density_) : aabb_min(aabb_min_), @@ -85,11 +108,19 @@ struct CostSource } }; +/// @brief request to the collision algorithm struct CollisionRequest { + /// @brief The maximum number of contacts will return size_t num_max_contacts; + + /// @brief whether the contact information (normal, penetration depth and contact position) will return bool enable_contact; + + /// @brief The maximum number of cost sources will return size_t num_max_cost_sources; + + /// @brief whether the cost sources will be computed bool enable_cost; CollisionRequest(size_t num_max_contacts_ = 1, @@ -104,12 +135,14 @@ struct CollisionRequest }; - +/// @brief collision result struct CollisionResult { private: + /// @brief contact information std::vector<Contact> contacts; + /// @brief cost sources std::set<CostSource> cost_sources; const CollisionRequest* request; @@ -125,11 +158,13 @@ public: request = &request_; } + /// @brief add one contact into result structure inline void addContact(const Contact& c) { contacts.push_back(c); } + /// @brief add one cost source into result structure inline void addCostSource(const CostSource& c) { if(request) @@ -144,21 +179,25 @@ public: } } + /// @brief return binary collision result bool isCollision() const { return contacts.size() > 0; } + /// @brief number of contacts found size_t numContacts() const { return contacts.size(); } + /// @brief number of cost sources found size_t numCostSources() const { return cost_sources.size(); } + /// @brief get the i-th contact calculated const Contact& getContact(size_t i) const { if(i < contacts.size()) @@ -167,18 +206,21 @@ public: return contacts.back(); } + /// @brief get all the contacts void getContacts(std::vector<Contact>& contacts_) { contacts_.resize(contacts.size()); std::copy(contacts.begin(), contacts.end(), contacts_.begin()); } + /// @brief get all the cost sources void getCostSources(std::vector<CostSource>& cost_sources_) { cost_sources_.resize(cost_sources.size()); std::copy(cost_sources.begin(), cost_sources.end(), cost_sources_.begin()); } + /// @brief clear the results obtained void clear() { contacts.clear(); @@ -188,9 +230,10 @@ public: - +/// @brief request to the distance computation struct DistanceRequest { + /// @brief whether to return the nearest points bool enable_nearest_points; DistanceRequest(bool enable_nearest_points_ = false) : enable_nearest_points(enable_nearest_points_) @@ -198,6 +241,7 @@ struct DistanceRequest } }; +/// @brief distance result struct DistanceResult { private: @@ -205,22 +249,38 @@ private: public: + /// @brief minimum distance between two objects FCL_REAL min_distance; + /// @brief nearest points Vec3f nearest_points[2]; + /// @brief collision object 1 const CollisionGeometry* o1; + + /// @brief collision object 2 const CollisionGeometry* o2; + + /// @brief information about the nearest point in object 1 + /// if object 1 is mesh or point cloud, it is the triangle or point id + /// if object 1 is geometry shape, it is NONE (-1), + /// if object 1 is octree, it is the id of the cell int b1; + + /// @brief information about the nearest point in object 2 + /// if object 2 is mesh or point cloud, it is the triangle or point id + /// if object 2 is geometry shape, it is NONE (-1), + /// if object 2 is octree, it is the id of the cell int b2; + /// @brief invalid contact primitive information static const int NONE = -1; DistanceResult(FCL_REAL min_distance_ = std::numeric_limits<FCL_REAL>::max()) : min_distance(min_distance_), o1(NULL), o2(NULL), - b1(-1), - b2(-1) + b1(NONE), + b2(NONE) { request = NULL; } @@ -230,6 +290,7 @@ public: request = &request_; } + /// @brief add distance information into the result void update(FCL_REAL distance, const CollisionGeometry* o1_, const CollisionGeometry* o2_, int b1_, int b2_) { if(min_distance > distance) @@ -242,6 +303,7 @@ public: } } + /// @brief add distance information into the result void update(FCL_REAL distance, const CollisionGeometry* o1_, const CollisionGeometry* o2_, int b1_, int b2_, const Vec3f& p1, const Vec3f& p2) { if(min_distance > distance) @@ -256,6 +318,7 @@ public: } } + /// @brief add distance information into the result void update(const DistanceResult& other_result) { if(min_distance > other_result.min_distance) @@ -270,13 +333,14 @@ public: } } + /// @brief clear the result void clear() { min_distance = std::numeric_limits<FCL_REAL>::max(); o1 = NULL; o2 = NULL; - b1 = -1; - b2 = -1; + b1 = NONE; + b2 = NONE; } }; diff --git a/trunk/fcl/include/fcl/collision_node.h b/trunk/fcl/include/fcl/collision_node.h index b269cdf1d812a353c5e431136e905fc495e77427..58a7ee73906b733901d1dbb0eab4c2d9eac2612c 100644 --- a/trunk/fcl/include/fcl/collision_node.h +++ b/trunk/fcl/include/fcl/collision_node.h @@ -42,17 +42,26 @@ #include "fcl/traversal_node_bvhs.h" #include "fcl/BVH_front.h" + + + namespace fcl { + +/// @brief collision on collision traversal node; can use front list to accelerate void collide(CollisionTraversalNodeBase* node, BVHFrontList* front_list = NULL); +/// @brief self collision on collision traversal node; can use front list to accelerate void selfCollide(CollisionTraversalNodeBase* node, BVHFrontList* front_list = NULL); +/// @brief distance computation on distance traversal node; can use front list to accelerate void distance(DistanceTraversalNodeBase* node, BVHFrontList* front_list = NULL, int qsize = 2); +/// @brief special collision on OBB traversal node void collide2(MeshCollisionTraversalNodeOBB* node, BVHFrontList* front_list = NULL); +/// @brief special collision on RSS traversal node void collide2(MeshCollisionTraversalNodeRSS* node, BVHFrontList* front_list = NULL); } diff --git a/trunk/fcl/include/fcl/collision_object.h b/trunk/fcl/include/fcl/collision_object.h index 6576194de5d4d1a081e91774e6b39e6e3ef6ac28..fad09584c0bec9ca9397824c66b3dba0e9931fc2 100644 --- a/trunk/fcl/include/fcl/collision_object.h +++ b/trunk/fcl/include/fcl/collision_object.h @@ -45,66 +45,78 @@ namespace fcl { +/// @brief object type: BVH (mesh, points), basic geometry, octree enum OBJECT_TYPE {OT_UNKNOWN, OT_BVH, OT_GEOM, OT_OCTREE, OT_COUNT}; +/// @brief traversal node type: bounding volume (AABB, OBB, RSS, kIOS, OBBRSS, KDOP16, KDOP18, kDOP24), basic shape (box, sphere, capsule, cone, cylinder, convex, plane, triangle), and octree enum NODE_TYPE {BV_UNKNOWN, BV_AABB, BV_OBB, BV_RSS, BV_kIOS, BV_OBBRSS, BV_KDOP16, BV_KDOP18, BV_KDOP24, GEOM_BOX, GEOM_SPHERE, GEOM_CAPSULE, GEOM_CONE, GEOM_CYLINDER, GEOM_CONVEX, GEOM_PLANE, GEOM_TRIANGLE, GEOM_OCTREE, NODE_COUNT}; +/// @brief The geometry for the object for collision or distance computation class CollisionGeometry { public: - CollisionGeometry() + CollisionGeometry() : cost_density(1), + threshold_occupied(1), + threshold_free(0) { - cost_density = 1; - threshold_occupied = 1; - threshold_free = 0; } virtual ~CollisionGeometry() {} + /// @brief get the type of the object virtual OBJECT_TYPE getObjectType() const { return OT_UNKNOWN; } + /// @brief get the node type virtual NODE_TYPE getNodeType() const { return BV_UNKNOWN; } + /// @brief compute the AABB for object in local coordinate virtual void computeLocalAABB() = 0; + /// @brief get user data in geometry void* getUserData() const { return user_data; } + /// @brief set user data in geometry void setUserData(void *data) { user_data = data; } - + /// @brief whether the object is completely occupied inline bool isOccupied() const { return cost_density >= threshold_occupied; } + + /// @brief whether the object is completely free inline bool isFree() const { return cost_density <= threshold_free; } + + /// @brief whether the object has some uncertainty inline bool isUncertain() const { return !isOccupied() && !isFree(); } - /// AABB center in local coordinate + /// @brief AABB center in local coordinate Vec3f aabb_center; - /// AABB radius + /// @brief AABB radius FCL_REAL aabb_radius; - /// AABB in local coordinate, used for tight AABB when only translation transform + /// @brief AABB in local coordinate, used for tight AABB when only translation transform AABB aabb_local; - /// pointer to user defined data specific to this object + /// @brief pointer to user defined data specific to this object void *user_data; - /// collision cost for unit volume + /// @brief collision cost for unit volume FCL_REAL cost_density; - /// threshold for occupied ( >= is occupied) + /// @brief threshold for occupied ( >= is occupied) FCL_REAL threshold_occupied; - /// threshold for free (<= is free) + /// @brief threshold for free (<= is free) FCL_REAL threshold_free; }; +/// @brief the object for collision or distance computation, contains the geometry and the transform information class CollisionObject { public: @@ -135,21 +147,25 @@ public: { } + /// @brief get the type of the object OBJECT_TYPE getObjectType() const { return cgeom->getObjectType(); } + /// @brief get the node type NODE_TYPE getNodeType() const { return cgeom->getNodeType(); } + /// @brief get the AABB in world space inline const AABB& getAABB() const { return aabb; } + /// @brief compute the AABB in world space inline void computeAABB() { if(t.getQuatRotation().isIdentity()) @@ -165,101 +181,121 @@ public: } } + /// @brief get user data in object void* getUserData() const { return user_data; } + /// @brief set user data in object void setUserData(void *data) { user_data = data; } + /// @brief get translation of the object inline const Vec3f& getTranslation() const { return t.getTranslation(); } + /// @brief get matrix rotation of the object inline const Matrix3f& getRotation() const { return t.getRotation(); } + /// @brief get quaternion rotation of the object inline const Quaternion3f& getQuatRotation() const { return t.getQuatRotation(); } + /// @brief get object's transform inline const Transform3f& getTransform() const { return t; } + /// @brief set object's rotation matrix void setRotation(const Matrix3f& R) { t.setRotation(R); } + /// @brief set object's translation void setTranslation(const Vec3f& T) { t.setTranslation(T); } + /// @brief set object's quatenrion rotation void setQuatRotation(const Quaternion3f& q) { t.setQuatRotation(q); } + /// @brief set object's transform void setTransform(const Matrix3f& R, const Vec3f& T) { t.setTransform(R, T); } + /// @brief set object's transform void setTransform(const Quaternion3f& q, const Vec3f& T) { t.setTransform(q, T); } + /// @brief set object's transform void setTransform(const Transform3f& tf) { t = tf; } + /// @brief whether the object is in local coordinate bool isIdentityTransform() const { return t.isIdentity(); } + /// @brief set the object in local coordinate void setIdentityTransform() { t.setIdentity(); } + /// @brief get geometry from the object instance const CollisionGeometry* getCollisionGeometry() const { return cgeom.get(); } + /// @brief get object's cost density FCL_REAL getCostDensity() const { return cgeom->cost_density; } + /// @brief set object's cost density void setCostDensity(FCL_REAL c) { cgeom->cost_density = c; } + /// @brief whether the object is completely occupied inline bool isOccupied() const { return cgeom->isOccupied(); } + /// @brief whether the object is completely free inline bool isFree() const { return cgeom->isFree(); } + /// @brief whether the object is uncertain inline bool isUncertain() const { return cgeom->isUncertain(); @@ -271,10 +307,10 @@ protected: Transform3f t; - /// AABB in global coordinate + /// @brief AABB in global coordinate mutable AABB aabb; - /// pointer to user defined data specific to this object + /// @brief pointer to user defined data specific to this object void *user_data; }; diff --git a/trunk/fcl/include/fcl/hierarchy_tree.h b/trunk/fcl/include/fcl/hierarchy_tree.h deleted file mode 100644 index 254ed18084a8c3deb3e41d456f8f8bd54c7f86d4..0000000000000000000000000000000000000000 --- a/trunk/fcl/include/fcl/hierarchy_tree.h +++ /dev/null @@ -1,2053 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2011, Willow Garage, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** \author Jia Pan */ - -#ifndef FCL_HIERARCHY_TREE_H -#define FCL_HIERARCHY_TREE_H - -#include <vector> -#include <map> -#include "fcl/BV/AABB.h" -#include "fcl/vec_3f.h" -#include "fcl/morton.h" -#include <boost/bind.hpp> -#include <boost/iterator/zip_iterator.hpp> - -namespace fcl -{ - - -template<typename BV> -struct NodeBase -{ - BV bv; - NodeBase<BV>* parent; - bool isLeaf() const { return (childs[1] == NULL); } - bool isInternal() const { return !isLeaf(); } - union - { - NodeBase<BV>* childs[2]; - void* data; - }; - - FCL_UINT32 code; - - NodeBase() - { - parent = NULL; - childs[0] = NULL; - childs[1] = NULL; - } -}; - -template<typename BV> -bool nodeBaseLess(NodeBase<BV>* a, NodeBase<BV>* b, int d) -{ - if(a->bv.center()[d] < b->bv.center()[d]) return true; - return false; -} - -template<typename BV> -size_t select(const NodeBase<BV>& query, const NodeBase<BV>& node1, const NodeBase<BV>& node2) -{ - return 0; -} - -template<> -size_t select(const NodeBase<AABB>& node, const NodeBase<AABB>& node1, const NodeBase<AABB>& node2); - -template<typename BV> -size_t select(const BV& query, const NodeBase<BV>& node1, const NodeBase<BV>& node2) -{ - return 0; -} - -template<> -size_t select(const AABB& query, const NodeBase<AABB>& node1, const NodeBase<AABB>& node2); - - - -template<typename BV> -class HierarchyTree -{ - typedef NodeBase<BV> NodeType; - typedef typename std::vector<NodeBase<BV>* >::iterator NodeVecIterator; - typedef typename std::vector<NodeBase<BV>* >::const_iterator NodeVecConstIterator; - - struct SortByMorton - { - bool operator() (NodeType* a, NodeType* b) const - { - return a->code < b->code; - } - }; - -public: - - HierarchyTree(int bu_threshold_ = 16, int topdown_level_ = 0) - { - root_node = NULL; - n_leaves = 0; - free_node = NULL; - max_lookahead_level = -1; - opath = 0; - bu_threshold = bu_threshold_; - topdown_level = topdown_level_; - } - - ~HierarchyTree() - { - clear(); - } - - void init(std::vector<NodeType*>& leaves, int level = 0) - { - switch(level) - { - case 0: - init_0(leaves); - break; - case 1: - init_1(leaves); - break; - case 2: - init_2(leaves); - break; - case 3: - init_3(leaves); - break; - default: - init_0(leaves); - } - } - - /** \brief Insest a node */ - NodeType* insert(const BV& bv, void* data) - { - NodeType* leaf = createNode(NULL, bv, data); - insertLeaf(root_node, leaf); - ++n_leaves; - return leaf; - } - - /** \brief Remove a leaf node */ - void remove(NodeType* leaf) - { - removeLeaf(leaf); - deleteNode(leaf); - --n_leaves; - } - - /** \brief Clear the tree */ - void clear() - { - if(root_node) - recurseDeleteNode(root_node); - n_leaves = 0; - delete free_node; - free_node = NULL; - max_lookahead_level = -1; - opath = 0; - } - - /** \brief Whether the tree is empty */ - bool empty() const - { - return (NULL == root_node); - } - - /** \brief update one leaf node */ - void update(NodeType* leaf, int lookahead_level = -1) - { - NodeType* root = removeLeaf(leaf); - if(root) - { - if(lookahead_level > 0) - { - for(int i = 0; (i < lookahead_level) && root->parent; ++i) - root = root->parent; - } - else - root = root_node; - } - insertLeaf(root, leaf); - } - - bool update(NodeType* leaf, const BV& bv) - { - if(leaf->bv.contain(bv)) return false; - update_(leaf, bv); - return true; - } - - /** \brief update one leaf's bounding volume, with prediction */ - bool update(NodeType* leaf, const BV& bv, const Vec3f& vel, FCL_REAL margin) - { - if(leaf->bv.contain(bv)) return false; - update_(leaf, bv); - return true; - } - - /** \brief update one leaf's bounding volume, with prediction */ - bool update(NodeType* leaf, const BV& bv, const Vec3f& vel) - { - if(leaf->bv.contain(bv)) return false; - update_(leaf, bv); - return true; - } - - size_t getMaxHeight() const - { - if(!root_node) - return 0; - return getMaxHeight(root_node); - } - - size_t getMaxDepth() const - { - if(!root_node) return 0; - - size_t max_depth; - getMaxDepth(root_node, 0, max_depth); - return max_depth; - } - - /** \brief balance the tree from bottom */ - void balanceBottomup() - { - if(root_node) - { - std::vector<NodeType*> leaves; - leaves.reserve(n_leaves); - fetchLeaves(root_node, leaves); - bottomup(leaves.begin(), leaves.end()); - root_node = leaves[0]; - } - } - - /** \brief balance the tree from top */ - void balanceTopdown() - { - if(root_node) - { - std::vector<NodeType*> leaves; - leaves.reserve(n_leaves); - fetchLeaves(root_node, leaves); - root_node = topdown(leaves.begin(), leaves.end()); - } - } - - - /** \brief balance the tree in an incremental way */ - void balanceIncremental(int iterations) - { - if(iterations < 0) iterations = n_leaves; - if(root_node && (iterations > 0)) - { - for(int i = 0; i < iterations; ++i) - { - NodeType* node = root_node; - unsigned int bit = 0; - while(!node->isLeaf()) - { - node = sort(node, root_node)->childs[(opath>>bit)&1]; - bit = (bit+1)&(sizeof(unsigned int) * 8-1); - } - update(node); - ++opath; - } - } - } - - /** \brief refit */ - void refit() - { - if(root_node) - recurseRefit(root_node); - } - - /** \brief extract all the leaves of the tree */ - void extractLeaves(const NodeType* root, std::vector<NodeType*>& leaves) const - { - if(!root->isLeaf()) - { - extractLeaves(root->childs[0], leaves); - extractLeaves(root->childs[1], leaves); - } - else - leaves.push_back(root); - } - - size_t size() const - { - return n_leaves; - } - - inline NodeType* getRoot() const - { - return root_node; - } - - inline NodeType*& getRoot() - { - return root_node; - } - - void print(NodeType* root, int depth) - { - 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; - if(root->isLeaf()) - { - } - else - { - print(root->childs[0], depth+1); - print(root->childs[1], depth+1); - } - } - - - -private: - - /** \brief construct a tree for a set of leaves from bottom -- very heavy way */ - void bottomup(const NodeVecIterator lbeg, const NodeVecIterator lend) - { - NodeVecIterator lcur_end = lend; - while(lbeg < lcur_end - 1) - { - NodeVecIterator min_it1, min_it2; - FCL_REAL min_size = std::numeric_limits<FCL_REAL>::max(); - for(NodeVecIterator it1 = lbeg; it1 < lcur_end; ++it1) - { - for(NodeVecIterator it2 = it1 + 1; it2 < lcur_end; ++it2) - { - FCL_REAL cur_size = ((*it1)->bv + (*it2)->bv).size(); - if(cur_size < min_size) - { - min_size = cur_size; - min_it1 = it1; - min_it2 = it2; - } - } - } - - NodeType* n[2] = {*min_it1, *min_it2}; - NodeType* p = createNode(NULL, n[0]->bv, n[1]->bv, NULL); - p->childs[0] = n[0]; - p->childs[1] = n[1]; - n[0]->parent = p; - n[1]->parent = p; - *min_it1 = p; - NodeType* tmp = *min_it2; - lcur_end--; - *min_it2 = *lcur_end; - *lcur_end = tmp; - } - } - - /** \brief construct a tree for a set of leaves from top */ - NodeType* topdown(const NodeVecIterator lbeg, const NodeVecIterator lend) - { - switch(topdown_level) - { - case 0: - return topdown_0(lbeg, lend); - break; - case 1: - return topdown_1(lbeg, lend); - break; - default: - return topdown_0(lbeg, lend); - } - } - - - size_t getMaxHeight(NodeType* node) const - { - if(!node->isLeaf()) - { - size_t height1 = getMaxHeight(node->childs[0]); - size_t height2 = getMaxHeight(node->childs[1]); - return std::max(height1, height2) + 1; - } - else - return 0; - } - - void getMaxDepth(NodeType* node, size_t depth, size_t& max_depth) const - { - if(!node->isLeaf()) - { - getMaxDepth(node->childs[0], depth+1, max_depth); - getMaxDepth(node->childs[1], depth+1, max_depth); - } - else - max_depth = std::max(max_depth, depth); - } - - - NodeType* topdown_0(const NodeVecIterator lbeg, const NodeVecIterator lend) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(num_leaves > bu_threshold) - { - BV vol = (*lbeg)->bv; - for(NodeVecIterator it = lbeg + 1; it < lend; ++it) - vol += (*it)->bv; - - int best_axis = 0; - FCL_REAL extent[3] = {vol.width(), vol.height(), vol.depth()}; - if(extent[1] > extent[0]) best_axis = 1; - if(extent[2] > extent[best_axis]) best_axis = 2; - - // compute median - NodeVecIterator lcenter = lbeg + num_leaves / 2; - std::nth_element(lbeg, lcenter, lend, boost::bind(&nodeBaseLess<BV>, _1, _2, boost::ref(best_axis))); - - NodeType* node = createNode(NULL, vol, NULL); - node->childs[0] = topdown_0(lbeg, lcenter); - node->childs[1] = topdown_0(lcenter, lend); - node->childs[0]->parent = node; - node->childs[1]->parent = node; - return node; - } - else - { - bottomup(lbeg, lend); - return *lbeg; - } - } - return *lbeg; - } - - - NodeType* topdown_1(const NodeVecIterator lbeg, const NodeVecIterator lend) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(num_leaves > bu_threshold) - { - Vec3f split_p = (*lbeg)->bv.center(); - BV vol = (*lbeg)->bv; - NodeVecIterator it; - for(it = lbeg + 1; it < lend; ++it) - { - split_p += (*it)->bv.center(); - vol += (*it)->bv; - } - split_p /= (FCL_REAL)(num_leaves); - int best_axis = -1; - int bestmidp = num_leaves; - int splitcount[3][2] = {{0,0}, {0,0}, {0,0}}; - for(it = lbeg; it < lend; ++it) - { - Vec3f x = (*it)->bv.center() - split_p; - for(size_t j = 0; j < 3; ++j) - ++splitcount[j][x[j] > 0 ? 1 : 0]; - } - - for(size_t i = 0; i < 3; ++i) - { - if((splitcount[i][0] > 0) && (splitcount[i][1] > 0)) - { - int midp = std::abs(splitcount[i][0] - splitcount[i][1]); - if(midp < bestmidp) - { - best_axis = i; - bestmidp = midp; - } - } - } - - if(best_axis < 0) best_axis = 0; - - FCL_REAL split_value = split_p[best_axis]; - NodeVecIterator lcenter = lbeg; - for(it = lbeg; it < lend; ++it) - { - if((*it)->bv.center()[best_axis] < split_value) - { - NodeType* temp = *it; - *it = *lcenter; - *lcenter = temp; - ++lcenter; - } - } - - NodeType* node = createNode(NULL, vol, NULL); - node->childs[0] = topdown_1(lbeg, lcenter); - node->childs[1] = topdown_1(lcenter, lend); - node->childs[0]->parent = node; - node->childs[1]->parent = node; - return node; - } - else - { - bottomup(lbeg, lend); - return *lbeg; - } - } - return *lbeg; - } - - - void init_0(std::vector<NodeType*>& leaves) - { - clear(); - root_node = topdown(leaves.begin(), leaves.end()); - n_leaves = leaves.size(); - max_lookahead_level = -1; - opath = 0; - } - - void init_1(std::vector<NodeType*>& leaves) - { - clear(); - - BV bound_bv; - if(leaves.size() > 0) - bound_bv = leaves[0]->bv; - for(size_t i = 1; i < leaves.size(); ++i) - bound_bv += leaves[i]->bv; - - morton_functor<FCL_UINT32> coder(bound_bv); - for(size_t i = 0; i < leaves.size(); ++i) - leaves[i]->code = coder(leaves[i]->bv.center()); - - std::sort(leaves.begin(), leaves.end(), SortByMorton()); - - root_node = mortonRecurse_0(leaves.begin(), leaves.end(), (1 << (coder.bits()-1)), coder.bits()-1); - - refit(); - n_leaves = leaves.size(); - max_lookahead_level = -1; - opath = 0; - } - - void init_2(std::vector<NodeType*>& leaves) - { - clear(); - - BV bound_bv; - if(leaves.size() > 0) - bound_bv = leaves[0]->bv; - for(size_t i = 1; i < leaves.size(); ++i) - bound_bv += leaves[i]->bv; - - morton_functor<FCL_UINT32> coder(bound_bv); - for(size_t i = 0; i < leaves.size(); ++i) - leaves[i]->code = coder(leaves[i]->bv.center()); - - std::sort(leaves.begin(), leaves.end(), SortByMorton()); - - root_node = mortonRecurse_1(leaves.begin(), leaves.end(), (1 << (coder.bits()-1)), coder.bits()-1); - - refit(); - n_leaves = leaves.size(); - max_lookahead_level = -1; - opath = 0; - } - - void init_3(std::vector<NodeType*>& leaves) - { - clear(); - - BV bound_bv; - if(leaves.size() > 0) - bound_bv = leaves[0]->bv; - for(size_t i = 1; i < leaves.size(); ++i) - bound_bv += leaves[i]->bv; - - morton_functor<FCL_UINT32> coder(bound_bv); - for(size_t i = 0; i < leaves.size(); ++i) - leaves[i]->code = coder(leaves[i]->bv.center()); - - std::sort(leaves.begin(), leaves.end(), SortByMorton()); - - root_node = mortonRecurse_2(leaves.begin(), leaves.end()); - - refit(); - n_leaves = leaves.size(); - max_lookahead_level = -1; - opath = 0; - } - - - NodeType* mortonRecurse_0(const NodeVecIterator lbeg, const NodeVecIterator lend, const FCL_UINT32& split, int bits) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(bits > 0) - { - NodeType dummy; - dummy.code = split; - NodeVecIterator lcenter = std::lower_bound(lbeg, lend, &dummy, SortByMorton()); - - if(lcenter == lbeg) - { - FCL_UINT32 split2 = split | (1 << (bits - 1)); - return mortonRecurse_0(lbeg, lend, split2, bits - 1); - } - else if(lcenter == lend) - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - return mortonRecurse_0(lbeg, lend, split1, bits - 1); - } - else - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - FCL_UINT32 split2 = split | (1 << (bits - 1)); - - NodeType* child1 = mortonRecurse_0(lbeg, lcenter, split1, bits - 1); - NodeType* child2 = mortonRecurse_0(lcenter, lend, split2, bits - 1); - NodeType* node = createNode(NULL, NULL); - node->childs[0] = child1; - node->childs[1] = child2; - child1->parent = node; - child2->parent = node; - return node; - } - } - else - { - NodeType* node = topdown(lbeg, lend); - return node; - } - } - else - return *lbeg; - } - - NodeType* mortonRecurse_1(const NodeVecIterator lbeg, const NodeVecIterator lend, const FCL_UINT32& split, int bits) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(bits > 0) - { - NodeType dummy; - dummy.code = split; - NodeVecIterator lcenter = std::lower_bound(lbeg, lend, &dummy, SortByMorton()); - - if(lcenter == lbeg) - { - FCL_UINT32 split2 = split | (1 << (bits - 1)); - return mortonRecurse_1(lbeg, lend, split2, bits - 1); - } - else if(lcenter == lend) - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - return mortonRecurse_1(lbeg, lend, split1, bits - 1); - } - else - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - FCL_UINT32 split2 = split | (1 << (bits - 1)); - - NodeType* child1 = mortonRecurse_1(lbeg, lcenter, split1, bits - 1); - NodeType* child2 = mortonRecurse_1(lcenter, lend, split2, bits - 1); - NodeType* node = createNode(NULL, NULL); - node->childs[0] = child1; - node->childs[1] = child2; - child1->parent = node; - child2->parent = node; - return node; - } - } - else - { - NodeType* child1 = mortonRecurse_1(lbeg, lbeg + num_leaves / 2, 0, bits - 1); - NodeType* child2 = mortonRecurse_1(lbeg + num_leaves / 2, lend, 0, bits - 1); - NodeType* node = createNode(NULL, NULL); - node->childs[0] = child1; - node->childs[1] = child2; - child1->parent = node; - child2->parent = node; - return node; - } - } - else - return *lbeg; - } - - NodeType* mortonRecurse_2(const NodeVecIterator lbeg, const NodeVecIterator lend) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - NodeType* child1 = mortonRecurse_2(lbeg, lbeg + num_leaves / 2); - NodeType* child2 = mortonRecurse_2(lbeg + num_leaves / 2, lend); - NodeType* node = createNode(NULL, NULL); - node->childs[0] = child1; - node->childs[1] = child2; - child1->parent = node; - child2->parent = node; - return node; - } - else - return *lbeg; - } - - - /** \brief update one leaf node's bounding volume */ - void update_(NodeType* leaf, const BV& bv) - { - NodeType* root = removeLeaf(leaf); - if(root) - { - if(max_lookahead_level >= 0) - { - for(int i = 0; (i < max_lookahead_level) && root->parent; ++i) - root = root->parent; - } - else - root = root_node; - } - - leaf->bv = bv; - insertLeaf(root, leaf); - } - - /** \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 Insert a leaf node and also update its ancestors */ - void insertLeaf(NodeType* root, NodeType* leaf) - { - if(!root_node) - { - root_node = leaf; - leaf->parent = NULL; - } - else - { - if(!root->isLeaf()) - { - do - { - root = root->childs[select(*leaf, *(root->childs[0]), *(root->childs[1]))]; - } - while(!root->isLeaf()); - } - - NodeType* prev = root->parent; - NodeType* node = createNode(prev, leaf->bv, root->bv, NULL); - if(prev) - { - prev->childs[indexOf(root)] = node; - node->childs[0] = root; root->parent = node; - node->childs[1] = leaf; leaf->parent = node; - do - { - if(!prev->bv.contain(node->bv)) - prev->bv = prev->childs[0]->bv + prev->childs[1]->bv; - else - break; - node = prev; - } while (NULL != (prev = node->parent)); - } - else - { - node->childs[0] = root; root->parent = node; - node->childs[1] = leaf; leaf->parent = node; - root_node = node; - } - } - } - - /** \brief Remove a leaf. The leaf node itself is not deleted yet, but all the unnecessary internal nodes are deleted. - return the node with the smallest depth and is influenced by the remove operation */ - NodeType* removeLeaf(NodeType* leaf) - { - if(leaf == root_node) - { - root_node = NULL; - return NULL; - } - else - { - NodeType* parent = leaf->parent; - NodeType* prev = parent->parent; - NodeType* sibling = parent->childs[1-indexOf(leaf)]; - if(prev) - { - prev->childs[indexOf(parent)] = sibling; - sibling->parent = prev; - deleteNode(parent); - while(prev) - { - BV new_bv = prev->childs[0]->bv + prev->childs[1]->bv; - if(!new_bv.equal(prev->bv)) - { - prev->bv = new_bv; - prev = prev->parent; - } - else break; - } - - return prev ? prev : root_node; - } - else - { - root_node = sibling; - sibling->parent = NULL; - deleteNode(parent); - return root_node; - } - } - } - - /** \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) - { - 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) - { - // node cannot be NULL - return (node->parent->childs[1] == node); - } - - NodeType* createNode(NodeType* parent, - const BV& bv, - void* data) - { - NodeType* node = createNode(parent, data); - node->bv = bv; - return node; - } - - /** \brief create one node (leaf or internal */ - NodeType* createNode(NodeType* parent, - const BV& bv1, - const BV& bv2, - void* data) - { - NodeType* node = createNode(parent, data); - node->bv = bv1 + bv2; - return node; - } - - - inline NodeType* createNode(NodeType* parent, - void* data) - { - NodeType* node = NULL; - if(free_node) - { - node = free_node; - free_node = NULL; - } - else - node = new NodeType(); - node->parent = parent; - node->data = data; - node->childs[1] = 0; - return node; - } - - inline void deleteNode(NodeType* node) - { - if(free_node != node) - { - delete free_node; - free_node = node; - } - } - - void recurseDeleteNode(NodeType* node) - { - if(!node->isLeaf()) - { - recurseDeleteNode(node->childs[0]); - recurseDeleteNode(node->childs[1]); - } - - if(node == root_node) root_node = NULL; - deleteNode(node); - } - - void recurseRefit(NodeType* node) - { - if(!node->isLeaf()) - { - recurseRefit(node->childs[0]); - recurseRefit(node->childs[1]); - node->bv = node->childs[0]->bv + node->childs[1]->bv; - } - else - return; - } - - - static BV bounds(const std::vector<NodeType*>& leaves) - { - if(leaves.size() == 0) return BV(); - BV bv = leaves[0]->bv; - for(size_t i = 1; i < leaves.size(); ++i) - { - bv += leaves[i]->bv; - } - - return bv; - } - - static BV bounds(const NodeVecIterator lbeg, const NodeVecIterator lend) - { - if(lbeg == lend) return BV(); - BV bv = *lbeg; - for(NodeVecIterator it = lbeg + 1; it < lend; ++it) - { - bv += (*it)->bv; - } - - return bv; - } - -protected: - NodeType* root_node; - size_t n_leaves; - - unsigned int opath; - - NodeType* free_node; // This is a one NodeType cache, the reason is that we need to remove a node and then add it again frequently. - - int max_lookahead_level; - -public: - - int topdown_level; - int bu_threshold; - - -}; - - -template<> -bool HierarchyTree<AABB>::update(NodeBase<AABB>* leaf, const AABB& bv_, const Vec3f& vel, FCL_REAL margin); - -template<> -bool HierarchyTree<AABB>::update(NodeBase<AABB>* leaf, const AABB& bv_, const Vec3f& vel); - - -namespace alternative -{ - -template<typename BV> -struct NodeBase -{ - BV bv; - - union - { - size_t parent; - size_t next; - }; - - union - { - size_t childs[2]; - void* data; - }; - - FCL_UINT32 code; - - bool isLeaf() const { return (childs[1] == (size_t)(-1)); } - bool isInternal() const { return !isLeaf(); } -}; - -template<typename BV> -struct nodeBaseLess -{ - nodeBaseLess(const NodeBase<BV>* nodes_, size_t d_) - { - nodes = nodes_; - d = d_; - } - - bool operator() (size_t i, size_t j) const - { - if(nodes[i].bv.center()[d] < nodes[j].bv.center()[d]) - return true; - return false; - } - - const NodeBase<BV>* nodes; - size_t d; -}; - - - - -template<typename BV> -size_t select(size_t query, size_t node1, size_t node2, NodeBase<BV>* nodes) -{ - return 0; -} - -template<> -size_t select(size_t query, size_t node1, size_t node2, NodeBase<AABB>* nodes); - -template<typename BV> -size_t select(const BV& query, size_t node1, size_t node2, NodeBase<BV>* nodes) -{ - return 0; -} - -template<> -size_t select(const AABB& query, size_t node1, size_t node2, NodeBase<AABB>* nodes); - - -template<typename BV> -class HierarchyTree -{ - typedef NodeBase<BV> NodeType; - - struct SortByMorton - { - bool operator() (size_t a, size_t b) const - { - if((a != NULL_NODE) && (b != NULL_NODE)) - { - return nodes[a].code < nodes[b].code; - } - else if(a == NULL_NODE) - { - return split < nodes[b].code; - } - else if(b == NULL_NODE) - { - return nodes[a].code < split; - } - return false; - } - - NodeType* nodes; - FCL_UINT32 split; - }; - -public: - HierarchyTree(int bu_threshold_ = 16, int topdown_level_ = 0) - { - root_node = NULL_NODE; - n_nodes = 0; - n_nodes_alloc = 16; - nodes = new NodeType[n_nodes_alloc]; - for(size_t i = 0; i < n_nodes_alloc - 1; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - n_leaves = 0; - freelist = 0; - opath = 0; - max_lookahead_level = -1; - bu_threshold = bu_threshold_; - topdown_level = topdown_level_; - } - - ~HierarchyTree() - { - delete [] nodes; - } - - void init(NodeType* leaves, int n_leaves_, int level = 0) - { - switch(level) - { - case 0: - init_0(leaves, n_leaves_); - break; - case 1: - init_1(leaves, n_leaves_); - break; - case 2: - init_2(leaves, n_leaves_); - break; - case 3: - init_3(leaves, n_leaves_); - break; - default: - init_0(leaves, n_leaves_); - } - } - - void init_0(NodeType* leaves, int n_leaves_) - { - clear(); - - n_leaves = n_leaves_; - root_node = NULL_NODE; - nodes = new NodeType[n_leaves * 2]; - memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); - freelist = n_leaves; - n_nodes = n_leaves; - n_nodes_alloc = 2 * n_leaves; - for(size_t i = n_leaves; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - - size_t* ids = new size_t[n_leaves]; - for(size_t i = 0; i < n_leaves; ++i) - ids[i] = i; - - root_node = topdown(ids, ids + n_leaves); - delete [] ids; - - opath = 0; - max_lookahead_level = -1; - } - - void init_1(NodeType* leaves, int n_leaves_) - { - clear(); - - n_leaves = n_leaves_; - root_node = NULL_NODE; - nodes = new NodeType[n_leaves * 2]; - memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); - freelist = n_leaves; - n_nodes = n_leaves; - n_nodes_alloc = 2 * n_leaves; - for(size_t i = n_leaves; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - - - BV bound_bv; - if(n_leaves > 0) - bound_bv = nodes[0].bv; - for(size_t i = 1; i < n_leaves; ++i) - bound_bv += nodes[i].bv; - - morton_functor<FCL_UINT32> coder(bound_bv); - for(size_t i = 0; i < n_leaves; ++i) - nodes[i].code = coder(nodes[i].bv.center()); - - - size_t* ids = new size_t[n_leaves]; - for(size_t i = 0; i < n_leaves; ++i) - ids[i] = i; - - SortByMorton comp; - comp.nodes = nodes; - std::sort(ids, ids + n_leaves, comp); - root_node = mortonRecurse_0(ids, ids + n_leaves, (1 << coder.bits()-1), coder.bits()-1); - delete [] ids; - - refit(); - - opath = 0; - max_lookahead_level = -1; - } - - void init_2(NodeType* leaves, int n_leaves_) - { - clear(); - - n_leaves = n_leaves_; - root_node = NULL_NODE; - nodes = new NodeType[n_leaves * 2]; - memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); - freelist = n_leaves; - n_nodes = n_leaves; - n_nodes_alloc = 2 * n_leaves; - for(size_t i = n_leaves; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - - - BV bound_bv; - if(n_leaves > 0) - bound_bv = nodes[0].bv; - for(size_t i = 1; i < n_leaves; ++i) - bound_bv += nodes[i].bv; - - morton_functor<FCL_UINT32> coder(bound_bv); - for(size_t i = 0; i < n_leaves; ++i) - nodes[i].code = coder(nodes[i].bv.center()); - - - size_t* ids = new size_t[n_leaves]; - for(size_t i = 0; i < n_leaves; ++i) - ids[i] = i; - - SortByMorton comp; - comp.nodes = nodes; - std::sort(ids, ids + n_leaves, comp); - root_node = mortonRecurse_1(ids, ids + n_leaves, (1 << coder.bits()-1), coder.bits()-1); - delete [] ids; - - refit(); - - opath = 0; - max_lookahead_level = -1; - } - - void init_3(NodeType* leaves, int n_leaves_) - { - clear(); - - n_leaves = n_leaves_; - root_node = NULL_NODE; - nodes = new NodeType[n_leaves * 2]; - memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); - freelist = n_leaves; - n_nodes = n_leaves; - n_nodes_alloc = 2 * n_leaves; - for(size_t i = n_leaves; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - - - BV bound_bv; - if(n_leaves > 0) - bound_bv = nodes[0].bv; - for(size_t i = 1; i < n_leaves; ++i) - bound_bv += nodes[i].bv; - - morton_functor<FCL_UINT32> coder(bound_bv); - for(size_t i = 0; i < n_leaves; ++i) - nodes[i].code = coder(nodes[i].bv.center()); - - - size_t* ids = new size_t[n_leaves]; - for(size_t i = 0; i < n_leaves; ++i) - ids[i] = i; - - SortByMorton comp; - comp.nodes = nodes; - std::sort(ids, ids + n_leaves, comp); - root_node = mortonRecurse_2(ids, ids + n_leaves); - delete [] ids; - - refit(); - - opath = 0; - max_lookahead_level = -1; - } - - - - - size_t insert(const BV& bv, void* data) - { - size_t node = createNode(NULL_NODE, bv, data); - insertLeaf(root_node, node); - ++n_leaves; - return node; - } - - void remove(size_t leaf) - { - removeLeaf(leaf); - deleteNode(leaf); - --n_leaves; - } - - void clear() - { - delete [] nodes; - root_node = NULL_NODE; - n_nodes = 0; - n_nodes_alloc = 16; - nodes = new NodeType[n_nodes_alloc]; - for(size_t i = 0; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - n_leaves = 0; - freelist = 0; - opath = 0; - max_lookahead_level = -1; - } - - bool empty() const - { - return (n_nodes == 0); - } - - - void update(size_t leaf, int lookahead_level = -1) - { - size_t root = removeLeaf(leaf); - if(root != NULL_NODE) - { - if(lookahead_level > 0) - { - for(int i = 0; (i < lookahead_level) && (nodes[root].parent != NULL_NODE); ++i) - root = nodes[root].parent; - } - else - root = root_node; - } - insertLeaf(root, leaf); - } - - bool update(size_t leaf, const BV& bv) - { - if(nodes[leaf].bv.contain(bv)) return false; - update_(leaf, bv); - return true; - } - - bool update(size_t leaf, const BV& bv, const Vec3f& vel, FCL_REAL margin) - { - if(nodes[leaf].bv.contain(bv)) return false; - update_(leaf, bv); - return true; - } - - bool update(size_t leaf, const BV& bv, const Vec3f& vel) - { - if(nodes[leaf].bv.contain(bv)) return false; - update_(leaf, bv); - return true; - } - - - size_t getMaxHeight() const - { - if(root_node == NULL_NODE) return 0; - - return getMaxHeight(root_node); - } - - size_t getMaxDepth() const - { - if(root_node == NULL_NODE) return 0; - - size_t max_depth; - getMaxDepth(root_node, 0, max_depth); - return max_depth; - } - - void balanceBottomup() - { - if(root_node != NULL_NODE) - { - NodeType* leaves = new NodeType[n_leaves]; - NodeType* leaves_ = leaves; - extractLeaves(root_node, leaves_); - root_node = NULL_NODE; - memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); - freelist = n_leaves; - n_nodes = n_leaves; - for(size_t i = n_leaves; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - - - size_t* ids = new size_t[n_leaves]; - for(size_t i = 0; i < n_leaves; ++i) - ids[i] = i; - - bottomup(ids, ids + n_leaves); - root_node = *ids; - - delete [] ids; - } - } - - void balanceTopdown() - { - if(root_node != NULL_NODE) - { - NodeType* leaves = new NodeType[n_leaves]; - NodeType* leaves_ = leaves; - extractLeaves(root_node, leaves_); - root_node = NULL_NODE; - memcpy(nodes, leaves, sizeof(NodeType) * n_leaves); - freelist = n_leaves; - n_nodes = n_leaves; - for(size_t i = n_leaves; i < n_nodes_alloc; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - - size_t* ids = new size_t[n_leaves]; - for(size_t i = 0; i < n_leaves; ++i) - ids[i] = i; - - root_node = topdown(ids, ids + n_leaves); - delete [] ids; - } - } - - void balanceIncremental(int iterations) - { - if(iterations < 0) iterations = n_leaves; - if((root_node != NULL_NODE) && (iterations > 0)) - { - for(int i = 0; i < iterations; ++i) - { - size_t node = root_node; - unsigned int bit = 0; - while(!nodes[node].isLeaf()) - { - node = nodes[node].childs[(opath>>bit)&1]; - bit = (bit+1)&(sizeof(unsigned int) * 8-1); - } - update(node); - ++opath; - } - } - } - - void refit() - { - if(root_node != NULL_NODE) - recurseRefit(root_node); - } - - void extractLeaves(size_t root, NodeType*& leaves) const - { - if(!nodes[root].isLeaf()) - { - extractLeaves(nodes[root].childs[0], leaves); - extractLeaves(nodes[root].childs[1], leaves); - } - else - { - *leaves = nodes[root]; - leaves++; - } - } - - size_t size() const - { - return n_leaves; - } - - size_t getRoot() const - { - return root_node; - } - - NodeType* getNodes() const - { - return nodes; - } - - void print(size_t root, int depth) - { - for(int i = 0; i < depth; ++i) - std::cout << " "; - NodeType* n = nodes + root; - std::cout << " (" << n->bv.min_[0] << ", " << n->bv.min_[1] << ", " << n->bv.min_[2] << "; " << n->bv.max_[0] << ", " << n->bv.max_[1] << ", " << n->bv.max_[2] << ")" << std::endl; - if(n->isLeaf()) - { - } - else - { - print(n->childs[0], depth+1); - print(n->childs[1], depth+1); - } - } - - - -private: - - size_t getMaxHeight(size_t node) const - { - if(!nodes[node].isLeaf()) - { - size_t height1 = getMaxHeight(nodes[node].childs[0]); - size_t height2 = getMaxHeight(nodes[node].childs[1]); - return std::max(height1, height2) + 1; - } - else - return 0; - } - - void getMaxDepth(size_t node, size_t depth, size_t& max_depth) const - { - if(!nodes[node].isLeaf()) - { - getMaxDepth(nodes[node].childs[0], depth+1, max_depth); - getmaxDepth(nodes[node].childs[1], depth+1, max_depth); - } - else - max_depth = std::max(max_depth, depth); - } - - - void bottomup(size_t* lbeg, size_t* lend) - { - size_t* lcur_end = lend; - while(lbeg < lcur_end - 1) - { - size_t* min_it1, *min_it2; - FCL_REAL min_size = std::numeric_limits<FCL_REAL>::max(); - for(size_t* it1 = lbeg; it1 < lcur_end; ++it1) - { - for(size_t* it2 = it1 + 1; it2 < lcur_end; ++it2) - { - FCL_REAL cur_size = (nodes[*it1].bv + nodes[*it2].bv).size(); - if(cur_size < min_size) - { - min_size = cur_size; - min_it1 = it1; - min_it2 = it2; - } - } - } - - size_t p = createNode(NULL_NODE, nodes[*min_it1].bv, nodes[*min_it2].bv, NULL); - nodes[p].childs[0] = *min_it1; - nodes[p].childs[1] = *min_it2; - nodes[*min_it1].parent = p; - nodes[*min_it2].parent = p; - *min_it1 = p; - size_t tmp = *min_it2; - lcur_end--; - *min_it2 = *lcur_end; - *lcur_end = tmp; - } - } - - size_t topdown(size_t* lbeg, size_t* lend) - { - switch(topdown_level) - { - case 0: - return topdown_0(lbeg, lend); - break; - case 1: - return topdown_1(lbeg, lend); - break; - default: - return topdown_0(lbeg, lend); - } - } - - - - size_t topdown_0(size_t* lbeg, size_t* lend) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(num_leaves > bu_threshold) - { - BV vol = nodes[*lbeg].bv; - for(size_t* i = lbeg + 1; i < lend; ++i) - vol += nodes[*i].bv; - - int best_axis = 0; - FCL_REAL extent[3] = {vol.width(), vol.height(), vol.depth()}; - if(extent[1] > extent[0]) best_axis = 1; - if(extent[2] > extent[best_axis]) best_axis = 2; - - nodeBaseLess<BV> comp(nodes, best_axis); - size_t* lcenter = lbeg + num_leaves / 2; - std::nth_element(lbeg, lcenter, lend, comp); - - size_t node = createNode(NULL_NODE, vol, NULL); - nodes[node].childs[0] = topdown_0(lbeg, lcenter); - nodes[node].childs[1] = topdown_0(lcenter, lend); - nodes[nodes[node].childs[0]].parent = node; - nodes[nodes[node].childs[1]].parent = node; - return node; - } - else - { - bottomup(lbeg, lend); - return *lbeg; - } - } - return *lbeg; - } - - size_t topdown_1(size_t* lbeg, size_t* lend) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(num_leaves > bu_threshold) - { - Vec3f split_p = nodes[*lbeg].bv.center(); - BV vol = nodes[*lbeg].bv; - for(size_t* i = lbeg + 1; i < lend; ++i) - { - split_p += nodes[*i].bv.center(); - vol += nodes[*i].bv; - } - split_p /= (FCL_REAL)(num_leaves); - int best_axis = -1; - int bestmidp = num_leaves; - int splitcount[3][2] = {{0,0}, {0,0}, {0,0}}; - for(size_t* i = lbeg; i < lend; ++i) - { - Vec3f x = nodes[*i].bv.center() - split_p; - for(size_t j = 0; j < 3; ++j) - ++splitcount[j][x[j] > 0 ? 1 : 0]; - } - - for(size_t i = 0; i < 3; ++i) - { - if((splitcount[i][0] > 0) && (splitcount[i][1] > 0)) - { - int midp = std::abs(splitcount[i][0] - splitcount[i][1]); - if(midp < bestmidp) - { - best_axis = i; - bestmidp = midp; - } - } - } - - if(best_axis < 0) best_axis = 0; - - FCL_REAL split_value = split_p[best_axis]; - size_t* lcenter = lbeg; - for(size_t* i = lbeg; i < lend; ++i) - { - if(nodes[*i].bv.center()[best_axis] < split_value) - { - size_t temp = *i; - *i = *lcenter; - *lcenter = temp; - ++lcenter; - } - } - - size_t node = createNode(NULL_NODE, vol, NULL); - nodes[node].childs[0] = topdown_1(lbeg, lcenter); - nodes[node].childs[1] = topdown_1(lcenter, lend); - nodes[nodes[node].childs[0]].parent = node; - nodes[nodes[node].childs[1]].parent = node; - return node; - } - else - { - bottomup(lbeg, lend); - return *lbeg; - } - } - return *lbeg; - } - - size_t mortonRecurse_0(size_t* lbeg, size_t* lend, const FCL_UINT32& split, int bits) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(bits > 0) - { - SortByMorton comp; - comp.nodes = nodes; - comp.split = split; - size_t* lcenter = std::lower_bound(lbeg, lend, NULL_NODE, comp); - - if(lcenter == lbeg) - { - FCL_UINT32 split2 = split | (1 << (bits - 1)); - return mortonRecurse_0(lbeg, lend, split2, bits - 1); - } - else if(lcenter == lend) - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - return mortonRecurse_0(lbeg, lend, split1, bits - 1); - } - else - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - FCL_UINT32 split2 = split | (1 << (bits - 1)); - - size_t child1 = mortonRecurse_0(lbeg, lcenter, split1, bits - 1); - size_t child2 = mortonRecurse_0(lcenter, lend, split2, bits - 1); - size_t node = createNode(NULL_NODE, NULL); - nodes[node].childs[0] = child1; - nodes[node].childs[1] = child2; - nodes[child1].parent = node; - nodes[child2].parent = node; - return node; - } - } - else - { - size_t node = topdown(lbeg, lend); - return node; - } - } - else - return *lbeg; - } - - size_t mortonRecurse_1(size_t* lbeg, size_t* lend, const FCL_UINT32& split, int bits) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - if(bits > 0) - { - SortByMorton comp; - comp.nodes = nodes; - comp.split = split; - size_t* lcenter = std::lower_bound(lbeg, lend, NULL_NODE, comp); - - if(lcenter == lbeg) - { - FCL_UINT32 split2 = split | (1 << (bits - 1)); - return mortonRecurse_1(lbeg, lend, split2, bits - 1); - } - else if(lcenter == lend) - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - return mortonRecurse_1(lbeg, lend, split1, bits - 1); - } - else - { - FCL_UINT32 split1 = (split & (~(1 << bits))) | (1 << (bits - 1)); - FCL_UINT32 split2 = split | (1 << (bits - 1)); - - size_t child1 = mortonRecurse_1(lbeg, lcenter, split1, bits - 1); - size_t child2 = mortonRecurse_1(lcenter, lend, split2, bits - 1); - size_t node = createNode(NULL_NODE, NULL); - nodes[node].childs[0] = child1; - nodes[node].childs[1] = child2; - nodes[child1].parent = node; - nodes[child2].parent = node; - return node; - } - } - else - { - size_t child1 = mortonRecurse_1(lbeg, lbeg + num_leaves / 2, 0, bits - 1); - size_t child2 = mortonRecurse_1(lbeg + num_leaves / 2, lend, 0, bits - 1); - size_t node = createNode(NULL_NODE, NULL); - nodes[node].childs[0] = child1; - nodes[node].childs[1] = child2; - nodes[child1].parent = node; - nodes[child2].parent = node; - return node; - } - } - else - return *lbeg; - } - - size_t mortonRecurse_2(size_t* lbeg, size_t* lend) - { - int num_leaves = lend - lbeg; - if(num_leaves > 1) - { - size_t child1 = mortonRecurse_2(lbeg, lbeg + num_leaves / 2); - size_t child2 = mortonRecurse_2(lbeg + num_leaves / 2, lend); - size_t node = createNode(NULL_NODE, NULL); - nodes[node].childs[0] = child1; - nodes[node].childs[1] = child2; - nodes[child1].parent = node; - nodes[child2].parent = node; - return node; - } - else - return *lbeg; - } - - - void insertLeaf(size_t root, size_t leaf) - { - if(root_node == NULL_NODE) - { - root_node = leaf; - nodes[leaf].parent = NULL_NODE; - } - else - { - if(!nodes[root].isLeaf()) - { - do - { - root = nodes[root].childs[select(leaf, nodes[root].childs[0], nodes[root].childs[1], nodes)]; - } - while(!nodes[root].isLeaf()); - } - - size_t prev = nodes[root].parent; - size_t node = createNode(prev, nodes[leaf].bv, nodes[root].bv, NULL); - if(prev != NULL_NODE) - { - nodes[prev].childs[indexOf(root)] = node; - nodes[node].childs[0] = root; nodes[root].parent = node; - nodes[node].childs[1] = leaf; nodes[leaf].parent = node; - do - { - if(!nodes[prev].bv.contain(nodes[node].bv)) - nodes[prev].bv = nodes[nodes[prev].childs[0]].bv + nodes[nodes[prev].childs[1]].bv; - else - break; - node = prev; - } while (NULL_NODE != (prev = nodes[node].parent)); - } - else - { - nodes[node].childs[0] = root; nodes[root].parent = node; - nodes[node].childs[1] = leaf; nodes[leaf].parent = node; - root_node = node; - } - } - } - - size_t removeLeaf(size_t leaf) - { - if(leaf == root_node) - { - root_node = NULL_NODE; - return NULL_NODE; - } - else - { - size_t parent = nodes[leaf].parent; - size_t prev = nodes[parent].parent; - size_t sibling = nodes[parent].childs[1-indexOf(leaf)]; - - if(prev != NULL_NODE) - { - nodes[prev].childs[indexOf(parent)] = sibling; - nodes[sibling].parent = prev; - deleteNode(parent); - while(prev != NULL_NODE) - { - BV new_bv = nodes[nodes[prev].childs[0]].bv + nodes[nodes[prev].childs[1]].bv; - if(!new_bv.equal(nodes[prev].bv)) - { - nodes[prev].bv = new_bv; - prev = nodes[prev].parent; - } - else break; - } - - return (prev != NULL_NODE) ? prev : root_node; - } - else - { - root_node = sibling; - nodes[sibling].parent = NULL_NODE; - deleteNode(parent); - return root_node; - } - } - } - - - void update_(size_t leaf, const BV& bv) - { - size_t root = removeLeaf(leaf); - if(root != NULL_NODE) - { - if(max_lookahead_level >= 0) - { - for(int i = 0; (i < max_lookahead_level) && (nodes[root].parent != NULL_NODE); ++i) - root = nodes[root].parent; - } - - nodes[leaf].bv = bv; - insertLeaf(root, leaf); - } - } - - inline size_t indexOf(size_t node) - { - return (nodes[nodes[node].parent].childs[1] == node); - } - - - size_t allocateNode() - { - if(freelist == NULL_NODE) - { - NodeType* old_nodes = nodes; - n_nodes_alloc *= 2; - nodes = new NodeType[n_nodes_alloc]; - memcpy(nodes, old_nodes, n_nodes * sizeof(NodeType)); - delete [] old_nodes; - - for(size_t i = n_nodes; i < n_nodes_alloc - 1; ++i) - nodes[i].next = i + 1; - nodes[n_nodes_alloc - 1].next = NULL_NODE; - freelist = n_nodes; - } - - size_t node_id = freelist; - freelist = nodes[node_id].next; - nodes[node_id].parent = NULL_NODE; - nodes[node_id].childs[0] = NULL_NODE; - nodes[node_id].childs[1] = NULL_NODE; - ++n_nodes; - return node_id; - } - - size_t createNode(size_t parent, - const BV& bv1, - const BV& bv2, - void* data) - { - size_t node = allocateNode(); - nodes[node].parent = parent; - nodes[node].data = data; - nodes[node].bv = bv1 + bv2; - return node; - } - - size_t createNode(size_t parent, - const BV& bv, - void* data) - { - size_t node = allocateNode(); - nodes[node].parent = parent; - nodes[node].data = data; - nodes[node].bv = bv; - return node; - } - - size_t createNode(size_t parent, - void* data) - { - size_t node = allocateNode(); - nodes[node].parent = parent; - nodes[node].data = data; - return node; - } - - void deleteNode(size_t node) - { - nodes[node].next = freelist; - freelist = node; - --n_nodes; - } - - void recurseRefit(size_t node) - { - if(!nodes[node].isLeaf()) - { - recurseRefit(nodes[node].childs[0]); - recurseRefit(nodes[node].childs[1]); - nodes[node].bv = nodes[nodes[node].childs[0]].bv + nodes[nodes[node].childs[1]].bv; - } - else - return; - } - - void fetchLeaves(size_t root, NodeType*& leaves, int depth = -1) - { - if((!nodes[root].isLeaf()) && depth) - { - fetchLeaves(nodes[root].childs[0], leaves, depth-1); - fetchLeaves(nodes[root].childs[1], leaves, depth-1); - deleteNode(root); - } - else - { - *leaves = nodes[root]; - leaves++; - } - } - - - -protected: - size_t root_node; - NodeType* nodes; - size_t n_nodes; - size_t n_nodes_alloc; - - size_t n_leaves; - size_t freelist; - unsigned int opath; - - int max_lookahead_level; - -public: - int bu_threshold; - int topdown_level; - -public: - static const size_t NULL_NODE = -1; -}; - -template<typename BV> -const size_t HierarchyTree<BV>::NULL_NODE; - - - - - -} - - - -} - - -#endif diff --git a/trunk/fcl/src/BV/OBB.cpp b/trunk/fcl/src/BV/OBB.cpp index 68fc42c30f7500fe94a89e8e35573db391e5c781..4de8f8d0e29c1f53e8ee9595e12b5e156b4ef1fa 100644 --- a/trunk/fcl/src/BV/OBB.cpp +++ b/trunk/fcl/src/BV/OBB.cpp @@ -384,4 +384,11 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBB& b1, const OBB& b2) return !obbDisjoint(R, T, b1.extent, b2.extent); } +OBB translate(const OBB& bv, const Vec3f& t) +{ + OBB res(bv); + res.To += t; + return res; +} + } diff --git a/trunk/fcl/src/BV/OBBRSS.cpp b/trunk/fcl/src/BV/OBBRSS.cpp index 5df9821b3c55fef7ebbae7e9f5d8147a6c84dd83..3a5fc39af8732f206ef1571696eda94c3885e0e0 100644 --- a/trunk/fcl/src/BV/OBBRSS.cpp +++ b/trunk/fcl/src/BV/OBBRSS.cpp @@ -49,5 +49,12 @@ FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const O return distance(R0, T0, b1.rss, b2.rss, P, Q); } +OBBRSS translate(const OBBRSS& bv, const Vec3f& t) +{ + OBBRSS res(bv); + res.obb.To += t; + res.rss.Tr += t; +} + } diff --git a/trunk/fcl/src/BV/RSS.cpp b/trunk/fcl/src/BV/RSS.cpp index ae98c25bda2092320774215fa9a09e787bb019fd..ee296fcee80eddf9d5ff50fbbc2039963fc7834a 100644 --- a/trunk/fcl/src/BV/RSS.cpp +++ b/trunk/fcl/src/BV/RSS.cpp @@ -1136,7 +1136,12 @@ FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& return (dist < (FCL_REAL)0.0) ? (FCL_REAL)0.0 : dist; } - +RSS translate(const RSS& bv, const Vec3f& t) +{ + RSS res(bv); + res.Tr += t; + return res; +} diff --git a/trunk/fcl/src/BV/kDOP.cpp b/trunk/fcl/src/BV/kDOP.cpp index d99c7727d8d9ddeb500846e8c7a18e3ca2318979..2b2b0f815df0f7d15210ffe0ddfbd3c912e678c9 100644 --- a/trunk/fcl/src/BV/kDOP.cpp +++ b/trunk/fcl/src/BV/kDOP.cpp @@ -104,6 +104,7 @@ inline void getDistances<9>(const Vec3f& p, FCL_REAL* d) } + template<size_t N> KDOP<N>::KDOP() { @@ -225,8 +226,34 @@ FCL_REAL KDOP<N>::distance(const KDOP<N>& other, Vec3f* P, Vec3f* Q) const } +template<size_t N> +KDOP<N> translate(const KDOP<N>& bv, const Vec3f& t) +{ + KDOP<N> res(bv); + for(size_t i = 0; i < 3; ++i) + { + res.dist(i) += t[i]; + res.dist(N / 2 + i) += t[i]; + } + + FCL_REAL d[(N - 6) / 2]; + getDistances<(N - 6) / 2>(t, d); + for(size_t i = 0; i < (N - 6) / 2; ++i) + { + res.dist(3 + i) += d[i]; + res.dist(3 + i + N / 2) += d[i]; + } + + return res; +} + + template class KDOP<16>; template class KDOP<18>; template class KDOP<24>; +template KDOP<16> translate<16>(const KDOP<16>&, const Vec3f&); +template KDOP<18> translate<18>(const KDOP<18>&, const Vec3f&); +template KDOP<24> translate<24>(const KDOP<24>&, const Vec3f&); + } diff --git a/trunk/fcl/src/BV/kIOS.cpp b/trunk/fcl/src/BV/kIOS.cpp index 94e3bcd3f563c55f87f6448f3e5883fdf37e3578..30171aff59d20fb798cfeefb8acae2bf01407169 100644 --- a/trunk/fcl/src/BV/kIOS.cpp +++ b/trunk/fcl/src/BV/kIOS.cpp @@ -196,4 +196,16 @@ FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const kIOS& b1, const kIO } +kIOS translate(const kIOS& bv, const Vec3f& t) +{ + kIOS res(bv); + for(size_t i = 0; i < res.num_spheres; ++i) + { + res.spheres[i].o += t; + } + + translate(res.obb, t); +} + + } diff --git a/trunk/fcl/src/BVH_model.cpp b/trunk/fcl/src/BVH_model.cpp index 607c69d5f074067eb8cb323802d4bcfdb55f5c6d..73f768bc48a22ec00f190fba3471240b01eab5ff 100644 --- a/trunk/fcl/src/BVH_model.cpp +++ b/trunk/fcl/src/BVH_model.cpp @@ -43,10 +43,15 @@ namespace fcl { template<typename BV> -BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other) +BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other), + num_tris(other.num_tris), + num_vertices(other.num_vertices), + build_state(other.build_state), + bv_splitter(other.bv_splitter), + bv_fitter(other.bv_fitter), + num_tris_allocated(other.num_tris), + num_vertices_allocated(other.num_vertices) { - num_tris = num_tris_allocated = other.num_tris; - num_vertices = num_vertices_allocated = other.num_vertices; if(other.vertices) { vertices = new Vec3f[num_vertices]; @@ -100,12 +105,6 @@ BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other) } else bvs = NULL; - - build_state = other.build_state; - - bv_splitter = other.bv_splitter; - - bv_fitter = other.bv_fitter; } @@ -875,6 +874,75 @@ void BVHModel<BV>::computeLocalAABB() aabb_local = aabb_; } + +template<> +void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c) +{ + OBB& obb = bvs[bv_id].bv; + if(!bvs[bv_id].isLeaf()) + { + makeParentRelativeRecurse(bvs[bv_id].first_child, obb.axis, obb.To); + + makeParentRelativeRecurse(bvs[bv_id].first_child + 1, obb.axis, obb.To); + } + + // make self parent relative + obb.axis[0] = Vec3f(parent_axis[0].dot(obb.axis[0]), parent_axis[1].dot(obb.axis[0]), parent_axis[2].dot(obb.axis[0])); + obb.axis[1] = Vec3f(parent_axis[0].dot(obb.axis[1]), parent_axis[1].dot(obb.axis[1]), parent_axis[2].dot(obb.axis[1])); + obb.axis[2] = Vec3f(parent_axis[0].dot(obb.axis[2]), parent_axis[1].dot(obb.axis[2]), parent_axis[2].dot(obb.axis[2])); + + Vec3f t = obb.To - parent_c; + obb.To = Vec3f(parent_axis[0].dot(t), parent_axis[1].dot(t), parent_axis[2].dot(t)); +} + +template<> +void BVHModel<RSS>::makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c) +{ + RSS& rss = bvs[bv_id].bv; + if(!bvs[bv_id].isLeaf()) + { + makeParentRelativeRecurse(bvs[bv_id].first_child, rss.axis, rss.Tr); + + makeParentRelativeRecurse(bvs[bv_id].first_child + 1, rss.axis, rss.Tr); + } + + // make self parent relative + rss.axis[0] = Vec3f(parent_axis[0].dot(rss.axis[0]), parent_axis[1].dot(rss.axis[0]), parent_axis[2].dot(rss.axis[0])); + rss.axis[1] = Vec3f(parent_axis[0].dot(rss.axis[1]), parent_axis[1].dot(rss.axis[1]), parent_axis[2].dot(rss.axis[1])); + rss.axis[2] = Vec3f(parent_axis[0].dot(rss.axis[2]), parent_axis[1].dot(rss.axis[2]), parent_axis[2].dot(rss.axis[2])); + + Vec3f t = rss.Tr - parent_c; + rss.Tr = Vec3f(parent_axis[0].dot(t), parent_axis[1].dot(t), parent_axis[2].dot(t)); +} + +template<> +void BVHModel<OBBRSS>::makeParentRelativeRecurse(int bv_id, Vec3f parent_axis[], const Vec3f& parent_c) +{ + OBB& obb = bvs[bv_id].bv.obb; + RSS& rss = bvs[bv_id].bv.rss; + if(!bvs[bv_id].isLeaf()) + { + makeParentRelativeRecurse(bvs[bv_id].first_child, obb.axis, obb.To); + + makeParentRelativeRecurse(bvs[bv_id].first_child + 1, obb.axis, obb.To); + } + + // make self parent relative + obb.axis[0] = Vec3f(parent_axis[0].dot(obb.axis[0]), parent_axis[1].dot(obb.axis[0]), parent_axis[2].dot(obb.axis[0])); + obb.axis[1] = Vec3f(parent_axis[0].dot(obb.axis[1]), parent_axis[1].dot(obb.axis[1]), parent_axis[2].dot(obb.axis[1])); + obb.axis[2] = Vec3f(parent_axis[0].dot(obb.axis[2]), parent_axis[1].dot(obb.axis[2]), parent_axis[2].dot(obb.axis[2])); + + rss.axis[0] = obb.axis[0]; + rss.axis[1] = obb.axis[1]; + rss.axis[2] = obb.axis[2]; + + Vec3f t = obb.To - parent_c; + obb.To = Vec3f(parent_axis[0].dot(t), parent_axis[1].dot(t), parent_axis[2].dot(t)); + rss.Tr = obb.To; +} + + + template<> NODE_TYPE BVHModel<AABB>::getNodeType() const { @@ -925,6 +993,9 @@ NODE_TYPE BVHModel<KDOP<24> >::getNodeType() const + + + template class BVHModel<KDOP<16> >; template class BVHModel<KDOP<18> >; template class BVHModel<KDOP<24> >; diff --git a/trunk/fcl/src/BV_splitter.cpp b/trunk/fcl/src/BV_splitter.cpp index d28405323b829a8da6efaa37b7e820c34e6ebf93..b657363e2fd744ab1df3ce0ccd028ce53185b99c 100644 --- a/trunk/fcl/src/BV_splitter.cpp +++ b/trunk/fcl/src/BV_splitter.cpp @@ -169,75 +169,84 @@ void computeSplitValue_median(const BV& bv, Vec3f* vertices, Triangle* triangles } } - +template<> void BVSplitter<OBB>::computeRule_bvcenter(const OBB& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<OBB>(bv, split_vector); computeSplitValue_bvcenter<OBB>(bv, split_value); } +template<> void BVSplitter<OBB>::computeRule_mean(const OBB& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<OBB>(bv, split_vector); computeSplitValue_mean<OBB>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } +template<> void BVSplitter<OBB>::computeRule_median(const OBB& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<OBB>(bv, split_vector); computeSplitValue_median<OBB>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } - +template<> void BVSplitter<RSS>::computeRule_bvcenter(const RSS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<RSS>(bv, split_vector); computeSplitValue_bvcenter<RSS>(bv, split_value); } - + +template<> void BVSplitter<RSS>::computeRule_mean(const RSS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<RSS>(bv, split_vector); computeSplitValue_mean<RSS>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } +template<> void BVSplitter<RSS>::computeRule_median(const RSS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<RSS>(bv, split_vector); computeSplitValue_median<RSS>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } +template<> void BVSplitter<kIOS>::computeRule_bvcenter(const kIOS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<kIOS>(bv, split_vector); computeSplitValue_bvcenter<kIOS>(bv, split_value); } +template<> void BVSplitter<kIOS>::computeRule_mean(const kIOS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<kIOS>(bv, split_vector); computeSplitValue_mean<kIOS>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } +template<> void BVSplitter<kIOS>::computeRule_median(const kIOS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<kIOS>(bv, split_vector); computeSplitValue_median<kIOS>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } - +template<> void BVSplitter<OBBRSS>::computeRule_bvcenter(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<OBBRSS>(bv, split_vector); computeSplitValue_bvcenter<OBBRSS>(bv, split_value); } +template<> void BVSplitter<OBBRSS>::computeRule_mean(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<OBBRSS>(bv, split_vector); computeSplitValue_mean<OBBRSS>(bv, vertices, tri_indices, primitive_indices, num_primitives, type, split_vector, split_value); } +template<> void BVSplitter<OBBRSS>::computeRule_median(const OBBRSS& bv, unsigned int* primitive_indices, int num_primitives) { computeSplitVector<OBBRSS>(bv, split_vector); @@ -245,4 +254,29 @@ void BVSplitter<OBBRSS>::computeRule_median(const OBBRSS& bv, unsigned int* prim } +template<> +bool BVSplitter<OBB>::apply(const Vec3f& q) const +{ + return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; +} + +template<> +bool BVSplitter<RSS>::apply(const Vec3f& q) const +{ + return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; +} + +template<> +bool BVSplitter<kIOS>::apply(const Vec3f& q) const +{ + return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; +} + +template<> +bool BVSplitter<OBBRSS>::apply(const Vec3f& q) const +{ + return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value; +} + + } diff --git a/trunk/fcl/src/broad_phase_collision.cpp b/trunk/fcl/src/broad_phase_collision.cpp deleted file mode 100644 index ae45d64e9cd7954fddb1ab5a360e8f4165336bb2..0000000000000000000000000000000000000000 --- a/trunk/fcl/src/broad_phase_collision.cpp +++ /dev/null @@ -1,3209 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2011, Willow Garage, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** \author Jia Pan */ - - -#include "fcl/broad_phase_collision.h" -#include "fcl/collision.h" -#include "fcl/distance.h" -#include "fcl/BV.h" -#include "fcl/geometric_shapes_utility.h" -#include <algorithm> -#include <set> -#include <deque> -#include <iostream> - -namespace fcl -{ - -void NaiveCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) -{ - std::copy(other_objs.begin(), other_objs.end(), std::back_inserter(objs)); -} - -void NaiveCollisionManager::unregisterObject(CollisionObject* obj) -{ - objs.remove(obj); -} - -void NaiveCollisionManager::registerObject(CollisionObject* obj) -{ - objs.push_back(obj); -} - -void NaiveCollisionManager::setup() -{ - -} - -void NaiveCollisionManager::update() -{ - -} - -void NaiveCollisionManager::clear() -{ - objs.clear(); -} - -void NaiveCollisionManager::getObjects(std::vector<CollisionObject*>& objs_) const -{ - objs_.resize(objs.size()); - std::copy(objs.begin(), objs.end(), objs_.begin()); -} - -void NaiveCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) - { - if(callback(obj, *it, cdata)) - return; - } -} - -void NaiveCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); - it != end; ++it) - { - if(obj->getAABB().distance((*it)->getAABB()) < min_dist) - { - if(callback(obj, *it, cdata, min_dist)) - return; - } - } -} - -void NaiveCollisionManager::collide(void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end = objs.end(); - it1 != end; ++it1) - { - std::list<CollisionObject*>::const_iterator it2 = it1; it2++; - for(; it2 != end; ++it2) - { - if((*it1)->getAABB().overlap((*it2)->getAABB())) - if(callback(*it1, *it2, cdata)) - return; - } - } -} - -void NaiveCollisionManager::distance(void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end = objs.end(); it1 != end; ++it1) - { - std::list<CollisionObject*>::const_iterator it2 = it1; it2++; - for(; it2 != end; ++it2) - { - if((*it1)->getAABB().distance((*it2)->getAABB()) < min_dist) - { - if(callback(*it1, *it2, cdata, min_dist)) - return; - } - } - } -} - -void NaiveCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const -{ - NaiveCollisionManager* other_manager = static_cast<NaiveCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - collide(cdata, callback); - return; - } - - for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end1 = objs.end(); it1 != end1; ++it1) - { - for(std::list<CollisionObject*>::const_iterator it2 = other_manager->objs.begin(), end2 = other_manager->objs.end(); it2 != end2; ++it2) - { - if((*it1)->getAABB().overlap((*it2)->getAABB())) - if(callback((*it1), (*it2), cdata)) - return; - } - } -} - -void NaiveCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const -{ - NaiveCollisionManager* other_manager = static_cast<NaiveCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - distance(cdata, callback); - return; - } - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end1 = objs.end(); it1 != end1; ++it1) - { - for(std::list<CollisionObject*>::const_iterator it2 = other_manager->objs.begin(), end2 = other_manager->objs.end(); it2 != end2; ++it2) - { - if((*it1)->getAABB().distance((*it2)->getAABB()) < min_dist) - { - if(callback(*it1, *it2, cdata, min_dist)) - return; - } - } - } -} - -bool NaiveCollisionManager::empty() const -{ - return objs.empty(); -} - - -/** \brief Functor sorting objects according to the AABB lower x bound */ -struct SortByXLow -{ - bool operator()(const CollisionObject* a, const CollisionObject* b) const - { - if(a->getAABB().min_[0] < b->getAABB().min_[0]) - return true; - return false; - } -}; - -/** \brief Functor sorting objects according to the AABB lower y bound */ -struct SortByYLow -{ - bool operator()(const CollisionObject* a, const CollisionObject* b) const - { - if(a->getAABB().min_[1] < b->getAABB().min_[1]) - return true; - return false; - } -}; - -/** \brief Functor sorting objects according to the AABB lower z bound */ -struct SortByZLow -{ - bool operator()(const CollisionObject* a, const CollisionObject* b) const - { - if(a->getAABB().min_[2] < b->getAABB().min_[2]) - return true; - return false; - } -}; - -/** \brief Dummy collision object with a point AABB */ -class DummyCollisionObject : public CollisionObject -{ -public: - DummyCollisionObject(const AABB& aabb_) : CollisionObject() - { - aabb = aabb_; - } - - void computeLocalAABB() {} -}; - - -void SSaPCollisionManager::unregisterObject(CollisionObject* obj) -{ - setup(); - - DummyCollisionObject dummyHigh(AABB(obj->getAABB().max_)); - - std::vector<CollisionObject*>::iterator pos_start1 = objs_x.begin(); - std::vector<CollisionObject*>::iterator pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow()); - - while(pos_start1 < pos_end1) - { - if(*pos_start1 == obj) - { - objs_x.erase(pos_start1); - break; - } - ++pos_start1; - } - - std::vector<CollisionObject*>::iterator pos_start2 = objs_y.begin(); - std::vector<CollisionObject*>::iterator pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow()); - - while(pos_start2 < pos_end2) - { - if(*pos_start2 == obj) - { - objs_y.erase(pos_start2); - break; - } - ++pos_start2; - } - - std::vector<CollisionObject*>::iterator pos_start3 = objs_z.begin(); - std::vector<CollisionObject*>::iterator pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow()); - - while(pos_start3 < pos_end3) - { - if(*pos_start3 == obj) - { - objs_z.erase(pos_start3); - break; - } - ++pos_start3; - } -} - - -void SSaPCollisionManager::registerObject(CollisionObject* obj) -{ - objs_x.push_back(obj); - objs_y.push_back(obj); - objs_z.push_back(obj); - setup_ = false; -} - -void SSaPCollisionManager::setup() -{ - if(!setup_) - { - std::sort(objs_x.begin(), objs_x.end(), SortByXLow()); - std::sort(objs_y.begin(), objs_y.end(), SortByYLow()); - std::sort(objs_z.begin(), objs_z.end(), SortByZLow()); - setup_ = true; - } -} - -void SSaPCollisionManager::update() -{ - setup_ = false; - setup(); -} - -void SSaPCollisionManager::clear() -{ - objs_x.clear(); - objs_y.clear(); - objs_z.clear(); - setup_ = false; -} - -void SSaPCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const -{ - objs.resize(objs_x.size()); - std::copy(objs_x.begin(), objs_x.end(), objs.begin()); -} - -bool SSaPCollisionManager::checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, - CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - while(pos_start < pos_end) - { - if(*pos_start != obj) // no collision between the same object - { - if((*pos_start)->getAABB().overlap(obj->getAABB())) - { - if(callback(*pos_start, obj, cdata)) - return true; - } - } - pos_start++; - } - return false; -} - -bool SSaPCollisionManager::checkDis(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - while(pos_start < pos_end) - { - if(*pos_start != obj) // no distance between the same object - { - if((*pos_start)->getAABB().distance(obj->getAABB()) < min_dist) - { - if(callback(*pos_start, obj, cdata, min_dist)) - return true; - } - } - pos_start++; - } - - return false; -} - - - -void SSaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - collide_(obj, cdata, callback); -} - -bool SSaPCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - static const unsigned int CUTOFF = 100; - - DummyCollisionObject dummyHigh(AABB(obj->getAABB().max_)); - bool coll_res = false; - - std::vector<CollisionObject*>::const_iterator pos_start1 = objs_x.begin(); - std::vector<CollisionObject*>::const_iterator pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow()); - unsigned int d1 = pos_end1 - pos_start1; - - if(d1 > CUTOFF) - { - std::vector<CollisionObject*>::const_iterator pos_start2 = objs_y.begin(); - std::vector<CollisionObject*>::const_iterator pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow()); - unsigned int d2 = pos_end2 - pos_start2; - - if(d2 > CUTOFF) - { - std::vector<CollisionObject*>::const_iterator pos_start3 = objs_z.begin(); - std::vector<CollisionObject*>::const_iterator pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow()); - unsigned int d3 = pos_end3 - pos_start3; - - if(d3 > CUTOFF) - { - if(d3 <= d2 && d3 <= d1) - coll_res = checkColl(pos_start3, pos_end3, obj, cdata, callback); - else - { - if(d2 <= d3 && d2 <= d1) - coll_res = checkColl(pos_start2, pos_end2, obj, cdata, callback); - else - coll_res = checkColl(pos_start1, pos_end1, obj, cdata, callback); - } - } - else - coll_res = checkColl(pos_start3, pos_end3, obj, cdata, callback); - } - else - coll_res = checkColl(pos_start2, pos_end2, obj, cdata, callback); - } - else - coll_res = checkColl(pos_start1, pos_end1, obj, cdata, callback); - - return coll_res; -} - - -void SSaPCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - distance_(obj, cdata, callback, min_dist); -} - -bool SSaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - static const unsigned int CUTOFF = 100; - Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; - Vec3f dummy_vector = obj->getAABB().max_; - if(min_dist < std::numeric_limits<FCL_REAL>::max()) - dummy_vector += Vec3f(min_dist, min_dist, min_dist); - - std::vector<CollisionObject*>::const_iterator pos_start1 = objs_x.begin(); - std::vector<CollisionObject*>::const_iterator pos_start2 = objs_y.begin(); - std::vector<CollisionObject*>::const_iterator pos_start3 = objs_z.begin(); - std::vector<CollisionObject*>::const_iterator pos_end1 = objs_x.end(); - std::vector<CollisionObject*>::const_iterator pos_end2 = objs_y.end(); - std::vector<CollisionObject*>::const_iterator pos_end3 = objs_z.end(); - - int status = 1; - FCL_REAL old_min_distance; - - while(1) - { - old_min_distance = min_dist; - DummyCollisionObject dummyHigh((AABB(dummy_vector))); - - pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow()); - unsigned int d1 = pos_end1 - pos_start1; - - bool dist_res = false; - - if(d1 > CUTOFF) - { - pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow()); - unsigned int d2 = pos_end2 - pos_start2; - - if(d2 > CUTOFF) - { - pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow()); - unsigned int d3 = pos_end3 - pos_start3; - - if(d3 > CUTOFF) - { - if(d3 <= d2 && d3 <= d1) - dist_res = checkDis(pos_start3, pos_end3, obj, cdata, callback, min_dist); - else - { - if(d2 <= d3 && d2 <= d1) - dist_res = checkDis(pos_start2, pos_end2, obj, cdata, callback, min_dist); - else - dist_res = checkDis(pos_start1, pos_end1, obj, cdata, callback, min_dist); - } - } - else - dist_res = checkDis(pos_start3, pos_end3, obj, cdata, callback, min_dist); - } - else - dist_res = checkDis(pos_start2, pos_end2, obj, cdata, callback, min_dist); - } - else - { - dist_res = checkDis(pos_start1, pos_end1, obj, cdata, callback, min_dist); - } - - if(dist_res) return true; - - if(status == 1) - { - if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) - break; - else - { - // from infinity to a finite one, only need one additional loop - // to check the possible missed ones to the right of the objs array - if(min_dist < old_min_distance) - { - dummy_vector = obj->getAABB().max_ + Vec3f(min_dist, min_dist, min_dist); - status = 0; - } - else // need more loop - { - if(dummy_vector.equal(obj->getAABB().max_)) - dummy_vector = dummy_vector + delta; - else - dummy_vector = dummy_vector * 2 - obj->getAABB().max_; - } - } - - // 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; - } - - return false; -} - -void SSaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - std::vector<CollisionObject*>::const_iterator pos, run_pos, pos_end; - size_t axis = selectOptimalAxis(objs_x, objs_y, objs_z, - pos, pos_end); - size_t axis2 = (axis + 1 > 2) ? 0 : (axis + 1); - size_t axis3 = (axis2 + 1 > 2) ? 0 : (axis2 + 1); - - run_pos = pos; - - while((run_pos < pos_end) && (pos < pos_end)) - { - CollisionObject* obj = *(pos++); - - while(1) - { - if((*run_pos)->getAABB().min_[axis] < obj->getAABB().min_[axis]) - { - run_pos++; - if(run_pos == pos_end) break; - continue; - } - else - { - run_pos++; - break; - } - } - - if(run_pos < pos_end) - { - std::vector<CollisionObject*>::const_iterator run_pos2 = run_pos; - - while((*run_pos2)->getAABB().min_[axis] <= obj->getAABB().max_[axis]) - { - CollisionObject* obj2 = *run_pos2; - run_pos2++; - - if((obj->getAABB().max_[axis2] >= obj2->getAABB().min_[axis2]) && (obj2->getAABB().max_[axis2] >= obj->getAABB().min_[axis2])) - { - if((obj->getAABB().max_[axis3] >= obj2->getAABB().min_[axis3]) && (obj2->getAABB().max_[axis3] >= obj->getAABB().min_[axis3])) - { - if(callback(obj, obj2, cdata)) - return; - } - } - - if(run_pos2 == pos_end) break; - } - } - } -} - - -void SSaPCollisionManager::distance(void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - std::vector<CollisionObject*>::const_iterator it, it_end; - size_t axis = selectOptimalAxis(objs_x, objs_y, objs_z, it, it_end); - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - for(; it != it_end; ++it) - { - if(distance_(*it, cdata, callback, min_dist)) - return; - } -} - -void SSaPCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const -{ - SSaPCollisionManager* other_manager = static_cast<SSaPCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - collide(cdata, callback); - return; - } - - - std::vector<CollisionObject*>::const_iterator it, end; - if(this->size() < other_manager->size()) - { - for(it = objs_x.begin(), end = objs_x.end(); it != end; ++it) - if(other_manager->collide_(*it, cdata, callback)) return; - } - else - { - for(it = other_manager->objs_x.begin(), end != other_manager->objs_x.end(); it != end; ++it) - if(collide_(*it, cdata, callback)) return; - } -} - -void SSaPCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const -{ - SSaPCollisionManager* other_manager = static_cast<SSaPCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - distance(cdata, callback); - return; - } - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - std::vector<CollisionObject*>::const_iterator it, end; - if(this->size() < other_manager->size()) - { - for(it = objs_x.begin(), end = objs_x.end(); it != end; ++it) - if(other_manager->distance_(*it, cdata, callback, min_dist)) return; - } - else - { - for(it = other_manager->objs_x.begin(), end = other_manager->objs_x.end(); it != end; ++it) - if(distance_(*it, cdata, callback, min_dist)) return; - } -} - -bool SSaPCollisionManager::empty() const -{ - return objs_x.empty(); -} - - -void SaPCollisionManager::unregisterObject(CollisionObject* obj) -{ - std::list<SaPAABB*>::iterator it = AABB_arr.begin(); - for(std::list<SaPAABB*>::iterator end = AABB_arr.end(); it != end; ++it) - { - if((*it)->obj == obj) - break; - } - - AABB_arr.erase(it); - obj_aabb_map.erase(obj); - - if(it == AABB_arr.end()) - return; - - SaPAABB* curr = *it; - *it = NULL; - - for(int coord = 0; coord < 3; ++coord) - { - //first delete the lo endpoint of the interval. - if(curr->lo->prev[coord] == NULL) - elist[coord] = curr->lo->next[coord]; - else - curr->lo->prev[coord]->next[coord] = curr->lo->next[coord]; - - curr->lo->next[coord]->prev[coord] = curr->lo->prev[coord]; - - //then, delete the "hi" endpoint. - if(curr->hi->prev[coord] == NULL) - elist[coord] = curr->hi->next[coord]; - else - curr->hi->prev[coord]->next[coord] = curr->hi->next[coord]; - - if(curr->hi->next[coord] != NULL) - curr->hi->next[coord]->prev[coord] = curr->hi->prev[coord]; - } - - delete curr->lo; - delete curr->hi; - delete curr; - - overlap_pairs.remove_if(isUnregistered(obj)); -} - -void SaPCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) -{ - if(size() > 0) - BroadPhaseCollisionManager::registerObjects(other_objs); - else - { - std::vector<EndPoint*> endpoints(2 * other_objs.size()); - - for(size_t i = 0; i < other_objs.size(); ++i) - { - SaPAABB* sapaabb = new SaPAABB(); - sapaabb->obj = other_objs[i]; - sapaabb->lo = new EndPoint(); - sapaabb->hi = new EndPoint(); - sapaabb->cached = other_objs[i]->getAABB(); - endpoints[2 * i] = sapaabb->lo; - endpoints[2 * i + 1] = sapaabb->hi; - sapaabb->lo->minmax = 0; - sapaabb->hi->minmax = 1; - sapaabb->lo->aabb = sapaabb; - sapaabb->hi->aabb = sapaabb; - AABB_arr.push_back(sapaabb); - obj_aabb_map[other_objs[i]] = sapaabb; - } - - - FCL_REAL scale[3]; - for(size_t coord = 0; coord < 3; ++coord) - { - std::sort(endpoints.begin(), endpoints.end(), - boost::bind(std::less<FCL_REAL>(), - boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const >(&EndPoint::getVal), _1, coord), - boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const >(&EndPoint::getVal), _2, coord))); - - endpoints[0]->prev[coord] = NULL; - endpoints[0]->next[coord] = endpoints[1]; - for(int i = 1; i < endpoints.size() - 1; ++i) - { - endpoints[i]->prev[coord] = endpoints[i-1]; - endpoints[i]->next[coord] = endpoints[i+1]; - } - endpoints[endpoints.size() - 1]->prev[coord] = endpoints[endpoints.size() - 2]; - endpoints[endpoints.size() - 1]->next[coord] = NULL; - - elist[coord] = endpoints[0]; - - scale[coord] = endpoints.back()->aabb->cached.max_[coord] - endpoints[0]->aabb->cached.min_[coord]; - } - - int axis = 0; - if(scale[axis] < scale[1]) axis = 1; - if(scale[axis] < scale[2]) axis = 2; - - EndPoint* pos = elist[axis]; - - while(pos != NULL) - { - EndPoint* pos_next = NULL; - SaPAABB* aabb = pos->aabb; - EndPoint* pos_it = pos->next[axis]; - - while(pos_it != NULL) - { - if(pos_it->aabb == aabb) - { - if(pos_next == NULL) pos_next = pos_it; - break; - } - - if(pos_it->minmax == 0) - { - if(pos_next == NULL) pos_next = pos_it; - if(pos_it->aabb->cached.overlap(aabb->cached)) - overlap_pairs.push_back(SaPPair(pos_it->aabb->obj, aabb->obj)); - } - pos_it = pos_it->next[axis]; - } - - pos = pos_next; - } - } - - updateVelist(); -} - -void SaPCollisionManager::registerObject(CollisionObject* obj) -{ - SaPAABB* curr = new SaPAABB; - curr->cached = obj->getAABB(); - curr->obj = obj; - curr->lo = new EndPoint; - curr->lo->minmax = 0; - curr->lo->aabb = curr; - - curr->hi = new EndPoint; - curr->hi->minmax = 1; - curr->hi->aabb = curr; - - for(int coord = 0; coord < 3; ++coord) - { - EndPoint* current = elist[coord]; - - // first insert the lo end point - if(current == NULL) // empty list - { - elist[coord] = curr->lo; - curr->lo->prev[coord] = curr->lo->next[coord] = NULL; - } - else // otherwise, find the correct location in the list and insert - { - EndPoint* curr_lo = curr->lo; - FCL_REAL curr_lo_val = curr_lo->getVal()[coord]; - while((current->getVal()[coord] < curr_lo_val) && (current->next[coord] != NULL)) - current = current->next[coord]; - - if(current->getVal()[coord] >= curr_lo_val) - { - curr_lo->prev[coord] = current->prev[coord]; - curr_lo->next[coord] = current; - if(current->prev[coord] == NULL) - elist[coord] = curr_lo; - else - current->prev[coord]->next[coord] = curr_lo; - - current->prev[coord] = curr_lo; - } - else - { - curr_lo->prev[coord] = current; - curr_lo->next[coord] = NULL; - current->next[coord] = curr_lo; - } - } - - // now insert hi end point - current = curr->lo; - - EndPoint* curr_hi = curr->hi; - FCL_REAL curr_hi_val = curr_hi->getVal()[coord]; - - if(coord == 0) - { - while((current->getVal()[coord] < curr_hi_val) && (current->next[coord] != NULL)) - { - if(current != curr->lo) - if(current->aabb->cached.overlap(curr->cached)) - overlap_pairs.push_back(SaPPair(current->aabb->obj, obj)); - - current = current->next[coord]; - } - } - else - { - while((current->getVal()[coord] < curr_hi_val) && (current->next[coord] != NULL)) - current = current->next[coord]; - } - - if(current->getVal()[coord] >= curr_hi_val) - { - curr_hi->prev[coord] = current->prev[coord]; - curr_hi->next[coord] = current; - if(current->prev[coord] == NULL) - elist[coord] = curr_hi; - else - current->prev[coord]->next[coord] = curr_hi; - - current->prev[coord] = curr_hi; - } - else - { - curr_hi->prev[coord] = current; - curr_hi->next[coord] = NULL; - current->next[coord] = curr_hi; - } - } - - AABB_arr.push_back(curr); - - obj_aabb_map[obj] = curr; - - updateVelist(); -} - -void SaPCollisionManager::setup() -{ - FCL_REAL scale[3]; - scale[0] = (velist[0].back())->getVal(0) - velist[0][0]->getVal(0); - scale[1] = (velist[1].back())->getVal(1) - velist[1][0]->getVal(1);; - scale[2] = (velist[2].back())->getVal(2) - velist[2][0]->getVal(2); - size_t axis = 0; - if(scale[axis] < scale[1]) axis = 1; - if(scale[axis] < scale[2]) axis = 2; - optimal_axis = axis; -} - -void SaPCollisionManager::update_(SaPAABB* updated_aabb) -{ - if(updated_aabb->cached.equal(updated_aabb->obj->getAABB())) - return; - - SaPAABB* current = updated_aabb; - - Vec3f new_min = current->obj->getAABB().min_; - Vec3f new_max = current->obj->getAABB().max_; - - SaPAABB dummy; - dummy.cached = current->obj->getAABB(); - - for(int coord = 0; coord < 3; ++coord) - { - int direction; // -1 reverse, 0 nochange, 1 forward - EndPoint* temp; - - if(current->lo->getVal(coord) > new_min[coord]) - direction = -1; - else if(current->lo->getVal(coord) < new_min[coord]) - direction = 1; - else direction = 0; - - if(direction == -1) - { - //first update the "lo" endpoint of the interval - if(current->lo->prev[coord] != NULL) - { - temp = current->lo; - while((temp != NULL) && (temp->getVal(coord) > new_min[coord])) - { - if(temp->minmax == 1) - if(temp->aabb->cached.overlap(dummy.cached)) - addToOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); - temp = temp->prev[coord]; - } - - if(temp == NULL) - { - current->lo->prev[coord]->next[coord] = current->lo->next[coord]; - current->lo->next[coord]->prev[coord] = current->lo->prev[coord]; - current->lo->prev[coord] = NULL; - current->lo->next[coord] = elist[coord]; - elist[coord]->prev[coord] = current->lo; - elist[coord] = current->lo; - } - else - { - current->lo->prev[coord]->next[coord] = current->lo->next[coord]; - current->lo->next[coord]->prev[coord] = current->lo->prev[coord]; - current->lo->prev[coord] = temp; - current->lo->next[coord] = temp->next[coord]; - temp->next[coord]->prev[coord] = current->lo; - temp->next[coord] = current->lo; - } - } - - current->lo->getVal(coord) = new_min[coord]; - - // update hi end point - temp = current->hi; - while(temp->getVal(coord) > new_max[coord]) - { - if((temp->minmax == 0) && (temp->aabb->cached.overlap(current->cached))) - removeFromOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); - temp = temp->prev[coord]; - } - - current->hi->prev[coord]->next[coord] = current->hi->next[coord]; - if(current->hi->next[coord] != NULL) - current->hi->next[coord]->prev[coord] = current->hi->prev[coord]; - current->hi->prev[coord] = temp; - current->hi->next[coord] = temp->next[coord]; - if(temp->next[coord] != NULL) - temp->next[coord]->prev[coord] = current->hi; - temp->next[coord] = current->hi; - - current->hi->getVal(coord) = new_max[coord]; - } - else if(direction == 1) - { - //here, we first update the "hi" endpoint. - if(current->hi->next[coord] != NULL) - { - temp = current->hi; - while((temp->next[coord] != NULL) && (temp->getVal(coord) < new_max[coord])) - { - if(temp->minmax == 0) - if(temp->aabb->cached.overlap(dummy.cached)) - addToOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); - temp = temp->next[coord]; - } - - if(temp->getVal(coord) < new_max[coord]) - { - current->hi->prev[coord]->next[coord] = current->hi->next[coord]; - current->hi->next[coord]->prev[coord] = current->hi->prev[coord]; - current->hi->prev[coord] = temp; - current->hi->next[coord] = NULL; - temp->next[coord] = current->hi; - } - else - { - current->hi->prev[coord]->next[coord] = current->hi->next[coord]; - current->hi->next[coord]->prev[coord] = current->hi->prev[coord]; - current->hi->prev[coord] = temp->prev[coord]; - current->hi->next[coord] = temp; - temp->prev[coord]->next[coord] = current->hi; - temp->prev[coord] = current->hi; - } - } - - current->hi->getVal(coord) = new_max[coord]; - - //then, update the "lo" endpoint of the interval. - temp = current->lo; - - while(temp->getVal(coord) < new_min[coord]) - { - if((temp->minmax == 1) && (temp->aabb->cached.overlap(current->cached))) - removeFromOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); - temp = temp->next[coord]; - } - - if(current->lo->prev[coord] != NULL) - current->lo->prev[coord]->next[coord] = current->lo->next[coord]; - else - elist[coord] = current->lo->next[coord]; - current->lo->next[coord]->prev[coord] = current->lo->prev[coord]; - current->lo->prev[coord] = temp->prev[coord]; - current->lo->next[coord] = temp; - if(temp->prev[coord] != NULL) - temp->prev[coord]->next[coord] = current->lo; - else - elist[coord] = current->lo; - temp->prev[coord] = current->lo; - current->lo->getVal(coord) = new_min[coord]; - } - } -} - -void SaPCollisionManager::update(CollisionObject* updated_obj) -{ - update_(obj_aabb_map[updated_obj]); - - updateVelist(); - - setup(); -} - -void SaPCollisionManager::update(const std::vector<CollisionObject*>& updated_objs) -{ - for(size_t i = 0; i < updated_objs.size(); ++i) - update_(obj_aabb_map[updated_objs[i]]); - - updateVelist(); - - setup(); -} - -void SaPCollisionManager::update() -{ - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it) - { - update_(*it); - } - - updateVelist(); - - setup(); -} - - -void SaPCollisionManager::clear() -{ - for(std::list<SaPAABB*>::iterator it = AABB_arr.begin(), end = AABB_arr.end(); - it != end; - ++it) - { - delete (*it)->hi; - delete (*it)->lo; - delete *it; - *it = NULL; - } - - AABB_arr.clear(); - overlap_pairs.clear(); - - elist[0] = NULL; - elist[1] = NULL; - elist[2] = NULL; - - velist[0].clear(); - velist[1].clear(); - velist[2].clear(); - - obj_aabb_map.clear(); -} - -void SaPCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const -{ - objs.resize(AABB_arr.size()); - int i = 0; - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it, ++i) - { - objs[i] = (*it)->obj; - } -} - -bool SaPCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - size_t axis = optimal_axis; - const AABB& obj_aabb = obj->getAABB(); - - FCL_REAL min_val = obj_aabb.min_[axis]; - FCL_REAL max_val = obj_aabb.max_[axis]; - - EndPoint dummy; - SaPAABB dummy_aabb; - dummy_aabb.cached = obj_aabb; - dummy.minmax = 1; - dummy.aabb = &dummy_aabb; - - // 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<FCL_REAL>(), - boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _1, axis), - boost::bind(static_cast<FCL_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 = elist[axis]; - - while(pos != end_pos) - { - if(pos->aabb->obj != obj) - { - if((pos->minmax == 0) && (pos->aabb->hi->getVal(axis) >= min_val)) - { - 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, FCL_REAL& min_dist) const -{ - Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; - AABB aabb = obj->getAABB(); - - if(min_dist < std::numeric_limits<FCL_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; - FCL_REAL old_min_distance; - - EndPoint* start_pos = elist[axis]; - - while(1) - { - old_min_distance = min_dist; - FCL_REAL min_val = aabb.min_[axis]; - FCL_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<FCL_REAL>(), - boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _1, axis), - boost::bind(static_cast<FCL_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) - { - // 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(curr_obj != obj) - { - if(!enable_tested_set_) - { - if(pos->aabb->cached.distance(obj->getAABB()) < min_dist) - { - if(callback(curr_obj, obj, cdata, min_dist)) - return true; - } - } - else - { - if(!inTestedSet(curr_obj, obj)) - { - if(pos->aabb->cached.distance(obj->getAABB()) < min_dist) - { - if(callback(curr_obj, obj, cdata, min_dist)) - return true; - } - - insertTestedSet(curr_obj, obj); - } - } - } - } - - pos = pos->next[axis]; - } - - if(status == 1) - { - if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) - break; - 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; - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - distance_(obj, cdata, callback, min_dist); -} - -void SaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - for(std::list<SaPPair>::const_iterator it = overlap_pairs.begin(), end = overlap_pairs.end(); it != end; ++it) - { - CollisionObject* obj1 = it->obj1; - CollisionObject* obj2 = it->obj2; - - if(callback(obj1, obj2, cdata)) - return; - } -} - -void SaPCollisionManager::distance(void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - enable_tested_set_ = true; - tested_set.clear(); - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it) - { - if(distance_((*it)->obj, cdata, callback, min_dist)) - break; - } - - enable_tested_set_ = false; - tested_set.clear(); -} - -void SaPCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const -{ - SaPCollisionManager* other_manager = static_cast<SaPCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - collide(cdata, callback); - return; - } - - if(this->size() < other_manager->size()) - { - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it) - { - if(other_manager->collide_((*it)->obj, cdata, callback)) - return; - } - } - else - { - for(std::list<SaPAABB*>::const_iterator it = other_manager->AABB_arr.begin(), end = other_manager->AABB_arr.end(); it != end; ++it) - { - if(collide_((*it)->obj, cdata, callback)) - return; - } - } -} - -void SaPCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const -{ - SaPCollisionManager* other_manager = static_cast<SaPCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - distance(cdata, callback); - return; - } - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - if(this->size() < other_manager->size()) - { - for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it) - { - if(other_manager->distance_((*it)->obj, cdata, callback, min_dist)) - return; - } - } - else - { - for(std::list<SaPAABB*>::const_iterator it = other_manager->AABB_arr.begin(), end = other_manager->AABB_arr.end(); it != end; ++it) - { - if(distance_((*it)->obj, cdata, callback, min_dist)) - return; - } - } -} - -bool SaPCollisionManager::empty() const -{ - return AABB_arr.size(); -} - - - -void IntervalTreeCollisionManager::unregisterObject(CollisionObject* obj) -{ - // must sorted before - setup(); - - EndPoint p; - p.value = obj->getAABB().min_[0]; - 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, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); - - if(start1 < end1) - { - unsigned int start_id = start1 - endpoints[0].begin(); - unsigned int end_id = end1 - endpoints[0].begin(); - unsigned int cur_id = start_id; - for(unsigned int i = start_id; i < end_id; ++i) - { - if(endpoints[0][i].obj != obj) - { - if(i == cur_id) cur_id++; - else - { - endpoints[0][cur_id] = endpoints[0][i]; - cur_id++; - } - } - } - if(cur_id < end_id) - endpoints[0].resize(endpoints[0].size() - 2); - } - - p.value = obj->getAABB().min_[1]; - 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, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); - - if(start2 < end2) - { - unsigned int start_id = start2 - endpoints[1].begin(); - unsigned int end_id = end2 - endpoints[1].begin(); - unsigned int cur_id = start_id; - for(unsigned int i = start_id; i < end_id; ++i) - { - if(endpoints[1][i].obj != obj) - { - if(i == cur_id) cur_id++; - else - { - endpoints[1][cur_id] = endpoints[1][i]; - cur_id++; - } - } - } - if(cur_id < end_id) - endpoints[1].resize(endpoints[1].size() - 2); - } - - - p.value = obj->getAABB().min_[2]; - 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, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); - - if(start3 < end3) - { - unsigned int start_id = start3 - endpoints[2].begin(); - unsigned int end_id = end3 - endpoints[2].begin(); - unsigned int cur_id = start_id; - for(unsigned int i = start_id; i < end_id; ++i) - { - if(endpoints[2][i].obj != obj) - { - if(i == cur_id) cur_id++; - else - { - endpoints[2][cur_id] = endpoints[2][i]; - cur_id++; - } - } - } - if(cur_id < end_id) - endpoints[2].resize(endpoints[2].size() - 2); - } - - // update the interval tree - if(obj_interval_maps[0].find(obj) != obj_interval_maps[0].end()) - { - SAPInterval* ivl1 = obj_interval_maps[0][obj]; - SAPInterval* ivl2 = obj_interval_maps[1][obj]; - SAPInterval* ivl3 = obj_interval_maps[2][obj]; - - interval_trees[0]->deleteNode(ivl1); - interval_trees[1]->deleteNode(ivl2); - interval_trees[2]->deleteNode(ivl3); - - delete ivl1; - delete ivl2; - delete ivl3; - - obj_interval_maps[0].erase(obj); - obj_interval_maps[1].erase(obj); - obj_interval_maps[2].erase(obj); - } -} - -void IntervalTreeCollisionManager::registerObject(CollisionObject* obj) -{ - EndPoint p, q; - - p.obj = obj; - q.obj = obj; - p.minmax = 0; - q.minmax = 1; - p.value = obj->getAABB().min_[0]; - q.value = obj->getAABB().max_[0]; - endpoints[0].push_back(p); - endpoints[0].push_back(q); - - p.value = obj->getAABB().min_[1]; - q.value = obj->getAABB().max_[1]; - endpoints[1].push_back(p); - endpoints[1].push_back(q); - - p.value = obj->getAABB().min_[2]; - q.value = obj->getAABB().max_[2]; - endpoints[2].push_back(p); - endpoints[2].push_back(q); - setup_ = false; -} - -void IntervalTreeCollisionManager::setup() -{ - if(!setup_) - { - 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]; - - for(int i = 0; i < 3; ++i) - interval_trees[i] = new IntervalTree; - - for(unsigned int i = 0, size = endpoints[0].size(); i < size; ++i) - { - EndPoint p = endpoints[0][i]; - CollisionObject* obj = p.obj; - if(p.minmax == 0) - { - SAPInterval* ivl1 = new SAPInterval(obj->getAABB().min_[0], obj->getAABB().max_[0], obj); - SAPInterval* ivl2 = new SAPInterval(obj->getAABB().min_[1], obj->getAABB().max_[1], obj); - SAPInterval* ivl3 = new SAPInterval(obj->getAABB().min_[2], obj->getAABB().max_[2], obj); - - interval_trees[0]->insert(ivl1); - interval_trees[1]->insert(ivl2); - interval_trees[2]->insert(ivl3); - - obj_interval_maps[0][obj] = ivl1; - obj_interval_maps[1][obj] = ivl2; - obj_interval_maps[2][obj] = ivl3; - } - } - - setup_ = true; - } -} - -void IntervalTreeCollisionManager::update() -{ - setup_ = false; - - for(unsigned int i = 0, size = endpoints[0].size(); i < size; ++i) - { - if(endpoints[0][i].minmax == 0) - endpoints[0][i].value = endpoints[0][i].obj->getAABB().min_[0]; - else - endpoints[0][i].value = endpoints[0][i].obj->getAABB().max_[0]; - } - - for(unsigned int i = 0, size = endpoints[1].size(); i < size; ++i) - { - if(endpoints[1][i].minmax == 0) - endpoints[1][i].value = endpoints[1][i].obj->getAABB().min_[1]; - else - endpoints[1][i].value = endpoints[1][i].obj->getAABB().max_[1]; - } - - for(unsigned int i = 0, size = endpoints[2].size(); i < size; ++i) - { - if(endpoints[2][i].minmax == 0) - endpoints[2][i].value = endpoints[2][i].obj->getAABB().min_[2]; - else - endpoints[2][i].value = endpoints[2][i].obj->getAABB().max_[2]; - } - - setup(); - -} - - -void IntervalTreeCollisionManager::update(CollisionObject* updated_obj) -{ - AABB old_aabb; - const AABB& new_aabb = updated_obj->getAABB(); - for(int i = 0; i < 3; ++i) - { - std::map<CollisionObject*, SAPInterval*>::const_iterator it = obj_interval_maps[i].find(updated_obj); - interval_trees[i]->deleteNode(it->second); - old_aabb.min_[i] = it->second->low; - old_aabb.max_[i] = it->second->high; - it->second->low = new_aabb.min_[i]; - it->second->high = new_aabb.max_[i]; - interval_trees[i]->insert(it->second); - } - - EndPoint dummy; - std::vector<EndPoint>::iterator it; - for(int i = 0; i < 3; ++i) - { - dummy.value = old_aabb.min_[i]; - it = std::lower_bound(endpoints[i].begin(), endpoints[i].end(), dummy, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); - for(; it != endpoints[i].end(); ++it) - { - if(it->obj == updated_obj && it->minmax == 0) - { - it->value = new_aabb.min_[i]; - break; - } - } - - dummy.value = old_aabb.max_[i]; - it = std::lower_bound(endpoints[i].begin(), endpoints[i].end(), dummy, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); - for(; it != endpoints[i].end(); ++it) - { - if(it->obj == updated_obj && it->minmax == 0) - { - it->value = new_aabb.max_[i]; - break; - } - } - - std::sort(endpoints[i].begin(), endpoints[i].end(), boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); - } -} - -void IntervalTreeCollisionManager::update(const std::vector<CollisionObject*>& updated_objs) -{ - for(size_t i = 0; i < updated_objs.size(); ++i) - update(updated_objs[i]); -} - -void IntervalTreeCollisionManager::clear() -{ - endpoints[0].clear(); - endpoints[1].clear(); - endpoints[2].clear(); - - delete interval_trees[0]; interval_trees[0] = NULL; - delete interval_trees[1]; interval_trees[1] = NULL; - delete interval_trees[2]; interval_trees[2] = NULL; - - for(int i = 0; i < 3; ++i) - { - for(std::map<CollisionObject*, SAPInterval*>::const_iterator it = obj_interval_maps[i].begin(), end = obj_interval_maps[i].end(); - it != end; ++it) - { - delete it->second; - } - } - - for(int i = 0; i < 3; ++i) - obj_interval_maps[i].clear(); - - setup_ = false; -} - -void IntervalTreeCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const -{ - objs.resize(endpoints[0].size() / 2); - unsigned int j = 0; - for(unsigned int i = 0, size = endpoints[0].size(); i < size; ++i) - { - if(endpoints[0][i].minmax == 0) - { - objs[j] = endpoints[0][i].obj; j++; - } - } -} - -void IntervalTreeCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - collide_(obj, cdata, callback); -} - -bool IntervalTreeCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - static const unsigned int CUTOFF = 100; - - std::deque<SimpleInterval*> results0, results1, results2; - - results0 = interval_trees[0]->query(obj->getAABB().min_[0], obj->getAABB().max_[0]); - if(results0.size() > CUTOFF) - { - results1 = interval_trees[1]->query(obj->getAABB().min_[1], obj->getAABB().max_[1]); - if(results1.size() > CUTOFF) - { - results2 = interval_trees[2]->query(obj->getAABB().min_[2], obj->getAABB().max_[2]); - if(results2.size() > CUTOFF) - { - int d1 = results0.size(); - int d2 = results1.size(); - int d3 = results2.size(); - - if(d1 >= d2 && d1 >= d3) - return checkColl(results0.begin(), results0.end(), obj, cdata, callback); - else if(d2 >= d1 && d2 >= d3) - return checkColl(results1.begin(), results1.end(), obj, cdata, callback); - else - return checkColl(results2.begin(), results2.end(), obj, cdata, callback); - } - else - return checkColl(results2.begin(), results2.end(), obj, cdata, callback); - } - else - return checkColl(results1.begin(), results1.end(), obj, cdata, callback); - } - else - return checkColl(results0.begin(), results0.end(), obj, cdata, callback); -} - -void IntervalTreeCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - distance_(obj, cdata, callback, min_dist); -} - -bool IntervalTreeCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - static const unsigned int CUTOFF = 100; - - Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; - AABB aabb = obj->getAABB(); - if(min_dist < std::numeric_limits<FCL_REAL>::max()) - { - Vec3f min_dist_delta(min_dist, min_dist, min_dist); - aabb.expand(min_dist_delta); - } - - int status = 1; - FCL_REAL old_min_distance; - - while(1) - { - bool dist_res = false; - - old_min_distance = min_dist; - - std::deque<SimpleInterval*> results0, results1, results2; - - results0 = interval_trees[0]->query(aabb.min_[0], aabb.max_[0]); - if(results0.size() > CUTOFF) - { - results1 = interval_trees[1]->query(aabb.min_[1], aabb.max_[1]); - if(results1.size() > CUTOFF) - { - results2 = interval_trees[2]->query(aabb.min_[2], aabb.max_[2]); - if(results2.size() > CUTOFF) - { - int d1 = results0.size(); - int d2 = results1.size(); - int d3 = results2.size(); - - if(d1 >= d2 && d1 >= d3) - dist_res = checkDist(results0.begin(), results0.end(), obj, cdata, callback, min_dist); - else if(d2 >= d1 && d2 >= d3) - dist_res = checkDist(results1.begin(), results1.end(), obj, cdata, callback, min_dist); - else - dist_res = checkDist(results2.begin(), results2.end(), obj, cdata, callback, min_dist); - } - else - dist_res = checkDist(results2.begin(), results2.end(), obj, cdata, callback, min_dist); - } - else - dist_res = checkDist(results1.begin(), results1.end(), obj, cdata, callback, min_dist); - } - else - dist_res = checkDist(results0.begin(), results0.end(), obj, cdata, callback, min_dist); - - if(dist_res) return true; - - results0.clear(); - results1.clear(); - results2.clear(); - - if(status == 1) - { - if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) - break; - 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 IntervalTreeCollisionManager::collide(void* cdata, CollisionCallBack callback) const -{ - if(size() == 0) return; - - std::set<CollisionObject*> active; - std::set<std::pair<CollisionObject*, CollisionObject*> > overlap; - unsigned int n = endpoints[0].size(); - double diff_x = endpoints[0][0].value - endpoints[0][n-1].value; - double diff_y = endpoints[1][0].value - endpoints[1][n-1].value; - double diff_z = endpoints[2][0].value - endpoints[2][n-1].value; - - int axis = 0; - if(diff_y > diff_x && diff_y > diff_z) - axis = 1; - else if(diff_z > diff_y && diff_z > diff_x) - axis = 2; - - for(unsigned int i = 0; i < n; ++i) - { - const EndPoint& endpoint = endpoints[axis][i]; - CollisionObject* index = endpoint.obj; - if(endpoint.minmax == 0) - { - std::set<CollisionObject*>::iterator iter = active.begin(); - std::set<CollisionObject*>::iterator end = active.end(); - for(; iter != end; ++iter) - { - CollisionObject* active_index = *iter; - const AABB& b0 = active_index->getAABB(); - const AABB& b1 = index->getAABB(); - - int axis2 = (axis + 1) % 3; - int axis3 = (axis + 2) % 3; - - if(b0.axisOverlap(b1, axis2) && b0.axisOverlap(b1, axis3)) - { - std::pair<std::set<std::pair<CollisionObject*, CollisionObject*> >::iterator, bool> insert_res; - if(active_index < index) - insert_res = overlap.insert(std::make_pair(active_index, index)); - else - insert_res = overlap.insert(std::make_pair(index, active_index)); - - if(insert_res.second) - { - if(callback(active_index, index, cdata)) - return; - } - } - } - active.insert(index); - } - else - active.erase(index); - } - -} - -void IntervalTreeCollisionManager::distance(void* cdata, DistanceCallBack callback) const -{ - if(size() == 0) return; - - enable_tested_set_ = true; - tested_set.clear(); - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - for(size_t i = 0; i < endpoints[0].size(); ++i) - if(distance_(endpoints[0][i].obj, cdata, callback, min_dist)) break; - - enable_tested_set_ = false; - tested_set.clear(); -} - -void IntervalTreeCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const -{ - IntervalTreeCollisionManager* other_manager = static_cast<IntervalTreeCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - collide(cdata, callback); - return; - } - - if(this->size() < other_manager->size()) - { - for(size_t i = 0, size = endpoints[0].size(); i < size; ++i) - if(other_manager->collide_(endpoints[0][i].obj, cdata, callback)) return; - } - else - { - for(size_t i = 0, size = other_manager->endpoints[0].size(); i < size; ++i) - if(collide_(other_manager->endpoints[0][i].obj, cdata, callback)) return; - } -} - -void IntervalTreeCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const -{ - IntervalTreeCollisionManager* other_manager = static_cast<IntervalTreeCollisionManager*>(other_manager_); - - if((size() == 0) || (other_manager->size() == 0)) return; - - if(this == other_manager) - { - distance(cdata, callback); - return; - } - - FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); - - if(this->size() < other_manager->size()) - { - for(size_t i = 0, size = endpoints[0].size(); i < size; ++i) - if(other_manager->distance_(endpoints[0][i].obj, cdata, callback, min_dist)) return; - } - else - { - for(size_t i = 0, size = other_manager->endpoints[0].size(); i < size; ++i) - if(distance_(other_manager->endpoints[0][i].obj, cdata, callback, min_dist)) return; - } -} - -bool IntervalTreeCollisionManager::empty() const -{ - return endpoints[0].empty(); -} - -bool IntervalTreeCollisionManager::checkColl(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, CollisionCallBack callback) const -{ - while(pos_start < pos_end) - { - SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start); - if(ivl->obj != obj) - { - if(ivl->obj->getAABB().overlap(obj->getAABB())) - { - if(callback(ivl->obj, obj, cdata)) - return true; - } - } - - pos_start++; - } - - return false; -} - -bool IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - while(pos_start < pos_end) - { - SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start); - if(ivl->obj != obj) - { - if(!enable_tested_set_) - { - if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) - { - if(callback(ivl->obj, obj, cdata, min_dist)) - return true; - } - } - else - { - if(!inTestedSet(ivl->obj, obj)) - { - if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) - { - if(callback(ivl->obj, obj, cdata, min_dist)) - return true; - } - - insertTestedSet(ivl->obj, obj); - } - } - } - - pos_start++; - } - - return false; -} - -void DynamicAABBTreeCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) -{ - if(size() > 0) - { - BroadPhaseCollisionManager::registerObjects(other_objs); - } - else - { - std::vector<DynamicAABBNode*> leaves(other_objs.size()); - table.rehash(other_objs.size()); - for(size_t i = 0, size = other_objs.size(); i < size; ++i) - { - DynamicAABBNode* node = new DynamicAABBNode; // node will be managed by the dtree - 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.init(leaves, tree_init_level); - - 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_) - { - int num = dtree.size(); - if(num == 0) - { - setup_ = true; - return; - } - - int height = dtree.getMaxHeight(); - - - if(height - std::log((FCL_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level) - dtree.balanceIncremental(tree_incremental_balance_pass); - else - dtree.balanceTopdown(); - - setup_ = true; - } -} - - -void DynamicAABBTreeCollisionManager::update() -{ - for(DynamicAABBTable::const_iterator it = table.begin(); it != table.end(); ++it) - { - CollisionObject* obj = it->first; - DynamicAABBNode* node = it->second; - node->bv = obj->getAABB(); - } - - dtree.refit(); - setup_ = false; - - setup(); -} - -void DynamicAABBTreeCollisionManager::update_(CollisionObject* updated_obj) -{ - DynamicAABBTable::const_iterator it = table.find(updated_obj); - if(it != table.end()) - { - DynamicAABBNode* node = it->second; - if(!node->bv.equal(updated_obj->getAABB())) - dtree.update(node, updated_obj->getAABB()); - } - setup_ = false; -} - -void DynamicAABBTreeCollisionManager::update(CollisionObject* updated_obj) -{ - update_(updated_obj); - setup(); -} - -void DynamicAABBTreeCollisionManager::update(const std::vector<CollisionObject*>& updated_objs) -{ - for(size_t i = 0, size = updated_objs.size(); i < size; ++i) - update_(updated_objs[i]); - setup(); -} - -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, FCL_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()))) - { - FCL_REAL d1 = root2->bv.distance(root1->childs[0]->bv); - FCL_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 - { - FCL_REAL d1 = root1->bv.distance(root2->childs[0]->bv); - FCL_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, FCL_REAL& min_dist) const -{ - if(root->isLeaf()) - { - CollisionObject* root_obj = static_cast<CollisionObject*>(root->data); - return callback(root_obj, query, cdata, min_dist); - } - - FCL_REAL d1 = query->getAABB().distance(root->childs[0]->bv); - FCL_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, FCL_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; -} - - -bool collisionRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) -{ - if(root1->isLeaf() && !root2->hasChildren()) - { - CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); - - if(!tree2->isNodeFree(root2) && !obj1->isFree()) - { - OBB obb1, obb2; - convertBV(root1->bv, Transform3f(), obb1); - convertBV(root2_bv, tf2, obb2); - - if(obb1.overlap(obb2)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - - box->cost_density = root2->getOccupancy(); - box->threshold_occupied = tree2->getOccupancyThres(); - - CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(obj1, &obj2, cdata); - } - else return false; - } - else return false; - } - - OBB obb1, obb2; - convertBV(root1->bv, Transform3f(), obb1); - convertBV(root2_bv, tf2, obb2); - - if(tree2->isNodeFree(root2) || !obb1.overlap(obb2)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - if(collisionRecurse_(root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - if(collisionRecurse_(root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - if(collisionRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback)) - return true; - } - } - } - return false; -} - -bool collisionRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, CollisionCallBack callback) -{ - if(root1->isLeaf() && !root2->hasChildren()) - { - CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); - - if(!tree2->isNodeFree(root2) && !obj1->isFree()) - { - const AABB& root2_bv_t = translate(root2_bv, tf2); - if(root1->bv.overlap(root2_bv_t)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - - box->cost_density = root2->getOccupancy(); - box->threshold_occupied = tree2->getOccupancyThres(); - - CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(obj1, &obj2, cdata); - } - else return false; - } - else return false; - } - - const AABB& root2_bv_t = translate(root2_bv, tf2); - if(tree2->isNodeFree(root2) || !root1->bv.overlap(root2_bv_t)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - if(collisionRecurse_(root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - if(collisionRecurse_(root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - if(collisionRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback)) - return true; - } - } - } - return false; -} - - - -bool DynamicAABBTreeCollisionManager::collisionRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) const -{ - if(tf2.getQuatRotation().isIdentity()) - return collisionRecurse_(root1, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback); - else // has rotation - return collisionRecurse_(root1, tree2, root2, root2_bv, tf2, cdata, callback); -} - - -bool distanceRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) -{ - if(root1->isLeaf() && !root2->hasChildren()) - { - if(tree2->isNodeOccupied(root2)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); - } - else return false; - } - - if(!tree2->isNodeOccupied(root2)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - const AABB& aabb2 = translate(root2_bv, tf2); - FCL_REAL d1 = aabb2.distance(root1->childs[0]->bv); - FCL_REAL d2 = aabb2.distance(root1->childs[1]->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse_(root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse_(root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse_(root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse_(root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - const AABB& aabb2 = translate(child_bv, tf2); - - FCL_REAL d = root1->bv.distance(aabb2); - - if(d < min_dist) - { - if(distanceRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - } - - return false; -} - - -bool distanceRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) -{ - if(root1->isLeaf() && !root2->hasChildren()) - { - if(tree2->isNodeOccupied(root2)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); - } - else return false; - } - - if(!tree2->isNodeOccupied(root2)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - AABB aabb2; - convertBV(root2_bv, tf2, aabb2); - - FCL_REAL d1 = aabb2.distance(root1->childs[0]->bv); - FCL_REAL d2 = aabb2.distance(root1->childs[1]->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse_(root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse_(root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse_(root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse_(root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - AABB aabb2; - convertBV(child_bv, tf2, aabb2); - FCL_REAL d = root1->bv.distance(aabb2); - - if(d < min_dist) - { - if(distanceRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - } - - return false; -} - -bool DynamicAABBTreeCollisionManager::distanceRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - if(tf2.getQuatRotation().isIdentity()) - return distanceRecurse_(root1, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback, min_dist); - else - return distanceRecurse_(root1, tree2, root2, root2_bv, tf2, cdata, callback, min_dist); -} - - - - -void DynamicAABBTreeCollisionManager2::registerObjects(const std::vector<CollisionObject*>& other_objs) -{ - if(size() > 0) - { - BroadPhaseCollisionManager::registerObjects(other_objs); - } - else - { - DynamicAABBNode* leaves = new DynamicAABBNode[other_objs.size()]; - table.rehash(other_objs.size()); - for(size_t i = 0, size = other_objs.size(); i < size; ++i) - { - leaves[i].bv = other_objs[i]->getAABB(); - leaves[i].parent = dtree.NULL_NODE; - leaves[i].childs[1] = dtree.NULL_NODE; - leaves[i].data = other_objs[i]; - table[other_objs[i]] = i; - } - - int n_leaves = other_objs.size(); - - dtree.init(leaves, n_leaves, tree_init_level); - - setup_ = true; - } -} - -void DynamicAABBTreeCollisionManager2::registerObject(CollisionObject* obj) -{ - size_t node = dtree.insert(obj->getAABB(), obj); - table[obj] = node; -} - -void DynamicAABBTreeCollisionManager2::unregisterObject(CollisionObject* obj) -{ - size_t node = table[obj]; - table.erase(obj); - dtree.remove(node); -} - -void DynamicAABBTreeCollisionManager2::setup() -{ - if(!setup_) - { - int num = dtree.size(); - if(num == 0) - { - setup_ = true; - return; - } - - int height = dtree.getMaxHeight(); - - - if(height - std::log((FCL_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level) - dtree.balanceIncremental(tree_incremental_balance_pass); - else - dtree.balanceTopdown(); - - setup_ = true; - } -} - - -void DynamicAABBTreeCollisionManager2::update() -{ - for(DynamicAABBTable::const_iterator it = table.begin(), end = table.end(); it != end; ++it) - { - CollisionObject* obj = it->first; - size_t node = it->second; - dtree.getNodes()[node].bv = obj->getAABB(); - } - - dtree.refit(); - setup_ = false; - - setup(); -} - -void DynamicAABBTreeCollisionManager2::update_(CollisionObject* updated_obj) -{ - DynamicAABBTable::const_iterator it = table.find(updated_obj); - if(it != table.end()) - { - size_t node = it->second; - if(!dtree.getNodes()[node].bv.equal(updated_obj->getAABB())) - dtree.update(node, updated_obj->getAABB()); - } - setup_ = false; -} - -void DynamicAABBTreeCollisionManager2::update(CollisionObject* updated_obj) -{ - update_(updated_obj); - setup(); -} - -void DynamicAABBTreeCollisionManager2::update(const std::vector<CollisionObject*>& updated_objs) -{ - for(size_t i = 0, size = updated_objs.size(); i < size; ++i) - update_(updated_objs[i]); - setup(); -} - -bool DynamicAABBTreeCollisionManager2::collisionRecurse(DynamicAABBNode* nodes1, size_t root1_id, - DynamicAABBNode* nodes2, size_t root2_id, - void* cdata, CollisionCallBack callback) const -{ - DynamicAABBNode* root1 = nodes1 + root1_id; - DynamicAABBNode* root2 = nodes2 + root2_id; - 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(nodes1, root1->childs[0], nodes2, root2_id, cdata, callback)) - return true; - if(collisionRecurse(nodes1, root1->childs[1], nodes2, root2_id, cdata, callback)) - return true; - } - else - { - if(collisionRecurse(nodes1, root1_id, nodes2, root2->childs[0], cdata, callback)) - return true; - if(collisionRecurse(nodes1, root1_id, nodes2, root2->childs[1], cdata, callback)) - return true; - } - return false; -} - -bool DynamicAABBTreeCollisionManager2::collisionRecurse(DynamicAABBNode* nodes, size_t root_id, CollisionObject* query, void* cdata, CollisionCallBack callback) const -{ - DynamicAABBNode* root = nodes + root_id; - 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 = alternative::select(query->getAABB(), root->childs[0], root->childs[1], nodes); - - if(collisionRecurse(nodes, root->childs[select_res], query, cdata, callback)) - return true; - - if(collisionRecurse(nodes, root->childs[1-select_res], query, cdata, callback)) - return true; - - return false; -} - -bool DynamicAABBTreeCollisionManager2::selfCollisionRecurse(DynamicAABBNode* nodes, size_t root_id, void* cdata, CollisionCallBack callback) const -{ - DynamicAABBNode* root = nodes + root_id; - if(root->isLeaf()) return false; - - if(selfCollisionRecurse(nodes, root->childs[0], cdata, callback)) - return true; - - if(selfCollisionRecurse(nodes, root->childs[1], cdata, callback)) - return true; - - if(collisionRecurse(nodes, root->childs[0], nodes, root->childs[1], cdata, callback)) - return true; - - return false; -} - -bool DynamicAABBTreeCollisionManager2::distanceRecurse(DynamicAABBNode* nodes1, size_t root1_id, - DynamicAABBNode* nodes2, size_t root2_id, - void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - DynamicAABBNode* root1 = nodes1 + root1_id; - DynamicAABBNode* root2 = nodes2 + root2_id; - 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()))) - { - FCL_REAL d1 = root2->bv.distance((nodes1 + root1->childs[0])->bv); - FCL_REAL d2 = root2->bv.distance((nodes1 + root1->childs[1])->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse(nodes1, root1->childs[1], nodes2, root2_id, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse(nodes1, root1->childs[0], nodes2, root2_id, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse(nodes1, root1->childs[0], nodes2, root2_id, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse(nodes1, root1->childs[1], nodes2, root2_id, cdata, callback, min_dist)) - return true; - } - } - } - else - { - FCL_REAL d1 = root1->bv.distance((nodes2 + root2->childs[0])->bv); - FCL_REAL d2 = root1->bv.distance((nodes2 + root2->childs[1])->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse(nodes1, root1_id, nodes2, root2->childs[1], cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse(nodes1, root1_id, nodes2, root2->childs[0], cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse(nodes1, root1_id, nodes2, root2->childs[0], cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse(nodes1, root1_id, nodes2, root2->childs[1], cdata, callback, min_dist)) - return true; - } - } - } - - return false; -} - -bool DynamicAABBTreeCollisionManager2::distanceRecurse(DynamicAABBNode* nodes, size_t root_id, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - DynamicAABBNode* root = nodes + root_id; - if(root->isLeaf()) - { - CollisionObject* root_obj = static_cast<CollisionObject*>(root->data); - return callback(root_obj, query, cdata, min_dist); - } - - FCL_REAL d1 = query->getAABB().distance((nodes + root->childs[0])->bv); - FCL_REAL d2 = query->getAABB().distance((nodes + root->childs[1])->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse(nodes, root->childs[1], query, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse(nodes, root->childs[0], query, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse(nodes, root->childs[0], query, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse(nodes, root->childs[1], query, cdata, callback, min_dist)) - return true; - } - } - - return false; -} - -bool DynamicAABBTreeCollisionManager2::selfDistanceRecurse(DynamicAABBNode* nodes, size_t root_id, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const -{ - DynamicAABBNode* root = nodes + root_id; - if(root->isLeaf()) return false; - - if(selfDistanceRecurse(nodes, root->childs[0], cdata, callback, min_dist)) - return true; - - if(selfDistanceRecurse(nodes, root->childs[1], cdata, callback, min_dist)) - return true; - - if(distanceRecurse(nodes, root->childs[0], nodes, root->childs[1], cdata, callback, min_dist)) - return true; - - return false; -} - -bool collisionRecurse_(DynamicAABBTreeCollisionManager2::DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) -{ - DynamicAABBTreeCollisionManager2::DynamicAABBNode* root1 = nodes1 + root1_id; - if(root1->isLeaf() && !root2->hasChildren()) - { - CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); - if(!tree2->isNodeFree(root2) && !obj1->isFree()) - { - OBB obb1, obb2; - convertBV(root1->bv, Transform3f(), obb1); - convertBV(root2_bv, tf2, obb2); - - if(obb1.overlap(obb2)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - - box->cost_density = root2->getOccupancy(); - box->threshold_occupied = tree2->getOccupancyThres(); - - CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(obj1, &obj2, cdata); - } - else return false; - } - else return false; - } - - OBB obb1, obb2; - convertBV(root1->bv, Transform3f(), obb1); - convertBV(root2_bv, tf2, obb2); - - if(tree2->isNodeFree(root2) || !obb1.overlap(obb2)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - if(collisionRecurse_(nodes1, root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - if(collisionRecurse_(nodes1, root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - if(collisionRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback)) - return true; - } - } - } - - return false; -} - -bool collisionRecurse_(DynamicAABBTreeCollisionManager2::DynamicAABBNode* nodes1, size_t root1_id, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, CollisionCallBack callback) -{ - DynamicAABBTreeCollisionManager2::DynamicAABBNode* root1 = nodes1 + root1_id; - if(root1->isLeaf() && !root2->hasChildren()) - { - CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); - if(!tree2->isNodeFree(root2)) - { - const AABB& root_bv_t = translate(root2_bv, tf2); - if(root1->bv.overlap(root_bv_t)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - - box->cost_density = root2->getOccupancy(); - box->threshold_occupied = tree2->getOccupancyThres(); - - CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(obj1, &obj2, cdata); - } - else return false; - } - else return false; - } - - const AABB& root_bv_t = translate(root2_bv, tf2); - if(tree2->isNodeFree(root2) || !root1->bv.overlap(root_bv_t)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - if(collisionRecurse_(nodes1, root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - if(collisionRecurse_(nodes1, root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback)) - return true; - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - if(collisionRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback)) - return true; - } - } - } - - return false; -} - - - -bool DynamicAABBTreeCollisionManager2::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 -{ - if(tf2.getQuatRotation().isIdentity()) - return collisionRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback); - else - return collisionRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2, cdata, callback); -} - - -bool distanceRecurse_(DynamicAABBTreeCollisionManager2::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) -{ - DynamicAABBTreeCollisionManager2::DynamicAABBNode* root1 = nodes1 + root1_id; - if(root1->isLeaf() && !root2->hasChildren()) - { - if(tree2->isNodeOccupied(root2)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); - } - else return false; - } - - if(!tree2->isNodeOccupied(root2)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - AABB aabb2; - convertBV(root2_bv, tf2, aabb2); - - FCL_REAL d1 = aabb2.distance((nodes1 + root1->childs[0])->bv); - FCL_REAL d2 = aabb2.distance((nodes1 + root1->childs[1])->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - AABB aabb2; - convertBV(child_bv, tf2, aabb2); - FCL_REAL d = root1->bv.distance(aabb2); - - if(d < min_dist) - { - if(distanceRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - } - - return false; -} - - -bool distanceRecurse_(DynamicAABBTreeCollisionManager2::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) -{ - DynamicAABBTreeCollisionManager2::DynamicAABBNode* root1 = nodes1 + root1_id; - if(root1->isLeaf() && !root2->hasChildren()) - { - if(tree2->isNodeOccupied(root2)) - { - Box* box = new Box(); - Transform3f box_tf; - constructBox(root2_bv, tf2, *box, box_tf); - CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); - return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); - } - else return false; - } - - if(!tree2->isNodeOccupied(root2)) return false; - - if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) - { - const AABB& aabb2 = translate(root2_bv, tf2); - - FCL_REAL d1 = aabb2.distance((nodes1 + root1->childs[0])->bv); - FCL_REAL d2 = aabb2.distance((nodes1 + root1->childs[1])->bv); - - if(d2 < d1) - { - if(d2 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d1 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - else - { - if(d1 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - - if(d2 < min_dist) - { - if(distanceRecurse_(nodes1, root1->childs[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - else - { - for(unsigned int i = 0; i < 8; ++i) - { - if(root2->childExists(i)) - { - const OcTree::OcTreeNode* child = root2->getChild(i); - AABB child_bv; - computeChildBV(root2_bv, i, child_bv); - - const AABB& aabb2 = translate(child_bv, tf2); - FCL_REAL d = root1->bv.distance(aabb2); - - if(d < min_dist) - { - if(distanceRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback, min_dist)) - return true; - } - } - } - } - - return false; -} - -bool DynamicAABBTreeCollisionManager2::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 -{ - if(tf2.getQuatRotation().isIdentity()) - return distanceRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback, min_dist); - else - return distanceRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2, cdata, callback, min_dist); -} - -} diff --git a/trunk/fcl/src/broadphase/broadphase_SSaP.cpp b/trunk/fcl/src/broadphase/broadphase_SSaP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc9d2df5af9780d5fd7303293e5356f9d543caf8 --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_SSaP.cpp @@ -0,0 +1,504 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#include "fcl/broadphase/broadphase_SSaP.h" +#include <algorithm> +#include <limits> + +namespace fcl +{ + +/** \brief Functor sorting objects according to the AABB lower x bound */ +struct SortByXLow +{ + bool operator()(const CollisionObject* a, const CollisionObject* b) const + { + if(a->getAABB().min_[0] < b->getAABB().min_[0]) + return true; + return false; + } +}; + +/** \brief Functor sorting objects according to the AABB lower y bound */ +struct SortByYLow +{ + bool operator()(const CollisionObject* a, const CollisionObject* b) const + { + if(a->getAABB().min_[1] < b->getAABB().min_[1]) + return true; + return false; + } +}; + +/** \brief Functor sorting objects according to the AABB lower z bound */ +struct SortByZLow +{ + bool operator()(const CollisionObject* a, const CollisionObject* b) const + { + if(a->getAABB().min_[2] < b->getAABB().min_[2]) + return true; + return false; + } +}; + +/** \brief Dummy collision object with a point AABB */ +class DummyCollisionObject : public CollisionObject +{ +public: + DummyCollisionObject(const AABB& aabb_) : CollisionObject() + { + aabb = aabb_; + } + + void computeLocalAABB() {} +}; + + +void SSaPCollisionManager::unregisterObject(CollisionObject* obj) +{ + setup(); + + DummyCollisionObject dummyHigh(AABB(obj->getAABB().max_)); + + std::vector<CollisionObject*>::iterator pos_start1 = objs_x.begin(); + std::vector<CollisionObject*>::iterator pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow()); + + while(pos_start1 < pos_end1) + { + if(*pos_start1 == obj) + { + objs_x.erase(pos_start1); + break; + } + ++pos_start1; + } + + std::vector<CollisionObject*>::iterator pos_start2 = objs_y.begin(); + std::vector<CollisionObject*>::iterator pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow()); + + while(pos_start2 < pos_end2) + { + if(*pos_start2 == obj) + { + objs_y.erase(pos_start2); + break; + } + ++pos_start2; + } + + std::vector<CollisionObject*>::iterator pos_start3 = objs_z.begin(); + std::vector<CollisionObject*>::iterator pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow()); + + while(pos_start3 < pos_end3) + { + if(*pos_start3 == obj) + { + objs_z.erase(pos_start3); + break; + } + ++pos_start3; + } +} + + +void SSaPCollisionManager::registerObject(CollisionObject* obj) +{ + objs_x.push_back(obj); + objs_y.push_back(obj); + objs_z.push_back(obj); + setup_ = false; +} + +void SSaPCollisionManager::setup() +{ + if(!setup_) + { + std::sort(objs_x.begin(), objs_x.end(), SortByXLow()); + std::sort(objs_y.begin(), objs_y.end(), SortByYLow()); + std::sort(objs_z.begin(), objs_z.end(), SortByZLow()); + setup_ = true; + } +} + +void SSaPCollisionManager::update() +{ + setup_ = false; + setup(); +} + +void SSaPCollisionManager::clear() +{ + objs_x.clear(); + objs_y.clear(); + objs_z.clear(); + setup_ = false; +} + +void SSaPCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const +{ + objs.resize(objs_x.size()); + std::copy(objs_x.begin(), objs_x.end(), objs.begin()); +} + +bool SSaPCollisionManager::checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, + CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + while(pos_start < pos_end) + { + if(*pos_start != obj) // no collision between the same object + { + if((*pos_start)->getAABB().overlap(obj->getAABB())) + { + if(callback(*pos_start, obj, cdata)) + return true; + } + } + pos_start++; + } + return false; +} + +bool SSaPCollisionManager::checkDis(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + while(pos_start < pos_end) + { + if(*pos_start != obj) // no distance between the same object + { + if((*pos_start)->getAABB().distance(obj->getAABB()) < min_dist) + { + if(callback(*pos_start, obj, cdata, min_dist)) + return true; + } + } + pos_start++; + } + + return false; +} + + + +void SSaPCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + collide_(obj, cdata, callback); +} + +bool SSaPCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + static const unsigned int CUTOFF = 100; + + DummyCollisionObject dummyHigh(AABB(obj->getAABB().max_)); + bool coll_res = false; + + std::vector<CollisionObject*>::const_iterator pos_start1 = objs_x.begin(); + std::vector<CollisionObject*>::const_iterator pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow()); + unsigned int d1 = pos_end1 - pos_start1; + + if(d1 > CUTOFF) + { + std::vector<CollisionObject*>::const_iterator pos_start2 = objs_y.begin(); + std::vector<CollisionObject*>::const_iterator pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow()); + unsigned int d2 = pos_end2 - pos_start2; + + if(d2 > CUTOFF) + { + std::vector<CollisionObject*>::const_iterator pos_start3 = objs_z.begin(); + std::vector<CollisionObject*>::const_iterator pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow()); + unsigned int d3 = pos_end3 - pos_start3; + + if(d3 > CUTOFF) + { + if(d3 <= d2 && d3 <= d1) + coll_res = checkColl(pos_start3, pos_end3, obj, cdata, callback); + else + { + if(d2 <= d3 && d2 <= d1) + coll_res = checkColl(pos_start2, pos_end2, obj, cdata, callback); + else + coll_res = checkColl(pos_start1, pos_end1, obj, cdata, callback); + } + } + else + coll_res = checkColl(pos_start3, pos_end3, obj, cdata, callback); + } + else + coll_res = checkColl(pos_start2, pos_end2, obj, cdata, callback); + } + else + coll_res = checkColl(pos_start1, pos_end1, obj, cdata, callback); + + return coll_res; +} + + +void SSaPCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + distance_(obj, cdata, callback, min_dist); +} + +bool SSaPCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + static const unsigned int CUTOFF = 100; + Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; + Vec3f dummy_vector = obj->getAABB().max_; + if(min_dist < std::numeric_limits<FCL_REAL>::max()) + dummy_vector += Vec3f(min_dist, min_dist, min_dist); + + std::vector<CollisionObject*>::const_iterator pos_start1 = objs_x.begin(); + std::vector<CollisionObject*>::const_iterator pos_start2 = objs_y.begin(); + std::vector<CollisionObject*>::const_iterator pos_start3 = objs_z.begin(); + std::vector<CollisionObject*>::const_iterator pos_end1 = objs_x.end(); + std::vector<CollisionObject*>::const_iterator pos_end2 = objs_y.end(); + std::vector<CollisionObject*>::const_iterator pos_end3 = objs_z.end(); + + int status = 1; + FCL_REAL old_min_distance; + + while(1) + { + old_min_distance = min_dist; + DummyCollisionObject dummyHigh((AABB(dummy_vector))); + + pos_end1 = std::upper_bound(pos_start1, objs_x.end(), &dummyHigh, SortByXLow()); + unsigned int d1 = pos_end1 - pos_start1; + + bool dist_res = false; + + if(d1 > CUTOFF) + { + pos_end2 = std::upper_bound(pos_start2, objs_y.end(), &dummyHigh, SortByYLow()); + unsigned int d2 = pos_end2 - pos_start2; + + if(d2 > CUTOFF) + { + pos_end3 = std::upper_bound(pos_start3, objs_z.end(), &dummyHigh, SortByZLow()); + unsigned int d3 = pos_end3 - pos_start3; + + if(d3 > CUTOFF) + { + if(d3 <= d2 && d3 <= d1) + dist_res = checkDis(pos_start3, pos_end3, obj, cdata, callback, min_dist); + else + { + if(d2 <= d3 && d2 <= d1) + dist_res = checkDis(pos_start2, pos_end2, obj, cdata, callback, min_dist); + else + dist_res = checkDis(pos_start1, pos_end1, obj, cdata, callback, min_dist); + } + } + else + dist_res = checkDis(pos_start3, pos_end3, obj, cdata, callback, min_dist); + } + else + dist_res = checkDis(pos_start2, pos_end2, obj, cdata, callback, min_dist); + } + else + { + dist_res = checkDis(pos_start1, pos_end1, obj, cdata, callback, min_dist); + } + + if(dist_res) return true; + + if(status == 1) + { + if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) + break; + else + { + // from infinity to a finite one, only need one additional loop + // to check the possible missed ones to the right of the objs array + if(min_dist < old_min_distance) + { + dummy_vector = obj->getAABB().max_ + Vec3f(min_dist, min_dist, min_dist); + status = 0; + } + else // need more loop + { + if(dummy_vector.equal(obj->getAABB().max_)) + dummy_vector = dummy_vector + delta; + else + dummy_vector = dummy_vector * 2 - obj->getAABB().max_; + } + } + + // 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; + } + + return false; +} + +void SSaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + std::vector<CollisionObject*>::const_iterator pos, run_pos, pos_end; + size_t axis = selectOptimalAxis(objs_x, objs_y, objs_z, + pos, pos_end); + size_t axis2 = (axis + 1 > 2) ? 0 : (axis + 1); + size_t axis3 = (axis2 + 1 > 2) ? 0 : (axis2 + 1); + + run_pos = pos; + + while((run_pos < pos_end) && (pos < pos_end)) + { + CollisionObject* obj = *(pos++); + + while(1) + { + if((*run_pos)->getAABB().min_[axis] < obj->getAABB().min_[axis]) + { + run_pos++; + if(run_pos == pos_end) break; + continue; + } + else + { + run_pos++; + break; + } + } + + if(run_pos < pos_end) + { + std::vector<CollisionObject*>::const_iterator run_pos2 = run_pos; + + while((*run_pos2)->getAABB().min_[axis] <= obj->getAABB().max_[axis]) + { + CollisionObject* obj2 = *run_pos2; + run_pos2++; + + if((obj->getAABB().max_[axis2] >= obj2->getAABB().min_[axis2]) && (obj2->getAABB().max_[axis2] >= obj->getAABB().min_[axis2])) + { + if((obj->getAABB().max_[axis3] >= obj2->getAABB().min_[axis3]) && (obj2->getAABB().max_[axis3] >= obj->getAABB().min_[axis3])) + { + if(callback(obj, obj2, cdata)) + return; + } + } + + if(run_pos2 == pos_end) break; + } + } + } +} + + +void SSaPCollisionManager::distance(void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + std::vector<CollisionObject*>::const_iterator it, it_end; + size_t axis = selectOptimalAxis(objs_x, objs_y, objs_z, it, it_end); + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + for(; it != it_end; ++it) + { + if(distance_(*it, cdata, callback, min_dist)) + return; + } +} + +void SSaPCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const +{ + SSaPCollisionManager* other_manager = static_cast<SSaPCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + collide(cdata, callback); + return; + } + + + std::vector<CollisionObject*>::const_iterator it, end; + if(this->size() < other_manager->size()) + { + for(it = objs_x.begin(), end = objs_x.end(); it != end; ++it) + if(other_manager->collide_(*it, cdata, callback)) return; + } + else + { + for(it = other_manager->objs_x.begin(), end != other_manager->objs_x.end(); it != end; ++it) + if(collide_(*it, cdata, callback)) return; + } +} + +void SSaPCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const +{ + SSaPCollisionManager* other_manager = static_cast<SSaPCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + distance(cdata, callback); + return; + } + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + std::vector<CollisionObject*>::const_iterator it, end; + if(this->size() < other_manager->size()) + { + for(it = objs_x.begin(), end = objs_x.end(); it != end; ++it) + if(other_manager->distance_(*it, cdata, callback, min_dist)) return; + } + else + { + for(it = other_manager->objs_x.begin(), end = other_manager->objs_x.end(); it != end; ++it) + if(distance_(*it, cdata, callback, min_dist)) return; + } +} + +bool SSaPCollisionManager::empty() const +{ + return objs_x.empty(); +} + + + +} diff --git a/trunk/fcl/src/broadphase/broadphase_SaP.cpp b/trunk/fcl/src/broadphase/broadphase_SaP.cpp new file mode 100644 index 0000000000000000000000000000000000000000..432a94b333827f11c72deccb0f4ff2d2d0b23238 --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_SaP.cpp @@ -0,0 +1,762 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#include "fcl/broadphase/broadphase_SaP.h" +#include <algorithm> +#include <limits> +#include <boost/bind.hpp> + +namespace fcl +{ + +void SaPCollisionManager::unregisterObject(CollisionObject* obj) +{ + std::list<SaPAABB*>::iterator it = AABB_arr.begin(); + for(std::list<SaPAABB*>::iterator end = AABB_arr.end(); it != end; ++it) + { + if((*it)->obj == obj) + break; + } + + AABB_arr.erase(it); + obj_aabb_map.erase(obj); + + if(it == AABB_arr.end()) + return; + + SaPAABB* curr = *it; + *it = NULL; + + for(int coord = 0; coord < 3; ++coord) + { + //first delete the lo endpoint of the interval. + if(curr->lo->prev[coord] == NULL) + elist[coord] = curr->lo->next[coord]; + else + curr->lo->prev[coord]->next[coord] = curr->lo->next[coord]; + + curr->lo->next[coord]->prev[coord] = curr->lo->prev[coord]; + + //then, delete the "hi" endpoint. + if(curr->hi->prev[coord] == NULL) + elist[coord] = curr->hi->next[coord]; + else + curr->hi->prev[coord]->next[coord] = curr->hi->next[coord]; + + if(curr->hi->next[coord] != NULL) + curr->hi->next[coord]->prev[coord] = curr->hi->prev[coord]; + } + + delete curr->lo; + delete curr->hi; + delete curr; + + overlap_pairs.remove_if(isUnregistered(obj)); +} + +void SaPCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) +{ + if(size() > 0) + BroadPhaseCollisionManager::registerObjects(other_objs); + else + { + std::vector<EndPoint*> endpoints(2 * other_objs.size()); + + for(size_t i = 0; i < other_objs.size(); ++i) + { + SaPAABB* sapaabb = new SaPAABB(); + sapaabb->obj = other_objs[i]; + sapaabb->lo = new EndPoint(); + sapaabb->hi = new EndPoint(); + sapaabb->cached = other_objs[i]->getAABB(); + endpoints[2 * i] = sapaabb->lo; + endpoints[2 * i + 1] = sapaabb->hi; + sapaabb->lo->minmax = 0; + sapaabb->hi->minmax = 1; + sapaabb->lo->aabb = sapaabb; + sapaabb->hi->aabb = sapaabb; + AABB_arr.push_back(sapaabb); + obj_aabb_map[other_objs[i]] = sapaabb; + } + + + FCL_REAL scale[3]; + for(size_t coord = 0; coord < 3; ++coord) + { + std::sort(endpoints.begin(), endpoints.end(), + boost::bind(std::less<FCL_REAL>(), + boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const >(&EndPoint::getVal), _1, coord), + boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const >(&EndPoint::getVal), _2, coord))); + + endpoints[0]->prev[coord] = NULL; + endpoints[0]->next[coord] = endpoints[1]; + for(int i = 1; i < endpoints.size() - 1; ++i) + { + endpoints[i]->prev[coord] = endpoints[i-1]; + endpoints[i]->next[coord] = endpoints[i+1]; + } + endpoints[endpoints.size() - 1]->prev[coord] = endpoints[endpoints.size() - 2]; + endpoints[endpoints.size() - 1]->next[coord] = NULL; + + elist[coord] = endpoints[0]; + + scale[coord] = endpoints.back()->aabb->cached.max_[coord] - endpoints[0]->aabb->cached.min_[coord]; + } + + int axis = 0; + if(scale[axis] < scale[1]) axis = 1; + if(scale[axis] < scale[2]) axis = 2; + + EndPoint* pos = elist[axis]; + + while(pos != NULL) + { + EndPoint* pos_next = NULL; + SaPAABB* aabb = pos->aabb; + EndPoint* pos_it = pos->next[axis]; + + while(pos_it != NULL) + { + if(pos_it->aabb == aabb) + { + if(pos_next == NULL) pos_next = pos_it; + break; + } + + if(pos_it->minmax == 0) + { + if(pos_next == NULL) pos_next = pos_it; + if(pos_it->aabb->cached.overlap(aabb->cached)) + overlap_pairs.push_back(SaPPair(pos_it->aabb->obj, aabb->obj)); + } + pos_it = pos_it->next[axis]; + } + + pos = pos_next; + } + } + + updateVelist(); +} + +void SaPCollisionManager::registerObject(CollisionObject* obj) +{ + SaPAABB* curr = new SaPAABB; + curr->cached = obj->getAABB(); + curr->obj = obj; + curr->lo = new EndPoint; + curr->lo->minmax = 0; + curr->lo->aabb = curr; + + curr->hi = new EndPoint; + curr->hi->minmax = 1; + curr->hi->aabb = curr; + + for(int coord = 0; coord < 3; ++coord) + { + EndPoint* current = elist[coord]; + + // first insert the lo end point + if(current == NULL) // empty list + { + elist[coord] = curr->lo; + curr->lo->prev[coord] = curr->lo->next[coord] = NULL; + } + else // otherwise, find the correct location in the list and insert + { + EndPoint* curr_lo = curr->lo; + FCL_REAL curr_lo_val = curr_lo->getVal()[coord]; + while((current->getVal()[coord] < curr_lo_val) && (current->next[coord] != NULL)) + current = current->next[coord]; + + if(current->getVal()[coord] >= curr_lo_val) + { + curr_lo->prev[coord] = current->prev[coord]; + curr_lo->next[coord] = current; + if(current->prev[coord] == NULL) + elist[coord] = curr_lo; + else + current->prev[coord]->next[coord] = curr_lo; + + current->prev[coord] = curr_lo; + } + else + { + curr_lo->prev[coord] = current; + curr_lo->next[coord] = NULL; + current->next[coord] = curr_lo; + } + } + + // now insert hi end point + current = curr->lo; + + EndPoint* curr_hi = curr->hi; + FCL_REAL curr_hi_val = curr_hi->getVal()[coord]; + + if(coord == 0) + { + while((current->getVal()[coord] < curr_hi_val) && (current->next[coord] != NULL)) + { + if(current != curr->lo) + if(current->aabb->cached.overlap(curr->cached)) + overlap_pairs.push_back(SaPPair(current->aabb->obj, obj)); + + current = current->next[coord]; + } + } + else + { + while((current->getVal()[coord] < curr_hi_val) && (current->next[coord] != NULL)) + current = current->next[coord]; + } + + if(current->getVal()[coord] >= curr_hi_val) + { + curr_hi->prev[coord] = current->prev[coord]; + curr_hi->next[coord] = current; + if(current->prev[coord] == NULL) + elist[coord] = curr_hi; + else + current->prev[coord]->next[coord] = curr_hi; + + current->prev[coord] = curr_hi; + } + else + { + curr_hi->prev[coord] = current; + curr_hi->next[coord] = NULL; + current->next[coord] = curr_hi; + } + } + + AABB_arr.push_back(curr); + + obj_aabb_map[obj] = curr; + + updateVelist(); +} + +void SaPCollisionManager::setup() +{ + FCL_REAL scale[3]; + scale[0] = (velist[0].back())->getVal(0) - velist[0][0]->getVal(0); + scale[1] = (velist[1].back())->getVal(1) - velist[1][0]->getVal(1);; + scale[2] = (velist[2].back())->getVal(2) - velist[2][0]->getVal(2); + size_t axis = 0; + if(scale[axis] < scale[1]) axis = 1; + if(scale[axis] < scale[2]) axis = 2; + optimal_axis = axis; +} + +void SaPCollisionManager::update_(SaPAABB* updated_aabb) +{ + if(updated_aabb->cached.equal(updated_aabb->obj->getAABB())) + return; + + SaPAABB* current = updated_aabb; + + Vec3f new_min = current->obj->getAABB().min_; + Vec3f new_max = current->obj->getAABB().max_; + + SaPAABB dummy; + dummy.cached = current->obj->getAABB(); + + for(int coord = 0; coord < 3; ++coord) + { + int direction; // -1 reverse, 0 nochange, 1 forward + EndPoint* temp; + + if(current->lo->getVal(coord) > new_min[coord]) + direction = -1; + else if(current->lo->getVal(coord) < new_min[coord]) + direction = 1; + else direction = 0; + + if(direction == -1) + { + //first update the "lo" endpoint of the interval + if(current->lo->prev[coord] != NULL) + { + temp = current->lo; + while((temp != NULL) && (temp->getVal(coord) > new_min[coord])) + { + if(temp->minmax == 1) + if(temp->aabb->cached.overlap(dummy.cached)) + addToOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); + temp = temp->prev[coord]; + } + + if(temp == NULL) + { + current->lo->prev[coord]->next[coord] = current->lo->next[coord]; + current->lo->next[coord]->prev[coord] = current->lo->prev[coord]; + current->lo->prev[coord] = NULL; + current->lo->next[coord] = elist[coord]; + elist[coord]->prev[coord] = current->lo; + elist[coord] = current->lo; + } + else + { + current->lo->prev[coord]->next[coord] = current->lo->next[coord]; + current->lo->next[coord]->prev[coord] = current->lo->prev[coord]; + current->lo->prev[coord] = temp; + current->lo->next[coord] = temp->next[coord]; + temp->next[coord]->prev[coord] = current->lo; + temp->next[coord] = current->lo; + } + } + + current->lo->getVal(coord) = new_min[coord]; + + // update hi end point + temp = current->hi; + while(temp->getVal(coord) > new_max[coord]) + { + if((temp->minmax == 0) && (temp->aabb->cached.overlap(current->cached))) + removeFromOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); + temp = temp->prev[coord]; + } + + current->hi->prev[coord]->next[coord] = current->hi->next[coord]; + if(current->hi->next[coord] != NULL) + current->hi->next[coord]->prev[coord] = current->hi->prev[coord]; + current->hi->prev[coord] = temp; + current->hi->next[coord] = temp->next[coord]; + if(temp->next[coord] != NULL) + temp->next[coord]->prev[coord] = current->hi; + temp->next[coord] = current->hi; + + current->hi->getVal(coord) = new_max[coord]; + } + else if(direction == 1) + { + //here, we first update the "hi" endpoint. + if(current->hi->next[coord] != NULL) + { + temp = current->hi; + while((temp->next[coord] != NULL) && (temp->getVal(coord) < new_max[coord])) + { + if(temp->minmax == 0) + if(temp->aabb->cached.overlap(dummy.cached)) + addToOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); + temp = temp->next[coord]; + } + + if(temp->getVal(coord) < new_max[coord]) + { + current->hi->prev[coord]->next[coord] = current->hi->next[coord]; + current->hi->next[coord]->prev[coord] = current->hi->prev[coord]; + current->hi->prev[coord] = temp; + current->hi->next[coord] = NULL; + temp->next[coord] = current->hi; + } + else + { + current->hi->prev[coord]->next[coord] = current->hi->next[coord]; + current->hi->next[coord]->prev[coord] = current->hi->prev[coord]; + current->hi->prev[coord] = temp->prev[coord]; + current->hi->next[coord] = temp; + temp->prev[coord]->next[coord] = current->hi; + temp->prev[coord] = current->hi; + } + } + + current->hi->getVal(coord) = new_max[coord]; + + //then, update the "lo" endpoint of the interval. + temp = current->lo; + + while(temp->getVal(coord) < new_min[coord]) + { + if((temp->minmax == 1) && (temp->aabb->cached.overlap(current->cached))) + removeFromOverlapPairs(SaPPair(temp->aabb->obj, current->obj)); + temp = temp->next[coord]; + } + + if(current->lo->prev[coord] != NULL) + current->lo->prev[coord]->next[coord] = current->lo->next[coord]; + else + elist[coord] = current->lo->next[coord]; + current->lo->next[coord]->prev[coord] = current->lo->prev[coord]; + current->lo->prev[coord] = temp->prev[coord]; + current->lo->next[coord] = temp; + if(temp->prev[coord] != NULL) + temp->prev[coord]->next[coord] = current->lo; + else + elist[coord] = current->lo; + temp->prev[coord] = current->lo; + current->lo->getVal(coord) = new_min[coord]; + } + } +} + +void SaPCollisionManager::update(CollisionObject* updated_obj) +{ + update_(obj_aabb_map[updated_obj]); + + updateVelist(); + + setup(); +} + +void SaPCollisionManager::update(const std::vector<CollisionObject*>& updated_objs) +{ + for(size_t i = 0; i < updated_objs.size(); ++i) + update_(obj_aabb_map[updated_objs[i]]); + + updateVelist(); + + setup(); +} + +void SaPCollisionManager::update() +{ + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it) + { + update_(*it); + } + + updateVelist(); + + setup(); +} + + +void SaPCollisionManager::clear() +{ + for(std::list<SaPAABB*>::iterator it = AABB_arr.begin(), end = AABB_arr.end(); + it != end; + ++it) + { + delete (*it)->hi; + delete (*it)->lo; + delete *it; + *it = NULL; + } + + AABB_arr.clear(); + overlap_pairs.clear(); + + elist[0] = NULL; + elist[1] = NULL; + elist[2] = NULL; + + velist[0].clear(); + velist[1].clear(); + velist[2].clear(); + + obj_aabb_map.clear(); +} + +void SaPCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const +{ + objs.resize(AABB_arr.size()); + int i = 0; + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it, ++i) + { + objs[i] = (*it)->obj; + } +} + +bool SaPCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + size_t axis = optimal_axis; + const AABB& obj_aabb = obj->getAABB(); + + FCL_REAL min_val = obj_aabb.min_[axis]; + FCL_REAL max_val = obj_aabb.max_[axis]; + + EndPoint dummy; + SaPAABB dummy_aabb; + dummy_aabb.cached = obj_aabb; + dummy.minmax = 1; + dummy.aabb = &dummy_aabb; + + // 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<FCL_REAL>(), + boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _1, axis), + boost::bind(static_cast<FCL_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 = elist[axis]; + + while(pos != end_pos) + { + if(pos->aabb->obj != obj) + { + if((pos->minmax == 0) && (pos->aabb->hi->getVal(axis) >= min_val)) + { + 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, FCL_REAL& min_dist) const +{ + Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; + AABB aabb = obj->getAABB(); + + if(min_dist < std::numeric_limits<FCL_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; + FCL_REAL old_min_distance; + + EndPoint* start_pos = elist[axis]; + + while(1) + { + old_min_distance = min_dist; + FCL_REAL min_val = aabb.min_[axis]; + FCL_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<FCL_REAL>(), + boost::bind(static_cast<FCL_REAL (EndPoint::*)(size_t) const>(&EndPoint::getVal), _1, axis), + boost::bind(static_cast<FCL_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) + { + // 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(curr_obj != obj) + { + if(!enable_tested_set_) + { + if(pos->aabb->cached.distance(obj->getAABB()) < min_dist) + { + if(callback(curr_obj, obj, cdata, min_dist)) + return true; + } + } + else + { + if(!inTestedSet(curr_obj, obj)) + { + if(pos->aabb->cached.distance(obj->getAABB()) < min_dist) + { + if(callback(curr_obj, obj, cdata, min_dist)) + return true; + } + + insertTestedSet(curr_obj, obj); + } + } + } + } + + pos = pos->next[axis]; + } + + if(status == 1) + { + if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) + break; + 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; + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + distance_(obj, cdata, callback, min_dist); +} + +void SaPCollisionManager::collide(void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + for(std::list<SaPPair>::const_iterator it = overlap_pairs.begin(), end = overlap_pairs.end(); it != end; ++it) + { + CollisionObject* obj1 = it->obj1; + CollisionObject* obj2 = it->obj2; + + if(callback(obj1, obj2, cdata)) + return; + } +} + +void SaPCollisionManager::distance(void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + enable_tested_set_ = true; + tested_set.clear(); + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it) + { + if(distance_((*it)->obj, cdata, callback, min_dist)) + break; + } + + enable_tested_set_ = false; + tested_set.clear(); +} + +void SaPCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const +{ + SaPCollisionManager* other_manager = static_cast<SaPCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + collide(cdata, callback); + return; + } + + if(this->size() < other_manager->size()) + { + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(); it != AABB_arr.end(); ++it) + { + if(other_manager->collide_((*it)->obj, cdata, callback)) + return; + } + } + else + { + for(std::list<SaPAABB*>::const_iterator it = other_manager->AABB_arr.begin(), end = other_manager->AABB_arr.end(); it != end; ++it) + { + if(collide_((*it)->obj, cdata, callback)) + return; + } + } +} + +void SaPCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const +{ + SaPCollisionManager* other_manager = static_cast<SaPCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + distance(cdata, callback); + return; + } + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + if(this->size() < other_manager->size()) + { + for(std::list<SaPAABB*>::const_iterator it = AABB_arr.begin(), end = AABB_arr.end(); it != end; ++it) + { + if(other_manager->distance_((*it)->obj, cdata, callback, min_dist)) + return; + } + } + else + { + for(std::list<SaPAABB*>::const_iterator it = other_manager->AABB_arr.begin(), end = other_manager->AABB_arr.end(); it != end; ++it) + { + if(distance_((*it)->obj, cdata, callback, min_dist)) + return; + } + } +} + +bool SaPCollisionManager::empty() const +{ + return AABB_arr.size(); +} + + + +} diff --git a/trunk/fcl/src/broadphase/broadphase_bruteforce.cpp b/trunk/fcl/src/broadphase/broadphase_bruteforce.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b68508e99abcc982ac199c40667789ac090a69eb --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_bruteforce.cpp @@ -0,0 +1,197 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#include "fcl/broadphase/broadphase_bruteforce.h" +#include <limits> + +namespace fcl +{ + +void NaiveCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) +{ + std::copy(other_objs.begin(), other_objs.end(), std::back_inserter(objs)); +} + +void NaiveCollisionManager::unregisterObject(CollisionObject* obj) +{ + objs.remove(obj); +} + +void NaiveCollisionManager::registerObject(CollisionObject* obj) +{ + objs.push_back(obj); +} + +void NaiveCollisionManager::setup() +{ + +} + +void NaiveCollisionManager::update() +{ + +} + +void NaiveCollisionManager::clear() +{ + objs.clear(); +} + +void NaiveCollisionManager::getObjects(std::vector<CollisionObject*>& objs_) const +{ + objs_.resize(objs.size()); + std::copy(objs.begin(), objs.end(), objs_.begin()); +} + +void NaiveCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); it != end; ++it) + { + if(callback(obj, *it, cdata)) + return; + } +} + +void NaiveCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + for(std::list<CollisionObject*>::const_iterator it = objs.begin(), end = objs.end(); + it != end; ++it) + { + if(obj->getAABB().distance((*it)->getAABB()) < min_dist) + { + if(callback(obj, *it, cdata, min_dist)) + return; + } + } +} + +void NaiveCollisionManager::collide(void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end = objs.end(); + it1 != end; ++it1) + { + std::list<CollisionObject*>::const_iterator it2 = it1; it2++; + for(; it2 != end; ++it2) + { + if((*it1)->getAABB().overlap((*it2)->getAABB())) + if(callback(*it1, *it2, cdata)) + return; + } + } +} + +void NaiveCollisionManager::distance(void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end = objs.end(); it1 != end; ++it1) + { + std::list<CollisionObject*>::const_iterator it2 = it1; it2++; + for(; it2 != end; ++it2) + { + if((*it1)->getAABB().distance((*it2)->getAABB()) < min_dist) + { + if(callback(*it1, *it2, cdata, min_dist)) + return; + } + } + } +} + +void NaiveCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const +{ + NaiveCollisionManager* other_manager = static_cast<NaiveCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + collide(cdata, callback); + return; + } + + for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end1 = objs.end(); it1 != end1; ++it1) + { + for(std::list<CollisionObject*>::const_iterator it2 = other_manager->objs.begin(), end2 = other_manager->objs.end(); it2 != end2; ++it2) + { + if((*it1)->getAABB().overlap((*it2)->getAABB())) + if(callback((*it1), (*it2), cdata)) + return; + } + } +} + +void NaiveCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const +{ + NaiveCollisionManager* other_manager = static_cast<NaiveCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + distance(cdata, callback); + return; + } + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + for(std::list<CollisionObject*>::const_iterator it1 = objs.begin(), end1 = objs.end(); it1 != end1; ++it1) + { + for(std::list<CollisionObject*>::const_iterator it2 = other_manager->objs.begin(), end2 = other_manager->objs.end(); it2 != end2; ++it2) + { + if((*it1)->getAABB().distance((*it2)->getAABB()) < min_dist) + { + if(callback(*it1, *it2, cdata, min_dist)) + return; + } + } + } +} + +bool NaiveCollisionManager::empty() const +{ + return objs.empty(); +} + + +} diff --git a/trunk/fcl/src/broadphase/broadphase_dynamic_AABB_tree.cpp b/trunk/fcl/src/broadphase/broadphase_dynamic_AABB_tree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb106a5d8b92ec853ef3d306715cb12fb39e56f7 --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_dynamic_AABB_tree.cpp @@ -0,0 +1,644 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + + +#include "fcl/broadphase/broadphase_dynamic_AABB_tree.h" + +namespace fcl +{ + +void DynamicAABBTreeCollisionManager::registerObjects(const std::vector<CollisionObject*>& other_objs) +{ + if(size() > 0) + { + BroadPhaseCollisionManager::registerObjects(other_objs); + } + else + { + std::vector<DynamicAABBNode*> leaves(other_objs.size()); + table.rehash(other_objs.size()); + for(size_t i = 0, size = other_objs.size(); i < size; ++i) + { + DynamicAABBNode* node = new DynamicAABBNode; // node will be managed by the dtree + node->bv = other_objs[i]->getAABB(); + node->parent = NULL; + node->children[1] = NULL; + node->data = other_objs[i]; + table[other_objs[i]] = node; + leaves[i] = node; + } + + dtree.init(leaves, tree_init_level); + + 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_) + { + int num = dtree.size(); + if(num == 0) + { + setup_ = true; + return; + } + + int height = dtree.getMaxHeight(); + + + if(height - std::log((FCL_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level) + dtree.balanceIncremental(tree_incremental_balance_pass); + else + dtree.balanceTopdown(); + + setup_ = true; + } +} + + +void DynamicAABBTreeCollisionManager::update() +{ + for(DynamicAABBTable::const_iterator it = table.begin(); it != table.end(); ++it) + { + CollisionObject* obj = it->first; + DynamicAABBNode* node = it->second; + node->bv = obj->getAABB(); + } + + dtree.refit(); + setup_ = false; + + setup(); +} + +void DynamicAABBTreeCollisionManager::update_(CollisionObject* updated_obj) +{ + DynamicAABBTable::const_iterator it = table.find(updated_obj); + if(it != table.end()) + { + DynamicAABBNode* node = it->second; + if(!node->bv.equal(updated_obj->getAABB())) + dtree.update(node, updated_obj->getAABB()); + } + setup_ = false; +} + +void DynamicAABBTreeCollisionManager::update(CollisionObject* updated_obj) +{ + update_(updated_obj); + setup(); +} + +void DynamicAABBTreeCollisionManager::update(const std::vector<CollisionObject*>& updated_objs) +{ + for(size_t i = 0, size = updated_objs.size(); i < size; ++i) + update_(updated_objs[i]); + setup(); +} + +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->children[0], root2, cdata, callback)) + return true; + if(collisionRecurse(root1->children[1], root2, cdata, callback)) + return true; + } + else + { + if(collisionRecurse(root1, root2->children[0], cdata, callback)) + return true; + if(collisionRecurse(root1, root2->children[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->children[0]), *(root->children[1])); + + if(collisionRecurse(root->children[select_res], query, cdata, callback)) + return true; + + if(collisionRecurse(root->children[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->children[0], cdata, callback)) + return true; + + if(selfCollisionRecurse(root->children[1], cdata, callback)) + return true; + + if(collisionRecurse(root->children[0], root->children[1], cdata, callback)) + return true; + + return false; +} + +bool DynamicAABBTreeCollisionManager::distanceRecurse(DynamicAABBNode* root1, DynamicAABBNode* root2, void* cdata, DistanceCallBack callback, FCL_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()))) + { + FCL_REAL d1 = root2->bv.distance(root1->children[0]->bv); + FCL_REAL d2 = root2->bv.distance(root1->children[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(root1->children[1], root2, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(root1->children[0], root2, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(root1->children[0], root2, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(root1->children[1], root2, cdata, callback, min_dist)) + return true; + } + } + } + else + { + FCL_REAL d1 = root1->bv.distance(root2->children[0]->bv); + FCL_REAL d2 = root1->bv.distance(root2->children[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(root1, root2->children[1], cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(root1, root2->children[0], cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(root1, root2->children[0], cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(root1, root2->children[1], cdata, callback, min_dist)) + return true; + } + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager::distanceRecurse(DynamicAABBNode* root, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + if(root->isLeaf()) + { + CollisionObject* root_obj = static_cast<CollisionObject*>(root->data); + return callback(root_obj, query, cdata, min_dist); + } + + FCL_REAL d1 = query->getAABB().distance(root->children[0]->bv); + FCL_REAL d2 = query->getAABB().distance(root->children[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(root->children[1], query, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(root->children[0], query, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(root->children[0], query, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(root->children[1], query, cdata, callback, min_dist)) + return true; + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager::selfDistanceRecurse(DynamicAABBNode* root, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + if(root->isLeaf()) return false; + + if(selfDistanceRecurse(root->children[0], cdata, callback, min_dist)) + return true; + + if(selfDistanceRecurse(root->children[1], cdata, callback, min_dist)) + return true; + + if(distanceRecurse(root->children[0], root->children[1], cdata, callback, min_dist)) + return true; + + return false; +} + + +bool collisionRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) +{ + if(root1->isLeaf() && !root2->hasChildren()) + { + CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); + + if(!tree2->isNodeFree(root2) && !obj1->isFree()) + { + OBB obb1, obb2; + convertBV(root1->bv, Transform3f(), obb1); + convertBV(root2_bv, tf2, obb2); + + if(obb1.overlap(obb2)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + + box->cost_density = root2->getOccupancy(); + box->threshold_occupied = tree2->getOccupancyThres(); + + CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(obj1, &obj2, cdata); + } + else return false; + } + else return false; + } + + OBB obb1, obb2; + convertBV(root1->bv, Transform3f(), obb1); + convertBV(root2_bv, tf2, obb2); + + if(tree2->isNodeFree(root2) || !obb1.overlap(obb2)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + if(collisionRecurse_(root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + if(collisionRecurse_(root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + if(collisionRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback)) + return true; + } + } + } + return false; +} + +bool collisionRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, CollisionCallBack callback) +{ + if(root1->isLeaf() && !root2->hasChildren()) + { + CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); + + if(!tree2->isNodeFree(root2) && !obj1->isFree()) + { + const AABB& root2_bv_t = translate(root2_bv, tf2); + if(root1->bv.overlap(root2_bv_t)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + + box->cost_density = root2->getOccupancy(); + box->threshold_occupied = tree2->getOccupancyThres(); + + CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(obj1, &obj2, cdata); + } + else return false; + } + else return false; + } + + const AABB& root2_bv_t = translate(root2_bv, tf2); + if(tree2->isNodeFree(root2) || !root1->bv.overlap(root2_bv_t)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + if(collisionRecurse_(root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + if(collisionRecurse_(root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + if(collisionRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback)) + return true; + } + } + } + return false; +} + + + +bool DynamicAABBTreeCollisionManager::collisionRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, CollisionCallBack callback) const +{ + if(tf2.getQuatRotation().isIdentity()) + return collisionRecurse_(root1, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback); + else // has rotation + return collisionRecurse_(root1, tree2, root2, root2_bv, tf2, cdata, callback); +} + + +bool distanceRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Vec3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) +{ + if(root1->isLeaf() && !root2->hasChildren()) + { + if(tree2->isNodeOccupied(root2)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); + } + else return false; + } + + if(!tree2->isNodeOccupied(root2)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + const AABB& aabb2 = translate(root2_bv, tf2); + FCL_REAL d1 = aabb2.distance(root1->children[0]->bv); + FCL_REAL d2 = aabb2.distance(root1->children[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse_(root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse_(root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse_(root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse_(root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + const AABB& aabb2 = translate(child_bv, tf2); + + FCL_REAL d = root1->bv.distance(aabb2); + + if(d < min_dist) + { + if(distanceRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + } + + return false; +} + + +bool distanceRecurse_(DynamicAABBTreeCollisionManager::DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) +{ + if(root1->isLeaf() && !root2->hasChildren()) + { + if(tree2->isNodeOccupied(root2)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); + } + else return false; + } + + if(!tree2->isNodeOccupied(root2)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + AABB aabb2; + convertBV(root2_bv, tf2, aabb2); + + FCL_REAL d1 = aabb2.distance(root1->children[0]->bv); + FCL_REAL d2 = aabb2.distance(root1->children[1]->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse_(root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse_(root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse_(root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse_(root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + AABB aabb2; + convertBV(child_bv, tf2, aabb2); + FCL_REAL d = root1->bv.distance(aabb2); + + if(d < min_dist) + { + if(distanceRecurse_(root1, tree2, child, child_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager::distanceRecurse(DynamicAABBNode* root1, const OcTree* tree2, const OcTree::OcTreeNode* root2, const AABB& root2_bv, const Transform3f& tf2, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + if(tf2.getQuatRotation().isIdentity()) + return distanceRecurse_(root1, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback, min_dist); + else + return distanceRecurse_(root1, tree2, root2, root2_bv, tf2, cdata, callback, min_dist); +} + + +} diff --git a/trunk/fcl/src/broadphase/broadphase_dynamic_AABB_tree_array.cpp b/trunk/fcl/src/broadphase/broadphase_dynamic_AABB_tree_array.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d21379ed60bdd17322bb938df465c9fbd1a492c --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_dynamic_AABB_tree_array.cpp @@ -0,0 +1,659 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#include "fcl/broadphase/broadphase_dynamic_AABB_tree_array.h" + +namespace fcl +{ + +void DynamicAABBTreeCollisionManager_Array::registerObjects(const std::vector<CollisionObject*>& other_objs) +{ + if(size() > 0) + { + BroadPhaseCollisionManager::registerObjects(other_objs); + } + else + { + DynamicAABBNode* leaves = new DynamicAABBNode[other_objs.size()]; + table.rehash(other_objs.size()); + for(size_t i = 0, size = other_objs.size(); i < size; ++i) + { + leaves[i].bv = other_objs[i]->getAABB(); + leaves[i].parent = dtree.NULL_NODE; + leaves[i].children[1] = dtree.NULL_NODE; + leaves[i].data = other_objs[i]; + table[other_objs[i]] = i; + } + + int n_leaves = other_objs.size(); + + dtree.init(leaves, n_leaves, tree_init_level); + + setup_ = true; + } +} + +void DynamicAABBTreeCollisionManager_Array::registerObject(CollisionObject* obj) +{ + size_t node = dtree.insert(obj->getAABB(), obj); + table[obj] = node; +} + +void DynamicAABBTreeCollisionManager_Array::unregisterObject(CollisionObject* obj) +{ + size_t node = table[obj]; + table.erase(obj); + dtree.remove(node); +} + +void DynamicAABBTreeCollisionManager_Array::setup() +{ + if(!setup_) + { + int num = dtree.size(); + if(num == 0) + { + setup_ = true; + return; + } + + int height = dtree.getMaxHeight(); + + + if(height - std::log((FCL_REAL)num) / std::log(2.0) < max_tree_nonbalanced_level) + dtree.balanceIncremental(tree_incremental_balance_pass); + else + dtree.balanceTopdown(); + + setup_ = true; + } +} + + +void DynamicAABBTreeCollisionManager_Array::update() +{ + for(DynamicAABBTable::const_iterator it = table.begin(), end = table.end(); it != end; ++it) + { + CollisionObject* obj = it->first; + size_t node = it->second; + dtree.getNodes()[node].bv = obj->getAABB(); + } + + dtree.refit(); + setup_ = false; + + setup(); +} + +void DynamicAABBTreeCollisionManager_Array::update_(CollisionObject* updated_obj) +{ + DynamicAABBTable::const_iterator it = table.find(updated_obj); + if(it != table.end()) + { + size_t node = it->second; + if(!dtree.getNodes()[node].bv.equal(updated_obj->getAABB())) + dtree.update(node, updated_obj->getAABB()); + } + setup_ = false; +} + +void DynamicAABBTreeCollisionManager_Array::update(CollisionObject* updated_obj) +{ + update_(updated_obj); + setup(); +} + +void DynamicAABBTreeCollisionManager_Array::update(const std::vector<CollisionObject*>& updated_objs) +{ + for(size_t i = 0, size = updated_objs.size(); i < size; ++i) + update_(updated_objs[i]); + setup(); +} + +bool DynamicAABBTreeCollisionManager_Array::collisionRecurse(DynamicAABBNode* nodes1, size_t root1_id, + DynamicAABBNode* nodes2, size_t root2_id, + void* cdata, CollisionCallBack callback) const +{ + DynamicAABBNode* root1 = nodes1 + root1_id; + DynamicAABBNode* root2 = nodes2 + root2_id; + 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(nodes1, root1->children[0], nodes2, root2_id, cdata, callback)) + return true; + if(collisionRecurse(nodes1, root1->children[1], nodes2, root2_id, cdata, callback)) + return true; + } + else + { + if(collisionRecurse(nodes1, root1_id, nodes2, root2->children[0], cdata, callback)) + return true; + if(collisionRecurse(nodes1, root1_id, nodes2, root2->children[1], cdata, callback)) + return true; + } + return false; +} + +bool DynamicAABBTreeCollisionManager_Array::collisionRecurse(DynamicAABBNode* nodes, size_t root_id, CollisionObject* query, void* cdata, CollisionCallBack callback) const +{ + DynamicAABBNode* root = nodes + root_id; + 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 = implementation_array::select(query->getAABB(), root->children[0], root->children[1], nodes); + + if(collisionRecurse(nodes, root->children[select_res], query, cdata, callback)) + return true; + + if(collisionRecurse(nodes, root->children[1-select_res], query, cdata, callback)) + return true; + + return false; +} + +bool DynamicAABBTreeCollisionManager_Array::selfCollisionRecurse(DynamicAABBNode* nodes, size_t root_id, void* cdata, CollisionCallBack callback) const +{ + DynamicAABBNode* root = nodes + root_id; + if(root->isLeaf()) return false; + + if(selfCollisionRecurse(nodes, root->children[0], cdata, callback)) + return true; + + if(selfCollisionRecurse(nodes, root->children[1], cdata, callback)) + return true; + + if(collisionRecurse(nodes, root->children[0], nodes, root->children[1], cdata, callback)) + return true; + + return false; +} + +bool DynamicAABBTreeCollisionManager_Array::distanceRecurse(DynamicAABBNode* nodes1, size_t root1_id, + DynamicAABBNode* nodes2, size_t root2_id, + void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + DynamicAABBNode* root1 = nodes1 + root1_id; + DynamicAABBNode* root2 = nodes2 + root2_id; + 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()))) + { + FCL_REAL d1 = root2->bv.distance((nodes1 + root1->children[0])->bv); + FCL_REAL d2 = root2->bv.distance((nodes1 + root1->children[1])->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(nodes1, root1->children[1], nodes2, root2_id, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(nodes1, root1->children[0], nodes2, root2_id, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(nodes1, root1->children[0], nodes2, root2_id, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(nodes1, root1->children[1], nodes2, root2_id, cdata, callback, min_dist)) + return true; + } + } + } + else + { + FCL_REAL d1 = root1->bv.distance((nodes2 + root2->children[0])->bv); + FCL_REAL d2 = root1->bv.distance((nodes2 + root2->children[1])->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[1], cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[0], cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[0], cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(nodes1, root1_id, nodes2, root2->children[1], cdata, callback, min_dist)) + return true; + } + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager_Array::distanceRecurse(DynamicAABBNode* nodes, size_t root_id, CollisionObject* query, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + DynamicAABBNode* root = nodes + root_id; + if(root->isLeaf()) + { + CollisionObject* root_obj = static_cast<CollisionObject*>(root->data); + return callback(root_obj, query, cdata, min_dist); + } + + FCL_REAL d1 = query->getAABB().distance((nodes + root->children[0])->bv); + FCL_REAL d2 = query->getAABB().distance((nodes + root->children[1])->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse(nodes, root->children[1], query, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse(nodes, root->children[0], query, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse(nodes, root->children[0], query, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse(nodes, root->children[1], query, cdata, callback, min_dist)) + return true; + } + } + + return false; +} + +bool DynamicAABBTreeCollisionManager_Array::selfDistanceRecurse(DynamicAABBNode* nodes, size_t root_id, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + DynamicAABBNode* root = nodes + root_id; + if(root->isLeaf()) return false; + + if(selfDistanceRecurse(nodes, root->children[0], cdata, callback, min_dist)) + return true; + + if(selfDistanceRecurse(nodes, root->children[1], cdata, callback, min_dist)) + return true; + + if(distanceRecurse(nodes, root->children[0], nodes, root->children[1], cdata, callback, min_dist)) + return true; + + return false; +} + +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) +{ + DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id; + if(root1->isLeaf() && !root2->hasChildren()) + { + CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); + if(!tree2->isNodeFree(root2) && !obj1->isFree()) + { + OBB obb1, obb2; + convertBV(root1->bv, Transform3f(), obb1); + convertBV(root2_bv, tf2, obb2); + + if(obb1.overlap(obb2)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + + box->cost_density = root2->getOccupancy(); + box->threshold_occupied = tree2->getOccupancyThres(); + + CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(obj1, &obj2, cdata); + } + else return false; + } + else return false; + } + + OBB obb1, obb2; + convertBV(root1->bv, Transform3f(), obb1); + convertBV(root2_bv, tf2, obb2); + + if(tree2->isNodeFree(root2) || !obb1.overlap(obb2)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + if(collisionRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + if(collisionRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + if(collisionRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback)) + return true; + } + } + } + + return false; +} + +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) +{ + DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id; + if(root1->isLeaf() && !root2->hasChildren()) + { + CollisionObject* obj1 = static_cast<CollisionObject*>(root1->data); + if(!tree2->isNodeFree(root2)) + { + const AABB& root_bv_t = translate(root2_bv, tf2); + if(root1->bv.overlap(root_bv_t)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + + box->cost_density = root2->getOccupancy(); + box->threshold_occupied = tree2->getOccupancyThres(); + + CollisionObject obj2(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(obj1, &obj2, cdata); + } + else return false; + } + else return false; + } + + const AABB& root_bv_t = translate(root2_bv, tf2); + if(tree2->isNodeFree(root2) || !root1->bv.overlap(root_bv_t)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + if(collisionRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + if(collisionRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback)) + return true; + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + if(collisionRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback)) + return true; + } + } + } + + return false; +} + + + +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 +{ + if(tf2.getQuatRotation().isIdentity()) + return collisionRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback); + else + return collisionRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2, cdata, callback); +} + + +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) +{ + DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id; + if(root1->isLeaf() && !root2->hasChildren()) + { + if(tree2->isNodeOccupied(root2)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); + } + else return false; + } + + if(!tree2->isNodeOccupied(root2)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + AABB aabb2; + convertBV(root2_bv, tf2, aabb2); + + FCL_REAL d1 = aabb2.distance((nodes1 + root1->children[0])->bv); + FCL_REAL d2 = aabb2.distance((nodes1 + root1->children[1])->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + AABB aabb2; + convertBV(child_bv, tf2, aabb2); + FCL_REAL d = root1->bv.distance(aabb2); + + if(d < min_dist) + { + if(distanceRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + } + + return false; +} + + +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) +{ + DynamicAABBTreeCollisionManager_Array::DynamicAABBNode* root1 = nodes1 + root1_id; + if(root1->isLeaf() && !root2->hasChildren()) + { + if(tree2->isNodeOccupied(root2)) + { + Box* box = new Box(); + Transform3f box_tf; + constructBox(root2_bv, tf2, *box, box_tf); + CollisionObject obj(boost::shared_ptr<CollisionGeometry>(box), box_tf); + return callback(static_cast<CollisionObject*>(root1->data), &obj, cdata, min_dist); + } + else return false; + } + + if(!tree2->isNodeOccupied(root2)) return false; + + if(!root2->hasChildren() || (!root1->isLeaf() && (root1->bv.size() > root2_bv.size()))) + { + const AABB& aabb2 = translate(root2_bv, tf2); + + FCL_REAL d1 = aabb2.distance((nodes1 + root1->children[0])->bv); + FCL_REAL d2 = aabb2.distance((nodes1 + root1->children[1])->bv); + + if(d2 < d1) + { + if(d2 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d1 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + else + { + if(d1 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[0], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + + if(d2 < min_dist) + { + if(distanceRecurse_(nodes1, root1->children[1], tree2, root2, root2_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + else + { + for(unsigned int i = 0; i < 8; ++i) + { + if(root2->childExists(i)) + { + const OcTree::OcTreeNode* child = root2->getChild(i); + AABB child_bv; + computeChildBV(root2_bv, i, child_bv); + + const AABB& aabb2 = translate(child_bv, tf2); + FCL_REAL d = root1->bv.distance(aabb2); + + if(d < min_dist) + { + if(distanceRecurse_(nodes1, root1_id, tree2, child, child_bv, tf2, cdata, callback, min_dist)) + return true; + } + } + } + } + + return false; +} + +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 +{ + if(tf2.getQuatRotation().isIdentity()) + return distanceRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2.getTranslation(), cdata, callback, min_dist); + else + return distanceRecurse_(nodes1, root1_id, tree2, root2, root2_bv, tf2, cdata, callback, min_dist); +} + + +} diff --git a/trunk/fcl/src/broadphase/broadphase_interval_tree.cpp b/trunk/fcl/src/broadphase/broadphase_interval_tree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..219086bc86dd1d35a35a61efd64c3d21ff658919 --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_interval_tree.cpp @@ -0,0 +1,654 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#include "fcl/broadphase/broadphase_interval_tree.h" +#include <algorithm> +#include <limits> +#include <boost/bind.hpp> + +namespace fcl +{ + +void IntervalTreeCollisionManager::unregisterObject(CollisionObject* obj) +{ + // must sorted before + setup(); + + EndPoint p; + p.value = obj->getAABB().min_[0]; + 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, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + + if(start1 < end1) + { + unsigned int start_id = start1 - endpoints[0].begin(); + unsigned int end_id = end1 - endpoints[0].begin(); + unsigned int cur_id = start_id; + for(unsigned int i = start_id; i < end_id; ++i) + { + if(endpoints[0][i].obj != obj) + { + if(i == cur_id) cur_id++; + else + { + endpoints[0][cur_id] = endpoints[0][i]; + cur_id++; + } + } + } + if(cur_id < end_id) + endpoints[0].resize(endpoints[0].size() - 2); + } + + p.value = obj->getAABB().min_[1]; + 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, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + + if(start2 < end2) + { + unsigned int start_id = start2 - endpoints[1].begin(); + unsigned int end_id = end2 - endpoints[1].begin(); + unsigned int cur_id = start_id; + for(unsigned int i = start_id; i < end_id; ++i) + { + if(endpoints[1][i].obj != obj) + { + if(i == cur_id) cur_id++; + else + { + endpoints[1][cur_id] = endpoints[1][i]; + cur_id++; + } + } + } + if(cur_id < end_id) + endpoints[1].resize(endpoints[1].size() - 2); + } + + + p.value = obj->getAABB().min_[2]; + 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, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + + if(start3 < end3) + { + unsigned int start_id = start3 - endpoints[2].begin(); + unsigned int end_id = end3 - endpoints[2].begin(); + unsigned int cur_id = start_id; + for(unsigned int i = start_id; i < end_id; ++i) + { + if(endpoints[2][i].obj != obj) + { + if(i == cur_id) cur_id++; + else + { + endpoints[2][cur_id] = endpoints[2][i]; + cur_id++; + } + } + } + if(cur_id < end_id) + endpoints[2].resize(endpoints[2].size() - 2); + } + + // update the interval tree + if(obj_interval_maps[0].find(obj) != obj_interval_maps[0].end()) + { + SAPInterval* ivl1 = obj_interval_maps[0][obj]; + SAPInterval* ivl2 = obj_interval_maps[1][obj]; + SAPInterval* ivl3 = obj_interval_maps[2][obj]; + + interval_trees[0]->deleteNode(ivl1); + interval_trees[1]->deleteNode(ivl2); + interval_trees[2]->deleteNode(ivl3); + + delete ivl1; + delete ivl2; + delete ivl3; + + obj_interval_maps[0].erase(obj); + obj_interval_maps[1].erase(obj); + obj_interval_maps[2].erase(obj); + } +} + +void IntervalTreeCollisionManager::registerObject(CollisionObject* obj) +{ + EndPoint p, q; + + p.obj = obj; + q.obj = obj; + p.minmax = 0; + q.minmax = 1; + p.value = obj->getAABB().min_[0]; + q.value = obj->getAABB().max_[0]; + endpoints[0].push_back(p); + endpoints[0].push_back(q); + + p.value = obj->getAABB().min_[1]; + q.value = obj->getAABB().max_[1]; + endpoints[1].push_back(p); + endpoints[1].push_back(q); + + p.value = obj->getAABB().min_[2]; + q.value = obj->getAABB().max_[2]; + endpoints[2].push_back(p); + endpoints[2].push_back(q); + setup_ = false; +} + +void IntervalTreeCollisionManager::setup() +{ + if(!setup_) + { + 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]; + + for(int i = 0; i < 3; ++i) + interval_trees[i] = new IntervalTree; + + for(unsigned int i = 0, size = endpoints[0].size(); i < size; ++i) + { + EndPoint p = endpoints[0][i]; + CollisionObject* obj = p.obj; + if(p.minmax == 0) + { + SAPInterval* ivl1 = new SAPInterval(obj->getAABB().min_[0], obj->getAABB().max_[0], obj); + SAPInterval* ivl2 = new SAPInterval(obj->getAABB().min_[1], obj->getAABB().max_[1], obj); + SAPInterval* ivl3 = new SAPInterval(obj->getAABB().min_[2], obj->getAABB().max_[2], obj); + + interval_trees[0]->insert(ivl1); + interval_trees[1]->insert(ivl2); + interval_trees[2]->insert(ivl3); + + obj_interval_maps[0][obj] = ivl1; + obj_interval_maps[1][obj] = ivl2; + obj_interval_maps[2][obj] = ivl3; + } + } + + setup_ = true; + } +} + +void IntervalTreeCollisionManager::update() +{ + setup_ = false; + + for(unsigned int i = 0, size = endpoints[0].size(); i < size; ++i) + { + if(endpoints[0][i].minmax == 0) + endpoints[0][i].value = endpoints[0][i].obj->getAABB().min_[0]; + else + endpoints[0][i].value = endpoints[0][i].obj->getAABB().max_[0]; + } + + for(unsigned int i = 0, size = endpoints[1].size(); i < size; ++i) + { + if(endpoints[1][i].minmax == 0) + endpoints[1][i].value = endpoints[1][i].obj->getAABB().min_[1]; + else + endpoints[1][i].value = endpoints[1][i].obj->getAABB().max_[1]; + } + + for(unsigned int i = 0, size = endpoints[2].size(); i < size; ++i) + { + if(endpoints[2][i].minmax == 0) + endpoints[2][i].value = endpoints[2][i].obj->getAABB().min_[2]; + else + endpoints[2][i].value = endpoints[2][i].obj->getAABB().max_[2]; + } + + setup(); + +} + + +void IntervalTreeCollisionManager::update(CollisionObject* updated_obj) +{ + AABB old_aabb; + const AABB& new_aabb = updated_obj->getAABB(); + for(int i = 0; i < 3; ++i) + { + std::map<CollisionObject*, SAPInterval*>::const_iterator it = obj_interval_maps[i].find(updated_obj); + interval_trees[i]->deleteNode(it->second); + old_aabb.min_[i] = it->second->low; + old_aabb.max_[i] = it->second->high; + it->second->low = new_aabb.min_[i]; + it->second->high = new_aabb.max_[i]; + interval_trees[i]->insert(it->second); + } + + EndPoint dummy; + std::vector<EndPoint>::iterator it; + for(int i = 0; i < 3; ++i) + { + dummy.value = old_aabb.min_[i]; + it = std::lower_bound(endpoints[i].begin(), endpoints[i].end(), dummy, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + for(; it != endpoints[i].end(); ++it) + { + if(it->obj == updated_obj && it->minmax == 0) + { + it->value = new_aabb.min_[i]; + break; + } + } + + dummy.value = old_aabb.max_[i]; + it = std::lower_bound(endpoints[i].begin(), endpoints[i].end(), dummy, boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + for(; it != endpoints[i].end(); ++it) + { + if(it->obj == updated_obj && it->minmax == 0) + { + it->value = new_aabb.max_[i]; + break; + } + } + + std::sort(endpoints[i].begin(), endpoints[i].end(), boost::bind(&EndPoint::value, _1) < boost::bind(&EndPoint::value, _2)); + } +} + +void IntervalTreeCollisionManager::update(const std::vector<CollisionObject*>& updated_objs) +{ + for(size_t i = 0; i < updated_objs.size(); ++i) + update(updated_objs[i]); +} + +void IntervalTreeCollisionManager::clear() +{ + endpoints[0].clear(); + endpoints[1].clear(); + endpoints[2].clear(); + + delete interval_trees[0]; interval_trees[0] = NULL; + delete interval_trees[1]; interval_trees[1] = NULL; + delete interval_trees[2]; interval_trees[2] = NULL; + + for(int i = 0; i < 3; ++i) + { + for(std::map<CollisionObject*, SAPInterval*>::const_iterator it = obj_interval_maps[i].begin(), end = obj_interval_maps[i].end(); + it != end; ++it) + { + delete it->second; + } + } + + for(int i = 0; i < 3; ++i) + obj_interval_maps[i].clear(); + + setup_ = false; +} + +void IntervalTreeCollisionManager::getObjects(std::vector<CollisionObject*>& objs) const +{ + objs.resize(endpoints[0].size() / 2); + unsigned int j = 0; + for(unsigned int i = 0, size = endpoints[0].size(); i < size; ++i) + { + if(endpoints[0][i].minmax == 0) + { + objs[j] = endpoints[0][i].obj; j++; + } + } +} + +void IntervalTreeCollisionManager::collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + collide_(obj, cdata, callback); +} + +bool IntervalTreeCollisionManager::collide_(CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + static const unsigned int CUTOFF = 100; + + std::deque<SimpleInterval*> results0, results1, results2; + + results0 = interval_trees[0]->query(obj->getAABB().min_[0], obj->getAABB().max_[0]); + if(results0.size() > CUTOFF) + { + results1 = interval_trees[1]->query(obj->getAABB().min_[1], obj->getAABB().max_[1]); + if(results1.size() > CUTOFF) + { + results2 = interval_trees[2]->query(obj->getAABB().min_[2], obj->getAABB().max_[2]); + if(results2.size() > CUTOFF) + { + int d1 = results0.size(); + int d2 = results1.size(); + int d3 = results2.size(); + + if(d1 >= d2 && d1 >= d3) + return checkColl(results0.begin(), results0.end(), obj, cdata, callback); + else if(d2 >= d1 && d2 >= d3) + return checkColl(results1.begin(), results1.end(), obj, cdata, callback); + else + return checkColl(results2.begin(), results2.end(), obj, cdata, callback); + } + else + return checkColl(results2.begin(), results2.end(), obj, cdata, callback); + } + else + return checkColl(results1.begin(), results1.end(), obj, cdata, callback); + } + else + return checkColl(results0.begin(), results0.end(), obj, cdata, callback); +} + +void IntervalTreeCollisionManager::distance(CollisionObject* obj, void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + distance_(obj, cdata, callback, min_dist); +} + +bool IntervalTreeCollisionManager::distance_(CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + static const unsigned int CUTOFF = 100; + + Vec3f delta = (obj->getAABB().max_ - obj->getAABB().min_) * 0.5; + AABB aabb = obj->getAABB(); + if(min_dist < std::numeric_limits<FCL_REAL>::max()) + { + Vec3f min_dist_delta(min_dist, min_dist, min_dist); + aabb.expand(min_dist_delta); + } + + int status = 1; + FCL_REAL old_min_distance; + + while(1) + { + bool dist_res = false; + + old_min_distance = min_dist; + + std::deque<SimpleInterval*> results0, results1, results2; + + results0 = interval_trees[0]->query(aabb.min_[0], aabb.max_[0]); + if(results0.size() > CUTOFF) + { + results1 = interval_trees[1]->query(aabb.min_[1], aabb.max_[1]); + if(results1.size() > CUTOFF) + { + results2 = interval_trees[2]->query(aabb.min_[2], aabb.max_[2]); + if(results2.size() > CUTOFF) + { + int d1 = results0.size(); + int d2 = results1.size(); + int d3 = results2.size(); + + if(d1 >= d2 && d1 >= d3) + dist_res = checkDist(results0.begin(), results0.end(), obj, cdata, callback, min_dist); + else if(d2 >= d1 && d2 >= d3) + dist_res = checkDist(results1.begin(), results1.end(), obj, cdata, callback, min_dist); + else + dist_res = checkDist(results2.begin(), results2.end(), obj, cdata, callback, min_dist); + } + else + dist_res = checkDist(results2.begin(), results2.end(), obj, cdata, callback, min_dist); + } + else + dist_res = checkDist(results1.begin(), results1.end(), obj, cdata, callback, min_dist); + } + else + dist_res = checkDist(results0.begin(), results0.end(), obj, cdata, callback, min_dist); + + if(dist_res) return true; + + results0.clear(); + results1.clear(); + results2.clear(); + + if(status == 1) + { + if(old_min_distance < std::numeric_limits<FCL_REAL>::max()) + break; + 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 IntervalTreeCollisionManager::collide(void* cdata, CollisionCallBack callback) const +{ + if(size() == 0) return; + + std::set<CollisionObject*> active; + std::set<std::pair<CollisionObject*, CollisionObject*> > overlap; + unsigned int n = endpoints[0].size(); + double diff_x = endpoints[0][0].value - endpoints[0][n-1].value; + double diff_y = endpoints[1][0].value - endpoints[1][n-1].value; + double diff_z = endpoints[2][0].value - endpoints[2][n-1].value; + + int axis = 0; + if(diff_y > diff_x && diff_y > diff_z) + axis = 1; + else if(diff_z > diff_y && diff_z > diff_x) + axis = 2; + + for(unsigned int i = 0; i < n; ++i) + { + const EndPoint& endpoint = endpoints[axis][i]; + CollisionObject* index = endpoint.obj; + if(endpoint.minmax == 0) + { + std::set<CollisionObject*>::iterator iter = active.begin(); + std::set<CollisionObject*>::iterator end = active.end(); + for(; iter != end; ++iter) + { + CollisionObject* active_index = *iter; + const AABB& b0 = active_index->getAABB(); + const AABB& b1 = index->getAABB(); + + int axis2 = (axis + 1) % 3; + int axis3 = (axis + 2) % 3; + + if(b0.axisOverlap(b1, axis2) && b0.axisOverlap(b1, axis3)) + { + std::pair<std::set<std::pair<CollisionObject*, CollisionObject*> >::iterator, bool> insert_res; + if(active_index < index) + insert_res = overlap.insert(std::make_pair(active_index, index)); + else + insert_res = overlap.insert(std::make_pair(index, active_index)); + + if(insert_res.second) + { + if(callback(active_index, index, cdata)) + return; + } + } + } + active.insert(index); + } + else + active.erase(index); + } + +} + +void IntervalTreeCollisionManager::distance(void* cdata, DistanceCallBack callback) const +{ + if(size() == 0) return; + + enable_tested_set_ = true; + tested_set.clear(); + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + for(size_t i = 0; i < endpoints[0].size(); ++i) + if(distance_(endpoints[0][i].obj, cdata, callback, min_dist)) break; + + enable_tested_set_ = false; + tested_set.clear(); +} + +void IntervalTreeCollisionManager::collide(BroadPhaseCollisionManager* other_manager_, void* cdata, CollisionCallBack callback) const +{ + IntervalTreeCollisionManager* other_manager = static_cast<IntervalTreeCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + collide(cdata, callback); + return; + } + + if(this->size() < other_manager->size()) + { + for(size_t i = 0, size = endpoints[0].size(); i < size; ++i) + if(other_manager->collide_(endpoints[0][i].obj, cdata, callback)) return; + } + else + { + for(size_t i = 0, size = other_manager->endpoints[0].size(); i < size; ++i) + if(collide_(other_manager->endpoints[0][i].obj, cdata, callback)) return; + } +} + +void IntervalTreeCollisionManager::distance(BroadPhaseCollisionManager* other_manager_, void* cdata, DistanceCallBack callback) const +{ + IntervalTreeCollisionManager* other_manager = static_cast<IntervalTreeCollisionManager*>(other_manager_); + + if((size() == 0) || (other_manager->size() == 0)) return; + + if(this == other_manager) + { + distance(cdata, callback); + return; + } + + FCL_REAL min_dist = std::numeric_limits<FCL_REAL>::max(); + + if(this->size() < other_manager->size()) + { + for(size_t i = 0, size = endpoints[0].size(); i < size; ++i) + if(other_manager->distance_(endpoints[0][i].obj, cdata, callback, min_dist)) return; + } + else + { + for(size_t i = 0, size = other_manager->endpoints[0].size(); i < size; ++i) + if(distance_(other_manager->endpoints[0][i].obj, cdata, callback, min_dist)) return; + } +} + +bool IntervalTreeCollisionManager::empty() const +{ + return endpoints[0].empty(); +} + +bool IntervalTreeCollisionManager::checkColl(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, CollisionCallBack callback) const +{ + while(pos_start < pos_end) + { + SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start); + if(ivl->obj != obj) + { + if(ivl->obj->getAABB().overlap(obj->getAABB())) + { + if(callback(ivl->obj, obj, cdata)) + return true; + } + } + + pos_start++; + } + + return false; +} + +bool IntervalTreeCollisionManager::checkDist(std::deque<SimpleInterval*>::const_iterator pos_start, std::deque<SimpleInterval*>::const_iterator pos_end, CollisionObject* obj, void* cdata, DistanceCallBack callback, FCL_REAL& min_dist) const +{ + while(pos_start < pos_end) + { + SAPInterval* ivl = static_cast<SAPInterval*>(*pos_start); + if(ivl->obj != obj) + { + if(!enable_tested_set_) + { + if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) + { + if(callback(ivl->obj, obj, cdata, min_dist)) + return true; + } + } + else + { + if(!inTestedSet(ivl->obj, obj)) + { + if(ivl->obj->getAABB().distance(obj->getAABB()) < min_dist) + { + if(callback(ivl->obj, obj, cdata, min_dist)) + return true; + } + + insertTestedSet(ivl->obj, obj); + } + } + } + + pos_start++; + } + + return false; +} + +} diff --git a/trunk/fcl/src/broadphase/broadphase_spatialhash.cpp b/trunk/fcl/src/broadphase/broadphase_spatialhash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e39cb3302dd0d3c04e53e06688e7498351ce030d --- /dev/null +++ b/trunk/fcl/src/broadphase/broadphase_spatialhash.cpp @@ -0,0 +1,42 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** \author Jia Pan */ + +#include "fcl/broadphase/broadphase_spatialhash.h" + +namespace fcl +{ + +} diff --git a/trunk/fcl/src/hierarchy_tree.cpp b/trunk/fcl/src/broadphase/hierarchy_tree.cpp similarity index 98% rename from trunk/fcl/src/hierarchy_tree.cpp rename to trunk/fcl/src/broadphase/hierarchy_tree.cpp index 015ce41d245a0fa1fbae40d487c2a2cc69657822..9c3ce96dad9140fe67b9b27761993886a8f614b8 100644 --- a/trunk/fcl/src/hierarchy_tree.cpp +++ b/trunk/fcl/src/broadphase/hierarchy_tree.cpp @@ -34,7 +34,7 @@ /** \author Jia Pan */ -#include "fcl/hierarchy_tree.h" +#include "fcl/broadphase/hierarchy_tree.h" namespace fcl { @@ -100,7 +100,7 @@ bool HierarchyTree<AABB>::update(NodeBase<AABB>* leaf, const AABB& bv_, const Ve return true; } -namespace alternative +namespace implementation_array { template<> size_t select(size_t query, size_t node1, size_t node2, NodeBase<AABB>* nodes) diff --git a/trunk/fcl/src/interval_tree.cpp b/trunk/fcl/src/broadphase/interval_tree.cpp similarity index 94% rename from trunk/fcl/src/interval_tree.cpp rename to trunk/fcl/src/broadphase/interval_tree.cpp index d96dc2fa6a2c41416dfe604d8772845eeb161d2f..1585b0145801b9cbefdeb613bd811df8b767b9db 100644 --- a/trunk/fcl/src/interval_tree.cpp +++ b/trunk/fcl/src/broadphase/interval_tree.cpp @@ -34,7 +34,7 @@ /** \author Jia Pan */ -#include "fcl/interval_tree.h" +#include "fcl/broadphase/interval_tree.h" #include <iostream> #include <cstdlib> @@ -45,13 +45,28 @@ namespace fcl IntervalTreeNode::IntervalTreeNode(){} IntervalTreeNode::IntervalTreeNode(SimpleInterval* new_interval) : - stored_interval (new_interval), - key(new_interval->low), - high(new_interval->high), - max_high(high) {} + stored_interval (new_interval), + key(new_interval->low), + high(new_interval->high), + max_high(high) {} IntervalTreeNode::~IntervalTreeNode() {} + +/// @brief Class describes the information needed when we take the +/// right branch in searching for intervals but possibly come back +/// and check the left branch as well. +struct it_recursion_node +{ +public: + IntervalTreeNode* start_node; + + unsigned int parent_index; + + bool try_right_branch; +}; + + IntervalTree::IntervalTree() { nil = new IntervalTreeNode; @@ -66,7 +81,7 @@ IntervalTree::IntervalTree() root->red = false; root->stored_interval = NULL; - /* the following are used for the query function */ + /// the following are used for the query function recursion_node_stack_size = 128; recursion_node_stack = (it_recursion_node*)malloc(recursion_node_stack_size*sizeof(it_recursion_node)); recursion_node_stack_top = 1; @@ -159,7 +174,7 @@ void IntervalTree::rightRotate(IntervalTreeNode* y) -/** \brief Inserts z into the tree as if it were a regular binary tree */ +/// @brief Inserts z into the tree as if it were a regular binary tree void IntervalTree::recursiveInsert(IntervalTreeNode* z) { IntervalTreeNode* x; @@ -206,7 +221,7 @@ IntervalTreeNode* IntervalTree::insert(SimpleInterval* new_interval) x->red = true; while(x->parent->red) { - /* use sentinel instead of checking for root */ + /// use sentinel instead of checking for root if(x->parent == x->parent->parent->left) { y = x->parent->parent->right; @@ -452,8 +467,8 @@ SimpleInterval* IntervalTree::deleteNode(IntervalTreeNode* z) } } - /* y should not be nil in this case */ - /* y is the node to splice out and x is its child */ + /// @brief y should not be nil in this case + /// y is the node to splice out and x is its child if(y != z) { y->max_high = -std::numeric_limits<double>::max(); @@ -486,7 +501,7 @@ SimpleInterval* IntervalTree::deleteNode(IntervalTreeNode* z) return node_to_delete; } -/** \brief returns 1 if the intervals overlap, and 0 otherwise */ +/// @brief returns 1 if the intervals overlap, and 0 otherwise bool overlap(double a1, double a2, double b1, double b2) { if(a1 <= b1)