diff --git a/.travis.yml b/.travis.yml index 8a7593e12731348cb1ab3f9182ee4bcaac6fc217..b34dd4f9ceb367fb0765e9ef07f3e9aad5a94c61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,30 +4,78 @@ env: global: - CTEST_PARALLEL_LEVEL=4 - CTEST_OUTPUT_ON_FAILURE=1 + - CXX_FLAGS_DEBUG="-O1" + - BUILD_PYTHON_INTERFACE=ON - MAKEFLAGS="-j2" +cache: + ccache: true + matrix: include: - - dist: trusty - compiler: gcc + - name: "Trusty - Release - g++" env: BUILD_TYPE=Release - - dist: xenial - compiler: gcc + dist: trusty + compiler: g++ + addons: + apt: + packages: + - cmake + - libboost-all-dev + - libassimp-dev + - libeigen3-dev + + - name: "Xenial - Release - g++" env: BUILD_TYPE=Release - - dist: bionic - compiler: gcc + dist: xenial + compiler: g++ + addons: + apt: + packages: + - cmake + - libboost-all-dev + - libassimp-dev + - libeigen3-dev + - liboctomap-dev + + - name: "Bionic - Release - g++" env: BUILD_TYPE=Release - - dist: bionic - compiler: gcc + dist: bionic + compiler: g++ + addons: + apt: + packages: + - cmake + - libboost-all-dev + - libassimp-dev + - libeigen3-dev + - liboctomap-dev + + - name: "Bionic - Debug - g++" env: BUILD_TYPE=Debug - - os: osx - compiler: clang + dist: bionic + compiler: g++ + addons: + apt: + packages: + - cmake + - libboost-all-dev + - libassimp-dev + - libeigen3-dev + - liboctomap-dev + + - name: "OSX - Release - clang" env: BUILD_TYPE=Release + os: osx + compiler: clang + cache: + ccache: true + directories: + - $HOME/Library/Caches/Homebrew -install: - # Install dependencies for FCL - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then 'ci/install_linux.sh' ; fi - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then 'ci/install_osx.sh' ; fi +before_install: + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then source travis_custom/custom_before_install_linux.sh ; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then source travis_custom/custom_before_install_osx.sh ; fi script: # Create build directory @@ -35,7 +83,7 @@ script: - cd build # Configure - - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS=-w .. + - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS=-w -DCMAKE_CXX_FLAGS_DEBUG=${CXX_FLAGS_DEBUG} -DBUILD_PYTHON_INTERFACE=${BUILD_PYTHON_INTERFACE} .. # Build - make diff --git a/CMakeLists.txt b/CMakeLists.txt index d2d53d9cb4c80233995131989a1bef1a2cd28046..2b787c5a8ebf7f9ebc20075e75531bdfb3bb6cce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,16 +34,17 @@ cmake_minimum_required(VERSION 2.8) set(CXX_DISABLE_WERROR TRUE) -include(cmake/base.cmake) -include(cmake/eigen.cmake) -include(cmake/boost.cmake) -include(cmake/hpp.cmake) set(PROJECT_NAME hpp-fcl) set(PROJECT_DESCRIPTION "HPP fork of FCL -- The Flexible Collision Library" ) +include(cmake/eigen.cmake) +include(cmake/boost.cmake) +include(cmake/python.cmake) +include(cmake/hpp.cmake) + IF(APPLE) SET(CMAKE_MACOSX_RPATH TRUE) SET(CMAKE_SKIP_BUILD_RPATH FALSE) @@ -57,7 +58,11 @@ IF(APPLE) endif("${isSystemDir}" STREQUAL "-1") ENDIF(APPLE) -setup_hpp_project() +OPTION(BUILD_PYTHON_INTERFACE "Build the python bindings" OFF) + +# Tell CMake that we compute the PROJECT_VERSION manually. +CMAKE_POLICY(SET CMP0048 OLD) +project(${PROJECT_NAME} CXX) add_required_dependency("eigen3 >= 3.0.0") include_directories(SYSTEM ${EIGEN3_INCLUDE_DIRS}) @@ -66,10 +71,13 @@ include_directories(SYSTEM ${EIGEN3_INCLUDE_DIRS}) set (RUN_TESTS TRUE CACHE BOOL "compile and run unit tests") # Required dependencies +set(BOOST_COMPONENTS thread date_time system) if (RUN_TESTS) - set(BOOST_COMPONENTS thread date_time filesystem system unit_test_framework) -else () - set(BOOST_COMPONENTS thread date_time system) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} filesystem unit_test_framework) +endif () +if (BUILD_PYTHON_INTERFACE) + FINDPYTHON() + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} python) endif () search_for_boost() @@ -97,10 +105,8 @@ ADD_REQUIRED_DEPENDENCY("assimp >= 2.0") if(ASSIMP_FOUND) if (NOT ${ASSIMP_VERSION} VERSION_LESS "2.0.1150") add_definitions(-DHPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES) - SET(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES TRUE) message(STATUS "Assimp version has unified headers") else() - SET(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES FALSE) message(STATUS "Assimp version does not have unified headers") endif() endif() @@ -118,57 +124,53 @@ SET(${PROJECT_NAME}_HEADERS include/hpp/fcl/BV/kDOP.h include/hpp/fcl/narrowphase/narrowphase.h include/hpp/fcl/narrowphase/gjk.h - include/hpp/fcl/shape/geometric_shapes_utility.h include/hpp/fcl/shape/geometric_shape_to_BVH_model.h include/hpp/fcl/shape/geometric_shapes.h include/hpp/fcl/distance_func_matrix.h include/hpp/fcl/collision.h - include/hpp/fcl/collision_node.h include/hpp/fcl/collision_func_matrix.h include/hpp/fcl/distance.h include/hpp/fcl/math/matrix_3f.h include/hpp/fcl/math/vec_3f.h - include/hpp/fcl/math/tools.h + include/hpp/fcl/math/types.h include/hpp/fcl/math/transform.h - include/hpp/fcl/traversal/details/traversal.h - include/hpp/fcl/traversal/traversal_node_shapes.h - include/hpp/fcl/traversal/traversal_node_setup.h - include/hpp/fcl/traversal/traversal_recurse.h - include/hpp/fcl/traversal/traversal_node_octree.h - include/hpp/fcl/traversal/traversal_node_bvhs.h - include/hpp/fcl/traversal/traversal_node_bvh_shape.h - include/hpp/fcl/traversal/traversal_node_base.h include/hpp/fcl/data_types.h - include/hpp/fcl/BVH/BV_splitter.h include/hpp/fcl/BVH/BVH_internal.h include/hpp/fcl/BVH/BVH_model.h - include/hpp/fcl/BVH/BV_fitter.h include/hpp/fcl/BVH/BVH_front.h include/hpp/fcl/BVH/BVH_utility.h - include/hpp/fcl/intersect.h include/hpp/fcl/collision_object.h include/hpp/fcl/collision_utility.h include/hpp/fcl/octree.h include/hpp/fcl/fwd.hh include/hpp/fcl/mesh_loader/assimp.h include/hpp/fcl/mesh_loader/loader.h + include/hpp/fcl/internal/BV_fitter.h + include/hpp/fcl/internal/BV_splitter.h + include/hpp/fcl/internal/intersect.h + include/hpp/fcl/internal/tools.h + include/hpp/fcl/internal/traversal_node_base.h + include/hpp/fcl/internal/traversal_node_bvh_shape.h + include/hpp/fcl/internal/traversal_node_bvhs.h + include/hpp/fcl/internal/traversal_node_octree.h + include/hpp/fcl/internal/traversal_node_setup.h + include/hpp/fcl/internal/traversal_node_shapes.h + include/hpp/fcl/internal/traversal_recurse.h + include/hpp/fcl/internal/traversal.h ) add_subdirectory(src) +if (BUILD_PYTHON_INTERFACE) + add_subdirectory(python) +endif () if (RUN_TESTS) add_subdirectory(test) endif () pkg_config_append_libs("hpp-fcl") PKG_CONFIG_APPEND_BOOST_LIBS(thread date_time filesystem system) -IF(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES) - #Â FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES kept for backard compatibility reasons. - PKG_CONFIG_APPEND_CFLAGS("-DFCL_USE_ASSIMP_UNIFIED_HEADER_NAMES -DHPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES") -ENDIF(HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES) IF(HPP_FCL_HAVE_OCTOMAP) #Â FCL_HAVE_OCTOMAP kept for backward compatibility reasons. PKG_CONFIG_APPEND_CFLAGS( "-DHPP_FCL_HAVE_OCTOMAP -DFCL_HAVE_OCTOMAP -DOCTOMAP_MAJOR_VERSION=${OCTOMAP_MAJOR_VERSION} -DOCTOMAP_MINOR_VERSION=${OCTOMAP_MINOR_VERSION} -DOCTOMAP_PATCH_VERSION=${OCTOMAP_PATCH_VERSION}") ENDIF(HPP_FCL_HAVE_OCTOMAP) - -setup_hpp_project_finalize() diff --git a/README.md b/README.md index 26b99ec6bf79fb50c1234d21450c744f6a0b06a3..6641511a9ea4e6e0dcff1f764f8b7e9cfbc68029 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,8 @@ [](https://gepgitlab.laas.fr/humanoid-path-planner/hpp-fcl/commits/master) [](http://projects.laas.fr/gepetto/doc/humanoid-path-planner/hpp-fcl/master/coverage/) -This project is a fork from https://github.com/flexible-collision-library/fcl. The main difference is the computation of a lower bound of the distance between two objects when collision checking is performed and no collision is found. +This project is a fork from https://github.com/flexible-collision-library/fcl. + +The main differences are. +- the use of a safety margin when detecting collision, +- the computation of a lower bound of the distance between two objects when collision checking is performed and no collision is found. diff --git a/ci/install_linux.sh b/ci/install_linux.sh deleted file mode 100755 index db894789de15500662bb69b03a187bdc8c287af8..0000000000000000000000000000000000000000 --- a/ci/install_linux.sh +++ /dev/null @@ -1,20 +0,0 @@ -sudo apt-get -qq update - -######################## -# Mendatory dependencies -######################## -sudo apt-get -qq --yes --force-yes install cmake -sudo apt-get -qq --yes --force-yes install libboost-all-dev -sudo apt-get -qq --yes --force-yes install libassimp-dev -sudo apt-get -qq --yes --force-yes install libeigen3-dev - -# Octomap -git clone https://github.com/OctoMap/octomap -cd octomap -git checkout tags/v1.8.0 -mkdir build -cd build -cmake .. -make -sudo make install - diff --git a/ci/install_osx.sh b/ci/install_osx.sh deleted file mode 100755 index 9f90326aad01b93f0d96bb99646271cd22e9affe..0000000000000000000000000000000000000000 --- a/ci/install_osx.sh +++ /dev/null @@ -1,9 +0,0 @@ -brew tap homebrew/science - -brew install git -brew install cmake -brew install boost -brew install libccd -brew install assimp -brew install eigen -brew install octomap diff --git a/cmake b/cmake index 441552634e4c427956be7b2834a6bbf894b24f0c..46dc4a57521bde14ea75c959b6b4f887af50c65d 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 441552634e4c427956be7b2834a6bbf894b24f0c +Subproject commit 46dc4a57521bde14ea75c959b6b4f887af50c65d diff --git a/doc/gjk.py b/doc/gjk.py new file mode 100644 index 0000000000000000000000000000000000000000..06d25c93e542616768cdb5486df11e7f11f3d50b --- /dev/null +++ b/doc/gjk.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +import pdb +import sys + +#Â ABC = AB^AC +# (ABC^AJ).a = (j.c - j.b) a.a + (j.a - j.c) b.a + (j.b - j.a) c.a, for j = b or c + +segment_fmt = "{j}a_aa" +plane_fmt = "" +edge_fmt = "{j}a * {b}a_{c}a + {j}{b} * {c}a_aa - {j}{c} * {b}a_aa" + +# These checks must be negative and not positive, as in the cheat sheet. +# They are the same as in the cheat sheet, except that we consider (...).dot(A) instead of (...).dot(-A) +plane_tests = [ "C.dot (a_cross_b)", "D.dot(a_cross_c)", "-D.dot(a_cross_b)" ] +checks = plane_tests \ + + [ edge_fmt.format (**{'j':j,'b':"b",'c':"c"}) for j in [ "b", "c" ] ] \ + + [ edge_fmt.format (**{'j':j,'b':"c",'c':"d"}) for j in [ "c", "d" ] ] \ + + [ edge_fmt.format (**{'j':j,'b':"d",'c':"b"}) for j in [ "d", "b" ] ] \ + + [ segment_fmt.format(**{'j':j}) for j in [ "b", "c", "d" ] ] +checks_hr = [ "ABC.AO >= 0", "ACD.AO >= 0", "ADB.AO >= 0" ] \ + + [ "(ABC ^ {}).AO >= 0".format(n) for n in [ "AB", "AC" ] ] \ + + [ "(ACD ^ {}).AO >= 0".format(n) for n in [ "AC", "AD" ] ] \ + + [ "(ADB ^ {}).AO >= 0".format(n) for n in [ "AD", "AB" ] ] \ + + [ "AB.AO >= 0", "AC.AO >= 0", "AD.AO >= 0" ] + +# weights of the checks. +weights = [ 2, ] * 3 + [ 3, ] * 6 + [ 1, ] * 3 + +# Segment tests first, because they have lower weight. +#tests = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ] +tests = [9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, ] +assert len(tests) == len(checks) +assert sorted(tests) == list(range(len(tests))) + +regions = [ "ABC", "ACD", "ADB", "AB", "AC", "AD", "A", "Inside", ] +cases = list(range(len(regions))) + +# The following 3 lists refer to table doc/GJK_tetrahedra_boolean_table.ods + +# A check ID is (+/- (index+1)) where a minus sign encodes a NOT operation +# and index refers to an index in list checks. + +# definitions is a list of list of check IDs to be ANDed. +# For instance, a0.a3.!a4 -> [ 1, 4, -5] +definitions = [ + [ 1, 4,- 5 ], + [ 2, 6,- 7 ], + [ 3, 8,- 9 ], + [- 4, 9, 10 ], + [- 6, 5, 11 ], + [- 8, 7, 12 ], + [-10,-11,-12 ], + [- 1,- 2,- 3 ], + ] +# conditions is a list of (list of (list of check IDs to be ANDed) to be ORed). +conditions = [ + [], + [], + [], + [], + [], + [], + [], + [ ], #[ [10, 11, 12], ], # I don't think this is always true... + ] +# rejections is a list of (list of (list of check IDs to be ANDed) to be ORed). +rejections = [ + [ [ 2, 6, 7], [ 3,- 8,- 9], ], + [ [ 3, 8, 9], [ 1,- 4,- 5], ], + [ [ 1, 4, 5], [ 2,- 6,- 7], ], + [ [- 1,- 3], ], + [ [- 2,- 1], ], + [ [- 3,- 2], ], + [ [ 4,- 5], [ 6,- 7], [ 8,- 9], ], + [], + ] + +implications = [ + [ [ 4, 5, 10, ], [ 11],], + [ [ 6, 7, 11, ], [ 12],], + [ [ 8, 9, 12, ], [ 10],], + + [ [- 4,- 5, 11, ], [ 10],], + [ [- 6,- 7, 12, ], [ 11],], + [ [- 8,- 9, 10, ], [ 12],], + + [ [ 1, 4, 5, 6], [- 7] ], + [ [ 2, 6, 9, 8], [- 9] ], + [ [ 3, 8, 9, 4], [- 5] ], + + [ [- 4, 5, 10,], [- 11] ], + [ [ 4,- 5,- 10,], [ 11] ], + [ [- 6, 7, 11,], [- 12] ], + [ [ 6,- 7,- 11,], [ 12] ], + [ [- 8, 9, 12,], [- 10] ], + [ [ 8,- 9,- 12,], [ 10] ], + + [ [ 10, 3, 9, -12, 4, -5], [1] ], + [ [ 10, -3, 1, -4], [9] ], + [ [ 10, -3, -1, 2, -6, 11], [5] ], + [ [ -10, 11, 2, -12, -5, -1], [6] ], + [ [ -10,11,-2,1,5], [-6] ], + [ [-10,-11,12,1,-7,-2,4],[-5]], + [ [-10,-11,12,-3,2,7],[-8]], + [ [-10,-11,12,-3,-2],[-1]], + ] + +def set_test_values (current_tests, test_values, itest, value): + def satisfies (values, indices): + for k in indices: + if k > 0 and values[ k-1] != True : return False + if k < 0 and values[-k-1] != False: return False + return True + + remaining_tests = list(current_tests) + next_test_values = list(test_values) + + remaining_tests.remove (itest) + next_test_values[itest] = value + rerun = True + while rerun: + rerun = False + for impl in implications: + if satisfies(next_test_values, impl[0]): + for id in impl[1]: + k = (id - 1) if id > 0 else (-id-1) + if k in remaining_tests: + next_test_values[k] = (id > 0) + remaining_tests.remove(k) + rerun = True + else: + if next_test_values[k] != (id > 0): + raise ValueError ("Absurd case") + return remaining_tests, next_test_values + +def set_tests_values (current_tests, test_values, itests, values): + for itest,value in zip(itests,values): + current_tests, test_values = set_test_values (current_tests, test_values, itest, value) + return current_tests, test_values + +def apply_test_values (cases, test_values): + def canSatisfy (values, indices): + for k in indices: + if k > 0 and values[ k-1] == False: return False + if k < 0 and values[-k-1] == True : return False + return True + def satisfies (values, indices): + for k in indices: + if k > 0 and values[ k-1] != True : return False + if k < 0 and values[-k-1] != False: return False + return True + + # Check all cases. + left_cases = [] + for case in cases: + defi = definitions[case] + conds = conditions[case] + rejs = rejections[case] + if satisfies (test_values, defi): + # A definition is True, stop recursion + return [ case ] + if not canSatisfy (test_values, defi): + continue + for cond in conds: + if satisfies (test_values, cond): + # A condition is True, stop recursion + return [ case ] + append = True + for rej in rejs: + if satisfies (test_values, rej): + # A rejection is True, discard this case + append = False + break + if append: left_cases.append (case) + return left_cases + +def max_number_of_tests (current_tests, cases, test_values = [None,]*len(tests), prevBestScore = float('inf'), prevScore = 0): + for test in current_tests: + assert test_values[test] == None, "Test " +str(test)+ " already performed" + + left_cases = apply_test_values (cases, test_values) + + if len(left_cases) == 1: + return prevScore, { 'case': left_cases[0], } + elif len(left_cases) == 0: + return prevScore, { 'case': None, 'comments': [ "applied " + str(test_values), "to " + ", ".join([regions[c] for c in cases ]) ] } + + assert len(current_tests) > 0, "No more test but " + str(left_cases) + " remains" + + currentBestScore = prevBestScore + bestScore = float('inf') + bestOrder = [None, None] + for i, test in enumerate(current_tests): + assert bestScore >= currentBestScore + + currentScore = prevScore + len(left_cases) * weights[test] + #currentScore = prevScore + weights[test] + if currentScore > currentBestScore: # Cannot do better -> stop + continue + + try: + remaining_tests, next_test_values = set_test_values (current_tests, test_values, test, True) + except ValueError: + remaining_tests = None + + if remaining_tests is not None: + # Do not put this in try catch as I do not want other ValueError to be understood as an infeasible branch. + score_if_t, order_if_t = max_number_of_tests (remaining_tests, left_cases, next_test_values, currentBestScore, currentScore) + if score_if_t >= currentBestScore: # True didn't do better -> stop + continue + else: + score_if_t, order_if_t = prevScore, None + + try: + remaining_tests, next_test_values = set_test_values (current_tests, test_values, test, False) + except ValueError: + remaining_tests = None + + if remaining_tests is not None: + # Do not put this in try catch as I do not want other ValueError to be understood as an infeasible branch. + score_if_f, order_if_f = max_number_of_tests (remaining_tests, left_cases, next_test_values, currentBestScore, currentScore) + else: + score_if_f, order_if_f = prevScore, None + + currentScore = max(score_if_t, score_if_f) + if currentScore < bestScore: + if currentScore < currentBestScore: + bestScore = currentScore + bestOrder = { 'test': test, 'true': order_if_t, 'false': order_if_f } + #pdb.set_trace() + currentBestScore = currentScore + if len(tests) == len(current_tests): + print ("New best score: {}".format(currentBestScore)) + + return bestScore, bestOrder + +def printComments (order, indent, file): + if 'comments' in order: + for comment in order['comments']: + print (indent + "// " + comment, file=file) + +def printOrder (order, indent = "", start=True,file=sys.stdout,curTests=[]): + if start: + print ("bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next)", file=file) + print ("{", file=file) + print (indent+"// The code of this function was generated using doc/gjk.py", file=file) + print (indent+"const vertex_id_t a = 3, b = 2, c = 1, d = 0;", file=file) + for l in "abcd": + print (indent+"const Vec3f& {} (current.vertex[{}]->w);".format(l.upper(),l), file=file) + print (indent+"const FCL_REAL aa = A.squaredNorm();".format(l), file=file) + for l in "dcb": + for m in "abcd": + if m <= l: + print (indent+"const FCL_REAL {0}{1} = {2}.dot({3});".format(l,m,l.upper(),m.upper()), file=file) + else: + print (indent+"const FCL_REAL& {0}{1} = {1}{0};".format(l,m), file=file) + print (indent+"const FCL_REAL {0}a_aa = {0}a - aa;".format(l), file=file) + for l0,l1 in zip("bcd","cdb"): + print (indent+"const FCL_REAL {0}a_{1}a = {0}a - {1}a;".format(l0,l1), file=file) + for l in "bc": + print (indent+"const Vec3f a_cross_{0} = A.cross({1});".format(l,l.upper()), file=file) + print("", file=file) + print( "#define REGION_INSIDE() "+indent+"\\", file=file) + print(indent+" ray.setZero(); \\", file=file) + print(indent+" next.vertex[0] = current.vertex[d]; \\", file=file) + print(indent+" next.vertex[1] = current.vertex[c]; \\", file=file) + print(indent+" next.vertex[2] = current.vertex[b]; \\", file=file) + print(indent+" next.vertex[3] = current.vertex[a]; \\", file=file) + print(indent+" next.rank=4; \\", file=file) + print(indent+" return true;", file=file) + print("", file=file) + + if 'case' in order: + case = order['case'] + if case is None: + print (indent + "// There are no case corresponding to this set of tests.", file=file) + printComments (order, indent, file) + print (indent + "assert(false);", file=file) + return + region = regions[case] + print (indent + "// Region " + region, file=file) + printComments (order, indent, file) + toFree = ['b', 'c', 'd'] + if region == "Inside": + print (indent + "REGION_INSIDE()", file=file) + toFree = [] + elif region == 'A': + print (indent + "originToPoint (current, a, A, next, ray);", file=file) + elif len(region)==2: + a = region[0] + B = region[1] + print (indent + "originToSegment (current, a, {b}, A, {B}, {B}-A, -{b}a_aa, next, ray);".format( + **{ 'b':B.lower(), 'B':B,} ), file=file) + toFree.remove(B.lower()) + elif len(region)==3: + B = region[1] + C = region[2] + test = plane_tests[['ABC','ACD','ADB'].index(region)] + if test.startswith('-'): test = test[1:] + else: test = '-'+test + print (indent + "originToTriangle (current, a, {b}, {c}, ({B}-A).cross({C}-A), {t}, next, ray);".format( + **{'b':B.lower(), 'c':C.lower(), 'B':B, 'C':C, 't':test}), file=file) + toFree.remove(B.lower()) + toFree.remove(C.lower()) + else: + assert False, "Unknown region " + region + for pt in toFree: + print (indent + "free_v[nfree++] = current.vertex[{}];".format(pt), file=file) + else: + assert "test" in order and 'true' in order and 'false' in order + check = checks[order['test']] + check_hr = checks_hr[order['test']] + printComments (order, indent, file) + nextTests_t=curTests+["a"+str(order['test']+1),] + nextTests_f=curTests+["!a"+str(order['test']+1),] + if order['true'] is None: + if order['false'] is None: + print (indent + """assert(false && "Case {} should never happen.");""".format(check_hr)) + else: + print (indent + "assert(!({} <= 0)); // Not {} / {}".format(check, check_hr, ".".join(nextTests_f)), file=file) + printOrder (order['false'], indent=indent, start=False, file=file, curTests=nextTests_f) + elif order['false'] is None: + print (indent + "assert({} <= 0); // {} / {}".format(check, check_hr, ".".join(nextTests_t)), file=file) + printOrder (order['true'], indent=indent, start=False, file=file, curTests=nextTests_t) + else: + print (indent + "if ({} <= 0) {{ // if {} / {}".format(check, check_hr, ".".join(nextTests_t)), file=file) + printOrder (order['true'], indent=indent+" ", start=False, file=file, curTests=nextTests_t) + print (indent + "}} else {{ // not {} / {}".format(check_hr, ".".join(nextTests_f)), file=file) + printOrder (order['false'], indent=indent+" ", start=False, file=file, curTests=nextTests_f) + print (indent + "}} // end of {}".format(check_hr), file=file) + + if start: + print ("",file=file) + print ("#undef REGION_INSIDE", file=file) + print (indent+"return false;", file=file) + print ("}", file=file) + +def unit_tests (): + # a4, a5, a10, a11, a12 + cases = list(range(len(regions))) + pdb.set_trace() + left_cases = apply_test_values (cases, + test_values=[None,None,None,True,True,None,None,None,None,True,True,True]) + assert len(left_cases) > 1 + +#unit_tests() + +score, order = max_number_of_tests (tests, cases) + +print(score) +printOrder(order, indent=" ") + +# TODO add weights such that: +# - it is preferred to have all the use of one check in one branch. +# idea: ponderate by the number of remaining tests. diff --git a/include/hpp/fcl/BV/AABB.h b/include/hpp/fcl/BV/AABB.h index 0b93c48a0ab6829d21abf18557526aa2f1d442b5..55a5e4adb92a73b9d2b8416c487b1075a8bac831 100644 --- a/include/hpp/fcl/BV/AABB.h +++ b/include/hpp/fcl/BV/AABB.h @@ -39,14 +39,17 @@ #define HPP_FCL_AABB_H #include <stdexcept> -#include <hpp/fcl/math/vec_3f.h> -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> namespace hpp { namespace fcl { class CollisionRequest; +/// @defgroup Bounding_Volume +/// regroup class of differents types of bounding volume. +/// @{ + /// @brief A class describing the AABB collision structure, which is a box in 3D space determined by two diagonal points class AABB { @@ -82,6 +85,20 @@ public: { } + /// @name Bounding volume API + /// Common API to BVs. + /// @{ + + /// @brief Check whether the AABB contains a point + inline bool contain(const Vec3f& p) const + { + if(p[0] < min_[0] || p[0] > max_[0]) return false; + if(p[1] < min_[1] || p[1] > max_[1]) return false; + if(p[2] < min_[2] || p[2] > max_[2]) return false; + + return true; + } + /// @brief Check whether two AABB are overlap inline bool overlap(const AABB& other) const { @@ -97,53 +114,14 @@ public: } /// Not implemented - inline bool overlap(const AABB& other, const CollisionRequest&, - FCL_REAL& sqrDistLowerBound) const - { - sqrDistLowerBound = sqrt (-1); - return overlap (other); - } + bool overlap(const AABB& other, const CollisionRequest& request, + FCL_REAL& sqrDistLowerBound) const; - /// @brief Check whether the AABB contains another AABB - inline bool contain(const AABB& other) const - { - return (other.min_[0] >= min_[0]) && (other.max_[0] <= max_[0]) && (other.min_[1] >= min_[1]) && (other.max_[1] <= max_[1]) && (other.min_[2] >= min_[2]) && (other.max_[2] <= max_[2]); - } - - - /// @brief Check whether two AABB are overlapped along specific axis - inline bool axisOverlap(const AABB& other, int axis_id) const - { - if(min_[axis_id] > other.max_[axis_id]) return false; - - if(max_[axis_id] < other.min_[axis_id]) return false; - - return true; - } - - /// @brief Check whether two AABB are overlap and return the overlap part - inline bool overlap(const AABB& other, AABB& overlap_part) const - { - if(!overlap(other)) - { - return false; - } - - overlap_part.min_ = min_.cwiseMax(other.min_); - overlap_part.max_ = max_.cwiseMin(other.max_); - return true; - } - - - /// @brief Check whether the AABB contains a point - inline bool contain(const Vec3f& p) const - { - if(p[0] < min_[0] || p[0] > max_[0]) return false; - if(p[1] < min_[1] || p[1] > max_[1]) return false; - if(p[2] < min_[2] || p[2] > max_[2]) return false; + /// @brief Distance between two AABBs + FCL_REAL distance(const AABB& other) const; - return true; - } + /// @brief Distance between two AABBs; P and Q, should not be NULL, return the nearest points + FCL_REAL distance(const AABB& other, Vec3f* P, Vec3f* Q) const; /// @brief Merge the AABB and a point inline AABB& operator += (const Vec3f& p) @@ -168,6 +146,18 @@ public: return res += other; } + /// @brief Size of the AABB (used in BV_Splitter to order two AABBs) + inline FCL_REAL size() const + { + return (max_ - min_).squaredNorm(); + } + + /// @brief Center of the AABB + inline Vec3f center() const + { + return (min_ + max_) * 0.5; + } + /// @brief Width of the AABB inline FCL_REAL width() const { @@ -186,40 +176,31 @@ public: return max_[2] - min_[2]; } - /// @brief Volume of the AABB + /// @brief Volume of the AABB inline FCL_REAL volume() const { return width() * height() * depth(); - } - - /// @brief Size of the AABB (used in BV_Splitter to order two AABBs) - inline FCL_REAL size() const - { - return (max_ - min_).squaredNorm(); } - /// @brief Radius of the AABB - inline FCL_REAL radius() const - { - return (max_ - min_).norm() / 2; - } + /// @} - /// @brief Center of the AABB - inline Vec3f center() const + /// @brief Check whether the AABB contains another AABB + inline bool contain(const AABB& other) const { - return (min_ + max_) * 0.5; + return (other.min_[0] >= min_[0]) && (other.max_[0] <= max_[0]) && (other.min_[1] >= min_[1]) && (other.max_[1] <= max_[1]) && (other.min_[2] >= min_[2]) && (other.max_[2] <= max_[2]); } - /// @brief Distance between two AABBs; P and Q, should not be NULL, return the nearest points - FCL_REAL distance(const AABB& other, Vec3f* P, Vec3f* Q) const; - - /// @brief Distance between two AABBs - FCL_REAL distance(const AABB& other) const; - - /// @brief whether two AABB are equal - inline bool equal(const AABB& other) const + /// @brief Check whether two AABB are overlap and return the overlap part + inline bool overlap(const AABB& other, AABB& overlap_part) const { - return isEqual(min_, other.min_) && isEqual(max_, other.max_); + if(!overlap(other)) + { + return false; + } + + overlap_part.min_ = min_.cwiseMax(other.min_); + overlap_part.max_ = max_.cwiseMin(other.max_); + return true; } /// @brief expand the half size of the AABB by delta, and keep the center unchanged. @@ -269,7 +250,6 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const AABB& b1, const AABB& b2 bool overlap(const Matrix3f& R0, const Vec3f& T0, const AABB& b1, const AABB& b2, const CollisionRequest& request, FCL_REAL& sqrDistLowerBound); - } } // namespace hpp diff --git a/include/hpp/fcl/BV/BV.h b/include/hpp/fcl/BV/BV.h index d88aa1fc7396825555968e0c3c854045a2d14bd0..238ec16bfc416c9235741900d1f28c9577b931d2 100644 --- a/include/hpp/fcl/BV/BV.h +++ b/include/hpp/fcl/BV/BV.h @@ -47,7 +47,7 @@ #include <hpp/fcl/BV/kIOS.h> #include <hpp/fcl/math/transform.h> -/** \brief Main namespace */ +/** @brief Main namespace */ namespace hpp { namespace fcl @@ -90,43 +90,7 @@ class Converter<AABB, OBB> { public: static void convert(const AABB& bv1, const Transform3f& tf1, OBB& bv2) - { - /* - bv2.To = tf1.transform(bv1.center()); - - /// Sort the AABB edges so that AABB extents are ordered. - FCL_REAL d[3] = {bv1.width(), bv1.height(), bv1.depth() }; - std::size_t id[3] = {0, 1, 2}; - - for(std::size_t i = 1; i < 3; ++i) - { - for(std::size_t j = i; j > 0; --j) - { - if(d[j] > d[j-1]) - { - { - FCL_REAL tmp = d[j]; - d[j] = d[j-1]; - d[j-1] = tmp; - } - { - std::size_t tmp = id[j]; - id[j] = id[j-1]; - id[j-1] = tmp; - } - } - } - } - - Vec3f extent = (bv1.max_ - bv1.min_) * 0.5; - bv2.extent = Vec3f(extent[id[0]], extent[id[1]], extent[id[2]]); - const Matrix3f& R = tf1.getRotation(); - bool left_hand = (id[0] == (id[1] + 1) % 3); - bv2.axis[0] = left_hand ? -R.col(id[0]) : R.col(id[0]); - bv2.axis[1] = R.col(id[1]); - bv2.axis[2] = R.col(id[2]); - */ - + { bv2.To.noalias() = tf1.transform(bv1.center()); bv2.extent.noalias() = (bv1.max_ - bv1.min_) * 0.5; bv2.axes.noalias() = tf1.getRotation(); @@ -161,7 +125,7 @@ class Converter<RSS, OBB> public: static void convert(const RSS& bv1, const Transform3f& tf1, OBB& bv2) { - bv2.extent.noalias() = Vec3f(bv1.l[0] * 0.5 + bv1.r, bv1.l[1] * 0.5 + bv1.r, bv1.r); + bv2.extent.noalias() = Vec3f(bv1.length[0] * 0.5 + bv1.radius, bv1.length[1] * 0.5 + bv1.radius, bv1.radius); bv2.To.noalias() = tf1.transform(bv1.Tr); bv2.axes.noalias() = tf1.getRotation() * bv1.axes; } @@ -204,9 +168,9 @@ public: bv2.Tr = tf1.transform(bv1.To); bv2.axes.noalias() = tf1.getRotation() * bv1.axes; - bv2.r = bv1.extent[2]; - bv2.l[0] = 2 * (bv1.extent[0] - bv2.r); - bv2.l[1] = 2 * (bv1.extent[1] - bv2.r); + bv2.radius = bv1.extent[2]; + bv2.length[0] = 2 * (bv1.extent[0] - bv2.radius); + bv2.length[1] = 2 * (bv1.extent[1] - bv2.radius); } }; @@ -219,9 +183,9 @@ public: bv2.Tr.noalias() = tf1.transform(bv1.Tr); bv2.axes.noalias() = tf1.getRotation() * bv1.axes; - bv2.r = bv1.r; - bv2.l[0] = bv1.l[0]; - bv2.l[1] = bv1.l[1]; + bv2.radius = bv1.radius; + bv2.length[0] = bv1.length[0]; + bv2.length[1] = bv1.length[1]; } }; @@ -268,9 +232,9 @@ public: } Vec3f extent = (bv1.max_ - bv1.min_) * 0.5; - bv2.r = extent[id[2]]; - bv2.l[0] = (extent[id[0]] - bv2.r) * 2; - bv2.l[1] = (extent[id[1]] - bv2.r) * 2; + bv2.radius = extent[id[2]]; + bv2.length[0] = (extent[id[0]] - bv2.radius) * 2; + bv2.length[1] = (extent[id[1]] - bv2.radius) * 2; const Matrix3f& R = tf1.getRotation(); bool left_hand = (id[0] == (id[1] + 1) % 3); diff --git a/include/hpp/fcl/BV/BV_node.h b/include/hpp/fcl/BV/BV_node.h index 5889b740367f4b97b7424e71af45642c92c3c458..86e858f2f40b5da2857b229ceb9e8b6d13f32985 100644 --- a/include/hpp/fcl/BV/BV_node.h +++ b/include/hpp/fcl/BV/BV_node.h @@ -39,8 +39,7 @@ #ifndef HPP_FCL_BV_NODE_H #define HPP_FCL_BV_NODE_H -#include <hpp/fcl/math/vec_3f.h> -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> #include <hpp/fcl/BV/BV.h> #include <iostream> @@ -50,6 +49,10 @@ namespace hpp namespace fcl { +/// @defgroup Construction_Of_BVH +/// regroup class which are used to build BVH (Bounding Volume Hierarchy) +/// @{ + /// @brief BVNodeBase encodes the tree structure for BVH struct BVNodeBase { diff --git a/include/hpp/fcl/BV/OBB.h b/include/hpp/fcl/BV/OBB.h index f3897cf37808f0d7ee54ee583ceba5159c070264..32468de639bbef10eea0ac63c1b873e4b5d583ae 100644 --- a/include/hpp/fcl/BV/OBB.h +++ b/include/hpp/fcl/BV/OBB.h @@ -38,9 +38,7 @@ #ifndef HPP_FCL_OBB_H #define HPP_FCL_OBB_H - -#include <hpp/fcl/math/vec_3f.h> -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> namespace hpp { @@ -48,6 +46,9 @@ namespace fcl { class CollisionRequest; +/// @addtogroup Bounding_Volume +/// @{ + /// @brief Oriented bounding box class class OBB { @@ -62,26 +63,22 @@ public: /// @brief Half dimensions of OBB Vec3f extent; + /// @brief Check whether the OBB contains a point. + bool contain(const Vec3f& p) const; + /// Check collision between two OBB - /// \return true if collision happens. + /// @return true if collision happens. bool overlap(const OBB& other) const; /// Check collision between two OBB - /// \return true if collision happens. - /// \retval sqrDistLowerBound squared lower bound on distance between boxes if + /// @return true if collision happens. + /// @retval sqrDistLowerBound squared lower bound on distance between boxes if /// they do not overlap. bool overlap(const OBB& other, const CollisionRequest& request, FCL_REAL& sqrDistLowerBound) const; - - /// @brief Check collision between two OBB and return the overlap part. For OBB, the overlap_part return value is NOT used as the overlap part of two obbs usually is not an obb. - bool overlap(const OBB& other, OBB& /*overlap_part*/) const - { - return overlap(other); - } - - /// @brief Check whether the OBB contains a point. - bool contain(const Vec3f& p) const; + /// @brief Distance between two OBBs, not implemented. + FCL_REAL distance(const OBB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; /// @brief A simple way to merge the OBB and a point (the result is not compact). OBB& operator += (const Vec3f& p); @@ -96,6 +93,18 @@ public: /// @brief Return the merged OBB of current OBB and the other one (the result is not compact). OBB operator + (const OBB& other) const; + /// @brief Size of the OBB (used in BV_Splitter to order two OBBs) + inline FCL_REAL size() const + { + return extent.squaredNorm(); + } + + /// @brief Center of the OBB + inline const Vec3f& center() const + { + return To; + } + /// @brief Width of the OBB. inline FCL_REAL width() const { @@ -119,22 +128,6 @@ public: { return width() * height() * depth(); } - - /// @brief Size of the OBB (used in BV_Splitter to order two OBBs) - inline FCL_REAL size() const - { - return extent.squaredNorm(); - } - - /// @brief Center of the OBB - inline const Vec3f& center() const - { - return To; - } - - - /// @brief Distance between two OBBs, not implemented. - FCL_REAL distance(const OBB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; }; @@ -151,9 +144,9 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBB& b1, /// Check collision between two boxes -/// \param B, T orientation and position of first box, -/// \param a half dimensions of first box, -/// \param b half dimensions of second box. +/// @param B, T orientation and position of first box, +/// @param a half dimensions of first box, +/// @param b half dimensions of second box. /// The second box is in identity configuration. bool obbDisjoint(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b); } diff --git a/include/hpp/fcl/BV/OBBRSS.h b/include/hpp/fcl/BV/OBBRSS.h index bc8d715c95ccc5d552b8f42a04cac105902e1c20..def7ce67ddd35cc54d5bd654acdeb8c138b5622f 100644 --- a/include/hpp/fcl/BV/OBBRSS.h +++ b/include/hpp/fcl/BV/OBBRSS.h @@ -48,6 +48,9 @@ namespace fcl { class CollisionRequest; +/// @addtogroup Bounding_Volume +/// @{ + /// @brief Class merging the OBB and RSS, can handle collision and distance simultaneously class OBBRSS { @@ -59,6 +62,12 @@ public: /// @brief RSS member, for distance RSS rss; +/// @brief Check whether the OBBRSS contains a point + inline bool contain(const Vec3f& p) const + { + return obb.contain(p); + } + /// @brief Check collision between two OBBRSS bool overlap(const OBBRSS& other) const { @@ -66,7 +75,7 @@ public: } /// Check collision between two OBBRSS - /// \retval sqrDistLowerBound squared lower bound on distance between + /// @retval sqrDistLowerBound squared lower bound on distance between /// objects if they do not overlap. bool overlap(const OBBRSS& other, const CollisionRequest& request, FCL_REAL& sqrDistLowerBound) const @@ -74,16 +83,10 @@ public: return obb.overlap(other.obb, request, sqrDistLowerBound); } - /// @brief Check collision between two OBBRSS and return the overlap part. - bool overlap(const OBBRSS& other, OBBRSS& /*overlap_part*/) const - { - return overlap(other); - } - - /// @brief Check whether the OBBRSS contains a point - inline bool contain(const Vec3f& p) const + /// @brief Distance between two OBBRSS; P and Q , is not NULL, returns the nearest points + FCL_REAL distance(const OBBRSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const { - return obb.contain(p); + return rss.distance(other.rss, P, Q); } /// @brief Merge the OBBRSS and a point @@ -110,6 +113,18 @@ public: return result; } + /// @brief Size of the OBBRSS (used in BV_Splitter to order two OBBRSS) + inline FCL_REAL size() const + { + return obb.size(); + } + + /// @brief Center of the OBBRSS + inline const Vec3f& center() const + { + return obb.center(); + } + /// @brief Width of the OBRSS inline FCL_REAL width() const { @@ -133,42 +148,30 @@ public: { return obb.volume(); } - - /// @brief Size of the OBBRSS (used in BV_Splitter to order two OBBRSS) - inline FCL_REAL size() const - { - return obb.size(); - } - - /// @brief Center of the OBBRSS - inline const Vec3f& center() const - { - return obb.center(); - } - - /// @brief Distance between two OBBRSS; P and Q , is not NULL, returns the nearest points - FCL_REAL distance(const OBBRSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const - { - return rss.distance(other.rss, P, Q); - } }; -/// @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); +inline bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2) +{ + return overlap(R0, T0, b1.obb, b2.obb); +} /// Check collision between two OBBRSS -/// \param b1 first OBBRSS in configuration (R0, T0) -/// \param b2 second OBBRSS in identity position -/// \retval squared lower bound on the distance if OBBRSS do not overlap. -bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, - const OBBRSS& b2, const CollisionRequest& request, - FCL_REAL& sqrDistLowerBound); +/// @param b1 first OBBRSS in configuration (R0, T0) +/// @param b2 second OBBRSS in identity position +/// @retval squared lower bound on the distance if OBBRSS do not overlap. +inline bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, + const OBBRSS& b2, const CollisionRequest& request, + FCL_REAL& sqrDistLowerBound) +{ + return overlap(R0, T0, b1.obb, b2.obb, request, sqrDistLowerBound); +} /// @brief Computate distance between two OBBRSS, b1 is in configuation (R0, T0) and b2 is in indentity; P and Q, is not NULL, returns the nearest points -FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2, Vec3f* P = NULL, Vec3f* Q = NULL); +inline FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2, Vec3f* P = NULL, Vec3f* Q = NULL) +{ + return distance(R0, T0, b1.rss, b2.rss, P, Q); +} } diff --git a/include/hpp/fcl/BV/RSS.h b/include/hpp/fcl/BV/RSS.h index 6822e97e42abb8ab1186e1e78a0fd3ed74bba667..a380de68c2b033bda110b5bee23d1dfa679058bb 100644 --- a/include/hpp/fcl/BV/RSS.h +++ b/include/hpp/fcl/BV/RSS.h @@ -39,8 +39,7 @@ #define HPP_FCL_RSS_H #include <stdexcept> -#include <hpp/fcl/math/vec_3f.h> -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> #include <boost/math/constants/constants.hpp> namespace hpp @@ -49,6 +48,9 @@ namespace fcl { class CollisionRequest; +/// @addtogroup Bounding_Volume +/// @{ + /// @brief A class for rectangle sphere-swept bounding volume class RSS { @@ -61,10 +63,14 @@ public: Vec3f Tr; /// @brief Side lengths of rectangle - FCL_REAL l[2]; + FCL_REAL length[2]; /// @brief Radius of sphere summed with rectangle to form RSS - FCL_REAL r; + FCL_REAL radius; + + + /// @brief Check whether the RSS contains a point + inline bool contain(const Vec3f& p) const; /// @brief Check collision between two RSS bool overlap(const RSS& other) const; @@ -77,15 +83,8 @@ public: return overlap (other); } - /// @brief Check collision between two RSS and return the overlap part. - /// For RSS, we return nothing, as the overlap part of two RSSs usually is not a RSS. - bool overlap(const RSS& other, RSS& /*overlap_part*/) const - { - return overlap(other); - } - - /// @brief Check whether the RSS contains a point - inline bool contain(const Vec3f& p) const; + /// @brief the distance between two RSS; P and Q, if not NULL, return the nearest points + FCL_REAL distance(const RSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; /// @brief A simple way to merge the RSS and a point, not compact. /// @todo This function may have some bug. @@ -101,51 +100,51 @@ public: /// @brief Return the merged RSS of current RSS and the other one RSS operator + (const RSS& other) const; + + /// @brief Size of the RSS (used in BV_Splitter to order two RSSs) + inline FCL_REAL size() const + { + return (std::sqrt(length[0] * length[0] + length[1] * length[1]) + 2 * radius); + } + + /// @brief The RSS center + inline const Vec3f& center() const + { + return Tr; + } + /// @brief Width of the RSS inline FCL_REAL width() const { - return l[0] + 2 * r; + return length[0] + 2 * radius; } /// @brief Height of the RSS inline FCL_REAL height() const { - return l[1] + 2 * r; + return length[1] + 2 * radius; } /// @brief Depth of the RSS inline FCL_REAL depth() const { - return 2 * r; + return 2 * radius; } /// @brief Volume of the RSS inline FCL_REAL volume() const { - return (l[0] * l[1] * 2 * r + 4 * boost::math::constants::pi<FCL_REAL>() * r * r * r); - } - - /// @brief Size of the RSS (used in BV_Splitter to order two RSSs) - inline FCL_REAL size() const - { - return (std::sqrt(l[0] * l[0] + l[1] * l[1]) + 2 * r); + return (length[0] * length[1] * 2 * radius + 4 * boost::math::constants::pi<FCL_REAL>() * radius * radius * radius); } - /// @brief The RSS center - inline const Vec3f& center() const + /// @brief Check collision between two RSS and return the overlap part. + /// For RSS, we return nothing, as the overlap part of two RSSs usually is not a RSS. + bool overlap(const RSS& other, RSS& /*overlap_part*/) const { - return Tr; + return overlap(other); } - - /// @brief the distance between two RSS; P and Q, if not NULL, return the nearest points - FCL_REAL distance(const RSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; - }; - -/// @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) @@ -165,4 +164,4 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2, } // namespace hpp -#endif +#endif \ No newline at end of file diff --git a/include/hpp/fcl/BV/kDOP.h b/include/hpp/fcl/BV/kDOP.h index da5901624e1f4f8f8e5d380b024daaf36d7c8f26..6a5c6aabe88b7a3a8cb6398ef2365b8d41d0119f 100644 --- a/include/hpp/fcl/BV/kDOP.h +++ b/include/hpp/fcl/BV/kDOP.h @@ -39,7 +39,7 @@ #define HPP_FCL_KDOP_H #include <stdexcept> -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> namespace hpp { @@ -48,6 +48,9 @@ namespace fcl class CollisionRequest; + /// @addtogroup Bounding_Volume + /// @{ + /// @brief KDOP class describes the KDOP collision structures. K is set as the template parameter, which should be 16, 18, or 24 /// The KDOP structure is defined by some pairs of parallel planes defined by some axes. /// For K = 16, the planes are 6 AABB planes and 10 diagonal planes that cut off some space of the edges: @@ -85,6 +88,10 @@ namespace fcl template<size_t N> class KDOP { +private: + /// @brief Origin's distances to N KDOP planes + FCL_REAL dist_[N]; + public: /// @brief Creating kDOP containing nothing @@ -107,8 +114,8 @@ public: return overlap (other); } - //// @brief Check whether one point is inside the KDOP - bool inside(const Vec3f& p) const; + /// @brief The distance between two KDOP<N>. Not implemented. + FCL_REAL distance(const KDOP<N>& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; /// @brief Merge the point and the KDOP KDOP<N>& operator += (const Vec3f& p); @@ -119,6 +126,19 @@ public: /// @brief Create a KDOP by mergin two KDOPs KDOP<N> operator + (const KDOP<N>& other) const; + /// @brief Size of the kDOP (used in BV_Splitter to order two kDOPs) + inline FCL_REAL size() const + { + return width() * width() + height() * height() + depth() * depth(); + } + + /// @brief The (AABB) center + inline Vec3f center() const + { + return Vec3f(dist_[0] + dist_[N / 2], dist_[1] + dist_[N / 2 + 1], dist_[2] + dist_[N / 2 + 2]) * 0.5; + } + + /// @brief The (AABB) width inline FCL_REAL width() const { @@ -143,26 +163,6 @@ public: return width() * height() * depth(); } - /// @brief Size of the kDOP (used in BV_Splitter to order two kDOPs) - inline FCL_REAL size() const - { - return width() * width() + height() * height() + depth() * depth(); - } - - /// @brief The (AABB) center - inline Vec3f center() const - { - return Vec3f(dist_[0] + dist_[N / 2], dist_[1] + dist_[N / 2 + 1], dist_[2] + dist_[N / 2 + 2]) * 0.5; - } - - /// @brief The distance between two KDOP<N>. Not implemented. - FCL_REAL distance(const KDOP<N>& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; - -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]; @@ -173,6 +173,8 @@ public: return dist_[i]; } + //// @brief Check whether one point is inside the KDOP + bool inside(const Vec3f& p) const; }; diff --git a/include/hpp/fcl/BV/kIOS.h b/include/hpp/fcl/BV/kIOS.h index a7228168d3d3ffcbf45defdeb6acf6d850037fb7..be1a4f0bb0d050646ed287c66245f940d43f3d3a 100644 --- a/include/hpp/fcl/BV/kIOS.h +++ b/include/hpp/fcl/BV/kIOS.h @@ -46,7 +46,10 @@ namespace hpp namespace fcl { class CollisionRequest; - + +/// @addtogroup Bounding_Volume +/// @{ + /// @brief A class describing the kIOS collision structure, which is a set of spheres. class kIOS { @@ -93,6 +96,9 @@ public: /// @ OBB related with kIOS OBB obb; + /// @brief Check whether the kIOS contains a point + inline bool contain(const Vec3f& p) const; + /// @brief Check collision between two kIOS bool overlap(const kIOS& other) const; @@ -100,16 +106,8 @@ public: bool overlap(const kIOS& other, const CollisionRequest&, FCL_REAL& sqrDistLowerBound) const; - /// @brief Check collision between two kIOS and return the overlap part. - /// For kIOS, we return nothing, as the overlappart of two kIOS usually is not an kIOS - /// @todo Not efficient. It first checks the sphere collisions and then use OBB for further culling. - bool overlap(const kIOS& other, kIOS& /*overlap_part*/) const - { - return overlap(other); - } - - /// @brief Check whether the kIOS contains a point - inline bool contain(const Vec3f& p) const; + /// @brief The distance between two kIOS + FCL_REAL distance(const kIOS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; /// @brief A simple way to merge the kIOS and a point kIOS& operator += (const Vec3f& p); @@ -124,6 +122,9 @@ public: /// @brief Return the merged kIOS of current kIOS and the other one kIOS operator + (const kIOS& other) const; + /// @brief size of the kIOS (used in BV_Splitter to order two kIOSs) + FCL_REAL size() const; + /// @brief Center of the kIOS const Vec3f& center() const { @@ -141,12 +142,6 @@ public: /// @brief Volume of the kIOS FCL_REAL volume() const; - - /// @brief size of the kIOS (used in BV_Splitter to order two kIOSs) - FCL_REAL size() const; - - /// @brief The distance between two kIOS - FCL_REAL distance(const kIOS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const; }; diff --git a/include/hpp/fcl/BVH/BVH_model.h b/include/hpp/fcl/BVH/BVH_model.h index 1f29a9bbbb8b18f3f5b34b3b605ad2c51758e386..095ff21c250877fb5b5c42a94aa0b6a89d7b3756 100644 --- a/include/hpp/fcl/BVH/BVH_model.h +++ b/include/hpp/fcl/BVH/BVH_model.h @@ -41,8 +41,6 @@ #include <hpp/fcl/collision_object.h> #include <hpp/fcl/BVH/BVH_internal.h> #include <hpp/fcl/BV/BV_node.h> -#include <hpp/fcl/BVH/BV_splitter.h> -#include <hpp/fcl/BVH/BV_fitter.h> #include <vector> #include <boost/shared_ptr.hpp> #include <boost/noncopyable.hpp> @@ -52,13 +50,39 @@ namespace hpp namespace fcl { -/// @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 boost::noncopyable -{ +/// @addtogroup Construction_Of_BVH +/// @{ + +class ConvexBase; + +template <typename BV> class BVFitter; +template <typename BV> class BVSplitter; +/// @brief A base class describing the bounding hierarchy of a mesh model or a point cloud model (which is viewed as a degraded version of mesh) +class BVHModelBase : public CollisionGeometry +{ 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 Convex<Triangle> representation of this object + boost::shared_ptr< ConvexBase > convex; + /// @brief Model type described by the instance BVHModelType getModelType() const { @@ -71,64 +95,32 @@ public: } /// @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) + BVHModelBase() : vertices(NULL), + tri_indices(NULL), + prev_vertices(NULL), + num_tris(0), + num_vertices(0), + build_state(BVH_BUILD_STATE_EMPTY), + num_tris_allocated(0), + num_vertices_allocated(0), + num_vertex_updated(0) { } /// @brief copy from another BVH - BVHModel(const BVHModel& other); + BVHModelBase(const BVHModelBase& other); /// @brief deconstruction, delete mesh data related. - ~BVHModel() + virtual ~BVHModelBase () { delete [] vertices; delete [] tri_indices; - 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 Access the bv giving the its index - const BVNode<BV>& getBV(int id) const - { - return bvs[id]; - } - - /// @brief Access the bv giving the its index - BVNode<BV>& getBV(int id) - { - return bvs[id]; - } - - /// @brief Get the number of bv in the BVH - int getNumBVs() const - { - return num_bvs; } /// @brief Get the object type: it is a BVH OBJECT_TYPE getObjectType() const { return OT_BVH; } - /// @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 void computeLocalAABB(); @@ -150,7 +142,6 @@ public: /// @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) int beginReplaceModel(); @@ -166,7 +157,6 @@ public: /// @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. int beginUpdateModel(); @@ -183,16 +173,16 @@ public: /// @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 - int memUsage(int msg) const; + /// @brief Build this Convex<Triangle> representation of this model. + /// \note this only takes the points of this model. It does not check that the + /// object is convex. It does not compute a convex hull. + void buildConvexRepresentation(bool share_memory); + + virtual int memUsage(int msg) const = 0; /// @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() - { - Matrix3f I (Matrix3f::Identity()); - makeParentRelativeRecurse(0, I, Vec3f()); - } + virtual void makeParentRelative() = 0; Vec3f computeCOM() const { @@ -244,41 +234,89 @@ public: return C.trace() * Matrix3f::Identity() - C; } -public: - /// @brief Geometry point data - Vec3f* vertices; - - /// @brief Geometry triangle index data, will be NULL for point clouds - Triangle* tri_indices; +protected: + virtual void deleteBVs() = 0; + virtual bool allocateBVs() = 0; - /// @brief Geometry point data in previous frame - Vec3f* prev_vertices; + /// @brief Build the bounding volume hierarchy + virtual int buildTree() = 0; - /// @brief Number of triangles - int num_tris; + /// @brief Refit the bounding volume hierarchy + virtual int refitTree(bool bottomup) = 0; - /// @brief Number of points - int num_vertices; + int num_tris_allocated; + int num_vertices_allocated; + int num_vertex_updated; /// for ccd vertex update +}; - /// @brief The state of BVH building process - BVHBuildState build_state; +/// @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 BVHModelBase +{ +public: /// @brief Split rule to split one BV node into two children - boost::shared_ptr<BVSplitterBase<BV> > bv_splitter; + boost::shared_ptr<BVSplitter<BV> > bv_splitter; /// @brief Fitting rule to fit a BV node to a set of geometry primitives - boost::shared_ptr<BVFitterBase<BV> > bv_fitter; + boost::shared_ptr<BVFitter<BV> > bv_fitter; + + /// @brief Constructing an empty BVH + BVHModel(); + + /// @brief copy from another BVH + BVHModel(const BVHModel& other); + + /// @brief deconstruction, delete mesh data related. + ~BVHModel() + { + delete [] bvs; + delete [] primitive_indices; + } + + /// @brief We provide getBV() and getNumBVs() because BVH may be compressed (in future), so we must provide some flexibility here + + /// @brief Access the bv giving the its index + const BVNode<BV>& getBV(int id) const + { + assert (id < num_bvs); + return bvs[id]; + } + + /// @brief Access the bv giving the its index + BVNode<BV>& getBV(int id) + { + assert (id < num_bvs); + return bvs[id]; + } + + /// @brief Get the number of bv in the BVH + int getNumBVs() const + { + return num_bvs; + } + /// @brief Get the BV type: default is unknown + NODE_TYPE getNodeType() const { return BV_UNKNOWN; } + + /// @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() + { + Matrix3f I (Matrix3f::Identity()); + makeParentRelativeRecurse(0, I, Vec3f()); + } private: + void deleteBVs(); + bool allocateBVs(); - 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; @@ -303,7 +341,7 @@ private: /// @brief Recursive kernel for bottomup refitting int recursiveRefitTree_bottomup(int bv_id); - /// @recursively compute each bv's transform related to its parent. For default BV, only the translation works. + /// @ 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, Matrix3f& parent_axes, const Vec3f& parent_c) { @@ -318,6 +356,7 @@ private: } }; +/// @} template<> void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes, const Vec3f& parent_c); diff --git a/include/hpp/fcl/BVH/BVH_utility.h b/include/hpp/fcl/BVH/BVH_utility.h index 85110c265b2d383fa9b72590e69b6f121c6dd393..e87cf918fe29abd65dcf2f25c3b11d5de3670de8 100644 --- a/include/hpp/fcl/BVH/BVH_utility.h +++ b/include/hpp/fcl/BVH/BVH_utility.h @@ -46,39 +46,6 @@ namespace hpp { namespace fcl { -/// @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) -{ - for(int i = 0; i < model.num_bvs; ++i) - { - BVNode<BV>& bvnode = model.getBV(i); - - BV bv; - for(int j = 0; j < bvnode.num_primitives; ++j) - { - int v_id = bvnode.first_primitive + j; - const Variance3f& uc = ucs[v_id]; - - Vec3f& v = model.vertices[bvnode.first_primitive + j]; - - for(int k = 0; k < 3; ++k) - { - bv += (v + uc.axis[k] * (r * uc.sigma[k])); - bv += (v - uc.axis[k] * (r * uc.sigma[k])); - } - } - - bvnode.bv = bv; - } -} - -/// @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 the corresponding variance information, for RSS -void BVHExpand(BVHModel<RSS>& model, const Variance3f* ucs, FCL_REAL r); - /// @brief Extract the part of the BVHModel that is inside an AABB. /// A triangle in collision with the AABB is considered inside. template<typename BV> @@ -99,7 +66,6 @@ void circumCircleComputation(const Vec3f& a, const Vec3f& b, const Vec3f& c, Vec /// @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); - } } // namespace hpp diff --git a/include/hpp/fcl/collision.h b/include/hpp/fcl/collision.h index f673494defbe47ff01b4217928990d7cbf84bd8f..c17759919ae445a4e69df4b7b75c12ce6c83a8a4 100644 --- a/include/hpp/fcl/collision.h +++ b/include/hpp/fcl/collision.h @@ -39,7 +39,7 @@ #ifndef HPP_FCL_COLLISION_H #define HPP_FCL_COLLISION_H -#include <hpp/fcl/math/vec_3f.h> +#include <hpp/fcl/data_types.h> #include <hpp/fcl/collision_object.h> #include <hpp/fcl/collision_data.h> @@ -52,15 +52,13 @@ namespace fcl /// 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. - std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, - const CollisionRequest& request, - CollisionResult& result); + const CollisionRequest& request, CollisionResult& result); +/// @copydoc collide(const CollisionObject*, const CollisionObject*, const CollisionRequest&, CollisionResult&) std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const CollisionRequest& request, - CollisionResult& result); + const CollisionRequest& request, CollisionResult& result); } } // namespace hpp diff --git a/include/hpp/fcl/collision_data.h b/include/hpp/fcl/collision_data.h index 88ed5d23949ef53f4c8a54375fa72c6f069d589d..fdc9993acfe47bfe90f40230b8f9cb1730c8b0ec 100644 --- a/include/hpp/fcl/collision_data.h +++ b/include/hpp/fcl/collision_data.h @@ -41,7 +41,7 @@ #include <hpp/fcl/collision_object.h> -#include <hpp/fcl/math/vec_3f.h> +#include <hpp/fcl/data_types.h> #include <vector> #include <set> #include <limits> @@ -215,7 +215,7 @@ public: Vec3f cached_gjk_guess; /// Lower bound on distance between objects if they are disjoint - /// \note computed only on request. + /// @note computed only on request. FCL_REAL distance_lower_bound; public: @@ -259,7 +259,7 @@ public: } /// @brief get all the contacts - void getContacts(std::vector<Contact>& contacts_) + void getContacts(std::vector<Contact>& contacts_) const { contacts_.resize(contacts.size()); std::copy(contacts.begin(), contacts.end(), contacts_.begin()); diff --git a/include/hpp/fcl/collision_func_matrix.h b/include/hpp/fcl/collision_func_matrix.h index 417039ca642447e3ecf0405861e3cf51c25fd233..892ea4013d870af3a8be510593454934f3931f6f 100644 --- a/include/hpp/fcl/collision_func_matrix.h +++ b/include/hpp/fcl/collision_func_matrix.h @@ -42,6 +42,7 @@ #include <hpp/fcl/collision_object.h> #include <hpp/fcl/collision_data.h> +#include <hpp/fcl/narrowphase/narrowphase.h> namespace hpp { @@ -49,7 +50,7 @@ namespace fcl { /// @brief collision matrix stores the functions for collision between different types of objects and provides a uniform call interface -template<typename NarrowPhaseSolver> + struct CollisionFunctionMatrix { /// @brief the uniform call interface for collision: for collision, we need know @@ -57,7 +58,7 @@ struct CollisionFunctionMatrix /// 2. the solver for narrow phase collision, this is for the collision between geometric shapes; /// 3. the request setting for collision (e.g., whether need to return normal information, whether need to compute cost); /// 4. the structure to return collision result - typedef std::size_t (*CollisionFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, const CollisionRequest& request, CollisionResult& result); + typedef std::size_t (*CollisionFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result); /// @brief each item in the collision matrix is a function to handle collision between objects of type1 and type2 CollisionFunc collision_matrix[NODE_COUNT][NODE_COUNT]; diff --git a/include/hpp/fcl/collision_object.h b/include/hpp/fcl/collision_object.h index 6dd142e8102435455897aa633336dd316ffbc7bc..1e743dbd08709af80e789ca23e63901c97c0bf45 100644 --- a/include/hpp/fcl/collision_object.h +++ b/include/hpp/fcl/collision_object.h @@ -56,6 +56,9 @@ enum OBJECT_TYPE {OT_UNKNOWN, OT_BVH, OT_GEOM, OT_OCTREE, OT_COUNT}; 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_HALFSPACE, GEOM_TRIANGLE, GEOM_OCTREE, NODE_COUNT}; +/// @addtogroup Construction_Of_BVH +/// @{ + /// @brief The geometry for the object for collision or distance computation class CollisionGeometry { @@ -203,7 +206,7 @@ public: /// @brief compute the AABB in world space inline void computeAABB() { - if(isQuatIdentity(t.getQuatRotation())) + if(t.getRotation().isIdentity()) { aabb = translate(cgeom->aabb_local, t.getTranslation()); } @@ -240,12 +243,6 @@ public: 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 { @@ -264,11 +261,7 @@ public: 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) @@ -276,11 +269,7 @@ public: 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) diff --git a/include/hpp/fcl/data_types.h b/include/hpp/fcl/data_types.h index fb234d919bacb5ba90718929719462f91be494c3..3d3c3beab99fbb660b46e55b09fa37d4e47f2616 100644 --- a/include/hpp/fcl/data_types.h +++ b/include/hpp/fcl/data_types.h @@ -41,47 +41,75 @@ #include <cstddef> #include <boost/cstdint.hpp> +#include <Eigen/Core> +#include <Eigen/Geometry> + + +namespace hpp +{ + +#ifdef HPP_FCL_HAVE_OCTOMAP + #define OCTOMAP_VERSION_AT_LEAST(x,y,z) \ + (OCTOMAP_MAJOR_VERSION > x || (OCTOMAP_MAJOR_VERSION >= x && \ + (OCTOMAP_MINOR_VERSION > y || (OCTOMAP_MINOR_VERSION >= y && \ + OCTOMAP_PATCH_VERSION >= z)))) + + #define OCTOMAP_VERSION_AT_MOST(x,y,z) \ + (OCTOMAP_MAJOR_VERSION < x || (OCTOMAP_MAJOR_VERSION <= x && \ + (OCTOMAP_MINOR_VERSION < y || (OCTOMAP_MINOR_VERSION <= y && \ + OCTOMAP_PATCH_VERSION <= z)))) +#endif // HPP_FCL_HAVE_OCTOMAP +} + namespace hpp { namespace fcl { - typedef double FCL_REAL; typedef boost::uint64_t FCL_INT64; typedef boost::int64_t FCL_UINT64; typedef boost::uint32_t FCL_UINT32; typedef boost::int32_t FCL_INT32; +typedef Eigen::Matrix<FCL_REAL, 3, 1> Vec3f; +typedef Eigen::Matrix<FCL_REAL, 3, 3> Matrix3f; /// @brief Triangle with 3 indices for points class Triangle { - /// @brief indices for each vertex of triangle - std::size_t vids[3]; - public: + typedef std::size_t index_type; + typedef int size_type; + /// @brief Default constructor Triangle() {} /// @brief Create a triangle with given vertex indices - Triangle(std::size_t p1, std::size_t p2, std::size_t p3) + Triangle(index_type p1, index_type p2, index_type p3) { set(p1, p2, p3); } /// @brief Set the vertex indices of the triangle - inline void set(std::size_t p1, std::size_t p2, std::size_t p3) + inline void set(index_type p1, index_type p2, index_type p3) { vids[0] = p1; vids[1] = p2; vids[2] = p3; } /// @access the triangle index - inline std::size_t operator[](int i) const { return vids[i]; } + inline index_type operator[](int i) const { return vids[i]; } - inline std::size_t& operator[](int i) { return vids[i]; } + inline index_type& operator[](int i) { return vids[i]; } + + static inline size_type size() { return 3; } + +private: + /// @brief indices for each vertex of triangle + index_type vids[3]; }; } } // namespace hpp + #endif diff --git a/include/hpp/fcl/distance.h b/include/hpp/fcl/distance.h index 87216ce6df8a1621f7bf885f94fd243ece3c64e0..45bbcbd736a89d860e759cd1d61b49350584f403 100644 --- a/include/hpp/fcl/distance.h +++ b/include/hpp/fcl/distance.h @@ -33,7 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/** \author Jia Pan */ +/** @author Jia Pan */ #ifndef HPP_FCL_DISTANCE_H #define HPP_FCL_DISTANCE_H @@ -48,14 +48,12 @@ namespace fcl /// @brief Main distance interface: given two collision objects, and the requirements for contacts, including whether return the nearest points, this function performs the distance between them. /// Return value is the minimum distance generated between the two objects. +FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const DistanceRequest& request, DistanceResult& result); -FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, - const DistanceRequest& request, DistanceResult& result); - +/// @copydoc distance(const CollisionObject*, const CollisionObject*, const DistanceRequest&, DistanceResult&) FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const DistanceRequest& request, DistanceResult& result); - } } // namespace hpp diff --git a/include/hpp/fcl/distance_func_matrix.h b/include/hpp/fcl/distance_func_matrix.h index c5a6f44cc622fdfdfd6121641b705d5634a4afb4..1f0ea6d26e573f065a6a97cc6552fff40ba31a20 100644 --- a/include/hpp/fcl/distance_func_matrix.h +++ b/include/hpp/fcl/distance_func_matrix.h @@ -40,6 +40,7 @@ #include <hpp/fcl/collision_object.h> #include <hpp/fcl/collision_data.h> +#include <hpp/fcl/narrowphase/narrowphase.h> namespace hpp { @@ -47,14 +48,13 @@ namespace fcl { /// @brief distance matrix stores the functions for distance between different types of objects and provides a uniform call interface -template<typename NarrowPhaseSolver> struct DistanceFunctionMatrix { /// @brief the uniform call interface for distance: for distance, we need know /// 1. two objects o1 and o2 and their configuration in world coordinate tf1 and tf2; /// 2. the solver for narrow phase collision, this is for distance computation between geometric shapes; /// 3. the request setting for distance (e.g., whether need to return nearest points); - typedef FCL_REAL (*DistanceFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, + typedef FCL_REAL (*DistanceFunc)(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result); /// @brief each item in the distance matrix is a function to handle distance between objects of type1 and type2 diff --git a/include/hpp/fcl/fwd.hh b/include/hpp/fcl/fwd.hh index 45fc60eceb5bc2e808476d4e72b2843cb045db57..e2fa5302856031621f7dac2ffb0022117b846afc 100644 --- a/include/hpp/fcl/fwd.hh +++ b/include/hpp/fcl/fwd.hh @@ -37,6 +37,8 @@ #ifndef HPP_FCL_FWD_HH #define HPP_FCL_FWD_HH +#include <boost/shared_ptr.hpp> + namespace hpp { namespace fcl { class CollisionObject; @@ -49,6 +51,9 @@ namespace fcl { class Transform3f; class AABB; + + class BVHModelBase; + typedef boost::shared_ptr<BVHModelBase> BVHModelPtr_t; } } // namespace hpp diff --git a/include/hpp/fcl/BVH/BV_fitter.h b/include/hpp/fcl/internal/BV_fitter.h similarity index 60% rename from include/hpp/fcl/BVH/BV_fitter.h rename to include/hpp/fcl/internal/BV_fitter.h index 8a1585343e57b2329512c1223073730737dae615..d8070d695129b820c00a979007416b3e8cf5e70e 100644 --- a/include/hpp/fcl/BVH/BV_fitter.h +++ b/include/hpp/fcl/internal/BV_fitter.h @@ -41,6 +41,7 @@ #include <hpp/fcl/BVH/BVH_internal.h> #include <hpp/fcl/BV/kIOS.h> #include <hpp/fcl/BV/OBBRSS.h> +#include <hpp/fcl/BV/AABB.h> #include <iostream> namespace hpp @@ -70,32 +71,16 @@ void fit<kIOS>(Vec3f* ps, int n, kIOS& bv); 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; -}; +template<> +void fit<AABB>(Vec3f* ps, int n, AABB& bv); /// @brief The class for the default algorithm fitting a bounding volume to a set of points template<typename BV> -class BVFitter : public BVFitterBase<BV> +class BVFitterTpl { public: /// @brief default deconstructor - virtual ~BVFitter() {} + virtual ~BVFitterTpl() {} /// @brief Prepare the geometry primitive data for fitting void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) @@ -115,6 +100,31 @@ public: type = type_; } + /// @brief Compute the fitting BV + virtual BV fit(unsigned int* primitive_indices, int num_primitives) = 0; + + /// @brief Clear the geometry primitive data + void clear() + { + vertices = NULL; + prev_vertices = NULL; + tri_indices = NULL; + type = BVH_MODEL_UNKNOWN; + } + +protected: + + Vec3f* vertices; + Vec3f* prev_vertices; + Triangle* tri_indices; + BVHModelType type; +}; + +/// @brief The class for the default algorithm fitting a bounding volume to a set of points +template<typename BV> +class BVFitter : public BVFitterTpl<BV> +{ +public: /// @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) @@ -154,200 +164,61 @@ public: return bv; } - /// @brief Clear the geometry primitive data - void clear() - { - vertices = NULL; - prev_vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - Vec3f* vertices; - Vec3f* prev_vertices; - Triangle* tri_indices; - BVHModelType type; +protected: + using BVFitterTpl<BV>::vertices; + using BVFitterTpl<BV>::prev_vertices; + using BVFitterTpl<BV>::tri_indices; + using BVFitterTpl<BV>::type; }; - /// @brief Specification of BVFitter for OBB bounding volume template<> -class BVFitter<OBB> : public BVFitterBase<OBB> +class BVFitter<OBB> : public BVFitterTpl<OBB> { public: - /// @brief Prepare the geometry primitive data for fitting - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - prev_vertices = NULL; - tri_indices = tri_indices_; - type = type_; - } - - /// @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_; - prev_vertices = prev_vertices_; - tri_indices = tri_indices_; - 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. OBB fit(unsigned int* primitive_indices, int num_primitives); - - /// brief Clear the geometry primitive data - void clear() - { - vertices = NULL; - prev_vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - Vec3f* vertices; - Vec3f* prev_vertices; - Triangle* tri_indices; - BVHModelType type; }; - /// @brief Specification of BVFitter for RSS bounding volume template<> -class BVFitter<RSS> : public BVFitterBase<RSS> +class BVFitter<RSS> : public BVFitterTpl<RSS> { public: - /// brief Prepare the geometry primitive data for fitting - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - prev_vertices = NULL; - tri_indices = tri_indices_; - type = type_; - } - - /// @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_; - prev_vertices = prev_vertices_; - tri_indices = tri_indices_; - 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. RSS fit(unsigned int* primitive_indices, int num_primitives); - - /// @brief Clear the geometry primitive data - void clear() - { - vertices = NULL; - prev_vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - Vec3f* vertices; - Vec3f* prev_vertices; - Triangle* tri_indices; - BVHModelType type; }; - /// @brief Specification of BVFitter for kIOS bounding volume template<> -class BVFitter<kIOS> : public BVFitterBase<kIOS> +class BVFitter<kIOS> : public BVFitterTpl<kIOS> { public: - /// @brief Prepare the geometry primitive data for fitting - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - prev_vertices = NULL; - tri_indices = tri_indices_; - type = type_; - } - - /// @brief Prepare the geometry primitive data for fitting - void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - prev_vertices = prev_vertices_; - tri_indices = tri_indices_; - 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. kIOS fit(unsigned int* primitive_indices, int num_primitives); - - /// @brief Clear the geometry primitive data - void clear() - { - vertices = NULL; - prev_vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - Vec3f* vertices; - Vec3f* prev_vertices; - Triangle* tri_indices; - BVHModelType type; }; - /// @brief Specification of BVFitter for OBBRSS bounding volume template<> -class BVFitter<OBBRSS> : public BVFitterBase<OBBRSS> +class BVFitter<OBBRSS> : public BVFitterTpl<OBBRSS> { public: - /// @brief Prepare the geometry primitive data for fitting - void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - prev_vertices = NULL; - tri_indices = tri_indices_; - type = type_; - } - - /// @brief Prepare the geometry primitive data for fitting - void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) - { - vertices = vertices_; - prev_vertices = prev_vertices_; - tri_indices = tri_indices_; - 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. OBBRSS fit(unsigned int* primitive_indices, int num_primitives); +}; - /// @brief Clear the geometry primitive data - void clear() - { - vertices = NULL; - prev_vertices = NULL; - tri_indices = NULL; - type = BVH_MODEL_UNKNOWN; - } - -private: - - Vec3f* vertices; - Vec3f* prev_vertices; - Triangle* tri_indices; - BVHModelType type; +/// @brief Specification of BVFitter for AABB bounding volume +template<> +class BVFitter<AABB> : public BVFitterTpl<AABB> +{ +public: + /// @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. + AABB fit(unsigned int* primitive_indices, int num_primitives); }; } diff --git a/include/hpp/fcl/BVH/BV_splitter.h b/include/hpp/fcl/internal/BV_splitter.h similarity index 92% rename from include/hpp/fcl/BVH/BV_splitter.h rename to include/hpp/fcl/internal/BV_splitter.h index 7ad7bd996b0d6fef5b96318256579f03f0f6cd1b..7be8ca7490f7ae6fe3e268e4ac3a3c6b8d3e0e52 100644 --- a/include/hpp/fcl/BVH/BV_splitter.h +++ b/include/hpp/fcl/internal/BV_splitter.h @@ -49,32 +49,13 @@ namespace hpp namespace fcl { -/// @brief Base interface for BV splitting algorithm -template<typename BV> -class BVSplitterBase -{ -public: - /// @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 - virtual void computeRule(const BV& bv, unsigned int* primitive_indices, int num_primitives) = 0; - - /// @brief Apply the split rule on a given point - virtual bool apply(const Vec3f& q) const = 0; - - /// @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 template<typename BV> -class BVSplitter : public BVSplitterBase<BV> +class BVSplitter { public: diff --git a/include/hpp/fcl/intersect.h b/include/hpp/fcl/internal/intersect.h similarity index 76% rename from include/hpp/fcl/intersect.h rename to include/hpp/fcl/internal/intersect.h index b56a6c626389fd6628ea5ef31b79a9f9a9fff38b..b0b397a3aeb3e4dcf5c4e4a55bdcc5fa331eb346 100644 --- a/include/hpp/fcl/intersect.h +++ b/include/hpp/fcl/internal/intersect.h @@ -38,45 +38,24 @@ #ifndef HPP_FCL_INTERSECT_H #define HPP_FCL_INTERSECT_H +/// @cond INTERNAL + #include <hpp/fcl/math/transform.h> #include <boost/math/special_functions/erf.hpp> -namespace hpp -{ +namespace hpp +{ namespace fcl { -/// @brief A class solves polynomial degree (1,2,3) equations -class PolySolver +/// @brief CCD intersect kernel among primitives +class Intersect { public: - /// @brief Solve a linear equation with coefficients c, return roots s and number of roots - static int solveLinear(FCL_REAL c[2], FCL_REAL s[1]); - - /// @brief Solve a quadratic function with coefficients c, return roots s and number of roots - static int solveQuadric(FCL_REAL c[3], FCL_REAL s[2]); - - /// @brief Solve a cubic function with coefficients c, return roots s and number of roots - static int solveCubic(FCL_REAL c[4], FCL_REAL s[3]); - -private: - /// @brief Check whether v is zero - static inline bool isZero(FCL_REAL v); + static bool buildTrianglePlane + (const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, FCL_REAL* t); +}; // class Intersect - /// @brief Compute v^{1/3} - static inline bool cbrt(FCL_REAL v); - - static const FCL_REAL NEAR_ZERO_THRESHOLD; -}; - -/// @brief CCD intersect kernel among primitives -class Intersect -{ -public: - static bool buildTrianglePlane - (const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, FCL_REAL* t); -}; // class Intersect - /// @brief Project functions class Project { @@ -130,9 +109,9 @@ public: Vec3f& VEC, Vec3f& X, Vec3f& Y); /// Compute squared distance between triangles - /// \param S and T are two triangles - /// \retval P, Q closest points if triangles do not intersect. - /// \return squared distance if triangles do not intersect, 0 otherwise. + /// @param S and T are two triangles + /// @retval P, Q closest points if triangles do not intersect. + /// @return squared distance if triangles do not intersect, 0 otherwise. /// If the triangles are disjoint, P and Q give the closet points of /// S and T respectively. However, /// if the triangles overlap, P and Q are basically a random pair of points @@ -147,10 +126,10 @@ public: Vec3f& P, Vec3f& Q); /// Compute squared distance between triangles - /// \param S and T are two triangles - /// \param R, Tl, rotation and translation applied to T, - /// \retval P, Q closest points if triangles do not intersect. - /// \return squared distance if triangles do not intersect, 0 otherwise. + /// @param S and T are two triangles + /// @param R, Tl, rotation and translation applied to T, + /// @retval P, Q closest points if triangles do not intersect. + /// @return squared distance if triangles do not intersect, 0 otherwise. /// If the triangles are disjoint, P and Q give the closet points of /// S and T respectively. However, /// if the triangles overlap, P and Q are basically a random pair of points @@ -161,10 +140,10 @@ public: Vec3f& P, Vec3f& Q); /// Compute squared distance between triangles - /// \param S and T are two triangles - /// \param tf, rotation and translation applied to T, - /// \retval P, Q closest points if triangles do not intersect. - /// \return squared distance if triangles do not intersect, 0 otherwise. + /// @param S and T are two triangles + /// @param tf, rotation and translation applied to T, + /// @retval P, Q closest points if triangles do not intersect. + /// @return squared distance if triangles do not intersect, 0 otherwise. /// If the triangles are disjoint, P and Q give the closet points of /// S and T respectively. However, /// if the triangles overlap, P and Q are basically a random pair of points @@ -176,10 +155,10 @@ public: /// Compute squared distance between triangles - /// \param S1, S2, S3 and T1, T2, T3 are triangle vertices - /// \param R, Tl, rotation and translation applied to T1, T2, T3, - /// \retval P, Q closest points if triangles do not intersect. - /// \return squared distance if triangles do not intersect, 0 otherwise. + /// @param S1, S2, S3 and T1, T2, T3 are triangle vertices + /// @param R, Tl, rotation and translation applied to T1, T2, T3, + /// @retval P, Q closest points if triangles do not intersect. + /// @return squared distance if triangles do not intersect, 0 otherwise. /// If the triangles are disjoint, P and Q give the closet points of /// S and T respectively. However, /// if the triangles overlap, P and Q are basically a random pair of points @@ -192,10 +171,10 @@ public: Vec3f& P, Vec3f& Q); /// Compute squared distance between triangles - /// \param S1, S2, S3 and T1, T2, T3 are triangle vertices - /// \param tf, rotation and translation applied to T1, T2, T3, - /// \retval P, Q closest points if triangles do not intersect. - /// \return squared distance if triangles do not intersect, 0 otherwise. + /// @param S1, S2, S3 and T1, T2, T3 are triangle vertices + /// @param tf, rotation and translation applied to T1, T2, T3, + /// @retval P, Q closest points if triangles do not intersect. + /// @return squared distance if triangles do not intersect, 0 otherwise. /// If the triangles are disjoint, P and Q give the closet points of /// S and T respectively. However, /// if the triangles overlap, P and Q are basically a random pair of points @@ -209,10 +188,10 @@ public: }; - } +} // namespace hpp + +/// @endcond -} // namespace hpp - #endif diff --git a/include/hpp/fcl/math/tools.h b/include/hpp/fcl/internal/tools.h similarity index 84% rename from include/hpp/fcl/math/tools.h rename to include/hpp/fcl/internal/tools.h index cfc19640f5d48b3aeef4c38e3707ee558fb958e1..8ad8a7abc3d1b82df20d475fafdfb2b14057972a 100644 --- a/include/hpp/fcl/math/tools.h +++ b/include/hpp/fcl/internal/tools.h @@ -98,14 +98,6 @@ void generateCoordinateSystem( } /* ----- Start Matrices ------ */ -template<typename Derived, typename OtherDerived> -void hat(const Eigen::MatrixBase<Derived>& mat, const Eigen::MatrixBase<OtherDerived>& vec) -{ - EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(Derived, 3, 3); - EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(OtherDerived, 3, 1); - const_cast< Eigen::MatrixBase<Derived>& >(mat) << 0, -vec[2], vec[1], vec[2], 0, -vec[0], -vec[1], vec[0], 0; -} - template<typename Derived, typename OtherDerived> void relativeTransform(const Eigen::MatrixBase<Derived>& R1, const Eigen::MatrixBase<OtherDerived>& t1, const Eigen::MatrixBase<Derived>& R2, const Eigen::MatrixBase<OtherDerived>& t2, @@ -205,38 +197,13 @@ void eigen(const Eigen::MatrixBase<Derived>& m, typename Derived::Scalar dout[3] return; } -template<typename Derived, typename OtherDerived> -typename Derived::Scalar quadraticForm(const Eigen::MatrixBase<Derived>& R, const Eigen::MatrixBase<OtherDerived>& v) -{ - return v.dot(R * v); -} - template<typename Derived, typename OtherDerived> bool isEqual(const Eigen::MatrixBase<Derived>& lhs, const Eigen::MatrixBase<OtherDerived>& rhs, const FCL_REAL tol = std::numeric_limits<FCL_REAL>::epsilon()*100) { return ((lhs - rhs).array().abs() < tol).all(); } -template <typename Derived> -inline Derived& setEulerZYX(const Eigen::MatrixBase<Derived>& R, FCL_REAL eulerX, FCL_REAL eulerY, FCL_REAL eulerZ) -{ - const_cast< Eigen::MatrixBase<Derived>& >(R).noalias() = ( - Eigen::AngleAxisd (eulerZ, Eigen::Vector3d::UnitZ()) * - Eigen::AngleAxisd (eulerY, Eigen::Vector3d::UnitY()) * - Eigen::AngleAxisd (eulerX, Eigen::Vector3d::UnitX()) - ).toRotationMatrix(); - return const_cast< Eigen::MatrixBase<Derived>& >(R).derived(); -} - -template <typename Derived> -inline Derived& setEulerYPR(const Eigen::MatrixBase<Derived>& R, FCL_REAL yaw, FCL_REAL pitch, FCL_REAL roll) -{ - return setEulerZYX(R, roll, pitch, yaw); } - -} - - } // namespace hpp -#endif +#endif \ No newline at end of file diff --git a/include/hpp/fcl/traversal/details/traversal.h b/include/hpp/fcl/internal/traversal.h similarity index 98% rename from include/hpp/fcl/traversal/details/traversal.h rename to include/hpp/fcl/internal/traversal.h index 2979a601f169303b8f3e6cf5b0a010c18d0e43fa..82553dcd6587be92f4279d1fae1f6077f5aa3e4b 100644 --- a/include/hpp/fcl/traversal/details/traversal.h +++ b/include/hpp/fcl/internal/traversal.h @@ -34,10 +34,11 @@ /** \author Joseph Mirabel */ - #ifndef HPP_FCL_TRAVERSAL_DETAILS_TRAVERSAL_H #define HPP_FCL_TRAVERSAL_DETAILS_TRAVERSAL_H +/// @cond INTERNAL + namespace hpp { namespace fcl @@ -73,4 +74,6 @@ namespace details } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/traversal/traversal_node_base.h b/include/hpp/fcl/internal/traversal_node_base.h similarity index 86% rename from include/hpp/fcl/traversal/traversal_node_base.h rename to include/hpp/fcl/internal/traversal_node_base.h index 918505de5e55d4f0678e8dad64603c96378559ba..6f6c41e32afcd3ddfbf79a11a32a6fefab5eab15 100644 --- a/include/hpp/fcl/traversal/traversal_node_base.h +++ b/include/hpp/fcl/internal/traversal_node_base.h @@ -38,6 +38,8 @@ #ifndef HPP_FCL_TRAVERSAL_NODE_BASE_H #define HPP_FCL_TRAVERSAL_NODE_BASE_H +/// @cond INTERNAL + #include <hpp/fcl/data_types.h> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/collision_data.h> @@ -48,6 +50,7 @@ namespace fcl { /// @brief Node structure encoding the information required for traversal. + class TraversalNodeBase { public: @@ -88,6 +91,10 @@ public: Transform3f tf2; }; +/// @defgroup Traversal_For_Collision +/// regroup class about traversal for distance. +/// @{ + /// @brief Node structure encoding the information required for collision traversal. class CollisionTraversalNodeBase : public TraversalNodeBase { @@ -98,16 +105,16 @@ public: virtual ~CollisionTraversalNodeBase(); /// @brief BV test between b1 and b2 - virtual bool BVTesting(int b1, int b2) const = 0; + virtual bool BVDisjoints(int b1, int b2) const = 0; /// BV test between b1 and b2 - /// \param b1, b2 Bounding volumes to test, - /// \retval sqrDistLowerBound square of a lower bound of the minimal + /// @param b1, b2 Bounding volumes to test, + /// @retval sqrDistLowerBound square of a lower bound of the minimal /// distance between bounding volumes. - virtual bool BVTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const = 0; + virtual bool BVDisjoints(int b1, int b2, FCL_REAL& sqrDistLowerBound) const = 0; /// @brief Leaf test between node b1 and b2, if they are both leafs - virtual void leafTesting(int /*b1*/, int /*b2*/, FCL_REAL& /*sqrDistLowerBound*/) const + virtual void leafCollides(int /*b1*/, int /*b2*/, FCL_REAL& /*sqrDistLowerBound*/) const { throw std::runtime_error ("Not implemented"); } @@ -128,6 +135,12 @@ public: bool enable_statistics; }; +/// @} + +/// @defgroup Traversal_For_Distance +/// regroup class about traversal for distance. +/// @{ + /// @brief Node structure encoding the information required for distance traversal. class DistanceTraversalNodeBase : public TraversalNodeBase { @@ -137,12 +150,12 @@ public: virtual ~DistanceTraversalNodeBase(); /// @brief BV test between b1 and b2 - /// \return a lower bound of the distance between the two BV. - /// \note except for OBB, this method returns the distance. - virtual FCL_REAL BVTesting(int b1, int b2) const; + /// @return a lower bound of the distance between the two BV. + /// @note except for OBB, this method returns the distance. + virtual FCL_REAL BVDistanceLowerBound(int b1, int b2) const; /// @brief Leaf test between node b1 and b2, if they are both leafs - virtual void leafTesting(int b1, int b2) const = 0; + virtual void leafComputeDistance(int b1, int b2) const = 0; /// @brief Check whether the traversal can stop virtual bool canStop(FCL_REAL c) const; @@ -159,8 +172,13 @@ public: /// @brief Whether stores statistics bool enable_statistics; }; + +///@} + } } // namespace hpp -#endif +/// @endcond + +#endif \ No newline at end of file diff --git a/include/hpp/fcl/traversal/traversal_node_bvh_shape.h b/include/hpp/fcl/internal/traversal_node_bvh_shape.h similarity index 83% rename from include/hpp/fcl/traversal/traversal_node_bvh_shape.h rename to include/hpp/fcl/internal/traversal_node_bvh_shape.h index 27ec3f9afed15285cdb311fff127bab9028e824e..37162e5cadfe3837e7f8a2020580a2406b0b3beb 100644 --- a/include/hpp/fcl/traversal/traversal_node_bvh_shape.h +++ b/include/hpp/fcl/internal/traversal_node_bvh_shape.h @@ -39,11 +39,14 @@ #ifndef HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H #define HPP_FCL_TRAVERSAL_NODE_MESH_SHAPE_H +/// @cond INTERNAL + #include <hpp/fcl/collision_data.h> #include <hpp/fcl/shape/geometric_shapes.h> +#include <hpp/fcl/narrowphase/narrowphase.h> #include <hpp/fcl/shape/geometric_shapes_utility.h> -#include <hpp/fcl/traversal/traversal_node_base.h> -#include <hpp/fcl/traversal/details/traversal.h> +#include <hpp/fcl/internal/traversal_node_base.h> +#include <hpp/fcl/internal/traversal.h> #include <hpp/fcl/BVH/BVH_model.h> @@ -52,6 +55,9 @@ namespace hpp namespace fcl { +/// @addtogroup Traversal_For_Collision +/// @{ + /// @brief Traversal node for collision between BVH and shape template<typename BV, typename S> class BVHShapeCollisionTraversalNode : public CollisionTraversalNodeBase @@ -146,7 +152,7 @@ public: /// @brief Traversal node for collision between mesh and shape -template<typename BV, typename S, typename NarrowPhaseSolver, +template<typename BV, typename S, int _Options = RelativeTransformationIsIdentity> class MeshShapeCollisionTraversalNode : public BVHShapeCollisionTraversalNode<BV, S> { @@ -166,7 +172,7 @@ public: } /// @brief BV culling test in one BVTT node - bool BVTesting(int b1, int /*b2*/) const + bool BVDisjoints(int b1, int /*b2*/) const { if(this->enable_statistics) this->num_bv_tests++; if (RTIsIdentity) @@ -176,11 +182,11 @@ public: } /// test between BV b1 and shape - /// \param b1 BV to test, - /// \retval sqrDistLowerBound square of a lower bound of the minimal + /// @param b1 BV to test, + /// @retval sqrDistLowerBound square of a lower bound of the minimal /// distance between bounding volumes. /// @brief BV culling test in one BVTT node - bool BVTesting(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const + bool BVDisjoints(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const { if(this->enable_statistics) this->num_bv_tests++; bool res; @@ -195,7 +201,7 @@ public: } /// @brief Intersection testing between leaves (one triangle and one shape) - void leafTesting(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const + void leafCollides(int b1, int /*b2*/, FCL_REAL& sqrDistLowerBound) const { if(this->enable_statistics) this->num_leaf_tests++; const BVNode<BV>& node = this->model1->getBV(b1); @@ -256,50 +262,50 @@ public: Vec3f* vertices; Triangle* tri_indices; - const NarrowPhaseSolver* nsolver; + const GJKSolver* nsolver; }; /// @brief Traversal node for mesh and shape, when mesh BVH is one of the oriented node (OBB, RSS, OBBRSS, kIOS) -template<typename S, typename NarrowPhaseSolver> -class MeshShapeCollisionTraversalNodeOBB : public MeshShapeCollisionTraversalNode<OBB, S, NarrowPhaseSolver, 0> +template<typename S> +class MeshShapeCollisionTraversalNodeOBB : public MeshShapeCollisionTraversalNode<OBB, S, 0> { public: MeshShapeCollisionTraversalNodeOBB(const CollisionRequest& request) : - MeshShapeCollisionTraversalNode<OBB, S, NarrowPhaseSolver, 0> + MeshShapeCollisionTraversalNode<OBB, S, 0> (request) { } }; -template<typename S, typename NarrowPhaseSolver> -class MeshShapeCollisionTraversalNodeRSS : public MeshShapeCollisionTraversalNode<RSS, S, NarrowPhaseSolver, 0> +template<typename S> +class MeshShapeCollisionTraversalNodeRSS : public MeshShapeCollisionTraversalNode<RSS, S, 0> { public: MeshShapeCollisionTraversalNodeRSS (const CollisionRequest& request): - MeshShapeCollisionTraversalNode<RSS, S, NarrowPhaseSolver, 0> + MeshShapeCollisionTraversalNode<RSS, S, 0> (request) { } }; -template<typename S, typename NarrowPhaseSolver> -class MeshShapeCollisionTraversalNodekIOS : public MeshShapeCollisionTraversalNode<kIOS, S, NarrowPhaseSolver, 0> +template<typename S> +class MeshShapeCollisionTraversalNodekIOS : public MeshShapeCollisionTraversalNode<kIOS, S, 0> { public: MeshShapeCollisionTraversalNodekIOS(const CollisionRequest& request): - MeshShapeCollisionTraversalNode<kIOS, S, NarrowPhaseSolver, 0> + MeshShapeCollisionTraversalNode<kIOS, S, 0> (request) { } }; -template<typename S, typename NarrowPhaseSolver> -class MeshShapeCollisionTraversalNodeOBBRSS : public MeshShapeCollisionTraversalNode<OBBRSS, S, NarrowPhaseSolver, 0> +template<typename S> +class MeshShapeCollisionTraversalNodeOBBRSS : public MeshShapeCollisionTraversalNode<OBBRSS, S, 0> { public: MeshShapeCollisionTraversalNodeOBBRSS (const CollisionRequest& request) : - MeshShapeCollisionTraversalNode <OBBRSS, S, NarrowPhaseSolver, 0> + MeshShapeCollisionTraversalNode <OBBRSS, S, 0> (request) { } @@ -307,7 +313,7 @@ public: /// @brief Traversal node for collision between shape and mesh -template<typename S, typename BV, typename NarrowPhaseSolver, +template<typename S, typename BV, int _Options = RelativeTransformationIsIdentity> class ShapeMeshCollisionTraversalNode : public ShapeBVHCollisionTraversalNode<S, BV> { @@ -326,8 +332,8 @@ public: } /// BV test between b1 and b2 - /// \param b2 Bounding volumes to test, - bool BVTesting(int /*b1*/, int b2) const + /// @param b2 Bounding volumes to test, + bool BVDisjoints(int /*b1*/, int b2) const { if(this->enable_statistics) this->num_bv_tests++; if (RTIsIdentity) @@ -337,10 +343,10 @@ public: } /// BV test between b1 and b2 - /// \param b2 Bounding volumes to test, - /// \retval sqrDistLowerBound square of a lower bound of the minimal + /// @param b2 Bounding volumes to test, + /// @retval sqrDistLowerBound square of a lower bound of the minimal /// distance between bounding volumes. - bool BVTesting(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const + bool BVDisjoints(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const { if(this->enable_statistics) this->num_bv_tests++; bool res; @@ -355,7 +361,7 @@ public: } /// @brief Intersection testing between leaves (one shape and one triangle) - void leafTesting(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const + void leafCollides(int /*b1*/, int b2, FCL_REAL& sqrDistLowerBound) const { if(this->enable_statistics) this->num_leaf_tests++; const BVNode<BV>& node = this->model2->getBV(b2); @@ -416,49 +422,54 @@ public: Vec3f* vertices; Triangle* tri_indices; - const NarrowPhaseSolver* nsolver; + const GJKSolver* nsolver; }; /// @brief Traversal node for shape and mesh, when mesh BVH is one of the oriented node (OBB, RSS, OBBRSS, kIOS) -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshCollisionTraversalNodeOBB : public ShapeMeshCollisionTraversalNode<S, OBB, NarrowPhaseSolver, 0> +template<typename S> +class ShapeMeshCollisionTraversalNodeOBB : public ShapeMeshCollisionTraversalNode<S, OBB, 0> { public: - ShapeMeshCollisionTraversalNodeOBB() : ShapeMeshCollisionTraversalNode<S, OBB, NarrowPhaseSolver>() + ShapeMeshCollisionTraversalNodeOBB() : ShapeMeshCollisionTraversalNode<S, OBB>() { } }; -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshCollisionTraversalNodeRSS : public ShapeMeshCollisionTraversalNode<S, RSS, NarrowPhaseSolver, 0> +template<typename S> +class ShapeMeshCollisionTraversalNodeRSS : public ShapeMeshCollisionTraversalNode<S, RSS, 0> { public: - ShapeMeshCollisionTraversalNodeRSS() : ShapeMeshCollisionTraversalNode<S, RSS, NarrowPhaseSolver>() + ShapeMeshCollisionTraversalNodeRSS() : ShapeMeshCollisionTraversalNode<S, RSS>() { } }; -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshCollisionTraversalNodekIOS : public ShapeMeshCollisionTraversalNode<S, kIOS, NarrowPhaseSolver, 0> +template<typename S> +class ShapeMeshCollisionTraversalNodekIOS : public ShapeMeshCollisionTraversalNode<S, kIOS, 0> { public: - ShapeMeshCollisionTraversalNodekIOS() : ShapeMeshCollisionTraversalNode<S, kIOS, NarrowPhaseSolver>() + ShapeMeshCollisionTraversalNodekIOS() : ShapeMeshCollisionTraversalNode<S, kIOS>() { } }; -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshCollisionTraversalNodeOBBRSS : public ShapeMeshCollisionTraversalNode<S, OBBRSS, NarrowPhaseSolver, 0> +template<typename S> +class ShapeMeshCollisionTraversalNodeOBBRSS : public ShapeMeshCollisionTraversalNode<S, OBBRSS, 0> { public: - ShapeMeshCollisionTraversalNodeOBBRSS() : ShapeMeshCollisionTraversalNode<S, OBBRSS, NarrowPhaseSolver>() + ShapeMeshCollisionTraversalNodeOBBRSS() : ShapeMeshCollisionTraversalNode<S, OBBRSS>() { } }; +/// @} + +/// @addtogroup Traversal_For_Distance +/// @{ + /// @brief Traversal node for distance computation between BVH and shape template<typename BV, typename S> class BVHShapeDistanceTraversalNode : public DistanceTraversalNodeBase @@ -493,7 +504,7 @@ public: } /// @brief BV culling test in one BVTT node - FCL_REAL BVTesting(int b1, int /*b2*/) const + FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const { return model1->getBV(b1).bv.distance(model2_bv); } @@ -541,7 +552,7 @@ public: } /// @brief BV culling test in one BVTT node - FCL_REAL BVTesting(int b1, int b2) const + FCL_REAL BVDistanceLowerBound(int b1, int b2) const { return model1_bv.distance(model2->getBV(b2).bv); } @@ -557,7 +568,7 @@ public: /// @brief Traversal node for distance between mesh and shape -template<typename BV, typename S, typename NarrowPhaseSolver> +template<typename BV, typename S> class MeshShapeDistanceTraversalNode : public BVHShapeDistanceTraversalNode<BV, S> { public: @@ -573,7 +584,7 @@ public: } /// @brief Distance testing between leaves (one triangle and one shape) - void leafTesting(int b1, int /*b2*/) const + void leafComputeDistance(int b1, int /*b2*/) const { if(this->enable_statistics) this->num_leaf_tests++; @@ -612,20 +623,20 @@ public: FCL_REAL rel_err; FCL_REAL abs_err; - const NarrowPhaseSolver* nsolver; + const GJKSolver* nsolver; }; /// @cond IGNORE namespace details { -template<typename BV, typename S, typename NarrowPhaseSolver> -void meshShapeDistanceOrientedNodeLeafTesting(int b1, int /* b2 */, +template<typename BV, typename S> +void meshShapeDistanceOrientedNodeleafComputeDistance(int b1, int /* b2 */, const BVHModel<BV>* model1, const S& model2, Vec3f* vertices, Triangle* tri_indices, const Transform3f& tf1, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, bool enable_statistics, int & num_leaf_tests, const DistanceRequest& /* request */, @@ -651,11 +662,11 @@ void meshShapeDistanceOrientedNodeLeafTesting(int b1, int /* b2 */, } -template<typename BV, typename S, typename NarrowPhaseSolver> +template<typename BV, typename S> static inline void distancePreprocessOrientedNode(const BVHModel<BV>* model1, Vec3f* vertices, Triangle* tri_indices, int init_tri_id, const S& model2, const Transform3f& tf1, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& /* request */, DistanceResult& result) { @@ -681,12 +692,12 @@ static inline void distancePreprocessOrientedNode(const BVHModel<BV>* model1, -/// @brief Traversal node for distance between mesh and shape, when mesh BVH is one of the oriented node (RSS, OBBRSS, kIOS) -template<typename S, typename NarrowPhaseSolver> -class MeshShapeDistanceTraversalNodeRSS : public MeshShapeDistanceTraversalNode<RSS, S, NarrowPhaseSolver> +/// @brief Traversal node for distance between mesh and shape, when mesh BVH is one of the oriented node (RSS, kIOS, OBBRSS) +template<typename S> +class MeshShapeDistanceTraversalNodeRSS : public MeshShapeDistanceTraversalNode<RSS, S> { public: - MeshShapeDistanceTraversalNodeRSS() : MeshShapeDistanceTraversalNode<RSS, S, NarrowPhaseSolver>() + MeshShapeDistanceTraversalNodeRSS() : MeshShapeDistanceTraversalNode<RSS, S>() { } @@ -700,25 +711,25 @@ public: { } - FCL_REAL BVTesting(int b1, int /*b2*/) const + FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const { if(this->enable_statistics) this->num_bv_tests++; return distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model2_bv, this->model1->getBV(b1).bv); } - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { - details::meshShapeDistanceOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices, + details::meshShapeDistanceOrientedNodeleafComputeDistance(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices, this->tf1, this->tf2, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result)); } }; -template<typename S, typename NarrowPhaseSolver> -class MeshShapeDistanceTraversalNodekIOS : public MeshShapeDistanceTraversalNode<kIOS, S, NarrowPhaseSolver> +template<typename S> +class MeshShapeDistanceTraversalNodekIOS : public MeshShapeDistanceTraversalNode<kIOS, S> { public: - MeshShapeDistanceTraversalNodekIOS() : MeshShapeDistanceTraversalNode<kIOS, S, NarrowPhaseSolver>() + MeshShapeDistanceTraversalNodekIOS() : MeshShapeDistanceTraversalNode<kIOS, S>() { } @@ -732,25 +743,25 @@ public: { } - FCL_REAL BVTesting(int b1, int /*b2*/) const + FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const { if(this->enable_statistics) this->num_bv_tests++; return distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model2_bv, this->model1->getBV(b1).bv); } - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { - details::meshShapeDistanceOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices, + details::meshShapeDistanceOrientedNodeleafComputeDistance(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices, this->tf1, this->tf2, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result)); } }; -template<typename S, typename NarrowPhaseSolver> -class MeshShapeDistanceTraversalNodeOBBRSS : public MeshShapeDistanceTraversalNode<OBBRSS, S, NarrowPhaseSolver> +template<typename S> +class MeshShapeDistanceTraversalNodeOBBRSS : public MeshShapeDistanceTraversalNode<OBBRSS, S> { public: - MeshShapeDistanceTraversalNodeOBBRSS() : MeshShapeDistanceTraversalNode<OBBRSS, S, NarrowPhaseSolver>() + MeshShapeDistanceTraversalNodeOBBRSS() : MeshShapeDistanceTraversalNode<OBBRSS, S>() { } @@ -765,22 +776,22 @@ public: } - FCL_REAL BVTesting(int b1, int /*b2*/) const + FCL_REAL BVDistanceLowerBound(int b1, int /*b2*/) const { if(this->enable_statistics) this->num_bv_tests++; return distance(this->tf1.getRotation(), this->tf1.getTranslation(), this->model2_bv, this->model1->getBV(b1).bv); } - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { - details::meshShapeDistanceOrientedNodeLeafTesting(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices, + details::meshShapeDistanceOrientedNodeleafComputeDistance(b1, b2, this->model1, *(this->model2), this->vertices, this->tri_indices, this->tf1, this->tf2, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result)); } }; /// @brief Traversal node for distance between shape and mesh -template<typename S, typename BV, typename NarrowPhaseSolver> +template<typename S, typename BV> class ShapeMeshDistanceTraversalNode : public ShapeBVHDistanceTraversalNode<S, BV> { public: @@ -796,7 +807,7 @@ public: } /// @brief Distance testing between leaves (one shape and one triangle) - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { if(this->enable_statistics) this->num_leaf_tests++; @@ -835,14 +846,15 @@ public: FCL_REAL rel_err; FCL_REAL abs_err; - const NarrowPhaseSolver* nsolver; + const GJKSolver* nsolver; }; -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshDistanceTraversalNodeRSS : public ShapeMeshDistanceTraversalNode<S, RSS, NarrowPhaseSolver> +/// @brief Traversal node for distance between shape and mesh, when mesh BVH is one of the oriented node (RSS, kIOS, OBBRSS) +template<typename S> +class ShapeMeshDistanceTraversalNodeRSS : public ShapeMeshDistanceTraversalNode<S, RSS> { public: - ShapeMeshDistanceTraversalNodeRSS() : ShapeMeshDistanceTraversalNode<S, RSS, NarrowPhaseSolver>() + ShapeMeshDistanceTraversalNodeRSS() : ShapeMeshDistanceTraversalNode<S, RSS>() { } @@ -856,25 +868,25 @@ public: { } - FCL_REAL BVTesting(int b1, int b2) const + FCL_REAL BVDistanceLowerBound(int b1, int b2) const { if(this->enable_statistics) this->num_bv_tests++; return distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model1_bv, this->model2->getBV(b2).bv); } - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { - details::meshShapeDistanceOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices, + details::meshShapeDistanceOrientedNodeleafComputeDistance(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices, this->tf2, this->tf1, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result)); } }; -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshDistanceTraversalNodekIOS : public ShapeMeshDistanceTraversalNode<S, kIOS, NarrowPhaseSolver> +template<typename S> +class ShapeMeshDistanceTraversalNodekIOS : public ShapeMeshDistanceTraversalNode<S, kIOS> { public: - ShapeMeshDistanceTraversalNodekIOS() : ShapeMeshDistanceTraversalNode<S, kIOS, NarrowPhaseSolver>() + ShapeMeshDistanceTraversalNodekIOS() : ShapeMeshDistanceTraversalNode<S, kIOS>() { } @@ -888,25 +900,25 @@ public: { } - FCL_REAL BVTesting(int b1, int b2) const + FCL_REAL BVDistanceLowerBound(int b1, int b2) const { if(this->enable_statistics) this->num_bv_tests++; return distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model1_bv, this->model2->getBV(b2).bv); } - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { - details::meshShapeDistanceOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices, + details::meshShapeDistanceOrientedNodeleafComputeDistance(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices, this->tf2, this->tf1, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result)); } }; -template<typename S, typename NarrowPhaseSolver> -class ShapeMeshDistanceTraversalNodeOBBRSS : public ShapeMeshDistanceTraversalNode<S, OBBRSS, NarrowPhaseSolver> +template<typename S> +class ShapeMeshDistanceTraversalNodeOBBRSS : public ShapeMeshDistanceTraversalNode<S, OBBRSS> { public: - ShapeMeshDistanceTraversalNodeOBBRSS() : ShapeMeshDistanceTraversalNode<S, OBBRSS, NarrowPhaseSolver>() + ShapeMeshDistanceTraversalNodeOBBRSS() : ShapeMeshDistanceTraversalNode<S, OBBRSS>() { } @@ -920,21 +932,26 @@ public: { } - FCL_REAL BVTesting(int b1, int b2) const + FCL_REAL BVDistanceLowerBound(int b1, int b2) const { if(this->enable_statistics) this->num_bv_tests++; return distance(this->tf2.getRotation(), this->tf2.getTranslation(), this->model1_bv, this->model2->getBV(b2).bv); } - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { - details::meshShapeDistanceOrientedNodeLeafTesting(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices, + details::meshShapeDistanceOrientedNodeleafComputeDistance(b2, b1, this->model2, *(this->model1), this->vertices, this->tri_indices, this->tf2, this->tf1, this->nsolver, this->enable_statistics, this->num_leaf_tests, this->request, *(this->result)); } }; + +/// @} + } } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/traversal/traversal_node_bvhs.h b/include/hpp/fcl/internal/traversal_node_bvhs.h similarity index 90% rename from include/hpp/fcl/traversal/traversal_node_bvhs.h rename to include/hpp/fcl/internal/traversal_node_bvhs.h index 985aa90d3f7c9e84fcec17d0d121d4b657f6379b..ed251b832357a59cc260229c818f2130101286b7 100644 --- a/include/hpp/fcl/traversal/traversal_node_bvhs.h +++ b/include/hpp/fcl/internal/traversal_node_bvhs.h @@ -35,19 +35,20 @@ /** \author Jia Pan */ - #ifndef HPP_FCL_TRAVERSAL_NODE_MESHES_H #define HPP_FCL_TRAVERSAL_NODE_MESHES_H +/// @cond INTERNAL + #include <hpp/fcl/collision_data.h> -#include <hpp/fcl/traversal/traversal_node_base.h> +#include <hpp/fcl/internal/traversal_node_base.h> #include <hpp/fcl/BV/BV_node.h> #include <hpp/fcl/BV/BV.h> #include <hpp/fcl/BVH/BVH_model.h> -#include <hpp/fcl/intersect.h> +#include <hpp/fcl/internal/intersect.h> #include <hpp/fcl/shape/geometric_shapes.h> #include <hpp/fcl/narrowphase/narrowphase.h> -#include <hpp/fcl/traversal/details/traversal.h> +#include <hpp/fcl/internal/traversal.h> #include <boost/shared_array.hpp> #include <boost/shared_ptr.hpp> @@ -55,11 +56,14 @@ #include <vector> #include <cassert> - namespace hpp { namespace fcl { + +/// @addtogroup Traversal_For_Collision +/// @{ + /// @brief Traversal node for collision between BVH models template<typename BV> class BVHCollisionTraversalNode : public CollisionTraversalNodeBase @@ -157,7 +161,7 @@ public: } /// @brief BV culling test in one BVTT node - bool BVTesting(int b1, int b2) const + bool BVDisjoints(int b1, int b2) const { if(this->enable_statistics) this->num_bv_tests++; if (RTIsIdentity) @@ -168,10 +172,10 @@ public: } /// BV test between b1 and b2 - /// \param b1, b2 Bounding volumes to test, - /// \retval sqrDistLowerBound square of a lower bound of the minimal + /// @param b1, b2 Bounding volumes to test, + /// @retval sqrDistLowerBound square of a lower bound of the minimal /// distance between bounding volumes. - bool BVTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const + bool BVDisjoints(int b1, int b2, FCL_REAL& sqrDistLowerBound) const { if(this->enable_statistics) this->num_bv_tests++; if (RTIsIdentity) @@ -188,8 +192,8 @@ public: /// Intersection testing between leaves (two triangles) /// - /// \param b1, b2 id of primitive in bounding volume hierarchy - /// \retval sqrDistLowerBound squared lower bound of distance between + /// @param b1, b2 id of primitive in bounding volume hierarchy + /// @retval sqrDistLowerBound squared lower bound of distance between /// primitives if they are not in collision. /// /// This method supports a security margin. If the distance between @@ -197,10 +201,10 @@ public: /// considered as in collision. in this case a contact point is /// returned in the CollisionResult. /// - /// \note If the distance between objects is less than the security margin, + /// @note If the distance between objects is less than the security margin, /// and the object are not colliding, the penetration depth is /// negative. - void leafTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const + void leafCollides(int b1, int b2, FCL_REAL& sqrDistLowerBound) const { if(this->enable_statistics) this->num_leaf_tests++; @@ -222,7 +226,7 @@ public: TriangleP tri1 (P1, P2, P3); TriangleP tri2 (Q1, Q2, Q3); - GJKSolver_indep solver; + GJKSolver solver; Vec3f p1, p2; // closest points if no collision contact points if collision. Vec3f normal; FCL_REAL distance; @@ -269,9 +273,11 @@ typedef MeshCollisionTraversalNode<RSS , 0> MeshCollisionTraversalNodeRSS ; typedef MeshCollisionTraversalNode<kIOS , 0> MeshCollisionTraversalNodekIOS ; typedef MeshCollisionTraversalNode<OBBRSS, 0> MeshCollisionTraversalNodeOBBRSS; +/// @} + namespace details { - template<typename BV> struct DistanceTraversalBVTesting_impl + template<typename BV> struct DistanceTraversalBVDistanceLowerBound_impl { static FCL_REAL run(const BVNode<BV>& b1, const BVNode<BV>& b2) { @@ -279,7 +285,7 @@ namespace details } }; - template<> struct DistanceTraversalBVTesting_impl<OBB> + template<> struct DistanceTraversalBVDistanceLowerBound_impl<OBB> { static FCL_REAL run(const BVNode<OBB>& b1, const BVNode<OBB>& b2) { @@ -295,6 +301,9 @@ namespace details }; } // namespace details +/// @addtogroup Traversal_For_Distance +/// @{ + /// @brief Traversal node for distance computation between BVH models template<typename BV> class BVHDistanceTraversalNode : public DistanceTraversalNodeBase @@ -361,10 +370,10 @@ public: } /// @brief BV culling test in one BVTT node - FCL_REAL BVTesting(int b1, int b2) const + FCL_REAL BVDistanceLowerBound(int b1, int b2) const { if(enable_statistics) num_bv_tests++; - return details::DistanceTraversalBVTesting_impl<BV> + return details::DistanceTraversalBVDistanceLowerBound_impl<BV> ::run (model1->getBV(b1), model2->getBV(b2)); } @@ -397,7 +406,7 @@ public: } /// @brief Distance testing between leaves (two triangles) - void leafTesting(int b1, int b2) const + void leafComputeDistance(int b1, int b2) const { if(this->enable_statistics) this->num_leaf_tests++; @@ -457,9 +466,9 @@ public: void postprocess(); - FCL_REAL BVTesting(int b1, int b2) const; + FCL_REAL BVDistanceLowerBound(int b1, int b2) const; - void leafTesting(int b1, int b2) const; + void leafComputeDistance(int b1, int b2) const; Matrix3f R; Vec3f T; @@ -475,9 +484,9 @@ public: void postprocess(); - FCL_REAL BVTesting(int b1, int b2) const; + FCL_REAL BVDistanceLowerBound(int b1, int b2) const; - void leafTesting(int b1, int b2) const; + void leafComputeDistance(int b1, int b2) const; Matrix3f R; Vec3f T; @@ -492,16 +501,18 @@ public: void postprocess(); - FCL_REAL BVTesting(int b1, int b2) const; + FCL_REAL BVDistanceLowerBound(int b1, int b2) const; - FCL_REAL BVTesting(int b1, int b2, FCL_REAL& sqrDistLowerBound) const; + FCL_REAL BVDistanceLowerBound(int b1, int b2, FCL_REAL& sqrDistLowerBound) const; - void leafTesting(int b1, int b2) const; + void leafComputeDistance(int b1, int b2) const; Matrix3f R; Vec3f T; }; +/// @} + /// @brief for OBB and RSS, there is local coordinate of BV, so normal need to be transformed namespace details { @@ -518,11 +529,12 @@ inline const Matrix3f& getBVAxes<OBBRSS>(const OBBRSS& bv) return bv.obb.axes; } - } } } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/traversal/traversal_node_octree.h b/include/hpp/fcl/internal/traversal_node_octree.h similarity index 93% rename from include/hpp/fcl/traversal/traversal_node_octree.h rename to include/hpp/fcl/internal/traversal_node_octree.h index b9c47c07afb8f37ac7a8be75cb4a53e95e33a7e8..e2857da225d33f3a4c1e843d84914ac518a30539 100644 --- a/include/hpp/fcl/traversal/traversal_node_octree.h +++ b/include/hpp/fcl/internal/traversal_node_octree.h @@ -38,12 +38,14 @@ #ifndef HPP_FCL_TRAVERSAL_NODE_OCTREE_H #define HPP_FCL_TRAVERSAL_NODE_OCTREE_H +/// @cond INTERNAL + #include <hpp/fcl/collision_data.h> -#include <hpp/fcl/traversal/traversal_node_base.h> +#include <hpp/fcl/internal/traversal_node_base.h> #include <hpp/fcl/narrowphase/narrowphase.h> -#include <hpp/fcl/shape/geometric_shapes_utility.h> #include <hpp/fcl/octree.h> #include <hpp/fcl/BVH/BVH_model.h> +#include <hpp/fcl/shape/geometric_shapes_utility.h> namespace hpp { @@ -51,11 +53,10 @@ namespace fcl { /// @brief Algorithms for collision related with octree -template<typename NarrowPhaseSolver> class OcTreeSolver { private: - const NarrowPhaseSolver* solver; + const GJKSolver* solver; mutable const CollisionRequest* crequest; mutable const DistanceRequest* drequest; @@ -64,7 +65,7 @@ private: mutable DistanceResult* dresult; public: - OcTreeSolver(const NarrowPhaseSolver* solver_) : solver(solver_), + OcTreeSolver(const GJKSolver* solver_) : solver(solver_), crequest(NULL), drequest(NULL), cresult(NULL), @@ -886,11 +887,10 @@ private: } }; - - +/// @addtogroup Traversal_For_Collision +/// @{ /// @brief Traversal node for octree collision -template<typename NarrowPhaseSolver> class OcTreeCollisionTraversalNode : public CollisionTraversalNodeBase { public: @@ -903,17 +903,17 @@ public: otsolver = NULL; } - bool BVTesting(int, int) const + bool BVDisjoints(int, int) const { return false; } - bool BVTesting(int, int, FCL_REAL&) const + bool BVDisjoints(int, int, FCL_REAL&) const { return false; } - void leafTesting(int, int, FCL_REAL&) const + void leafCollides(int, int, FCL_REAL&) const { otsolver->OcTreeIntersect(model1, model2, tf1, tf2, request, *result); } @@ -923,15 +923,16 @@ public: Transform3f tf1, tf2; - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for octree distance -template<typename NarrowPhaseSolver> -class OcTreeDistanceTraversalNode : public DistanceTraversalNodeBase +/// @brief Traversal node for shape-octree collision +template<typename S> +class ShapeOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase { public: - OcTreeDistanceTraversalNode() + ShapeOcTreeCollisionTraversalNode(const CollisionRequest& request) : + CollisionTraversalNodeBase (request) { model1 = NULL; model2 = NULL; @@ -939,34 +940,36 @@ public: otsolver = NULL; } - - FCL_REAL BVTesting(int, int) const + bool BVDisjoints(int, int) const { - return -1; + return false; } - bool BVTesting(int, int, FCL_REAL&) const + bool BVDisjoints(int, int, FCL_REAL&) const { return false; } - void leafTesting(int, int) const + void leafCollides(int, int, FCL_REAL&) const { - otsolver->OcTreeDistance(model1, model2, tf1, tf2, request, *result); + otsolver->OcTreeShapeIntersect(model2, *model1, tf2, tf1, request, *result); } - const OcTree* model1; + const S* model1; const OcTree* model2; - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + Transform3f tf1, tf2; + + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for shape-octree collision -template<typename S, typename NarrowPhaseSolver> -class ShapeOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase +/// @brief Traversal node for octree-shape collision + +template<typename S> +class OcTreeShapeCollisionTraversalNode : public CollisionTraversalNodeBase { public: - ShapeOcTreeCollisionTraversalNode(const CollisionRequest& request) : + OcTreeShapeCollisionTraversalNode(const CollisionRequest& request) : CollisionTraversalNodeBase (request) { model1 = NULL; @@ -975,35 +978,35 @@ public: otsolver = NULL; } - bool BVTesting(int, int) const + bool BVDisjoints(int, int) const { return false; } - bool BVTesting(int, int, FCL_REAL&) const + bool BVDisjoints(int, int, fcl::FCL_REAL&) const { return false; } - void leafTesting(int, int, FCL_REAL&) const + void leafCollides(int, int, FCL_REAL&) const { - otsolver->OcTreeShapeIntersect(model2, *model1, tf2, tf1, request, *result); + otsolver->OcTreeShapeIntersect(model1, *model2, tf1, tf2, request, *result); } - const S* model1; - const OcTree* model2; + const OcTree* model1; + const S* model2; Transform3f tf1, tf2; - - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for octree-shape collision -template<typename S, typename NarrowPhaseSolver> -class OcTreeShapeCollisionTraversalNode : public CollisionTraversalNodeBase +/// @brief Traversal node for mesh-octree collision +template<typename BV> +class MeshOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase { public: - OcTreeShapeCollisionTraversalNode(const CollisionRequest& request) : + MeshOcTreeCollisionTraversalNode(const CollisionRequest& request) : CollisionTraversalNodeBase (request) { model1 = NULL; @@ -1012,163 +1015,167 @@ public: otsolver = NULL; } - bool BVTesting(int, int) const + bool BVDisjoints(int, int) const { return false; } - bool BVTesting(int, int, fcl::FCL_REAL&) const + bool BVDisjoints(int, int, FCL_REAL&) const { return false; } - void leafTesting(int, int, FCL_REAL&) const + void leafCollides(int, int, FCL_REAL&) const { - otsolver->OcTreeShapeIntersect(model1, *model2, tf1, tf2, request, *result); + otsolver->OcTreeMeshIntersect(model2, model1, tf2, tf1, request, *result); } - const OcTree* model1; - const S* model2; + const BVHModel<BV>* model1; + const OcTree* model2; Transform3f tf1, tf2; - - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for shape-octree distance -template<typename S, typename NarrowPhaseSolver> -class ShapeOcTreeDistanceTraversalNode : public DistanceTraversalNodeBase +/// @brief Traversal node for octree-mesh collision +template<typename BV> +class OcTreeMeshCollisionTraversalNode : public CollisionTraversalNodeBase { public: - ShapeOcTreeDistanceTraversalNode() + OcTreeMeshCollisionTraversalNode(const CollisionRequest& request) : + CollisionTraversalNodeBase (request) { model1 = NULL; model2 = NULL; - + otsolver = NULL; } - FCL_REAL BVTesting(int, int) const + bool BVDisjoints(int, int) const { - return -1; + return false; } - void leafTesting(int, int) const + bool BVDisjoints(int, int, FCL_REAL&) const { - otsolver->OcTreeShapeDistance(model2, *model1, tf2, tf1, request, *result); + return false; } - const S* model1; - const OcTree* model2; + void leafCollides(int, int, FCL_REAL&) const + { + otsolver->OcTreeMeshIntersect(model1, model2, tf1, tf2, request, *result); + } + + const OcTree* model1; + const BVHModel<BV>* model2; - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + Transform3f tf1, tf2; + + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for octree-shape distance -template<typename S, typename NarrowPhaseSolver> -class OcTreeShapeDistanceTraversalNode : public DistanceTraversalNodeBase +/// @} + +/// @addtogroup Traversal_For_Distance +/// @{ + +/// @brief Traversal node for octree distance +class OcTreeDistanceTraversalNode : public DistanceTraversalNodeBase { public: - OcTreeShapeDistanceTraversalNode() + OcTreeDistanceTraversalNode() { model1 = NULL; model2 = NULL; - + otsolver = NULL; } - FCL_REAL BVTesting(int, int) const + + FCL_REAL BVDistanceLowerBound(int, int) const { return -1; } - void leafTesting(int, int) const + bool BVDistanceLowerBound(int, int, FCL_REAL&) const { - otsolver->OcTreeShapeDistance(model1, *model2, tf1, tf2, request, *result); + return false; + } + + void leafComputeDistance(int, int) const + { + otsolver->OcTreeDistance(model1, model2, tf1, tf2, request, *result); } const OcTree* model1; - const S* model2; + const OcTree* model2; - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for mesh-octree collision -template<typename BV, typename NarrowPhaseSolver> -class MeshOcTreeCollisionTraversalNode : public CollisionTraversalNodeBase + + +/// @brief Traversal node for shape-octree distance +template<typename S> +class ShapeOcTreeDistanceTraversalNode : public DistanceTraversalNodeBase { public: - MeshOcTreeCollisionTraversalNode(const CollisionRequest& request) : - CollisionTraversalNodeBase (request) + ShapeOcTreeDistanceTraversalNode() { model1 = NULL; model2 = NULL; - + otsolver = NULL; } - bool BVTesting(int, int) const + FCL_REAL BVDistanceLowerBound(int, int) const { - return false; - } - - bool BVTesting(int, int, FCL_REAL&) const - { - return false; + return -1; } - void leafTesting(int, int, FCL_REAL&) const + void leafComputeDistance(int, int) const { - otsolver->OcTreeMeshIntersect(model2, model1, tf2, tf1, request, *result); + otsolver->OcTreeShapeDistance(model2, *model1, tf2, tf1, request, *result); } - const BVHModel<BV>* model1; + const S* model1; const OcTree* model2; - Transform3f tf1, tf2; - - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + const OcTreeSolver* otsolver; }; -/// @brief Traversal node for octree-mesh collision -template<typename BV, typename NarrowPhaseSolver> -class OcTreeMeshCollisionTraversalNode : public CollisionTraversalNodeBase +/// @brief Traversal node for octree-shape distance +template<typename S> +class OcTreeShapeDistanceTraversalNode : public DistanceTraversalNodeBase { public: - OcTreeMeshCollisionTraversalNode(const CollisionRequest& request) : - CollisionTraversalNodeBase (request) + OcTreeShapeDistanceTraversalNode() { model1 = NULL; model2 = NULL; - + otsolver = NULL; } - bool BVTesting(int, int) const + FCL_REAL BVDistanceLowerBound(int, int) const { - return false; - } - - bool BVTesting(int, int, FCL_REAL&) const - { - return false; + return -1; } - void leafTesting(int, int, FCL_REAL&) const + void leafComputeDistance(int, int) const { - otsolver->OcTreeMeshIntersect(model1, model2, tf1, tf2, request, *result); + otsolver->OcTreeShapeDistance(model1, *model2, tf1, tf2, request, *result); } const OcTree* model1; - const BVHModel<BV>* model2; + const S* model2; - Transform3f tf1, tf2; - - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + const OcTreeSolver* otsolver; }; /// @brief Traversal node for mesh-octree distance -template<typename BV, typename NarrowPhaseSolver> +template<typename BV> class MeshOcTreeDistanceTraversalNode : public DistanceTraversalNodeBase { public: @@ -1180,12 +1187,12 @@ public: otsolver = NULL; } - FCL_REAL BVTesting(int, int) const + FCL_REAL BVDistanceLowerBound(int, int) const { return -1; } - void leafTesting(int, int) const + void leafComputeDistance(int, int) const { otsolver->OcTreeMeshDistance(model2, model1, tf2, tf1, request, *result); } @@ -1193,12 +1200,12 @@ public: const BVHModel<BV>* model1; const OcTree* model2; - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + const OcTreeSolver* otsolver; }; /// @brief Traversal node for octree-mesh distance -template<typename BV, typename NarrowPhaseSolver> +template<typename BV> class OcTreeMeshDistanceTraversalNode : public DistanceTraversalNodeBase { public: @@ -1210,12 +1217,12 @@ public: otsolver = NULL; } - FCL_REAL BVTesting(int, int) const + FCL_REAL BVDistanceLowerBound(int, int) const { return -1; } - void leafTesting(int, int) const + void leafComputeDistance(int, int) const { otsolver->OcTreeMeshDistance(model1, model2, tf1, tf2, request, *result); } @@ -1223,14 +1230,16 @@ public: const OcTree* model1; const BVHModel<BV>* model2; - const OcTreeSolver<NarrowPhaseSolver>* otsolver; + const OcTreeSolver* otsolver; }; - +/// @} } } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/traversal/traversal_node_setup.h b/include/hpp/fcl/internal/traversal_node_setup.h similarity index 67% rename from include/hpp/fcl/traversal/traversal_node_setup.h rename to include/hpp/fcl/internal/traversal_node_setup.h index 041b3fa68731525070797d48661ee7cde48d35b5..7a5006d134177e29c8c9b762615d2285eff97186 100644 --- a/include/hpp/fcl/traversal/traversal_node_setup.h +++ b/include/hpp/fcl/internal/traversal_node_setup.h @@ -35,16 +35,17 @@ /** \author Jia Pan */ - #ifndef HPP_FCL_TRAVERSAL_NODE_SETUP_H #define HPP_FCL_TRAVERSAL_NODE_SETUP_H -#include <hpp/fcl/traversal/traversal_node_bvhs.h> -#include <hpp/fcl/traversal/traversal_node_shapes.h> -#include <hpp/fcl/traversal/traversal_node_bvh_shape.h> +/// @cond INTERNAL + +#include <hpp/fcl/internal/traversal_node_bvhs.h> +#include <hpp/fcl/internal/traversal_node_shapes.h> +#include <hpp/fcl/internal/traversal_node_bvh_shape.h> #ifdef HPP_FCL_HAVE_OCTOMAP -#include <hpp/fcl/traversal/traversal_node_octree.h> +#include <hpp/fcl/internal/traversal_node_octree.h> #endif #include <hpp/fcl/BVH/BVH_utility.h> @@ -56,12 +57,11 @@ namespace fcl #ifdef HPP_FCL_HAVE_OCTOMAP /// @brief Initialize traversal node for collision between two octrees, given current object transform -template<typename NarrowPhaseSolver> -bool initialize(OcTreeCollisionTraversalNode<NarrowPhaseSolver>& node, - const OcTree& model1, const Transform3f& tf1, - const OcTree& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, - CollisionResult& result) +inline bool initialize(OcTreeCollisionTraversalNode& node, + const OcTree& model1, const Transform3f& tf1, + const OcTree& model2, const Transform3f& tf2, + const OcTreeSolver* otsolver, + CollisionResult& result) { node.result = &result; @@ -77,13 +77,13 @@ bool initialize(OcTreeCollisionTraversalNode<NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance between two octrees, given current object transform -template<typename NarrowPhaseSolver> -bool initialize(OcTreeDistanceTraversalNode<NarrowPhaseSolver>& node, - const OcTree& model1, const Transform3f& tf1, - const OcTree& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, - const DistanceRequest& request, - DistanceResult& result) +inline bool initialize(OcTreeDistanceTraversalNode& node, + const OcTree& model1, const Transform3f& tf1, + const OcTree& model2, const Transform3f& tf2, + const OcTreeSolver* otsolver, + const DistanceRequest& request, + DistanceResult& result) + { node.request = request; node.result = &result; @@ -100,11 +100,11 @@ bool initialize(OcTreeDistanceTraversalNode<NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for collision between one shape and one octree, given current object transform -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeOcTreeCollisionTraversalNode<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(ShapeOcTreeCollisionTraversalNode<S>& node, const S& model1, const Transform3f& tf1, const OcTree& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, CollisionResult& result) { node.result = &result; @@ -121,11 +121,11 @@ bool initialize(ShapeOcTreeCollisionTraversalNode<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for collision between one octree and one shape, given current object transform -template<typename S, typename NarrowPhaseSolver> -bool initialize(OcTreeShapeCollisionTraversalNode<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(OcTreeShapeCollisionTraversalNode<S>& node, const OcTree& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, CollisionResult& result) { node.result = &result; @@ -142,11 +142,11 @@ bool initialize(OcTreeShapeCollisionTraversalNode<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance between one shape and one octree, given current object transform -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeOcTreeDistanceTraversalNode<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(ShapeOcTreeDistanceTraversalNode<S>& node, const S& model1, const Transform3f& tf1, const OcTree& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, const DistanceRequest& request, DistanceResult& result) { @@ -165,11 +165,11 @@ bool initialize(ShapeOcTreeDistanceTraversalNode<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance between one octree and one shape, given current object transform -template<typename S, typename NarrowPhaseSolver> -bool initialize(OcTreeShapeDistanceTraversalNode<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(OcTreeShapeDistanceTraversalNode<S>& node, const OcTree& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, const DistanceRequest& request, DistanceResult& result) { @@ -188,11 +188,11 @@ bool initialize(OcTreeShapeDistanceTraversalNode<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for collision between one mesh and one octree, given current object transform -template<typename BV, typename NarrowPhaseSolver> -bool initialize(MeshOcTreeCollisionTraversalNode<BV, NarrowPhaseSolver>& node, +template<typename BV> +bool initialize(MeshOcTreeCollisionTraversalNode<BV>& node, const BVHModel<BV>& model1, const Transform3f& tf1, const OcTree& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, CollisionResult& result) { node.result = &result; @@ -209,11 +209,11 @@ bool initialize(MeshOcTreeCollisionTraversalNode<BV, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for collision between one octree and one mesh, given current object transform -template<typename BV, typename NarrowPhaseSolver> -bool initialize(OcTreeMeshCollisionTraversalNode<BV, NarrowPhaseSolver>& node, +template<typename BV> +bool initialize(OcTreeMeshCollisionTraversalNode<BV>& node, const OcTree& model1, const Transform3f& tf1, const BVHModel<BV>& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, CollisionResult& result) { node.result = &result; @@ -230,11 +230,11 @@ bool initialize(OcTreeMeshCollisionTraversalNode<BV, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance between one mesh and one octree, given current object transform -template<typename BV, typename NarrowPhaseSolver> -bool initialize(MeshOcTreeDistanceTraversalNode<BV, NarrowPhaseSolver>& node, +template<typename BV> +bool initialize(MeshOcTreeDistanceTraversalNode<BV>& node, const BVHModel<BV>& model1, const Transform3f& tf1, const OcTree& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, const DistanceRequest& request, DistanceResult& result) { @@ -253,11 +253,11 @@ bool initialize(MeshOcTreeDistanceTraversalNode<BV, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for collision between one octree and one mesh, given current object transform -template<typename BV, typename NarrowPhaseSolver> -bool initialize(OcTreeMeshDistanceTraversalNode<BV, NarrowPhaseSolver>& node, +template<typename BV> +bool initialize(OcTreeMeshDistanceTraversalNode<BV>& node, const OcTree& model1, const Transform3f& tf1, const BVHModel<BV>& model2, const Transform3f& tf2, - const OcTreeSolver<NarrowPhaseSolver>* otsolver, + const OcTreeSolver* otsolver, const DistanceRequest& request, DistanceResult& result) { @@ -279,11 +279,11 @@ bool initialize(OcTreeMeshDistanceTraversalNode<BV, NarrowPhaseSolver>& node, /// @brief Initialize traversal node for collision between two geometric shapes, given current object transform -template<typename S1, typename S2, typename NarrowPhaseSolver> -bool initialize(ShapeCollisionTraversalNode<S1, S2, NarrowPhaseSolver>& node, +template<typename S1, typename S2> +bool initialize(ShapeCollisionTraversalNode<S1, S2>& node, const S1& shape1, const Transform3f& tf1, const S2& shape2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { node.model1 = &shape1; @@ -298,11 +298,11 @@ bool initialize(ShapeCollisionTraversalNode<S1, S2, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for collision between one mesh and one shape, given current object transform -template<typename BV, typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeCollisionTraversalNode<BV, S, NarrowPhaseSolver>& node, +template<typename BV, typename S> +bool initialize(MeshShapeCollisionTraversalNode<BV, S>& node, BVHModel<BV>& model1, Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result, bool use_refit = false, bool refit_bottomup = false) { @@ -342,61 +342,15 @@ bool initialize(MeshShapeCollisionTraversalNode<BV, S, NarrowPhaseSolver>& node, return true; } - -/// @brief Initialize traversal node for collision between one mesh and one shape, given current object transform -template<typename S, typename BV, typename NarrowPhaseSolver> -bool initialize(ShapeMeshCollisionTraversalNode<S, BV, NarrowPhaseSolver>& node, - const S& model1, const Transform3f& tf1, - BVHModel<BV>& model2, Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - CollisionResult& result, - bool use_refit = false, bool refit_bottomup = false) -{ - if(model2.getModelType() != BVH_MODEL_TRIANGLES) - return false; - - if(!tf2.isIdentity()) - { - std::vector<Vec3f> vertices_transformed(model2.num_vertices); - for(int i = 0; i < model2.num_vertices; ++i) - { - Vec3f& p = model2.vertices[i]; - Vec3f new_v = tf2.transform(p); - vertices_transformed[i] = new_v; - } - - model2.beginReplaceModel(); - model2.replaceSubModel(vertices_transformed); - model2.endReplaceModel(use_refit, refit_bottomup); - - tf2.setIdentity(); - } - - node.model1 = &model1; - node.tf1 = tf1; - node.model2 = &model2; - node.tf2 = tf2; - node.nsolver = nsolver; - - computeBV(model1, tf1, node.model1_bv); - - node.vertices = model2.vertices; - node.tri_indices = model2.tri_indices; - - node.result = &result; - - return true; -} - /// @cond IGNORE namespace details { -template<typename BV, typename S, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode> -static inline bool setupMeshShapeCollisionOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, +template<typename BV, typename S, template<typename> class OrientedNode> +static inline bool setupMeshShapeCollisionOrientedNode(OrientedNode<S>& node, const BVHModel<BV>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { if(model1.getModelType() != BVH_MODEL_TRIANGLES) @@ -424,44 +378,44 @@ static inline bool setupMeshShapeCollisionOrientedNode(OrientedNode<S, NarrowPha /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBB type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeCollisionTraversalNodeOBB<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeCollisionTraversalNodeOBB<S>& node, const BVHModel<OBB>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); } /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for RSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeCollisionTraversalNodeRSS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeCollisionTraversalNodeRSS<S>& node, const BVHModel<RSS>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); } /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for kIOS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeCollisionTraversalNodekIOS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeCollisionTraversalNodekIOS<S>& node, const BVHModel<kIOS>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); } /// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBBRSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeCollisionTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeCollisionTraversalNodeOBBRSS<S>& node, const BVHModel<OBBRSS>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { return details::setupMeshShapeCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); @@ -471,11 +425,11 @@ bool initialize(MeshShapeCollisionTraversalNodeOBBRSS<S, NarrowPhaseSolver>& nod /// @cond IGNORE namespace details { -template<typename S, typename BV, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode> -static inline bool setupShapeMeshCollisionOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, +template<typename S, typename BV, template<typename> class OrientedNode> +static inline bool setupShapeMeshCollisionOrientedNode(OrientedNode<S>& node, const S& model1, const Transform3f& tf1, const BVHModel<BV>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, CollisionResult& result) { if(model2.getModelType() != BVH_MODEL_TRIANGLES) @@ -499,56 +453,10 @@ static inline bool setupShapeMeshCollisionOrientedNode(OrientedNode<S, NarrowPha } /// @endcond -/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBB type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshCollisionTraversalNodeOBB<S, NarrowPhaseSolver>& node, - const S& model1, const Transform3f& tf1, - const BVHModel<OBB>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - CollisionResult& result) -{ - return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); -} - -/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for RSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshCollisionTraversalNodeRSS<S, NarrowPhaseSolver>& node, - const S& model1, const Transform3f& tf1, - const BVHModel<RSS>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - CollisionResult& result) -{ - return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); -} - -/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for kIOS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshCollisionTraversalNodekIOS<S, NarrowPhaseSolver>& node, - const S& model1, const Transform3f& tf1, - const BVHModel<kIOS>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - CollisionResult& result) -{ - return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); -} - -/// @brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBBRSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshCollisionTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node, - const S& model1, const Transform3f& tf1, - const BVHModel<OBBRSS>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - CollisionResult& result) -{ - return details::setupShapeMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, nsolver, result); -} - - - /// @brief Initialize traversal node for collision between two meshes, given the current transforms template<typename BV> -bool initialize(MeshCollisionTraversalNode<BV>& node, +bool initialize(MeshCollisionTraversalNode<BV, RelativeTransformationIsIdentity>& node, BVHModel<BV>& model1, Transform3f& tf1, BVHModel<BV>& model2, Transform3f& tf2, CollisionResult& result, @@ -607,38 +515,40 @@ bool initialize(MeshCollisionTraversalNode<BV>& node, return true; } +template<typename BV> +bool initialize(MeshCollisionTraversalNode<BV, 0>& node, + const BVHModel<BV>& model1, const Transform3f& tf1, + const BVHModel<BV>& model2, const Transform3f& tf2, + CollisionResult& result) +{ + if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES) + return false; -/// @brief Initialize traversal node for collision between two meshes, specialized for OBB type -bool initialize(MeshCollisionTraversalNodeOBB& node, - const BVHModel<OBB>& model1, const Transform3f& tf1, - const BVHModel<OBB>& model2, const Transform3f& tf2, - CollisionResult& result); + node.vertices1 = model1.vertices; + node.vertices2 = model2.vertices; -/// @brief Initialize traversal node for collision between two meshes, specialized for RSS type -bool initialize(MeshCollisionTraversalNodeRSS& node, - const BVHModel<RSS>& model1, const Transform3f& tf1, - const BVHModel<RSS>& model2, const Transform3f& tf2, - CollisionResult& result); + node.tri_indices1 = model1.tri_indices; + node.tri_indices2 = model2.tri_indices; -/// @brief Initialize traversal node for collision between two meshes, specialized for OBBRSS type -bool initialize(MeshCollisionTraversalNodeOBBRSS& node, - const BVHModel<OBBRSS>& model1, const Transform3f& tf1, - const BVHModel<OBBRSS>& model2, const Transform3f& tf2, - CollisionResult& result); + node.model1 = &model1; + node.tf1 = tf1; + node.model2 = &model2; + node.tf2 = tf2; -/// @brief Initialize traversal node for collision between two meshes, specialized for kIOS type -bool initialize(MeshCollisionTraversalNodekIOS& node, - const BVHModel<kIOS>& model1, const Transform3f& tf1, - const BVHModel<kIOS>& model2, const Transform3f& tf2, - CollisionResult& result); + node.result = &result; + node.RT.R = tf1.getRotation().transpose() * tf2.getRotation(); + node.RT.T = tf1.getRotation().transpose() * (tf2.getTranslation() - tf1.getTranslation()); + + return true; +} /// @brief Initialize traversal node for distance between two geometric shapes -template<typename S1, typename S2, typename NarrowPhaseSolver> -bool initialize(ShapeDistanceTraversalNode<S1, S2, NarrowPhaseSolver>& node, +template<typename S1, typename S2> +bool initialize(ShapeDistanceTraversalNode<S1, S2>& node, const S1& shape1, const Transform3f& tf1, const S2& shape2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -740,11 +650,11 @@ bool initialize(MeshDistanceTraversalNodeOBBRSS& node, DistanceResult& result); /// @brief Initialize traversal node for distance computation between one mesh and one shape, given the current transforms -template<typename BV, typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeDistanceTraversalNode<BV, S, NarrowPhaseSolver>& node, +template<typename BV, typename S> +bool initialize(MeshShapeDistanceTraversalNode<BV, S>& node, BVHModel<BV>& model1, Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result, bool use_refit = false, bool refit_bottomup = false) @@ -787,11 +697,11 @@ bool initialize(MeshShapeDistanceTraversalNode<BV, S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance computation between one shape and one mesh, given the current transforms -template<typename S, typename BV, typename NarrowPhaseSolver> -bool initialize(ShapeMeshDistanceTraversalNode<S, BV, NarrowPhaseSolver>& node, +template<typename S, typename BV> +bool initialize(ShapeMeshDistanceTraversalNode<S, BV>& node, const S& model1, const Transform3f& tf1, BVHModel<BV>& model2, Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result, bool use_refit = false, bool refit_bottomup = false) @@ -837,11 +747,11 @@ bool initialize(ShapeMeshDistanceTraversalNode<S, BV, NarrowPhaseSolver>& node, namespace details { -template<typename BV, typename S, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode> -static inline bool setupMeshShapeDistanceOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, +template<typename BV, typename S, template<typename> class OrientedNode> +static inline bool setupMeshShapeDistanceOrientedNode(OrientedNode<S>& node, const BVHModel<BV>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -868,11 +778,11 @@ static inline bool setupMeshShapeDistanceOrientedNode(OrientedNode<S, NarrowPhas /// @endcond /// @brief Initialize traversal node for distance computation between one mesh and one shape, specialized for RSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeDistanceTraversalNodeRSS<S>& node, const BVHModel<RSS>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -880,11 +790,11 @@ bool initialize(MeshShapeDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance computation between one mesh and one shape, specialized for kIOS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeDistanceTraversalNodekIOS<S>& node, const BVHModel<kIOS>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -892,11 +802,11 @@ bool initialize(MeshShapeDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance computation between one mesh and one shape, specialized for OBBRSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(MeshShapeDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(MeshShapeDistanceTraversalNodeOBBRSS<S>& node, const BVHModel<OBBRSS>& model1, const Transform3f& tf1, const S& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -906,11 +816,11 @@ bool initialize(MeshShapeDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node namespace details { -template<typename S, typename BV, typename NarrowPhaseSolver, template<typename, typename> class OrientedNode> -static inline bool setupShapeMeshDistanceOrientedNode(OrientedNode<S, NarrowPhaseSolver>& node, +template<typename S, typename BV, template<typename> class OrientedNode> +static inline bool setupShapeMeshDistanceOrientedNode(OrientedNode<S>& node, const S& model1, const Transform3f& tf1, const BVHModel<BV>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -939,11 +849,11 @@ static inline bool setupShapeMeshDistanceOrientedNode(OrientedNode<S, NarrowPhas /// @brief Initialize traversal node for distance computation between one shape and one mesh, specialized for RSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(ShapeMeshDistanceTraversalNodeRSS<S>& node, const S& model1, const Transform3f& tf1, const BVHModel<RSS>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -951,11 +861,11 @@ bool initialize(ShapeMeshDistanceTraversalNodeRSS<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance computation between one shape and one mesh, specialized for kIOS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(ShapeMeshDistanceTraversalNodekIOS<S>& node, const S& model1, const Transform3f& tf1, const BVHModel<kIOS>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -963,11 +873,11 @@ bool initialize(ShapeMeshDistanceTraversalNodekIOS<S, NarrowPhaseSolver>& node, } /// @brief Initialize traversal node for distance computation between one shape and one mesh, specialized for OBBRSS type -template<typename S, typename NarrowPhaseSolver> -bool initialize(ShapeMeshDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node, +template<typename S> +bool initialize(ShapeMeshDistanceTraversalNodeOBBRSS<S>& node, const S& model1, const Transform3f& tf1, const BVHModel<OBBRSS>& model2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { @@ -978,4 +888,6 @@ bool initialize(ShapeMeshDistanceTraversalNodeOBBRSS<S, NarrowPhaseSolver>& node } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/traversal/traversal_node_shapes.h b/include/hpp/fcl/internal/traversal_node_shapes.h similarity index 89% rename from include/hpp/fcl/traversal/traversal_node_shapes.h rename to include/hpp/fcl/internal/traversal_node_shapes.h index 5180e9dcb43fe097e3be7730be259ee6e2feea8a..eff6de320de79356b5ffd09954a8525741f6e5a0 100644 --- a/include/hpp/fcl/traversal/traversal_node_shapes.h +++ b/include/hpp/fcl/internal/traversal_node_shapes.h @@ -35,25 +35,27 @@ /** \author Jia Pan */ - #ifndef HPP_FCL_TRAVERSAL_NODE_SHAPES_H #define HPP_FCL_TRAVERSAL_NODE_SHAPES_H +/// @cond INTERNAL + #include <hpp/fcl/collision_data.h> -#include <hpp/fcl/traversal/traversal_node_base.h> #include <hpp/fcl/narrowphase/narrowphase.h> -#include <hpp/fcl/shape/geometric_shapes_utility.h> #include <hpp/fcl/BV/BV.h> #include <hpp/fcl/shape/geometric_shapes_utility.h> +#include <hpp/fcl/internal/traversal_node_base.h> namespace hpp { namespace fcl { +/// @addtogroup Traversal_For_Collision +/// @{ /// @brief Traversal node for collision between two shapes -template<typename S1, typename S2, typename NarrowPhaseSolver> +template<typename S1, typename S2> class ShapeCollisionTraversalNode : public CollisionTraversalNodeBase { public: @@ -67,19 +69,19 @@ public: } /// @brief BV culling test in one BVTT node - bool BVTesting(int, int) const + bool BVDisjoints(int, int) const { return false; } /// @brief BV culling test in one BVTT node - bool BVTesting(int, int, FCL_REAL&) const + bool BVDisjoints(int, int, FCL_REAL&) const { throw std::runtime_error ("Not implemented"); } /// @brief Intersection testing between leaves (two shapes) - void leafTesting(int, int, FCL_REAL&) const + void leafCollides(int, int, FCL_REAL&) const { bool is_collision = false; if(request.enable_contact) @@ -111,11 +113,16 @@ public: const S1* model1; const S2* model2; - const NarrowPhaseSolver* nsolver; + const GJKSolver* nsolver; }; +/// @} + +/// @addtogroup Traversal_For_Distance +/// @{ + /// @brief Traversal node for distance between two shapes -template<typename S1, typename S2, typename NarrowPhaseSolver> +template<typename S1, typename S2> class ShapeDistanceTraversalNode : public DistanceTraversalNodeBase { public: @@ -128,13 +135,13 @@ public: } /// @brief BV culling test in one BVTT node - FCL_REAL BVTesting(int, int) const + FCL_REAL BVDistanceLowerBound(int, int) const { return -1; // should not be used } /// @brief Distance testing between leaves (two shapes) - void leafTesting(int, int) const + void leafComputeDistance(int, int) const { FCL_REAL distance; Vec3f closest_p1, closest_p2, normal; @@ -147,10 +154,15 @@ public: const S1* model1; const S2* model2; - const NarrowPhaseSolver* nsolver; + const GJKSolver* nsolver; }; + +/// @} + } } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/traversal/traversal_recurse.h b/include/hpp/fcl/internal/traversal_recurse.h similarity index 80% rename from include/hpp/fcl/traversal/traversal_recurse.h rename to include/hpp/fcl/internal/traversal_recurse.h index f50bd75e2bbb05a5b214f6edefd50e614556d8ea..f5dbe283222f49c0025bf6c1f30a990641b1ff6b 100644 --- a/include/hpp/fcl/traversal/traversal_recurse.h +++ b/include/hpp/fcl/internal/traversal_recurse.h @@ -35,14 +35,15 @@ /** \author Jia Pan */ - #ifndef HPP_FCL_TRAVERSAL_RECURSE_H #define HPP_FCL_TRAVERSAL_RECURSE_H -#include <hpp/fcl/traversal/traversal_node_base.h> -#include <hpp/fcl/traversal/traversal_node_bvhs.h> +/// @cond INTERNAL + #include <hpp/fcl/BVH/BVH_front.h> #include <queue> +#include <hpp/fcl/internal/traversal_node_base.h> +#include <hpp/fcl/internal/traversal_node_bvhs.h> namespace hpp { @@ -50,17 +51,14 @@ namespace fcl { /// Recurse function for collision -/// \param node collision node, -/// \param b1, b2 ids of bounding volume nodes for object 1 and object 2 -/// \retval sqrDistLowerBound squared lower bound on distance between objects. +/// @param node collision node, +/// @param b1, b2 ids of bounding volume nodes for object 1 and object 2 +/// @retval sqrDistLowerBound squared lower bound on distance between objects. void collisionRecurse(CollisionTraversalNodeBase* node, int b1, int b2, BVHFrontList* front_list, FCL_REAL& sqrDistLowerBound); -/// @brief Recurse function for collision, specialized for OBB type -void collisionRecurse(MeshCollisionTraversalNodeOBB* node, int b1, int b2, const Matrix3f& R, const Vec3f& T, BVHFrontList* front_list); - -/// @brief Recurse function for collision, specialized for RSS type -void collisionRecurse(MeshCollisionTraversalNodeRSS* node, int b1, int b2, const Matrix3f& R, const Vec3f& T, BVHFrontList* front_list); +void collisionNonRecurse(CollisionTraversalNodeBase* node, + BVHFrontList* front_list, FCL_REAL& sqrDistLowerBound); /// @brief Recurse function for distance void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontList* front_list); @@ -73,9 +71,10 @@ void propagateBVHFrontListCollisionRecurse (CollisionTraversalNodeBase* node, const CollisionRequest& request, CollisionResult& result, BVHFrontList* front_list); - } } // namespace hpp +/// @endcond + #endif diff --git a/include/hpp/fcl/math/matrix_3f.h b/include/hpp/fcl/math/matrix_3f.h index 122f329109d49150a81edda376ca3144ee9ebccd..3c60bb44b1f3c6c4f2b080be1791ba0eb59b03ed 100644 --- a/include/hpp/fcl/math/matrix_3f.h +++ b/include/hpp/fcl/math/matrix_3f.h @@ -38,70 +38,9 @@ #ifndef HPP_FCL_MATRIX_3F_H #define HPP_FCL_MATRIX_3F_H -#include <hpp/fcl/math/vec_3f.h> +# warning "This file is deprecated. Include <hpp/fcl/math/types.h> instead." -namespace hpp -{ -namespace fcl -{ +// List of equivalent includes. +# include <hpp/fcl/math/types.h> - typedef Eigen::Matrix<FCL_REAL, 3, 3> Matrix3f; - -/// @brief Class for variance matrix in 3d -class Variance3f -{ -public: - /// @brief Variation matrix - Matrix3f Sigma; - - /// @brief Variations along the eign axes - Matrix3f::Scalar sigma[3]; - - /// @brief Eigen axes of the variation matrix - Vec3f axis[3]; - - Variance3f() {} - - Variance3f(const Matrix3f& S) : Sigma(S) - { - init(); - } - - /// @brief init the Variance - void init() - { - eigen(Sigma, sigma, axis); - } - - /// @brief Compute the sqrt of Sigma matrix based on the eigen decomposition result, this is useful when the uncertainty matrix is initialized as a square variation matrix - Variance3f& sqrt() - { - for(std::size_t i = 0; i < 3; ++i) - { - if(sigma[i] < 0) sigma[i] = 0; - sigma[i] = std::sqrt(sigma[i]); - } - - - Sigma.setZero(); - for(std::size_t i = 0; i < 3; ++i) - { - for(std::size_t j = 0; j < 3; ++j) - { - Sigma(i, j) += sigma[0] * axis[0][i] * axis[0][j]; - Sigma(i, j) += sigma[1] * axis[1][i] * axis[1][j]; - Sigma(i, j) += sigma[2] * axis[2][i] * axis[2][j]; - } - } - - return *this; - } -}; - -} - - - -} // namespace hpp - -#endif +#endif \ No newline at end of file diff --git a/include/hpp/fcl/math/transform.h b/include/hpp/fcl/math/transform.h index 69c12043c6795bedf2c110374bf43a99afc3fa30..dd6e9f4cbaeb197d17742d7bfef4adc520b712e7 100644 --- a/include/hpp/fcl/math/transform.h +++ b/include/hpp/fcl/math/transform.h @@ -39,7 +39,7 @@ #ifndef HPP_FCL_TRANSFORM_H #define HPP_FCL_TRANSFORM_H -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> #include <boost/thread/mutex.hpp> namespace hpp @@ -48,6 +48,7 @@ namespace fcl { typedef Eigen::Quaternion<FCL_REAL> Quaternion3f; + static inline std::ostream& operator << (std::ostream& o, const Quaternion3f& q) { o << "(" << q.w() << " " << q.x() << " " << q.y() << " " << q.z() << ")"; @@ -68,18 +69,11 @@ inline bool areQuatEquals (const Quaternion3f& q1, const Quaternion3f& q2) /// @brief Simple transform class used locally by InterpMotion class Transform3f { - /// @brief Whether matrix cache is set - mutable bool matrix_set; /// @brief Matrix cache - mutable Matrix3f R; + Matrix3f R; /// @brief Tranlation vector Vec3f T; - - /// @brief Rotation - Quaternion3f q; - - const Matrix3f& getRotationInternal() const; public: /// @brief Default transform is no movement @@ -89,57 +83,40 @@ public: } /// @brief Construct transform from rotation and translation - Transform3f(const Matrix3f& R_, const Vec3f& T_) : matrix_set(true), - R(R_), - T(T_) - { - q = Quaternion3f(R_); - } + template <typename Matrixx3Like, typename Vector3Like> + Transform3f(const Eigen::MatrixBase<Matrixx3Like>& R_, + const Eigen::MatrixBase<Vector3Like>& T_) : + R(R_), + T(T_) + {} /// @brief Construct transform from rotation and translation - Transform3f(const Quaternion3f& q_, const Vec3f& T_) : matrix_set(false), - T(T_), - q(q_) - { - } + template <typename Vector3Like> + Transform3f(const Quaternion3f& q_, + const Eigen::MatrixBase<Vector3Like>& T_) : + R(q_.toRotationMatrix()), + T(T_) + {} /// @brief Construct transform from rotation - Transform3f(const Matrix3f& R_) : matrix_set(true), - R(R_), + Transform3f(const Matrix3f& R_) : R(R_), T(Vec3f::Zero()) - { - q = Quaternion3f(R_); - } + {} /// @brief Construct transform from rotation - Transform3f(const Quaternion3f& q_) : matrix_set(false), - T(Vec3f::Zero()), - q(q_) - { - } + Transform3f(const Quaternion3f& q_) : R(q_), + T(Vec3f::Zero()) + {} /// @brief Construct transform from translation - Transform3f(const Vec3f& T_) : matrix_set(true), - T(T_), - q(Quaternion3f::Identity()) - { - R.setIdentity(); - } - - /// @brief Construct transform from another transform - Transform3f(const Transform3f& tf) : matrix_set(tf.matrix_set), - R(tf.R), - T(tf.T), - q(tf.q) - { - } + Transform3f(const Vec3f& T_) : R(Matrix3f::Identity()), + T(T_) + {} /// @brief operator = Transform3f& operator = (const Transform3f& tf) { - matrix_set = tf.matrix_set; R = tf.R; - q = tf.q; T = tf.T; return *this; } @@ -153,31 +130,28 @@ public: /// @brief get rotation inline const Matrix3f& getRotation() const { - if(matrix_set) return R; - return getRotationInternal(); + return R; } /// @brief get quaternion - inline const Quaternion3f& getQuatRotation() const + inline Quaternion3f getQuatRotation() const { - return q; + return Quaternion3f (R); } /// @brief set transform from rotation and translation - inline void setTransform(const Matrix3f& R_, const Vec3f& T_) + template <typename Matrixx3Like, typename Vector3Like> + inline void setTransform(const Eigen::MatrixBase<Matrixx3Like>& R_, const Eigen::MatrixBase<Vector3Like>& T_) { R.noalias() = R_; T.noalias() = T_; - q = Quaternion3f(R_); - matrix_set = true; } /// @brief set transform from rotation and translation inline void setTransform(const Quaternion3f& q_, const Vec3f& T_) { - matrix_set = false; - q = q_; - T.noalias() = T_; + R = q_.toRotationMatrix(); + T = T_; } /// @brief set transform from rotation @@ -185,8 +159,6 @@ public: inline void setRotation(const Eigen::MatrixBase<Derived>& R_) { R.noalias() = R_; - matrix_set = true; - q = Quaternion3f(R); } /// @brief set transform from translation @@ -199,53 +171,54 @@ public: /// @brief set transform from rotation inline void setQuatRotation(const Quaternion3f& q_) { - matrix_set = false; - q = q_; + R = q_.toRotationMatrix(); } /// @brief transform a given vector by the transform template <typename Derived> inline Vec3f transform(const Eigen::MatrixBase<Derived>& v) const { - return q * v + T; + return R * v + T; } /// @brief inverse transform - inline Transform3f& inverse() + inline Transform3f& inverseInPlace() { - matrix_set = false; - q = q.conjugate(); - T = q * (-T); + R.transposeInPlace(); + T = - R * T; return *this; } + /// @brief inverse transform + inline Transform3f inverse() + { + return Transform3f (R.transpose(), - R.transpose() * T); + } + /// @brief inverse the transform and multiply with another inline Transform3f inverseTimes(const Transform3f& other) const { - const Quaternion3f& q_inv = q.conjugate(); - return Transform3f(q_inv * other.q, q_inv * (other.T - T)); + return Transform3f(R.transpose() * other.R, R.transpose() * (other.T - T)); } /// @brief multiply with another transform inline const Transform3f& operator *= (const Transform3f& other) { - matrix_set = false; - T += q * other.T; - q *= other.q; + T += R * other.T; + R *= other.R; return *this; } /// @brief multiply with another transform inline Transform3f operator * (const Transform3f& other) const { - Quaternion3f q_new = q * other.q; - return Transform3f(q_new, q * other.T + T); + return Transform3f(R * other.R, R * other.T + T); } /// @brief check whether the transform is identity inline bool isIdentity() const { - return isQuatIdentity(q) && T.isZero(); + return R.isIdentity() && T.isZero(); } /// @brief set the transform to be identity transform @@ -253,36 +226,26 @@ public: { R.setIdentity(); T.setZero(); - q.setIdentity(); - matrix_set = true; } bool operator == (const Transform3f& other) const { - return areQuatEquals(q, other.getQuatRotation()) && (T == other.getTranslation()); + return R == other.R && (T == other.getTranslation()); } bool operator != (const Transform3f& other) const { return !(*this == other); } - }; -/// @brief inverse the transform -Transform3f inverse(const Transform3f& tf); - -/// @brief compute the relative transform between two transforms: tf2 = tf1 * tf (relative to the local coordinate system in tf1) -void relativeTransform(const Transform3f& tf1, const Transform3f& tf2, - Transform3f& tf); - -/// @brief compute the relative transform between two transforms: tf2 = tf * tf1 (relative to the global coordinate system) -void relativeTransform2(const Transform3f& tf1, const Transform3f& tf2, - Transform3f& tf); - - +template<typename Derived> +inline Quaternion3f fromAxisAngle(const Eigen::MatrixBase<Derived>& axis, FCL_REAL angle) +{ + return Quaternion3f (Eigen::AngleAxis<double>(angle, axis)); } +} } // namespace hpp #endif diff --git a/include/hpp/fcl/math/types.h b/include/hpp/fcl/math/types.h new file mode 100644 index 0000000000000000000000000000000000000000..ec431e7a92b59d788dc4582b7b84d25e3815696f --- /dev/null +++ b/include/hpp/fcl/math/types.h @@ -0,0 +1,46 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011-2014, Willow Garage, Inc. + * Copyright (c) 2014-2015, Open Source Robotics Foundation + * 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 Open Source Robotics Foundation 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 Joseph Mirabel */ + +#ifndef HPP_FCL_MATH_TYPES_H +#define HPP_FCL_MATH_TYPES_H + +# warning "This file is deprecated. Include <hpp/fcl/data_types.h> instead." + +// List of equivalent includes. +# include <hpp/fcl/data_types.h> + +#endif \ No newline at end of file diff --git a/include/hpp/fcl/math/vec_3f.h b/include/hpp/fcl/math/vec_3f.h index b7fcef9db0947c75d0324e7fc3a0ab846ded248c..9d41c14f8fa9a8daaf0cf97bd7d90da811d4fe9a 100644 --- a/include/hpp/fcl/math/vec_3f.h +++ b/include/hpp/fcl/math/vec_3f.h @@ -38,37 +38,9 @@ #ifndef HPP_FCL_VEC_3F_H #define HPP_FCL_VEC_3F_H -#include <hpp/fcl/data_types.h> +# warning "This file is deprecated. Include <hpp/fcl/math/types.h> instead." -#include <Eigen/Core> -#include <Eigen/Geometry> -#include <hpp/fcl/math/tools.h> +// List of equivalent includes. +# include <hpp/fcl/math/types.h> -#include <cmath> -#include <iostream> -#include <limits> - - -namespace hpp -{ -namespace fcl -{ - typedef Eigen::Matrix<FCL_REAL, 3, 1> Vec3f; -} - - -#ifdef HPP_FCL_HAVE_OCTOMAP - #define OCTOMAP_VERSION_AT_LEAST(x,y,z) \ - (OCTOMAP_MAJOR_VERSION > x || (OCTOMAP_MAJOR_VERSION >= x && \ - (OCTOMAP_MINOR_VERSION > y || (OCTOMAP_MINOR_VERSION >= y && \ - OCTOMAP_PATCH_VERSION >= z)))) - - #define OCTOMAP_VERSION_AT_MOST(x,y,z) \ - (OCTOMAP_MAJOR_VERSION < x || (OCTOMAP_MAJOR_VERSION <= x && \ - (OCTOMAP_MINOR_VERSION < y || (OCTOMAP_MINOR_VERSION <= y && \ - OCTOMAP_PATCH_VERSION <= z)))) -#endif // HPP_FCL_HAVE_OCTOMAP - -} // namespace hpp - -#endif +#endif \ No newline at end of file diff --git a/include/hpp/fcl/mesh_loader/assimp.h b/include/hpp/fcl/mesh_loader/assimp.h index b5c6ab0c7aa41b08bcbbb1a4cd65ecc9a77ef6b1..68748291dd9c9ce494040948dafc23d12e394bef 100644 --- a/include/hpp/fcl/mesh_loader/assimp.h +++ b/include/hpp/fcl/mesh_loader/assimp.h @@ -38,38 +38,21 @@ #ifndef HPP_FCL_MESH_LOADER_ASSIMP_H #define HPP_FCL_MESH_LOADER_ASSIMP_H -// Assimp >= 5.0 is forcing the use of C++11 keywords. A fix has been submitted https://github.com/assimp/assimp/pull/2758. -// The next lines fixes the bug for current version of hpp-fcl. -#include <assimp/defs.h> -#if __cplusplus < 201103L && defined(AI_NO_EXCEPT) - #undef AI_NO_EXCEPT - #define AI_NO_EXCEPT -#endif - -#ifdef HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES - #include <assimp/DefaultLogger.hpp> - #include <assimp/IOStream.hpp> - #include <assimp/IOSystem.hpp> - #include <assimp/scene.h> - #include <assimp/Importer.hpp> - #include <assimp/postprocess.h> -#else - #include <assimp/DefaultLogger.h> - #include <assimp/assimp.hpp> - #include <assimp/IOStream.h> - #include <assimp/IOSystem.h> - #include <assimp/aiScene.h> - #include <assimp/aiPostProcess.h> -#endif - #include <hpp/fcl/BV/OBBRSS.h> #include <hpp/fcl/BVH/BVH_model.h> +class aiScene; +namespace Assimp { + class Importer; +} + namespace hpp { namespace fcl { - + +namespace internal +{ struct TriangleAndVertices { @@ -77,6 +60,16 @@ struct TriangleAndVertices std::vector <fcl::Triangle> triangles_; }; +struct Loader { + Loader (); + ~Loader (); + + void load (const std::string& resource_path); + + Assimp::Importer* importer; + aiScene const* scene; +}; + /** * @brief Recursive procedure for building a mesh * @@ -86,31 +79,26 @@ struct TriangleAndVertices * @param[in] vertices_offset Current number of vertices in the model * @param tv Triangles and Vertices of the mesh submodels */ -unsigned buildMesh (const fcl::Vec3f & scale, - const aiScene* scene, - const aiNode* node, - unsigned vertices_offset, - TriangleAndVertices & tv); +void buildMesh (const fcl::Vec3f & scale, + const aiScene* scene, + unsigned vertices_offset, + TriangleAndVertices & tv); /** * @brief Convert an assimp scene to a mesh * - * @param[in] name File (ressource) transformed into an assimp scene in loa * @param[in] scale Scale to apply when reading the ressource * @param[in] scene Pointer to the assimp scene * @param[out] mesh The mesh that must be built */ template<class BoundingVolume> -inline void meshFromAssimpScene(const std::string & name, +inline void meshFromAssimpScene( const fcl::Vec3f & scale, const aiScene* scene, const boost::shared_ptr < BVHModel<BoundingVolume> > & mesh) { TriangleAndVertices tv; - if (!scene->HasMeshes()) - throw std::invalid_argument (std::string ("No meshes found in file ")+name); - int res = mesh->beginModel (); if (res != fcl::BVH_OK) @@ -120,13 +108,14 @@ inline void meshFromAssimpScene(const std::string & name, throw std::runtime_error (error.str ()); } - buildMesh (scale, scene, scene->mRootNode, - (unsigned) mesh->num_vertices, tv); + buildMesh (scale, scene, (unsigned) mesh->num_vertices, tv); mesh->addSubModel (tv.vertices_, tv.triangles_); mesh->endModel (); } +} // namespace internal + /** * @brief Read a mesh file and convert it to a polyhedral mesh * @@ -139,46 +128,13 @@ inline void loadPolyhedronFromResource (const std::string & resource_path, const fcl::Vec3f & scale, const boost::shared_ptr < BVHModel<BoundingVolume> > & polyhedron) { - Assimp::Importer importer; - // set list of ignored parameters (parameters used for rendering) - importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, - aiComponent_TANGENTS_AND_BITANGENTS| - aiComponent_COLORS | - aiComponent_BONEWEIGHTS | - aiComponent_ANIMATIONS | - aiComponent_LIGHTS | - aiComponent_CAMERAS| - aiComponent_TEXTURES | - aiComponent_TEXCOORDS | - aiComponent_MATERIALS | - aiComponent_NORMALS - ); - - const aiScene* scene = importer.ReadFile(resource_path.c_str(), - aiProcess_SortByPType | - aiProcess_Triangulate | - aiProcess_RemoveComponent | - aiProcess_ImproveCacheLocality | - // TODO: I (Joseph Mirabel) have no idea whether degenerated triangles are - // properly handled. Enabling aiProcess_FindDegenerates would throw an - // exception when that happens. Is it too conservative ? - // aiProcess_FindDegenerates | - aiProcess_JoinIdenticalVertices - ); - - if (!scene) - { - const std::string exception_message (std::string ("Could not load resource ") + resource_path + std::string("\n") + - importer.GetErrorString () + std::string("\n") + - "Hint: the mesh directory may be wrong."); - throw std::invalid_argument(exception_message); - } - - meshFromAssimpScene (resource_path, scale, scene, polyhedron); -} + internal::Loader scene; + scene.load (resource_path); + internal::meshFromAssimpScene (scale, scene.scene, polyhedron); } +} // namespace fcl } // namespace hpp -#endif // FCL_MESH_LOADER_ASSIMP_H +#endif // HPP_FCL_MESH_LOADER_ASSIMP_H diff --git a/include/hpp/fcl/mesh_loader/loader.h b/include/hpp/fcl/mesh_loader/loader.h index ce8a30afbb52e241c40668c6a4aca49457174e61..5039bc05fa6e97625313b6f39b34158e227a37d8 100644 --- a/include/hpp/fcl/mesh_loader/loader.h +++ b/include/hpp/fcl/mesh_loader/loader.h @@ -40,7 +40,7 @@ #include <boost/shared_ptr.hpp> #include <hpp/fcl/fwd.hh> #include <hpp/fcl/config.hh> -#include <hpp/fcl/math/vec_3f.h> +#include <hpp/fcl/data_types.h> #include <hpp/fcl/collision_object.h> namespace hpp @@ -55,7 +55,7 @@ namespace fcl { /// \param bvType ignored /// \deprecated Use MeshLoader::load(const std::string&, const Vec3f&) - CollisionGeometryPtr_t load (const std::string& filename, + BVHModelPtr_t load (const std::string& filename, const Vec3f& scale, const NODE_TYPE& bvType) HPP_FCL_DEPRECATED { @@ -63,7 +63,7 @@ namespace fcl { return load (filename, scale); } - virtual CollisionGeometryPtr_t load (const std::string& filename, + virtual BVHModelPtr_t load (const std::string& filename, const Vec3f& scale); MeshLoader (const NODE_TYPE& bvType = BV_OBBRSS) : bvType_ (bvType) {} @@ -83,17 +83,7 @@ namespace fcl { CachedMeshLoader (const NODE_TYPE& bvType = BV_OBBRSS) : MeshLoader (bvType) {} - /// \param bvType ignored - /// \deprecated Use MeshLoader::load(const std::string&, const Vec3f&) - CollisionGeometryPtr_t load (const std::string& filename, - const Vec3f& scale, - const NODE_TYPE& bvType) HPP_FCL_DEPRECATED - { - (void) bvType; - return load(filename, scale); - } - - virtual CollisionGeometryPtr_t load (const std::string& filename, + virtual BVHModelPtr_t load (const std::string& filename, const Vec3f& scale); struct Key { @@ -105,7 +95,7 @@ namespace fcl { bool operator< (const CachedMeshLoader::Key& b) const; }; - typedef std::map <Key, CollisionGeometryPtr_t> Cache_t; + typedef std::map <Key, BVHModelPtr_t> Cache_t; const Cache_t cache () const { return cache_; } private: diff --git a/include/hpp/fcl/narrowphase/gjk.h b/include/hpp/fcl/narrowphase/gjk.h index 4748e3e087efa12a8238d0df311eec54ec7b544c..6e7d25ffc487085b533802b52cf1fb94c67c93cb 100644 --- a/include/hpp/fcl/narrowphase/gjk.h +++ b/include/hpp/fcl/narrowphase/gjk.h @@ -50,83 +50,89 @@ namespace details { /// @brief the support function for shape -Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir); +Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized); /// @brief Minkowski difference class of two shapes /// -/// \note The Minkowski difference is expressed in the frame of the first shape. +/// @todo template this by the two shapes. The triangle / triangle case can be +/// easily optimized computing once the triangle shapes[1] into frame0 +/// +/// @note The Minkowski difference is expressed in the frame of the first shape. struct MinkowskiDiff { /// @brief points to two shapes const ShapeBase* shapes[2]; - /// @brief rotation from shape0 to shape1 - Matrix3f toshape1; + /// @brief rotation from shape1 to shape0 + /// such that @f$ p_in_0 = oR1 * p_in_1 + ot1 @f$. + Matrix3f oR1; + + /// @brief translation from shape1 to shape0 + /// such that @f$ p_in_0 = oR1 * p_in_1 + ot1 @f$. + Vec3f ot1; + + typedef void (*GetSupportFunction) (const MinkowskiDiff& minkowskiDiff, + const Vec3f& dir, bool dirIsNormalized, Vec3f& support0, Vec3f& support1); + GetSupportFunction getSupportFunc; - /// @brief transform from shape1 to shape0 - Transform3f toshape0; + MinkowskiDiff() : getSupportFunc (NULL) {} - MinkowskiDiff() { } + /// Set the two shapes, + /// assuming the relative transformation between them is identity. + void set (const ShapeBase* shape0, const ShapeBase* shape1); + + /// Set the two shapes, with a relative transformation. + void set (const ShapeBase* shape0, const ShapeBase* shape1, + const Transform3f& tf0, const Transform3f& tf1); /// @brief support function for shape0 - inline Vec3f support0(const Vec3f& d) const + inline Vec3f support0(const Vec3f& d, bool dIsNormalized) const { - return getSupport(shapes[0], d); + return getSupport(shapes[0], d, dIsNormalized); } - + /// @brief support function for shape1 - inline Vec3f support1(const Vec3f& d) const + inline Vec3f support1(const Vec3f& d, bool dIsNormalized) const { - return toshape0.transform(getSupport(shapes[1], toshape1 * d)); + return oR1 * getSupport(shapes[1], oR1.transpose() * d, dIsNormalized) + ot1; } /// @brief support function for the pair of shapes - inline Vec3f support(const Vec3f& d) const - { - return support0(d) - support1(-d); - } - - /// @brief support function for the d-th shape (d = 0 or 1) - inline Vec3f support(const Vec3f& d, size_t index) const + inline void support(const Vec3f& d, bool dIsNormalized, Vec3f& supp0, Vec3f& supp1) const { - if(index) - return support1(d); - else - return support0(d); + assert(getSupportFunc != NULL); + getSupportFunc(*this, d, dIsNormalized, supp0, supp1); } }; - /// @brief class for GJK algorithm /// -/// \note The computations are performed in the frame of the first shape. +/// @note The computations are performed in the frame of the first shape. struct GJK { struct SimplexV { - /// @brief support direction - Vec3f d; - /// @brieg support vector (i.e., the furthest point on the shape along the support direction) + /// @brief support vector for shape 0 and 1. + Vec3f w0, w1; + /// @brief support vector (i.e., the furthest point on the shape along the support direction) Vec3f w; - - SimplexV () : d(Vec3f::Zero()), w(Vec3f::Zero()) {} }; + typedef unsigned char vertex_id_t; + struct Simplex { /// @brief simplex vertex SimplexV* vertex[4]; - /// @brief weight - FCL_REAL coefficient[4]; /// @brief size of simplex (number of vertices) - size_t rank; + vertex_id_t rank; - Simplex() : rank(0) {} + Simplex() {} }; enum Status {Valid, Inside, Failed}; - MinkowskiDiff shape; + MinkowskiDiff const* shape; Vec3f ray; FCL_REAL distance; Simplex simplices[2]; @@ -141,16 +147,14 @@ struct GJK void initialize(); /// @brief GJK algorithm, given the initial value guess - Status evaluate(const MinkowskiDiff& shape_, const Vec3f& guess); + Status evaluate(const MinkowskiDiff& shape, const Vec3f& guess); /// @brief apply the support function along a direction, the result is return in sv - void getSupport(const Vec3f& d, SimplexV& sv) const; - - /// @brief discard one vertex from the simplex - void removeVertex(Simplex& simplex); - - /// @brief append one vertex to the simplex - void appendVertex(Simplex& simplex, const Vec3f& v); + inline void getSupport(const Vec3f& d, bool dIsNormalized, SimplexV& sv) const + { + shape->support(d, dIsNormalized, sv.w0, sv.w1); + sv.w.noalias() = sv.w0 - sv.w1; + } /// @brief whether the simplex enclose the origin bool encloseOrigin(); @@ -161,20 +165,48 @@ struct GJK return simplex; } + /// Get the closest points on each object. + /// @return true on success + static bool getClosestPoints (const Simplex& simplex, Vec3f& w0, Vec3f& w1); + /// @brief get the guess from current simplex Vec3f getGuessFromSimplex() const; + /// @brief Distance threshold for early break. + /// GJK stops when it proved the distance is more than this threshold. + /// @note The closest points will be erroneous in this case. + /// If you want the closest points, set this to infinity (the default). + void setDistanceEarlyBreak (const FCL_REAL& dup) + { + distance_upper_bound = dup; + } + private: SimplexV store_v[4]; SimplexV* free_v[4]; - size_t nfree; - size_t current; + vertex_id_t nfree; + vertex_id_t current; Simplex* simplex; Status status; unsigned int max_iterations; FCL_REAL tolerance; + FCL_REAL distance_upper_bound; + + /// @brief discard one vertex from the simplex + inline void removeVertex(Simplex& simplex); + + /// @brief append one vertex to the simplex + inline void appendVertex(Simplex& simplex, const Vec3f& v, bool isNormalized = false); + + /// @brief Project origin (0) onto line a-b + bool projectLineOrigin(const Simplex& current, Simplex& next); + /// @brief Project origin (0) onto triangle a-b-c + bool projectTriangleOrigin(const Simplex& current, Simplex& next); + + /// @brief Project origin (0) onto tetrahedran a-b-c-d + bool projectTetrahedraOrigin(const Simplex& current, Simplex& next); }; @@ -273,6 +305,9 @@ public: void initialize(); + Status evaluate(GJK& gjk, const Vec3f& guess); + +private: bool getEdgeDist(SimplexF* face, SimplexV* a, SimplexV* b, FCL_REAL& dist); SimplexF* newFace(SimplexV* a, SimplexV* b, SimplexV* vertex, bool forced); @@ -280,8 +315,6 @@ public: /// @brief Find the best polytope face to split SimplexF* findBest(); - Status evaluate(GJK& gjk, const Vec3f& guess); - /// @brief the goal is to add a face connecting vertex w and face edge f[e] bool expand(size_t pass, SimplexV* w, SimplexF* f, size_t e, SimplexHorizon& horizon); }; diff --git a/include/hpp/fcl/narrowphase/narrowphase.h b/include/hpp/fcl/narrowphase/narrowphase.h index a85f7fae3131b7333d88401a4168af161bdaf42d..2dedf459c939ebb0ce1e21729eafafd6f2837149 100644 --- a/include/hpp/fcl/narrowphase/narrowphase.h +++ b/include/hpp/fcl/narrowphase/narrowphase.h @@ -50,7 +50,7 @@ namespace fcl /// @brief collision and distance solver based on GJK algorithm implemented in fcl (rewritten the code from the GJK in bullet) - struct GJKSolver_indep + struct GJKSolver { /// @brief intersection checking between two shapes template<typename S1, typename S2> @@ -62,10 +62,7 @@ namespace fcl if(enable_cached_guess) guess = cached_guess; details::MinkowskiDiff shape; - shape.shapes[0] = &s1; - shape.shapes[1] = &s2; - shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation(); - shape.toshape0 = tf1.inverseTimes(tf2); + shape.set (&s1, &s2, tf1, tf2); details::GJK gjk((unsigned int )gjk_max_iterations, gjk_tolerance); details::GJK::Status gjk_status = gjk.evaluate(shape, -guess); @@ -79,12 +76,8 @@ namespace fcl details::EPA::Status epa_status = epa.evaluate(gjk, -guess); if(epa_status != details::EPA::Failed) { - Vec3f w0 (Vec3f::Zero()); - for(size_t i = 0; i < epa.result.rank; ++i) - { - w0 += shape.support(epa.result.vertex[i]->d, 0) * - epa.result.coefficient[i]; - } + Vec3f w0, w1; + details::GJK::getClosestPoints (epa.result, w0, w1); if(penetration_depth) *penetration_depth = -epa.depth; if(normal) *normal = tf2.getRotation() * epa.normal; if(contact_points) *contact_points = tf1.transform(w0 - epa.normal*(epa.depth *0.5)); @@ -101,7 +94,7 @@ namespace fcl } //// @brief intersection checking between one shape and a triangle with transformation - /// \return true if the shape are colliding. + /// @return true if the shape are colliding. template<typename S> bool shapeTriangleInteraction (const S& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, @@ -109,16 +102,18 @@ namespace fcl Vec3f& p1, Vec3f& p2, Vec3f& normal) const { bool col; - TriangleP tri(P1, P2, P3); + // Express everything in frame 1 + const Transform3f tf_1M2 (tf1.inverseTimes(tf2)); + TriangleP tri( + tf_1M2.transform (P1), + tf_1M2.transform (P2), + tf_1M2.transform (P3)); Vec3f guess(1, 0, 0); if(enable_cached_guess) guess = cached_guess; details::MinkowskiDiff shape; - shape.shapes[0] = &s; - shape.shapes[1] = &tri; - shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation(); - shape.toshape0 = tf1.inverseTimes(tf2); + shape.set (&s, &tri); details::GJK gjk((unsigned int )gjk_max_iterations, gjk_tolerance); details::GJK::Status gjk_status = gjk.evaluate(shape, -guess); @@ -132,12 +127,8 @@ namespace fcl details::EPA epa(epa_max_face_num, epa_max_vertex_num, epa_max_iterations, epa_tolerance); details::EPA::Status epa_status = epa.evaluate(gjk, -guess); assert (epa_status != details::EPA::Failed); (void) epa_status; - Vec3f w0 (Vec3f::Zero()); - for(size_t i = 0; i < epa.result.rank; ++i) - { - w0 += shape.support(epa.result.vertex[i]->d, 0) * - epa.result.coefficient[i]; - } + Vec3f w0, w1; + details::GJK::getClosestPoints (epa.result, w0, w1); distance = -epa.depth; normal = -epa.normal; p1 = p2 = tf1.transform(w0 - epa.normal*(epa.depth *0.5)); @@ -148,16 +139,15 @@ namespace fcl case details::GJK::Failed: { col = false; - Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero()); - for(size_t i = 0; i < gjk.getSimplex()->rank; ++i) - { - FCL_REAL p = gjk.getSimplex()->coefficient[i]; - w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p; - w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p; - } - distance = (w0 - w1).norm(); - p1 = tf1.transform (w0); - p2 = tf1.transform (w1); + + details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2); + // TODO On degenerated case, the closest point may be wrong + // (i.e. an object face normal is colinear to gjk.ray + // assert (distance == (w0 - w1).norm()); + distance = gjk.distance; + + p1 = tf1.transform (p1); + p2 = tf1.transform (p2); assert (distance > 0); } break; @@ -183,10 +173,7 @@ namespace fcl if(enable_cached_guess) guess = cached_guess; details::MinkowskiDiff shape; - shape.shapes[0] = &s1; - shape.shapes[1] = &s2; - shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation(); - shape.toshape0 = tf1.inverseTimes(tf2); + shape.set (&s1, &s2, tf1, tf2); details::GJK gjk((unsigned int) gjk_max_iterations, gjk_tolerance); details::GJK::Status gjk_status = gjk.evaluate(shape, -guess); @@ -196,13 +183,8 @@ namespace fcl { // TODO: understand why GJK fails between cylinder and box assert (distance * distance < sqrt (eps)); - Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero()); - for(size_t i = 0; i < gjk.getSimplex()->rank; ++i) - { - FCL_REAL p = gjk.getSimplex()->coefficient[i]; - w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p; - w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p; - } + Vec3f w0, w1; + details::GJK::getClosestPoints (*gjk.getSimplex(), w0, w1); distance = 0; p1 = p2 = tf1.transform (.5* (w0 + w1)); normal = Vec3f (0,0,0); @@ -210,18 +192,14 @@ namespace fcl } else if(gjk_status == details::GJK::Valid) { - Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero()); - for(size_t i = 0; i < gjk.getSimplex()->rank; ++i) - { - FCL_REAL p = gjk.getSimplex()->coefficient[i]; - w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p; - w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p; - } - - distance = (w0 - w1).norm(); - - p1 = tf1.transform (w0); - p2 = tf1.transform (w1); + details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2); + // TODO On degenerated case, the closest point may be wrong + // (i.e. an object face normal is colinear to gjk.ray + // assert (distance == (w0 - w1).norm()); + distance = gjk.distance; + + p1 = tf1.transform (p1); + p2 = tf1.transform (p2); return true; } else @@ -234,12 +212,8 @@ namespace fcl details::EPA::Status epa_status = epa.evaluate(gjk, -guess); if(epa_status != details::EPA::Failed) { - Vec3f w0 (Vec3f::Zero()); - for(size_t i = 0; i < epa.result.rank; ++i) - { - w0 += shape.support(epa.result.vertex[i]->d, 0) * - epa.result.coefficient[i]; - } + Vec3f w0, w1; + details::GJK::getClosestPoints (epa.result, w0, w1); assert (epa.depth >= -eps); distance = std::min (0., -epa.depth); normal = tf2.getRotation() * epa.normal; @@ -248,24 +222,18 @@ namespace fcl } else { - Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero()); - for(size_t i = 0; i < gjk.getSimplex()->rank; ++i) - { - FCL_REAL p = gjk.getSimplex()->coefficient[i]; - w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p; - w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p; - } + details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2); distance = 0; - p1 = tf1.transform (w0); - p2 = tf1.transform (w1); + p1 = tf1.transform (p1); + p2 = tf1.transform (p2); } return false; } } /// @brief default setting for GJK algorithm - GJKSolver_indep() + GJKSolver() { gjk_max_iterations = 128; gjk_tolerance = 1e-6; @@ -319,202 +287,202 @@ namespace fcl /// @brief Fast implementation for sphere-capsule collision template<> - bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1, const Sphere &s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; /// @brief Fast implementation for sphere-sphere collision template<> - bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; /// @brief Fast implementation for box-box collision template<> - bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1, const Box& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace>(const Sphere& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Sphere, Halfspace>(const Sphere& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Box, Halfspace>(const Box& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Box, Halfspace>(const Box& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Box>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Box>(const Halfspace& s1, const Transform3f& tf1, const Box& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Capsule, Halfspace>(const Capsule& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Capsule, Halfspace>(const Capsule& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Capsule>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Capsule>(const Halfspace& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Cylinder, Halfspace>(const Cylinder& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Cylinder, Halfspace>(const Cylinder& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Cylinder>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Cylinder>(const Halfspace& s1, const Transform3f& tf1, const Cylinder& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Cone, Halfspace>(const Cone& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Cone, Halfspace>(const Cone& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Cone>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Cone>(const Halfspace& s1, const Transform3f& tf1, const Cone& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Sphere, Plane>(const Sphere& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Sphere, Plane>(const Sphere& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Sphere>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Sphere>(const Plane& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Box, Plane>(const Box& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Box, Plane>(const Box& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Box>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Box>(const Plane& s1, const Transform3f& tf1, const Box& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Capsule, Plane>(const Capsule& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Capsule, Plane>(const Capsule& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Capsule>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Capsule>(const Plane& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Cylinder, Plane>(const Cylinder& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Cylinder, Plane>(const Cylinder& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Cylinder>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Cylinder>(const Plane& s1, const Transform3f& tf1, const Cylinder& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Cone, Plane>(const Cone& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Cone, Plane>(const Cone& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Cone>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Cone>(const Plane& s1, const Transform3f& tf1, const Cone& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; template<> - bool GJKSolver_indep::shapeIntersect<Plane, Plane>(const Plane& s1, const Transform3f& tf1, + bool GJKSolver::shapeIntersect<Plane, Plane>(const Plane& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const; /// @brief Fast implementation for sphere-triangle collision template<> - bool GJKSolver_indep::shapeTriangleInteraction + bool GJKSolver::shapeTriangleInteraction (const Sphere& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; template<> - bool GJKSolver_indep::shapeTriangleInteraction + bool GJKSolver::shapeTriangleInteraction (const Halfspace& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; template<> - bool GJKSolver_indep::shapeTriangleInteraction + bool GJKSolver::shapeTriangleInteraction (const Plane& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; /// @brief Fast implementation for sphere-capsule distance template<> - bool GJKSolver_indep::shapeDistance<Sphere, Capsule> + bool GJKSolver::shapeDistance<Sphere, Capsule> (const Sphere& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; template<> - bool GJKSolver_indep::shapeDistance<Capsule, Sphere> + bool GJKSolver::shapeDistance<Capsule, Sphere> (const Capsule& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; /// @brief Fast implementation for sphere-cylinder distance template<> - bool GJKSolver_indep::shapeDistance<Sphere, Cylinder> + bool GJKSolver::shapeDistance<Sphere, Cylinder> (const Sphere& s1, const Transform3f& tf1, const Cylinder& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; template<> - bool GJKSolver_indep::shapeDistance<Cylinder, Sphere> + bool GJKSolver::shapeDistance<Cylinder, Sphere> (const Cylinder& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; /// @brief Fast implementation for sphere-sphere distance template<> - bool GJKSolver_indep::shapeDistance<Sphere, Sphere> + bool GJKSolver::shapeDistance<Sphere, Sphere> (const Sphere& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; // @brief Computation of the distance result for capsule capsule. Closest points are based on two line-segments. template<> - bool GJKSolver_indep::shapeDistance<Capsule, Capsule> + bool GJKSolver::shapeDistance<Capsule, Capsule> (const Capsule& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; @@ -524,7 +492,7 @@ namespace fcl // Do not run EPA algorithm to compute penetration depth, use a dedicated // method. template<> - bool GJKSolver_indep::shapeDistance<TriangleP, TriangleP> + bool GJKSolver::shapeDistance<TriangleP, TriangleP> (const TriangleP& s1, const Transform3f& tf1, const TriangleP& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const; diff --git a/include/hpp/fcl/profile.h b/include/hpp/fcl/profile.h index 96d70d1cf8ec02916c1a608c3aef439c03d24155..a7e3f2780503a26cc021676e95cfec25d0f3dcbb 100644 --- a/include/hpp/fcl/profile.h +++ b/include/hpp/fcl/profile.h @@ -115,7 +115,7 @@ public: class ScopedBlock { public: - /// @brief Start counting time for the block named \e name of the profiler \e prof + /// @brief Start counting time for the block named @e name of the profiler @e prof ScopedBlock(const std::string &name, Profiler &prof = Profiler::Instance()) : name_(name), prof_(prof) { prof_.begin(name); @@ -138,7 +138,7 @@ public: { public: - /// @brief Take as argument the profiler instance to operate on (\e prof) + /// @brief Take as argument the profiler instance to operate on (@e prof) ScopedStart(Profiler &prof = Profiler::Instance()) : prof_(prof), wasRunning_(prof_.running()) { if (!wasRunning_) diff --git a/include/hpp/fcl/shape/convex.h b/include/hpp/fcl/shape/convex.h new file mode 100644 index 0000000000000000000000000000000000000000..cafbddd040b474fbab5204eb4c7d156869530db7 --- /dev/null +++ b/include/hpp/fcl/shape/convex.h @@ -0,0 +1,97 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011-2014, Willow Garage, Inc. + * Copyright (c) 2014-2015, Open Source Robotics Foundation + * 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 Open Source Robotics Foundation 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 HPP_FCL_SHAPE_CONVEX_H +#define HPP_FCL_SHAPE_CONVEX_H + +#include <hpp/fcl/shape/geometric_shapes.h> + +namespace hpp +{ +namespace fcl +{ + +/// @brief Convex polytope +/// @tparam PolygonT the polygon class. It must have method \c size() and +/// \c operator[](int i) +template <typename PolygonT> +class Convex : public ConvexBase +{ +public: + /// @brief Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information + /// \param own_storage whether this class owns the pointers of points and + /// polygons. If owned, they are deleted upon destruction. + /// \param points_ list of 3D points + /// \param num_points_ number of 3D points + /// \param polygons_ \copydoc Convex::polygons + /// \param num_polygons_ the number of polygons. + /// \note num_polygons_ is not the allocated size of polygons_. + Convex(bool ownStorage, + Vec3f* points_, int num_points_, + PolygonT* polygons_, int num_polygons_); + + /// @brief Copy constructor + /// Only the list of neighbors is copied. + Convex(const Convex& other); + + ~Convex(); + + /// @brief An array of PolygonT object. + /// PolygonT should contains a list of vertices for each polygon, + /// in counter clockwise order. + PolygonT* polygons; + int num_polygons; + + /// based on http://number-none.com/blow/inertia/bb_inertia.doc + Matrix3f computeMomentofInertia() const; + + Vec3f computeCOM() const; + + FCL_REAL computeVolume() const; + +protected: + void fillNeighbors(); +}; + +} + +} // namespace hpp + +#include <hpp/fcl/shape/details/convex.hxx> + +#endif diff --git a/include/hpp/fcl/shape/details/convex.hxx b/include/hpp/fcl/shape/details/convex.hxx new file mode 100644 index 0000000000000000000000000000000000000000..b76eae2414acdf9ac5148488c6d782e500166a04 --- /dev/null +++ b/include/hpp/fcl/shape/details/convex.hxx @@ -0,0 +1,233 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2019, CNRS - LAAS + * 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 Open Source Robotics Foundation 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 Joseph Mirabel */ + + +#ifndef HPP_FCL_SHAPE_CONVEX_HXX +#define HPP_FCL_SHAPE_CONVEX_HXX + +#include <set> + +namespace hpp +{ +namespace fcl +{ + +template <typename PolygonT> +Convex<PolygonT>::Convex(bool own_storage, Vec3f* points_, int num_points_, + PolygonT* polygons_, int num_polygons_) : + ConvexBase(own_storage, points_, num_points_), + polygons (polygons_), + num_polygons (num_polygons_) +{ + fillNeighbors(); +} + +template <typename PolygonT> +Convex<PolygonT>::Convex(const Convex<PolygonT>& other) : + ConvexBase (other), + polygons (other.polygons), + num_polygons (other.num_polygons) +{ + if (own_storage_) { + polygons = new PolygonT[num_polygons]; + memcpy(polygons, other.polygons, sizeof(PolygonT) * num_polygons); + } +} + +template <typename PolygonT> +Convex<PolygonT>::~Convex() +{ + if (own_storage_) delete [] polygons; +} + +template <typename PolygonT> +Matrix3f Convex<PolygonT>::computeMomentofInertia() const +{ + typedef typename PolygonT::size_type size_type; + typedef typename PolygonT::index_type index_type; + + Matrix3f C = Matrix3f::Zero(); + + Matrix3f C_canonical; + C_canonical << 1/60.0, 1/120.0, 1/120.0, + 1/120.0, 1/60.0, 1/120.0, + 1/120.0, 1/120.0, 1/60.0; + + for(int i = 0; i < num_polygons; ++i) + { + const PolygonT& polygon (polygons[i]); + + // compute the center of the polygon + Vec3f plane_center(0,0,0); + for(size_type j = 0; j < polygon.size(); ++j) + plane_center += points[polygon[j]]; + plane_center /= polygon.size(); + + // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape + const Vec3f& v3 = plane_center; + for(size_type j = 0; j < polygon.size(); ++j) + { + index_type e_first = polygon[j]; + index_type e_second = polygon[(j+1)%polygon.size()]; + const Vec3f& v1 = points[e_first]; + const Vec3f& v2 = points[e_second]; + Matrix3f A; A << v1.transpose(), v2.transpose(), v3.transpose(); // this is A' in the original document + C += A.transpose() * C_canonical * A * (v1.cross(v2)).dot(v3); + } + } + + return C.trace() * Matrix3f::Identity() - C; +} + +template <typename PolygonT> +Vec3f Convex<PolygonT>::computeCOM() const +{ + typedef typename PolygonT::size_type size_type; + typedef typename PolygonT::index_type index_type; + + Vec3f com(0,0,0); + FCL_REAL vol = 0; + for(int i = 0; i < num_polygons; ++i) + { + const PolygonT& polygon (polygons[i]); + // compute the center of the polygon + Vec3f plane_center(0,0,0); + for(size_type j = 0; j < polygon.size(); ++j) + plane_center += points[polygon[j]]; + plane_center /= polygon.size(); + + // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape + const Vec3f& v3 = plane_center; + for(size_type j = 0; j < polygon.size(); ++j) + { + index_type e_first = polygon[j]; + index_type e_second = polygon[(j+1)%polygon.size()]; + const Vec3f& v1 = points[e_first]; + const Vec3f& v2 = points[e_second]; + FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3); + vol += d_six_vol; + com += (points[e_first] + points[e_second] + plane_center) * d_six_vol; + } + } + + return com / (vol * 4); // here we choose zero as the reference +} + +template <typename PolygonT> +FCL_REAL Convex<PolygonT>::computeVolume() const +{ + typedef typename PolygonT::size_type size_type; + typedef typename PolygonT::index_type index_type; + + FCL_REAL vol = 0; + for(int i = 0; i < num_polygons; ++i) + { + const PolygonT& polygon (polygons[i]); + + // compute the center of the polygon + Vec3f plane_center(0,0,0); + for(size_type j = 0; j < polygon.size(); ++j) + plane_center += points[polygon[j]]; + plane_center /= polygon.size(); + + // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero point) of the convex shape + const Vec3f& v3 = plane_center; + for(size_type j = 0; j < polygon.size(); ++j) + { + index_type e_first = polygon[j]; + index_type e_second = polygon[(j+1)%polygon.size()]; + const Vec3f& v1 = points[e_first]; + const Vec3f& v2 = points[e_second]; + FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3); + vol += d_six_vol; + } + } + + return vol / 6; +} + +template <typename PolygonT> +void Convex<PolygonT>::fillNeighbors() +{ + neighbors = new Neighbors[num_points]; + + typedef typename PolygonT::size_type size_type; + typedef typename PolygonT::index_type index_type; + std::vector<std::set<index_type> > nneighbors (num_points); + unsigned int c_nneighbors = 0; + + for (int l = 0; l < num_polygons; ++l) + { + const PolygonT& polygon (polygons[l]); + size_type n = polygon.size(); + + for(size_type j = 0; j < polygon.size(); ++j) + { + size_type i = (j==0 ) ? n-1 : j-1; + size_type k = (j==n-1) ? 0 : j+1; + index_type pi = polygon[i], + pj = polygon[j], + pk = polygon[k]; + // Update neighbors of pj; + if (nneighbors[pj].count(pi) == 0) { + c_nneighbors++; + nneighbors[pj].insert(pi); + } + if (nneighbors[pj].count(pk) == 0) { + c_nneighbors++; + nneighbors[pj].insert(pk); + } + } + } + + nneighbors_ = new unsigned int[c_nneighbors]; + unsigned int* p_nneighbors = nneighbors_; + for (int i = 0; i < num_points; ++i) { + Neighbors& n = neighbors[i]; + if (nneighbors[i].size() >= std::numeric_limits<unsigned char>::max()) + throw std::logic_error ("Too many neighbors."); + n.count_ = (unsigned char)nneighbors[i].size(); + n.n_ = p_nneighbors; + p_nneighbors = std::copy (nneighbors[i].begin(), nneighbors[i].end(), p_nneighbors); + } + assert (p_nneighbors == nneighbors_ + c_nneighbors); +} + +} + +} // namespace hpp + +#endif diff --git a/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h b/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h index f50309a01012cdbf2c9bf2158c7e2f917ead3549..5307014ad0762d4d83d8f6473a2ebfb0513a1dfc 100644 --- a/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h +++ b/include/hpp/fcl/shape/geometric_shape_to_BVH_model.h @@ -52,30 +52,30 @@ namespace fcl template<typename BV> void generateBVHModel(BVHModel<BV>& model, const Box& shape, const Transform3f& pose) { - double a = shape.side[0]; - double b = shape.side[1]; - double c = shape.side[2]; + double a = shape.halfSide[0]; + double b = shape.halfSide[1]; + double c = shape.halfSide[2]; std::vector<Vec3f> points(8); - std::vector<Triangle> tri_indices(12); - points[0] << 0.5 * a, -0.5 * b, 0.5 * c; - points[1] << 0.5 * a, 0.5 * b, 0.5 * c; - points[2] << -0.5 * a, 0.5 * b, 0.5 * c; - points[3] << -0.5 * a, -0.5 * b, 0.5 * c; - points[4] << 0.5 * a, -0.5 * b, -0.5 * c; - points[5] << 0.5 * a, 0.5 * b, -0.5 * c; - points[6] << -0.5 * a, 0.5 * b, -0.5 * c; - points[7] << -0.5 * a, -0.5 * b, -0.5 * c; - - tri_indices[0].set(0, 4, 1); - tri_indices[1].set(1, 4, 5); - tri_indices[2].set(2, 6, 3); - tri_indices[3].set(3, 6, 7); - tri_indices[4].set(3, 0, 2); - tri_indices[5].set(2, 0, 1); - tri_indices[6].set(6, 5, 7); - tri_indices[7].set(7, 5, 4); - tri_indices[8].set(1, 5, 2); - tri_indices[9].set(2, 5, 6); + Triangle tri_indices[12]; + points[0] = Vec3f ( a, -b, c); + points[1] = Vec3f ( a, b, c); + points[2] = Vec3f (-a, b, c); + points[3] = Vec3f (-a, -b, c); + points[4] = Vec3f ( a, -b, -c); + points[5] = Vec3f ( a, b, -c); + points[6] = Vec3f (-a, b, -c); + points[7] = Vec3f (-a, -b, -c); + + tri_indices[ 0].set(0, 4, 1); + tri_indices[ 1].set(1, 4, 5); + tri_indices[ 2].set(2, 6, 3); + tri_indices[ 3].set(3, 6, 7); + tri_indices[ 4].set(3, 0, 2); + tri_indices[ 5].set(2, 0, 1); + tri_indices[ 6].set(6, 5, 7); + tri_indices[ 7].set(7, 5, 4); + tri_indices[ 8].set(1, 5, 2); + tri_indices[ 9].set(2, 5, 6); tri_indices[10].set(3, 7, 0); tri_indices[11].set(0, 7, 4); diff --git a/include/hpp/fcl/shape/geometric_shapes.h b/include/hpp/fcl/shape/geometric_shapes.h index 87723bbd4df6a1b9b5cb5fb1aff37bc337c0e27f..d991f4e02f0e1d81813fad1bb50c5458e485c84e 100644 --- a/include/hpp/fcl/shape/geometric_shapes.h +++ b/include/hpp/fcl/shape/geometric_shapes.h @@ -42,7 +42,7 @@ #include <boost/math/constants/constants.hpp> #include <hpp/fcl/collision_object.h> -#include <hpp/fcl/math/vec_3f.h> +#include <hpp/fcl/data_types.h> #include <string.h> namespace hpp @@ -56,10 +56,16 @@ class ShapeBase : public CollisionGeometry public: ShapeBase() {} + virtual ~ShapeBase () {}; + /// @brief Get object type: a geometric shape OBJECT_TYPE getObjectType() const { return OT_GEOM; } }; +/// @defgroup Geometric_Shapes +/// regroup class of differents types of geometric shapes. +/// @{ + /// @brief Triangle stores the points instead of only indices of points class TriangleP : public ShapeBase { @@ -80,18 +86,18 @@ public: class Box : public ShapeBase { public: - Box(FCL_REAL x, FCL_REAL y, FCL_REAL z) : ShapeBase(), side(x, y, z) + Box(FCL_REAL x, FCL_REAL y, FCL_REAL z) : ShapeBase(), halfSide(x/2, y/2, z/2) { } - Box(const Vec3f& side_) : ShapeBase(), side(side_) + Box(const Vec3f& side_) : ShapeBase(), halfSide(side_/2) { } Box() {} - /// @brief box side length - Vec3f side; + /// @brief box side half-length + Vec3f halfSide; /// @brief Compute AABB void computeLocalAABB(); @@ -101,18 +107,14 @@ public: FCL_REAL computeVolume() const { - return side[0] * side[1] * side[2]; + return 8*halfSide.prod(); } Matrix3f computeMomentofInertia() const { FCL_REAL V = computeVolume(); - FCL_REAL a2 = side[0] * side[0] * V; - FCL_REAL b2 = side[1] * side[1] * V; - FCL_REAL c2 = side[2] * side[2] * V; - return (Matrix3f() << (b2 + c2) / 12, 0, 0, - 0, (a2 + c2) / 12, 0, - 0, 0, (a2 + b2) / 12).finished(); + Vec3f s (halfSide.cwiseAbs2() * V); + return (Vec3f (s[1] + s[2], s[0] + s[2], s[0] + s[1]) / 3).asDiagonal(); } }; @@ -149,15 +151,16 @@ public: class Capsule : public ShapeBase { public: - Capsule(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_) + Capsule(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_) { + halfLength = lz_/2; } /// @brief Radius of capsule FCL_REAL radius; - /// @brief Length along z axis - FCL_REAL lz; + /// @brief Half Length along z axis + FCL_REAL halfLength; /// @brief Compute AABB void computeLocalAABB(); @@ -167,15 +170,15 @@ public: FCL_REAL computeVolume() const { - return boost::math::constants::pi<FCL_REAL>() * radius * radius *(lz + radius * 4/3.0); + return boost::math::constants::pi<FCL_REAL>() * radius * radius *((halfLength * 2) + radius * 4/3.0); } Matrix3f computeMomentofInertia() const { - FCL_REAL v_cyl = radius * radius * lz * boost::math::constants::pi<FCL_REAL>(); + FCL_REAL v_cyl = radius * radius * (halfLength * 2) * boost::math::constants::pi<FCL_REAL>(); FCL_REAL v_sph = radius * radius * radius * boost::math::constants::pi<FCL_REAL>() * 4 / 3.0; - FCL_REAL ix = v_cyl * lz * lz / 12.0 + 0.25 * v_cyl * radius + 0.4 * v_sph * radius * radius + 0.25 * v_sph * lz * lz; + FCL_REAL ix = v_cyl * halfLength * halfLength / 3. + 0.25 * v_cyl * radius + 0.4 * v_sph * radius * radius + v_sph * halfLength * halfLength; FCL_REAL iz = (0.5 * v_cyl + 0.4 * v_sph) * radius * radius; return (Matrix3f() << ix, 0, 0, @@ -189,15 +192,16 @@ public: class Cone : public ShapeBase { public: - Cone(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_) + Cone(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_) { + halfLength = lz_/2; } /// @brief Radius of the cone FCL_REAL radius; - /// @brief Length along z axis - FCL_REAL lz; + /// @brief Half Length along z axis + FCL_REAL halfLength; /// @brief Compute AABB void computeLocalAABB(); @@ -207,13 +211,14 @@ public: FCL_REAL computeVolume() const { - return boost::math::constants::pi<FCL_REAL>() * radius * radius * lz / 3; + return boost::math::constants::pi<FCL_REAL>() * radius * radius * (halfLength * 2) / 3; } + /// \todo verify this formula as it seems different from https://en.wikipedia.org/wiki/List_of_moments_of_inertia#List_of_3D_inertia_tensors Matrix3f computeMomentofInertia() const { FCL_REAL V = computeVolume(); - FCL_REAL ix = V * (0.1 * lz * lz + 3 * radius * radius / 20); + FCL_REAL ix = V * (0.4 * halfLength * halfLength + 3 * radius * radius / 20); FCL_REAL iz = 0.3 * V * radius * radius; return (Matrix3f() << ix, 0, 0, @@ -223,7 +228,7 @@ public: Vec3f computeCOM() const { - return Vec3f(0, 0, -0.25 * lz); + return Vec3f(0, 0, -0.5 * halfLength); } }; @@ -231,16 +236,16 @@ public: class Cylinder : public ShapeBase { public: - Cylinder(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_) + Cylinder(FCL_REAL radius_, FCL_REAL lz_) : ShapeBase(), radius(radius_) { + halfLength = lz_/2; } - /// @brief Radius of the cylinder FCL_REAL radius; - /// @brief Length along z axis - FCL_REAL lz; + /// @brief Half Length along z axis + FCL_REAL halfLength; /// @brief Compute AABB void computeLocalAABB(); @@ -250,13 +255,13 @@ public: FCL_REAL computeVolume() const { - return boost::math::constants::pi<FCL_REAL>() * radius * radius * lz; + return boost::math::constants::pi<FCL_REAL>() * radius * radius * (halfLength * 2); } Matrix3f computeMomentofInertia() const { FCL_REAL V = computeVolume(); - FCL_REAL ix = V * (3 * radius * radius + lz * lz) / 12; + FCL_REAL ix = V * (radius * radius / 4 + halfLength * halfLength / 3); FCL_REAL iz = V * radius * radius / 2; return (Matrix3f() << ix, 0, 0, 0, ix, 0, @@ -264,54 +269,13 @@ public: } }; -/// @brief Convex polytope -class Convex : public ShapeBase +/// @brief Base for convex polytope. +/// @note Inherited classes are responsible for filling ConvexBase::neighbors; +class ConvexBase : public ShapeBase { public: - /// @brief Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information - /// \param points_ list of 3D points - /// \param num_points_ number of 3D points - /// \param polygons_ \copydoc Convex::polygons - /// \param num_polygons_ the number of polygons. - /// \note num_polygons_ is not the allocated size of polygons_. - Convex(Vec3f* points_, - int num_points_, - int* polygons_, - int num_polygons_) : ShapeBase() - { - num_polygons = num_polygons_; - points = points_; - num_points = num_points_; - polygons = polygons_; - edges = NULL; - - Vec3f sum (0,0,0); - for(int i = 0; i < num_points; ++i) - { - sum += points[i]; - } - center = sum * (FCL_REAL)(1.0 / num_points); - - fillEdges(); - } - - /// @brief Copy constructor - Convex(const Convex& other) : ShapeBase(other) - { - num_polygons = other.num_polygons; - points = other.points; - num_points = other.num_points; - polygons = other.polygons; - num_edges = other.num_edges; - edges = new Edge[num_edges]; - memcpy(edges, other.edges, sizeof(Edge) * num_edges); - } - - ~Convex() - { - delete [] edges; - } + virtual ~ConvexBase(); /// @brief Compute AABB void computeLocalAABB(); @@ -319,141 +283,46 @@ public: /// @brief Get node type: a conex polytope NODE_TYPE getNodeType() const { return GEOM_CONVEX; } - /// @brief An array of indices to the points of each polygon, it should be the number of vertices - /// followed by that amount of indices to "points" in counter clockwise order - int* polygons; - + /// @brief An array of the points of the polygon. Vec3f* points; int num_points; - int num_edges; - int num_polygons; - struct Edge + struct Neighbors { - int first, second; - }; + unsigned char count_; + unsigned int* n_; - Edge* edges; + unsigned char const& count () const { return count_; } + unsigned int & operator[] (int i) { assert(i<count_); return n_[i]; } + unsigned int const& operator[] (int i) const { assert(i<count_); return n_[i]; } + }; + /// Neighbors of each vertex. + /// It is an array of size num_points. For each vertex, it contains the number + /// of neighbors and a list of indices to them. + Neighbors* neighbors; /// @brief center of the convex polytope, this is used for collision: center is guaranteed in the internal of the polytope (as it is convex) Vec3f center; - /// based on http://number-none.com/blow/inertia/bb_inertia.doc - Matrix3f computeMomentofInertia() const - { - - Matrix3f C = Matrix3f::Zero(); - - Matrix3f C_canonical; - C_canonical << 1/60.0, 1/120.0, 1/120.0, - 1/120.0, 1/60.0, 1/120.0, - 1/120.0, 1/120.0, 1/60.0; - - int* points_in_poly = polygons; - int* index = polygons + 1; - for(int i = 0; i < num_polygons; ++i) - { - Vec3f plane_center(0,0,0); - - // compute the center of the polygon - for(int j = 0; j < *points_in_poly; ++j) - plane_center += points[index[j]]; - plane_center = plane_center * (1.0 / *points_in_poly); - - // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape - const Vec3f& v3 = plane_center; - for(int j = 0; j < *points_in_poly; ++j) - { - int e_first = index[j]; - int e_second = index[(j+1)%*points_in_poly]; - const Vec3f& v1 = points[e_first]; - const Vec3f& v2 = points[e_second]; - Matrix3f A; A << v1.transpose(), v2.transpose(), v3.transpose(); // this is A' in the original document - C += A.derived().transpose() * C_canonical * A * (v1.cross(v2)).dot(v3); - } - - points_in_poly += (*points_in_poly + 1); - index = points_in_poly + 1; - } - - return C.trace() * Matrix3f::Identity() - C; - } +protected: + /// @brief Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information + /// \param points_ list of 3D points + /// \param num_points_ number of 3D points + ConvexBase(bool ownStorage, Vec3f* points_, int num_points_); - Vec3f computeCOM() const - { - Vec3f com(0,0,0); - FCL_REAL vol = 0; - int* points_in_poly = polygons; - int* index = polygons + 1; - for(int i = 0; i < num_polygons; ++i) - { - Vec3f plane_center(0,0,0); - - // compute the center of the polygon - for(int j = 0; j < *points_in_poly; ++j) - plane_center += points[index[j]]; - plane_center = plane_center * (1.0 / *points_in_poly); - - // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero) of the convex shape - const Vec3f& v3 = plane_center; - for(int j = 0; j < *points_in_poly; ++j) - { - int e_first = index[j]; - int e_second = index[(j+1)%*points_in_poly]; - const Vec3f& v1 = points[e_first]; - const Vec3f& v2 = points[e_second]; - FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3); - vol += d_six_vol; - com += (points[e_first] + points[e_second] + plane_center) * d_six_vol; - } - - points_in_poly += (*points_in_poly + 1); - index = points_in_poly + 1; - } - - return com / (vol * 4); // here we choose zero as the reference - } + /// @brief Copy constructor + /// Only the list of neighbors is copied. + ConvexBase(const ConvexBase& other); - FCL_REAL computeVolume() const - { - FCL_REAL vol = 0; - int* points_in_poly = polygons; - int* index = polygons + 1; - for(int i = 0; i < num_polygons; ++i) - { - Vec3f plane_center(0,0,0); - - // compute the center of the polygon - for(int j = 0; j < *points_in_poly; ++j) - plane_center += points[index[j]]; - plane_center = plane_center * (1.0 / *points_in_poly); - - // compute the volume of tetrahedron making by neighboring two points, the plane center and the reference point (zero point) of the convex shape - const Vec3f& v3 = plane_center; - for(int j = 0; j < *points_in_poly; ++j) - { - int e_first = index[j]; - int e_second = index[(j+1)%*points_in_poly]; - const Vec3f& v1 = points[e_first]; - const Vec3f& v2 = points[e_second]; - FCL_REAL d_six_vol = (v1.cross(v2)).dot(v3); - vol += d_six_vol; - } - - points_in_poly += (*points_in_poly + 1); - index = points_in_poly + 1; - } - - return vol / 6; - } + unsigned int* nneighbors_; - + bool own_storage_; -protected: - /// @brief Get edge information - void fillEdges(); +private: + void computeCenter(); }; +template <typename PolygonT> class Convex; /// @brief Half Space: this is equivalent to the Plane in ODE. The separation plane is defined as n * x = d; /// Points in the negative side of the separation plane (i.e. {x | n * x < d}) are inside the half space and points @@ -552,7 +421,6 @@ protected: void unitNormalTest(); }; - } } // namespace hpp diff --git a/include/hpp/fcl/shape/geometric_shapes_utility.h b/include/hpp/fcl/shape/geometric_shapes_utility.h index bec2e05e97fb9212cbb017e7747f8ba6c0b4624b..b078f5e05f1702d49c733feb57d303a544286097 100644 --- a/include/hpp/fcl/shape/geometric_shapes_utility.h +++ b/include/hpp/fcl/shape/geometric_shapes_utility.h @@ -42,6 +42,7 @@ #include <vector> #include <hpp/fcl/shape/geometric_shapes.h> #include <hpp/fcl/BV/BV.h> +#include <hpp/fcl/internal/BV_fitter.h> namespace hpp { @@ -57,7 +58,7 @@ std::vector<Vec3f> getBoundVertices(const Sphere& sphere, const Transform3f& tf) std::vector<Vec3f> getBoundVertices(const Capsule& capsule, const Transform3f& tf); std::vector<Vec3f> getBoundVertices(const Cone& cone, const Transform3f& tf); std::vector<Vec3f> getBoundVertices(const Cylinder& cylinder, const Transform3f& tf); -std::vector<Vec3f> getBoundVertices(const Convex& convex, const Transform3f& tf); +std::vector<Vec3f> getBoundVertices(const ConvexBase& convex, const Transform3f& tf); std::vector<Vec3f> getBoundVertices(const TriangleP& triangle, const Transform3f& tf); } /// @endcond @@ -87,7 +88,7 @@ template<> void computeBV<AABB, Cylinder>(const Cylinder& s, const Transform3f& tf, AABB& bv); template<> -void computeBV<AABB, Convex>(const Convex& s, const Transform3f& tf, AABB& bv); +void computeBV<AABB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, AABB& bv); template<> void computeBV<AABB, TriangleP>(const TriangleP& s, const Transform3f& tf, AABB& bv); @@ -116,7 +117,7 @@ template<> void computeBV<OBB, Cylinder>(const Cylinder& s, const Transform3f& tf, OBB& bv); template<> -void computeBV<OBB, Convex>(const Convex& s, const Transform3f& tf, OBB& bv); +void computeBV<OBB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, OBB& bv); template<> void computeBV<OBB, Halfspace>(const Halfspace& s, const Transform3f& tf, OBB& bv); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..270080ff5fba46aa5dcd260be20af0046b1519a5 --- /dev/null +++ b/python/CMakeLists.txt @@ -0,0 +1,61 @@ +# +# Software License Agreement (BSD License) +# +# Copyright (c) 2019 CNRS-LAAS +# Author: Joseph Mirabel +# 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 CNRS-LAAS. 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. + +ADD_REQUIRED_DEPENDENCY("eigenpy >= 1.2") + +SET(LIBRARY_NAME hppfcl) + +INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}" ${PYTHON_INCLUDE_DIRS}) + +ADD_LIBRARY(${LIBRARY_NAME} SHARED + version.cc + math.cc + collision-geometries.cc + collision.cc + distance.cc + fcl.cc) + +TARGET_LINK_BOOST_PYTHON(${LIBRARY_NAME}) +TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${Boost_LIBRARIES}) +TARGET_LINK_LIBRARIES(${LIBRARY_NAME} ${PROJECT_NAME}) +PKG_CONFIG_USE_DEPENDENCY(${LIBRARY_NAME} eigenpy) + +SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES + PREFIX "" + LIBRARY_OUTPUT_NAME ${LIBRARY_NAME}) + +SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES SUFFIX "${PYTHON_EXT_SUFFIX}") + +INSTALL(TARGETS ${LIBRARY_NAME} + DESTINATION ${PYTHON_SITELIB}) diff --git a/python/collision-geometries.cc b/python/collision-geometries.cc new file mode 100644 index 0000000000000000000000000000000000000000..fc604318acd9736acdf852c41dd401b748700d40 --- /dev/null +++ b/python/collision-geometries.cc @@ -0,0 +1,244 @@ +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2019 CNRS-LAAS +// Author: Joseph Mirabel +// 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 CNRS-LAAS. 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. + +#include <boost/python.hpp> + +#include "fcl.hh" + +#include <hpp/fcl/fwd.hh> +#include <hpp/fcl/shape/geometric_shapes.h> +#include <hpp/fcl/shape/convex.h> +#include <hpp/fcl/BVH/BVH_model.h> + +using namespace boost::python; + +using namespace hpp::fcl; +using boost::shared_ptr; +using boost::noncopyable; + +struct BVHModelBaseWrapper +{ + static Vec3f vertices (const BVHModelBase& bvh, int i) + { + if (i >= bvh.num_vertices) throw std::out_of_range("index is out of range"); + return bvh.vertices[i]; + } + + static Triangle tri_indices (const BVHModelBase& bvh, int i) + { + if (i >= bvh.num_tris) throw std::out_of_range("index is out of range"); + return bvh.tri_indices[i]; + } +}; + +template <typename BV> +void exposeBVHModel (const std::string& bvname) +{ + typedef BVHModel<BV> BVHModel_t; + + std::string type = "BVHModel" + bvname; + class_ <BVHModel_t, bases<BVHModelBase>, shared_ptr<BVHModel_t> > + (type.c_str(), init<>()) + ; +} + +struct ConvexBaseWrapper +{ + static Vec3f points (const ConvexBase& convex, int i) + { + if (i >= convex.num_points) throw std::out_of_range("index is out of range"); + return convex.points[i]; + } + + static list neighbors (const ConvexBase& convex, int i) + { + if (i >= convex.num_points) throw std::out_of_range("index is out of range"); + list n; + for (unsigned char j = 0; j < convex.neighbors[i].count(); ++j) + n.append (convex.neighbors[i][j]); + return n; + } +}; + +template <typename PolygonT> +struct ConvexWrapper +{ + typedef Convex<PolygonT> Convex_t; + + static PolygonT polygons (const Convex_t& convex, int i) + { + if (i >= convex.num_polygons) throw std::out_of_range("index is out of range"); + return convex.polygons[i]; + } +}; + +void exposeShapes () +{ + class_ <ShapeBase, bases<CollisionGeometry>, shared_ptr<ShapeBase>, noncopyable> + ("ShapeBase", no_init) + //.def ("getObjectType", &CollisionGeometry::getObjectType) + ; + + class_ <Box, bases<ShapeBase>, shared_ptr<Box> > + ("Box", init<>()) + .def (init<FCL_REAL,FCL_REAL,FCL_REAL>()) + .def (init<Vec3f>()) + .add_property("halfSide", + make_getter(&Box::halfSide, return_value_policy<return_by_value>()), + make_setter(&Box::halfSide, return_value_policy<return_by_value>())); + ; + + class_ <Capsule, bases<ShapeBase>, shared_ptr<Capsule> > + ("Capsule", init<FCL_REAL, FCL_REAL>()) + .def_readwrite ("radius", &Capsule::radius) + .def_readwrite ("halfLength", &Capsule::halfLength) + ; + + class_ <Cone, bases<ShapeBase>, shared_ptr<Cone> > + ("Cone", init<FCL_REAL, FCL_REAL>()) + .def_readwrite ("radius", &Cone::radius) + .def_readwrite ("halfLength", &Cone::halfLength) + ; + + class_ <ConvexBase, bases<ShapeBase>, shared_ptr<ConvexBase >, noncopyable> + ("ConvexBase", no_init) + .def_readonly ("center", &ConvexBase::center) + .def_readonly ("num_points", &ConvexBase::num_points) + .def ("points", &ConvexBaseWrapper::points) + .def ("neighbors", &ConvexBaseWrapper::neighbors) + ; + + class_ <Convex<Triangle>, bases<ConvexBase>, shared_ptr<Convex<Triangle> >, noncopyable> + ("Convex", no_init) + .def_readonly ("num_polygons", &Convex<Triangle>::num_polygons) + .def ("polygons", &ConvexWrapper<Triangle>::polygons) + ; + + class_ <Cylinder, bases<ShapeBase>, shared_ptr<Cylinder> > + ("Cylinder", init<FCL_REAL, FCL_REAL>()) + .def_readwrite ("radius", &Cylinder::radius) + .def_readwrite ("halfLength", &Cylinder::halfLength) + ; + + class_ <Halfspace, bases<ShapeBase>, shared_ptr<Halfspace> > + ("Halfspace", "The half-space is defined by {x | n * x < d}.", init<const Vec3f&, FCL_REAL>()) + .def (init<FCL_REAL,FCL_REAL,FCL_REAL,FCL_REAL>()) + .def (init<>()) + .def_readwrite ("n", &Halfspace::n) + .def_readwrite ("d", &Halfspace::d) + ; + + class_ <Plane, bases<ShapeBase>, shared_ptr<Plane> > + ("Plane", "The plane is defined by {x | n * x = d}.", init<const Vec3f&, FCL_REAL>()) + .def (init<FCL_REAL,FCL_REAL,FCL_REAL,FCL_REAL>()) + .def (init<>()) + .def_readwrite ("n", &Plane::n) + .def_readwrite ("d", &Plane::d) + ; + + class_ <Sphere, bases<ShapeBase>, shared_ptr<Sphere> > + ("Sphere", init<FCL_REAL>()) + .def_readwrite ("radius", &Sphere::radius) + ; + + class_ <TriangleP, bases<ShapeBase>, shared_ptr<TriangleP> > + ("TriangleP", init<const Vec3f&, const Vec3f&, const Vec3f&>()) + .def_readwrite ("a", &TriangleP::a) + .def_readwrite ("b", &TriangleP::b) + .def_readwrite ("c", &TriangleP::c) + ; + +} + +void exposeCollisionGeometries () +{ + enum_<OBJECT_TYPE>("OBJECT_TYPE") + .value ("OT_UNKNOWN", OT_UNKNOWN) + .value ("OT_BVH" , OT_BVH) + .value ("OT_GEOM" , OT_GEOM) + .value ("OT_OCTREE" , OT_OCTREE) + ; + enum_<NODE_TYPE>("NODE_TYPE") + .value ("BV_UNKNOWN", BV_UNKNOWN) + .value ("BV_AABB" , BV_AABB) + .value ("BV_OBB" , BV_OBB) + .value ("BV_RSS" , BV_RSS) + .value ("BV_kIOS" , BV_kIOS) + .value ("BV_OBBRSS", BV_OBBRSS) + .value ("BV_KDOP16", BV_KDOP16) + .value ("BV_KDOP18", BV_KDOP18) + .value ("BV_KDOP24", BV_KDOP24) + .value ("GEOM_BOX" , GEOM_BOX) + .value ("GEOM_SPHERE" , GEOM_SPHERE) + .value ("GEOM_CAPSULE" , GEOM_CAPSULE) + .value ("GEOM_CONE" , GEOM_CONE) + .value ("GEOM_CYLINDER" , GEOM_CYLINDER) + .value ("GEOM_CONVEX" , GEOM_CONVEX) + .value ("GEOM_PLANE" , GEOM_PLANE) + .value ("GEOM_HALFSPACE", GEOM_HALFSPACE) + .value ("GEOM_TRIANGLE" , GEOM_TRIANGLE) + .value ("GEOM_OCTREE" , GEOM_OCTREE) + ; + + class_ <CollisionGeometry, CollisionGeometryPtr_t, noncopyable> + ("CollisionGeometry", no_init) + .def ("getObjectType", &CollisionGeometry::getObjectType) + .def ("getNodeType", &CollisionGeometry::getNodeType) + + .def ("computeLocalAABB", &CollisionGeometry::computeLocalAABB) + + .def ("computeCOM", &CollisionGeometry::computeCOM) + .def ("computeMomentofInertia", &CollisionGeometry::computeMomentofInertia) + .def ("computeVolume", &CollisionGeometry::computeVolume) + .def ("computeMomentofInertiaRelatedToCOM", &CollisionGeometry::computeMomentofInertiaRelatedToCOM) + + .def_readwrite("aabb_radius",&CollisionGeometry::aabb_radius,"AABB radius") + ; + + exposeShapes(); + + class_ <BVHModelBase, bases<CollisionGeometry>, BVHModelPtr_t, noncopyable> + ("BVHModelBase", no_init) + .def ("vertices", &BVHModelBaseWrapper::vertices) + .def ("tri_indices", &BVHModelBaseWrapper::tri_indices) + .def_readonly ("num_vertices", &BVHModelBase::num_vertices) + .def_readonly ("num_tris", &BVHModelBase::num_tris) + + .def_readonly ("convex", &BVHModelBase::convex) + + .def ("buildConvexRepresentation", &BVHModelBase::buildConvexRepresentation) + ; + exposeBVHModel<OBB >("OBB" ); + exposeBVHModel<OBBRSS >("OBBRSS" ); +} diff --git a/python/collision.cc b/python/collision.cc new file mode 100644 index 0000000000000000000000000000000000000000..47be7f5eae7b7f463195fa3bedd509406d63ea89 --- /dev/null +++ b/python/collision.cc @@ -0,0 +1,105 @@ +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2019 CNRS-LAAS +// Author: Joseph Mirabel +// 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 CNRS-LAAS. 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. + +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> + +#include "fcl.hh" + +#include <hpp/fcl/fwd.hh> +#include <hpp/fcl/collision.h> + +using namespace boost::python; + +using namespace hpp::fcl; +using boost::shared_ptr; +using boost::noncopyable; + +void exposeCollisionAPI () +{ + enum_ <CollisionRequestFlag> ("CollisionRequestFlag") + .value ("CONTACT", CONTACT) + .value ("DISTANCE_LOWER_BOUND", DISTANCE_LOWER_BOUND) + .value ("NO_REQUEST", NO_REQUEST) + ; + + class_ <CollisionRequest> ("CollisionRequest", init<>()) + .def (init<CollisionRequestFlag, size_t>()) + + .def_readwrite ("num_max_contacts" , &CollisionRequest::num_max_contacts) + .def_readwrite ("enable_contact" , &CollisionRequest::enable_contact) + .def_readwrite ("enable_distance_lower_bound", &CollisionRequest::enable_distance_lower_bound) + .def_readwrite ("enable_cached_gjk_guess" , &CollisionRequest::enable_cached_gjk_guess) + .def_readwrite ("cached_gjk_guess" , &CollisionRequest::cached_gjk_guess) + .def_readwrite ("security_margin" , &CollisionRequest::security_margin) + .def_readwrite ("break_distance" , &CollisionRequest::break_distance) + ; + + class_ <Contact> ("Contact", init<>()) + //.def(init<CollisionGeometryPtr_t, CollisionGeometryPtr_t, int, int>()) + //.def(init<CollisionGeometryPtr_t, CollisionGeometryPtr_t, int, int, Vec3f, Vec3f, FCL_REAL>()) + .def_readonly ("o1", &Contact::o1) + .def_readonly ("o2", &Contact::o2) + .def_readwrite ("b1", &Contact::b1) + .def_readwrite ("b2", &Contact::b2) + .def_readwrite ("normal", &Contact::normal) + .def_readwrite ("pos", &Contact::pos) + .def_readwrite ("penetration_depth", &Contact::penetration_depth) + .def (self == self) + ; + + class_< std::vector<Contact> >("StdVec_Contact") + .def(vector_indexing_suite< std::vector<Contact> >()) + ; + + class_ <CollisionResult> ("CollisionResult", init<>()) + .def ("isCollision", &CollisionResult::isCollision) + .def ("numContacts", &CollisionResult::numContacts) + .def ("getContact" , &CollisionResult::getContact , return_value_policy<copy_const_reference>()) + .def ("getContacts", &CollisionResult::getContacts, return_internal_reference<>()) + .def ("addContact" , &CollisionResult::addContact ) + .def ("clear", &CollisionResult::clear) + ; + + class_< std::vector<CollisionResult> >("CollisionResult") + .def(vector_indexing_suite< std::vector<CollisionResult> >()) + ; + + def ("collide", static_cast< std::size_t (*)(const CollisionObject*, const CollisionObject*, + const CollisionRequest&, CollisionResult&) > (&collide)); + def ("collide", static_cast< std::size_t (*)( + const CollisionGeometry*, const Transform3f&, + const CollisionGeometry*, const Transform3f&, + const CollisionRequest&, CollisionResult&) > (&collide)); +} diff --git a/python/distance.cc b/python/distance.cc new file mode 100644 index 0000000000000000000000000000000000000000..d7ca2e8f096798c3ada63f15e8745af95a678ec9 --- /dev/null +++ b/python/distance.cc @@ -0,0 +1,87 @@ +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2019 CNRS-LAAS +// Author: Joseph Mirabel +// 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 CNRS-LAAS. 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. + +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> + +#include "fcl.hh" + +#include <hpp/fcl/fwd.hh> +#include <hpp/fcl/distance.h> + +using namespace boost::python; + +using namespace hpp::fcl; +using boost::shared_ptr; +using boost::noncopyable; + +struct DistanceRequestWrapper +{ + static Vec3f getNearestPoint1(const DistanceResult & res) { return res.nearest_points[0]; } + static Vec3f getNearestPoint2(const DistanceResult & res) { return res.nearest_points[1]; } +}; + +void exposeDistanceAPI () +{ + class_ <DistanceRequest> ("DistanceRequest", init<optional<bool,FCL_REAL,FCL_REAL> >()) + .def_readwrite ("enable_nearest_points", &DistanceRequest::enable_nearest_points) + .def_readwrite ("rel_err" , &DistanceRequest::rel_err) + .def_readwrite ("abs_err" , &DistanceRequest::abs_err) + ; + + class_ <DistanceResult> ("DistanceResult", init<>()) + .def_readwrite ("min_distance", &DistanceResult::min_distance) + .def_readwrite ("normal", &DistanceResult::normal) + //.def_readwrite ("nearest_points", &DistanceResult::nearest_points) + .def("getNearestPoint1",&DistanceRequestWrapper::getNearestPoint1) + .def("getNearestPoint2",&DistanceRequestWrapper::getNearestPoint2) + .def_readonly ("o1", &DistanceResult::o1) + .def_readonly ("o2", &DistanceResult::o2) + .def_readwrite ("b1", &DistanceResult::b1) + .def_readwrite ("b2", &DistanceResult::b2) + + .def ("clear", &DistanceResult::clear) + ; + + class_< std::vector<DistanceResult> >("StdVec_DistanceResult") + .def(vector_indexing_suite< std::vector<DistanceResult> >()) + ; + + def ("distance", static_cast< FCL_REAL (*)(const CollisionObject*, const CollisionObject*, + const DistanceRequest&, DistanceResult&) > (&distance)); + def ("distance", static_cast< FCL_REAL (*)( + const CollisionGeometry*, const Transform3f&, + const CollisionGeometry*, const Transform3f&, + const DistanceRequest&, DistanceResult&) > (&distance)); +} diff --git a/python/fcl.cc b/python/fcl.cc new file mode 100644 index 0000000000000000000000000000000000000000..0aa4b104fb09dd6ff8a033237d409bd230483789 --- /dev/null +++ b/python/fcl.cc @@ -0,0 +1,71 @@ +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2019 CNRS-LAAS +// Author: Joseph Mirabel +// 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 CNRS-LAAS. 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. + +#include <boost/python.hpp> + +#include "fcl.hh" + +#include <hpp/fcl/fwd.hh> +#include <hpp/fcl/shape/geometric_shapes.h> +#include <hpp/fcl/BVH/BVH_model.h> + +#include <hpp/fcl/mesh_loader/loader.h> + +#include <hpp/fcl/collision.h> + +using namespace boost::python; + +using namespace hpp::fcl; +using boost::shared_ptr; +using boost::noncopyable; + +void exposeMeshLoader () +{ + class_ <MeshLoader> ("MeshLoader", init< optional< NODE_TYPE> >()) + .def ("load", static_cast <BVHModelPtr_t (MeshLoader::*) (const std::string&, const Vec3f&)> (&MeshLoader::load)) + ; + + class_ <CachedMeshLoader, bases<MeshLoader> > ("CachedMeshLoader", init< optional< NODE_TYPE> >()) + ; +} + +BOOST_PYTHON_MODULE(hppfcl) +{ + exposeVersion(); + exposeMaths(); + exposeCollisionGeometries(); + exposeMeshLoader(); + exposeCollisionAPI(); + exposeDistanceAPI(); +} diff --git a/python/fcl.hh b/python/fcl.hh new file mode 100644 index 0000000000000000000000000000000000000000..f56b9d19ac5b479cfde2b25be9fc4e8ba492c951 --- /dev/null +++ b/python/fcl.hh @@ -0,0 +1,11 @@ +void exposeVersion(); + +void exposeMaths(); + +void exposeCollisionGeometries(); + +void exposeMeshLoader(); + +void exposeCollisionAPI(); + +void exposeDistanceAPI(); diff --git a/python/math.cc b/python/math.cc new file mode 100644 index 0000000000000000000000000000000000000000..0b47a345ce5f938cbea72fb258be5ae67c05c119 --- /dev/null +++ b/python/math.cc @@ -0,0 +1,107 @@ +// +// Software License Agreement (BSD License) +// +// Copyright (c) 2019 CNRS-LAAS +// Author: Joseph Mirabel +// 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 CNRS-LAAS. 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. + +#include <boost/python.hpp> + +#include <eigenpy/eigenpy.hpp> +#include <eigenpy/geometry.hpp> + +#include <hpp/fcl/fwd.hh> +#include <hpp/fcl/math/transform.h> + +#include "fcl.hh" + +using namespace boost::python; + +using namespace hpp::fcl; + +struct TriangleWrapper +{ + static Triangle::index_type getitem (const Triangle& t, int i) + { + if (i >= 3) throw std::out_of_range("index is out of range"); + return t[i]; + } + static void setitem (Triangle& t, int i, Triangle::index_type v) + { + if (i >= 3) throw std::out_of_range("index is out of range"); + t[i] = v; + } +}; + +void exposeMaths () +{ + eigenpy::enableEigenPy(); + + if(!eigenpy::register_symbolic_link_to_registered_type<Eigen::Quaterniond>()) + eigenpy::exposeQuaternion(); + if(!eigenpy::register_symbolic_link_to_registered_type<Eigen::AngleAxisd>()) + eigenpy::exposeAngleAxis(); + + class_ <Transform3f> ("Transform3f", init<>()) + .def (init<Matrix3f, Vec3f>()) + .def (init<Quaternion3f, Vec3f>()) + .def (init<Matrix3f>()) + .def (init<Quaternion3f>()) + .def (init<Vec3f>()) + + .def ("getQuatRotation", &Transform3f::getQuatRotation) + .def ("getTranslation", &Transform3f::getTranslation, return_value_policy<copy_const_reference>()) + .def ("getRotation", &Transform3f::getRotation, return_value_policy<copy_const_reference>()) + .def ("isIdentity", &Transform3f::setIdentity) + + .def ("setQuatRotation", &Transform3f::setQuatRotation) + .def ("setTranslation", &Transform3f::setTranslation<Vec3f>) + .def ("setRotation", &Transform3f::setRotation<Matrix3f>) + .def ("setTransform", &Transform3f::setTransform<Matrix3f,Vec3f>) + .def ("setTransform", static_cast<void (Transform3f::*)(const Quaternion3f&, const Vec3f&)>(&Transform3f::setTransform)) + .def ("setIdentity", &Transform3f::setIdentity) + + .def ("transform", &Transform3f::transform<Vec3f>) + .def ("inverseInPlace", &Transform3f::inverseInPlace, return_internal_reference<>()) + .def ("inverse", &Transform3f::inverse) + .def ("inverseTimes", &Transform3f::inverseTimes) + + .def (self * self) + .def (self *= self) + .def (self == self) + .def (self != self) + ; + + class_ <Triangle> ("Triangle", init<>()) + .def (init <Triangle::index_type, Triangle::index_type, Triangle::index_type>()) + .def ("__getitem__", &TriangleWrapper::getitem) + .def ("__setitem__", &TriangleWrapper::setitem) + ; +} diff --git a/python/version.cc b/python/version.cc new file mode 100644 index 0000000000000000000000000000000000000000..886493d122e5b400699d6f9e376477e067c78017 --- /dev/null +++ b/python/version.cc @@ -0,0 +1,44 @@ +// +// Copyright (c) 2019 CNRS +// + +#include "hpp/fcl/config.hh" +#include <boost/python.hpp> +#include <boost/preprocessor/stringize.hpp> + +namespace bp = boost::python; + +inline bool checkVersionAtLeast(unsigned int major, + unsigned int minor, + unsigned int patch) +{ + return HPP_FCL_VERSION_AT_LEAST(major, minor, patch); +} + +inline bool checkVersionAtMost(unsigned int major, + unsigned int minor, + unsigned int patch) +{ + return HPP_FCL_VERSION_AT_MOST(major, minor, patch); +} + +void exposeVersion() +{ + // Define release numbers of the current hpp-fcl version. + bp::scope().attr("__version__") = BOOST_PP_STRINGIZE(HPP_FCL_MAJOR_VERSION) "." + BOOST_PP_STRINGIZE(HPP_FCL_MINOR_VERSION) "." + BOOST_PP_STRINGIZE(HPP_FCL_PATCH_VERSION); + bp::scope().attr("HPP_FCL_MAJOR_VERSION") = HPP_FCL_MAJOR_VERSION; + bp::scope().attr("HPP_FCL_MINOR_VERSION") = HPP_FCL_MINOR_VERSION; + bp::scope().attr("HPP_FCL_PATCH_VERSION") = HPP_FCL_PATCH_VERSION; + + bp::def("checkVersionAtLeast",&checkVersionAtLeast, + bp::args("major","minor","patch"), + "Checks if the current version of hpp-fcl is at least" + " the version provided by the input arguments."); + + bp::def("checkVersionAtMost",&checkVersionAtMost, + bp::args("major","minor","patch"), + "Checks if the current version of hpp-fcl is at most" + " the version provided by the input arguments."); +} diff --git a/src/BV/AABB.cpp b/src/BV/AABB.cpp index 782e0bc16b778e3a31ad3b92acdd95a1671679a6..e9829aae6756b48c1f554579b8b68dcc37312f44 100644 --- a/src/BV/AABB.cpp +++ b/src/BV/AABB.cpp @@ -38,7 +38,7 @@ #include <hpp/fcl/BV/AABB.h> #include <limits> -#include <iostream> +#include <hpp/fcl/collision_data.h> namespace hpp { @@ -50,6 +50,21 @@ AABB::AABB() : min_(Vec3f::Constant(std::numeric_limits<FCL_REAL>::max())), { } +bool AABB::overlap(const AABB& other, const CollisionRequest& request, + FCL_REAL& sqrDistLowerBound) const +{ + const FCL_REAL breakDistance (request.break_distance + request.security_margin); + const FCL_REAL breakDistance2 = breakDistance * breakDistance; + + sqrDistLowerBound = (min_ - other.max_).array().max(0).matrix().squaredNorm(); + if(sqrDistLowerBound > breakDistance2) return false; + + sqrDistLowerBound = (other.min_ - max_).array().max(0).matrix().squaredNorm(); + if(sqrDistLowerBound > breakDistance2) return false; + + return true; +} + FCL_REAL AABB::distance(const AABB& other, Vec3f* P, Vec3f* Q) const { FCL_REAL result = 0; diff --git a/src/BV/OBB.cpp b/src/BV/OBB.cpp index 4cf4c49d40a16fc032172a6ea66799887a8c7805..98a45f4668fbd81d847f37745575fd166bcedb77 100644 --- a/src/BV/OBB.cpp +++ b/src/BV/OBB.cpp @@ -39,6 +39,7 @@ #include <hpp/fcl/BVH/BVH_utility.h> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/collision_data.h> +#include <hpp/fcl/internal/tools.h> #include <iostream> #include <limits> @@ -294,6 +295,71 @@ bool obbDisjoint(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& } +namespace internal +{ + inline FCL_REAL obbDisjoint_check_A_axis ( + const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf) + { + // |T| - |B| * b - a + Vec3f AABB_corner (T.cwiseAbs () - a); + AABB_corner.noalias() -= Bf.col(0) * b[0]; + AABB_corner.noalias() -= Bf.col(1) * b[1]; + AABB_corner.noalias() -= Bf.col(2) * b[2]; + return AABB_corner.array().max(0).matrix().squaredNorm (); + } + + inline FCL_REAL obbDisjoint_check_B_axis ( + const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf) + { + // Bf = |B| + // | B^T T| - Bf^T * a - b + register FCL_REAL s, t = 0; + s = std::abs(B.col(0).dot(T)) - Bf.col(0).dot(a) - b[0]; + if (s > 0) t += s*s; + s = std::abs(B.col(1).dot(T)) - Bf.col(1).dot(a) - b[1]; + if (s > 0) t += s*s; + s = std::abs(B.col(2).dot(T)) - Bf.col(2).dot(a) - b[2]; + if (s > 0) t += s*s; + return t; + } + + template <int ib, int jb = (ib+1)%3, int kb = (ib+2)%3 > + struct obbDisjoint_check_Ai_cross_Bi + { + static inline bool run (int ia, int ja, int ka, + const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, + const Matrix3f& Bf, + const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib); + + const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) + + b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb)); + // We need to divide by the norm || Aia x Bib || + // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2 + if (diff > 0) { + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + /* // or + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + squaredLowerBoundDistance = diff * diff; + if (squaredLowerBoundDistance > breakDistance2 * sinus2) { + squaredLowerBoundDistance /= sinus2; + return true; + } + // */ + } + return false; + } + }; +} + + // B, T orientation and position of 2nd OBB in frame of 1st OBB, // a extent of 1st OBB, // b extent of 2nd OBB. @@ -301,193 +367,39 @@ bool obbDisjoint(const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& // This function tests whether bounding boxes should be broken down. // bool obbDisjointAndLowerBoundDistance (const Matrix3f& B, const Vec3f& T, - const Vec3f& a, const Vec3f& b, + const Vec3f& a, const Vec3f& b, const CollisionRequest& request, - FCL_REAL& squaredLowerBoundDistance) + FCL_REAL& squaredLowerBoundDistance) { - FCL_REAL t, s; - FCL_REAL diff; - FCL_REAL breakDistance (request.break_distance + request.security_margin); - FCL_REAL breakDistance2 = breakDistance * breakDistance; + const FCL_REAL breakDistance (request.break_distance + request.security_margin); + const FCL_REAL breakDistance2 = breakDistance * breakDistance; - // Matrix3f Bf = abs(B); - // Bf += reps; Matrix3f Bf (B.cwiseAbs()); // Corner of b axis aligned bounding box the closest to the origin - Vec3f AABB_corner (T.cwiseAbs () - Bf * b); - Vec3f diff3 (AABB_corner - a); - diff3 = diff3.cwiseMax (Vec3f::Zero()); - - //for (Vec3f::Index i=0; i<3; ++i) diff3 [i] = std::max (0, diff3 [i]); - squaredLowerBoundDistance = diff3.squaredNorm (); + squaredLowerBoundDistance = internal::obbDisjoint_check_A_axis (T, a, b, Bf); if (squaredLowerBoundDistance > breakDistance2) return true; - AABB_corner = (B.transpose () * T).cwiseAbs () - Bf.transpose () * a; - // diff3 = | B^T T| - b - Bf^T a - diff3 = AABB_corner - b; - diff3 = diff3.cwiseMax (Vec3f::Zero()); - squaredLowerBoundDistance = diff3.squaredNorm (); - + squaredLowerBoundDistance = internal::obbDisjoint_check_B_axis (B, T, a, b, Bf); if (squaredLowerBoundDistance > breakDistance2) return true; - // A0 x B0 - s = T[2] * B(1, 0) - T[1] * B(2, 0); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - FCL_REAL sinus2; - diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + - b[1] * Bf(0, 2) + b[2] * Bf(0, 1)); - // We need to divide by the norm || A0 x B0 || - // As ||A0|| = ||B0|| = 1, - // 2 2 - // || A0 x B0 || + (A0 | B0) = 1 - if (diff > 0) { - sinus2 = 1 - Bf (0,0) * Bf (0,0); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A0 x B1 - s = T[2] * B(1, 1) - T[1] * B(2, 1); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + - b[0] * Bf(0, 2) + b[2] * Bf(0, 0)); - if (diff > 0) { - sinus2 = 1 - Bf (0,1) * Bf (0,1); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A0 x B2 - s = T[2] * B(1, 2) - T[1] * B(2, 2); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + - b[0] * Bf(0, 1) + b[1] * Bf(0, 0)); - if (diff > 0) { - sinus2 = 1 - Bf (0,2) * Bf (0,2); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A1 x B0 - s = T[0] * B(2, 0) - T[2] * B(0, 0); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + - b[1] * Bf(1, 2) + b[2] * Bf(1, 1)); - if (diff > 0) { - sinus2 = 1 - Bf (1,0) * Bf (1,0); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A1 x B1 - s = T[0] * B(2, 1) - T[2] * B(0, 1); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + - b[0] * Bf(1, 2) + b[2] * Bf(1, 0)); - if (diff > 0) { - sinus2 = 1 - Bf (1,1) * Bf (1,1); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A1 x B2 - s = T[0] * B(2, 2) - T[2] * B(0, 2); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + - b[0] * Bf(1, 1) + b[1] * Bf(1, 0)); - if (diff > 0) { - sinus2 = 1 - Bf (1,2) * Bf (1,2); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A2 x B0 - s = T[1] * B(0, 0) - T[0] * B(1, 0); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + - b[1] * Bf(2, 2) + b[2] * Bf(2, 1)); - if (diff > 0) { - sinus2 = 1 - Bf (2,0) * Bf (2,0); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A2 x B1 - s = T[1] * B(0, 1) - T[0] * B(1, 1); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + - b[0] * Bf(2, 2) + b[2] * Bf(2, 0)); - if (diff > 0) { - sinus2 = 1 - Bf (2,1) * Bf (2,1); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } - } - - // A2 x B2 - s = T[1] * B(0, 2) - T[0] * B(1, 2); - t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); - - diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + - b[0] * Bf(2, 1) + b[1] * Bf(2, 0)); - if (diff > 0) { - sinus2 = 1 - Bf (2,2) * Bf (2,2); - if (sinus2 > 1e-6) { - squaredLowerBoundDistance = diff * diff / sinus2; - if (squaredLowerBoundDistance > breakDistance2) { - return true; - } - } + // Ai x Bj + int ja = 1, ka = 2; + for (int ia = 0; ia < 3; ++ia) { + if (internal::obbDisjoint_check_Ai_cross_Bi<0>::run (ia, ja, ka, + B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (internal::obbDisjoint_check_Ai_cross_Bi<1>::run (ia, ja, ka, + B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (internal::obbDisjoint_check_Ai_cross_Bi<2>::run (ia, ja, ka, + B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + ja = ka; ka = ia; } return false; - } - - bool OBB::overlap(const OBB& other) const { /// compute what transform [R,T] that takes us from cs1 to cs2. diff --git a/src/BV/OBBRSS.cpp b/src/BV/OBBRSS.cpp index 5c3c7f830a1363b6cc7286f68815ac620fee8d94..648c1c054145d409635e51cceb9817a0b53de7b2 100644 --- a/src/BV/OBBRSS.cpp +++ b/src/BV/OBBRSS.cpp @@ -42,23 +42,6 @@ namespace hpp namespace fcl { -bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2) -{ - return overlap(R0, T0, b1.obb, b2.obb); -} - -bool overlap(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, - const OBBRSS& b2, const CollisionRequest& request, - FCL_REAL& sqrDistLowerBound) -{ - return overlap(R0, T0, b1.obb, b2.obb, request, sqrDistLowerBound); -} - -FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const OBBRSS& b1, const OBBRSS& b2, Vec3f* P, Vec3f* Q) -{ - return distance(R0, T0, b1.rss, b2.rss, P, Q); -} - OBBRSS translate(const OBBRSS& bv, const Vec3f& t) { OBBRSS res(bv); diff --git a/src/BV/RSS.cpp b/src/BV/RSS.cpp index 0f719bcebdad1f71a2bcbfe2b78005dd164842a9..220e6b449071abe273d4d53b125bdbe2700fc556 100644 --- a/src/BV/RSS.cpp +++ b/src/BV/RSS.cpp @@ -38,6 +38,7 @@ #include <hpp/fcl/BV/RSS.h> #include <hpp/fcl/BVH/BVH_utility.h> #include <iostream> +#include <hpp/fcl/internal/tools.h> namespace hpp { namespace fcl @@ -843,8 +844,8 @@ bool RSS::overlap(const RSS& other) const /// Now compute R1'R2 Matrix3f R (axes.transpose() * other.axes); - FCL_REAL dist = rectDistance(R, T, l, other.l); - return (dist <= (r + other.r)); + FCL_REAL dist = rectDistance(R, T, length, other.length); + return (dist <= (radius + other.radius)); } bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2) @@ -858,8 +859,8 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2) Vec3f T(b1.axes.transpose() * Ttemp); Matrix3f R(b1.axes.transpose() * R0 * b2.axes); - FCL_REAL dist = rectDistance(R, T, b1.l, b2.l); - return (dist <= (b1.r + b2.r)); + FCL_REAL dist = rectDistance(R, T, b1.length, b2.length); + return (dist <= (b1.radius + b2.radius)); } bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2, @@ -875,7 +876,7 @@ bool overlap(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& b2, Vec3f T(b1.axes.transpose() * Ttemp); Matrix3f R(b1.axes.transpose() * R0 * b2.axes); - FCL_REAL dist = rectDistance(R, T, b1.l, b2.l) - b1.r - b2.r; + FCL_REAL dist = rectDistance(R, T, b1.length, b2.length) - b1.radius - b2.radius; if (dist <= 0) return true; sqrDistLowerBound = dist * dist; return false; @@ -892,28 +893,28 @@ bool RSS::contain(const Vec3f& p) const Vec3f proj(proj0, proj1, proj2); /// projection is within the rectangle - if((proj0 < l[0]) && (proj0 > 0) && (proj1 < l[1]) && (proj1 > 0)) + if((proj0 < length[0]) && (proj0 > 0) && (proj1 < length[1]) && (proj1 > 0)) { - return (abs_proj2 < r); + return (abs_proj2 < radius); } - else if((proj0 < l[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > l[1]))) + else if((proj0 < length[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > length[1]))) { - FCL_REAL y = (proj1 > 0) ? l[1] : 0; + FCL_REAL y = (proj1 > 0) ? length[1] : 0; Vec3f v(proj0, y, 0); - return ((proj - v).squaredNorm() < r * r); + return ((proj - v).squaredNorm() < radius * radius); } - else if((proj1 < l[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > l[0]))) + else if((proj1 < length[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > length[0]))) { - FCL_REAL x = (proj0 > 0) ? l[0] : 0; + FCL_REAL x = (proj0 > 0) ? length[0] : 0; Vec3f v(x, proj1, 0); - return ((proj - v).squaredNorm() < r * r); + return ((proj - v).squaredNorm() < radius * radius); } else { - FCL_REAL x = (proj0 > 0) ? l[0] : 0; - FCL_REAL y = (proj1 > 0) ? l[1] : 0; + FCL_REAL x = (proj0 > 0) ? length[0] : 0; + FCL_REAL y = (proj1 > 0) ? length[1] : 0; Vec3f v(x, y, 0); - return ((proj - v).squaredNorm() < r * r); + return ((proj - v).squaredNorm() < radius * radius); } } @@ -927,99 +928,99 @@ RSS& RSS::operator += (const Vec3f& p) Vec3f proj(proj0, proj1, proj2); // projection is within the rectangle - if((proj0 < l[0]) && (proj0 > 0) && (proj1 < l[1]) && (proj1 > 0)) + if((proj0 < length[0]) && (proj0 > 0) && (proj1 < length[1]) && (proj1 > 0)) { - if(abs_proj2 < r) + if(abs_proj2 < radius) ; // do nothing else { - r = 0.5 * (r + abs_proj2); // enlarge the r + radius = 0.5 * (radius + abs_proj2); // enlarge the r // change RSS origin position if(proj2 > 0) - Tr[2] += 0.5 * (abs_proj2 - r); + Tr[2] += 0.5 * (abs_proj2 - radius); else - Tr[2] -= 0.5 * (abs_proj2 - r); + Tr[2] -= 0.5 * (abs_proj2 - radius); } } - else if((proj0 < l[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > l[1]))) + else if((proj0 < length[0]) && (proj0 > 0) && ((proj1 < 0) || (proj1 > length[1]))) { - FCL_REAL y = (proj1 > 0) ? l[1] : 0; + FCL_REAL y = (proj1 > 0) ? length[1] : 0; Vec3f v(proj0, y, 0); FCL_REAL new_r_sqr = (proj - v).squaredNorm(); - if(new_r_sqr < r * r) + if(new_r_sqr < radius * radius) ; // do nothing else { - if(abs_proj2 < r) + if(abs_proj2 < radius) { - FCL_REAL delta_y = - std::sqrt(r * r - proj2 * proj2) + fabs(proj1 - y); - l[1] += delta_y; + FCL_REAL delta_y = - std::sqrt(radius * radius - proj2 * proj2) + fabs(proj1 - y); + length[1] += delta_y; if(proj1 < 0) Tr[1] -= delta_y; } else { FCL_REAL delta_y = fabs(proj1 - y); - l[1] += delta_y; + length[1] += delta_y; if(proj1 < 0) Tr[1] -= delta_y; if(proj2 > 0) - Tr[2] += 0.5 * (abs_proj2 - r); + Tr[2] += 0.5 * (abs_proj2 - radius); else - Tr[2] -= 0.5 * (abs_proj2 - r); + Tr[2] -= 0.5 * (abs_proj2 - radius); } } } - else if((proj1 < l[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > l[0]))) + else if((proj1 < length[1]) && (proj1 > 0) && ((proj0 < 0) || (proj0 > length[0]))) { - FCL_REAL x = (proj0 > 0) ? l[0] : 0; + FCL_REAL x = (proj0 > 0) ? length[0] : 0; Vec3f v(x, proj1, 0); FCL_REAL new_r_sqr = (proj - v).squaredNorm(); - if(new_r_sqr < r * r) + if(new_r_sqr < radius * radius) ; // do nothing else { - if(abs_proj2 < r) + if(abs_proj2 < radius) { - FCL_REAL delta_x = - std::sqrt(r * r - proj2 * proj2) + fabs(proj0 - x); - l[0] += delta_x; + FCL_REAL delta_x = - std::sqrt(radius * radius - proj2 * proj2) + fabs(proj0 - x); + length[0] += delta_x; if(proj0 < 0) Tr[0] -= delta_x; } else { FCL_REAL delta_x = fabs(proj0 - x); - l[0] += delta_x; + length[0] += delta_x; if(proj0 < 0) Tr[0] -= delta_x; if(proj2 > 0) - Tr[2] += 0.5 * (abs_proj2 - r); + Tr[2] += 0.5 * (abs_proj2 - radius); else - Tr[2] -= 0.5 * (abs_proj2 - r); + Tr[2] -= 0.5 * (abs_proj2 - radius); } } } else { - FCL_REAL x = (proj0 > 0) ? l[0] : 0; - FCL_REAL y = (proj1 > 0) ? l[1] : 0; + FCL_REAL x = (proj0 > 0) ? length[0] : 0; + FCL_REAL y = (proj1 > 0) ? length[1] : 0; Vec3f v(x, y, 0); FCL_REAL new_r_sqr = (proj - v).squaredNorm(); - if(new_r_sqr < r * r) + if(new_r_sqr < radius * radius) ; // do nothing else { - if(abs_proj2 < r) + if(abs_proj2 < radius) { FCL_REAL diag = std::sqrt(new_r_sqr - proj2 * proj2); - FCL_REAL delta_diag = - std::sqrt(r * r - proj2 * proj2) + diag; + FCL_REAL delta_diag = - std::sqrt(radius * radius - proj2 * proj2) + diag; FCL_REAL delta_x = delta_diag / diag * fabs(proj0 - x); FCL_REAL delta_y = delta_diag / diag * fabs(proj1 - y); - l[0] += delta_x; - l[1] += delta_y; + length[0] += delta_x; + length[1] += delta_y; if(proj0 < 0 && proj1 < 0) { @@ -1032,8 +1033,8 @@ RSS& RSS::operator += (const Vec3f& p) FCL_REAL delta_x = fabs(proj0 - x); FCL_REAL delta_y = fabs(proj1 - y); - l[0] += delta_x; - l[1] += delta_y; + length[0] += delta_x; + length[1] += delta_y; if(proj0 < 0 && proj1 < 0) { @@ -1042,9 +1043,9 @@ RSS& RSS::operator += (const Vec3f& p) } if(proj2 > 0) - Tr[2] += 0.5 * (abs_proj2 - r); + Tr[2] += 0.5 * (abs_proj2 - radius); else - Tr[2] -= 0.5 * (abs_proj2 - r); + Tr[2] -= 0.5 * (abs_proj2 - radius); } } } @@ -1057,12 +1058,12 @@ RSS RSS::operator + (const RSS& other) const RSS bv; Vec3f v[16]; - Vec3f d0_pos (other.axes.col(0) * (other.l[0] + other.r)); - Vec3f d1_pos (other.axes.col(1) * (other.l[1] + other.r)); - Vec3f d0_neg (other.axes.col(0) * (-other.r)); - Vec3f d1_neg (other.axes.col(1) * (-other.r)); - Vec3f d2_pos (other.axes.col(2) * other.r); - Vec3f d2_neg (other.axes.col(2) * (-other.r)); + Vec3f d0_pos (other.axes.col(0) * (other.length[0] + other.radius)); + Vec3f d1_pos (other.axes.col(1) * (other.length[1] + other.radius)); + Vec3f d0_neg (other.axes.col(0) * (-other.radius)); + Vec3f d1_neg (other.axes.col(1) * (-other.radius)); + Vec3f d2_pos (other.axes.col(2) * other.radius); + Vec3f d2_neg (other.axes.col(2) * (-other.radius)); v[0].noalias() = other.Tr + d0_pos + d1_pos + d2_pos; v[1].noalias() = other.Tr + d0_pos + d1_pos + d2_neg; @@ -1073,12 +1074,12 @@ RSS RSS::operator + (const RSS& other) const v[6].noalias() = other.Tr + d0_neg + d1_neg + d2_pos; v[7].noalias() = other.Tr + d0_neg + d1_neg + d2_neg; - d0_pos.noalias() = axes.col(0) * (l[0] + r); - d1_pos.noalias() = axes.col(1) * (l[1] + r); - d0_neg.noalias() = axes.col(0) * (-r); - d1_neg.noalias() = axes.col(1) * (-r); - d2_pos.noalias() = axes.col(2) * r; - d2_neg.noalias() = axes.col(2) * (-r); + d0_pos.noalias() = axes.col(0) * (length[0] + radius); + d1_pos.noalias() = axes.col(1) * (length[1] + radius); + d0_neg.noalias() = axes.col(0) * (-radius); + d1_neg.noalias() = axes.col(1) * (-radius); + d2_pos.noalias() = axes.col(2) * radius; + d2_neg.noalias() = axes.col(2) * (-radius); v[ 8].noalias() = Tr + d0_pos + d1_pos + d2_pos; v[ 9].noalias() = Tr + d0_pos + d1_pos + d2_neg; @@ -1112,7 +1113,7 @@ RSS RSS::operator + (const RSS& other) const E[0][max]*E[1][mid] - E[0][mid]*E[1][max]; // set rss origin, rectangle size and radius - getRadiusAndOriginAndRectangleSize(v, NULL, NULL, NULL, 16, bv.axes, bv.Tr, bv.l, bv.r); + getRadiusAndOriginAndRectangleSize(v, NULL, NULL, NULL, 16, bv.axes, bv.Tr, bv.length, bv.radius); return bv; } @@ -1125,8 +1126,8 @@ FCL_REAL RSS::distance(const RSS& other, Vec3f* P, Vec3f* Q) const Matrix3f R (axes.transpose() * other.axes); Vec3f T (axes.transpose() * (other.Tr - Tr)); - FCL_REAL dist = rectDistance(R, T, l, other.l, P, Q); - dist -= (r + other.r); + FCL_REAL dist = rectDistance(R, T, length, other.length, P, Q); + dist -= (radius + other.radius); return (dist < (FCL_REAL)0.0) ? (FCL_REAL)0.0 : dist; } @@ -1137,8 +1138,8 @@ FCL_REAL distance(const Matrix3f& R0, const Vec3f& T0, const RSS& b1, const RSS& Vec3f T(b1.axes.transpose() * Ttemp); - FCL_REAL dist = rectDistance(R, T, b1.l, b2.l, P, Q); - dist -= (b1.r + b2.r); + FCL_REAL dist = rectDistance(R, T, b1.length, b2.length, P, Q); + dist -= (b1.radius + b2.radius); return (dist < (FCL_REAL)0.0) ? (FCL_REAL)0.0 : dist; } diff --git a/src/BVH/BVH_model.cpp b/src/BVH/BVH_model.cpp index 58ab55200a01cdbc29b3fc03ff554a8264ca1316..bba163c7457ff844f3060f1c681b56fd11333501 100644 --- a/src/BVH/BVH_model.cpp +++ b/src/BVH/BVH_model.cpp @@ -36,25 +36,28 @@ /** \author Jia Pan */ #include <hpp/fcl/BVH/BVH_model.h> -#include <hpp/fcl/BV/BV.h> + #include <iostream> #include <string.h> +#include <hpp/fcl/BV/BV.h> +#include <hpp/fcl/shape/convex.h> + +#include <hpp/fcl/internal/BV_splitter.h> +#include <hpp/fcl/internal/BV_fitter.h> + namespace hpp { namespace fcl { -template<typename BV> -BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other), - boost::noncopyable(), - 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) +BVHModelBase::BVHModelBase(const BVHModelBase& other) : + CollisionGeometry(other), + num_tris(other.num_tris), + num_vertices(other.num_vertices), + build_state(other.build_state), + num_tris_allocated(other.num_tris), + num_vertices_allocated(other.num_vertices) { if(other.vertices) { @@ -79,7 +82,29 @@ BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other), } else prev_vertices = NULL; +} +void BVHModelBase::buildConvexRepresentation(bool share_memory) +{ + if (!convex) { + Vec3f* points = vertices; + Triangle* polygons = tri_indices; + if (!share_memory) { + points = new Vec3f[num_vertices]; + memcpy(points, vertices, sizeof(Vec3f) * num_vertices); + + polygons = new Triangle[num_tris]; + memcpy(polygons, tri_indices, sizeof(Triangle) * num_tris); + } + convex.reset(new Convex<Triangle>(!share_memory, points, num_vertices, polygons, num_vertices)); + } +} + +template<typename BV> +BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : BVHModelBase(other), + bv_splitter(other.bv_splitter), + bv_fitter(other.bv_fitter) +{ if(other.primitive_indices) { int num_primitives = 0; @@ -112,18 +137,16 @@ BVHModel<BV>::BVHModel(const BVHModel<BV>& other) : CollisionGeometry(other), } -template<typename BV> -int BVHModel<BV>::beginModel(int num_tris_, int num_vertices_) +int BVHModelBase::beginModel(int num_tris_, int num_vertices_) { if(build_state != BVH_BUILD_STATE_EMPTY) { delete [] vertices; vertices = NULL; delete [] tri_indices; tri_indices = NULL; - delete [] bvs; bvs = NULL; delete [] prev_vertices; prev_vertices = NULL; - delete [] primitive_indices; primitive_indices = NULL; - num_vertices_allocated = num_vertices = num_tris_allocated = num_tris = num_bvs_allocated = num_bvs = 0; + num_vertices_allocated = num_vertices = num_tris_allocated = num_tris = 0; + deleteBVs(); } if(num_tris_ <= 0) num_tris_ = 8; @@ -158,9 +181,7 @@ int BVHModel<BV>::beginModel(int num_tris_, int num_vertices_) return BVH_OK; } - -template<typename BV> -int BVHModel<BV>::addVertex(const Vec3f& p) +int BVHModelBase::addVertex(const Vec3f& p) { if(build_state != BVH_BUILD_STATE_BEGUN) { @@ -189,8 +210,7 @@ int BVHModel<BV>::addVertex(const Vec3f& p) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) +int BVHModelBase::addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) { if(build_state == BVH_BUILD_STATE_PROCESSED) { @@ -243,8 +263,7 @@ int BVHModel<BV>::addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps) +int BVHModelBase::addSubModel(const std::vector<Vec3f>& ps) { if(build_state == BVH_BUILD_STATE_PROCESSED) { @@ -278,8 +297,7 @@ int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps, const std::vector<Triangle>& ts) +int BVHModelBase::addSubModel(const std::vector<Vec3f>& ps, const std::vector<Triangle>& ts) { if(build_state == BVH_BUILD_STATE_PROCESSED) { @@ -340,8 +358,7 @@ int BVHModel<BV>::addSubModel(const std::vector<Vec3f>& ps, const std::vector<Tr return BVH_OK; } -template<typename BV> -int BVHModel<BV>::endModel() +int BVHModelBase::endModel() { if(build_state != BVH_BUILD_STATE_BEGUN) { @@ -383,24 +400,9 @@ int BVHModel<BV>::endModel() num_vertices_allocated = num_vertices; } - // construct BVH tree - int num_bvs_to_be_allocated = 0; - if(num_tris == 0) - num_bvs_to_be_allocated = 2 * num_vertices - 1; - else - num_bvs_to_be_allocated = 2 * num_tris - 1; - - - bvs = new BVNode<BV> [num_bvs_to_be_allocated]; - primitive_indices = new unsigned int [num_bvs_to_be_allocated]; - if(!bvs || !primitive_indices) - { - std::cerr << "BVH Error! Out of memory for BV array in endModel()!" << std::endl; + if (!allocateBVs ()) return BVH_ERR_MODEL_OUT_OF_MEMORY; - } - num_bvs_allocated = num_bvs_to_be_allocated; - num_bvs = 0; buildTree(); @@ -412,8 +414,7 @@ int BVHModel<BV>::endModel() -template<typename BV> -int BVHModel<BV>::beginReplaceModel() +int BVHModelBase::beginReplaceModel() { if(build_state != BVH_BUILD_STATE_PROCESSED) { @@ -421,7 +422,8 @@ int BVHModel<BV>::beginReplaceModel() return BVH_ERR_BUILD_EMPTY_PREVIOUS_FRAME; } - if(prev_vertices) delete [] prev_vertices; prev_vertices = NULL; + if(prev_vertices) delete [] prev_vertices; + prev_vertices = NULL; num_vertex_updated = 0; @@ -430,8 +432,7 @@ int BVHModel<BV>::beginReplaceModel() return BVH_OK; } -template<typename BV> -int BVHModel<BV>::replaceVertex(const Vec3f& p) +int BVHModelBase::replaceVertex(const Vec3f& p) { if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN) { @@ -445,8 +446,7 @@ int BVHModel<BV>::replaceVertex(const Vec3f& p) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) +int BVHModelBase::replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) { if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN) { @@ -460,8 +460,7 @@ int BVHModel<BV>::replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& return BVH_OK; } -template<typename BV> -int BVHModel<BV>::replaceSubModel(const std::vector<Vec3f>& ps) +int BVHModelBase::replaceSubModel(const std::vector<Vec3f>& ps) { if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN) { @@ -477,8 +476,7 @@ int BVHModel<BV>::replaceSubModel(const std::vector<Vec3f>& ps) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::endReplaceModel(bool refit, bool bottomup) +int BVHModelBase::endReplaceModel(bool refit, bool bottomup) { if(build_state != BVH_BUILD_STATE_REPLACE_BEGUN) { @@ -510,8 +508,7 @@ int BVHModel<BV>::endReplaceModel(bool refit, bool bottomup) -template<typename BV> -int BVHModel<BV>::beginUpdateModel() +int BVHModelBase::beginUpdateModel() { if(build_state != BVH_BUILD_STATE_PROCESSED && build_state != BVH_BUILD_STATE_UPDATED) { @@ -538,8 +535,7 @@ int BVHModel<BV>::beginUpdateModel() return BVH_OK; } -template<typename BV> -int BVHModel<BV>::updateVertex(const Vec3f& p) +int BVHModelBase::updateVertex(const Vec3f& p) { if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN) { @@ -553,8 +549,7 @@ int BVHModel<BV>::updateVertex(const Vec3f& p) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) +int BVHModelBase::updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) { if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN) { @@ -568,8 +563,7 @@ int BVHModel<BV>::updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& return BVH_OK; } -template<typename BV> -int BVHModel<BV>::updateSubModel(const std::vector<Vec3f>& ps) +int BVHModelBase::updateSubModel(const std::vector<Vec3f>& ps) { if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN) { @@ -585,8 +579,7 @@ int BVHModel<BV>::updateSubModel(const std::vector<Vec3f>& ps) return BVH_OK; } -template<typename BV> -int BVHModel<BV>::endUpdateModel(bool refit, bool bottomup) +int BVHModelBase::endUpdateModel(bool refit, bool bottomup) { if(build_state != BVH_BUILD_STATE_UPDATE_BEGUN) { @@ -621,6 +614,72 @@ int BVHModel<BV>::endUpdateModel(bool refit, bool bottomup) +void BVHModelBase::computeLocalAABB() +{ + AABB aabb_; + for(int i = 0; i < num_vertices; ++i) + { + aabb_ += vertices[i]; + } + + aabb_center = aabb_.center(); + + aabb_radius = 0; + for(int i = 0; i < num_vertices; ++i) + { + FCL_REAL r = (aabb_center - vertices[i]).squaredNorm(); + if(r > aabb_radius) aabb_radius = r; + } + + aabb_radius = sqrt(aabb_radius); + + aabb_local = aabb_; +} + + + /// @brief Constructing an empty BVH +template<typename BV> +BVHModel<BV>::BVHModel() : + BVHModelBase (), + bv_splitter(new BVSplitter<BV>(SPLIT_METHOD_MEAN)), + bv_fitter(new BVFitter<BV>()), + num_bvs_allocated(0), + primitive_indices(NULL), + bvs(NULL), + num_bvs(0) +{ +} + +template<typename BV> +void BVHModel<BV>::deleteBVs() +{ + delete [] bvs; bvs = NULL; + delete [] primitive_indices; primitive_indices = NULL; + num_bvs_allocated = num_bvs = 0; +} + +template<typename BV> +bool BVHModel<BV>::allocateBVs() +{ + // construct BVH tree + int num_bvs_to_be_allocated = 0; + if(num_tris == 0) + num_bvs_to_be_allocated = 2 * num_vertices - 1; + else + num_bvs_to_be_allocated = 2 * num_tris - 1; + + + bvs = new BVNode<BV> [num_bvs_to_be_allocated]; + primitive_indices = new unsigned int [num_bvs_to_be_allocated]; + if(!bvs || !primitive_indices) + { + std::cerr << "BVH Error! Out of memory for BV array in endModel()!" << std::endl; + return false; + } + num_bvs_allocated = num_bvs_to_be_allocated; + num_bvs = 0; + return true; +} template<typename BV> int BVHModel<BV>::memUsage(int msg) const @@ -642,7 +701,6 @@ int BVHModel<BV>::memUsage(int msg) const return BVH_OK; } - template<typename BV> int BVHModel<BV>::buildTree() { @@ -765,8 +823,14 @@ int BVHModel<BV>::refitTree(bool bottomup) template<typename BV> int BVHModel<BV>::refitTree_bottomup() { + // TODO the recomputation of the BV is done manually, without using + // bv_fitter. The manual BV recomputation seems bugged. Using bv_fitter + // seems to correct the bug. + //bv_fitter->set(vertices, tri_indices, getModelType()); + int res = recursiveRefitTree_bottomup(0); + //bv_fitter->clear(); return res; } @@ -813,6 +877,9 @@ int BVHModel<BV>::recursiveRefitTree_bottomup(int bv_id) } else { + //TODO use bv_fitter to build BV. See comment in refitTree_bottomup + //unsigned int* cur_primitive_indices = primitive_indices + bvnode->first_primitive; + //bv = bv_fitter->fit(cur_primitive_indices, bvnode->num_primitives); Vec3f v[3]; for(int i = 0; i < 3; ++i) { @@ -835,6 +902,9 @@ int BVHModel<BV>::recursiveRefitTree_bottomup(int bv_id) recursiveRefitTree_bottomup(bvnode->leftChild()); recursiveRefitTree_bottomup(bvnode->rightChild()); bvnode->bv = bvs[bvnode->leftChild()].bv + bvs[bvnode->rightChild()].bv; + //TODO use bv_fitter to build BV. See comment in refitTree_bottomup + //unsigned int* cur_primitive_indices = primitive_indices + bvnode->first_primitive; + //bvnode->bv = bv_fitter->fit(cur_primitive_indices, bvnode->num_primitives); } return BVH_OK; @@ -855,29 +925,6 @@ int BVHModel<BV>::refitTree_topdown() return BVH_OK; } -template<typename BV> -void BVHModel<BV>::computeLocalAABB() -{ - AABB aabb_; - for(int i = 0; i < num_vertices; ++i) - { - aabb_ += vertices[i]; - } - - aabb_center = aabb_.center(); - - aabb_radius = 0; - for(int i = 0; i < num_vertices; ++i) - { - FCL_REAL r = (aabb_center - vertices[i]).squaredNorm(); - if(r > aabb_radius) aabb_radius = r; - } - - aabb_radius = sqrt(aabb_radius); - - aabb_local = aabb_; -} - template<> void BVHModel<OBB>::makeParentRelativeRecurse(int bv_id, Matrix3f& parent_axes, const Vec3f& parent_c) @@ -988,11 +1035,6 @@ NODE_TYPE BVHModel<KDOP<24> >::getNodeType() const return BV_KDOP24; } - - - - - template class BVHModel<KDOP<16> >; template class BVHModel<KDOP<18> >; template class BVHModel<KDOP<24> >; @@ -1001,6 +1043,7 @@ template class BVHModel<AABB>; template class BVHModel<RSS>; template class BVHModel<kIOS>; template class BVHModel<OBBRSS>; -} + +} // namespace fcl } // namespace hpp diff --git a/src/BVH/BVH_utility.cpp b/src/BVH/BVH_utility.cpp index 4c343906021f13f3ead41c3ddc040bebc1430c71..c408fc613aeb351e46037a2e0adcf00b47ea2ccc 100644 --- a/src/BVH/BVH_utility.cpp +++ b/src/BVH/BVH_utility.cpp @@ -45,80 +45,18 @@ namespace hpp namespace fcl { -void BVHExpand(BVHModel<OBB>& model, const Variance3f* ucs, FCL_REAL r = 1.0) -{ - for(int i = 0; i < model.getNumBVs(); ++i) - { - BVNode<OBB>& bvnode = model.getBV(i); - - Vec3f* vs = new Vec3f[bvnode.num_primitives * 6]; - - for(int j = 0; j < bvnode.num_primitives; ++j) - { - int v_id = bvnode.first_primitive + j; - const Variance3f& uc = ucs[v_id]; - - Vec3f&v = model.vertices[bvnode.first_primitive + j]; - - for(int k = 0; k < 3; ++k) - { - vs[6 * j + 2 * k] = v + uc.axis[k] * (r * uc.sigma[k]); - vs[6 * j + 2 * k + 1] = v - uc.axis[k] * (r * uc.sigma[k]); - } - } - - OBB bv; - fit(vs, bvnode.num_primitives * 6, bv); - - delete [] vs; - - bvnode.bv = bv; - } -} - -void BVHExpand(BVHModel<RSS>& model, const Variance3f* ucs, FCL_REAL r = 1.0) -{ - for(int i = 0; i < model.getNumBVs(); ++i) - { - BVNode<RSS>& bvnode = model.getBV(i); - - Vec3f* vs = new Vec3f[bvnode.num_primitives * 6]; - - for(int j = 0; j < bvnode.num_primitives; ++j) - { - int v_id = bvnode.first_primitive + j; - const Variance3f& uc = ucs[v_id]; - - Vec3f&v = model.vertices[bvnode.first_primitive + j]; - - for(int k = 0; k < 3; ++k) - { - vs[6 * j + 2 * k] = v + uc.axis[k] * (r * uc.sigma[k]); - vs[6 * j + 2 * k + 1] = v - uc.axis[k] * (r * uc.sigma[k]); - } - } - - RSS bv; - fit(vs, bvnode.num_primitives * 6, bv); - - delete [] vs; - - bvnode.bv = bv; - } -} - template<typename BV> BVHModel<BV>* BVHExtract(const BVHModel<BV>& model, const Transform3f& pose, const AABB& _aabb) { assert(model.getModelType() == BVH_MODEL_TRIANGLES); - const Quaternion3f& q = pose.getQuatRotation(); + const Matrix3f& q = pose.getRotation(); AABB aabb = translate (_aabb, - pose.getTranslation()); Transform3f box_pose; Box box; constructBox(_aabb, box, box_pose); box_pose = pose.inverseTimes (box_pose); - GJKSolver_indep gjk; + GJKSolver gjk; // Check what triangles should be kept. // TODO use the BV hierarchy @@ -280,7 +218,7 @@ void getCovariance(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, i } -/** \brief Compute the RSS bounding volume parameters: radius, rectangle size and the origin. +/** @brief Compute the RSS bounding volume parameters: radius, rectangle size and the origin. * The bounding volume axes are known. */ void getRadiusAndOriginAndRectangleSize(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, const Matrix3f& axes, Vec3f& origin, FCL_REAL l[2], FCL_REAL& r) @@ -561,7 +499,7 @@ void getRadiusAndOriginAndRectangleSize(Vec3f* ps, Vec3f* ps2, Triangle* ts, uns } -/** \brief Compute the bounding volume extent and center for a set or subset of points. +/** @brief Compute the bounding volume extent and center for a set or subset of points. * The bounding volume axes are known. */ static inline void getExtentAndCenter_pointcloud(Vec3f* ps, Vec3f* ps2, unsigned int* indices, int n, Matrix3f& axes, Vec3f& center, Vec3f& extent) @@ -606,7 +544,7 @@ static inline void getExtentAndCenter_pointcloud(Vec3f* ps, Vec3f* ps2, unsigned } -/** \brief Compute the bounding volume extent and center for a set or subset of points. +/** @brief Compute the bounding volume extent and center for a set or subset of points. * The bounding volume axes are known. */ static inline void getExtentAndCenter_mesh(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Matrix3f& axes, Vec3f& center, Vec3f& extent) diff --git a/src/BVH/BV_fitter.cpp b/src/BVH/BV_fitter.cpp index e27b76fc8e5950fef5d1c2b6b14b0b7403393b2a..aeed105d9b2f9f5ccb50b9c8b18dde114d790718 100644 --- a/src/BVH/BV_fitter.cpp +++ b/src/BVH/BV_fitter.cpp @@ -35,9 +35,10 @@ /** \author Jia Pan */ -#include <hpp/fcl/BVH/BV_fitter.h> +#include <hpp/fcl/internal/BV_fitter.h> #include <hpp/fcl/BVH/BVH_utility.h> #include <limits> +#include <hpp/fcl/internal/tools.h> namespace hpp { @@ -149,9 +150,9 @@ void fit1(Vec3f* ps, RSS& bv) { bv.Tr.noalias() = ps[0]; bv.axes.setIdentity(); - bv.l[0] = 0; - bv.l[1] = 0; - bv.r = 0; + bv.length[0] = 0; + bv.length[1] = 0; + bv.radius = 0; } void fit2(Vec3f* ps, RSS& bv) @@ -163,11 +164,11 @@ void fit2(Vec3f* ps, RSS& bv) bv.axes.col(0) /= len_p1p2; generateCoordinateSystem(bv.axes.col(0), bv.axes.col(1), bv.axes.col(2)); - bv.l[0] = len_p1p2; - bv.l[1] = 0; + bv.length[0] = len_p1p2; + bv.length[1] = 0; bv.Tr = p2; - bv.r = 0; + bv.radius = 0; } void fit3(Vec3f* ps, RSS& bv) @@ -192,7 +193,7 @@ void fit3(Vec3f* ps, RSS& bv) bv.axes.col(0).noalias() = e[imax].normalized(); bv.axes.col(1).noalias() = bv.axes.col(2).cross(bv.axes.col(0)); - getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, 3, bv.axes, bv.Tr, bv.l, bv.r); + getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, 3, bv.axes, bv.Tr, bv.length, bv.radius); } void fit6(Vec3f* ps, RSS& bv) @@ -214,7 +215,7 @@ void fitn(Vec3f* ps, int n, RSS& bv) axisFromEigen(E, s, bv.axes); // set rss origin, rectangle size and radius - getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, n, bv.axes, bv.Tr, bv.l, bv.r); + getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, n, bv.axes, bv.Tr, bv.length, bv.radius); } } @@ -433,7 +434,6 @@ void fit(Vec3f* ps, int n, OBB& bv) } } - template<> void fit(Vec3f* ps, int n, RSS& bv) { @@ -491,6 +491,16 @@ void fit(Vec3f* ps, int n, OBBRSS& bv) } } +template<> +void fit(Vec3f* ps, int n, AABB& bv) +{ + if (n <= 0) return; + bv = AABB (ps[0]); + for(int i = 1; i < n; ++i) + { + bv += ps[i]; + } +} OBB BVFitter<OBB>::fit(unsigned int* primitive_indices, int num_primitives) { @@ -532,9 +542,9 @@ OBBRSS BVFitter<OBBRSS>::fit(unsigned int* primitive_indices, int num_primitives getRadiusAndOriginAndRectangleSize(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.rss.axes, origin, l, r); bv.rss.Tr = origin; - bv.rss.l[0] = l[0]; - bv.rss.l[1] = l[1]; - bv.rss.r = r; + bv.rss.length[0] = l[0]; + bv.rss.length[1] = l[1]; + bv.rss.radius = r; return bv; } @@ -558,15 +568,14 @@ RSS BVFitter<RSS>::fit(unsigned int* primitive_indices, int num_primitives) getRadiusAndOriginAndRectangleSize(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.axes, origin, l, r); bv.Tr = origin; - bv.l[0] = l[0]; - bv.l[1] = l[1]; - bv.r = r; + bv.length[0] = l[0]; + bv.length[1] = l[1]; + bv.radius = r; return bv; } - kIOS BVFitter<kIOS>::fit(unsigned int* primitive_indices, int num_primitives) { kIOS bv; @@ -637,6 +646,47 @@ kIOS BVFitter<kIOS>::fit(unsigned int* primitive_indices, int num_primitives) return bv; } +AABB BVFitter<AABB>::fit(unsigned int* primitive_indices, int num_primitives) +{ + AABB bv; + if (num_primitives == 0) return bv; + + if(type == BVH_MODEL_TRIANGLES) /// The primitive is triangle + { + Triangle t0 = tri_indices[primitive_indices[0]]; + bv = AABB (vertices[t0[0]]); + + for(int i = 0; i < num_primitives; ++i) + { + Triangle t = tri_indices[primitive_indices[i]]; + bv += vertices[t[0]]; + bv += vertices[t[1]]; + bv += vertices[t[2]]; + + if(prev_vertices) /// can fitting both current and previous frame + { + bv += prev_vertices[t[0]]; + bv += prev_vertices[t[1]]; + bv += prev_vertices[t[2]]; + } + } + return bv; + } + else if(type == BVH_MODEL_POINTCLOUD) /// The primitive is point + { + bv = AABB (vertices[primitive_indices[0]]); + for(int i = 0; i < num_primitives; ++i) + { + bv += vertices[primitive_indices[i]]; + + if(prev_vertices) /// can fitting both current and previous frame + { + bv += prev_vertices[primitive_indices[i]]; + } + } + } + return bv; +} } diff --git a/src/BVH/BV_splitter.cpp b/src/BVH/BV_splitter.cpp index 1674cef4a88b52ba85bb5c64f166efa20063f112..bb5ac2e80034c6f3e5dc6548f121fd10aeb67a0b 100644 --- a/src/BVH/BV_splitter.cpp +++ b/src/BVH/BV_splitter.cpp @@ -35,7 +35,7 @@ /** \author Jia Pan */ -#include <hpp/fcl/BVH/BV_splitter.h> +#include <hpp/fcl/internal/BV_splitter.h> namespace hpp { diff --git a/src/collision.cpp b/src/collision.cpp index a5e5bb81edb26769d07e05190a814b0c4007dca9..b07f2b5d69292b1f64488533b23a1ef8aa8de857 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -47,23 +47,12 @@ namespace hpp namespace fcl { -template<typename GJKSolver> -CollisionFunctionMatrix<GJKSolver>& getCollisionFunctionLookTable() +CollisionFunctionMatrix& getCollisionFunctionLookTable() { - static CollisionFunctionMatrix<GJKSolver> table; + static CollisionFunctionMatrix table; return table; } -template<typename NarrowPhaseSolver> -std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, - const NarrowPhaseSolver* nsolver, - const CollisionRequest& request, - CollisionResult& result) -{ - return collide(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), - nsolver, request, result); -} - // reorder collision results in the order the call has been made. void invertResults(CollisionResult& result) { @@ -81,18 +70,17 @@ void invertResults(CollisionResult& result) } } -template<typename NarrowPhaseSolver> std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver_, + const GJKSolver* nsolver_, const CollisionRequest& request, CollisionResult& result) { - const NarrowPhaseSolver* nsolver = nsolver_; + const GJKSolver* nsolver = nsolver_; if(!nsolver_) - nsolver = new NarrowPhaseSolver(); + nsolver = new GJKSolver(); - const CollisionFunctionMatrix<NarrowPhaseSolver>& looktable = getCollisionFunctionLookTable<NarrowPhaseSolver>(); + const CollisionFunctionMatrix& looktable = getCollisionFunctionLookTable(); result.distance_lower_bound = -1; std::size_t res; if(request.num_max_contacts == 0) @@ -138,6 +126,14 @@ std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, return res; } +std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, + const GJKSolver* nsolver, + const CollisionRequest& request, + CollisionResult& result) +{ + return collide(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), nsolver, request, result); +} + std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, const CollisionRequest& request, CollisionResult& result) { @@ -145,8 +141,8 @@ std::size_t collide(const CollisionObject* o1, const CollisionObject* o2, { case GST_INDEP: { - GJKSolver_indep solver; - return collide<GJKSolver_indep>(o1, o2, &solver, request, result); + GJKSolver solver; + return collide(o1, o2, &solver, request, result); } default: return -1; // error @@ -161,8 +157,8 @@ std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, { case GST_INDEP: { - GJKSolver_indep solver; - return collide<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result); + GJKSolver solver; + return collide(o1, tf1, o2, tf2, &solver, request, result); } default: std::cerr << "Warning! Invalid GJK solver" << std::endl; diff --git a/src/collision_func_matrix.cpp b/src/collision_func_matrix.cpp index 91b4116748d6b67472cb69629281188309040bf8..efffb50c2394f05a55136bb80247c8fc9da075aa 100644 --- a/src/collision_func_matrix.cpp +++ b/src/collision_func_matrix.cpp @@ -38,10 +38,11 @@ #include <hpp/fcl/collision_func_matrix.h> -#include <hpp/fcl/traversal/traversal_node_setup.h> -#include <hpp/fcl/collision_node.h> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include <../src/collision_node.h> #include <hpp/fcl/narrowphase/narrowphase.h> -#include "distance_func_matrix.h" +#include <../src/distance_func_matrix.h> +#include <../src/traits_traversal.h> namespace hpp { @@ -49,106 +50,36 @@ namespace fcl { #ifdef HPP_FCL_HAVE_OCTOMAP -template<typename T_SH, typename NarrowPhaseSolver> -std::size_t ShapeOcTreeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - const CollisionRequest& request, CollisionResult& result) -{ - if(request.isSatisfied(result)) return result.numContacts(); - - ShapeOcTreeCollisionTraversalNode<T_SH, NarrowPhaseSolver> node (request); - const T_SH* obj1 = static_cast<const T_SH*>(o1); - const OcTree* obj2 = static_cast<const OcTree*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result); - collide(&node, request, result); - - return result.numContacts(); -} - -template<typename T_SH, typename NarrowPhaseSolver> -std::size_t OcTreeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, +template<typename TypeA, typename TypeB> +std::size_t Collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { if(request.isSatisfied(result)) return result.numContacts(); - OcTreeShapeCollisionTraversalNode<T_SH, NarrowPhaseSolver> node (request); - const OcTree* obj1 = static_cast<const OcTree*>(o1); - const T_SH* obj2 = static_cast<const T_SH*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result); - collide(&node, request, result); - - return result.numContacts(); -} - -template<typename NarrowPhaseSolver> -std::size_t OcTreeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - const CollisionRequest& request, CollisionResult& result) -{ - if(request.isSatisfied(result)) return result.numContacts(); - - OcTreeCollisionTraversalNode<NarrowPhaseSolver> node (request); - const OcTree* obj1 = static_cast<const OcTree*>(o1); - const OcTree* obj2 = static_cast<const OcTree*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result); - collide(&node, request, result); - - return result.numContacts(); -} - -template<typename T_BVH, typename NarrowPhaseSolver> -std::size_t OcTreeBVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - const CollisionRequest& request, CollisionResult& result) -{ - if(request.isSatisfied(result)) return result.numContacts(); - - OcTreeMeshCollisionTraversalNode<T_BVH, NarrowPhaseSolver> node (request); - const OcTree* obj1 = static_cast<const OcTree*>(o1); - const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); + typename TraversalTraitsCollision<TypeA, TypeB>::CollisionTraversal_t node (request); + const TypeA* obj1 = dynamic_cast<const TypeA*>(o1); + const TypeB* obj2 = dynamic_cast<const TypeB*>(o2); + OcTreeSolver otsolver(nsolver); initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result); collide(&node, request, result); - return result.numContacts(); -} - -template<typename T_BVH, typename NarrowPhaseSolver> -std::size_t BVHOcTreeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - const CollisionRequest& request, CollisionResult& result) -{ - if(request.isSatisfied(result)) return result.numContacts(); - - MeshOcTreeCollisionTraversalNode<T_BVH, NarrowPhaseSolver> node (request); - const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>*>(o1); - const OcTree* obj2 = static_cast<const OcTree*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, result); - collide(&node, request, result); return result.numContacts(); } - #endif -template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver> +template<typename T_SH1, typename T_SH2> std::size_t ShapeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { if(request.isSatisfied(result)) return result.numContacts(); DistanceResult distanceResult; DistanceRequest distanceRequest (request.enable_contact); - FCL_REAL distance = ShapeShapeDistance <T_SH1, T_SH2, NarrowPhaseSolver> + FCL_REAL distance = ShapeShapeDistance <T_SH1, T_SH2> (o1, tf1, o2, tf2, nsolver, distanceRequest, distanceResult); if (distance <= 0) { @@ -179,35 +110,12 @@ std::size_t ShapeShapeCollide(const CollisionGeometry* o1, const Transform3f& tf return 0; } -template<typename T_BVH, typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeCollider -{ - static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, - const CollisionRequest& request, CollisionResult& result) - { - if(request.isSatisfied(result)) return result.numContacts(); - - MeshShapeCollisionTraversalNode<T_BVH, T_SH, NarrowPhaseSolver> node (request); - const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1); - BVHModel<T_BVH>* obj1_tmp = new BVHModel<T_BVH>(*obj1); - Transform3f tf1_tmp = tf1; - const T_SH* obj2 = static_cast<const T_SH*>(o2); - - initialize(node, *obj1_tmp, tf1_tmp, *obj2, tf2, nsolver, result); - fcl::collide(&node, request, result); - - delete obj1_tmp; - return result.numContacts(); - } -}; - namespace details { -template<typename OrientMeshShapeCollisionTraveralNode, typename T_BVH, typename T_SH, typename NarrowPhaseSolver> +template<typename OrientMeshShapeCollisionTraveralNode, typename T_BVH, typename T_SH> std::size_t orientedBVHShapeCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { if(request.isSatisfied(result)) return result.numContacts(); @@ -224,53 +132,94 @@ std::size_t orientedBVHShapeCollide(const CollisionGeometry* o1, const Transform } -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeCollider<OBB, T_SH, NarrowPhaseSolver> +template<typename T_BVH, typename T_SH> +struct BVHShapeCollider +{ + static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, + const GJKSolver* nsolver, + const CollisionRequest& request, CollisionResult& result) + { + if(request.isSatisfied(result)) return result.numContacts(); + + MeshShapeCollisionTraversalNode<T_BVH, T_SH> node (request); + const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1); + BVHModel<T_BVH>* obj1_tmp = new BVHModel<T_BVH>(*obj1); + Transform3f tf1_tmp = tf1; + const T_SH* obj2 = static_cast<const T_SH*>(o2); + + initialize(node, *obj1_tmp, tf1_tmp, *obj2, tf2, nsolver, result); + fcl::collide(&node, request, result); + + delete obj1_tmp; + return result.numContacts(); + } +}; + +template<typename T_SH> +struct BVHShapeCollider<OBB, T_SH> { static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { - return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBB<T_SH, NarrowPhaseSolver>, OBB, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBB<T_SH>, OBB, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeCollider<RSS, T_SH, NarrowPhaseSolver> +template<typename T_SH> +struct BVHShapeCollider<RSS, T_SH> { static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { - return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeRSS<T_SH, NarrowPhaseSolver>, RSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeRSS<T_SH>, RSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeCollider<kIOS, T_SH, NarrowPhaseSolver> +template<typename T_SH> +struct BVHShapeCollider<kIOS, T_SH> { static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { - return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodekIOS<T_SH, NarrowPhaseSolver>, kIOS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodekIOS<T_SH>, kIOS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeCollider<OBBRSS, T_SH, NarrowPhaseSolver> +template<typename T_SH> +struct BVHShapeCollider<OBBRSS, T_SH> { static std::size_t collide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result) { - return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBBRSS<T_SH, NarrowPhaseSolver>, OBBRSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeCollide<MeshShapeCollisionTraversalNodeOBBRSS<T_SH>, OBBRSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; +namespace details +{ +template<typename OrientedMeshCollisionTraversalNode, typename T_BVH> +std::size_t orientedMeshCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result) +{ + if(request.isSatisfied(result)) return result.numContacts(); + + OrientedMeshCollisionTraversalNode node (request); + const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1); + const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>* >(o2); + + initialize(node, *obj1, tf1, *obj2, tf2, result); + collide(&node, request, result); + + return result.numContacts(); +} + +} template<typename T_BVH> std::size_t BVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result) @@ -294,25 +243,6 @@ std::size_t BVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, cons return result.numContacts(); } -namespace details -{ -template<typename OrientedMeshCollisionTraversalNode, typename T_BVH> -std::size_t orientedMeshCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result) -{ - if(request.isSatisfied(result)) return result.numContacts(); - - OrientedMeshCollisionTraversalNode node (request); - const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1); - const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>* >(o2); - - initialize(node, *obj1, tf1, *obj2, tf2, result); - collide(&node, request, result); - - return result.numContacts(); -} - -} - template<> std::size_t BVHCollide<OBB>(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const CollisionRequest& request, CollisionResult& result) { @@ -333,17 +263,16 @@ std::size_t BVHCollide<kIOS>(const CollisionGeometry* o1, const Transform3f& tf1 } -template<typename T_BVH, typename NarrowPhaseSolver> +template<typename T_BVH> std::size_t BVHCollide(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* /*nsolver*/, + const GJKSolver* /*nsolver*/, const CollisionRequest& request, CollisionResult& result) { return BVHCollide<T_BVH>(o1, tf1, o2, tf2, request, result); } -template<typename NarrowPhaseSolver> -CollisionFunctionMatrix<NarrowPhaseSolver>::CollisionFunctionMatrix() +CollisionFunctionMatrix::CollisionFunctionMatrix() { for(int i = 0; i < NODE_COUNT; ++i) { @@ -351,200 +280,200 @@ CollisionFunctionMatrix<NarrowPhaseSolver>::CollisionFunctionMatrix() collision_matrix[i][j] = NULL; } - collision_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeCollide<Box, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeCollide<Box, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeCollide<Box, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeCollide<Box, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeCollide<Box, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeCollide<Box, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeCollide<Box, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeCollide<Box, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeCollide<Sphere, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeCollide<Sphere, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeCollide<Sphere, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeCollide<Sphere, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeCollide<Sphere, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeCollide<Sphere, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeCollide<Sphere, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeCollide<Sphere, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeCollide<Capsule, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeCollide<Capsule, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeCollide<Capsule, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeCollide<Capsule, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeCollide<Capsule, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeCollide<Capsule, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeCollide<Capsule, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeCollide<Capsule, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeCollide<Cone, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeCollide<Cone, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeCollide<Cone, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeCollide<Cone, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeCollide<Cone, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeCollide<Cone, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeCollide<Cone, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeCollide<Cone, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeCollide<Cylinder, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeCollide<Cylinder, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeCollide<Cylinder, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeCollide<Cylinder, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeCollide<Cylinder, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeCollide<Cylinder, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeCollide<Cylinder, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeCollide<Cylinder, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeCollide<Convex, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeCollide<Convex, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeCollide<Convex, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeCollide<Convex, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeCollide<Convex, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeCollide<Convex, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeCollide<Convex, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeCollide<Convex, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeCollide<Plane, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeCollide<Plane, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeCollide<Plane, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeCollide<Plane, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeCollide<Plane, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeCollide<Plane, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeCollide<Plane, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeCollide<Plane, Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeCollide<Halfspace, Box, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeCollide<Halfspace, Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeCollide<Halfspace, Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeCollide<Halfspace, Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeCollide<Halfspace, Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeCollide<Halfspace, Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeCollide<Halfspace, Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeCollide<Halfspace, Halfspace, NarrowPhaseSolver>; - - collision_matrix[BV_AABB][GEOM_BOX] = &BVHShapeCollider<AABB, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeCollider<AABB, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeCollider<AABB, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_CONE] = &BVHShapeCollider<AABB, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeCollider<AABB, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeCollider<AABB, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeCollider<AABB, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeCollider<AABB, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_OBB][GEOM_BOX] = &BVHShapeCollider<OBB, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeCollider<OBB, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeCollider<OBB, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_CONE] = &BVHShapeCollider<OBB, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeCollider<OBB, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeCollider<OBB, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeCollider<OBB, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeCollider<OBB, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_RSS][GEOM_BOX] = &BVHShapeCollider<RSS, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeCollider<RSS, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeCollider<RSS, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_CONE] = &BVHShapeCollider<RSS, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeCollider<RSS, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeCollider<RSS, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeCollider<RSS, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeCollider<RSS, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeCollider<KDOP<16>, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeCollider<KDOP<16>, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<16>, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeCollider<KDOP<16>, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<16>, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeCollider<KDOP<16>, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeCollider<KDOP<16>, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<16>, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeCollider<KDOP<18>, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeCollider<KDOP<18>, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<18>, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeCollider<KDOP<18>, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<18>, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeCollider<KDOP<18>, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeCollider<KDOP<18>, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<18>, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeCollider<KDOP<24>, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeCollider<KDOP<24>, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<24>, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeCollider<KDOP<24>, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<24>, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeCollider<KDOP<24>, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeCollider<KDOP<24>, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<24>, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeCollider<kIOS, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeCollider<kIOS, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeCollider<kIOS, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeCollider<kIOS, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeCollider<kIOS, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeCollider<kIOS, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeCollider<kIOS, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeCollider<kIOS, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeCollider<OBBRSS, Box, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeCollider<OBBRSS, Sphere, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeCollider<OBBRSS, Capsule, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeCollider<OBBRSS, Cone, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeCollider<OBBRSS, Cylinder, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeCollider<OBBRSS, Convex, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeCollider<OBBRSS, Plane, NarrowPhaseSolver>::collide; - collision_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeCollider<OBBRSS, Halfspace, NarrowPhaseSolver>::collide; - - collision_matrix[BV_AABB][BV_AABB] = &BVHCollide<AABB, NarrowPhaseSolver>; - collision_matrix[BV_OBB][BV_OBB] = &BVHCollide<OBB, NarrowPhaseSolver>; - collision_matrix[BV_RSS][BV_RSS] = &BVHCollide<RSS, NarrowPhaseSolver>; - collision_matrix[BV_KDOP16][BV_KDOP16] = &BVHCollide<KDOP<16>, NarrowPhaseSolver>; - collision_matrix[BV_KDOP18][BV_KDOP18] = &BVHCollide<KDOP<18>, NarrowPhaseSolver>; - collision_matrix[BV_KDOP24][BV_KDOP24] = &BVHCollide<KDOP<24>, NarrowPhaseSolver>; - collision_matrix[BV_kIOS][BV_kIOS] = &BVHCollide<kIOS, NarrowPhaseSolver>; - collision_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHCollide<OBBRSS, NarrowPhaseSolver>; + collision_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeCollide<Box, Box>; + collision_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeCollide<Box, Sphere>; + collision_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeCollide<Box, Capsule>; + collision_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeCollide<Box, Cone>; + collision_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeCollide<Box, Cylinder>; + collision_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeCollide<Box, ConvexBase>; + collision_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeCollide<Box, Plane>; + collision_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeCollide<Box, Halfspace>; + + collision_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeCollide<Sphere, Box>; + collision_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeCollide<Sphere, Sphere>; + collision_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeCollide<Sphere, Capsule>; + collision_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeCollide<Sphere, Cone>; + collision_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeCollide<Sphere, Cylinder>; + collision_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeCollide<Sphere, ConvexBase>; + collision_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeCollide<Sphere, Plane>; + collision_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeCollide<Sphere, Halfspace>; + + collision_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeCollide<Capsule, Box>; + collision_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeCollide<Capsule, Sphere>; + collision_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeCollide<Capsule, Capsule>; + collision_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeCollide<Capsule, Cone>; + collision_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeCollide<Capsule, Cylinder>; + collision_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeCollide<Capsule, ConvexBase>; + collision_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeCollide<Capsule, Plane>; + collision_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeCollide<Capsule, Halfspace>; + + collision_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeCollide<Cone, Box>; + collision_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeCollide<Cone, Sphere>; + collision_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeCollide<Cone, Capsule>; + collision_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeCollide<Cone, Cone>; + collision_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeCollide<Cone, Cylinder>; + collision_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeCollide<Cone, ConvexBase>; + collision_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeCollide<Cone, Plane>; + collision_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeCollide<Cone, Halfspace>; + + collision_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeCollide<Cylinder, Box>; + collision_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeCollide<Cylinder, Sphere>; + collision_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeCollide<Cylinder, Capsule>; + collision_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeCollide<Cylinder, Cone>; + collision_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeCollide<Cylinder, Cylinder>; + collision_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeCollide<Cylinder, ConvexBase>; + collision_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeCollide<Cylinder, Plane>; + collision_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeCollide<Cylinder, Halfspace>; + + collision_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeCollide<ConvexBase, Box>; + collision_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeCollide<ConvexBase, Sphere>; + collision_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeCollide<ConvexBase, Capsule>; + collision_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeCollide<ConvexBase, Cone>; + collision_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeCollide<ConvexBase, Cylinder>; + collision_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeCollide<ConvexBase, ConvexBase>; + collision_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeCollide<ConvexBase, Plane>; + collision_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeCollide<ConvexBase, Halfspace>; + + collision_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeCollide<Plane, Box>; + collision_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeCollide<Plane, Sphere>; + collision_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeCollide<Plane, Capsule>; + collision_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeCollide<Plane, Cone>; + collision_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeCollide<Plane, Cylinder>; + collision_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeCollide<Plane, ConvexBase>; + collision_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeCollide<Plane, Plane>; + collision_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeCollide<Plane, Halfspace>; + + collision_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeCollide<Halfspace, Box>; + collision_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeCollide<Halfspace, Sphere>; + collision_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeCollide<Halfspace, Capsule>; + collision_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeCollide<Halfspace, Cone>; + collision_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeCollide<Halfspace, Cylinder>; + collision_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeCollide<Halfspace, ConvexBase>; + collision_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeCollide<Halfspace, Plane>; + collision_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeCollide<Halfspace, Halfspace>; + + collision_matrix[BV_AABB][GEOM_BOX] = &BVHShapeCollider<AABB, Box>::collide; + collision_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeCollider<AABB, Sphere>::collide; + collision_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeCollider<AABB, Capsule>::collide; + collision_matrix[BV_AABB][GEOM_CONE] = &BVHShapeCollider<AABB, Cone>::collide; + collision_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeCollider<AABB, Cylinder>::collide; + collision_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeCollider<AABB, ConvexBase>::collide; + collision_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeCollider<AABB, Plane>::collide; + collision_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeCollider<AABB, Halfspace>::collide; + + collision_matrix[BV_OBB][GEOM_BOX] = &BVHShapeCollider<OBB, Box>::collide; + collision_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeCollider<OBB, Sphere>::collide; + collision_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeCollider<OBB, Capsule>::collide; + collision_matrix[BV_OBB][GEOM_CONE] = &BVHShapeCollider<OBB, Cone>::collide; + collision_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeCollider<OBB, Cylinder>::collide; + collision_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeCollider<OBB, ConvexBase>::collide; + collision_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeCollider<OBB, Plane>::collide; + collision_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeCollider<OBB, Halfspace>::collide; + + collision_matrix[BV_RSS][GEOM_BOX] = &BVHShapeCollider<RSS, Box>::collide; + collision_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeCollider<RSS, Sphere>::collide; + collision_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeCollider<RSS, Capsule>::collide; + collision_matrix[BV_RSS][GEOM_CONE] = &BVHShapeCollider<RSS, Cone>::collide; + collision_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeCollider<RSS, Cylinder>::collide; + collision_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeCollider<RSS, ConvexBase>::collide; + collision_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeCollider<RSS, Plane>::collide; + collision_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeCollider<RSS, Halfspace>::collide; + + collision_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeCollider<KDOP<16>, Box>::collide; + collision_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeCollider<KDOP<16>, Sphere>::collide; + collision_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<16>, Capsule>::collide; + collision_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeCollider<KDOP<16>, Cone>::collide; + collision_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<16>, Cylinder>::collide; + collision_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeCollider<KDOP<16>, ConvexBase>::collide; + collision_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeCollider<KDOP<16>, Plane>::collide; + collision_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<16>, Halfspace>::collide; + + collision_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeCollider<KDOP<18>, Box>::collide; + collision_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeCollider<KDOP<18>, Sphere>::collide; + collision_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<18>, Capsule>::collide; + collision_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeCollider<KDOP<18>, Cone>::collide; + collision_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<18>, Cylinder>::collide; + collision_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeCollider<KDOP<18>, ConvexBase>::collide; + collision_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeCollider<KDOP<18>, Plane>::collide; + collision_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<18>, Halfspace>::collide; + + collision_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeCollider<KDOP<24>, Box>::collide; + collision_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeCollider<KDOP<24>, Sphere>::collide; + collision_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeCollider<KDOP<24>, Capsule>::collide; + collision_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeCollider<KDOP<24>, Cone>::collide; + collision_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeCollider<KDOP<24>, Cylinder>::collide; + collision_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeCollider<KDOP<24>, ConvexBase>::collide; + collision_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeCollider<KDOP<24>, Plane>::collide; + collision_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeCollider<KDOP<24>, Halfspace>::collide; + + collision_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeCollider<kIOS, Box>::collide; + collision_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeCollider<kIOS, Sphere>::collide; + collision_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeCollider<kIOS, Capsule>::collide; + collision_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeCollider<kIOS, Cone>::collide; + collision_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeCollider<kIOS, Cylinder>::collide; + collision_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeCollider<kIOS, ConvexBase>::collide; + collision_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeCollider<kIOS, Plane>::collide; + collision_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeCollider<kIOS, Halfspace>::collide; + + collision_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeCollider<OBBRSS, Box>::collide; + collision_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeCollider<OBBRSS, Sphere>::collide; + collision_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeCollider<OBBRSS, Capsule>::collide; + collision_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeCollider<OBBRSS, Cone>::collide; + collision_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeCollider<OBBRSS, Cylinder>::collide; + collision_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeCollider<OBBRSS, ConvexBase>::collide; + collision_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeCollider<OBBRSS, Plane>::collide; + collision_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeCollider<OBBRSS, Halfspace>::collide; + + collision_matrix[BV_AABB][BV_AABB] = &BVHCollide<AABB>; + collision_matrix[BV_OBB][BV_OBB] = &BVHCollide<OBB>; + collision_matrix[BV_RSS][BV_RSS] = &BVHCollide<RSS>; + collision_matrix[BV_KDOP16][BV_KDOP16] = &BVHCollide<KDOP<16> >; + collision_matrix[BV_KDOP18][BV_KDOP18] = &BVHCollide<KDOP<18> >; + collision_matrix[BV_KDOP24][BV_KDOP24] = &BVHCollide<KDOP<24> >; + collision_matrix[BV_kIOS][BV_kIOS] = &BVHCollide<kIOS>; + collision_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHCollide<OBBRSS>; #ifdef HPP_FCL_HAVE_OCTOMAP - collision_matrix[GEOM_OCTREE][GEOM_BOX] = &OcTreeShapeCollide<Box, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_SPHERE] = &OcTreeShapeCollide<Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &OcTreeShapeCollide<Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_CONE] = &OcTreeShapeCollide<Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &OcTreeShapeCollide<Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_CONVEX] = &OcTreeShapeCollide<Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_PLANE] = &OcTreeShapeCollide<Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &OcTreeShapeCollide<Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_BOX][GEOM_OCTREE] = &ShapeOcTreeCollide<Box, NarrowPhaseSolver>; - collision_matrix[GEOM_SPHERE][GEOM_OCTREE] = &ShapeOcTreeCollide<Sphere, NarrowPhaseSolver>; - collision_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &ShapeOcTreeCollide<Capsule, NarrowPhaseSolver>; - collision_matrix[GEOM_CONE][GEOM_OCTREE] = &ShapeOcTreeCollide<Cone, NarrowPhaseSolver>; - collision_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &ShapeOcTreeCollide<Cylinder, NarrowPhaseSolver>; - collision_matrix[GEOM_CONVEX][GEOM_OCTREE] = &ShapeOcTreeCollide<Convex, NarrowPhaseSolver>; - collision_matrix[GEOM_PLANE][GEOM_OCTREE] = &ShapeOcTreeCollide<Plane, NarrowPhaseSolver>; - collision_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &ShapeOcTreeCollide<Halfspace, NarrowPhaseSolver>; - - collision_matrix[GEOM_OCTREE][GEOM_OCTREE] = &OcTreeCollide<NarrowPhaseSolver>; - - collision_matrix[GEOM_OCTREE][BV_AABB] = &OcTreeBVHCollide<AABB, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_OBB] = &OcTreeBVHCollide<OBB, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_RSS] = &OcTreeBVHCollide<RSS, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_OBBRSS] = &OcTreeBVHCollide<OBBRSS, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_kIOS] = &OcTreeBVHCollide<kIOS, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_KDOP16] = &OcTreeBVHCollide<KDOP<16>, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_KDOP18] = &OcTreeBVHCollide<KDOP<18>, NarrowPhaseSolver>; - collision_matrix[GEOM_OCTREE][BV_KDOP24] = &OcTreeBVHCollide<KDOP<24>, NarrowPhaseSolver>; - - collision_matrix[BV_AABB][GEOM_OCTREE] = &BVHOcTreeCollide<AABB, NarrowPhaseSolver>; - collision_matrix[BV_OBB][GEOM_OCTREE] = &BVHOcTreeCollide<OBB, NarrowPhaseSolver>; - collision_matrix[BV_RSS][GEOM_OCTREE] = &BVHOcTreeCollide<RSS, NarrowPhaseSolver>; - collision_matrix[BV_OBBRSS][GEOM_OCTREE] = &BVHOcTreeCollide<OBBRSS, NarrowPhaseSolver>; - collision_matrix[BV_kIOS][GEOM_OCTREE] = &BVHOcTreeCollide<kIOS, NarrowPhaseSolver>; - collision_matrix[BV_KDOP16][GEOM_OCTREE] = &BVHOcTreeCollide<KDOP<16>, NarrowPhaseSolver>; - collision_matrix[BV_KDOP18][GEOM_OCTREE] = &BVHOcTreeCollide<KDOP<18>, NarrowPhaseSolver>; - collision_matrix[BV_KDOP24][GEOM_OCTREE] = &BVHOcTreeCollide<KDOP<24>, NarrowPhaseSolver>; + collision_matrix[GEOM_OCTREE][GEOM_BOX] = &Collide<OcTree, Box>; + collision_matrix[GEOM_OCTREE][GEOM_SPHERE] = &Collide<OcTree, Sphere>; + collision_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &Collide<OcTree, Capsule>; + collision_matrix[GEOM_OCTREE][GEOM_CONE] = &Collide<OcTree, Cone>; + collision_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &Collide<OcTree, Cylinder>; + collision_matrix[GEOM_OCTREE][GEOM_CONVEX] = &Collide<OcTree, ConvexBase>; + collision_matrix[GEOM_OCTREE][GEOM_PLANE] = &Collide<OcTree, Plane>; + collision_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &Collide<OcTree, Halfspace>; + + collision_matrix[GEOM_BOX][GEOM_OCTREE] = &Collide<Box, OcTree>; + collision_matrix[GEOM_SPHERE][GEOM_OCTREE] = &Collide<Sphere, OcTree>; + collision_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &Collide<Capsule, OcTree>; + collision_matrix[GEOM_CONE][GEOM_OCTREE] = &Collide<Cone, OcTree>; + collision_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &Collide<Cylinder, OcTree>; + collision_matrix[GEOM_CONVEX][GEOM_OCTREE] = &Collide<ConvexBase, OcTree>; + collision_matrix[GEOM_PLANE][GEOM_OCTREE] = &Collide<Plane, OcTree>; + collision_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &Collide<Halfspace, OcTree>; + + collision_matrix[GEOM_OCTREE][GEOM_OCTREE] = &Collide<OcTree, OcTree>; + + collision_matrix[GEOM_OCTREE][BV_AABB ] = &Collide<OcTree, BVHModel<AABB > >; + collision_matrix[GEOM_OCTREE][BV_OBB ] = &Collide<OcTree, BVHModel<OBB > >; + collision_matrix[GEOM_OCTREE][BV_RSS ] = &Collide<OcTree, BVHModel<RSS > >; + collision_matrix[GEOM_OCTREE][BV_OBBRSS] = &Collide<OcTree, BVHModel<OBBRSS > >; + collision_matrix[GEOM_OCTREE][BV_kIOS ] = &Collide<OcTree, BVHModel<kIOS > >; + collision_matrix[GEOM_OCTREE][BV_KDOP16] = &Collide<OcTree, BVHModel<KDOP<16> > >; + collision_matrix[GEOM_OCTREE][BV_KDOP18] = &Collide<OcTree, BVHModel<KDOP<18> > >; + collision_matrix[GEOM_OCTREE][BV_KDOP24] = &Collide<OcTree, BVHModel<KDOP<24> > >; + + collision_matrix[BV_AABB ][GEOM_OCTREE] = &Collide<BVHModel<AABB >, OcTree>; + collision_matrix[BV_OBB ][GEOM_OCTREE] = &Collide<BVHModel<OBB >, OcTree>; + collision_matrix[BV_RSS ][GEOM_OCTREE] = &Collide<BVHModel<RSS >, OcTree>; + collision_matrix[BV_OBBRSS][GEOM_OCTREE] = &Collide<BVHModel<OBBRSS >, OcTree>; + collision_matrix[BV_kIOS ][GEOM_OCTREE] = &Collide<BVHModel<kIOS >, OcTree>; + collision_matrix[BV_KDOP16][GEOM_OCTREE] = &Collide<BVHModel<KDOP<16> >, OcTree>; + collision_matrix[BV_KDOP18][GEOM_OCTREE] = &Collide<BVHModel<KDOP<18> >, OcTree>; + collision_matrix[BV_KDOP24][GEOM_OCTREE] = &Collide<BVHModel<KDOP<24> >, OcTree>; #endif } -template struct CollisionFunctionMatrix<GJKSolver_indep>; +//template struct CollisionFunctionMatrix; } } // namespace hpp diff --git a/src/collision_node.cpp b/src/collision_node.cpp index ad936342337342ba1076485ddca314d4d2709188..436c033d433bf09863c29b48bf2f09b9e644a48b 100644 --- a/src/collision_node.cpp +++ b/src/collision_node.cpp @@ -36,8 +36,8 @@ /** \author Jia Pan */ -#include <hpp/fcl/collision_node.h> -#include <hpp/fcl/traversal/traversal_recurse.h> +#include <../src/collision_node.h> +#include <hpp/fcl/internal/traversal_recurse.h> namespace hpp { @@ -46,7 +46,8 @@ namespace fcl void collide(CollisionTraversalNodeBase* node, const CollisionRequest& request, CollisionResult& result, - BVHFrontList* front_list) + BVHFrontList* front_list, + bool recursive) { if(front_list && front_list->size() > 0) { @@ -55,7 +56,10 @@ void collide(CollisionTraversalNodeBase* node, else { FCL_REAL sqrDistLowerBound=0; - collisionRecurse(node, 0, 0, front_list, sqrDistLowerBound); + if (recursive) + collisionRecurse(node, 0, 0, front_list, sqrDistLowerBound); + else + collisionNonRecurse(node, front_list, sqrDistLowerBound); result.distance_lower_bound = sqrt (sqrDistLowerBound); } } diff --git a/include/hpp/fcl/collision_node.h b/src/collision_node.h similarity index 82% rename from include/hpp/fcl/collision_node.h rename to src/collision_node.h index 23fd309de6da0d0281da458463727c00e40d367b..d657eea8fee87da58c7f2e16165264bd3f5b97a6 100644 --- a/include/hpp/fcl/collision_node.h +++ b/src/collision_node.h @@ -35,15 +35,14 @@ /** \author Jia Pan */ - #ifndef HPP_FCL_COLLISION_NODE_H #define HPP_FCL_COLLISION_NODE_H -#include <hpp/fcl/traversal/traversal_node_base.h> -#include <hpp/fcl/traversal/traversal_node_bvhs.h> -#include <hpp/fcl/BVH/BVH_front.h> - +/// @cond INTERNAL +#include <hpp/fcl/BVH/BVH_front.h> +#include <hpp/fcl/internal/traversal_node_base.h> +#include <hpp/fcl/internal/traversal_node_bvhs.h> /// @brief collision and distance function on traversal nodes. these functions provide a higher level abstraction for collision functions provided in collision_func_matrix namespace hpp @@ -54,15 +53,14 @@ namespace fcl /// collision on collision traversal node /// -/// \param node node containing both objects to test, -/// \retval squared lower bound to the distance between the objects if they +/// @param node node containing both objects to test, +/// @retval squared lower bound to the distance between the objects if they /// do not collide. -/// \param front_list list of nodes visited by the query, can be used to +/// @param front_list list of nodes visited by the query, can be used to /// accelerate computation - void collide(CollisionTraversalNodeBase* node, - const CollisionRequest& request, - CollisionResult& result, - BVHFrontList* front_list = NULL); +void collide(CollisionTraversalNodeBase* node, const CollisionRequest& request, + CollisionResult& result, BVHFrontList* front_list = NULL, + bool recursive = true); /// @brief distance computation on distance traversal node; can use front list to accelerate void distance(DistanceTraversalNodeBase* node, BVHFrontList* front_list = NULL, int qsize = 2); @@ -70,4 +68,6 @@ void distance(DistanceTraversalNodeBase* node, BVHFrontList* front_list = NULL, } // namespace hpp +/// @endcond + #endif diff --git a/src/distance.cpp b/src/distance.cpp index efda1c8ccb0c79483b0951aa43e86b7125b039d1..95c4a8b2ee9cd2ae4d1ef757939dbe83b5d19322 100644 --- a/src/distance.cpp +++ b/src/distance.cpp @@ -46,32 +46,22 @@ namespace hpp namespace fcl { -template<typename GJKSolver> -DistanceFunctionMatrix<GJKSolver>& getDistanceFunctionLookTable() +DistanceFunctionMatrix& getDistanceFunctionLookTable() { - static DistanceFunctionMatrix<GJKSolver> table; + static DistanceFunctionMatrix table; return table; } -template<typename NarrowPhaseSolver> -FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const NarrowPhaseSolver* nsolver, - const DistanceRequest& request, DistanceResult& result) -{ - return distance<NarrowPhaseSolver>(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), nsolver, - request, result); -} - -template<typename NarrowPhaseSolver> FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver_, + const GJKSolver* nsolver_, const DistanceRequest& request, DistanceResult& result) { - const NarrowPhaseSolver* nsolver = nsolver_; + const GJKSolver* nsolver = nsolver_; if(!nsolver_) - nsolver = new NarrowPhaseSolver(); + nsolver = new GJKSolver(); - const DistanceFunctionMatrix<NarrowPhaseSolver>& looktable = getDistanceFunctionLookTable<NarrowPhaseSolver>(); + const DistanceFunctionMatrix& looktable = getDistanceFunctionLookTable(); OBJECT_TYPE object_type1 = o1->getObjectType(); NODE_TYPE node_type1 = o1->getNodeType(); @@ -118,6 +108,12 @@ FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, return res; } +FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const GJKSolver* nsolver, + const DistanceRequest& request, DistanceResult& result) +{ + return distance(o1->collisionGeometry().get(), o1->getTransform(), o2->collisionGeometry().get(), o2->getTransform(), nsolver, + request, result); +} FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const DistanceRequest& request, DistanceResult& result) { @@ -125,8 +121,8 @@ FCL_REAL distance(const CollisionObject* o1, const CollisionObject* o2, const Di { case GST_INDEP: { - GJKSolver_indep solver; - return distance<GJKSolver_indep>(o1, o2, &solver, request, result); + GJKSolver solver; + return distance(o1, o2, &solver, request, result); } default: return -1; // error @@ -141,8 +137,8 @@ FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, { case GST_INDEP: { - GJKSolver_indep solver; - return distance<GJKSolver_indep>(o1, tf1, o2, tf2, &solver, request, result); + GJKSolver solver; + return distance(o1, tf1, o2, tf2, &solver, request, result); } default: return -1; diff --git a/src/distance_box_halfspace.cpp b/src/distance_box_halfspace.cpp index 629aa4caad9f970a5998416baecaef6ff3b14743..191cf09bcb86f2c04b7ae9aeb8b78ee11cae41b9 100644 --- a/src/distance_box_halfspace.cpp +++ b/src/distance_box_halfspace.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Box, Halfspace, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Box, Halfspace> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Box& s1 = static_cast <const Box&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Halfspace, Box, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Halfspace, Box> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Halfspace& s1 = static_cast <const Halfspace&> (*o1); diff --git a/src/distance_box_plane.cpp b/src/distance_box_plane.cpp index 389d62b7786dcbcd212d52f352cc1620ac1c0cb3..d63879225374473452c6aa0387b9cd323508c2c2 100644 --- a/src/distance_box_plane.cpp +++ b/src/distance_box_plane.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Box, Plane, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Box, Plane> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Box& s1 = static_cast <const Box&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Plane, Box, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Plane, Box> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Plane& s1 = static_cast <const Plane&> (*o1); diff --git a/src/distance_box_sphere.cpp b/src/distance_box_sphere.cpp index 7d56b9902ed5402e1c787bdedea255943f2d3721..f35030e308a3342788832a944ac6f0877640423c 100644 --- a/src/distance_box_sphere.cpp +++ b/src/distance_box_sphere.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Box, Sphere, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Box, Sphere> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Box& s1 = static_cast <const Box&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Sphere, Box, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Sphere, Box> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Sphere& s1 = static_cast <const Sphere&> (*o1); diff --git a/src/distance_capsule_capsule.cpp b/src/distance_capsule_capsule.cpp index 3e80e7b63d2416f6696f3d487a4bf475023f6e5f..029c23680cddf7b9771990228e93dd909077f3b4 100644 --- a/src/distance_capsule_capsule.cpp +++ b/src/distance_capsule_capsule.cpp @@ -10,7 +10,7 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" +#include <../src/distance_func_matrix.h> // Note that partial specialization of template functions is not allowed. // Therefore, two implementations with the default narrow phase solvers are @@ -23,13 +23,13 @@ namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Capsule, Capsule, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Capsule, Capsule> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest& request, + const GJKSolver*, const DistanceRequest& request, DistanceResult& result) { const Capsule* c1 = static_cast <const Capsule*> (o1); @@ -41,8 +41,8 @@ namespace fcl { // We assume that capsules are oriented along z-axis. Matrix3f::ConstColXpr direction1 = tf1.getRotation ().col (2); Matrix3f::ConstColXpr direction2 = tf2.getRotation ().col (2); - FCL_REAL halfLength1 = 0.5*c1->lz; - FCL_REAL halfLength2 = 0.5*c2->lz; + FCL_REAL halfLength1 = c1->halfLength; + FCL_REAL halfLength2 = c2->halfLength; Vec3f diff = center1 - center2; FCL_REAL a01 = -direction1.dot (direction2); @@ -321,17 +321,17 @@ namespace fcl { } template <> - std::size_t ShapeShapeCollide <Capsule, Capsule, GJKSolver_indep> + std::size_t ShapeShapeCollide <Capsule, Capsule> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const CollisionRequest& request, + const GJKSolver*, const CollisionRequest& request, CollisionResult& result) { - GJKSolver_indep* unused = 0x0; + GJKSolver* unused = 0x0; DistanceResult distanceResult; DistanceRequest distanceRequest (request.enable_contact); - FCL_REAL distance = ShapeShapeDistance <Capsule, Capsule, GJKSolver_indep> + FCL_REAL distance = ShapeShapeDistance <Capsule, Capsule> (o1, tf1, o2, tf2, unused, distanceRequest, distanceResult); if (distance <= 0) { diff --git a/src/distance_capsule_halfspace.cpp b/src/distance_capsule_halfspace.cpp index acd08f74a868effbefb50b20fca0cecb7fcc2d7a..f33fc5175999bacab4c1223243074d8356b6f278 100644 --- a/src/distance_capsule_halfspace.cpp +++ b/src/distance_capsule_halfspace.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Capsule, Halfspace, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Capsule, Halfspace> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Capsule& s1 = static_cast <const Capsule&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Halfspace, Capsule, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Halfspace, Capsule> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Halfspace& s1 = static_cast <const Halfspace&> (*o1); diff --git a/src/distance_capsule_plane.cpp b/src/distance_capsule_plane.cpp index 504d2fec1f5d8f0485e8263f3409af0c556a6a90..beb862d065661df9a52cd813083ad2893230c917 100644 --- a/src/distance_capsule_plane.cpp +++ b/src/distance_capsule_plane.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Capsule, Plane, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Capsule, Plane> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Capsule& s1 = static_cast <const Capsule&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Plane, Capsule, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Plane, Capsule> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Plane& s1 = static_cast <const Plane&> (*o1); diff --git a/src/distance_cone_halfspace.cpp b/src/distance_cone_halfspace.cpp index 0d4d4a1844e4dcdf9f5cd3e6af34bdf350adf549..0191f6530d5e6c4b1ee2014c223bc92c721d2b62 100644 --- a/src/distance_cone_halfspace.cpp +++ b/src/distance_cone_halfspace.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Cone, Halfspace, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Cone, Halfspace> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Cone& s1 = static_cast <const Cone&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Halfspace, Cone, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Halfspace, Cone> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Halfspace& s1 = static_cast <const Halfspace&> (*o1); diff --git a/src/distance_cone_plane.cpp b/src/distance_cone_plane.cpp index 754498da8920f07365fbce02cc7cb5c338776b56..bc66f953b9ae9e4db6fa17d2e70a3c74ef8e31a1 100644 --- a/src/distance_cone_plane.cpp +++ b/src/distance_cone_plane.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Cone, Plane, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Cone, Plane> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Cone& s1 = static_cast <const Cone&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Plane, Cone, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Plane, Cone> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Plane& s1 = static_cast <const Plane&> (*o1); diff --git a/src/distance_cylinder_halfspace.cpp b/src/distance_cylinder_halfspace.cpp index 4e6163a65c3d8b5597ca3cc8009dd89ba7b65586..dd469a6c4378999c390795d9b5a59d18e3d8dd39 100644 --- a/src/distance_cylinder_halfspace.cpp +++ b/src/distance_cylinder_halfspace.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Cylinder, Halfspace, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Cylinder, Halfspace> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Cylinder& s1 = static_cast <const Cylinder&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Halfspace, Cylinder, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Halfspace, Cylinder> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Halfspace& s1 = static_cast <const Halfspace&> (*o1); diff --git a/src/distance_cylinder_plane.cpp b/src/distance_cylinder_plane.cpp index 729f99eb859e7a5ed906741443d6b16a323b50b2..e8be52cb7c2e938b92bec2ed900cd919f8c65add 100644 --- a/src/distance_cylinder_plane.cpp +++ b/src/distance_cylinder_plane.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Cylinder, Plane, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Cylinder, Plane> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Cylinder& s1 = static_cast <const Cylinder&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Plane, Cylinder, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Plane, Cylinder> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Plane& s1 = static_cast <const Plane&> (*o1); diff --git a/src/distance_func_matrix.cpp b/src/distance_func_matrix.cpp index 423d8d62e52306a70bf19559e5a5020479ee8c30..68dab3ff569ee0348fd5a3a76c72c01fb4a96210 100644 --- a/src/distance_func_matrix.cpp +++ b/src/distance_func_matrix.cpp @@ -37,9 +37,9 @@ #include <hpp/fcl/distance_func_matrix.h> -#include <hpp/fcl/collision_node.h> -#include <hpp/fcl/traversal/traversal_node_setup.h> -#include <hpp/fcl/narrowphase/narrowphase.h> +#include <../src/collision_node.h> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include <../src/traits_traversal.h> namespace hpp { @@ -47,31 +47,16 @@ namespace fcl { #ifdef HPP_FCL_HAVE_OCTOMAP -template<typename T_SH, typename NarrowPhaseSolver> -FCL_REAL ShapeOcTreeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, - const DistanceRequest& request, DistanceResult& result) -{ - if(request.isSatisfied(result)) return result.min_distance; - ShapeOcTreeDistanceTraversalNode<T_SH, NarrowPhaseSolver> node; - const T_SH* obj1 = static_cast<const T_SH*>(o1); - const OcTree* obj2 = static_cast<const OcTree*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result); - distance(&node); - - return result.min_distance; -} - -template<typename T_SH, typename NarrowPhaseSolver> -FCL_REAL OcTreeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, +template<typename TypeA, typename TypeB> +FCL_REAL Distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { if(request.isSatisfied(result)) return result.min_distance; - OcTreeShapeDistanceTraversalNode<T_SH, NarrowPhaseSolver> node; - const OcTree* obj1 = static_cast<const OcTree*>(o1); - const T_SH* obj2 = static_cast<const T_SH*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); + typename TraversalTraitsDistance<TypeA, TypeB>::CollisionTraversal_t node; + const TypeA* obj1 = static_cast<const TypeA*>(o1); + const TypeB* obj2 = static_cast<const TypeB*>(o2); + OcTreeSolver otsolver(nsolver); initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result); distance(&node); @@ -79,62 +64,14 @@ FCL_REAL OcTreeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1 return result.min_distance; } -template<typename NarrowPhaseSolver> -FCL_REAL OcTreeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, - const DistanceRequest& request, DistanceResult& result) -{ - if(request.isSatisfied(result)) return result.min_distance; - OcTreeDistanceTraversalNode<NarrowPhaseSolver> node; - const OcTree* obj1 = static_cast<const OcTree*>(o1); - const OcTree* obj2 = static_cast<const OcTree*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result); - distance(&node); - - return result.min_distance; -} - -template<typename T_BVH, typename NarrowPhaseSolver> -FCL_REAL BVHOcTreeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, - const DistanceRequest& request, DistanceResult& result) -{ - if(request.isSatisfied(result)) return result.min_distance; - MeshOcTreeDistanceTraversalNode<T_BVH, NarrowPhaseSolver> node; - const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>*>(o1); - const OcTree* obj2 = static_cast<const OcTree*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result); - distance(&node); - - return result.min_distance; -} - -template<typename T_BVH, typename NarrowPhaseSolver> -FCL_REAL OcTreeBVHDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, - const DistanceRequest& request, DistanceResult& result) -{ - if(request.isSatisfied(result)) return result.min_distance; - OcTreeMeshDistanceTraversalNode<T_BVH, NarrowPhaseSolver> node; - const OcTree* obj1 = static_cast<const OcTree*>(o1); - const BVHModel<T_BVH>* obj2 = static_cast<const BVHModel<T_BVH>*>(o2); - OcTreeSolver<NarrowPhaseSolver> otsolver(nsolver); - - initialize(node, *obj1, tf1, *obj2, tf2, &otsolver, request, result); - distance(&node); - - return result.min_distance; -} - #endif -template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver> -FCL_REAL ShapeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, +template<typename T_SH1, typename T_SH2> +FCL_REAL ShapeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { if(request.isSatisfied(result)) return result.min_distance; - ShapeDistanceTraversalNode<T_SH1, T_SH2, NarrowPhaseSolver> node; + ShapeDistanceTraversalNode<T_SH1, T_SH2> node; const T_SH1* obj1 = static_cast<const T_SH1*>(o1); const T_SH2* obj2 = static_cast<const T_SH2*>(o2); @@ -144,14 +81,14 @@ FCL_REAL ShapeShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, return result.min_distance; } -template<typename T_BVH, typename T_SH, typename NarrowPhaseSolver> +template<typename T_BVH, typename T_SH> struct BVHShapeDistancer { - static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, + static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { if(request.isSatisfied(result)) return result.min_distance; - MeshShapeDistanceTraversalNode<T_BVH, T_SH, NarrowPhaseSolver> node; + MeshShapeDistanceTraversalNode<T_BVH, T_SH> node; const BVHModel<T_BVH>* obj1 = static_cast<const BVHModel<T_BVH>* >(o1); BVHModel<T_BVH>* obj1_tmp = new BVHModel<T_BVH>(*obj1); Transform3f tf1_tmp = tf1; @@ -168,8 +105,8 @@ struct BVHShapeDistancer namespace details { -template<typename OrientedMeshShapeDistanceTraversalNode, typename T_BVH, typename T_SH, typename NarrowPhaseSolver> -FCL_REAL orientedBVHShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, +template<typename OrientedMeshShapeDistanceTraversalNode, typename T_BVH, typename T_SH> +FCL_REAL orientedBVHShapeDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { if(request.isSatisfied(result)) return result.min_distance; @@ -185,34 +122,34 @@ FCL_REAL orientedBVHShapeDistance(const CollisionGeometry* o1, const Transform3f } -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeDistancer<RSS, T_SH, NarrowPhaseSolver> +template<typename T_SH> +struct BVHShapeDistancer<RSS, T_SH> { - static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, + static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { - return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeRSS<T_SH, NarrowPhaseSolver>, RSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeRSS<T_SH>, RSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeDistancer<kIOS, T_SH, NarrowPhaseSolver> +template<typename T_SH> +struct BVHShapeDistancer<kIOS, T_SH> { - static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, + static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { - return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodekIOS<T_SH, NarrowPhaseSolver>, kIOS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodekIOS<T_SH>, kIOS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; -template<typename T_SH, typename NarrowPhaseSolver> -struct BVHShapeDistancer<OBBRSS, T_SH, NarrowPhaseSolver> +template<typename T_SH> +struct BVHShapeDistancer<OBBRSS, T_SH> { - static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const NarrowPhaseSolver* nsolver, + static FCL_REAL distance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result) { - return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeOBBRSS<T_SH, NarrowPhaseSolver>, OBBRSS, T_SH, NarrowPhaseSolver>(o1, tf1, o2, tf2, nsolver, request, result); + return details::orientedBVHShapeDistance<MeshShapeDistanceTraversalNodeOBBRSS<T_SH>, OBBRSS, T_SH>(o1, tf1, o2, tf2, nsolver, request, result); } }; @@ -280,16 +217,15 @@ FCL_REAL BVHDistance<OBBRSS>(const CollisionGeometry* o1, const Transform3f& tf1 } -template<typename T_BVH, typename NarrowPhaseSolver> +template<typename T_BVH> FCL_REAL BVHDistance(const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* /*nsolver*/, + const GJKSolver* /*nsolver*/, const DistanceRequest& request, DistanceResult& result) { return BVHDistance<T_BVH>(o1, tf1, o2, tf2, request, result); } -template<typename NarrowPhaseSolver> -DistanceFunctionMatrix<NarrowPhaseSolver>::DistanceFunctionMatrix() +DistanceFunctionMatrix::DistanceFunctionMatrix() { for(int i = 0; i < NODE_COUNT; ++i) { @@ -297,205 +233,205 @@ DistanceFunctionMatrix<NarrowPhaseSolver>::DistanceFunctionMatrix() distance_matrix[i][j] = NULL; } - distance_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeDistance<Box, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeDistance<Box, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeDistance<Box, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeDistance<Box, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeDistance<Box, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeDistance<Box, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeDistance<Box, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeDistance<Box, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeDistance<Sphere, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeDistance<Sphere, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeDistance<Sphere, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeDistance<Sphere, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeDistance<Sphere, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeDistance<Sphere, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeDistance<Sphere, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeDistance<Sphere, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeDistance<Capsule, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeDistance<Capsule, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeDistance<Capsule, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeDistance<Capsule, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeDistance<Capsule, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeDistance<Capsule, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeDistance<Capsule, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeDistance<Capsule, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeDistance<Cone, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeDistance<Cone, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeDistance<Cone, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeDistance<Cone, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeDistance<Cone, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeDistance<Cone, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeDistance<Cone, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeDistance<Cone, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeDistance<Cylinder, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeDistance<Cylinder, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeDistance<Cylinder, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeDistance<Cylinder, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeDistance<Cylinder, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeDistance<Cylinder, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeDistance<Cylinder, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeDistance<Cylinder, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeDistance<Convex, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeDistance<Convex, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeDistance<Convex, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeDistance<Convex, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeDistance<Convex, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeDistance<Convex, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeDistance<Convex, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeDistance<Convex, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeDistance<Plane, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeDistance<Plane, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeDistance<Plane, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeDistance<Plane, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeDistance<Plane, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeDistance<Plane, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeDistance<Plane, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeDistance<Plane, Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeDistance<Halfspace, Box, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeDistance<Halfspace, Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeDistance<Halfspace, Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeDistance<Halfspace, Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeDistance<Halfspace, Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeDistance<Halfspace, Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeDistance<Halfspace, Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeDistance<Halfspace, Halfspace, NarrowPhaseSolver>; + distance_matrix[GEOM_BOX][GEOM_BOX] = &ShapeShapeDistance<Box, Box>; + distance_matrix[GEOM_BOX][GEOM_SPHERE] = &ShapeShapeDistance<Box, Sphere>; + distance_matrix[GEOM_BOX][GEOM_CAPSULE] = &ShapeShapeDistance<Box, Capsule>; + distance_matrix[GEOM_BOX][GEOM_CONE] = &ShapeShapeDistance<Box, Cone>; + distance_matrix[GEOM_BOX][GEOM_CYLINDER] = &ShapeShapeDistance<Box, Cylinder>; + distance_matrix[GEOM_BOX][GEOM_CONVEX] = &ShapeShapeDistance<Box, ConvexBase>; + distance_matrix[GEOM_BOX][GEOM_PLANE] = &ShapeShapeDistance<Box, Plane>; + distance_matrix[GEOM_BOX][GEOM_HALFSPACE] = &ShapeShapeDistance<Box, Halfspace>; + + distance_matrix[GEOM_SPHERE][GEOM_BOX] = &ShapeShapeDistance<Sphere, Box>; + distance_matrix[GEOM_SPHERE][GEOM_SPHERE] = &ShapeShapeDistance<Sphere, Sphere>; + distance_matrix[GEOM_SPHERE][GEOM_CAPSULE] = &ShapeShapeDistance<Sphere, Capsule>; + distance_matrix[GEOM_SPHERE][GEOM_CONE] = &ShapeShapeDistance<Sphere, Cone>; + distance_matrix[GEOM_SPHERE][GEOM_CYLINDER] = &ShapeShapeDistance<Sphere, Cylinder>; + distance_matrix[GEOM_SPHERE][GEOM_CONVEX] = &ShapeShapeDistance<Sphere, ConvexBase>; + distance_matrix[GEOM_SPHERE][GEOM_PLANE] = &ShapeShapeDistance<Sphere, Plane>; + distance_matrix[GEOM_SPHERE][GEOM_HALFSPACE] = &ShapeShapeDistance<Sphere, Halfspace>; + + distance_matrix[GEOM_CAPSULE][GEOM_BOX] = &ShapeShapeDistance<Capsule, Box>; + distance_matrix[GEOM_CAPSULE][GEOM_SPHERE] = &ShapeShapeDistance<Capsule, Sphere>; + distance_matrix[GEOM_CAPSULE][GEOM_CAPSULE] = &ShapeShapeDistance<Capsule, Capsule>; + distance_matrix[GEOM_CAPSULE][GEOM_CONE] = &ShapeShapeDistance<Capsule, Cone>; + distance_matrix[GEOM_CAPSULE][GEOM_CYLINDER] = &ShapeShapeDistance<Capsule, Cylinder>; + distance_matrix[GEOM_CAPSULE][GEOM_CONVEX] = &ShapeShapeDistance<Capsule, ConvexBase>; + distance_matrix[GEOM_CAPSULE][GEOM_PLANE] = &ShapeShapeDistance<Capsule, Plane>; + distance_matrix[GEOM_CAPSULE][GEOM_HALFSPACE] = &ShapeShapeDistance<Capsule, Halfspace>; + + distance_matrix[GEOM_CONE][GEOM_BOX] = &ShapeShapeDistance<Cone, Box>; + distance_matrix[GEOM_CONE][GEOM_SPHERE] = &ShapeShapeDistance<Cone, Sphere>; + distance_matrix[GEOM_CONE][GEOM_CAPSULE] = &ShapeShapeDistance<Cone, Capsule>; + distance_matrix[GEOM_CONE][GEOM_CONE] = &ShapeShapeDistance<Cone, Cone>; + distance_matrix[GEOM_CONE][GEOM_CYLINDER] = &ShapeShapeDistance<Cone, Cylinder>; + distance_matrix[GEOM_CONE][GEOM_CONVEX] = &ShapeShapeDistance<Cone, ConvexBase>; + distance_matrix[GEOM_CONE][GEOM_PLANE] = &ShapeShapeDistance<Cone, Plane>; + distance_matrix[GEOM_CONE][GEOM_HALFSPACE] = &ShapeShapeDistance<Cone, Halfspace>; + + distance_matrix[GEOM_CYLINDER][GEOM_BOX] = &ShapeShapeDistance<Cylinder, Box>; + distance_matrix[GEOM_CYLINDER][GEOM_SPHERE] = &ShapeShapeDistance<Cylinder, Sphere>; + distance_matrix[GEOM_CYLINDER][GEOM_CAPSULE] = &ShapeShapeDistance<Cylinder, Capsule>; + distance_matrix[GEOM_CYLINDER][GEOM_CONE] = &ShapeShapeDistance<Cylinder, Cone>; + distance_matrix[GEOM_CYLINDER][GEOM_CYLINDER] = &ShapeShapeDistance<Cylinder, Cylinder>; + distance_matrix[GEOM_CYLINDER][GEOM_CONVEX] = &ShapeShapeDistance<Cylinder, ConvexBase>; + distance_matrix[GEOM_CYLINDER][GEOM_PLANE] = &ShapeShapeDistance<Cylinder, Plane>; + distance_matrix[GEOM_CYLINDER][GEOM_HALFSPACE] = &ShapeShapeDistance<Cylinder, Halfspace>; + + distance_matrix[GEOM_CONVEX][GEOM_BOX] = &ShapeShapeDistance<ConvexBase, Box>; + distance_matrix[GEOM_CONVEX][GEOM_SPHERE] = &ShapeShapeDistance<ConvexBase, Sphere>; + distance_matrix[GEOM_CONVEX][GEOM_CAPSULE] = &ShapeShapeDistance<ConvexBase, Capsule>; + distance_matrix[GEOM_CONVEX][GEOM_CONE] = &ShapeShapeDistance<ConvexBase, Cone>; + distance_matrix[GEOM_CONVEX][GEOM_CYLINDER] = &ShapeShapeDistance<ConvexBase, Cylinder>; + distance_matrix[GEOM_CONVEX][GEOM_CONVEX] = &ShapeShapeDistance<ConvexBase, ConvexBase>; + distance_matrix[GEOM_CONVEX][GEOM_PLANE] = &ShapeShapeDistance<ConvexBase, Plane>; + distance_matrix[GEOM_CONVEX][GEOM_HALFSPACE] = &ShapeShapeDistance<ConvexBase, Halfspace>; + + distance_matrix[GEOM_PLANE][GEOM_BOX] = &ShapeShapeDistance<Plane, Box>; + distance_matrix[GEOM_PLANE][GEOM_SPHERE] = &ShapeShapeDistance<Plane, Sphere>; + distance_matrix[GEOM_PLANE][GEOM_CAPSULE] = &ShapeShapeDistance<Plane, Capsule>; + distance_matrix[GEOM_PLANE][GEOM_CONE] = &ShapeShapeDistance<Plane, Cone>; + distance_matrix[GEOM_PLANE][GEOM_CYLINDER] = &ShapeShapeDistance<Plane, Cylinder>; + distance_matrix[GEOM_PLANE][GEOM_CONVEX] = &ShapeShapeDistance<Plane, ConvexBase>; + distance_matrix[GEOM_PLANE][GEOM_PLANE] = &ShapeShapeDistance<Plane, Plane>; + distance_matrix[GEOM_PLANE][GEOM_HALFSPACE] = &ShapeShapeDistance<Plane, Halfspace>; + + distance_matrix[GEOM_HALFSPACE][GEOM_BOX] = &ShapeShapeDistance<Halfspace, Box>; + distance_matrix[GEOM_HALFSPACE][GEOM_SPHERE] = &ShapeShapeDistance<Halfspace, Sphere>; + distance_matrix[GEOM_HALFSPACE][GEOM_CAPSULE] = &ShapeShapeDistance<Halfspace, Capsule>; + distance_matrix[GEOM_HALFSPACE][GEOM_CONE] = &ShapeShapeDistance<Halfspace, Cone>; + distance_matrix[GEOM_HALFSPACE][GEOM_CYLINDER] = &ShapeShapeDistance<Halfspace, Cylinder>; + distance_matrix[GEOM_HALFSPACE][GEOM_CONVEX] = &ShapeShapeDistance<Halfspace, ConvexBase>; + distance_matrix[GEOM_HALFSPACE][GEOM_PLANE] = &ShapeShapeDistance<Halfspace, Plane>; + distance_matrix[GEOM_HALFSPACE][GEOM_HALFSPACE] = &ShapeShapeDistance<Halfspace, Halfspace>; /* AABB distance not implemented */ /* - distance_matrix[BV_AABB][GEOM_BOX] = &BVHShapeDistancer<AABB, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeDistancer<AABB, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeDistancer<AABB, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_CONE] = &BVHShapeDistancer<AABB, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeDistancer<AABB, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeDistancer<AABB, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeDistancer<AABB, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeDistancer<AABB, Halfspace, NarrowPhaseSolver>::distance; + distance_matrix[BV_AABB][GEOM_BOX] = &BVHShapeDistancer<AABB, Box>::distance; + distance_matrix[BV_AABB][GEOM_SPHERE] = &BVHShapeDistancer<AABB, Sphere>::distance; + distance_matrix[BV_AABB][GEOM_CAPSULE] = &BVHShapeDistancer<AABB, Capsule>::distance; + distance_matrix[BV_AABB][GEOM_CONE] = &BVHShapeDistancer<AABB, Cone>::distance; + distance_matrix[BV_AABB][GEOM_CYLINDER] = &BVHShapeDistancer<AABB, Cylinder>::distance; + distance_matrix[BV_AABB][GEOM_CONVEX] = &BVHShapeDistancer<AABB, ConvexBase>::distance; + distance_matrix[BV_AABB][GEOM_PLANE] = &BVHShapeDistancer<AABB, Plane>::distance; + distance_matrix[BV_AABB][GEOM_HALFSPACE] = &BVHShapeDistancer<AABB, Halfspace>::distance; */ - distance_matrix[BV_OBB][GEOM_BOX] = &BVHShapeDistancer<OBB, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeDistancer<OBB, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeDistancer<OBB, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_CONE] = &BVHShapeDistancer<OBB, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeDistancer<OBB, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeDistancer<OBB, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeDistancer<OBB, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeDistancer<OBB, Halfspace, NarrowPhaseSolver>::distance; - - distance_matrix[BV_RSS][GEOM_BOX] = &BVHShapeDistancer<RSS, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeDistancer<RSS, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeDistancer<RSS, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_CONE] = &BVHShapeDistancer<RSS, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeDistancer<RSS, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeDistancer<RSS, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeDistancer<RSS, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeDistancer<RSS, Halfspace, NarrowPhaseSolver>::distance; + distance_matrix[BV_OBB][GEOM_BOX] = &BVHShapeDistancer<OBB, Box>::distance; + distance_matrix[BV_OBB][GEOM_SPHERE] = &BVHShapeDistancer<OBB, Sphere>::distance; + distance_matrix[BV_OBB][GEOM_CAPSULE] = &BVHShapeDistancer<OBB, Capsule>::distance; + distance_matrix[BV_OBB][GEOM_CONE] = &BVHShapeDistancer<OBB, Cone>::distance; + distance_matrix[BV_OBB][GEOM_CYLINDER] = &BVHShapeDistancer<OBB, Cylinder>::distance; + distance_matrix[BV_OBB][GEOM_CONVEX] = &BVHShapeDistancer<OBB, ConvexBase>::distance; + distance_matrix[BV_OBB][GEOM_PLANE] = &BVHShapeDistancer<OBB, Plane>::distance; + distance_matrix[BV_OBB][GEOM_HALFSPACE] = &BVHShapeDistancer<OBB, Halfspace>::distance; + + distance_matrix[BV_RSS][GEOM_BOX] = &BVHShapeDistancer<RSS, Box>::distance; + distance_matrix[BV_RSS][GEOM_SPHERE] = &BVHShapeDistancer<RSS, Sphere>::distance; + distance_matrix[BV_RSS][GEOM_CAPSULE] = &BVHShapeDistancer<RSS, Capsule>::distance; + distance_matrix[BV_RSS][GEOM_CONE] = &BVHShapeDistancer<RSS, Cone>::distance; + distance_matrix[BV_RSS][GEOM_CYLINDER] = &BVHShapeDistancer<RSS, Cylinder>::distance; + distance_matrix[BV_RSS][GEOM_CONVEX] = &BVHShapeDistancer<RSS, ConvexBase>::distance; + distance_matrix[BV_RSS][GEOM_PLANE] = &BVHShapeDistancer<RSS, Plane>::distance; + distance_matrix[BV_RSS][GEOM_HALFSPACE] = &BVHShapeDistancer<RSS, Halfspace>::distance; /* KDOP distance not implemented */ /* - distance_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeDistancer<KDOP<16>, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<16>, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<16>, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeDistancer<KDOP<16>, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<16>, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<16>, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeDistancer<KDOP<16>, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<16>, Halfspace, NarrowPhaseSolver>::distance; - - distance_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeDistancer<KDOP<18>, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<18>, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<18>, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeDistancer<KDOP<18>, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<18>, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<18>, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeDistancer<KDOP<18>, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<18>, Halfspace, NarrowPhaseSolver>::distance; - - distance_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeDistancer<KDOP<24>, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<24>, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<24>, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeDistancer<KDOP<24>, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<24>, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<24>, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeDistancer<KDOP<24>, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<24>, Halfspace, NarrowPhaseSolver>::distance; + distance_matrix[BV_KDOP16][GEOM_BOX] = &BVHShapeDistancer<KDOP<16>, Box>::distance; + distance_matrix[BV_KDOP16][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<16>, Sphere>::distance; + distance_matrix[BV_KDOP16][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<16>, Capsule>::distance; + distance_matrix[BV_KDOP16][GEOM_CONE] = &BVHShapeDistancer<KDOP<16>, Cone>::distance; + distance_matrix[BV_KDOP16][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<16>, Cylinder>::distance; + distance_matrix[BV_KDOP16][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<16>, ConvexBase>::distance; + distance_matrix[BV_KDOP16][GEOM_PLANE] = &BVHShapeDistancer<KDOP<16>, Plane>::distance; + distance_matrix[BV_KDOP16][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<16>, Halfspace>::distance; + + distance_matrix[BV_KDOP18][GEOM_BOX] = &BVHShapeDistancer<KDOP<18>, Box>::distance; + distance_matrix[BV_KDOP18][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<18>, Sphere>::distance; + distance_matrix[BV_KDOP18][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<18>, Capsule>::distance; + distance_matrix[BV_KDOP18][GEOM_CONE] = &BVHShapeDistancer<KDOP<18>, Cone>::distance; + distance_matrix[BV_KDOP18][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<18>, Cylinder>::distance; + distance_matrix[BV_KDOP18][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<18>, ConvexBase>::distance; + distance_matrix[BV_KDOP18][GEOM_PLANE] = &BVHShapeDistancer<KDOP<18>, Plane>::distance; + distance_matrix[BV_KDOP18][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<18>, Halfspace>::distance; + + distance_matrix[BV_KDOP24][GEOM_BOX] = &BVHShapeDistancer<KDOP<24>, Box>::distance; + distance_matrix[BV_KDOP24][GEOM_SPHERE] = &BVHShapeDistancer<KDOP<24>, Sphere>::distance; + distance_matrix[BV_KDOP24][GEOM_CAPSULE] = &BVHShapeDistancer<KDOP<24>, Capsule>::distance; + distance_matrix[BV_KDOP24][GEOM_CONE] = &BVHShapeDistancer<KDOP<24>, Cone>::distance; + distance_matrix[BV_KDOP24][GEOM_CYLINDER] = &BVHShapeDistancer<KDOP<24>, Cylinder>::distance; + distance_matrix[BV_KDOP24][GEOM_CONVEX] = &BVHShapeDistancer<KDOP<24>, ConvexBase>::distance; + distance_matrix[BV_KDOP24][GEOM_PLANE] = &BVHShapeDistancer<KDOP<24>, Plane>::distance; + distance_matrix[BV_KDOP24][GEOM_HALFSPACE] = &BVHShapeDistancer<KDOP<24>, Halfspace>::distance; */ - distance_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeDistancer<kIOS, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeDistancer<kIOS, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeDistancer<kIOS, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeDistancer<kIOS, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeDistancer<kIOS, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeDistancer<kIOS, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeDistancer<kIOS, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeDistancer<kIOS, Halfspace, NarrowPhaseSolver>::distance; - - distance_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeDistancer<OBBRSS, Box, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeDistancer<OBBRSS, Sphere, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeDistancer<OBBRSS, Capsule, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeDistancer<OBBRSS, Cone, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeDistancer<OBBRSS, Cylinder, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeDistancer<OBBRSS, Convex, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeDistancer<OBBRSS, Plane, NarrowPhaseSolver>::distance; - distance_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeDistancer<OBBRSS, Halfspace, NarrowPhaseSolver>::distance; - - distance_matrix[BV_AABB][BV_AABB] = &BVHDistance<AABB, NarrowPhaseSolver>; - distance_matrix[BV_OBB][BV_OBB] = &BVHDistance<OBB, NarrowPhaseSolver>; - distance_matrix[BV_RSS][BV_RSS] = &BVHDistance<RSS, NarrowPhaseSolver>; - distance_matrix[BV_kIOS][BV_kIOS] = &BVHDistance<kIOS, NarrowPhaseSolver>; - distance_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHDistance<OBBRSS, NarrowPhaseSolver>; + distance_matrix[BV_kIOS][GEOM_BOX] = &BVHShapeDistancer<kIOS, Box>::distance; + distance_matrix[BV_kIOS][GEOM_SPHERE] = &BVHShapeDistancer<kIOS, Sphere>::distance; + distance_matrix[BV_kIOS][GEOM_CAPSULE] = &BVHShapeDistancer<kIOS, Capsule>::distance; + distance_matrix[BV_kIOS][GEOM_CONE] = &BVHShapeDistancer<kIOS, Cone>::distance; + distance_matrix[BV_kIOS][GEOM_CYLINDER] = &BVHShapeDistancer<kIOS, Cylinder>::distance; + distance_matrix[BV_kIOS][GEOM_CONVEX] = &BVHShapeDistancer<kIOS, ConvexBase>::distance; + distance_matrix[BV_kIOS][GEOM_PLANE] = &BVHShapeDistancer<kIOS, Plane>::distance; + distance_matrix[BV_kIOS][GEOM_HALFSPACE] = &BVHShapeDistancer<kIOS, Halfspace>::distance; + + distance_matrix[BV_OBBRSS][GEOM_BOX] = &BVHShapeDistancer<OBBRSS, Box>::distance; + distance_matrix[BV_OBBRSS][GEOM_SPHERE] = &BVHShapeDistancer<OBBRSS, Sphere>::distance; + distance_matrix[BV_OBBRSS][GEOM_CAPSULE] = &BVHShapeDistancer<OBBRSS, Capsule>::distance; + distance_matrix[BV_OBBRSS][GEOM_CONE] = &BVHShapeDistancer<OBBRSS, Cone>::distance; + distance_matrix[BV_OBBRSS][GEOM_CYLINDER] = &BVHShapeDistancer<OBBRSS, Cylinder>::distance; + distance_matrix[BV_OBBRSS][GEOM_CONVEX] = &BVHShapeDistancer<OBBRSS, ConvexBase>::distance; + distance_matrix[BV_OBBRSS][GEOM_PLANE] = &BVHShapeDistancer<OBBRSS, Plane>::distance; + distance_matrix[BV_OBBRSS][GEOM_HALFSPACE] = &BVHShapeDistancer<OBBRSS, Halfspace>::distance; + + distance_matrix[BV_AABB][BV_AABB] = &BVHDistance<AABB>; + distance_matrix[BV_OBB][BV_OBB] = &BVHDistance<OBB>; + distance_matrix[BV_RSS][BV_RSS] = &BVHDistance<RSS>; + distance_matrix[BV_kIOS][BV_kIOS] = &BVHDistance<kIOS>; + distance_matrix[BV_OBBRSS][BV_OBBRSS] = &BVHDistance<OBBRSS>; #ifdef HPP_FCL_HAVE_OCTOMAP - distance_matrix[GEOM_OCTREE][GEOM_BOX] = &OcTreeShapeDistance<Box, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_SPHERE] = &OcTreeShapeDistance<Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &OcTreeShapeDistance<Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_CONE] = &OcTreeShapeDistance<Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &OcTreeShapeDistance<Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_CONVEX] = &OcTreeShapeDistance<Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_PLANE] = &OcTreeShapeDistance<Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &OcTreeShapeDistance<Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_BOX][GEOM_OCTREE] = &ShapeOcTreeDistance<Box, NarrowPhaseSolver>; - distance_matrix[GEOM_SPHERE][GEOM_OCTREE] = &ShapeOcTreeDistance<Sphere, NarrowPhaseSolver>; - distance_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &ShapeOcTreeDistance<Capsule, NarrowPhaseSolver>; - distance_matrix[GEOM_CONE][GEOM_OCTREE] = &ShapeOcTreeDistance<Cone, NarrowPhaseSolver>; - distance_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &ShapeOcTreeDistance<Cylinder, NarrowPhaseSolver>; - distance_matrix[GEOM_CONVEX][GEOM_OCTREE] = &ShapeOcTreeDistance<Convex, NarrowPhaseSolver>; - distance_matrix[GEOM_PLANE][GEOM_OCTREE] = &ShapeOcTreeDistance<Plane, NarrowPhaseSolver>; - distance_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &ShapeOcTreeDistance<Halfspace, NarrowPhaseSolver>; - - distance_matrix[GEOM_OCTREE][GEOM_OCTREE] = &OcTreeDistance<NarrowPhaseSolver>; - - distance_matrix[GEOM_OCTREE][BV_AABB] = &OcTreeBVHDistance<AABB, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_OBB] = &OcTreeBVHDistance<OBB, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_RSS] = &OcTreeBVHDistance<RSS, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_OBBRSS] = &OcTreeBVHDistance<OBBRSS, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_kIOS] = &OcTreeBVHDistance<kIOS, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_KDOP16] = &OcTreeBVHDistance<KDOP<16>, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_KDOP18] = &OcTreeBVHDistance<KDOP<18>, NarrowPhaseSolver>; - distance_matrix[GEOM_OCTREE][BV_KDOP24] = &OcTreeBVHDistance<KDOP<24>, NarrowPhaseSolver>; - - distance_matrix[BV_AABB][GEOM_OCTREE] = &BVHOcTreeDistance<AABB, NarrowPhaseSolver>; - distance_matrix[BV_OBB][GEOM_OCTREE] = &BVHOcTreeDistance<OBB, NarrowPhaseSolver>; - distance_matrix[BV_RSS][GEOM_OCTREE] = &BVHOcTreeDistance<RSS, NarrowPhaseSolver>; - distance_matrix[BV_OBBRSS][GEOM_OCTREE] = &BVHOcTreeDistance<OBBRSS, NarrowPhaseSolver>; - distance_matrix[BV_kIOS][GEOM_OCTREE] = &BVHOcTreeDistance<kIOS, NarrowPhaseSolver>; - distance_matrix[BV_KDOP16][GEOM_OCTREE] = &BVHOcTreeDistance<KDOP<16>, NarrowPhaseSolver>; - distance_matrix[BV_KDOP18][GEOM_OCTREE] = &BVHOcTreeDistance<KDOP<18>, NarrowPhaseSolver>; - distance_matrix[BV_KDOP24][GEOM_OCTREE] = &BVHOcTreeDistance<KDOP<24>, NarrowPhaseSolver>; + distance_matrix[GEOM_OCTREE][GEOM_BOX] = &Distance<OcTree, Box>; + distance_matrix[GEOM_OCTREE][GEOM_SPHERE] = &Distance<OcTree, Sphere>; + distance_matrix[GEOM_OCTREE][GEOM_CAPSULE] = &Distance<OcTree, Capsule>; + distance_matrix[GEOM_OCTREE][GEOM_CONE] = &Distance<OcTree, Cone>; + distance_matrix[GEOM_OCTREE][GEOM_CYLINDER] = &Distance<OcTree, Cylinder>; + distance_matrix[GEOM_OCTREE][GEOM_CONVEX] = &Distance<OcTree, ConvexBase>; + distance_matrix[GEOM_OCTREE][GEOM_PLANE] = &Distance<OcTree, Plane>; + distance_matrix[GEOM_OCTREE][GEOM_HALFSPACE] = &Distance<OcTree, Halfspace>; + + distance_matrix[GEOM_BOX][GEOM_OCTREE] = &Distance<Box, OcTree>; + distance_matrix[GEOM_SPHERE][GEOM_OCTREE] = &Distance<Sphere, OcTree>; + distance_matrix[GEOM_CAPSULE][GEOM_OCTREE] = &Distance<Capsule, OcTree>; + distance_matrix[GEOM_CONE][GEOM_OCTREE] = &Distance<Cone, OcTree>; + distance_matrix[GEOM_CYLINDER][GEOM_OCTREE] = &Distance<Cylinder, OcTree>; + distance_matrix[GEOM_CONVEX][GEOM_OCTREE] = &Distance<ConvexBase, OcTree>; + distance_matrix[GEOM_PLANE][GEOM_OCTREE] = &Distance<Plane, OcTree>; + distance_matrix[GEOM_HALFSPACE][GEOM_OCTREE] = &Distance<Halfspace, OcTree>; + + distance_matrix[GEOM_OCTREE][GEOM_OCTREE] = &Distance<OcTree, OcTree>; + + distance_matrix[GEOM_OCTREE][BV_AABB ] = &Distance<OcTree, BVHModel<AABB > >; + distance_matrix[GEOM_OCTREE][BV_OBB ] = &Distance<OcTree, BVHModel<OBB > >; + distance_matrix[GEOM_OCTREE][BV_RSS ] = &Distance<OcTree, BVHModel<RSS > >; + distance_matrix[GEOM_OCTREE][BV_OBBRSS] = &Distance<OcTree, BVHModel<OBBRSS > >; + distance_matrix[GEOM_OCTREE][BV_kIOS ] = &Distance<OcTree, BVHModel<kIOS > >; + distance_matrix[GEOM_OCTREE][BV_KDOP16] = &Distance<OcTree, BVHModel<KDOP<16> > >; + distance_matrix[GEOM_OCTREE][BV_KDOP18] = &Distance<OcTree, BVHModel<KDOP<18> > >; + distance_matrix[GEOM_OCTREE][BV_KDOP24] = &Distance<OcTree, BVHModel<KDOP<24> > >; + + distance_matrix[BV_AABB][GEOM_OCTREE ] = &Distance<BVHModel<AABB >, OcTree>; + distance_matrix[BV_OBB][GEOM_OCTREE ] = &Distance<BVHModel<OBB >, OcTree>; + distance_matrix[BV_RSS][GEOM_OCTREE ] = &Distance<BVHModel<RSS >, OcTree>; + distance_matrix[BV_OBBRSS][GEOM_OCTREE] = &Distance<BVHModel<OBBRSS >, OcTree>; + distance_matrix[BV_kIOS][GEOM_OCTREE ] = &Distance<BVHModel<kIOS >, OcTree>; + distance_matrix[BV_KDOP16][GEOM_OCTREE] = &Distance<BVHModel<KDOP<16> >, OcTree>; + distance_matrix[BV_KDOP18][GEOM_OCTREE] = &Distance<BVHModel<KDOP<18> >, OcTree>; + distance_matrix[BV_KDOP24][GEOM_OCTREE] = &Distance<BVHModel<KDOP<24> >, OcTree>; #endif } -template struct DistanceFunctionMatrix<GJKSolver_indep>; +//template struct DistanceFunctionMatrix; } } // namespace hpp diff --git a/src/distance_func_matrix.h b/src/distance_func_matrix.h index 5cb194384daf982f891d858de1297038277673ba..3a142614f523f3a9e35b285c248a46852edebd6f 100644 --- a/src/distance_func_matrix.h +++ b/src/distance_func_matrix.h @@ -34,24 +34,35 @@ /** \author Florent Lamiraux */ +#ifndef HPP_FCL_DISTANCE_FUNC_MATRIX_H +#define HPP_FCL_DISTANCE_FUNC_MATRIX_H + +/// @cond INTERNAL + #include <hpp/fcl/collision_data.h> +#include <hpp/fcl/narrowphase/narrowphase.h> namespace hpp { -namespace fcl { - template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver> +namespace fcl +{ + template<typename T_SH1, typename T_SH2> FCL_REAL ShapeShapeDistance (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, const DistanceRequest& request, + const GJKSolver* nsolver, const DistanceRequest& request, DistanceResult& result); - template<typename T_SH1, typename T_SH2, typename NarrowPhaseSolver> + template<typename T_SH1, typename T_SH2> std::size_t ShapeShapeCollide (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const NarrowPhaseSolver* nsolver, const CollisionRequest& request, + const GJKSolver* nsolver, const CollisionRequest& request, CollisionResult& result); } } // namespace hpp + +/// @endcond + +#endif \ No newline at end of file diff --git a/src/distance_sphere_cylinder.cpp b/src/distance_sphere_cylinder.cpp index 4b7387c30f4a728df647b5a53ffb07c86d9726d6..993933d98c11437394116540f907edf0ba0c8300 100644 --- a/src/distance_sphere_cylinder.cpp +++ b/src/distance_sphere_cylinder.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Sphere, Cylinder, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Sphere, Cylinder> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Sphere& s1 = static_cast <const Sphere&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Cylinder, Sphere, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Cylinder, Sphere> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Cylinder& s1 = static_cast <const Cylinder&> (*o1); diff --git a/src/distance_sphere_halfspace.cpp b/src/distance_sphere_halfspace.cpp index 80c3bd95f1ebef818f448d0eaad851c6c036a3db..6c7b9b7435a01e4785b401640f1f35064103295f 100644 --- a/src/distance_sphere_halfspace.cpp +++ b/src/distance_sphere_halfspace.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Sphere, Halfspace, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Sphere, Halfspace> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Sphere& s1 = static_cast <const Sphere&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Halfspace, Sphere, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Halfspace, Sphere> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Halfspace& s1 = static_cast <const Halfspace&> (*o1); diff --git a/src/distance_sphere_plane.cpp b/src/distance_sphere_plane.cpp index 7d0487629644113960e97fac60a7b85a9c74f095..28754534852fc053ed52621d8cedae1298ac8d22 100644 --- a/src/distance_sphere_plane.cpp +++ b/src/distance_sphere_plane.cpp @@ -40,19 +40,19 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" -#include "../src/narrowphase/details.h" +#include <../src/distance_func_matrix.h> +#include "narrowphase/details.h" namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Sphere, Plane, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Sphere, Plane> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Sphere& s1 = static_cast <const Sphere&> (*o1); @@ -65,10 +65,10 @@ namespace fcl { } template <> - FCL_REAL ShapeShapeDistance <Plane, Sphere, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Plane, Sphere> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { const Plane& s1 = static_cast <const Plane&> (*o1); diff --git a/src/distance_sphere_sphere.cpp b/src/distance_sphere_sphere.cpp index 40b383fde5bd4e96c36de2c7d74227bc458c3ceb..646ebe591b8e696690f6e94ee79d657df7851dd6 100644 --- a/src/distance_sphere_sphere.cpp +++ b/src/distance_sphere_sphere.cpp @@ -37,7 +37,7 @@ #include <limits> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "distance_func_matrix.h" +#include <../src/distance_func_matrix.h> // Note that partial specialization of template functions is not allowed. // Therefore, two implementations with the default narrow phase solvers are @@ -50,13 +50,13 @@ namespace hpp { namespace fcl { - class GJKSolver_indep; + class GJKSolver; template <> - FCL_REAL ShapeShapeDistance <Sphere, Sphere, GJKSolver_indep> + FCL_REAL ShapeShapeDistance <Sphere, Sphere> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const DistanceRequest&, + const GJKSolver*, const DistanceRequest&, DistanceResult& result) { FCL_REAL epsilon = 1e-7; @@ -97,10 +97,10 @@ namespace fcl { } template <> - std::size_t ShapeShapeCollide <Sphere, Sphere, GJKSolver_indep> + std::size_t ShapeShapeCollide <Sphere, Sphere> (const CollisionGeometry* o1, const Transform3f& tf1, const CollisionGeometry* o2, const Transform3f& tf2, - const GJKSolver_indep*, const CollisionRequest& request, + const GJKSolver*, const CollisionRequest& request, CollisionResult& result) { FCL_REAL epsilon = 1e-7; diff --git a/src/intersect.cpp b/src/intersect.cpp index e2bdab97bebe1319b7165ca8b2119f6a65df90c0..8cbfdda4a15cf66485de4ab22342000cb00563e6 100644 --- a/src/intersect.cpp +++ b/src/intersect.cpp @@ -35,144 +35,17 @@ /** \author Jia Pan */ -#include <hpp/fcl/intersect.h> +#include <hpp/fcl/internal/intersect.h> #include <iostream> #include <limits> #include <vector> #include <boost/math/special_functions/fpclassify.hpp> +#include <hpp/fcl/internal/tools.h> namespace hpp { namespace fcl { -const FCL_REAL PolySolver::NEAR_ZERO_THRESHOLD = 1e-9; - - -bool PolySolver::isZero(FCL_REAL v) -{ - return (v < NEAR_ZERO_THRESHOLD) && (v > -NEAR_ZERO_THRESHOLD); -} - -bool PolySolver::cbrt(FCL_REAL v) -{ - return powf((float) v, (float) (1.0 / 3.0)); -} - -int PolySolver::solveLinear(FCL_REAL c[2], FCL_REAL s[1]) -{ - if(isZero(c[1])) - return 0; - s[0] = - c[0] / c[1]; - return 1; -} - -int PolySolver::solveQuadric(FCL_REAL c[3], FCL_REAL s[2]) -{ - FCL_REAL p, q, D; - - // make sure we have a d2 equation - - if(isZero(c[2])) - return solveLinear(c, s); - - // normal for: x^2 + px + q - p = c[1] / (2.0 * c[2]); - q = c[0] / c[2]; - D = p * p - q; - - if(isZero(D)) - { - // one FCL_REAL root - s[0] = s[1] = -p; - return 1; - } - - if(D < 0.0) - // no real root - return 0; - else - { - // two real roots - FCL_REAL sqrt_D = sqrt(D); - s[0] = sqrt_D - p; - s[1] = -sqrt_D - p; - return 2; - } -} - -int PolySolver::solveCubic(FCL_REAL c[4], FCL_REAL s[3]) -{ - int i, num; - FCL_REAL sub, A, B, C, sq_A, p, q, cb_p, D; - const FCL_REAL ONE_OVER_THREE = 1 / 3.0; - const FCL_REAL PI = 3.14159265358979323846; - - // make sure we have a d2 equation - if(isZero(c[3])) - return solveQuadric(c, s); - - // normalize the equation:x ^ 3 + Ax ^ 2 + Bx + C = 0 - A = c[2] / c[3]; - B = c[1] / c[3]; - C = c[0] / c[3]; - - // substitute x = y - A / 3 to eliminate the quadratic term: x^3 + px + q = 0 - sq_A = A * A; - p = (-ONE_OVER_THREE * sq_A + B) * ONE_OVER_THREE; - q = 0.5 * (2.0 / 27.0 * A * sq_A - ONE_OVER_THREE * A * B + C); - - // use Cardano's formula - cb_p = p * p * p; - D = q * q + cb_p; - - if(isZero(D)) - { - if(isZero(q)) - { - // one triple solution - s[0] = 0.0; - num = 1; - } - else - { - // one single and one FCL_REAL solution - FCL_REAL u = cbrt(-q); - s[0] = 2.0 * u; - s[1] = -u; - num = 2; - } - } - else - { - if(D < 0.0) - { - // three real solutions - FCL_REAL phi = ONE_OVER_THREE * acos(-q / sqrt(-cb_p)); - FCL_REAL t = 2.0 * sqrt(-p); - s[0] = t * cos(phi); - s[1] = -t * cos(phi + PI / 3.0); - s[2] = -t * cos(phi - PI / 3.0); - num = 3; - } - else - { - // one real solution - FCL_REAL sqrt_D = sqrt(D); - FCL_REAL u = cbrt(sqrt_D + fabs(q)); - if(q > 0.0) - s[0] = - u + p / u ; - else - s[0] = u - p / u; - num = 1; - } - } - - // re-substitute - sub = ONE_OVER_THREE * A; - for(i = 0; i < num; i++) - s[i] -= sub; - return num; -} bool Intersect::buildTrianglePlane (const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, FCL_REAL* t) diff --git a/src/math/transform.cpp b/src/math/transform.cpp index 9e6b31c8e7ad71672ba495bd39c1873655003b4f..1e8c15bf81b195fffa2d8ab9aba555c77e7fb5a3 100644 --- a/src/math/transform.cpp +++ b/src/math/transform.cpp @@ -44,36 +44,17 @@ namespace hpp namespace fcl { -const Matrix3f& Transform3f::getRotationInternal() const -{ - if(!matrix_set) - { - R = q.toRotationMatrix(); - matrix_set = true; - } - - return R; -} - -Transform3f inverse(const Transform3f& tf) -{ - Transform3f res(tf); - return res.inverse(); -} - void relativeTransform(const Transform3f& tf1, const Transform3f& tf2, Transform3f& tf) { - const Quaternion3f& q1_inv = tf1.getQuatRotation().conjugate(); - tf = Transform3f(q1_inv * tf2.getQuatRotation(), q1_inv * (tf2.getTranslation() - tf1.getTranslation())); + tf = tf1.inverseTimes (tf2); } void relativeTransform2(const Transform3f& tf1, const Transform3f& tf2, Transform3f& tf) { - const Quaternion3f& q1inv = tf1.getQuatRotation().conjugate(); - const Quaternion3f& q2_q1inv = tf2.getQuatRotation() * q1inv; - tf = Transform3f(q2_q1inv, tf2.getTranslation() - q2_q1inv * tf1.getTranslation()); + Matrix3f R (tf2.getRotation() * tf1.getRotation().transpose()); + tf = Transform3f(R, tf2.getTranslation() - R * tf1.getTranslation()); } diff --git a/src/mesh_loader/assimp.cpp b/src/mesh_loader/assimp.cpp index 7e58853a73f8bdf86b1202e1e08b62cb933f3ca8..2645a4be2e07729b069eabe4bf8d00647a09e352 100644 --- a/src/mesh_loader/assimp.cpp +++ b/src/mesh_loader/assimp.cpp @@ -34,16 +34,102 @@ #include <hpp/fcl/mesh_loader/assimp.h> +// Assimp >= 5.0 is forcing the use of C++11 keywords. A fix has been submitted https://github.com/assimp/assimp/pull/2758. +// The next lines fixes the bug for current version of hpp-fcl. +#include <assimp/defs.h> +#if __cplusplus < 201103L && defined(AI_NO_EXCEPT) + #undef AI_NO_EXCEPT + #define AI_NO_EXCEPT +#endif + +#ifdef HPP_FCL_USE_ASSIMP_UNIFIED_HEADER_NAMES + #include <assimp/DefaultLogger.hpp> + #include <assimp/IOStream.hpp> + #include <assimp/IOSystem.hpp> + #include <assimp/Importer.hpp> + #include <assimp/postprocess.h> + #include <assimp/scene.h> +#else + #include <assimp/DefaultLogger.h> + #include <assimp/assimp.hpp> + #include <assimp/IOStream.h> + #include <assimp/IOSystem.h> + #include <assimp/aiPostProcess.h> + #include <assimp/aiScene.h> +#endif + namespace hpp { namespace fcl { -unsigned buildMesh (const fcl::Vec3f & scale, - const aiScene* scene, - const aiNode* node, - unsigned vertices_offset, - TriangleAndVertices & tv) +namespace internal +{ + +Loader::Loader () : importer (new Assimp::Importer()) +{ + // set list of ignored parameters (parameters used for rendering) + importer->SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, + aiComponent_TANGENTS_AND_BITANGENTS| + aiComponent_COLORS | + aiComponent_BONEWEIGHTS | + aiComponent_ANIMATIONS | + aiComponent_LIGHTS | + aiComponent_CAMERAS| + aiComponent_TEXTURES | + aiComponent_TEXCOORDS | + aiComponent_MATERIALS | + aiComponent_NORMALS + ); + +} + +Loader::~Loader () +{ + if (importer) delete importer; +} + +void Loader::load (const std::string & resource_path) +{ + scene = importer->ReadFile(resource_path.c_str(), + aiProcess_SortByPType | + aiProcess_Triangulate | + aiProcess_RemoveComponent | + aiProcess_ImproveCacheLocality | + // TODO: I (Joseph Mirabel) have no idea whether degenerated triangles are + // properly handled. Enabling aiProcess_FindDegenerates would throw an + // exception when that happens. Is it too conservative ? + // aiProcess_FindDegenerates | + aiProcess_JoinIdenticalVertices + ); + + if (!scene) + { + const std::string exception_message (std::string ("Could not load resource ") + resource_path + std::string("\n") + + importer->GetErrorString () + std::string("\n") + + "Hint: the mesh directory may be wrong."); + throw std::invalid_argument(exception_message); + } + + if (!scene->HasMeshes()) + throw std::invalid_argument (std::string ("No meshes found in file ")+resource_path); +} + +/** + * @brief Recursive procedure for building a mesh + * + * @param[in] scale Scale to apply when reading the ressource + * @param[in] scene Pointer to the assimp scene + * @param[in] node Current node of the scene + * @param[in] vertices_offset Current number of vertices in the model + * @param tv Triangles and Vertices of the mesh submodels + */ +unsigned recurseBuildMesh ( + const fcl::Vec3f & scale, + const aiScene* scene, + const aiNode* node, + unsigned vertices_offset, + TriangleAndVertices & tv) { if (!node) return 0; @@ -100,12 +186,20 @@ unsigned buildMesh (const fcl::Vec3f & scale, for (uint32_t i=0; i < node->mNumChildren; ++i) { - nbVertices += buildMesh(scale, scene, node->mChildren[i], nbVertices, tv); + nbVertices += recurseBuildMesh(scale, scene, node->mChildren[i], nbVertices, tv); } return nbVertices; } +void buildMesh (const fcl::Vec3f & scale, + const aiScene* scene, + unsigned vertices_offset, + TriangleAndVertices & tv) +{ + recurseBuildMesh (scale, scene, scene->mRootNode, vertices_offset, tv); } +} // namespace internal +} // namespace fcl } // namespace hpp diff --git a/src/mesh_loader/loader.cpp b/src/mesh_loader/loader.cpp index d2e9b36a2f7ded1cc9922ff8896365870d717477..4646a8bb603ebbe5b064439a7980706527ea25f8 100644 --- a/src/mesh_loader/loader.cpp +++ b/src/mesh_loader/loader.cpp @@ -53,14 +53,14 @@ namespace fcl { } template <typename BV> - CollisionGeometryPtr_t _load (const std::string& filename, const Vec3f& scale) + BVHModelPtr_t _load (const std::string& filename, const Vec3f& scale) { boost::shared_ptr < BVHModel<BV> > polyhedron (new BVHModel<BV>); loadPolyhedronFromResource (filename, scale, polyhedron); return polyhedron; } - CollisionGeometryPtr_t MeshLoader::load (const std::string& filename, + BVHModelPtr_t MeshLoader::load (const std::string& filename, const Vec3f& scale) { switch (bvType_) { @@ -77,13 +77,13 @@ namespace fcl { } } - CollisionGeometryPtr_t CachedMeshLoader::load (const std::string& filename, + BVHModelPtr_t CachedMeshLoader::load (const std::string& filename, const Vec3f& scale) { Key key (filename, scale); Cache_t::const_iterator _cached = cache_.find (key); if (_cached == cache_.end()) { - CollisionGeometryPtr_t geom = MeshLoader::load (filename, scale); + BVHModelPtr_t geom = MeshLoader::load (filename, scale); cache_.insert (std::make_pair(key, geom)); return geom; } else { diff --git a/src/narrowphase/details.h b/src/narrowphase/details.h index ee654943ab14cf258533fecef8366f6ba74f66f2..58036184bf7a6e40b6d75fbb9e73ac39e19f6375 100644 --- a/src/narrowphase/details.h +++ b/src/narrowphase/details.h @@ -38,8 +38,7 @@ #ifndef HPP_FCL_SRC_NARROWPHASE_DETAILS_H # define HPP_FCL_SRC_NARROWPHASE_DETAILS_H -#include <hpp/fcl/collision_node.h> -#include <hpp/fcl/traversal/traversal_node_setup.h> +#include <hpp/fcl/internal/traversal_node_setup.h> #include <hpp/fcl/narrowphase/narrowphase.h> namespace hpp @@ -74,11 +73,8 @@ namespace fcl { const Capsule& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal_) { - Transform3f tf2_inv (tf2); - tf2_inv.inverse(); - - Vec3f pos1 (tf2.transform (Vec3f (0., 0., 0.5 * s2.lz))); // from distance function - Vec3f pos2 (tf2.transform (Vec3f (0., 0., -0.5 * s2.lz))); + Vec3f pos1 (tf2.transform (Vec3f (0., 0., s2.halfLength))); // from distance function + Vec3f pos2 (tf2.transform (Vec3f (0., 0., -s2.halfLength))); Vec3f s_c = tf1.getTranslation (); Vec3f segment_point; @@ -112,11 +108,8 @@ namespace fcl { const Capsule& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) { - Transform3f tf2_inv(tf2); - tf2_inv.inverse(); - - Vec3f pos1 (tf2.transform (Vec3f (0., 0., 0.5 * s2.lz))); - Vec3f pos2 (tf2.transform (Vec3f (0., 0., -0.5 * s2.lz))); + Vec3f pos1 (tf2.transform (Vec3f (0., 0., s2.halfLength))); + Vec3f pos2 (tf2.transform (Vec3f (0., 0., -s2.halfLength))); Vec3f s_c = tf1.getTranslation (); Vec3f segment_point; @@ -126,7 +119,7 @@ namespace fcl { FCL_REAL norm (normal.norm()); dist = norm - s1.radius - s2.radius; - FCL_REAL eps (std::numeric_limits<FCL_REAL>::epsilon()); + static const FCL_REAL eps (std::numeric_limits<FCL_REAL>::epsilon()); if (norm > eps) { normal.normalize(); } else { @@ -147,10 +140,10 @@ namespace fcl { const Cylinder& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) { - FCL_REAL eps (sqrt (std::numeric_limits <FCL_REAL>::epsilon ())); + static const FCL_REAL eps (sqrt (std::numeric_limits <FCL_REAL>::epsilon ())); FCL_REAL r1 (s1.radius); FCL_REAL r2 (s2.radius); - FCL_REAL lz2 (.5*s2.lz); + FCL_REAL lz2 (s2.halfLength); // boundaries of the cylinder axis Vec3f A (tf2.transform (Vec3f (0, 0, -lz2))); Vec3f B (tf2.transform (Vec3f (0, 0, lz2))); @@ -158,7 +151,7 @@ namespace fcl { Vec3f S (tf1.getTranslation ()); // axis of the cylinder Vec3f u (tf2.getRotation ().col (2)); - assert ((B - A - s2.lz * u).norm () < eps); + assert ((B - A - (s2.halfLength * 2) * u).norm () < eps); Vec3f AS (S - A); // abscissa of S on cylinder axis with A as the origin FCL_REAL s (u.dot (AS)); @@ -193,7 +186,7 @@ namespace fcl { dist = -r1; } } - } else if (s <= s2.lz) { + } else if (s <= (s2.halfLength * 2)) { // 0 < s <= s2.lz normal = -v; dist = dPS - r1 - r2; @@ -207,7 +200,7 @@ namespace fcl { // lz < s if (dPS <= r2) { // closest point on cylinder is on cylinder disc basis - dist = s - s2.lz - r1; p1 = S - r1 * u; p2 = B + dPS * v; normal = -u; + dist = s - (s2.halfLength * 2) - r1; p1 = S - r1 * u; p2 = B + dPS * v; normal = -u; } else { // closest point on cylinder is on cylinder circle basis p2 = B + r2 * v; @@ -280,7 +273,7 @@ namespace fcl { return (dist >=0); } - /** \brief the minimum distance from a point to a line */ + /** @brief the minimum distance from a point to a line */ inline FCL_REAL segmentSqrDistance (const Vec3f& from, const Vec3f& to,const Vec3f& p, Vec3f& nearest) { @@ -860,8 +853,8 @@ namespace fcl { - inline int boxBox2(const Vec3f& side1, const Matrix3f& R1, const Vec3f& T1, - const Vec3f& side2, const Matrix3f& R2, const Vec3f& T2, + inline int boxBox2(const Vec3f& halfSide1, const Matrix3f& R1, const Vec3f& T1, + const Vec3f& halfSide2, const Matrix3f& R2, const Vec3f& T2, Vec3f& normal, FCL_REAL* depth, int* return_code, int maxc, std::vector<ContactPoint>& contacts) { @@ -874,8 +867,8 @@ namespace fcl { Vec3f pp (R1.transpose() * p); // get pp = p relative to body 1 // get side lengths / 2 - Vec3f A (side1 * 0.5); - Vec3f B (side2 * 0.5); + const Vec3f& A (halfSide1); + const Vec3f& B (halfSide2); // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 Matrix3f R (R1.transpose() * R2); @@ -979,7 +972,7 @@ namespace fcl { Q.array() += fudge2; Vec3f n; - FCL_REAL eps = std::numeric_limits<FCL_REAL>::epsilon(); + static const FCL_REAL eps = std::numeric_limits<FCL_REAL>::epsilon(); // separating axis = u1 x (v1,v2,v3) tmp = pp[2] * R(1, 0) - pp[1] * R(2, 0); @@ -1443,8 +1436,8 @@ namespace fcl { int return_code; Vec3f normal; FCL_REAL depth; - /* int cnum = */ boxBox2(s1.side, tf1.getRotation(), tf1.getTranslation(), - s2.side, tf2.getRotation(), tf2.getTranslation(), + /* int cnum = */ boxBox2(s1.halfSide, tf1.getRotation(), tf1.getTranslation(), + s2.halfSide, tf2.getRotation(), tf2.getTranslation(), normal, &depth, &return_code, 4, contacts); @@ -1518,11 +1511,9 @@ namespace fcl { const Matrix3f& R = tf1.getRotation(); const Vec3f& T = tf1.getTranslation(); - Vec3f Q = R.transpose() * new_s2.n; - Vec3f A(Q[0] * s1.side[0], Q[1] * s1.side[1], Q[2] * s1.side[2]); - Vec3f B = A.cwiseAbs(); + Vec3f Q (R.transpose() * new_s2.n); - FCL_REAL depth = 0.5 * (B[0] + B[1] + B[2]) - new_s2.signedDistance(T); + FCL_REAL depth = Q.cwiseProduct(s1.halfSide).lpNorm<1>() - new_s2.signedDistance(T); return (depth >= 0); } @@ -1538,27 +1529,17 @@ namespace fcl { const Vec3f& T = tf1.getTranslation(); // Q: plane normal expressed in box frame - Vec3f Q = R.transpose() * new_s2.n; + const Vec3f Q (R.transpose() * new_s2.n); // A: scalar products of each side with normal - Vec3f A(Q[0] * s1.side[0], Q[1] * s1.side[1], Q[2] * s1.side[2]); - Vec3f B = A.cwiseAbs(); + const Vec3f A (Q.cwiseProduct(s1.halfSide)); - distance = new_s2.signedDistance(T) - 0.5 * (B[0] + B[1] + B[2]); + distance = new_s2.signedDistance(T) - A.lpNorm<1>(); if(distance > 0) { - p1 = T; - for (Vec3f::Index i=0; i<3; ++i) { - p1 -= A [i] > 0 ? (-.5 * s1.side [i] * R.col (i)) : - (.5 * s1.side [i] * R.col (i)); - } - p2 = p1 - distance * new_s2.n; + p1.noalias() = T + R * (A.array() > 0).select (s1.halfSide, - s1.halfSide); + p2.noalias() = p1 - distance * new_s2.n; return false; } - Vec3f axis[3]; - axis[0] = R.col(0); - axis[1] = R.col(1); - axis[2] = R.col(2); - /// find deepest point Vec3f p(T); int sign = 0; @@ -1566,25 +1547,21 @@ namespace fcl { if(std::abs(Q[0] - 1) < halfspaceIntersectTolerance<FCL_REAL>() || std::abs(Q[0] + 1) < halfspaceIntersectTolerance<FCL_REAL>()) { sign = (A[0] > 0) ? -1 : 1; - p += axis[0] * (0.5 * s1.side[0] * sign); + p += R.col(0) * (s1.halfSide[0] * sign); } else if(std::abs(Q[1] - 1) < halfspaceIntersectTolerance<FCL_REAL>() || std::abs(Q[1] + 1) < halfspaceIntersectTolerance<FCL_REAL>()) { sign = (A[1] > 0) ? -1 : 1; - p += axis[1] * (0.5 * s1.side[1] * sign); + p += R.col(1) * (s1.halfSide[1] * sign); } else if(std::abs(Q[2] - 1) < halfspaceIntersectTolerance<FCL_REAL>() || std::abs(Q[2] + 1) < halfspaceIntersectTolerance<FCL_REAL>()) { sign = (A[2] > 0) ? -1 : 1; - p += axis[2] * (0.5 * s1.side[2] * sign); + p += R.col(2) * (s1.halfSide[2] * sign); } else { - for(std::size_t i = 0; i < 3; ++i) - { - sign = (A[i] > 0) ? -1 : 1; - p += axis[i] * (0.5 * s1.side[i] * sign); - } + p.noalias() += R * (A.array() > 0).select (-s1.halfSide, s1.halfSide); } /// compute the contact point from the deepest point @@ -1628,7 +1605,7 @@ namespace fcl { int sign = (cosa > 0) ? -1 : 1; // closest capsule vertex to halfspace if no collision, // or deeper inside halspace if collision - Vec3f p = T + dir_z * (s1.lz * 0.5 * sign); + Vec3f p = T + dir_z * (s1.halfLength * sign); FCL_REAL signed_dist = new_s2.signedDistance(p); distance = signed_dist - s1.radius; @@ -1689,7 +1666,7 @@ namespace fcl { int sign = (cosa > 0) ? -1 : 1; // deepest point - Vec3f p = T + dir_z * (s1.lz * 0.5 * sign) + C; + Vec3f p = T + dir_z * (s1.halfLength * sign) + C; distance = new_s2.signedDistance(p); if(distance > 0) { // TODO: compute closest points @@ -1731,7 +1708,7 @@ namespace fcl { else { normal = -new_s2.n; - p1 = p2 = T - dir_z * (s1.lz * 0.5) - + p1 = p2 = T - dir_z * (s1.halfLength) - new_s2.n * (0.5 * distance + s1.radius); return true; } @@ -1749,8 +1726,8 @@ namespace fcl { C *= s; } - Vec3f a1 = T + dir_z * (0.5 * s1.lz); - Vec3f a2 = T - dir_z * (0.5 * s1.lz) + C; + Vec3f a1 = T + dir_z * (s1.halfLength); + Vec3f a2 = T - dir_z * (s1.halfLength) + C; FCL_REAL d1 = new_s2.signedDistance(a1); FCL_REAL d2 = new_s2.signedDistance(a2); @@ -1767,7 +1744,7 @@ namespace fcl { } inline bool convexHalfspaceIntersect - (const Convex& s1, const Transform3f& tf1, + (const ConvexBase& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) { @@ -2040,33 +2017,32 @@ namespace fcl { // Vec3f* contact_points, // FCL_REAL* penetration_depth, Vec3f* normal) { - FCL_REAL eps (sqrt (std::numeric_limits<FCL_REAL>::epsilon())); + static const FCL_REAL eps (sqrt (std::numeric_limits<FCL_REAL>::epsilon())); Plane new_s2 = transform(s2, tf2); const Matrix3f& R = tf1.getRotation(); const Vec3f& T = tf1.getTranslation(); - Vec3f Q = R.transpose() * new_s2.n; - Vec3f A(Q[0] * s1.side[0], Q[1] * s1.side[1], Q[2] * s1.side[2]); - Vec3f B = A.cwiseAbs(); + const Vec3f Q (R.transpose() * new_s2.n); + const Vec3f A (Q.cwiseProduct(s1.halfSide)); FCL_REAL signed_dist = new_s2.signedDistance(T); - distance = std::abs(signed_dist) - 0.5 * (B[0] + B[1] + B[2]); + distance = std::abs(signed_dist) - A.lpNorm<1>(); if(distance > 0) { // Is the box above or below the plane - int sign = signed_dist > 0 ? 1 : -1; + const bool positive = signed_dist > 0; // Set p1 at the center of the box p1 = T; for (Vec3f::Index i=0; i<3; ++i) { // scalar product between box axis and plane normal - FCL_REAL alpha (R.col (i).dot (new_s2.n)); - if (sign * alpha > eps) { - p1 -= .5 * R.col (i) * s1.side [i]; - } else if (sign * alpha < -eps) { - p1 += .5 * R.col (i) * s1.side [i]; + FCL_REAL alpha ((positive ? 1 : -1 ) * R.col (i).dot (new_s2.n)); + if (alpha > eps) { + p1 -= R.col (i) * s1.halfSide [i]; + } else if (alpha < -eps) { + p1 += R.col (i) * s1.halfSide [i]; } } - p2 = p1 - sign * distance * new_s2.n; + p2 = p1 - ( positive ? distance : -distance) * new_s2.n; assert (new_s2.distance (p2) < 3 *eps); return false; } @@ -2087,32 +2063,25 @@ namespace fcl { if(std::abs(Q[0] - 1) < planeIntersectTolerance<FCL_REAL>() || std::abs(Q[0] + 1) < planeIntersectTolerance<FCL_REAL>()) { - int sign2 = (A[0] > 0) ? -1 : 1; - sign2 *= sign; - p += axis[0] * (0.5 * s1.side[0] * sign2); + int sign2 = (A[0] > 0) ? -sign : sign; + p += R.col(0) * (s1.halfSide[0] * sign2); } else if(std::abs(Q[1] - 1) < planeIntersectTolerance<FCL_REAL>() || std::abs(Q[1] + 1) < planeIntersectTolerance<FCL_REAL>()) { - int sign2 = (A[1] > 0) ? -1 : 1; - sign2 *= sign; - p += axis[1] * (0.5 * s1.side[1] * sign2); + int sign2 = (A[1] > 0) ? -sign : sign; + p += R.col(1) * (s1.halfSide[1] * sign2); } else if(std::abs(Q[2] - 1) < planeIntersectTolerance<FCL_REAL>() || std::abs(Q[2] + 1) < planeIntersectTolerance<FCL_REAL>()) { - int sign2 = (A[2] > 0) ? -1 : 1; - sign2 *= sign; - p += axis[2] * (0.5 * s1.side[2] * sign2); + int sign2 = (A[2] > 0) ? -sign : sign; + p += R.col(2) * (s1.halfSide[2] * sign2); } else { - for(std::size_t i = 0; i < 3; ++i) - { - int sign2 = (A[i] > 0) ? -1 : 1; - sign2 *= sign; - p += axis[i] * (0.5 * s1.side[i] * sign2); - } + Vec3f tmp(sign * R * s1.halfSide); + p += (A.array() > 0).select (- tmp, tmp); } // compute the contact point by project the deepest point onto the plane @@ -2123,11 +2092,11 @@ namespace fcl { } /// Taken from book Real Time Collision Detection, from Christer Ericson - /// \param pb the closest point to the sphere center on the box surface - /// \param ps when colliding, matches pb, which is inside the sphere. + /// @param pb the closest point to the sphere center on the box surface + /// @param ps when colliding, matches pb, which is inside the sphere. /// when not colliding, the closest point on the sphere - /// \param normal direction of motion of the box - /// \return true if the distance is negative (the shape overlaps). + /// @param normal direction of motion of the box + /// @return true if the distance is negative (the shape overlaps). inline bool boxSphereDistance(const Box & b, const Transform3f& tfb, const Sphere& s, const Transform3f& tfs, FCL_REAL& dist, Vec3f& pb, Vec3f& ps, @@ -2143,7 +2112,7 @@ namespace fcl { bool inside = true; for (int i = 0; i < 3; ++i) { bool iinside = false; - FCL_REAL dist = Rb.col(i).dot(d), side_2 = b.side(i) / 2; + FCL_REAL dist = Rb.col(i).dot(d), side_2 = b.halfSide(i); if (dist < -side_2) dist = -side_2; // outside else if (dist > side_2) dist = side_2; // outside else iinside = true; // inside @@ -2184,8 +2153,8 @@ namespace fcl { Vec3f dir_z = R1.col(2); // ends of capsule inner segment - Vec3f a1 = T1 + dir_z * (0.5 * s1.lz); - Vec3f a2 = T1 - dir_z * (0.5 * s1.lz); + Vec3f a1 = T1 + dir_z * s1.halfLength; + Vec3f a2 = T1 - dir_z * s1.halfLength; FCL_REAL d1 = new_s2.signedDistance(a1); FCL_REAL d2 = new_s2.signedDistance(a2); @@ -2309,8 +2278,8 @@ namespace fcl { C *= s; } - Vec3f a1 = T + dir_z * (0.5 * s1.lz); - Vec3f a2 = T - dir_z * (0.5 * s1.lz); + Vec3f a1 = T + dir_z * (s1.halfLength); + Vec3f a2 = T - dir_z * (s1.halfLength); Vec3f c1, c2; if(cosa > 0) @@ -2377,8 +2346,8 @@ namespace fcl { else { if (d < 0) normal = new_s2.n; else normal = -new_s2.n; - p1 = p2 = T - dir_z * (0.5 * s1.lz) + - dir_z * (-0.5 * distance / s1.radius * s1.lz) - new_s2.n * d; + p1 = p2 = T - dir_z * (s1.halfLength) + + dir_z * (- distance / s1.radius * s1.halfLength) - new_s2.n * d; return true; } } @@ -2396,9 +2365,9 @@ namespace fcl { } Vec3f c[3]; - c[0] = T + dir_z * (0.5 * s1.lz); - c[1] = T - dir_z * (0.5 * s1.lz) + C; - c[2] = T - dir_z * (0.5 * s1.lz) - C; + c[0] = T + dir_z * (s1.halfLength); + c[1] = T - dir_z * (s1.halfLength) + C; + c[2] = T - dir_z * (s1.halfLength) - C; FCL_REAL d[3]; d[0] = new_s2.signedDistance(c[0]); @@ -2468,7 +2437,7 @@ namespace fcl { } inline bool convexPlaneIntersect - (const Convex& s1, const Transform3f& tf1, + (const ConvexBase& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) { @@ -2651,6 +2620,21 @@ namespace fcl { return true; } + + /// See the prototype below + inline FCL_REAL computePenetration + (const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, + const Vec3f& Q1, const Vec3f& Q2, const Vec3f& Q3, + Vec3f& normal) + { + Vec3f u ((P2-P1).cross (P3-P1)); + normal = u.normalized (); + FCL_REAL depth1 ((P1-Q1).dot (normal)); + FCL_REAL depth2 ((P1-Q2).dot (normal)); + FCL_REAL depth3 ((P1-Q3).dot (normal)); + return std::max (depth1, std::max (depth2, depth3)); + } + // Compute penetration distance and normal of two triangles in collision // Normal is normal of triangle 1 (P1, P2, P3), penetration depth is the // minimal distance (Q1, Q2, Q3) should be translated along the normal so @@ -2669,14 +2653,8 @@ namespace fcl { Vec3f globalQ1 (tf2.transform (Q1)); Vec3f globalQ2 (tf2.transform (Q2)); Vec3f globalQ3 (tf2.transform (Q3)); - Vec3f u ((globalP2-globalP1).cross (globalP3-globalP1)); - normal = u.normalized (); - FCL_REAL depth; - FCL_REAL depth1 ((globalP1-globalQ1).dot (normal)); - FCL_REAL depth2 ((globalP1-globalQ2).dot (normal)); - FCL_REAL depth3 ((globalP1-globalQ3).dot (normal)); - depth = std::max (depth1, std::max (depth2, depth3)); - return depth; + return computePenetration (globalP1, globalP2, globalP3, + globalQ1, globalQ2, globalQ3, normal); } } // details } // namespace fcl diff --git a/src/narrowphase/gjk.cpp b/src/narrowphase/gjk.cpp index ed15725c4ca635d44ccb74a047248befb458e7bb..9f0b94db7e2a185edb8bda396a9c2bf7b60bfe5a 100644 --- a/src/narrowphase/gjk.cpp +++ b/src/narrowphase/gjk.cpp @@ -36,7 +36,8 @@ /** \author Jia Pan */ #include <hpp/fcl/narrowphase/gjk.h> -#include <hpp/fcl/intersect.h> +#include <hpp/fcl/internal/intersect.h> +#include <hpp/fcl/internal/tools.h> namespace hpp { @@ -46,159 +47,395 @@ namespace fcl namespace details { -Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir) +struct shape_traits_base { - FCL_REAL eps (sqrt(std::numeric_limits<FCL_REAL>::epsilon())); - switch(shape->getNodeType()) + enum { NeedNormalizedDir = true + }; +}; + +template <typename Shape> struct shape_traits : shape_traits_base {}; + +template <> struct shape_traits<TriangleP> : shape_traits_base +{ + enum { NeedNormalizedDir = false + }; +}; + +template <> struct shape_traits<Box> : shape_traits_base +{ + enum { NeedNormalizedDir = false + }; +}; + +template <> struct shape_traits<Cone> : shape_traits_base +{ + enum { NeedNormalizedDir = false + }; +}; + +template <> struct shape_traits<Cylinder> : shape_traits_base +{ + enum { NeedNormalizedDir = false + }; +}; + +template <> struct shape_traits<ConvexBase> : shape_traits_base +{ + enum { NeedNormalizedDir = false + }; +}; + +void getShapeSupport(const TriangleP* triangle, const Vec3f& dir, Vec3f& support) +{ + FCL_REAL dota = dir.dot(triangle->a); + FCL_REAL dotb = dir.dot(triangle->b); + FCL_REAL dotc = dir.dot(triangle->c); + if(dota > dotb) { - case GEOM_TRIANGLE: - { - const TriangleP* triangle = static_cast<const TriangleP*>(shape); - FCL_REAL dota = dir.dot(triangle->a); - FCL_REAL dotb = dir.dot(triangle->b); - FCL_REAL dotc = dir.dot(triangle->c); - if(dota > dotb) - { - if(dotc > dota) - return triangle->c; - else - return triangle->a; - } - else - { - if(dotc > dotb) - return triangle->c; - else - return triangle->b; + if(dotc > dota) + support = triangle->c; + else + support = triangle->a; + } + else + { + if(dotc > dotb) + support = triangle->c; + else + support = triangle->b; + } +} + +inline void getShapeSupport(const Box* box, const Vec3f& dir, Vec3f& support) +{ + support.noalias() = (dir.array() > 0).select(box->halfSide, -box->halfSide); +} + +inline void getShapeSupport(const Sphere* sphere, const Vec3f& dir, Vec3f& support) +{ + support = dir * sphere->radius; +} + +inline void getShapeSupport(const Capsule* capsule, const Vec3f& dir, Vec3f& support) +{ + support = capsule->radius * dir; + if (dir[2] > 0) support[2] += capsule->halfLength; + else support[2] -= capsule->halfLength; +} + +void getShapeSupport(const Cone* cone, const Vec3f& dir, Vec3f& support) +{ + // TODO (Joseph Mirabel) + // this assumes that the cone radius is, for -0.5 < z < 0.5: + // (lz/2 - z) * radius / lz + // + // I did not change the code myself. However, I think it should be revised. + // 1. It can be optimized. + // 2. I am not sure this is what conePlaneIntersect and coneHalfspaceIntersect + // assumes... + FCL_REAL zdist = dir[0] * dir[0] + dir[1] * dir[1]; + FCL_REAL len = zdist + dir[2] * dir[2]; + zdist = std::sqrt(zdist); + len = std::sqrt(len); + FCL_REAL half_h = cone->halfLength; + FCL_REAL radius = cone->radius; + + FCL_REAL sin_a = radius / std::sqrt(radius * radius + 4 * half_h * half_h); + + if(dir[2] > len * sin_a) + support = Vec3f(0, 0, half_h); + else if(zdist > 0) + { + FCL_REAL rad = radius / zdist; + support = Vec3f(rad * dir[0], rad * dir[1], -half_h); + } + else + support = Vec3f(0, 0, -half_h); +} + +void getShapeSupport(const Cylinder* cylinder, const Vec3f& dir, Vec3f& support) +{ + static const FCL_REAL eps (sqrt(std::numeric_limits<FCL_REAL>::epsilon())); + FCL_REAL half_h = cylinder->halfLength; + if (dir [2] > eps) support[2] = half_h; + else if (dir [2] < -eps) support[2] = -half_h; + else support[2] = 0; + if (dir.head<2>().isZero()) + support.head<2>().setZero(); + else + support.head<2>() = dir.head<2>().normalized() * cylinder->radius; + assert (fabs (support [0] * dir [1] - support [1] * dir [0]) < eps); +} + +void getShapeSupport(const ConvexBase* convex, const Vec3f& dir, Vec3f& support) +{ + const Vec3f* pts = convex->points; + const ConvexBase::Neighbors* nn = convex->neighbors; + + int i = 0; + FCL_REAL maxdot = pts[i].dot(dir); + FCL_REAL dot; + bool found = true; + while (found) + { + const ConvexBase::Neighbors& n = nn[i]; + found = false; + for (int in = 0; in < n.count(); ++in) { + dot = pts[n[in]].dot(dir); + if (dot > maxdot) { + maxdot = dot; + i = n[in]; + found = true; } } + } + + support = pts[i]; +} + +#define CALL_GET_SHAPE_SUPPORT(ShapeType) \ + getShapeSupport (static_cast<const ShapeType*>(shape), \ + (shape_traits<ShapeType>::NeedNormalizedDir && !dirIsNormalized) \ + ? dir.normalized() : dir, \ + support) + +Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized) +{ + Vec3f support; + switch(shape->getNodeType()) + { + case GEOM_TRIANGLE: + CALL_GET_SHAPE_SUPPORT(TriangleP); break; case GEOM_BOX: - { - const Box* box = static_cast<const Box*>(shape); - Vec3f res((dir[0]>0)?(box->side[0]/2):(-box->side[0]/2), - (dir[1]>0)?(box->side[1]/2):(-box->side[1]/2), - (dir[2]>0)?(box->side[2]/2):(-box->side[2]/2)); - return res; - } + CALL_GET_SHAPE_SUPPORT(Box); break; case GEOM_SPHERE: - { - const Sphere* sphere = static_cast<const Sphere*>(shape); - return dir * sphere->radius; - } + CALL_GET_SHAPE_SUPPORT(Sphere); break; case GEOM_CAPSULE: - { - const Capsule* capsule = static_cast<const Capsule*>(shape); - FCL_REAL half_h = capsule->lz * 0.5; - Vec3f pos1(0, 0, half_h); - Vec3f pos2(0, 0, -half_h); - Vec3f v = dir * capsule->radius; - pos1 += v; - pos2 += v; - if(dir.dot(pos1) > dir.dot(pos2)) - return pos1; - else return pos2; - } + CALL_GET_SHAPE_SUPPORT(Capsule); break; case GEOM_CONE: - { - const Cone* cone = static_cast<const Cone*>(shape); - FCL_REAL zdist = dir[0] * dir[0] + dir[1] * dir[1]; - FCL_REAL len = zdist + dir[2] * dir[2]; - zdist = std::sqrt(zdist); - len = std::sqrt(len); - FCL_REAL half_h = cone->lz * 0.5; - FCL_REAL radius = cone->radius; - - FCL_REAL sin_a = radius / std::sqrt(radius * radius + 4 * half_h * half_h); - - if(dir[2] > len * sin_a) - return Vec3f(0, 0, half_h); - else if(zdist > 0) - { - FCL_REAL rad = radius / zdist; - return Vec3f(rad * dir[0], rad * dir[1], -half_h); - } - else - return Vec3f(0, 0, -half_h); - } + CALL_GET_SHAPE_SUPPORT(Cone); break; case GEOM_CYLINDER: - { - const Cylinder* cylinder = static_cast<const Cylinder*>(shape); - FCL_REAL zdist = std::sqrt(dir[0] * dir[0] + dir[1] * dir[1]); - FCL_REAL half_h = cylinder->lz * 0.5; - Vec3f res; - if(zdist == 0.0) - { - res = Vec3f(0, 0, (dir[2]>0)? half_h:-half_h); - } - else - { - FCL_REAL d = cylinder->radius / zdist; - FCL_REAL z (0.); - if (dir [2] > eps) z = half_h; - else if (dir [2] < -eps) z = -half_h; - res = Vec3f(d * dir[0], d * dir[1], z); - } - assert (fabs (res [0] * dir [1] - res [1] * dir [0]) < eps); - return res; - } + CALL_GET_SHAPE_SUPPORT(Cylinder); break; case GEOM_CONVEX: - { - const Convex* convex = static_cast<const Convex*>(shape); - FCL_REAL maxdot = - std::numeric_limits<FCL_REAL>::max(); - Vec3f* curp = convex->points; - Vec3f bestv(0,0,0); - for(int i = 0; i < convex->num_points; ++i, curp+=1) - { - FCL_REAL dot = dir.dot(*curp); - if(dot > maxdot) - { - bestv = *curp; - maxdot = dot; - } - } - return bestv; - } + CALL_GET_SHAPE_SUPPORT(ConvexBase); break; case GEOM_PLANE: - break; + case GEOM_HALFSPACE: default: + support.setZero(); ; // nothing } - return Vec3f(0, 0, 0); + return support; +} + +#undef CALL_GET_SHAPE_SUPPORT + +template <typename Shape0, typename Shape1, bool TransformIsIdentity> +void getSupportTpl (const Shape0* s0, const Shape1* s1, + const Matrix3f& oR1, const Vec3f& ot1, + const Vec3f& dir, Vec3f& support0, Vec3f& support1) +{ + getShapeSupport (s0, dir, support0); + if (TransformIsIdentity) + getShapeSupport (s1, - dir, support1); + else { + getShapeSupport (s1, - oR1.transpose() * dir, support1); + support1 = oR1 * support1 + ot1; + } +} + +template <typename Shape0, typename Shape1, bool TransformIsIdentity> +void getSupportFuncTpl (const MinkowskiDiff& md, + const Vec3f& dir, bool dirIsNormalized, Vec3f& support0, Vec3f& support1) +{ + enum { NeedNormalizedDir = + bool ( (bool)shape_traits<Shape0>::NeedNormalizedDir + || (bool)shape_traits<Shape1>::NeedNormalizedDir) + }; +#ifndef NDEBUG + // Need normalized direction and direction is normalized + assert(!NeedNormalizedDir || !dirIsNormalized || fabs(dir.squaredNorm() - 1) < 1e-6); + // Need normalized direction but direction is not normalized. + assert(!NeedNormalizedDir || dirIsNormalized || fabs(dir.normalized().squaredNorm() - 1) < 1e-6); + // Don't need normalized direction. Check that dir is not zero. + assert( NeedNormalizedDir || dir.cwiseAbs().maxCoeff() >= 1e-6); +#endif + getSupportTpl<Shape0, Shape1, TransformIsIdentity> ( + static_cast <const Shape0*>(md.shapes[0]), + static_cast <const Shape1*>(md.shapes[1]), + md.oR1, md.ot1, + (NeedNormalizedDir && !dirIsNormalized) ? dir.normalized() : dir, + support0, support1); +} + +template <typename Shape0> +MinkowskiDiff::GetSupportFunction makeGetSupportFunction1 (const ShapeBase* s1, bool identity) +{ + switch(s1->getNodeType()) + { + case GEOM_TRIANGLE: + if (identity) return getSupportFuncTpl<Shape0, TriangleP, true >; + else return getSupportFuncTpl<Shape0, TriangleP, false>; + case GEOM_BOX: + if (identity) return getSupportFuncTpl<Shape0, Box, true >; + else return getSupportFuncTpl<Shape0, Box, false>; + case GEOM_SPHERE: + if (identity) return getSupportFuncTpl<Shape0, Sphere, true >; + else return getSupportFuncTpl<Shape0, Sphere, false>; + case GEOM_CAPSULE: + if (identity) return getSupportFuncTpl<Shape0, Capsule, true >; + else return getSupportFuncTpl<Shape0, Capsule, false>; + case GEOM_CONE: + if (identity) return getSupportFuncTpl<Shape0, Cone, true >; + else return getSupportFuncTpl<Shape0, Cone, false>; + case GEOM_CYLINDER: + if (identity) return getSupportFuncTpl<Shape0, Cylinder, true >; + else return getSupportFuncTpl<Shape0, Cylinder, false>; + case GEOM_CONVEX: + if (identity) return getSupportFuncTpl<Shape0, ConvexBase, true >; + else return getSupportFuncTpl<Shape0, ConvexBase, false>; + default: + throw std::logic_error ("Unsupported geometric shape"); + } +} + +MinkowskiDiff::GetSupportFunction makeGetSupportFunction0 (const ShapeBase* s0, const ShapeBase* s1, bool identity) +{ + switch(s0->getNodeType()) + { + case GEOM_TRIANGLE: + return makeGetSupportFunction1<TriangleP> (s1, identity); + break; + case GEOM_BOX: + return makeGetSupportFunction1<Box> (s1, identity); + break; + case GEOM_SPHERE: + return makeGetSupportFunction1<Sphere> (s1, identity); + break; + case GEOM_CAPSULE: + return makeGetSupportFunction1<Capsule> (s1, identity); + break; + case GEOM_CONE: + return makeGetSupportFunction1<Cone> (s1, identity); + break; + case GEOM_CYLINDER: + return makeGetSupportFunction1<Cylinder> (s1, identity); + break; + case GEOM_CONVEX: + return makeGetSupportFunction1<ConvexBase> (s1, identity); + break; + default: + throw std::logic_error ("Unsupported geometric shape"); + } +} + +void MinkowskiDiff::set (const ShapeBase* shape0, const ShapeBase* shape1, + const Transform3f& tf0, const Transform3f& tf1) +{ + shapes[0] = shape0; + shapes[1] = shape1; + + oR1 = tf0.getRotation().transpose() * tf1.getRotation(); + ot1 = tf0.getRotation().transpose() * (tf1.getTranslation() - tf0.getTranslation()); + + bool identity = (oR1.isIdentity() && ot1.isZero()); + + getSupportFunc = makeGetSupportFunction0 (shape0, shape1, identity); +} + +void MinkowskiDiff::set (const ShapeBase* shape0, const ShapeBase* shape1) +{ + shapes[0] = shape0; + shapes[1] = shape1; + + oR1.setIdentity(); + ot1.setZero(); + + getSupportFunc = makeGetSupportFunction0 (shape0, shape1, true); } void GJK::initialize() { - ray = Vec3f::Zero(); nfree = 0; status = Failed; - current = 0; - distance = 0.0; + distance_upper_bound = std::numeric_limits<FCL_REAL>::max(); simplex = NULL; } - Vec3f GJK::getGuessFromSimplex() const { return ray; } +bool GJK::getClosestPoints (const Simplex& simplex, Vec3f& w0, Vec3f& w1) +{ + SimplexV* const* vs = simplex.vertex; + + for (vertex_id_t i = 0; i < simplex.rank; ++i) { + assert (vs[i]->w.isApprox (vs[i]->w0 - vs[i]->w1)); + } + + Project::ProjectResult projection; + switch (simplex.rank) { + case 1: + w0 = vs[0]->w0; + w1 = vs[0]->w1; + return true; + case 2: + { + const Vec3f& a = vs[0]->w, a0 = vs[0]->w0, a1 = vs[0]->w1, + b = vs[1]->w, b0 = vs[1]->w0, b1 = vs[1]->w1; + FCL_REAL la, lb; + Vec3f N (b - a); + la = N.dot(-a); + if (la <= 0) { + w0 = a0; + w1 = a1; + } else { + lb = N.squaredNorm(); + if (la > lb) { + w0 = b0; + w1 = b1; + } else { + lb = la / lb; + la = 1 - lb; + w0 = la * a0 + lb * b0; + w1 = la * a1 + lb * b1; + } + } + } + return true; + case 3: + // TODO avoid the reprojection + projection = Project::projectTriangleOrigin (vs[0]->w, vs[1]->w, vs[2]->w); + break; + case 4: // We are in collision. + projection = Project::projectTetrahedraOrigin (vs[0]->w, vs[1]->w, vs[2]->w, vs[3]->w); + break; + default: + throw std::logic_error ("The simplex rank must be in [ 1, 4 ]"); + } + w0.setZero(); + w1.setZero(); + for (vertex_id_t i = 0; i < simplex.rank; ++i) { + w0 += projection.parameterization[i] * vs[i]->w0; + w1 += projection.parameterization[i] * vs[i]->w1; + } + return true; +} GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess) { size_t iterations = 0; FCL_REAL alpha = 0; - Vec3f lastw[4]; - size_t clastw = 0; - Project::ProjectResult project_res; - + free_v[0] = &store_v[0]; free_v[1] = &store_v[1]; free_v[2] = &store_v[2]; @@ -207,21 +444,18 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess) nfree = 4; current = 0; status = Valid; - shape = shape_; + shape = &shape_; distance = 0.0; simplices[0].rank = 0; ray = guess; - // appendVertex(simplices[0], (ray.squaredNorm() > 0) ? -ray : Vec3f(1, 0, 0)); if (ray.squaredNorm() > 0) appendVertex(simplices[0], -ray); - else appendVertex(simplices[0], Vec3f(1, 0, 0)); - simplices[0].coefficient[0] = 1; + else appendVertex(simplices[0], Vec3f(1, 0, 0), true); ray = simplices[0].vertex[0]->w; - lastw[0] = lastw[1] = lastw[2] = lastw[3] = ray; // cache previous support points, the new support point will compare with it to avoid too close support points do { - size_t next = 1 - current; + vertex_id_t next = (vertex_id_t)(1 - current); Simplex& curr_simplex = simplices[current]; Simplex& next_simplex = simplices[next]; @@ -230,65 +464,52 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess) if(rl < tolerance) // mean origin is near the face of original simplex, return touch { status = Inside; + distance = 0; // rl ? break; } appendVertex(curr_simplex, -ray); // see below, ray points away from origin - // check B: when the new support point is close to previous support points, stop (as the new simplex is degenerated) + // check removed (by ?): when the new support point is close to previous support points, stop (as the new simplex is degenerated) const Vec3f& w = curr_simplex.vertex[curr_simplex.rank - 1]->w; - lastw[clastw = (clastw+1)&3] = w; - // check C: when the new support point is close to the sub-simplex where the ray point lies, stop (as the new simplex again is degenerated) + // check B: no collision if omega > 0 FCL_REAL omega = ray.dot(w) / rl; + if (omega > distance_upper_bound) + { + distance = omega; + break; + } + + // check C: when the new support point is close to the sub-simplex where the ray point lies, stop (as the new simplex again is degenerated) alpha = std::max(alpha, omega); if((rl - alpha) - tolerance * rl <= 0) { removeVertex(simplices[current]); + distance = rl; break; } + // This has been rewritten thanks to the excellent video: + // https://youtu.be/Qupqu1xe7Io + bool inside; switch(curr_simplex.rank) { case 2: - project_res = Project::projectLineOrigin(curr_simplex.vertex[0]->w, - curr_simplex.vertex[1]->w); + inside = projectLineOrigin (curr_simplex, next_simplex); break; case 3: - project_res = Project::projectTriangleOrigin(curr_simplex.vertex[0]->w, - curr_simplex.vertex[1]->w, - curr_simplex.vertex[2]->w); break; + inside = projectTriangleOrigin (curr_simplex, next_simplex); + break; case 4: - project_res = Project::projectTetrahedraOrigin(curr_simplex.vertex[0]->w, - curr_simplex.vertex[1]->w, - curr_simplex.vertex[2]->w, - curr_simplex.vertex[3]->w); + inside = projectTetrahedraOrigin (curr_simplex, next_simplex); break; } - if(project_res.sqr_distance >= 0) - { - next_simplex.rank = 0; - ray = Vec3f(0,0,0); - current = next; - for(size_t i = 0; i < curr_simplex.rank; ++i) - { - if(project_res.encode & (1 << i)) - { - next_simplex.vertex[next_simplex.rank] = curr_simplex.vertex[i]; - // weights[i] - next_simplex.coefficient[next_simplex.rank++] = - project_res.parameterization[i]; - // weights[i] - ray += curr_simplex.vertex[i]->w * project_res.parameterization[i]; - } - else - free_v[nfree++] = curr_simplex.vertex[i]; - } - if(project_res.encode == 15) status = Inside; // the origin is within the 4-simplex, collision - } - else - { - removeVertex(simplices[current]); + assert (nfree+next_simplex.rank == 4); + current = next; + if(inside) { + status = Inside; + distance = 0; break; } @@ -297,52 +518,37 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess) } while(status == Valid); simplex = &simplices[current]; - switch(status) - { - case Valid: distance = ray.norm(); break; - case Inside: distance = 0; break; - default: - distance = sqrt (project_res.sqr_distance); - break; - } return status; } -void GJK::getSupport(const Vec3f& d, SimplexV& sv) const -{ - sv.d.noalias() = d.normalized(); - sv.w.noalias() = shape.support(sv.d); -} - -void GJK::removeVertex(Simplex& simplex) +inline void GJK::removeVertex(Simplex& simplex) { free_v[nfree++] = simplex.vertex[--simplex.rank]; } -void GJK::appendVertex(Simplex& simplex, const Vec3f& v) +inline void GJK::appendVertex(Simplex& simplex, const Vec3f& v, bool isNormalized) { - simplex.coefficient[simplex.rank] = 0; // initial weight 0 simplex.vertex[simplex.rank] = free_v[--nfree]; // set the memory - getSupport(v, *simplex.vertex[simplex.rank++]); + getSupport (v, isNormalized, *simplex.vertex[simplex.rank++]); } bool GJK::encloseOrigin() { + Vec3f axis(Vec3f::Zero()); switch(simplex->rank) { case 1: + for(size_t i = 0; i < 3; ++i) { - for(size_t i = 0; i < 3; ++i) - { - Vec3f axis(Vec3f::Zero()); - axis[i] = 1; - appendVertex(*simplex, axis); - if(encloseOrigin()) return true; - removeVertex(*simplex); - appendVertex(*simplex, -axis); - if(encloseOrigin()) return true; - removeVertex(*simplex); - } + axis[i] = 1; + appendVertex(*simplex, axis, true); + if(encloseOrigin()) return true; + removeVertex(*simplex); + axis[i] = -1; + appendVertex(*simplex, -axis, true); + if(encloseOrigin()) return true; + removeVertex(*simplex); + axis[i] = 0; } break; case 2: @@ -350,10 +556,9 @@ bool GJK::encloseOrigin() Vec3f d = simplex->vertex[1]->w - simplex->vertex[0]->w; for(size_t i = 0; i < 3; ++i) { - Vec3f axis(0,0,0); axis[i] = 1; Vec3f p = d.cross(axis); - if(p.squaredNorm() > 0) + if(!p.isZero()) { appendVertex(*simplex, p); if(encloseOrigin()) return true; @@ -362,37 +567,482 @@ bool GJK::encloseOrigin() if(encloseOrigin()) return true; removeVertex(*simplex); } + axis[i] = 0; } } break; case 3: + axis.noalias() = + (simplex->vertex[1]->w - simplex->vertex[0]->w).cross + (simplex->vertex[2]->w - simplex->vertex[0]->w); + if(!axis.isZero()) { - Vec3f n = (simplex->vertex[1]->w - simplex->vertex[0]->w).cross - (simplex->vertex[2]->w - simplex->vertex[0]->w); - if(n.squaredNorm() > 0) - { - appendVertex(*simplex, n); - if(encloseOrigin()) return true; - removeVertex(*simplex); - appendVertex(*simplex, -n); - if(encloseOrigin()) return true; - removeVertex(*simplex); - } + appendVertex(*simplex, axis); + if(encloseOrigin()) return true; + removeVertex(*simplex); + appendVertex(*simplex, -axis); + if(encloseOrigin()) return true; + removeVertex(*simplex); } break; case 4: - { - if(std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w, - simplex->vertex[1]->w - simplex->vertex[3]->w, - simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0) - return true; - } + if(std::abs(triple(simplex->vertex[0]->w - simplex->vertex[3]->w, + simplex->vertex[1]->w - simplex->vertex[3]->w, + simplex->vertex[2]->w - simplex->vertex[3]->w)) > 0) + return true; break; } return false; } +inline void originToPoint ( + const GJK::Simplex& current, GJK::vertex_id_t a, + const Vec3f& A, + GJK::Simplex& next, + Vec3f& ray) +{ + // A is the closest to the origin + ray = A; + next.vertex[0] = current.vertex[a]; + next.rank = 1; +} + +inline void originToSegment ( + const GJK::Simplex& current, GJK::vertex_id_t a, GJK::vertex_id_t b, + const Vec3f& A, const Vec3f& B, + const Vec3f& AB, + const FCL_REAL& ABdotAO, + GJK::Simplex& next, + Vec3f& ray) +{ + // ray = - ( AB ^ AO ) ^ AB = (AB.B) A + (-AB.A) B + ray = AB.dot(B) * A + ABdotAO * B; + + next.vertex[0] = current.vertex[b]; + next.vertex[1] = current.vertex[a]; + next.rank = 2; + + // To ensure backward compatibility + ray /= AB.squaredNorm(); +} + +inline void originToTriangle ( + const GJK::Simplex& current, + GJK::vertex_id_t a, GJK::vertex_id_t b, GJK::vertex_id_t c, + const Vec3f& ABC, + const FCL_REAL& ABCdotAO, + GJK::Simplex& next, + Vec3f& ray) +{ + bool aboveTri (ABCdotAO >= 0); + ray = ABC; + + if (aboveTri) { + next.vertex[0] = current.vertex[c]; + next.vertex[1] = current.vertex[b]; + } else { + next.vertex[0] = current.vertex[b]; + next.vertex[1] = current.vertex[c]; + } + next.vertex[2] = current.vertex[a]; + next.rank = 3; + + // To ensure backward compatibility + ray *= -ABCdotAO / ABC.squaredNorm(); +} + +bool GJK::projectLineOrigin(const Simplex& current, Simplex& next) +{ + const vertex_id_t a = 1, b = 0; + // A is the last point we added. + const Vec3f& A = current.vertex[a]->w; + const Vec3f& B = current.vertex[b]->w; + + const Vec3f AB = B - A; + const FCL_REAL d = AB.dot(-A); + assert (d <= AB.squaredNorm()); + + if (d <= 0) { + // A is the closest to the origin + originToPoint (current, a, A, next, ray); + free_v[nfree++] = current.vertex[b]; + } else + originToSegment (current, a, b, A, B, AB, d, next, ray); + return false; +} + +bool GJK::projectTriangleOrigin(const Simplex& current, Simplex& next) +{ + const vertex_id_t a = 2, b = 1, c = 0; + // A is the last point we added. + const Vec3f& A = current.vertex[a]->w, + B = current.vertex[b]->w, + C = current.vertex[c]->w; + + const Vec3f AB = B - A, + AC = C - A, + ABC = AB.cross(AC); + + FCL_REAL edgeAC2o = ABC.cross(AC).dot (-A); + if (edgeAC2o >= 0) { + FCL_REAL towardsC = AC.dot (-A); + if (towardsC >= 0) { // Region 1 + originToSegment (current, a, c, A, C, AC, towardsC, next, ray); + free_v[nfree++] = current.vertex[b]; + } else { // Region 4 or 5 + FCL_REAL towardsB = AB.dot(-A); + if (towardsB < 0) { // Region 5 + // A is the closest to the origin + originToPoint (current, a, A, next, ray); + free_v[nfree++] = current.vertex[b]; + } else // Region 4 + originToSegment (current, a, b, A, B, AB, towardsB, next, ray); + free_v[nfree++] = current.vertex[c]; + } + } else { + FCL_REAL edgeAB2o = AB.cross(ABC).dot (-A); + if (edgeAB2o >= 0) { // Region 4 or 5 + FCL_REAL towardsB = AB.dot(-A); + if (towardsB < 0) { // Region 5 + // A is the closest to the origin + originToPoint (current, a, A, next, ray); + free_v[nfree++] = current.vertex[b]; + } else // Region 4 + originToSegment (current, a, b, A, B, AB, towardsB, next, ray); + free_v[nfree++] = current.vertex[c]; + } else { + originToTriangle (current, a, b, c, ABC, ABC.dot(-A), next, ray); + } + } + return false; +} + +bool GJK::projectTetrahedraOrigin(const Simplex& current, Simplex& next) +{ + // The code of this function was generated using doc/gjk.py + const vertex_id_t a = 3, b = 2, c = 1, d = 0; + const Vec3f& A (current.vertex[a]->w); + const Vec3f& B (current.vertex[b]->w); + const Vec3f& C (current.vertex[c]->w); + const Vec3f& D (current.vertex[d]->w); + const FCL_REAL aa = A.squaredNorm(); + const FCL_REAL da = D.dot(A); + const FCL_REAL db = D.dot(B); + const FCL_REAL dc = D.dot(C); + const FCL_REAL dd = D.dot(D); + const FCL_REAL da_aa = da - aa; + const FCL_REAL ca = C.dot(A); + const FCL_REAL cb = C.dot(B); + const FCL_REAL cc = C.dot(C); + const FCL_REAL& cd = dc; + const FCL_REAL ca_aa = ca - aa; + const FCL_REAL ba = B.dot(A); + const FCL_REAL bb = B.dot(B); + const FCL_REAL& bc = cb; + const FCL_REAL& bd = db; + const FCL_REAL ba_aa = ba - aa; + const FCL_REAL ba_ca = ba - ca; + const FCL_REAL ca_da = ca - da; + const FCL_REAL da_ba = da - ba; + const Vec3f a_cross_b = A.cross(B); + const Vec3f a_cross_c = A.cross(C); + +#define REGION_INSIDE() \ + ray.setZero(); \ + next.vertex[0] = current.vertex[d]; \ + next.vertex[1] = current.vertex[c]; \ + next.vertex[2] = current.vertex[b]; \ + next.vertex[3] = current.vertex[a]; \ + next.rank=4; \ + return true; + + if (ba_aa <= 0) { // if AB.AO >= 0 / a10 + if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / a10.a3 + if (ba * da_ba + bd * ba_aa - bb * da_aa <= 0) { // if (ADB ^ AB).AO >= 0 / a10.a3.a9 + if (da_aa <= 0) { // if AD.AO >= 0 / a10.a3.a9.a12 + assert(da * da_ba + dd * ba_aa - db * da_aa <= 0); // (ADB ^ AD).AO >= 0 / a10.a3.a9.a12.a8 + if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.a4 + // Region ABC + originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray); + free_v[nfree++] = current.vertex[d]; + } else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.a12.a8.!a4 + // Region AB + originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray); + free_v[nfree++] = current.vertex[c]; + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AB).AO >= 0 + } else { // not AD.AO >= 0 / a10.a3.a9.!a12 + if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.a4 + if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5 + if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.a6 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } else { // not (ACD ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.a5.!a6 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } // end of (ACD ^ AC).AO >= 0 + } else { // not (ABC ^ AC).AO >= 0 / a10.a3.a9.!a12.a4.!a5 + // Region ABC + originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray); + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AC).AO >= 0 + } else { // not (ABC ^ AB).AO >= 0 / a10.a3.a9.!a12.!a4 + // Region AB + originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray); + free_v[nfree++] = current.vertex[c]; + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AB).AO >= 0 + } // end of AD.AO >= 0 + } else { // not (ADB ^ AB).AO >= 0 / a10.a3.!a9 + if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / a10.a3.!a9.a8 + // Region ADB + originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray); + free_v[nfree++] = current.vertex[c]; + } else { // not (ADB ^ AD).AO >= 0 / a10.a3.!a9.!a8 + if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.a6 + if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.a7 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.a6.!a7 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } // end of (ACD ^ AD).AO >= 0 + } else { // not (ACD ^ AC).AO >= 0 / a10.a3.!a9.!a8.!a6 + if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.a7 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } else { // not (ACD ^ AD).AO >= 0 / a10.a3.!a9.!a8.!a6.!a7 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } // end of (ACD ^ AD).AO >= 0 + } // end of (ACD ^ AC).AO >= 0 + } // end of (ADB ^ AD).AO >= 0 + } // end of (ADB ^ AB).AO >= 0 + } else { // not ADB.AO >= 0 / a10.!a3 + if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / a10.!a3.a1 + if (ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0) { // if (ABC ^ AB).AO >= 0 / a10.!a3.a1.a4 + if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.a5 + if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.a6 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } else { // not (ACD ^ AC).AO >= 0 / a10.!a3.a1.a4.a5.!a6 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } // end of (ACD ^ AC).AO >= 0 + } else { // not (ABC ^ AC).AO >= 0 / a10.!a3.a1.a4.!a5 + // Region ABC + originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray); + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AC).AO >= 0 + } else { // not (ABC ^ AB).AO >= 0 / a10.!a3.a1.!a4 + // Region AB + originToSegment (current, a, b, A, B, B-A, -ba_aa, next, ray); + free_v[nfree++] = current.vertex[c]; + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AB).AO >= 0 + } else { // not ABC.AO >= 0 / a10.!a3.!a1 + if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / a10.!a3.!a1.a2 + if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.a6 + if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.a7 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } else { // not (ACD ^ AD).AO >= 0 / a10.!a3.!a1.a2.a6.!a7 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } // end of (ACD ^ AD).AO >= 0 + } else { // not (ACD ^ AC).AO >= 0 / a10.!a3.!a1.a2.!a6 + if (ca_aa <= 0) { // if AC.AO >= 0 / a10.!a3.!a1.a2.!a6.a11 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } else { // not AC.AO >= 0 / a10.!a3.!a1.a2.!a6.!a11 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } // end of AC.AO >= 0 + } // end of (ACD ^ AC).AO >= 0 + } else { // not ACD.AO >= 0 / a10.!a3.!a1.!a2 + // Region Inside + REGION_INSIDE() + } // end of ACD.AO >= 0 + } // end of ABC.AO >= 0 + } // end of ADB.AO >= 0 + } else { // not AB.AO >= 0 / !a10 + if (ca_aa <= 0) { // if AC.AO >= 0 / !a10.a11 + if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.a11.a2 + if (da_aa <= 0) { // if AD.AO >= 0 / !a10.a11.a2.a12 + if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.a6 + if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7 + if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.a8 + // Region ADB + originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray); + free_v[nfree++] = current.vertex[c]; + } else { // not (ADB ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.a7.!a8 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } // end of (ADB ^ AD).AO >= 0 + } else { // not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.a6.!a7 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } // end of (ACD ^ AD).AO >= 0 + } else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6 + assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0 / !a10.a11.a2.a12.!a6.!a7 + if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.a5 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.a12.!a6.!a7.!a5 + // Region ABC + originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray); + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AC).AO >= 0 + } // end of (ACD ^ AC).AO >= 0 + } else { // not AD.AO >= 0 / !a10.a11.a2.!a12 + if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5 + if (ca * ca_da + cc * da_aa - cd * ca_aa <= 0) { // if (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.a6 + assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0 / !a10.a11.a2.!a12.a5.a6.!a7 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } else { // not (ACD ^ AC).AO >= 0 / !a10.a11.a2.!a12.a5.!a6 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } // end of (ACD ^ AC).AO >= 0 + } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.a2.!a12.!a5 + if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.a1 + assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0); // (ABC ^ AB).AO >= 0 / !a10.a11.a2.!a12.!a5.a1.a4 + // Region ABC + originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray); + free_v[nfree++] = current.vertex[d]; + } else { // not ABC.AO >= 0 / !a10.a11.a2.!a12.!a5.!a1 + assert(!(da * ca_da + dc * da_aa - dd * ca_aa <= 0)); // Not (ACD ^ AD).AO >= 0 / !a10.a11.a2.!a12.!a5.!a1.!a7 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } // end of ABC.AO >= 0 + } // end of (ABC ^ AC).AO >= 0 + } // end of AD.AO >= 0 + } else { // not ACD.AO >= 0 / !a10.a11.!a2 + if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.a11.!a2.a1 + if (ca * ba_ca + cb * ca_aa - cc * ba_aa <= 0) { // if (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.a5 + // Region AC + originToSegment (current, a, c, A, C, C-A, -ca_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[d]; + } else { // not (ABC ^ AC).AO >= 0 / !a10.a11.!a2.a1.!a5 + assert(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0); // (ABC ^ AB).AO >= 0 / !a10.a11.!a2.a1.!a5.a4 + // Region ABC + originToTriangle (current, a, b, c, (B-A).cross(C-A), -C.dot (a_cross_b), next, ray); + free_v[nfree++] = current.vertex[d]; + } // end of (ABC ^ AC).AO >= 0 + } else { // not ABC.AO >= 0 / !a10.a11.!a2.!a1 + if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.a11.!a2.!a1.a3 + if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.a8 + // Region ADB + originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray); + free_v[nfree++] = current.vertex[c]; + } else { // not (ADB ^ AD).AO >= 0 / !a10.a11.!a2.!a1.a3.!a8 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } // end of (ADB ^ AD).AO >= 0 + } else { // not ADB.AO >= 0 / !a10.a11.!a2.!a1.!a3 + // Region Inside + REGION_INSIDE() + } // end of ADB.AO >= 0 + } // end of ABC.AO >= 0 + } // end of ACD.AO >= 0 + } else { // not AC.AO >= 0 / !a10.!a11 + if (da_aa <= 0) { // if AD.AO >= 0 / !a10.!a11.a12 + if (-D.dot(a_cross_b) <= 0) { // if ADB.AO >= 0 / !a10.!a11.a12.a3 + if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7 + if (da * da_ba + dd * ba_aa - db * da_aa <= 0) { // if (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.a8 + assert(!(ba * da_ba + bd * ba_aa - bb * da_aa <= 0)); // Not (ADB ^ AB).AO >= 0 / !a10.!a11.a12.a3.a7.a8.!a9 + // Region ADB + originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray); + free_v[nfree++] = current.vertex[c]; + } else { // not (ADB ^ AD).AO >= 0 / !a10.!a11.a12.a3.a7.!a8 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } // end of (ADB ^ AD).AO >= 0 + } else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.a3.!a7 + if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.a2 + assert(ca * ca_da + cc * da_aa - cd * ca_aa <= 0); // (ACD ^ AC).AO >= 0 / !a10.!a11.a12.a3.!a7.a2.a6 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } else { // not ACD.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2 + if (C.dot (a_cross_b) <= 0) { // if ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1 + assert(!(ba * ba_ca + bb * ca_aa - bc * ba_aa <= 0)); // Not (ABC ^ AB).AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.a1.!a4 + // Region ADB + originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray); + free_v[nfree++] = current.vertex[c]; + } else { // not ABC.AO >= 0 / !a10.!a11.a12.a3.!a7.!a2.!a1 + // Region ADB + originToTriangle (current, a, d, b, (D-A).cross(B-A), D.dot(a_cross_b), next, ray); + free_v[nfree++] = current.vertex[c]; + } // end of ABC.AO >= 0 + } // end of ACD.AO >= 0 + } // end of (ACD ^ AD).AO >= 0 + } else { // not ADB.AO >= 0 / !a10.!a11.a12.!a3 + if (D.dot(a_cross_c) <= 0) { // if ACD.AO >= 0 / !a10.!a11.a12.!a3.a2 + if (da * ca_da + dc * da_aa - dd * ca_aa <= 0) { // if (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.a7 + // Region AD + originToSegment (current, a, d, A, D, D-A, -da_aa, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + } else { // not (ACD ^ AD).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7 + assert(ca * ca_da + cc * da_aa - cd * ca_aa <= 0); // (ACD ^ AC).AO >= 0 / !a10.!a11.a12.!a3.a2.!a7.a6 + // Region ACD + originToTriangle (current, a, c, d, (C-A).cross(D-A), -D.dot(a_cross_c), next, ray); + free_v[nfree++] = current.vertex[b]; + } // end of (ACD ^ AD).AO >= 0 + } else { // not ACD.AO >= 0 / !a10.!a11.a12.!a3.!a2 + // Region Inside + REGION_INSIDE() + } // end of ACD.AO >= 0 + } // end of ADB.AO >= 0 + } else { // not AD.AO >= 0 / !a10.!a11.!a12 + // Region A + originToPoint (current, a, A, next, ray); + free_v[nfree++] = current.vertex[b]; + free_v[nfree++] = current.vertex[c]; + free_v[nfree++] = current.vertex[d]; + } // end of AD.AO >= 0 + } // end of AC.AO >= 0 + } // end of AB.AO >= 0 + +#undef REGION_INSIDE + return false; +} void EPA::initialize() { @@ -476,7 +1126,7 @@ EPA::SimplexF* EPA::newFace(SimplexV* a, SimplexV* b, SimplexV* c, bool forced) return NULL; } -/** \brief Find the best polytope face to split */ +/** @brief Find the best polytope face to split */ EPA::SimplexF* EPA::findBest() { SimplexF* minf = hull.root; @@ -515,10 +1165,6 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) SimplexV* tmp = simplex.vertex[0]; simplex.vertex[0] = simplex.vertex[1]; simplex.vertex[1] = tmp; - - FCL_REAL tmpv = simplex.coefficient[0]; - simplex.coefficient[0] = simplex.coefficient[1]; - simplex.coefficient[1] = tmpv; } SimplexF* tetrahedron[] = {newFace(simplex.vertex[0], simplex.vertex[1], @@ -554,7 +1200,8 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) SimplexV* w = &sv_store[nextsv++]; bool valid = true; best->pass = ++pass; - gjk.getSupport(best->n, *w); + // At the moment, SimplexF.n is always normalized. This could be revised in the future... + gjk.getSupport(best->n, true, *w); FCL_REAL wdist = best->n.dot(w->w) - best->d; if(wdist > tolerance) { @@ -589,25 +1236,12 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) } } - Vec3f projection = outer.n * outer.d; normal = outer.n; depth = outer.d; result.rank = 3; result.vertex[0] = outer.vertex[0]; result.vertex[1] = outer.vertex[1]; result.vertex[2] = outer.vertex[2]; - result.coefficient[0] = ((outer.vertex[1]->w - projection).cross - (outer.vertex[2]->w - projection)).norm(); - result.coefficient[1] = ((outer.vertex[2]->w - projection).cross - (outer.vertex[0]->w - projection)).norm(); - result.coefficient[2] = ((outer.vertex[0]->w - projection).cross - (outer.vertex[1]->w - projection)).norm(); - - FCL_REAL sum = result.coefficient[0] + result.coefficient[1] + - result.coefficient[2]; - result.coefficient[0] /= sum; - result.coefficient[1] /= sum; - result.coefficient[2] /= sum; return status; } } @@ -620,12 +1254,11 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) depth = 0; result.rank = 1; result.vertex[0] = simplex.vertex[0]; - result.coefficient[0] = 1; return status; } -/** \brief the goal is to add a face connecting vertex w and face edge f[e] */ +/** @brief the goal is to add a face connecting vertex w and face edge f[e] */ bool EPA::expand(size_t pass, SimplexV* w, SimplexF* f, size_t e, SimplexHorizon& horizon) { static const size_t nexti[] = {1, 2, 0}; diff --git a/src/narrowphase/narrowphase.cpp b/src/narrowphase/narrowphase.cpp index 00897891297baf99acae855225edf3d9711c982f..829855fbf5eaddd55deb8529d8f01229e21ce851 100644 --- a/src/narrowphase/narrowphase.cpp +++ b/src/narrowphase/narrowphase.cpp @@ -36,11 +36,13 @@ /** \author Jia Pan */ #include <hpp/fcl/narrowphase/narrowphase.h> -#include <hpp/fcl/shape/geometric_shapes_utility.h> -#include <hpp/fcl/intersect.h> -#include <boost/math/constants/constants.hpp> + #include <vector> -#include "../src/narrowphase/details.h" +#include <boost/math/constants/constants.hpp> + +#include <hpp/fcl/shape/geometric_shapes_utility.h> +#include <hpp/fcl/internal/intersect.h> +#include "details.h" namespace hpp { @@ -71,7 +73,7 @@ namespace fcl // +------------+-----+--------+---------+------+----------+-------+------------+----------+ template<> -bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1, const Capsule &s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -79,7 +81,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Tr } template<> -bool GJKSolver_indep::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const Transform3f& tf1, const Sphere &s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -89,7 +91,7 @@ bool GJKSolver_indep::shapeIntersect<Capsule, Sphere>(const Capsule &s1, const T } template<> -bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -97,7 +99,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Tra } template<> -bool GJKSolver_indep::shapeIntersect<Box, Sphere>(const Box & s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Box, Sphere>(const Box & s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -112,7 +114,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Sphere>(const Box & s1, const Transf } template<> -bool GJKSolver_indep::shapeIntersect<Sphere, Box>(const Sphere& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Sphere, Box>(const Sphere& s1, const Transform3f& tf1, const Box & s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -127,7 +129,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Box>(const Sphere& s1, const Transf } template<> -bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& tf1, const Box& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -135,7 +137,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Box>(const Box& s1, const Transform3f& } template<> -bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace> +bool GJKSolver::shapeIntersect<Sphere, Halfspace> (const Sphere& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -150,7 +152,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Halfspace> } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -165,7 +167,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Sphere>(const Halfspace& s1, con } template<> -bool GJKSolver_indep::shapeIntersect<Box, Halfspace> +bool GJKSolver::shapeIntersect<Box, Halfspace> (const Box& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -180,7 +182,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Halfspace> } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Box> +bool GJKSolver::shapeIntersect<Halfspace, Box> (const Halfspace& s1, const Transform3f& tf1, const Box& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -196,7 +198,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Box> } template<> -bool GJKSolver_indep::shapeIntersect<Capsule, Halfspace> +bool GJKSolver::shapeIntersect<Capsule, Halfspace> (const Capsule& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -211,7 +213,7 @@ bool GJKSolver_indep::shapeIntersect<Capsule, Halfspace> } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Capsule> +bool GJKSolver::shapeIntersect<Halfspace, Capsule> (const Halfspace& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -227,7 +229,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Capsule> } template<> -bool GJKSolver_indep::shapeIntersect<Cylinder, Halfspace> +bool GJKSolver::shapeIntersect<Cylinder, Halfspace> (const Cylinder& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -242,7 +244,7 @@ bool GJKSolver_indep::shapeIntersect<Cylinder, Halfspace> } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Cylinder> +bool GJKSolver::shapeIntersect<Halfspace, Cylinder> (const Halfspace& s1, const Transform3f& tf1, const Cylinder& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -258,7 +260,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Cylinder> } template<> -bool GJKSolver_indep::shapeIntersect<Cone, Halfspace> +bool GJKSolver::shapeIntersect<Cone, Halfspace> (const Cone& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -273,7 +275,7 @@ bool GJKSolver_indep::shapeIntersect<Cone, Halfspace> } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Cone> +bool GJKSolver::shapeIntersect<Halfspace, Cone> (const Halfspace& s1, const Transform3f& tf1, const Cone& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -289,7 +291,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Cone> } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* /*contact_points*/, FCL_REAL* /*penetration_depth*/, Vec3f* /*normal*/) const { @@ -301,7 +303,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Halfspace>(const Halfspace& s1, } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Transform3f& tf1, const Halfspace& s2, const Transform3f& tf2, Vec3f* /*contact_points*/, FCL_REAL* /*penetration_depth*/, Vec3f* /*normal*/) const { @@ -313,7 +315,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Halfspace>(const Plane& s1, const Tr } template<> -bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* /*contact_points*/, FCL_REAL* /*penetration_depth*/, Vec3f* /*normal*/) const { @@ -325,7 +327,7 @@ bool GJKSolver_indep::shapeIntersect<Halfspace, Plane>(const Halfspace& s1, cons } template<> -bool GJKSolver_indep::shapeIntersect<Sphere, Plane> +bool GJKSolver::shapeIntersect<Sphere, Plane> (const Sphere& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -340,7 +342,7 @@ bool GJKSolver_indep::shapeIntersect<Sphere, Plane> } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Sphere> +bool GJKSolver::shapeIntersect<Plane, Sphere> (const Plane& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -356,7 +358,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Sphere> } template<> -bool GJKSolver_indep::shapeIntersect<Box, Plane> +bool GJKSolver::shapeIntersect<Box, Plane> (const Box& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -371,7 +373,7 @@ bool GJKSolver_indep::shapeIntersect<Box, Plane> } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Box> +bool GJKSolver::shapeIntersect<Plane, Box> (const Plane& s1, const Transform3f& tf1, const Box& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -387,7 +389,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Box> } template<> -bool GJKSolver_indep::shapeIntersect<Capsule, Plane> +bool GJKSolver::shapeIntersect<Capsule, Plane> (const Capsule& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -402,7 +404,7 @@ bool GJKSolver_indep::shapeIntersect<Capsule, Plane> } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Capsule> +bool GJKSolver::shapeIntersect<Plane, Capsule> (const Plane& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -418,7 +420,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Capsule> } template<> -bool GJKSolver_indep::shapeIntersect<Cylinder, Plane> +bool GJKSolver::shapeIntersect<Cylinder, Plane> (const Cylinder& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -433,7 +435,7 @@ bool GJKSolver_indep::shapeIntersect<Cylinder, Plane> } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Cylinder> +bool GJKSolver::shapeIntersect<Plane, Cylinder> (const Plane& s1, const Transform3f& tf1, const Cylinder& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -449,7 +451,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Cylinder> } template<> -bool GJKSolver_indep::shapeIntersect<Cone, Plane> +bool GJKSolver::shapeIntersect<Cone, Plane> (const Cone& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -464,7 +466,7 @@ bool GJKSolver_indep::shapeIntersect<Cone, Plane> } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Cone> +bool GJKSolver::shapeIntersect<Plane, Cone> (const Plane& s1, const Transform3f& tf1, const Cone& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const @@ -480,7 +482,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Cone> } template<> -bool GJKSolver_indep::shapeIntersect<Plane, Plane>(const Plane& s1, const Transform3f& tf1, +bool GJKSolver::shapeIntersect<Plane, Plane>(const Plane& s1, const Transform3f& tf1, const Plane& s2, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const { @@ -491,7 +493,7 @@ bool GJKSolver_indep::shapeIntersect<Plane, Plane>(const Plane& s1, const Transf template<> -bool GJKSolver_indep::shapeTriangleInteraction +bool GJKSolver::shapeTriangleInteraction (const Sphere& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -502,7 +504,7 @@ bool GJKSolver_indep::shapeTriangleInteraction } template<> -bool GJKSolver_indep::shapeTriangleInteraction +bool GJKSolver::shapeTriangleInteraction (const Halfspace& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -512,7 +514,7 @@ bool GJKSolver_indep::shapeTriangleInteraction } template<> -bool GJKSolver_indep::shapeTriangleInteraction +bool GJKSolver::shapeTriangleInteraction (const Plane& s, const Transform3f& tf1, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, FCL_REAL& distance, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -526,9 +528,9 @@ bool GJKSolver_indep::shapeTriangleInteraction // +------------+-----+--------+---------+------+----------+-------+------------+----------+ // | | box | sphere | capsule | cone | cylinder | plane | half-space | triangle | // +------------+-----+--------+---------+------+----------+-------+------------+----------+ -// | box | | | | | | | | | +// | box | | O | | | | | | | // +------------+-----+--------+---------+------+----------+-------+------------+----------+ -// | sphere |/////| O | O | | | | | O | +// | sphere |/////| O | O | | | | | | // +------------+-----+--------+---------+------+----------+-------+------------+----------+ // | capsule |/////|////////| O | | | | | | // +------------+-----+--------+---------+------+----------+-------+------------+----------+ @@ -544,7 +546,7 @@ bool GJKSolver_indep::shapeTriangleInteraction // +------------+-----+--------+---------+------+----------+-------+------------+----------+ template<> -bool GJKSolver_indep::shapeDistance<Sphere, Capsule> +bool GJKSolver::shapeDistance<Sphere, Capsule> (const Sphere& s1, const Transform3f& tf1, const Capsule& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -553,7 +555,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Capsule> } template<> -bool GJKSolver_indep::shapeDistance<Capsule, Sphere> +bool GJKSolver::shapeDistance<Capsule, Sphere> (const Capsule& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -562,7 +564,7 @@ bool GJKSolver_indep::shapeDistance<Capsule, Sphere> } template<> -bool GJKSolver_indep::shapeDistance<Sphere, Cylinder> +bool GJKSolver::shapeDistance<Sphere, Cylinder> (const Sphere& s1, const Transform3f& tf1, const Cylinder& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -572,7 +574,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Cylinder> } template<> -bool GJKSolver_indep::shapeDistance<Box, Sphere> +bool GJKSolver::shapeDistance<Box, Sphere> (const Box & s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -581,7 +583,7 @@ bool GJKSolver_indep::shapeDistance<Box, Sphere> } template<> -bool GJKSolver_indep::shapeDistance<Sphere, Box> +bool GJKSolver::shapeDistance<Sphere, Box> (const Sphere& s1, const Transform3f& tf1, const Box & s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -592,7 +594,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Box> } template<> -bool GJKSolver_indep::shapeDistance<Cylinder, Sphere> +bool GJKSolver::shapeDistance<Cylinder, Sphere> (const Cylinder& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -602,7 +604,7 @@ bool GJKSolver_indep::shapeDistance<Cylinder, Sphere> } template<> -bool GJKSolver_indep::shapeDistance<Sphere, Sphere> +bool GJKSolver::shapeDistance<Sphere, Sphere> (const Sphere& s1, const Transform3f& tf1, const Sphere& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const @@ -611,7 +613,7 @@ bool GJKSolver_indep::shapeDistance<Sphere, Sphere> } template<> -bool GJKSolver_indep::shapeDistance<Capsule, Capsule> +bool GJKSolver::shapeDistance<Capsule, Capsule> (const Capsule& /*s1*/, const Transform3f& /*tf1*/, const Capsule& /*s2*/, const Transform3f& /*tf2*/, FCL_REAL& /*dist*/, Vec3f& /*p1*/, Vec3f& /*p2*/, Vec3f& /*normal*/) const @@ -620,58 +622,49 @@ bool GJKSolver_indep::shapeDistance<Capsule, Capsule> } template<> - bool GJKSolver_indep::shapeDistance<TriangleP, TriangleP> + bool GJKSolver::shapeDistance<TriangleP, TriangleP> (const TriangleP& s1, const Transform3f& tf1, const TriangleP& s2, const Transform3f& tf2, FCL_REAL& dist, Vec3f& p1, Vec3f& p2, Vec3f& normal) const { - Vec3f guess(1, 0, 0); + const TriangleP + t1 (tf1.transform(s1.a), tf1.transform(s1.b), tf1.transform(s1.c)), + t2 (tf2.transform(s2.a), tf2.transform(s2.b), tf2.transform(s2.c)); + + Vec3f guess; if(enable_cached_guess) guess = cached_guess; + else guess = (t1.a + t1.b + t1.c - t2.a - t2.b - t2.c) / 3; bool enable_penetration (true); details::MinkowskiDiff shape; - shape.shapes[0] = &s1; - shape.shapes[1] = &s2; - shape.toshape1 = tf2.getRotation().transpose() * tf1.getRotation(); - shape.toshape0 = tf1.inverseTimes(tf2); - - const Vec3f& P1 (s1.a); - const Vec3f& P2 (s1.b); - const Vec3f& P3 (s1.c); - const Vec3f& Q1 (s2.a); - const Vec3f& Q2 (s2.b); - const Vec3f& Q3 (s2.c); + shape.set (&t1, &t2); details::GJK gjk((unsigned int) gjk_max_iterations, gjk_tolerance); details::GJK::Status gjk_status = gjk.evaluate(shape, -guess); if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex(); - Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero()); - for(size_t i = 0; i < gjk.getSimplex()->rank; ++i) - { - FCL_REAL p = gjk.getSimplex()->coefficient[i]; - w0 += shape.support(gjk.getSimplex()->vertex[i]->d, 0) * p; - w1 += shape.support(-gjk.getSimplex()->vertex[i]->d, 1) * p; - } + details::GJK::getClosestPoints (*gjk.getSimplex(), p1, p2); + if((gjk_status == details::GJK::Valid) || (gjk_status == details::GJK::Failed)) { - dist = (w0 - w1).norm(); - p1 = tf1.transform (w0); - p2 = tf1.transform (w1); + // TODO On degenerated case, the closest point may be wrong + // (i.e. an object face normal is colinear to gjk.ray + // assert (dist == (w0 - w1).norm()); + dist = gjk.distance; return true; } else if (gjk_status == details::GJK::Inside) { - p1 = tf1.transform (w0); - p2 = tf1.transform (w1); - if (enable_penetration) { FCL_REAL penetrationDepth = details::computePenetration - (P1, P2, P3, Q1, Q2, Q3, tf1, tf2, normal); + (t1.a, t1.b, t1.c, t2.a, t2.b, t2.c, normal); dist = -penetrationDepth; assert (dist <= 1e-6); + // GJK says Inside when below GJK.tolerance. So non intersecting + // triangle may trigger "Inside" and have no penetration. + return penetrationDepth < 0; } dist = 0; return false; diff --git a/src/shape/geometric_shapes.cpp b/src/shape/geometric_shapes.cpp index 5f7e4f189f07abc8100372b842425c64667c518f..ddf0cb4febe3b12f963e78f612fc98d082d3ee0b 100644 --- a/src/shape/geometric_shapes.cpp +++ b/src/shape/geometric_shapes.cpp @@ -44,60 +44,49 @@ namespace hpp namespace fcl { -void Convex::fillEdges() +ConvexBase::ConvexBase(bool own_storage, Vec3f* points_, int num_points_) : + ShapeBase(), + points (points_), + num_points (num_points_), + own_storage_ (own_storage) { - int* points_in_poly = polygons; - if(edges) delete [] edges; + computeCenter(); +} - int num_edges_alloc = 0; - for(int i = 0; i < num_polygons; ++i) - { - num_edges_alloc += *points_in_poly; - points_in_poly += (*points_in_poly + 1); +ConvexBase::ConvexBase(const ConvexBase& other) : + ShapeBase (other), + points (other.points), + num_points (other.num_points), + center (other.center), + own_storage_ (other.own_storage_) +{ + if (own_storage_) { + points = new Vec3f[num_points]; + memcpy(points, other.points, sizeof(Vec3f) * num_points); } - edges = new Edge[num_edges_alloc]; + neighbors = new Neighbors[num_points]; + memcpy(neighbors, other.neighbors, sizeof(Neighbors) * num_points); - points_in_poly = polygons; - int* index = polygons + 1; - num_edges = 0; - Edge e; - bool isinset; - for(int i = 0; i < num_polygons; ++i) - { - for(int j = 0; j < *points_in_poly; ++j) - { - e.first = std::min(index[j], index[(j+1)%*points_in_poly]); - e.second = std::max(index[j], index[(j+1)%*points_in_poly]); - isinset = false; - for(int k = 0; k < num_edges; ++k) - { - if((edges[k].first == e.first) && (edges[k].second == e.second)) - { - isinset = true; - break; - } - } - - if(!isinset) - { - edges[num_edges].first = e.first; - edges[num_edges].second = e.second; - ++num_edges; - } - } - - points_in_poly += (*points_in_poly + 1); - index = points_in_poly + 1; - } + int c_nneighbors = 0; + for (int i = 0; i < num_points; ++i) c_nneighbors += neighbors[i].count(); + nneighbors_ = new unsigned int[c_nneighbors]; + memcpy(nneighbors_, other.nneighbors_, sizeof(unsigned int) * c_nneighbors); +} - if(num_edges < num_edges_alloc) - { - Edge* tmp = new Edge[num_edges]; - memcpy(tmp, edges, num_edges * sizeof(Edge)); - delete [] edges; - edges = tmp; - } +ConvexBase::~ConvexBase () +{ + delete [] neighbors; + delete [] nneighbors_; + if (own_storage_) delete [] points; +} + +void ConvexBase::computeCenter() +{ + center.setZero(); + for(int i = 0; i < num_points; ++i) + center += points[i]; + center /= num_points; } void Halfspace::unitNormalTest() @@ -132,7 +121,6 @@ void Plane::unitNormalTest() } } - void Box::computeLocalAABB() { computeBV<AABB>(*this, Transform3f(), aabb_local); @@ -168,7 +156,7 @@ void Cylinder::computeLocalAABB() aabb_radius = (aabb_local.min_ - aabb_center).norm(); } -void Convex::computeLocalAABB() +void ConvexBase::computeLocalAABB() { computeBV<AABB>(*this, Transform3f(), aabb_local); aabb_center = aabb_local.center(); diff --git a/src/shape/geometric_shapes_utility.cpp b/src/shape/geometric_shapes_utility.cpp index acf9fb335f56bd66b48cfdc77c2de8cee172432a..c0aba4929503b4948ed397f71a74ff2ceb51c460 100644 --- a/src/shape/geometric_shapes_utility.cpp +++ b/src/shape/geometric_shapes_utility.cpp @@ -37,7 +37,8 @@ #include <hpp/fcl/shape/geometric_shapes_utility.h> -#include <hpp/fcl/BVH/BV_fitter.h> +#include <hpp/fcl/internal/BV_fitter.h> +#include <hpp/fcl/internal/tools.h> namespace hpp { @@ -50,16 +51,16 @@ namespace details std::vector<Vec3f> getBoundVertices(const Box& box, const Transform3f& tf) { std::vector<Vec3f> result(8); - FCL_REAL a = box.side[0] / 2; - FCL_REAL b = box.side[1] / 2; - FCL_REAL c = box.side[2] / 2; - result[0] = tf.transform(Vec3f(a, b, c)); - result[1] = tf.transform(Vec3f(a, b, -c)); - result[2] = tf.transform(Vec3f(a, -b, c)); - result[3] = tf.transform(Vec3f(a, -b, -c)); - result[4] = tf.transform(Vec3f(-a, b, c)); - result[5] = tf.transform(Vec3f(-a, b, -c)); - result[6] = tf.transform(Vec3f(-a, -b, c)); + FCL_REAL a = box.halfSide[0]; + FCL_REAL b = box.halfSide[1]; + FCL_REAL c = box.halfSide[2]; + result[0] = tf.transform(Vec3f( a, b, c)); + result[1] = tf.transform(Vec3f( a, b, -c)); + result[2] = tf.transform(Vec3f( a, -b, c)); + result[3] = tf.transform(Vec3f( a, -b, -c)); + result[4] = tf.transform(Vec3f(-a, b, c)); + result[5] = tf.transform(Vec3f(-a, b, -c)); + result[6] = tf.transform(Vec3f(-a, -b, c)); result[7] = tf.transform(Vec3f(-a, -b, -c)); return result; @@ -95,7 +96,7 @@ std::vector<Vec3f> getBoundVertices(const Capsule& capsule, const Transform3f& t std::vector<Vec3f> result(36); const FCL_REAL m = (1 + sqrt(5.0)) / 2.0; - FCL_REAL hl = capsule.lz * 0.5; + FCL_REAL hl = capsule.halfLength; FCL_REAL edge_size = capsule.radius * 6 / (sqrt(27.0) + sqrt(15.0)); FCL_REAL a = edge_size; FCL_REAL b = m * edge_size; @@ -152,7 +153,7 @@ std::vector<Vec3f> getBoundVertices(const Cone& cone, const Transform3f& tf) { std::vector<Vec3f> result(7); - FCL_REAL hl = cone.lz * 0.5; + FCL_REAL hl = cone.halfLength; FCL_REAL r2 = cone.radius * 2 / sqrt(3.0); FCL_REAL a = 0.5 * r2; FCL_REAL b = cone.radius; @@ -173,7 +174,7 @@ std::vector<Vec3f> getBoundVertices(const Cylinder& cylinder, const Transform3f& { std::vector<Vec3f> result(12); - FCL_REAL hl = cylinder.lz * 0.5; + FCL_REAL hl = cylinder.halfLength; FCL_REAL r2 = cylinder.radius * 2 / sqrt(3.0); FCL_REAL a = 0.5 * r2; FCL_REAL b = cylinder.radius; @@ -195,7 +196,7 @@ std::vector<Vec3f> getBoundVertices(const Cylinder& cylinder, const Transform3f& return result; } -std::vector<Vec3f> getBoundVertices(const Convex& convex, const Transform3f& tf) +std::vector<Vec3f> getBoundVertices(const ConvexBase& convex, const Transform3f& tf) { std::vector<Vec3f> result(convex.num_points); for(int i = 0; i < convex.num_points; ++i) @@ -226,7 +227,7 @@ Halfspace transform(const Halfspace& a, const Transform3f& tf) /// where n' = R * n /// and d' = d + n' * T - Vec3f n = tf.getQuatRotation() * a.n; + Vec3f n = tf.getRotation() * a.n; FCL_REAL d = a.d + n.dot(tf.getTranslation()); return Halfspace(n, d); @@ -241,7 +242,7 @@ Plane transform(const Plane& a, const Transform3f& tf) /// where n' = R * n /// and d' = d + n' * T - Vec3f n = tf.getQuatRotation() * a.n; + Vec3f n = tf.getRotation() * a.n; FCL_REAL d = a.d + n.dot(tf.getTranslation()); return Plane(n, d); @@ -255,7 +256,7 @@ void computeBV<AABB, Box>(const Box& s, const Transform3f& tf, AABB& bv) const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); - Vec3f v_delta (0.5 * R.cwiseAbs() * s.side); + Vec3f v_delta (R.cwiseAbs() * s.halfSide); bv.max_ = T + v_delta; bv.min_ = T - v_delta; } @@ -276,7 +277,7 @@ void computeBV<AABB, Capsule>(const Capsule& s, const Transform3f& tf, AABB& bv) const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); - Vec3f v_delta(0.5 * (R.col(2)*s.lz).cwiseAbs() + Vec3f::Constant(s.radius)); + Vec3f v_delta(R.col(2).cwiseAbs() * s.halfLength + Vec3f::Constant(s.radius)); bv.max_ = T + v_delta; bv.min_ = T - v_delta; } @@ -287,9 +288,9 @@ void computeBV<AABB, Cone>(const Cone& s, const Transform3f& tf, AABB& bv) const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); - FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + 0.5 * fabs(R(0, 2) * s.lz); - FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + 0.5 * fabs(R(1, 2) * s.lz); - FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + 0.5 * fabs(R(2, 2) * s.lz); + FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + fabs(R(0, 2) * s.halfLength); + FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + fabs(R(1, 2) * s.halfLength); + FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + fabs(R(2, 2) * s.halfLength); Vec3f v_delta(x_range, y_range, z_range); bv.max_ = T + v_delta; @@ -302,9 +303,9 @@ void computeBV<AABB, Cylinder>(const Cylinder& s, const Transform3f& tf, AABB& b const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); - FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + 0.5 * fabs(R(0, 2) * s.lz); - FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + 0.5 * fabs(R(1, 2) * s.lz); - FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + 0.5 * fabs(R(2, 2) * s.lz); + FCL_REAL x_range = fabs(R(0, 0) * s.radius) + fabs(R(0, 1) * s.radius) + fabs(R(0, 2) * s.halfLength); + FCL_REAL y_range = fabs(R(1, 0) * s.radius) + fabs(R(1, 1) * s.radius) + fabs(R(1, 2) * s.halfLength); + FCL_REAL z_range = fabs(R(2, 0) * s.radius) + fabs(R(2, 1) * s.radius) + fabs(R(2, 2) * s.halfLength); Vec3f v_delta(x_range, y_range, z_range); bv.max_ = T + v_delta; @@ -312,7 +313,7 @@ void computeBV<AABB, Cylinder>(const Cylinder& s, const Transform3f& tf, AABB& b } template<> -void computeBV<AABB, Convex>(const Convex& s, const Transform3f& tf, AABB& bv) +void computeBV<AABB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, AABB& bv) { const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); @@ -405,9 +406,9 @@ void computeBV<OBB, Box>(const Box& s, const Transform3f& tf, OBB& bv) const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); - bv.To.noalias() = T; - bv.axes.noalias() = R; - bv.extent = s.side * (FCL_REAL)0.5; + bv.To = T; + bv.axes = R; + bv.extent = s.halfSide; } template<> @@ -428,7 +429,7 @@ void computeBV<OBB, Capsule>(const Capsule& s, const Transform3f& tf, OBB& bv) bv.To.noalias() = T; bv.axes.noalias() = R; - bv.extent << s.radius, s.radius, s.lz / 2 + s.radius; + bv.extent << s.radius, s.radius, s.halfLength + s.radius; } template<> @@ -439,7 +440,7 @@ void computeBV<OBB, Cone>(const Cone& s, const Transform3f& tf, OBB& bv) bv.To.noalias() = T; bv.axes.noalias() = R; - bv.extent << s.radius, s.radius, s.lz / 2; + bv.extent << s.radius, s.radius, s.halfLength; } template<> @@ -450,11 +451,11 @@ void computeBV<OBB, Cylinder>(const Cylinder& s, const Transform3f& tf, OBB& bv) bv.To.noalias() = T; bv.axes.noalias() = R; - bv.extent << s.radius, s.radius, s.lz / 2; + bv.extent << s.radius, s.radius, s.halfLength; } template<> -void computeBV<OBB, Convex>(const Convex& s, const Transform3f& tf, OBB& bv) +void computeBV<OBB, ConvexBase>(const ConvexBase& s, const Transform3f& tf, OBB& bv) { const Matrix3f& R = tf.getRotation(); const Vec3f& T = tf.getTranslation(); @@ -481,7 +482,7 @@ void computeBV<RSS, Halfspace>(const Halfspace&, const Transform3f&, RSS& bv) /// Half space can only have very rough RSS bv.axes.setIdentity(); bv.Tr.setZero(); - bv.l[0] = bv.l[1] = bv.r = std::numeric_limits<FCL_REAL>::max(); + bv.length[0] = bv.length[1] = bv.radius = std::numeric_limits<FCL_REAL>::max(); } template<> @@ -697,7 +698,7 @@ void computeBV<KDOP<24>, Halfspace>(const Halfspace& s, const Transform3f& tf, K template<> void computeBV<OBB, Plane>(const Plane& s, const Transform3f& tf, OBB& bv) { - Vec3f n = tf.getQuatRotation() * s.n; + Vec3f n = tf.getRotation() * s.n; generateCoordinateSystem(n, bv.axes.col(1), bv.axes.col(2)); bv.axes.col(0).noalias() = n; @@ -710,15 +711,15 @@ void computeBV<OBB, Plane>(const Plane& s, const Transform3f& tf, OBB& bv) template<> void computeBV<RSS, Plane>(const Plane& s, const Transform3f& tf, RSS& bv) { - Vec3f n = tf.getQuatRotation() * s.n; + Vec3f n = tf.getRotation() * s.n; generateCoordinateSystem(n, bv.axes.col(1), bv.axes.col(2)); bv.axes.col(0).noalias() = n; - bv.l[0] = std::numeric_limits<FCL_REAL>::max(); - bv.l[1] = std::numeric_limits<FCL_REAL>::max(); + bv.length[0] = std::numeric_limits<FCL_REAL>::max(); + bv.length[1] = std::numeric_limits<FCL_REAL>::max(); - bv.r = 0; + bv.radius = 0; Vec3f p = s.n * s.d; bv.Tr = tf.transform(p); diff --git a/src/traits_traversal.h b/src/traits_traversal.h new file mode 100644 index 0000000000000000000000000000000000000000..c296ac8fd1068d251f17d5c905d94497c8e2907c --- /dev/null +++ b/src/traits_traversal.h @@ -0,0 +1,105 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2019, CNRS-LAAS + * All rights reserved. + */ + +/** \author Lucile Remigy, Joseph Mirabel */ + +#include <hpp/fcl/collision_func_matrix.h> +#include <hpp/fcl/narrowphase/narrowphase.h> +#include <../src/collision_node.h> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include <../src/distance_func_matrix.h> + +namespace hpp +{ +namespace fcl +{ + +// TraversalTraitsCollision for collision_func_matrix.cpp + +template <typename TypeA, typename TypeB> +struct TraversalTraitsCollision +{ +}; + +#ifdef HPP_FCL_HAVE_OCTOMAP + +template <typename T_SH> +struct TraversalTraitsCollision <T_SH, OcTree> +{ + typedef ShapeOcTreeCollisionTraversalNode<T_SH> CollisionTraversal_t; +}; + +template <typename T_SH> +struct TraversalTraitsCollision <OcTree, T_SH> +{ + typedef OcTreeShapeCollisionTraversalNode<T_SH> CollisionTraversal_t; +}; + +template <> +struct TraversalTraitsCollision <OcTree, OcTree> +{ + typedef OcTreeCollisionTraversalNode CollisionTraversal_t; +}; + +template <typename T_BVH> +struct TraversalTraitsCollision <OcTree, BVHModel<T_BVH> > +{ + typedef OcTreeMeshCollisionTraversalNode<T_BVH> CollisionTraversal_t; +}; + +template <typename T_BVH> +struct TraversalTraitsCollision <BVHModel<T_BVH>, OcTree> +{ + typedef MeshOcTreeCollisionTraversalNode<T_BVH> CollisionTraversal_t; +}; + +#endif + +// TraversalTraitsDistance for distance_func_matrix.cpp + +template <typename TypeA, typename TypeB> +struct TraversalTraitsDistance +{ +}; + +#ifdef HPP_FCL_HAVE_OCTOMAP + +template <typename T_SH> +struct TraversalTraitsDistance <T_SH, OcTree> +{ + typedef ShapeOcTreeDistanceTraversalNode<T_SH> CollisionTraversal_t; +}; + +template <typename T_SH> +struct TraversalTraitsDistance <OcTree, T_SH> +{ + typedef OcTreeShapeDistanceTraversalNode<T_SH> CollisionTraversal_t; +}; + +template <> +struct TraversalTraitsDistance <OcTree, OcTree> +{ + typedef OcTreeDistanceTraversalNode CollisionTraversal_t; +}; + +template <typename T_BVH> +struct TraversalTraitsDistance <OcTree, BVHModel<T_BVH> > +{ + typedef OcTreeMeshDistanceTraversalNode<T_BVH> CollisionTraversal_t; +}; + +template <typename T_BVH> +struct TraversalTraitsDistance <BVHModel<T_BVH>, OcTree> +{ + typedef MeshOcTreeDistanceTraversalNode<T_BVH> CollisionTraversal_t; +}; + +#endif + +} + +} //hpp \ No newline at end of file diff --git a/src/traversal/traversal_node_base.cpp b/src/traversal/traversal_node_base.cpp index a4bc4eac9dedfa7ecef2ede85ec0ed51ce8f6f68..7ae6ab13286f29f06c8035d2f117a933255d9f7e 100644 --- a/src/traversal/traversal_node_base.cpp +++ b/src/traversal/traversal_node_base.cpp @@ -36,7 +36,7 @@ /** \author Jia Pan */ -#include <hpp/fcl/traversal/traversal_node_base.h> +#include <hpp/fcl/internal/traversal_node_base.h> #include <limits> namespace hpp @@ -97,7 +97,7 @@ DistanceTraversalNodeBase::~DistanceTraversalNodeBase() { } - FCL_REAL DistanceTraversalNodeBase::BVTesting(int /*b1*/, int /*b2*/) const + FCL_REAL DistanceTraversalNodeBase::BVDistanceLowerBound(int /*b1*/, int /*b2*/) const { return std::numeric_limits<FCL_REAL>::max(); } diff --git a/src/traversal/traversal_node_bvhs.cpp b/src/traversal/traversal_node_bvhs.cpp index 5fe97fa5a0eaf8b892e77971b24ca2854e8b02d2..cdaeddbecf728bc79ff218f7b12114786eb23f4d 100644 --- a/src/traversal/traversal_node_bvhs.cpp +++ b/src/traversal/traversal_node_bvhs.cpp @@ -36,7 +36,7 @@ /** \author Jia Pan */ -#include <hpp/fcl/traversal/traversal_node_bvhs.h> +#include <hpp/fcl/internal/traversal_node_bvhs.h> namespace hpp { @@ -46,7 +46,7 @@ namespace fcl namespace details { template<typename BV> -static inline void meshDistanceOrientedNodeLeafTesting(int b1, int b2, +static inline void meshDistanceOrientedNodeleafComputeDistance(int b1, int b2, const BVHModel<BV>* model1, const BVHModel<BV>* model2, Vec3f* vertices1, Vec3f* vertices2, Triangle* tri_indices1, Triangle* tri_indices2, @@ -152,15 +152,15 @@ void MeshDistanceTraversalNodeRSS::postprocess() details::distancePostprocessOrientedNode(model1, model2, tf1, request, *result); } -FCL_REAL MeshDistanceTraversalNodeRSS::BVTesting(int b1, int b2) const +FCL_REAL MeshDistanceTraversalNodeRSS::BVDistanceLowerBound(int b1, int b2) const { if(enable_statistics) num_bv_tests++; return distance(R, T, model1->getBV(b1).bv, model2->getBV(b2).bv); } -void MeshDistanceTraversalNodeRSS::leafTesting(int b1, int b2) const +void MeshDistanceTraversalNodeRSS::leafComputeDistance(int b1, int b2) const { - details::meshDistanceOrientedNodeLeafTesting(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, + details::meshDistanceOrientedNodeleafComputeDistance(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, R, T, enable_statistics, num_leaf_tests, request, *result); } @@ -180,15 +180,15 @@ void MeshDistanceTraversalNodekIOS::postprocess() details::distancePostprocessOrientedNode(model1, model2, tf1, request, *result); } -FCL_REAL MeshDistanceTraversalNodekIOS::BVTesting(int b1, int b2) const +FCL_REAL MeshDistanceTraversalNodekIOS::BVDistanceLowerBound(int b1, int b2) const { if(enable_statistics) num_bv_tests++; return distance(R, T, model1->getBV(b1).bv, model2->getBV(b2).bv); } -void MeshDistanceTraversalNodekIOS::leafTesting(int b1, int b2) const +void MeshDistanceTraversalNodekIOS::leafComputeDistance(int b1, int b2) const { - details::meshDistanceOrientedNodeLeafTesting(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, + details::meshDistanceOrientedNodeleafComputeDistance(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, R, T, enable_statistics, num_leaf_tests, request, *result); } @@ -208,15 +208,15 @@ void MeshDistanceTraversalNodeOBBRSS::postprocess() details::distancePostprocessOrientedNode(model1, model2, tf1, request, *result); } -FCL_REAL MeshDistanceTraversalNodeOBBRSS::BVTesting(int b1, int b2) const +FCL_REAL MeshDistanceTraversalNodeOBBRSS::BVDistanceLowerBound(int b1, int b2) const { if(enable_statistics) num_bv_tests++; return distance(R, T, model1->getBV(b1).bv, model2->getBV(b2).bv); } -void MeshDistanceTraversalNodeOBBRSS::leafTesting(int b1, int b2) const +void MeshDistanceTraversalNodeOBBRSS::leafComputeDistance(int b1, int b2) const { - details::meshDistanceOrientedNodeLeafTesting(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, + details::meshDistanceOrientedNodeleafComputeDistance(b1, b2, model1, model2, vertices1, vertices2, tri_indices1, tri_indices2, R, T, enable_statistics, num_leaf_tests, request, *result); } diff --git a/src/traversal/traversal_node_setup.cpp b/src/traversal/traversal_node_setup.cpp index 7275286062ab008bbba9dcb3abbb7f5d3053bb87..b0d13e489e719ee648d1e17f6a62236bcbbee824 100644 --- a/src/traversal/traversal_node_setup.cpp +++ b/src/traversal/traversal_node_setup.cpp @@ -36,81 +36,13 @@ /** \author Jia Pan */ -#include <hpp/fcl/traversal/traversal_node_setup.h> - +#include <hpp/fcl/internal/traversal_node_setup.h> +#include <hpp/fcl/internal/tools.h> namespace hpp { namespace fcl { - -namespace details -{ -template<typename BV, typename OrientedNode> -static inline bool setupMeshCollisionOrientedNode(OrientedNode& node, - const BVHModel<BV>& model1, const Transform3f& tf1, - const BVHModel<BV>& model2, const Transform3f& tf2, - CollisionResult& result) -{ - if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES) - return false; - - node.vertices1 = model1.vertices; - node.vertices2 = model2.vertices; - - node.tri_indices1 = model1.tri_indices; - node.tri_indices2 = model2.tri_indices; - - node.model1 = &model1; - node.tf1 = tf1; - node.model2 = &model2; - node.tf2 = tf2; - - node.result = &result; - - relativeTransform(tf1.getRotation(), tf1.getTranslation(), tf2.getRotation(), tf2.getTranslation(), node.RT.R, node.RT.T); - - return true; -} - -} - - -bool initialize(MeshCollisionTraversalNodeOBB& node, - const BVHModel<OBB>& model1, const Transform3f& tf1, - const BVHModel<OBB>& model2, const Transform3f& tf2, - CollisionResult& result) -{ - return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result); -} - - -bool initialize(MeshCollisionTraversalNodeRSS& node, - const BVHModel<RSS>& model1, const Transform3f& tf1, - const BVHModel<RSS>& model2, const Transform3f& tf2, - CollisionResult& result) -{ - return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result); -} - - -bool initialize(MeshCollisionTraversalNodekIOS& node, - const BVHModel<kIOS>& model1, const Transform3f& tf1, - const BVHModel<kIOS>& model2, const Transform3f& tf2, - CollisionResult& result) -{ - return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result); -} - -bool initialize(MeshCollisionTraversalNodeOBBRSS& node, - const BVHModel<OBBRSS>& model1, const Transform3f& tf1, - const BVHModel<OBBRSS>& model2, const Transform3f& tf2, - CollisionResult& result) -{ - return details::setupMeshCollisionOrientedNode(node, model1, tf1, model2, tf2, result); -} - - namespace details { template<typename BV, typename OrientedNode> diff --git a/src/traversal/traversal_recurse.cpp b/src/traversal/traversal_recurse.cpp index 050c76f0695e4e7a04f27cba1b45b3d32eb6eb60..cf4c822780e59276c4af07fd2fa8e1ae3730a0e0 100644 --- a/src/traversal/traversal_recurse.cpp +++ b/src/traversal/traversal_recurse.cpp @@ -36,7 +36,9 @@ /** \author Jia Pan */ -#include <hpp/fcl/traversal/traversal_recurse.h> +#include <hpp/fcl/internal/traversal_recurse.h> + +#include <vector> namespace hpp { @@ -52,12 +54,12 @@ void collisionRecurse(CollisionTraversalNodeBase* node, int b1, int b2, { updateFrontList(front_list, b1, b2); - if(node->BVTesting(b1, b2, sqrDistLowerBound)) return; - node->leafTesting(b1, b2, sqrDistLowerBound); + // if(node->BVDisjoints(b1, b2, sqrDistLowerBound)) return; + node->leafCollides(b1, b2, sqrDistLowerBound); return; } - if(node->BVTesting(b1, b2, sqrDistLowerBound)) { + if(node->BVDisjoints(b1, b2, sqrDistLowerBound)) { updateFrontList(front_list, b1, b2); return; } @@ -89,18 +91,70 @@ void collisionRecurse(CollisionTraversalNodeBase* node, int b1, int b2, } } - void collisionRecurse(MeshCollisionTraversalNodeOBB* /*node*/, int /*b1*/, - int /*b2*/, const Matrix3f& /*R*/, const Vec3f& /*T*/, - BVHFrontList* /*front_list*/) +void collisionNonRecurse(CollisionTraversalNodeBase* node, + BVHFrontList* front_list, FCL_REAL& sqrDistLowerBound) { - throw std::runtime_error ("Not implemented."); -} + typedef std::pair<int, int> BVPair_t; + //typedef std::stack<BVPair_t, std::vector<BVPair_t> > Stack_t; + typedef std::vector<BVPair_t> Stack_t; + + Stack_t pairs; + pairs.reserve (1000); + sqrDistLowerBound = std::numeric_limits<FCL_REAL>::infinity(); + FCL_REAL sdlb = std::numeric_limits<FCL_REAL>::infinity(); + + pairs.push_back (BVPair_t (0, 0)); + + while (!pairs.empty()) { + int a = pairs.back().first, + b = pairs.back().second; + pairs.pop_back(); + + bool la = node->isFirstNodeLeaf(a); + bool lb = node->isSecondNodeLeaf(b); + + // Leaf / Leaf case + if (la && lb) { + updateFrontList(front_list, a, b); + + // TODO should we test the BVs ? + //if(node->BVDijsoints(a, b, sdlb)) { + //if (sdlb < sqrDistLowerBound) sqrDistLowerBound = sdlb; + //continue; + //} + node->leafCollides(a, b, sdlb); + if (sdlb < sqrDistLowerBound) sqrDistLowerBound = sdlb; + if (node->canStop() && !front_list) return; + continue; + } - void collisionRecurse(MeshCollisionTraversalNodeRSS* /*node*/, int /*b1*/, - int /*b2*/, const Matrix3f& /*R*/, const Vec3f& /*T*/, - BVHFrontList* /*front_list*/) -{ - throw std::runtime_error ("Not implemented."); + // TODO shouldn't we test the leaf triangle against BV is la != lb + // if (la && !lb) { // leaf triangle 1 against BV 2 + // } else if (!la && lb) { // BV 1 against leaf triangle 2 + // } + + // Check the BV + if(node->BVDisjoints(a, b, sdlb)) { + if (sdlb < sqrDistLowerBound) sqrDistLowerBound = sdlb; + updateFrontList(front_list, a, b); + continue; + } + + if(node->firstOverSecond(a, b)) + { + int c1 = node->getFirstLeftChild(a); + int c2 = node->getFirstRightChild(a); + pairs.push_back (BVPair_t (c2, b)); + pairs.push_back (BVPair_t (c1, b)); + } + else + { + int c1 = node->getSecondLeftChild(b); + int c2 = node->getSecondRightChild(b); + pairs.push_back (BVPair_t (a, c2)); + pairs.push_back (BVPair_t (a, c1)); + } + } } /** Recurse function for self collision @@ -115,7 +169,7 @@ void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontLi { updateFrontList(front_list, b1, b2); - node->leafTesting(b1, b2); + node->leafComputeDistance(b1, b2); return; } @@ -136,8 +190,8 @@ void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontLi c2 = node->getSecondRightChild(b2); } - FCL_REAL d1 = node->BVTesting(a1, a2); - FCL_REAL d2 = node->BVTesting(c1, c2); + FCL_REAL d1 = node->BVDistanceLowerBound(a1, a2); + FCL_REAL d2 = node->BVDistanceLowerBound(c1, c2); if(d2 < d1) { @@ -166,17 +220,17 @@ void distanceRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFrontLi } -/** \brief Bounding volume test structure */ +/** @brief Bounding volume test structure */ struct BVT { - /** \brief distance between bvs */ + /** @brief distance between bvs */ FCL_REAL d; - /** \brief bv indices for a pair of bvs in two models */ + /** @brief bv indices for a pair of bvs in two models */ int b1, b2; }; -/** \brief Comparer between two BVT */ +/** @brief Comparer between two BVT */ struct BVT_Comparer { bool operator() (const BVT& lhs, const BVT& rhs) const @@ -221,7 +275,7 @@ struct BVTQ std::priority_queue<BVT, std::vector<BVT>, BVT_Comparer> pq; - /** \brief Queue size */ + /** @brief Queue size */ unsigned int qsize; }; @@ -244,7 +298,7 @@ void distanceQueueRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFr { updateFrontList(front_list, min_test.b1, min_test.b2); - node->leafTesting(min_test.b1, min_test.b2); + node->leafComputeDistance(min_test.b1, min_test.b2); } else if(bvtq.full()) { @@ -263,11 +317,11 @@ void distanceQueueRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFr int c2 = node->getFirstRightChild(min_test.b1); bvt1.b1 = c1; bvt1.b2 = min_test.b2; - bvt1.d = node->BVTesting(bvt1.b1, bvt1.b2); + bvt1.d = node->BVDistanceLowerBound(bvt1.b1, bvt1.b2); bvt2.b1 = c2; bvt2.b2 = min_test.b2; - bvt2.d = node->BVTesting(bvt2.b1, bvt2.b2); + bvt2.d = node->BVDistanceLowerBound(bvt2.b1, bvt2.b2); } else { @@ -275,11 +329,11 @@ void distanceQueueRecurse(DistanceTraversalNodeBase* node, int b1, int b2, BVHFr int c2 = node->getSecondRightChild(min_test.b2); bvt1.b1 = min_test.b1; bvt1.b2 = c1; - bvt1.d = node->BVTesting(bvt1.b1, bvt1.b2); + bvt1.d = node->BVDistanceLowerBound(bvt1.b1, bvt1.b2); bvt2.b1 = min_test.b1; bvt2.b2 = c2; - bvt2.d = node->BVTesting(bvt2.b1, bvt2.b2); + bvt2.d = node->BVDistanceLowerBound(bvt2.b1, bvt2.b2); } bvtq.push(bvt1); @@ -324,11 +378,11 @@ void propagateBVHFrontListCollisionRecurse } else { - if(!node->BVTesting(b1, b2, sqrDistLowerBound)) { + if(!node->BVDisjoints(b1, b2, sqrDistLowerBound)) { front_iter->valid = false; if(node->firstOverSecond(b1, b2)) { int c1 = node->getFirstLeftChild(b1); - int c2 = node->getFirstRightChild(b2); + int c2 = node->getFirstRightChild(b1); collisionRecurse(node, c1, b2, front_list, sqrDistLowerBound1); collisionRecurse(node, c2, b2, front_list, sqrDistLowerBound2); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 88ae18961a525dfdac3b4727a41c883faf384d17..2db77cc854e5afe7f8d759de2a459e4149a9338e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,44 +13,52 @@ macro(add_fcl_test test_name) target_link_libraries(${test_name} hpp-fcl ${Boost_LIBRARIES} + utility ) + PKG_CONFIG_USE_DEPENDENCY(${test_name} assimp) add_test(${test_name} ${EXECUTABLE_OUTPUT_PATH}/${test_name}) endmacro(add_fcl_test) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) +add_library(utility STATIC utility.cpp) -add_fcl_test(test_fcl_math test_fcl_math.cpp) +add_fcl_test(math math.cpp) -add_fcl_test(test_fcl_collision test_fcl_collision.cpp test_fcl_utility.cpp) -add_fcl_test(test_fcl_distance test_fcl_distance.cpp test_fcl_utility.cpp) -add_fcl_test(test_fcl_distance_lower_bound test_fcl_distance_lower_bound.cpp - test_fcl_utility.cpp) -add_fcl_test(test_fcl_geometric_shapes test_fcl_geometric_shapes.cpp test_fcl_utility.cpp) -#add_fcl_test(test_fcl_broadphase test_fcl_broadphase.cpp test_fcl_utility.cpp) -#add_fcl_test(test_fcl_shape_mesh_consistency test_fcl_shape_mesh_consistency.cpp test_fcl_utility.cpp) -add_fcl_test(test_fcl_frontlist test_fcl_frontlist.cpp test_fcl_utility.cpp) -#add_fcl_test(test_fcl_math test_fcl_math.cpp test_fcl_utility.cpp) +add_fcl_test(collision collision.cpp) +add_fcl_test(distance distance.cpp) +add_fcl_test(distance_lower_bound distance_lower_bound.cpp) +add_fcl_test(geometric_shapes geometric_shapes.cpp) +#add_fcl_test(broadphase broadphase.cpp) +#add_fcl_test(shape_mesh_consistency shape_mesh_consistency.cpp) +add_fcl_test(frontlist frontlist.cpp) +#add_fcl_test(math math.cpp) -# add_fcl_test(test_fcl_sphere_capsule test_fcl_sphere_capsule.cpp) -add_fcl_test(test_fcl_capsule_capsule test_fcl_capsule_capsule.cpp test_fcl_utility.cpp) -add_fcl_test(test_fcl_box_box_distance test_fcl_box_box_distance.cpp test_fcl_utility.cpp) -add_fcl_test(test_fcl_simple test_fcl_simple.cpp) -add_fcl_test(test_fcl_capsule_box_1 test_fcl_capsule_box_1.cpp test_fcl_utility.cpp) -add_fcl_test(test_fcl_capsule_box_2 test_fcl_capsule_box_2.cpp test_fcl_utility.cpp) -#add_fcl_test(test_fcl_obb test_fcl_obb.cpp) +# add_fcl_test(sphere_capsule sphere_capsule.cpp) +add_fcl_test(capsule_capsule capsule_capsule.cpp) +add_fcl_test(box_box_distance box_box_distance.cpp) +add_fcl_test(simple simple.cpp) +add_fcl_test(capsule_box_1 capsule_box_1.cpp) +add_fcl_test(capsule_box_2 capsule_box_2.cpp) +add_fcl_test(obb obb.cpp) +add_fcl_test(convex convex.cpp) -add_fcl_test(test_fcl_bvh_models test_fcl_bvh_models.cpp test_fcl_utility.cpp) +add_fcl_test(bvh_models bvh_models.cpp) -add_fcl_test(test_fcl_profiling test_fcl_profiling.cpp test_fcl_utility.cpp) -PKG_CONFIG_USE_DEPENDENCY(test_fcl_profiling assimp) +add_fcl_test(profiling profiling.cpp) +PKG_CONFIG_USE_DEPENDENCY(profiling assimp) -add_fcl_test(test_fcl_gjk test_fcl_gjk.cpp) +add_fcl_test(gjk gjk.cpp) if(HPP_FCL_HAVE_OCTOMAP) - add_fcl_test(test_fcl_octree test_fcl_octree.cpp test_fcl_utility.cpp) + add_fcl_test(octree octree.cpp) endif(HPP_FCL_HAVE_OCTOMAP) ## Benchmark -add_executable(test-benchmark benchmark.cpp test_fcl_utility.cpp) -target_link_libraries(test-benchmark hpp-fcl ${Boost_LIBRARIES}) +add_executable(test-benchmark benchmark.cpp) +target_link_libraries(test-benchmark hpp-fcl ${Boost_LIBRARIES} utility) + +## Python tests +IF(BUILD_PYTHON_INTERFACE) + ADD_SUBDIRECTORY(python_unit) +ENDIF(BUILD_PYTHON_INTERFACE) diff --git a/test/benchmark.cpp b/test/benchmark.cpp index 28b718c5df33032ccd153c1b949ac7583ec518d4..2b120ad0963bc32ac7d34ff2e8711b2b13767062 100644 --- a/test/benchmark.cpp +++ b/test/benchmark.cpp @@ -14,13 +14,16 @@ // received a copy of the GNU Lesser General Public License along with // hpp-fcl. If not, see <http://www.gnu.org/licenses/>. -#include <hpp/fcl/traversal/traversal_node_setup.h> -#include <hpp/fcl/traversal/traversal_node_bvhs.h> -#include <hpp/fcl/collision_node.h> -#include "test_fcl_utility.h" -#include "fcl_resources/config.h" #include <boost/filesystem.hpp> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include <hpp/fcl/internal/traversal_node_bvhs.h> +#include "../src/collision_node.h" +#include <hpp/fcl/internal/BV_splitter.h> + +#include "utility.h" +#include "fcl_resources/config.h" + #define RUN_CASE(BV,tf,models,split) \ run<BV>(tf, models, split, #BV " - " #split ":\t") diff --git a/test/benchmark/test_fcl_gjk.output b/test/benchmark/test_fcl_gjk.output index aaf9b5434d9259016a2fa21b57aee3875c5e5543..f20f15d5373150ab41cd103d3ca74c2b9639a87f 100644 --- a/test/benchmark/test_fcl_gjk.output +++ b/test/benchmark/test_fcl_gjk.output @@ -1,4 +1,4 @@ -Result after running test_fcl_gjk in Release mode. +Result after running gjk in Release mode. nCol = 2840 nDiff = 0 diff --git a/test/test_fcl_box_box_distance.cpp b/test/box_box_distance.cpp similarity index 99% rename from test/test_fcl_box_box_distance.cpp rename to test/box_box_distance.cpp index 0613a2edf7ce26abf7f5ebbeb788bf1740e2fa59..90d090e30f2c0853ef2bc0449536cf039a3d87ba 100644 --- a/test/test_fcl_box_box_distance.cpp +++ b/test/box_box_distance.cpp @@ -42,13 +42,14 @@ #define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps)) #include <cmath> +#include <iostream> #include <hpp/fcl/distance.h> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/collision.h> #include <hpp/fcl/collision_object.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "test_fcl_utility.h" +#include "utility.h" typedef boost::shared_ptr <hpp::fcl::CollisionGeometry> CollisionGeometryPtr_t; diff --git a/test/test_fcl_broadphase.cpp b/test/broadphase.cpp similarity index 99% rename from test/test_fcl_broadphase.cpp rename to test/broadphase.cpp index 320b3f2a0ff341309386a314bd83ce21ba0d1e7b..a7a1676f327350421f984225444e925f1e1924c5 100644 --- a/test/test_fcl_broadphase.cpp +++ b/test/broadphase.cpp @@ -45,7 +45,7 @@ #include <hpp/fcl/broadphase/broadphase.h> #include <hpp/fcl/shape/geometric_shape_to_BVH_model.h> #include <hpp/fcl/math/transform.h> -#include "test_fcl_utility.h" +#include "utility.h" #if USE_GOOGLEHASH #include <sparsehash/sparse_hash_map> diff --git a/test/test_fcl_bvh_models.cpp b/test/bvh_models.cpp similarity index 86% rename from test/test_fcl_bvh_models.cpp rename to test/bvh_models.cpp index 82c012862ae731b8eae75edbf01b9752f13d074a..4e8990cac95b2391b5f6d85b30d9aa1792d7140a 100644 --- a/test/test_fcl_bvh_models.cpp +++ b/test/bvh_models.cpp @@ -44,13 +44,13 @@ #include "fcl_resources/config.h" #include <hpp/fcl/collision.h> -#include "hpp/fcl/BVH/BVH_model.h" -#include "hpp/fcl/BVH/BVH_utility.h" -#include "hpp/fcl/math/transform.h" -#include "hpp/fcl/shape/geometric_shapes.h" +#include <hpp/fcl/BVH/BVH_model.h> +#include <hpp/fcl/BVH/BVH_utility.h> +#include <hpp/fcl/math/transform.h> +#include <hpp/fcl/shape/geometric_shapes.h> #include <hpp/fcl/mesh_loader/assimp.h> #include <hpp/fcl/mesh_loader/loader.h> -#include "test_fcl_utility.h" +#include "utility.h" #include <iostream> using namespace hpp::fcl; @@ -72,18 +72,18 @@ void testBVHModelPointCloud() } Box box; - double a = box.side[0]; - double b = box.side[1]; - double c = box.side[2]; + double a = box.halfSide[0]; + double b = box.halfSide[1]; + double c = box.halfSide[2]; std::vector<Vec3f> points(8); - points[0] << 0.5 * a, -0.5 * b, 0.5 * c; - points[1] << 0.5 * a, 0.5 * b, 0.5 * c; - points[2] << -0.5 * a, 0.5 * b, 0.5 * c; - points[3] << -0.5 * a, -0.5 * b, 0.5 * c; - points[4] << 0.5 * a, -0.5 * b, -0.5 * c; - points[5] << 0.5 * a, 0.5 * b, -0.5 * c; - points[6] << -0.5 * a, 0.5 * b, -0.5 * c; - points[7] << -0.5 * a, -0.5 * b, -0.5 * c; + points[0] << a, -b, c; + points[1] << a, b, c; + points[2] << -a, b, c; + points[3] << -a, -b, c; + points[4] << a, -b, -c; + points[5] << a, b, -c; + points[6] << -a, b, -c; + points[7] << -a, -b, -c; int result; @@ -113,19 +113,19 @@ void testBVHModelTriangles() Box box(1,1,1); AABB aabb (Vec3f(-1,0,-1), Vec3f(1,1,1)); - double a = box.side[0]; - double b = box.side[1]; - double c = box.side[2]; + double a = box.halfSide[0]; + double b = box.halfSide[1]; + double c = box.halfSide[2]; std::vector<Vec3f> points(8); std::vector<Triangle> tri_indices(12); - points[0] << 0.5 * a, -0.5 * b, 0.5 * c; - points[1] << 0.5 * a, 0.5 * b, 0.5 * c; - points[2] << -0.5 * a, 0.5 * b, 0.5 * c; - points[3] << -0.5 * a, -0.5 * b, 0.5 * c; - points[4] << 0.5 * a, -0.5 * b, -0.5 * c; - points[5] << 0.5 * a, 0.5 * b, -0.5 * c; - points[6] << -0.5 * a, 0.5 * b, -0.5 * c; - points[7] << -0.5 * a, -0.5 * b, -0.5 * c; + points[0] << a, -b, c; + points[1] << a, b, c; + points[2] << -a, b, c; + points[3] << -a, -b, c; + points[4] << a, -b, -c; + points[5] << a, b, -c; + points[6] << -a, b, -c; + points[7] << -a, -b, -c; tri_indices[0].set(0, 4, 1); tri_indices[1].set(1, 4, 5); @@ -202,19 +202,19 @@ void testBVHModelSubModel() boost::shared_ptr<BVHModel<BV> > model(new BVHModel<BV>); Box box; - double a = box.side[0]; - double b = box.side[1]; - double c = box.side[2]; + double a = box.halfSide[0]; + double b = box.halfSide[1]; + double c = box.halfSide[2]; std::vector<Vec3f> points(8); std::vector<Triangle> tri_indices(12); - points[0] << 0.5 * a, -0.5 * b, 0.5 * c; - points[1] << 0.5 * a, 0.5 * b, 0.5 * c; - points[2] << -0.5 * a, 0.5 * b, 0.5 * c; - points[3] << -0.5 * a, -0.5 * b, 0.5 * c; - points[4] << 0.5 * a, -0.5 * b, -0.5 * c; - points[5] << 0.5 * a, 0.5 * b, -0.5 * c; - points[6] << -0.5 * a, 0.5 * b, -0.5 * c; - points[7] << -0.5 * a, -0.5 * b, -0.5 * c; + points[0] << a, -b, c; + points[1] << a, b, c; + points[2] << -a, b, c; + points[3] << -a, -b, c; + points[4] << a, -b, -c; + points[5] << a, b, -c; + points[6] << -a, b, -c; + points[7] << -a, -b, -c; tri_indices[0].set(0, 4, 1); tri_indices[1].set(1, 4, 5); diff --git a/test/test_fcl_capsule_box_1.cpp b/test/capsule_box_1.cpp similarity index 98% rename from test/test_fcl_capsule_box_1.cpp rename to test/capsule_box_1.cpp index 8987672a545c2678c6e8c76d6b31081fd31a06e3..9f034b4f62f39edbf70a521e7b3ad77131f272f1 100644 --- a/test/test_fcl_capsule_box_1.cpp +++ b/test/capsule_box_1.cpp @@ -49,7 +49,7 @@ #include <hpp/fcl/collision_object.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "test_fcl_utility.h" +#include "utility.h" BOOST_AUTO_TEST_CASE(distance_capsule_box) { @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(distance_capsule_box) BOOST_CHECK_CLOSE (o1 [0], 1.0, 1e-1); CHECK_CLOSE_TO_0 (o1 [1], 1e-1); BOOST_CHECK_CLOSE (o2 [0], 0.5, 1e-1); - CHECK_CLOSE_TO_0 (o1 [1], 1e-1); + CHECK_CLOSE_TO_0 (o2 [1], 1e-1); // Move capsule above box tf1 = hpp::fcl::Transform3f (hpp::fcl::Vec3f (0., 0., 8.)); diff --git a/test/test_fcl_capsule_box_2.cpp b/test/capsule_box_2.cpp similarity index 99% rename from test/test_fcl_capsule_box_2.cpp rename to test/capsule_box_2.cpp index f87b6f60b35bf91522ca6191fe8a7290310b04e8..8a20117ab404ec0d648811b71ef71231968e1ad7 100644 --- a/test/test_fcl_capsule_box_2.cpp +++ b/test/capsule_box_2.cpp @@ -42,7 +42,7 @@ #define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps)) -#include "test_fcl_utility.h" +#include "utility.h" #include <cmath> #include <hpp/fcl/distance.h> diff --git a/test/test_fcl_capsule_capsule.cpp b/test/capsule_capsule.cpp similarity index 99% rename from test/test_fcl_capsule_capsule.cpp rename to test/capsule_capsule.cpp index 9d13e9b0793d5926a31b15d68c5fe23bf1889e00..7dda5376b31576e3fefee5dadbe8c2232d810841 100644 --- a/test/test_fcl_capsule_capsule.cpp +++ b/test/capsule_capsule.cpp @@ -43,13 +43,14 @@ #define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps)) #include <cmath> +#include <iostream> #include <hpp/fcl/distance.h> #include <hpp/fcl/math/transform.h> #include <hpp/fcl/collision.h> #include <hpp/fcl/collision_object.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "test_fcl_utility.h" +#include "utility.h" using namespace hpp::fcl; typedef boost::shared_ptr <CollisionGeometry> CollisionGeometryPtr_t; diff --git a/test/collision.cpp b/test/collision.cpp new file mode 100644 index 0000000000000000000000000000000000000000..655ab7908303ae489f7466125aeb2c0e9239c716 --- /dev/null +++ b/test/collision.cpp @@ -0,0 +1,644 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2011-2014, Willow Garage, Inc. + * Copyright (c) 2014-2015, Open Source Robotics Foundation + * 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 Open Source Robotics Foundation 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 Joseph Mirabel */ + +#define BOOST_CHRONO_VERSION 2 +#include <boost/chrono/chrono.hpp> +#include <boost/chrono/chrono_io.hpp> + +#define BOOST_TEST_MODULE FCL_COLLISION +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/utility/binary.hpp> + +#include <fstream> +#include <boost/filesystem.hpp> +#include <boost/assign/list_of.hpp> + +#include <hpp/fcl/collision.h> +#include <hpp/fcl/BV/BV.h> +#include <hpp/fcl/shape/geometric_shapes.h> +#include <hpp/fcl/narrowphase/narrowphase.h> +#include <hpp/fcl/mesh_loader/assimp.h> + +#include <hpp/fcl/internal/traversal_node_bvhs.h> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include "../src/collision_node.h" +#include <hpp/fcl/internal/BV_splitter.h> + +#include "utility.h" +#include "fcl_resources/config.h" + +using namespace hpp::fcl; + +int num_max_contacts = std::numeric_limits<int>::max(); + +BOOST_AUTO_TEST_CASE(OBB_Box_test) +{ + FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; + std::vector<Transform3f> rotate_transform; + generateRandomTransforms(r_extents, rotate_transform, 1); + + AABB aabb1; + aabb1.min_ = Vec3f(-600, -600, -600); + aabb1.max_ = Vec3f(600, 600, 600); + + OBB obb1; + convertBV(aabb1, rotate_transform[0], obb1); + Box box1; + Transform3f box1_tf; + constructBox(aabb1, rotate_transform[0], box1, box1_tf); + + FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; + std::size_t n = 1000; + + std::vector<Transform3f> transforms; + generateRandomTransforms(extents, transforms, n); + + for(std::size_t i = 0; i < transforms.size(); ++i) + { + AABB aabb; + aabb.min_ = aabb1.min_ * 0.5; + aabb.max_ = aabb1.max_ * 0.5; + + OBB obb2; + convertBV(aabb, transforms[i], obb2); + + Box box2; + Transform3f box2_tf; + constructBox(aabb, transforms[i], box2, box2_tf); + + GJKSolver solver; + + bool overlap_obb = obb1.overlap(obb2); + bool overlap_box = solver.shapeIntersect(box1, box1_tf, box2, box2_tf, NULL, NULL, NULL); + + BOOST_CHECK(overlap_obb == overlap_box); + } +} + +BOOST_AUTO_TEST_CASE(OBB_shape_test) +{ + FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; + std::vector<Transform3f> rotate_transform; + generateRandomTransforms(r_extents, rotate_transform, 1); + + AABB aabb1; + aabb1.min_ = Vec3f(-600, -600, -600); + aabb1.max_ = Vec3f(600, 600, 600); + + OBB obb1; + convertBV(aabb1, rotate_transform[0], obb1); + Box box1; + Transform3f box1_tf; + constructBox(aabb1, rotate_transform[0], box1, box1_tf); + + FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; + std::size_t n = 1000; + + std::vector<Transform3f> transforms; + generateRandomTransforms(extents, transforms, n); + + for(std::size_t i = 0; i < transforms.size(); ++i) + { + FCL_REAL len = (aabb1.max_[0] - aabb1.min_[0]) * 0.5; + OBB obb2; + GJKSolver solver; + + { + Sphere sphere(len); + computeBV(sphere, transforms[i], obb2); + + bool overlap_obb = obb1.overlap(obb2); + bool overlap_sphere = solver.shapeIntersect(box1, box1_tf, sphere, transforms[i], NULL, NULL, NULL); + BOOST_CHECK(overlap_obb >= overlap_sphere); + } + + { + Capsule capsule(len, 2 * len); + computeBV(capsule, transforms[i], obb2); + + bool overlap_obb = obb1.overlap(obb2); + bool overlap_capsule = solver.shapeIntersect(box1, box1_tf, capsule, transforms[i], NULL, NULL, NULL); + BOOST_CHECK(overlap_obb >= overlap_capsule); + } + + { + Cone cone(len, 2 * len); + computeBV(cone, transforms[i], obb2); + + bool overlap_obb = obb1.overlap(obb2); + bool overlap_cone = solver.shapeIntersect(box1, box1_tf, cone, transforms[i], NULL, NULL, NULL); + BOOST_CHECK(overlap_obb >= overlap_cone); + } + + { + Cylinder cylinder(len, 2 * len); + computeBV(cylinder, transforms[i], obb2); + + bool overlap_obb = obb1.overlap(obb2); + bool overlap_cylinder = solver.shapeIntersect(box1, box1_tf, cylinder, transforms[i], NULL, NULL, NULL); + BOOST_CHECK(overlap_obb >= overlap_cylinder); + } + } +} + +BOOST_AUTO_TEST_CASE(OBB_AABB_test) +{ + FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; + std::size_t n = 1000; + + std::vector<Transform3f> transforms; + generateRandomTransforms(extents, transforms, n); + + AABB aabb1; + aabb1.min_ = Vec3f(-600, -600, -600); + aabb1.max_ = Vec3f(600, 600, 600); + + OBB obb1; + convertBV(aabb1, Transform3f(), obb1); + + for(std::size_t i = 0; i < transforms.size(); ++i) + { + AABB aabb; + aabb.min_ = aabb1.min_ * 0.5; + aabb.max_ = aabb1.max_ * 0.5; + + AABB aabb2 = translate(aabb, transforms[i].getTranslation()); + + OBB obb2; + convertBV(aabb, Transform3f(transforms[i].getTranslation()), obb2); + + bool overlap_aabb = aabb1.overlap(aabb2); + bool overlap_obb = obb1.overlap(obb2); + if(overlap_aabb != overlap_obb) + { + std::cout << aabb1.min_ << " " << aabb1.max_ << std::endl; + std::cout << aabb2.min_ << " " << aabb2.max_ << std::endl; + std::cout << obb1.To << " " << obb1.extent << " " << obb1.axes << std::endl; + std::cout << obb2.To << " " << obb2.extent << " " << obb2.axes << std::endl; + } + + BOOST_CHECK(overlap_aabb == overlap_obb); + } + std::cout << std::endl; +} + +std::ostream* bench_stream = NULL; +bool bs_nl = true; +bool bs_hp = false; +#define BENCHMARK(stream) if (bench_stream!=NULL) { *bench_stream << (bs_nl ? "" : ", ") << stream; bs_nl = false; } +#define BENCHMARK_HEADER(stream) if (!bs_hp) { BENCHMARK(stream) } +#define BENCHMARK_NEXT() if (bench_stream!=NULL && !bs_nl) { *bench_stream << '\n'; bs_nl = true; bs_hp = true; } + +typedef std::vector<Contact> Contacts_t; +typedef boost::mpl::vector<OBB, RSS, KDOP<24>, KDOP<18>, KDOP<16>, kIOS, OBBRSS> BVs_t; +std::vector<SplitMethodType> splitMethods = boost::assign::list_of (SPLIT_METHOD_MEAN)(SPLIT_METHOD_MEDIAN)(SPLIT_METHOD_BV_CENTER); + +typedef boost::chrono::high_resolution_clock clock_type; +typedef clock_type::duration duration_type; + +#define BV_STR_SPECIALIZATION(bv) \ + template <> const char* str< bv > () { return #bv; } +template <typename BV> const char* str(); +BV_STR_SPECIALIZATION(AABB) +BV_STR_SPECIALIZATION(OBB) +BV_STR_SPECIALIZATION(RSS) +BV_STR_SPECIALIZATION(KDOP<24>) +BV_STR_SPECIALIZATION(KDOP<18>) +BV_STR_SPECIALIZATION(KDOP<16>) +BV_STR_SPECIALIZATION(kIOS) +BV_STR_SPECIALIZATION(OBBRSS) + +template <typename T> struct wrap {}; + +struct base_traits +{ + enum { IS_IMPLEMENTED = true + }; +}; + +enum { + Oriented = true, + NonOriented = false, + Recursive = true, + NonRecursive = false +}; + +template<typename BV, bool Oriented, bool recursive> +struct traits : base_traits +{}; + +template<size_t N, bool recursive> +struct traits<KDOP<N>, Oriented, recursive> : base_traits +{ + enum { IS_IMPLEMENTED = false + }; +}; + +struct mesh_mesh_run_test +{ + mesh_mesh_run_test (const std::vector<Transform3f>& _transforms, + const CollisionRequest _request + ) : + transforms (_transforms), + request (_request), + enable_statistics (false), + benchmark (false), + isInit (false), + indent (0) + {} + + const std::vector<Transform3f>& transforms; + const CollisionRequest request; + bool enable_statistics, benchmark; + std::vector<Contacts_t> contacts; + std::vector<Contacts_t> contacts_ref; + bool isInit; + + int indent; + + const char* getindent() + { + assert (indent < 9); + static const char* t[] = { "", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t", + "\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t" }; + return t[indent]; + } + + template<typename BV> + void query ( + const std::vector<Transform3f>& transforms, + SplitMethodType splitMethod, + const CollisionRequest request, + std::vector<Contacts_t>& contacts + ) + { + BENCHMARK_HEADER("BV"); + BENCHMARK_HEADER("oriented"); + BENCHMARK_HEADER("Split method"); + if (enable_statistics) { + BENCHMARK_HEADER("num_bv_tests"); + BENCHMARK_HEADER("num_leaf_tests"); + } + BENCHMARK_HEADER("numContacts"); + BENCHMARK_HEADER("distance_lower_bound"); + BENCHMARK_HEADER("time"); + BENCHMARK_NEXT(); + + typedef BVHModel<BV> BVH_t; + typedef boost::shared_ptr<BVH_t> BVHPtr_t; + + BVHPtr_t model1 (new BVH_t), model2 (new BVH_t); + model1->bv_splitter.reset(new BVSplitter<BV>(splitMethod)); + model2->bv_splitter.reset(new BVSplitter<BV>(splitMethod)); + + loadPolyhedronFromResource (TEST_RESOURCES_DIR "/env.obj", Vec3f::Ones(), model1); + loadPolyhedronFromResource (TEST_RESOURCES_DIR "/rob.obj", Vec3f::Ones(), model2); + + clock_type::time_point start, end; + const Transform3f tf2; + const std::size_t N = transforms.size(); + + contacts.resize (3*N); + + if (traits<BV, Oriented, Recursive>::IS_IMPLEMENTED) + { + BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented"); + ++indent; + + for(std::size_t i = 0; i < transforms.size(); ++i) + { + start = clock_type::now(); + const Transform3f& tf1 = transforms[i]; + + CollisionResult local_result; + MeshCollisionTraversalNode<BV, 0> node (request); + node.enable_statistics = enable_statistics; + + bool success = initialize (node, + *model1, tf1, *model2, tf2, + local_result); + BOOST_REQUIRE (success); + + collide(&node, request, local_result); + + end = clock_type::now(); + + BENCHMARK(str<BV>()); + BENCHMARK(1); + BENCHMARK(splitMethod); + if (enable_statistics) { + BOOST_TEST_MESSAGE (getindent() << "statistics: " << node.num_bv_tests << " " << node.num_leaf_tests); + BOOST_TEST_MESSAGE (getindent() << "nb contacts: " << local_result.numContacts()); + BENCHMARK(node.num_bv_tests); + BENCHMARK(node.num_leaf_tests); + } + BENCHMARK(local_result.numContacts()); + BENCHMARK(local_result.distance_lower_bound); + BENCHMARK((end - start).count()); + BENCHMARK_NEXT(); + + if(local_result.numContacts() > 0) + { + local_result.getContacts(contacts[i]); + std::sort(contacts[i].begin(), contacts[i].end()); + } + } + --indent; + } + + if (traits<BV, NonOriented, Recursive>::IS_IMPLEMENTED) + { + BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>()); + ++indent; + + for(std::size_t i = 0; i < transforms.size(); ++i) + { + start = clock_type::now(); + const Transform3f tf1 = transforms[i]; + + CollisionResult local_result; + MeshCollisionTraversalNode<BV, RelativeTransformationIsIdentity> node (request); + node.enable_statistics = enable_statistics; + + BVH_t* model1_tmp = new BVH_t(*model1); + Transform3f tf1_tmp = tf1; + BVH_t* model2_tmp = new BVH_t(*model2); + Transform3f tf2_tmp = tf2; + + bool success = initialize (node, + *model1_tmp, tf1_tmp, *model2_tmp, tf2_tmp, + local_result, true, true); + BOOST_REQUIRE (success); + + collide(&node, request, local_result); + delete model1_tmp; + delete model2_tmp; + + end = clock_type::now(); + BENCHMARK(str<BV>()); + BENCHMARK(2); + BENCHMARK(splitMethod); + if (enable_statistics) { + BOOST_TEST_MESSAGE (getindent() << "statistics: " << node.num_bv_tests << " " << node.num_leaf_tests); + BOOST_TEST_MESSAGE (getindent() << "nb contacts: " << local_result.numContacts()); + BENCHMARK(node.num_bv_tests); + BENCHMARK(node.num_leaf_tests); + } + BENCHMARK(local_result.numContacts()); + BENCHMARK(local_result.distance_lower_bound); + BENCHMARK((end - start).count()); + BENCHMARK_NEXT(); + + if(local_result.numContacts() > 0) + { + local_result.getContacts(contacts[i+N]); + std::sort(contacts[i+N].begin(), contacts[i+N].end()); + } + } + --indent; + } + + if (traits<BV, Oriented, NonRecursive>::IS_IMPLEMENTED) + { + BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented non-recursive"); + ++indent; + + for(std::size_t i = 0; i < transforms.size(); ++i) + { + start = clock_type::now(); + const Transform3f tf1 = transforms[i]; + + CollisionResult local_result; + MeshCollisionTraversalNode<BV, 0> node (request); + node.enable_statistics = enable_statistics; + + bool success = initialize (node, + *model1, tf1, *model2, tf2, + local_result); + BOOST_REQUIRE (success); + + collide(&node, request, local_result, NULL, false); + + end = clock_type::now(); + BENCHMARK(str<BV>()); + BENCHMARK(0); + BENCHMARK(splitMethod); + if (enable_statistics) { + BOOST_TEST_MESSAGE (getindent() << "statistics: " << node.num_bv_tests << " " << node.num_leaf_tests); + BOOST_TEST_MESSAGE (getindent() << "nb contacts: " << local_result.numContacts()); + BENCHMARK(node.num_bv_tests); + BENCHMARK(node.num_leaf_tests); + } + BENCHMARK(local_result.numContacts()); + BENCHMARK(local_result.distance_lower_bound); + BENCHMARK((end - start).count()); + BENCHMARK_NEXT(); + + if(local_result.numContacts() > 0) + { + local_result.getContacts(contacts[i+2*N]); + std::sort(contacts[i+2*N].begin(), contacts[i+2*N].end()); + } + } + --indent; + } + } + + void check_contacts (std::size_t i0, std::size_t i1, bool warn) + { + for(std::size_t i = i0; i < i1; ++i) { + Contacts_t in_ref_but_not_in_i; + std::set_difference ( + contacts_ref[i].begin(), contacts_ref[i].end(), + contacts [i].begin(), contacts [i].end(), + std::inserter(in_ref_but_not_in_i, in_ref_but_not_in_i.begin())); + if(!in_ref_but_not_in_i.empty()) { + for(std::size_t j = 0; j < in_ref_but_not_in_i.size(); ++j) { + if (warn) { + BOOST_WARN_MESSAGE (false, "Missed contacts: " + << in_ref_but_not_in_i[j].b1 << ", " + << in_ref_but_not_in_i[j].b2); + } else { + BOOST_CHECK_MESSAGE(false, "Missed contacts: " + << in_ref_but_not_in_i[j].b1 << ", " + << in_ref_but_not_in_i[j].b2); + } + } + } + + Contacts_t in_i_but_not_in_ref; + std::set_difference ( + contacts [i].begin(), contacts [i].end(), + contacts_ref[i].begin(), contacts_ref[i].end(), + std::inserter(in_i_but_not_in_ref, in_i_but_not_in_ref.begin())); + + if(!in_i_but_not_in_ref.empty()) { + for(std::size_t j = 0; j < in_i_but_not_in_ref.size(); ++j) { + if (warn) { + BOOST_WARN_MESSAGE (false, "False contacts: " + << in_i_but_not_in_ref[j].b1 << ", " + << in_i_but_not_in_ref[j].b2); + } else { + BOOST_CHECK_MESSAGE(false, "False contacts: " + << in_i_but_not_in_ref[j].b1 << ", " + << in_i_but_not_in_ref[j].b2); + } + } + } + } + } + + template<typename BV> + void check () + { + if (benchmark) return; + const std::size_t N = transforms.size(); + + BOOST_REQUIRE_EQUAL(contacts.size(), 3*N); + BOOST_REQUIRE_EQUAL(contacts.size(), contacts_ref.size()); + + if (traits<BV, Oriented, Recursive>::IS_IMPLEMENTED) { + BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented"); + ++indent; + check_contacts (0, N, false); + --indent; + } + if (traits<BV, NonOriented, Recursive>::IS_IMPLEMENTED) { + BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>()); + ++indent; + check_contacts (N, 2*N, true); + --indent; + } + if (traits<BV, Oriented, NonRecursive>::IS_IMPLEMENTED) { + BOOST_TEST_MESSAGE (getindent() << "BV: " << str<BV>() << " oriented non-recursive"); + ++indent; + check_contacts (2*N, 3*N, false); + --indent; + } + } + + template<typename BV> + void operator() (wrap<BV>) + { + for (std::size_t i = 0; i < splitMethods.size(); ++i) + { + BOOST_TEST_MESSAGE (getindent() << "splitMethod: " << splitMethods[i]); + ++indent; + query <BV> (transforms, splitMethods[i], request, (isInit ? contacts : contacts_ref)); + if (isInit) check<BV> (); + isInit = true; + --indent; + } + } +}; + +// This test +// 1. load two objects "env.obj" and "rob.obj" from directory +// fcl_resources, +// 2. generates n random transformation and for each of them denote tf, +// 2.1 performs a collision test where object 1 is in pose tf. All +// the contacts are stored in vector global_pairs. +// 2.2 performs a series of collision tests with the same object and +// the same poses using various methods and various types of bounding +// volumes. Each time the contacts are stored in vector global_pairs_now. +// +// The methods used to test collision are +// - collide_Test that calls function collide with tf for object1 pose and +// identity for the second object pose, +// - collide_Test2 that moves all vertices of object1 in pose tf and that +// calls function collide with identity for both object poses, +// +BOOST_AUTO_TEST_CASE(mesh_mesh) +{ + std::vector<Transform3f> transforms; + FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000}; + std::size_t n = 10; + + generateRandomTransforms(extents, transforms, n); + + Eigen::IOFormat f (Eigen::FullPrecision, 0, ", ", ",", "", "", "(", ")"); + for(std::size_t i = 0; i < transforms.size(); ++i) + { + BOOST_TEST_MESSAGE("q" << i << "=" + << transforms [i].getTranslation () .format (f) << "+" + << transforms [i].getQuatRotation ().coeffs ().format (f)); + } + + // Request all contacts and check that all methods give the same result. + mesh_mesh_run_test runner (transforms, CollisionRequest (CONTACT, num_max_contacts)); + runner.enable_statistics = true; + boost::mpl::for_each<BVs_t, wrap<boost::mpl::placeholders::_1> > (runner); +} + +BOOST_AUTO_TEST_CASE(mesh_mesh_benchmark) +{ + std::vector<Transform3f> transforms; + FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000}; + std::size_t n = 10; + + generateRandomTransforms(extents, transforms, n); + + Eigen::IOFormat f (Eigen::FullPrecision, 0, ", ", ",", "", "", "(", ")"); + for(std::size_t i = 0; i < transforms.size(); ++i) + { + BOOST_TEST_MESSAGE("q" << i << "=" + << transforms [i].getTranslation () .format (f) << "+" + << transforms [i].getQuatRotation ().coeffs ().format (f)); + } + + // Request all contacts and check that all methods give the same result. + typedef boost::mpl::vector<OBB, RSS, AABB, KDOP<24>, KDOP<18>, KDOP<16>, kIOS, OBBRSS> BVs_t; + + std::ofstream ofs ("./collision.benchmark.csv", std::ofstream::out); + bench_stream = &ofs; + + // without lower bound. + mesh_mesh_run_test runner1 (transforms, CollisionRequest ()); + runner1.enable_statistics = false; + runner1.benchmark = true; + boost::mpl::for_each<BVs_t, wrap<boost::mpl::placeholders::_1> > (runner1); + + // with lower bound. + mesh_mesh_run_test runner2 (transforms, CollisionRequest (DISTANCE_LOWER_BOUND, 1)); + runner2.enable_statistics = false; + runner2.benchmark = true; + boost::mpl::for_each<BVs_t, wrap<boost::mpl::placeholders::_1> > (runner2); + + bench_stream = NULL; + ofs.close(); +} diff --git a/test/convex.cpp b/test/convex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a81b1734ebd89ca6379ea0cc052ab5d321467d9f --- /dev/null +++ b/test/convex.cpp @@ -0,0 +1,240 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2019, LAAS-CNRS + * 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 Open Source Robotics Foundation 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 Joseph Mirabel */ + + +#define BOOST_TEST_MODULE FCL_GEOMETRIC_SHAPES +#define BOOST_TEST_DYN_LINK +#include <boost/test/unit_test.hpp> +#include <boost/utility/binary.hpp> + +#include <hpp/fcl/shape/convex.h> +#include <hpp/fcl/collision.h> +#include <hpp/fcl/distance.h> + +#include "utility.h" + +using namespace hpp::fcl; + +struct Quadrilateral +{ +public: + typedef std::size_t index_type; + typedef int size_type; + + Quadrilateral() {} + + Quadrilateral(index_type p0, index_type p1, index_type p2, index_type p3) + { + set(p0, p1, p2, p3); + } + + /// @brief Set the vertex indices of the triangle + inline void set(index_type p0, index_type p1, index_type p2, index_type p3) + { + vids[0] = p0; vids[1] = p1; vids[2] = p2; vids[3] = p3; + } + + /// @access the triangle index + inline index_type operator[](int i) const { return vids[i]; } + + inline index_type& operator[](int i) { return vids[i]; } + + static inline size_type size() { return 4; } + +private: + index_type vids[4]; +}; + +Convex<Quadrilateral> buildBox (FCL_REAL l, FCL_REAL w, FCL_REAL d) +{ + Vec3f* pts = new Vec3f[8]; + pts[0] = Vec3f( l, w, d); + pts[1] = Vec3f( l, w,-d); + pts[2] = Vec3f( l,-w, d); + pts[3] = Vec3f( l,-w,-d); + pts[4] = Vec3f(-l, w, d); + pts[5] = Vec3f(-l, w,-d); + pts[6] = Vec3f(-l,-w, d); + pts[7] = Vec3f(-l,-w,-d); + + Quadrilateral* polygons = new Quadrilateral[6]; + polygons[0].set(0, 2, 3, 1); // x+ side + polygons[1].set(2, 6, 7, 3); // y- side + polygons[2].set(4, 5, 7, 6); // x- side + polygons[3].set(0, 1, 5, 4); // y+ side + polygons[4].set(1, 3, 7, 5); // z- side + polygons[5].set(0, 2, 6, 4); // z+ side + + return Convex<Quadrilateral> (true, + pts, // points + 8, // num points + polygons, + 6 // number of polygons + ); +} + +BOOST_AUTO_TEST_CASE(convex) +{ + FCL_REAL l = 1, w = 1, d = 1; + Convex<Quadrilateral> box (buildBox (l, w, d)); + + // Check neighbors + for (int i = 0; i < 8; ++i) { + BOOST_CHECK_EQUAL(box.neighbors[i].count(), 3); + } + BOOST_CHECK_EQUAL(box.neighbors[0][0], 1); + BOOST_CHECK_EQUAL(box.neighbors[0][1], 2); + BOOST_CHECK_EQUAL(box.neighbors[0][2], 4); + + BOOST_CHECK_EQUAL(box.neighbors[1][0], 0); + BOOST_CHECK_EQUAL(box.neighbors[1][1], 3); + BOOST_CHECK_EQUAL(box.neighbors[1][2], 5); + + BOOST_CHECK_EQUAL(box.neighbors[2][0], 0); + BOOST_CHECK_EQUAL(box.neighbors[2][1], 3); + BOOST_CHECK_EQUAL(box.neighbors[2][2], 6); + + BOOST_CHECK_EQUAL(box.neighbors[3][0], 1); + BOOST_CHECK_EQUAL(box.neighbors[3][1], 2); + BOOST_CHECK_EQUAL(box.neighbors[3][2], 7); + + BOOST_CHECK_EQUAL(box.neighbors[4][0], 0); + BOOST_CHECK_EQUAL(box.neighbors[4][1], 5); + BOOST_CHECK_EQUAL(box.neighbors[4][2], 6); + + BOOST_CHECK_EQUAL(box.neighbors[5][0], 1); + BOOST_CHECK_EQUAL(box.neighbors[5][1], 4); + BOOST_CHECK_EQUAL(box.neighbors[5][2], 7); + + BOOST_CHECK_EQUAL(box.neighbors[6][0], 2); + BOOST_CHECK_EQUAL(box.neighbors[6][1], 4); + BOOST_CHECK_EQUAL(box.neighbors[6][2], 7); + + BOOST_CHECK_EQUAL(box.neighbors[7][0], 3); + BOOST_CHECK_EQUAL(box.neighbors[7][1], 5); + BOOST_CHECK_EQUAL(box.neighbors[7][2], 6); +} + +template <typename Sa, typename Sb> void compareShapeIntersection ( + const Sa& sa, const Sb& sb, + const Transform3f& tf1, const Transform3f& tf2, + FCL_REAL tol = 1e-9) +{ + CollisionRequest request (CONTACT | DISTANCE_LOWER_BOUND, 1); + CollisionResult resA, resB; + + collide(&sa, tf1, &sa, tf2, request, resA); + collide(&sb, tf1, &sb, tf2, request, resB); + + BOOST_CHECK_EQUAL(resA.isCollision(), resB.isCollision()); + BOOST_CHECK_EQUAL(resA.numContacts(), resB.numContacts()); + + if (resA.isCollision() && resB.isCollision()) { + Contact cA = resA.getContact(0), + cB = resB.getContact(0); + + BOOST_TEST_MESSAGE( + tf1 << '\n' + << cA.pos.format(pyfmt) << '\n' + << '\n' + << tf2 << '\n' + << cB.pos.format(pyfmt) << '\n' + ); + // Only warnings because there are still some bugs. + BOOST_WARN_SMALL((cA.pos - cB.pos ).squaredNorm(), tol); + BOOST_WARN_SMALL((cA.normal - cB.normal).squaredNorm(), tol); + } else { + BOOST_CHECK_CLOSE(resA.distance_lower_bound, resB.distance_lower_bound, tol); // distances should be same + } +} + +template <typename Sa, typename Sb> void compareShapeDistance ( + const Sa& sa, const Sb& sb, + const Transform3f& tf1, const Transform3f& tf2, + FCL_REAL tol = 1e-9) +{ + DistanceRequest request (true); + DistanceResult resA, resB; + + distance(&sa, tf1, &sa, tf2, request, resA); + distance(&sb, tf1, &sb, tf2, request, resB); + + BOOST_TEST_MESSAGE( + tf1 << '\n' + << resA.normal.format(pyfmt) << '\n' + << resA.nearest_points[0].format(pyfmt) << '\n' + << resA.nearest_points[1].format(pyfmt) << '\n' + << '\n' + << tf2 << '\n' + << resB.normal.format(pyfmt) << '\n' + << resB.nearest_points[0].format(pyfmt) << '\n' + << resB.nearest_points[1].format(pyfmt) << '\n' + ); + // TODO in one case, there is a mismatch between the distances and I cannot say + // which one is correct. To visualize the case, use script test/geometric_shapes.py + BOOST_WARN_CLOSE(resA.min_distance, resB.min_distance, tol); + //BOOST_CHECK_CLOSE(resA.min_distance, resB.min_distance, tol); + + // Only warnings because there are still some bugs. + BOOST_WARN_SMALL((resA.normal - resA.normal).squaredNorm(), tol); + BOOST_WARN_SMALL((resA.nearest_points[0] - resB.nearest_points[0]).squaredNorm(), tol); + BOOST_WARN_SMALL((resA.nearest_points[1] - resB.nearest_points[1]).squaredNorm(), tol); +} + +BOOST_AUTO_TEST_CASE(compare_convex_box) +{ + FCL_REAL extents [6] = {0, 0, 0, 10, 10, 10}; + FCL_REAL l = 1, w = 1, d = 1; + Box box(l*2, w*2, d*2); + Convex<Quadrilateral> convex_box (buildBox (l, w, d)); + + Transform3f tf1; + Transform3f tf2; + + tf2.setTranslation (Vec3f (3, 0, 0)); + compareShapeIntersection(box, convex_box, tf1, tf2); + compareShapeDistance (box, convex_box, tf1, tf2); + + tf2.setTranslation (Vec3f (0, 0, 0)); + compareShapeIntersection(box, convex_box, tf1, tf2); + compareShapeDistance (box, convex_box, tf1, tf2); + + for (int i = 0; i < 1000; ++i) { + generateRandomTransform(extents, tf2); + compareShapeIntersection(box, convex_box, tf1, tf2); + compareShapeDistance (box, convex_box, tf1, tf2); + } +} diff --git a/test/test_fcl_distance.cpp b/test/distance.cpp similarity index 98% rename from test/test_fcl_distance.cpp rename to test/distance.cpp index 35eb58408d061fbafbed6f6f8ff60ad9ffebfae8..dc4c2489aa433d1591e7dda3b04b742b7f091c18 100644 --- a/test/test_fcl_distance.cpp +++ b/test/distance.cpp @@ -39,15 +39,17 @@ #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> #include <boost/utility/binary.hpp> - -#include <hpp/fcl/traversal/traversal_node_bvhs.h> -#include <hpp/fcl/traversal/traversal_node_setup.h> -#include <hpp/fcl/collision_node.h> -#include "test_fcl_utility.h" #include <boost/timer.hpp> -#include "fcl_resources/config.h" #include <boost/filesystem.hpp> +#include <hpp/fcl/internal/traversal_node_bvhs.h> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include "../src/collision_node.h" +#include <hpp/fcl/internal/BV_splitter.h> + +#include "utility.h" +#include "fcl_resources/config.h" + using namespace hpp::fcl; bool verbose = false; @@ -447,7 +449,7 @@ bool collide_Test_OBB(const Transform3f& tf, bool success (initialize(node, (const BVHModel<OBB>&)m1, tf, (const BVHModel<OBB>&)m2, Transform3f(), local_result)); - assert (success); + BOOST_REQUIRE (success); node.enable_statistics = verbose; diff --git a/test/test_fcl_distance_lower_bound.cpp b/test/distance_lower_bound.cpp similarity index 99% rename from test/test_fcl_distance_lower_bound.cpp rename to test/distance_lower_bound.cpp index ee825ba65ff603fac9c0b29617e24256035e5887..0d5a0645d9060ee6e44f756a0dbece6e4ef5df1f 100644 --- a/test/test_fcl_distance_lower_bound.cpp +++ b/test/distance_lower_bound.cpp @@ -45,7 +45,7 @@ #include <hpp/fcl/narrowphase/narrowphase.h> #include <hpp/fcl/collision.h> #include <hpp/fcl/distance.h> -# include "test_fcl_utility.h" +# include "utility.h" # include "fcl_resources/config.h" using hpp::fcl::Transform3f; diff --git a/test/test_fcl_eigen.cpp b/test/eigen.cpp similarity index 98% rename from test/test_fcl_eigen.cpp rename to test/eigen.cpp index a1bcb12fa7dcb3b5398840e8641ee004671930fc..5b50dce7d6a3fef520f98ee6d6761702a1e52666 100644 --- a/test/test_fcl_eigen.cpp +++ b/test/eigen.cpp @@ -102,11 +102,11 @@ BOOST_AUTO_TEST_CASE(fcl_eigen_matrix3fx) a *= a; PRINT_MATRIX(a); - Matrix3fX b = inverse(a); + Matrix3fX b = a.inverse(); a += a + a * b; PRINT_MATRIX(a); - b = inverse(a); + b = a.inverse(); a.transpose (); PRINT_MATRIX(a); PRINT_MATRIX(a.transposeTimes (b)); diff --git a/test/test_fcl_frontlist.cpp b/test/frontlist.cpp similarity index 97% rename from test/test_fcl_frontlist.cpp rename to test/frontlist.cpp index 36a5c312423916e04fb09c648c74f81baac85d1e..9762d69b272c0211a7cd12778dba22e6cc2b6fd7 100644 --- a/test/test_fcl_frontlist.cpp +++ b/test/frontlist.cpp @@ -41,10 +41,11 @@ #include <boost/test/unit_test.hpp> #include <boost/utility/binary.hpp> -#include <hpp/fcl/traversal/traversal_node_bvhs.h> -#include <hpp/fcl/traversal/traversal_node_setup.h> -#include <hpp/fcl/collision_node.h> -#include "test_fcl_utility.h" +#include <hpp/fcl/internal/traversal_node_bvhs.h> +#include <hpp/fcl/internal/traversal_node_setup.h> +#include <../src/collision_node.h> +#include <hpp/fcl/internal/BV_splitter.h> +#include "utility.h" #include "fcl_resources/config.h" #include <boost/filesystem.hpp> @@ -83,7 +84,11 @@ BOOST_AUTO_TEST_CASE(front_list) std::vector<Transform3f> transforms2; // t1 FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000}; FCL_REAL delta_trans[] = {1, 1, 1}; - std::size_t n = 10; +#ifdef NDEBUG + std::size_t n = 20; +#else + std::size_t n = 5; +#endif bool verbose = false; generateRandomTransforms(extents, delta_trans, 0.005 * 2 * 3.1415, transforms, transforms2, n); @@ -233,7 +238,7 @@ bool collide_front_list_Test(const Transform3f& tf1, const Transform3f& tf2, MeshCollisionTraversalNode<BV> node (request); bool success = initialize <BV>(node, m1, pose1, m2, pose2, local_result); - assert (success); + BOOST_REQUIRE (success); node.enable_statistics = verbose; @@ -297,7 +302,7 @@ bool collide_front_list_Test_Oriented(const Transform3f& tf1, const Transform3f& bool success = initialize (node, (const BVHModel<BV>&)m1, pose1, (const BVHModel<BV>&)m2, pose2, local_result); - assert (success); + BOOST_REQUIRE (success); node.enable_statistics = verbose; @@ -310,7 +315,7 @@ bool collide_front_list_Test_Oriented(const Transform3f& tf1, const Transform3f& pose1 = tf2; success = initialize (node, (const BVHModel<BV>&)m1, pose1, (const BVHModel<BV>&)m2, pose2, local_result); - assert (success); + BOOST_REQUIRE (success); local_result.clear(); collide(&node, request, local_result, &front_list); @@ -347,7 +352,7 @@ bool collide_Test(const Transform3f& tf, MeshCollisionTraversalNode<BV> node (request); bool success = initialize <BV>(node, m1, pose1, m2, pose2, local_result); - assert (success); + BOOST_REQUIRE (success); node.enable_statistics = verbose; diff --git a/test/general_test.cpp b/test/general_test.cpp index 947682b2285caecd2b66223b03213eaeae46a5a7..144eb5fc3ad31c2be3cc35465f6dd738f9a0b718 100644 --- a/test/general_test.cpp +++ b/test/general_test.cpp @@ -12,7 +12,6 @@ int main(int argc, char** argv) { boost::shared_ptr<Box> box0(new Box(1,1,1)); boost::shared_ptr<Box> box1(new Box(1,1,1)); -// GJKSolver_indep solver; GJKSolver_libccd solver; Vec3f contact_points; FCL_REAL penetration_depth; diff --git a/test/test_fcl_geometric_shapes.cpp b/test/geometric_shapes.cpp similarity index 94% rename from test/test_fcl_geometric_shapes.cpp rename to test/geometric_shapes.cpp index 60df213b657c9818bf7667b2ecd725c448f516ff..08b22fec339ab5d1e987fb9875ea38c82a9e066c 100644 --- a/test/test_fcl_geometric_shapes.cpp +++ b/test/geometric_shapes.cpp @@ -44,32 +44,17 @@ #include <hpp/fcl/narrowphase/narrowphase.h> #include <hpp/fcl/collision.h> #include <hpp/fcl/distance.h> -#include "test_fcl_utility.h" +#include "utility.h" #include <iostream> +#include <hpp/fcl/internal/tools.h> using namespace hpp::fcl; FCL_REAL extents [6] = {0, 0, 0, 10, 10, 10}; FCL_REAL tol_gjk = 0.01; -GJKSolver_indep solver1; -GJKSolver_indep solver2; - -Eigen::IOFormat fmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "", ""); -Eigen::IOFormat pyfmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "[", "]"); - -namespace hpp { -namespace fcl { -std::ostream& operator<< (std::ostream& os, const Transform3f& tf) -{ - return os << "[ " << - tf.getTranslation().format(fmt) - << ", " - << tf.getQuatRotation().coeffs().format(fmt) - << " ]" ; -} -} -} +GJKSolver solver1; +GJKSolver solver2; #define BOOST_CHECK_FALSE(p) BOOST_CHECK(!(p)) @@ -204,72 +189,6 @@ void testShapeIntersection(const S1& s1, const Transform3f& tf1, } } -template <typename Sa, typename Sb> void compareShapeIntersection ( - const Sa& sa, const Sb& sb, - const Transform3f& tf1, const Transform3f& tf2, - FCL_REAL tol = 1e-9) -{ - CollisionRequest request (CONTACT | DISTANCE_LOWER_BOUND, 1); - CollisionResult resA, resB; - - collide(&sa, tf1, &sa, tf2, request, resA); - collide(&sb, tf1, &sb, tf2, request, resB); - - BOOST_CHECK_EQUAL(resA.isCollision(), resB.isCollision()); - BOOST_CHECK_EQUAL(resA.numContacts(), resB.numContacts()); - - if (resA.isCollision() && resB.isCollision()) { - Contact cA = resA.getContact(0), - cB = resB.getContact(0); - - BOOST_TEST_MESSAGE( - tf1 << '\n' - << cA.pos.format(pyfmt) << '\n' - << '\n' - << tf2 << '\n' - << cB.pos.format(pyfmt) << '\n' - ); - // Only warnings because there are still some bugs. - BOOST_WARN_SMALL((cA.pos - cB.pos ).squaredNorm(), tol); - BOOST_WARN_SMALL((cA.normal - cB.normal).squaredNorm(), tol); - } else { - BOOST_CHECK_CLOSE(resA.distance_lower_bound, resB.distance_lower_bound, tol); // distances should be same - } -} - -template <typename Sa, typename Sb> void compareShapeDistance ( - const Sa& sa, const Sb& sb, - const Transform3f& tf1, const Transform3f& tf2, - FCL_REAL tol = 1e-9) -{ - DistanceRequest request (true); - DistanceResult resA, resB; - - distance(&sa, tf1, &sa, tf2, request, resA); - distance(&sb, tf1, &sb, tf2, request, resB); - - BOOST_TEST_MESSAGE( - tf1 << '\n' - << resA.normal.format(pyfmt) << '\n' - << resA.nearest_points[0].format(pyfmt) << '\n' - << resA.nearest_points[1].format(pyfmt) << '\n' - << '\n' - << tf2 << '\n' - << resB.normal.format(pyfmt) << '\n' - << resB.nearest_points[0].format(pyfmt) << '\n' - << resB.nearest_points[1].format(pyfmt) << '\n' - ); - // TODO in one case, there is a mismatch between the distances and I cannot say - // which one is correct. To visualize the case, use script test/test_fcl_geometric_shapes.py - BOOST_WARN_CLOSE(resA.min_distance, resB.min_distance, tol); - //BOOST_CHECK_CLOSE(resA.min_distance, resB.min_distance, tol); - - // Only warnings because there are still some bugs. - BOOST_WARN_SMALL((resA.normal - resA.normal).squaredNorm(), tol); - BOOST_WARN_SMALL((resA.nearest_points[0] - resB.nearest_points[0]).squaredNorm(), tol); - BOOST_WARN_SMALL((resA.nearest_points[1] - resB.nearest_points[1]).squaredNorm(), tol); -} - BOOST_AUTO_TEST_CASE (shapeIntersection_cylinderbox) { Cylinder s1 (0.029, 0.1); @@ -284,21 +203,19 @@ BOOST_AUTO_TEST_CASE (shapeIntersection_cylinderbox) (Quaternion3f (0.70738826916719977, 0, 0, 0.70682518110536596), Vec3f (-0.29936284351096382, 0.80023864435868775, 0.71750000000000003)); - GJKSolver_indep solver; + GJKSolver solver; FCL_REAL distance; Vec3f p1, p2, normal; bool res = solver.shapeDistance (s1, tf1, s2, tf2, distance, p1, p2, normal); BOOST_CHECK ((res && distance > 0) || (!res && distance <= 0)); // If objects are not colliding, p2 should be outside the cylinder and // p1 should be outside the box - Vec3f p2Loc (inverse (tf1).transform (p2)); - bool p2_in_cylinder ((fabs (p2Loc [2]) <= .5*s1.lz) && + Vec3f p2Loc (tf1.inverse().transform (p2)); + bool p2_in_cylinder ((fabs (p2Loc [2]) <= s1.halfLength) && (p2Loc [0] * p2Loc [0] + p2Loc [1] * p2Loc [1] <= s1.radius)); - Vec3f p1Loc (inverse (tf2).transform (p1)); - bool p1_in_box ((fabs (p1Loc [0]) <= .5 * s2.side [0]) && - (fabs (p1Loc [1]) <= .5 * s2.side [1]) && - (fabs (p1Loc [2]) <= .5 * s2.side [2])); + Vec3f p1Loc (tf2.inverse().transform (p1)); + bool p1_in_box = (p1Loc.array().abs() <= s2.halfSide.array()).all(); std::cout << "p2 in cylinder = (" << p2Loc.transpose () << ")" << std::endl; std::cout << "p1 in box = (" << p1Loc.transpose () << ")" << std::endl; @@ -310,14 +227,12 @@ BOOST_AUTO_TEST_CASE (shapeIntersection_cylinderbox) // If objects are not colliding, p2 should be outside the cylinder and // p1 should be outside the box - p2Loc = inverse (tf1).transform (p2); - p2_in_cylinder = (fabs (p2Loc [2]) <= .5*s1.lz) && + p2Loc = tf1.inverse().transform (p2); + p2_in_cylinder = (fabs (p2Loc [2]) <= s1.halfLength) && (p2Loc [0] * p2Loc [0] + p2Loc [1] * p2Loc [1] <= s1.radius); - p1Loc = inverse (tf2).transform (p1); - p1_in_box = (fabs (p1Loc [0]) <= .5 * s2.side [0]) && - (fabs (p1Loc [1]) <= .5 * s2.side [1]) && - (fabs (p1Loc [2]) <= .5 * s2.side [2]); + p1Loc = tf2.inverse().transform (p1); + p1_in_box = (p1Loc.array().abs() <= s2.halfSide.array()).all(); std::cout << "p2 in cylinder = (" << p2Loc.transpose () << ")" << std::endl; std::cout << "p1 in box = (" << p1.transpose () << ")" << std::endl; @@ -440,9 +355,7 @@ void testBoxBoxContactPoints(const Matrix3f& R) for (int i = 0; i < 8; ++i) { - vertices[i][0] *= 0.5 * s2.side[0]; - vertices[i][1] *= 0.5 * s2.side[1]; - vertices[i][2] *= 0.5 * s2.side[2]; + vertices[i].array() *= s2.halfSide.array(); } Transform3f tf1 = Transform3f(Vec3f(0, 0, -50)); @@ -483,7 +396,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_boxbox) Vec3f normal; Quaternion3f q; - q = Eigen::AngleAxis<double>((FCL_REAL)3.140 / 6, Vec3f(0, 0, 1)); + q = AngleAxis((FCL_REAL)3.140 / 6, UnitZ); tf1 = Transform3f(); tf2 = Transform3f(); @@ -525,82 +438,6 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_boxbox) } } -BOOST_AUTO_TEST_CASE(compare_convex_box) -{ - FCL_REAL l = 1, w = 1, d = 1; - Box box(l*2, w*2, d*2); - - Vec3f pts[8]; - pts[0] = Vec3f( l, w, d); - pts[1] = Vec3f( l, w,-d); - pts[2] = Vec3f( l,-w, d); - pts[3] = Vec3f( l,-w,-d); - pts[4] = Vec3f(-l, w, d); - pts[5] = Vec3f(-l, w,-d); - pts[6] = Vec3f(-l,-w, d); - pts[7] = Vec3f(-l,-w,-d); - std::vector<int> polygons; - polygons.push_back(4); - polygons.push_back(0); - polygons.push_back(2); - polygons.push_back(3); - polygons.push_back(1); - - polygons.push_back(4); - polygons.push_back(2); - polygons.push_back(6); - polygons.push_back(7); - polygons.push_back(3); - - polygons.push_back(4); - polygons.push_back(4); - polygons.push_back(5); - polygons.push_back(7); - polygons.push_back(6); - - polygons.push_back(4); - polygons.push_back(0); - polygons.push_back(1); - polygons.push_back(5); - polygons.push_back(4); - - polygons.push_back(4); - polygons.push_back(1); - polygons.push_back(3); - polygons.push_back(7); - polygons.push_back(5); - - polygons.push_back(4); - polygons.push_back(0); - polygons.push_back(2); - polygons.push_back(6); - polygons.push_back(4); - - Convex convex_box ( - pts, // points - 8, // num points - polygons.data(), - 6 // number of polygons - ); - - Transform3f tf1; - Transform3f tf2; - - tf2.setTranslation (Vec3f (3, 0, 0)); - compareShapeIntersection(box, convex_box, tf1, tf2); - compareShapeDistance (box, convex_box, tf1, tf2); - - tf2.setTranslation (Vec3f (0, 0, 0)); - compareShapeIntersection(box, convex_box, tf1, tf2); - compareShapeDistance (box, convex_box, tf1, tf2); - - for (int i = 0; i < 1000; ++i) { - generateRandomTransform(extents, tf2); - compareShapeIntersection(box, convex_box, tf1, tf2); - compareShapeDistance (box, convex_box, tf1, tf2); - } -} - BOOST_AUTO_TEST_CASE(shapeIntersection_spherebox) { Sphere s1(20); @@ -954,20 +791,27 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacetriangle) normal); BOOST_CHECK(res); + // These tests fail because of numerical precision errors. The points t[1] and t[2] + // lies on the border of the half-space. + // The normals should be good, when computed (i.e. res == true) res = solver1.shapeTriangleInteraction (hs, transform, t[0], t[1], t[2], transform, distance, c1, c2, normal); - BOOST_CHECK(res); + // BOOST_CHECK(res); + if (res) + BOOST_CHECK(isEqual(normal, transform.getRotation() * Vec3f(1, 0, 0), 1e-9)); res = solver1.shapeTriangleInteraction (hs, Transform3f(), t[0], t[1], t[2], Transform3f(), distance, c1, c2, normal); - BOOST_CHECK(res); - BOOST_CHECK(isEqual(normal, Vec3f(1, 0, 0), 1e-9)); + // BOOST_CHECK(res); + if (res) + BOOST_CHECK(isEqual(normal, Vec3f(1, 0, 0), 1e-9)); res = solver1.shapeTriangleInteraction (hs, transform, t[0], t[1], t[2], transform, distance, c1, c2, normal); - BOOST_CHECK(res); - BOOST_CHECK(isEqual(normal, transform.getRotation() * Vec3f(1, 0, 0), 1e-9)); + // BOOST_CHECK(res); + if (res) + BOOST_CHECK(isEqual(normal, transform.getRotation() * Vec3f(1, 0, 0), 1e-9)); } BOOST_AUTO_TEST_CASE(shapeIntersection_planetriangle) @@ -1042,7 +886,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere) tf2 = transform; contact = transform.transform(Vec3f(-5, 0, 0)); depth = 10; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1056,7 +900,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere) tf2 = transform * Transform3f(Vec3f(5, 0, 0)); contact = transform.transform(Vec3f(-2.5, 0, 0)); depth = 15; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1070,7 +914,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere) tf2 = transform * Transform3f(Vec3f(-5, 0, 0)); contact = transform.transform(Vec3f(-7.5, 0, 0)); depth = 5; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1092,7 +936,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacesphere) tf2 = transform * Transform3f(Vec3f(10.1, 0, 0)); contact = transform.transform(Vec3f(0.05, 0, 0)); depth = 20.1; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); } @@ -1196,7 +1040,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox) tf2 = transform; contact = transform.transform(Vec3f(-1.25, 0, 0)); depth = 2.5; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1210,7 +1054,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox) tf2 = transform * Transform3f(Vec3f(1.25, 0, 0)); contact = transform.transform(Vec3f(-0.625, 0, 0)); depth = 3.75; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1224,7 +1068,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox) tf2 = transform * Transform3f(Vec3f(-1.25, 0, 0)); contact = transform.transform(Vec3f(-1.875, 0, 0)); depth = 1.25; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1238,7 +1082,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox) tf2 = transform * Transform3f(Vec3f(2.51, 0, 0)); contact = transform.transform(Vec3f(0.005, 0, 0)); depth = 5.01; - normal = transform.getQuatRotation() * Vec3f(-1, 0, 0); + normal = transform.getRotation() * Vec3f(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); tf1 = Transform3f(); @@ -1249,7 +1093,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_halfspacebox) tf2 = transform * Transform3f(Vec3f(-2.51, 0, 0)); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, false); - tf1 = Transform3f(transform.getQuatRotation()); + tf1 = Transform3f(transform.getRotation()); tf2 = Transform3f(); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true); } @@ -1327,7 +1171,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_planebox) tf2 = transform * Transform3f(Vec3f(-2.51, 0, 0)); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, false); - tf1 = Transform3f(transform.getQuatRotation()); + tf1 = Transform3f(transform.getRotation()); tf2 = Transform3f(); testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true); } @@ -3059,7 +2903,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersectionGJK_boxbox) Vec3f normal; Quaternion3f q; - q = Eigen::AngleAxis<double>((FCL_REAL)3.140 / 6, Vec3f(0, 0, 1)); + q = AngleAxis((FCL_REAL)3.140 / 6, UnitZ); tf1 = Transform3f(); tf2 = Transform3f(); diff --git a/test/gjk-geometric-tools-benchmark b/test/gjk-geometric-tools-benchmark index 4104d7511f78c3d9f22b4b16fe63395dcacdd5e5..7e522128798f30f7b695f22cf95f674eae03e7bc 100644 --- a/test/gjk-geometric-tools-benchmark +++ b/test/gjk-geometric-tools-benchmark @@ -1,4 +1,4 @@ -Result after running test_fcl_gjk.cpp in Release mode. +Result after running gjk.cpp in Release mode. nCol = 2831 nDiff = 41 diff --git a/test/test_fcl_gjk.cpp b/test/gjk.cpp similarity index 93% rename from test/test_fcl_gjk.cpp rename to test/gjk.cpp index 3bb9b907684090dd37281b3f02495ee24ae237b7..ef05e979ff8ec349ca04130a8283618ccb9ecc6c 100644 --- a/test/test_fcl_gjk.cpp +++ b/test/gjk.cpp @@ -43,8 +43,9 @@ #include <hpp/fcl/narrowphase/narrowphase.h> #include <hpp/fcl/shape/geometric_shapes.h> +#include<hpp/fcl/internal/tools.h> -using hpp::fcl::GJKSolver_indep; +using hpp::fcl::GJKSolver; using hpp::fcl::TriangleP; using hpp::fcl::Vec3f; using hpp::fcl::Quaternion3f; @@ -73,7 +74,7 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1) Eigen::IOFormat tuple (Eigen::FullPrecision, Eigen::DontAlignCols, "", ", ", "", "", "(", ")"); std::size_t N = 10000; - GJKSolver_indep solver; + GJKSolver solver; Transform3f tf1, tf2; Vec3f p1, p2, a1, a2; Matrix3f M; @@ -183,11 +184,11 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1) BOOST_CHECK (w1.squaredNorm () > eps*eps); M.col (0) = u1; M.col (1) = v1; M.col (2) = w1; // Compute a1 such that p1 = P1 + a11 u1 + a12 v1 + a13 u1 x v1 - a1 = M.inverse () * (p1 - P1); + a1 = M.inverse() * (p1 - P1); BOOST_CHECK (w2.squaredNorm () > eps*eps); // Compute a2 such that p2 = Q1 + a21 u2 + a22 v2 + a23 u2 x v2 M.col (0) = u2; M.col (1) = v2; M.col (2) = w2; - a2 = M.inverse () * (p2 - Q1); + a2 = M.inverse() * (p2 - Q1); // minimal distance and closest points can be considered as a constrained // optimisation problem: @@ -268,7 +269,7 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1) } } } - std::cerr << "nCol = " << nCol << std::endl; + std::cerr << "nCol / nTotal = " << nCol << " / " << N << std::endl; std::cerr << "nDiff = " << nDiff << std::endl; // statistics clock_t totalTimeGjkColl = 0; @@ -280,10 +281,10 @@ BOOST_AUTO_TEST_CASE(distance_triangle_triangle_1) totalTimeGjkNoColl += results [i].timeGjk; } } - std::cerr << "Total time gjk: " << totalTimeGjkNoColl + totalTimeGjkColl - << std::endl; + std::cerr << "Total / average time gjk: " << totalTimeGjkNoColl + totalTimeGjkColl + << ", " << FCL_REAL(totalTimeGjkNoColl + totalTimeGjkColl) / FCL_REAL(CLOCKS_PER_SEC*N) << "s" << std::endl; std::cerr << "-- Collisions -------------------------" << std::endl; - std::cerr << "Total time gjk: " << totalTimeGjkColl << std::endl; + std::cerr << "Total / average time gjk: " << totalTimeGjkColl << ", " << FCL_REAL(totalTimeGjkColl) / FCL_REAL(CLOCKS_PER_SEC*nCol) << "s" << std::endl; std::cerr << "-- No collisions -------------------------" << std::endl; - std::cerr << "Total time gjk: " << totalTimeGjkNoColl << std::endl; + std::cerr << "Total / average time gjk: " << totalTimeGjkNoColl << ", " << FCL_REAL(totalTimeGjkNoColl) / FCL_REAL(CLOCKS_PER_SEC*(N-nCol)) << "s" << std::endl; } diff --git a/test/test_fcl_math.cpp b/test/math.cpp similarity index 94% rename from test/test_fcl_math.cpp rename to test/math.cpp index a82721b1f5a2e5d3579ee2e86ed5c398d66a02d1..61a1717aaa78d7e472c5bf487fdc3a48c4419c23 100644 --- a/test/test_fcl_math.cpp +++ b/test/math.cpp @@ -39,19 +39,15 @@ #include <boost/test/unit_test.hpp> #include <boost/utility/binary.hpp> -#include <hpp/fcl/math/vec_3f.h> -#include <hpp/fcl/math/matrix_3f.h> +#include <hpp/fcl/data_types.h> #include <hpp/fcl/math/transform.h> -#include <hpp/fcl/intersect.h> +#include <hpp/fcl/internal/intersect.h> +#include <hpp/fcl/internal/tools.h> using namespace hpp::fcl; -template<typename Derived> -inline Quaternion3f fromAxisAngle(const Eigen::MatrixBase<Derived>& axis, FCL_REAL angle) -{ - return Quaternion3f (Eigen::AngleAxis<double>(angle, axis)); -} + BOOST_AUTO_TEST_CASE(vec_test_eigen_vec64) { diff --git a/test/obb.cpp b/test/obb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb4bd9a59cb40a5c9d4489a41c6ef0930f437b56 --- /dev/null +++ b/test/obb.cpp @@ -0,0 +1,1376 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2014-2016, CNRS-LAAS + * Author: Florent Lamiraux + * 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 CNRS 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. + */ + +#include <iostream> +#include <fstream> +#include <sstream> + +#define BOOST_CHRONO_VERSION 2 +#include <boost/chrono/chrono.hpp> +#include <boost/chrono/chrono_io.hpp> + +#include <hpp/fcl/narrowphase/narrowphase.h> + +#include "../src/BV/OBB.h" +#include "../src/distance_func_matrix.h" + +using namespace hpp::fcl; + +int getNumCPUs() +{ + int NumCPUs = 0; + int MaxID = -1; + std::ifstream f("/proc/cpuinfo"); + if (!f.is_open()) { + std::cerr << "failed to open /proc/cpuinfo\n"; + return -1; + } + const std::string Key = "processor"; + std::string ln; + while (std::getline(f, ln)) { + if (ln.empty()) continue; + size_t SplitIdx = ln.find(':'); + std::string value; + if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1); + if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) { + NumCPUs++; + if (!value.empty()) { + int CurID = (int) strtol(value.c_str(), NULL, 10); + MaxID = std::max(CurID, MaxID); + } + } + } + if (f.bad()) { + std::cerr << "Failure reading /proc/cpuinfo\n"; + return -1; + } + if (!f.eof()) { + std::cerr << "Failed to read to end of /proc/cpuinfo\n"; + return -1; + } + f.close(); + + if ((MaxID + 1) != NumCPUs) { + fprintf(stderr, + "CPU ID assignments in /proc/cpuinfo seem messed up." + " This is usually caused by a bad BIOS.\n"); + } + return NumCPUs; +} + +bool checkCpuScalingEnabled() +{ + int num_cpus = getNumCPUs (); + + // We don't have a valid CPU count, so don't even bother. + if (num_cpus <= 0) return false; + // On Linux, the CPUfreq subsystem exposes CPU information as files on the + // local file system. If reading the exported files fails, then we may not be + // running on Linux, so we silently ignore all the read errors. + std::string res; + for (int cpu = 0; cpu < num_cpus; ++cpu) { + std::ostringstream oss; + oss << "/sys/devices/system/cpu/cpu" << cpu << "/cpufreq/scaling_governor"; + std::string governor_file = oss.str(); + std::ifstream f(governor_file.c_str()); + if (!f.is_open()) return false; + f >> res; + if (!f.good()) return false; + if (res != "performance") return true; + } + return false; +} + +void randomOBBs ( + Vec3f& a, Vec3f& b, FCL_REAL extentNorm) +{ + // Extent norm is between 0 and extentNorm on each axis + //a = (Vec3f::Ones()+Vec3f::Random()) * extentNorm / (2*sqrt(3)); + //b = (Vec3f::Ones()+Vec3f::Random()) * extentNorm / (2*sqrt(3)); + + a = extentNorm * Vec3f::Random().cwiseAbs().normalized(); + b = extentNorm * Vec3f::Random().cwiseAbs().normalized(); +} + +void randomTransform ( + Matrix3f& B, Vec3f& T, + const Vec3f& a, const Vec3f& b, const FCL_REAL extentNorm) +{ + // TODO Should we scale T to a and b norm ? + (void) a; + (void) b; + (void) extentNorm; + + FCL_REAL N = a.norm() + b.norm(); + // A translation of norm N ensures there is no collision. + // Set translation to be between 0 and 2 * N; + T = ( Vec3f::Random() / sqrt(3) ) * 1.5 * N; + //T.setZero(); + + Quaternion3f q; + q.coeffs().setRandom(); + q.normalize(); + B = q; +} + +#define NB_METHODS 7 +#define MANUAL_PRODUCT 1 + +#if MANUAL_PRODUCT +# define PRODUCT(M33,v3) ( M33.col(0) * v3[0] + M33.col(1) * v3[1] + M33.col(2) * v3[2] ) +#else +# define PRODUCT(M33,v3) (M33*v3) +#endif + +typedef boost::chrono::high_resolution_clock clock_type; +typedef clock_type::duration duration_type; + +const char* sep = ",\t"; +const FCL_REAL eps = 1e-10; + +const Eigen::IOFormat py_fmt(Eigen::FullPrecision, + 0, + ", ", // Coeff separator + ",\n", // Row separator + "(", // row prefix + ",)", // row suffix + "( ", // mat prefix + ", )" // mat suffix + ); + +namespace obbDisjoint_impls +{ + /// @return true if OBB are disjoint. + bool distance (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, FCL_REAL& distance) + { + GJKSolver gjk; + Box ba (2*a), bb (2*b); + Transform3f tfa, tfb (B, T); + + Vec3f p1, p2, normal; + return gjk.shapeDistance (ba, tfa, bb, tfb, distance, p1, p2, normal); + } + + inline FCL_REAL _computeDistanceForCase1 ( + const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf) + { + Vec3f AABB_corner; + /* This seems to be slower + AABB_corner.noalias() = T.cwiseAbs () - a; + AABB_corner.noalias() -= PRODUCT(Bf,b); + /*/ +#if MANUAL_PRODUCT + AABB_corner.noalias() = T.cwiseAbs () - a; + AABB_corner.noalias() -= Bf.col(0) * b[0]; + AABB_corner.noalias() -= Bf.col(1) * b[1]; + AABB_corner.noalias() -= Bf.col(2) * b[2]; +#else + AABB_corner.noalias() = T.cwiseAbs () - Bf * b - a; +#endif + // */ + return AABB_corner.array().max(0).matrix().squaredNorm (); + } + + inline FCL_REAL _computeDistanceForCase2 ( + const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const Matrix3f& Bf) + { + /* + Vec3f AABB_corner(PRODUCT(B.transpose(), T).cwiseAbs() - b); + AABB_corner.noalias() -= PRODUCT(Bf.transpose(), a); + return AABB_corner.array().max(0).matrix().squaredNorm (); + /*/ +#if MANUAL_PRODUCT + register FCL_REAL s, t = 0; + s = std::abs(B.col(0).dot(T)) - Bf.col(0).dot(a) - b[0]; + if (s > 0) t += s*s; + s = std::abs(B.col(1).dot(T)) - Bf.col(1).dot(a) - b[1]; + if (s > 0) t += s*s; + s = std::abs(B.col(2).dot(T)) - Bf.col(2).dot(a) - b[2]; + if (s > 0) t += s*s; + return t; +#else + Vec3f AABB_corner((B.transpose () * T).cwiseAbs () - Bf.transpose () * a - b); + return AABB_corner.array().max(0).matrix().squaredNorm (); +#endif + // */ + } + + int separatingAxisId (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + int id = 0; + + Matrix3f Bf (B.cwiseAbs()); + + // Corner of b axis aligned bounding box the closest to the origin + squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return id; + ++id; + + // | B^T T| - b - Bf^T a + squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return id; + ++id; + + int ja = 1, ka = 2, jb = 1, kb = 2; + for (int ia = 0; ia < 3; ++ia) { + for (int ib = 0; ib < 3; ++ib) { + const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib); + + const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) + + b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb)); + // We need to divide by the norm || Aia x Bib || + // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2 + if (diff > 0) { + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return id; + } + } + /* // or + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + squaredLowerBoundDistance = diff * diff; + if (squaredLowerBoundDistance > breakDistance2 * sinus2) { + squaredLowerBoundDistance /= sinus2; + return true; + } + // */ + } + ++id; + + jb = kb; kb = ib; + } + ja = ka; ka = ia; + } + + return id; + } + + // ------------------------ 0 -------------------------------------- + bool withRuntimeLoop (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + Matrix3f Bf (B.cwiseAbs()); + + // Corner of b axis aligned bounding box the closest to the origin + squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + // | B^T T| - b - Bf^T a + squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + int ja = 1, ka = 2, jb = 1, kb = 2; + for (int ia = 0; ia < 3; ++ia) { + for (int ib = 0; ib < 3; ++ib) { + const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib); + + const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) + + b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb)); + // We need to divide by the norm || Aia x Bib || + // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2 + if (diff > 0) { + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + /* // or + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + squaredLowerBoundDistance = diff * diff; + if (squaredLowerBoundDistance > breakDistance2 * sinus2) { + squaredLowerBoundDistance /= sinus2; + return true; + } + // */ + } + + jb = kb; kb = ib; + } + ja = ka; ka = ia; + } + + return false; + + } + + // ------------------------ 1 -------------------------------------- + bool withManualLoopUnrolling_1 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + FCL_REAL t, s; + FCL_REAL diff; + + // Matrix3f Bf = abs(B); + // Bf += reps; + Matrix3f Bf (B.cwiseAbs()); + + // Corner of b axis aligned bounding box the closest to the origin + Vec3f AABB_corner (T.cwiseAbs () - Bf * b); + Vec3f diff3 (AABB_corner - a); + diff3 = diff3.cwiseMax (Vec3f::Zero()); + + //for (Vec3f::Index i=0; i<3; ++i) diff3 [i] = std::max (0, diff3 [i]); + squaredLowerBoundDistance = diff3.squaredNorm (); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + AABB_corner = (B.transpose () * T).cwiseAbs () - Bf.transpose () * a; + // diff3 = | B^T T| - b - Bf^T a + diff3 = AABB_corner - b; + diff3 = diff3.cwiseMax (Vec3f::Zero()); + squaredLowerBoundDistance = diff3.squaredNorm (); + + if (squaredLowerBoundDistance > breakDistance2) + return true; + + // A0 x B0 + s = T[2] * B(1, 0) - T[1] * B(2, 0); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + FCL_REAL sinus2; + diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + + b[1] * Bf(0, 2) + b[2] * Bf(0, 1)); + // We need to divide by the norm || A0 x B0 || + // As ||A0|| = ||B0|| = 1, + // 2 2 + // || A0 x B0 || + (A0 | B0) = 1 + if (diff > 0) { + sinus2 = 1 - Bf (0,0) * Bf (0,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A0 x B1 + s = T[2] * B(1, 1) - T[1] * B(2, 1); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + + b[0] * Bf(0, 2) + b[2] * Bf(0, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (0,1) * Bf (0,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A0 x B2 + s = T[2] * B(1, 2) - T[1] * B(2, 2); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + + b[0] * Bf(0, 1) + b[1] * Bf(0, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (0,2) * Bf (0,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B0 + s = T[0] * B(2, 0) - T[2] * B(0, 0); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + + b[1] * Bf(1, 2) + b[2] * Bf(1, 1)); + if (diff > 0) { + sinus2 = 1 - Bf (1,0) * Bf (1,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B1 + s = T[0] * B(2, 1) - T[2] * B(0, 1); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + + b[0] * Bf(1, 2) + b[2] * Bf(1, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (1,1) * Bf (1,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B2 + s = T[0] * B(2, 2) - T[2] * B(0, 2); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + + b[0] * Bf(1, 1) + b[1] * Bf(1, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (1,2) * Bf (1,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B0 + s = T[1] * B(0, 0) - T[0] * B(1, 0); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + + b[1] * Bf(2, 2) + b[2] * Bf(2, 1)); + if (diff > 0) { + sinus2 = 1 - Bf (2,0) * Bf (2,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B1 + s = T[1] * B(0, 1) - T[0] * B(1, 1); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + + b[0] * Bf(2, 2) + b[2] * Bf(2, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (2,1) * Bf (2,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B2 + s = T[1] * B(0, 2) - T[0] * B(1, 2); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + + b[0] * Bf(2, 1) + b[1] * Bf(2, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (2,2) * Bf (2,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + return false; + + } + + // ------------------------ 2 -------------------------------------- + bool withManualLoopUnrolling_2 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + Matrix3f Bf (B.cwiseAbs()); + + // Corner of b axis aligned bounding box the closest to the origin + squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + // A0 x B0 + FCL_REAL t, s; + s = T[2] * B(1, 0) - T[1] * B(2, 0); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + FCL_REAL sinus2; + FCL_REAL diff; + diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + + b[1] * Bf(0, 2) + b[2] * Bf(0, 1)); + // We need to divide by the norm || A0 x B0 || + // As ||A0|| = ||B0|| = 1, + // 2 2 + // || A0 x B0 || + (A0 | B0) = 1 + if (diff > 0) { + sinus2 = 1 - Bf (0,0) * Bf (0,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A0 x B1 + s = T[2] * B(1, 1) - T[1] * B(2, 1); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + + b[0] * Bf(0, 2) + b[2] * Bf(0, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (0,1) * Bf (0,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A0 x B2 + s = T[2] * B(1, 2) - T[1] * B(2, 2); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + + b[0] * Bf(0, 1) + b[1] * Bf(0, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (0,2) * Bf (0,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B0 + s = T[0] * B(2, 0) - T[2] * B(0, 0); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + + b[1] * Bf(1, 2) + b[2] * Bf(1, 1)); + if (diff > 0) { + sinus2 = 1 - Bf (1,0) * Bf (1,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B1 + s = T[0] * B(2, 1) - T[2] * B(0, 1); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + + b[0] * Bf(1, 2) + b[2] * Bf(1, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (1,1) * Bf (1,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B2 + s = T[0] * B(2, 2) - T[2] * B(0, 2); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + + b[0] * Bf(1, 1) + b[1] * Bf(1, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (1,2) * Bf (1,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B0 + s = T[1] * B(0, 0) - T[0] * B(1, 0); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + + b[1] * Bf(2, 2) + b[2] * Bf(2, 1)); + if (diff > 0) { + sinus2 = 1 - Bf (2,0) * Bf (2,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B1 + s = T[1] * B(0, 1) - T[0] * B(1, 1); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + + b[0] * Bf(2, 2) + b[2] * Bf(2, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (2,1) * Bf (2,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B2 + s = T[1] * B(0, 2) - T[0] * B(1, 2); + t = ((s < 0.0) ? -s : s); assert (t == fabs (s)); + + diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + + b[0] * Bf(2, 1) + b[1] * Bf(2, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (2,2) * Bf (2,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + return false; + + } + + // ------------------------ 3 -------------------------------------- + template <int ia, int ib, + int ja = (ia+1)%3, int ka = (ia+2)%3, + int jb = (ib+1)%3, int kb = (ib+2)%3 > + struct loop_case_1 { + static inline bool run ( + const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, + const Matrix3f& Bf, + const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib); + + const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) + + b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb)); + // We need to divide by the norm || Aia x Bib || + // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2 + if (diff > 0) { + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + /* // or + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + squaredLowerBoundDistance = diff * diff; + if (squaredLowerBoundDistance > breakDistance2 * sinus2) { + squaredLowerBoundDistance /= sinus2; + return true; + } + // */ + } + return false; + } + }; + + bool withTemplateLoopUnrolling_1 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + Matrix3f Bf (B.cwiseAbs()); + + // Corner of b axis aligned bounding box the closest to the origin + squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + // Ai x Bj + if (loop_case_1<0,0>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<0,1>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<0,2>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<1,0>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<1,1>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<1,2>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<2,0>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<2,1>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_1<2,2>::run (B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + + return false; + } + + // ------------------------ 4 -------------------------------------- + + template <int ib, int jb = (ib+1)%3, int kb = (ib+2)%3 > + struct loop_case_2 + { + static inline bool run (int ia, int ja, int ka, + const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, + const Matrix3f& Bf, + const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + const FCL_REAL s = T[ka] * B(ja, ib) - T[ja] * B(ka, ib); + + const FCL_REAL diff = fabs(s) - (a[ja] * Bf(ka, ib) + a[ka] * Bf(ja, ib) + + b[jb] * Bf(ia, kb) + b[kb] * Bf(ia, jb)); + // We need to divide by the norm || Aia x Bib || + // As ||Aia|| = ||Bib|| = 1, (Aia | Bib)^2 = cosine^2 + if (diff > 0) { + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + /* // or + FCL_REAL sinus2 = 1 - Bf (ia,ib) * Bf (ia,ib); + squaredLowerBoundDistance = diff * diff; + if (squaredLowerBoundDistance > breakDistance2 * sinus2) { + squaredLowerBoundDistance /= sinus2; + return true; + } + // */ + } + return false; + } + }; + + bool withPartialTemplateLoopUnrolling_1 (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + Matrix3f Bf (B.cwiseAbs()); + + // Corner of b axis aligned bounding box the closest to the origin + squaredLowerBoundDistance = _computeDistanceForCase1 (T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + squaredLowerBoundDistance = _computeDistanceForCase2 (B, T, a, b, Bf); + if (squaredLowerBoundDistance > breakDistance2) + return true; + + // Ai x Bj + int ja = 1, ka = 2; + for (int ia = 0; ia < 3; ++ia) { + if (loop_case_2<0>::run (ia, ja, ka, + B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_2<1>::run (ia, ja, ka, + B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + if (loop_case_2<2>::run (ia, ja, ka, + B, T, a, b, Bf, breakDistance2, squaredLowerBoundDistance)) return true; + ja = ka; ka = ia; + } + + return false; + } + + // ------------------------ 5 -------------------------------------- + bool originalWithLowerBound (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& breakDistance2, FCL_REAL& squaredLowerBoundDistance) + { + register FCL_REAL t, s; + FCL_REAL diff; + + Matrix3f Bf (B.cwiseAbs()); + squaredLowerBoundDistance = 0; + + // if any of these tests are one-sided, then the polyhedra are disjoint + + // A1 x A2 = A0 + t = ((T[0] < 0.0) ? -T[0] : T[0]); + + diff = t - (a[0] + Bf.row(0).dot(b)); + if (diff > 0) { + squaredLowerBoundDistance = diff*diff; + } + + // A2 x A0 = A1 + t = ((T[1] < 0.0) ? -T[1] : T[1]); + + diff = t - (a[1] + Bf.row(1).dot(b)); + if (diff > 0) { + squaredLowerBoundDistance += diff*diff; + } + + // A0 x A1 = A2 + t =((T[2] < 0.0) ? -T[2] : T[2]); + + diff = t - (a[2] + Bf.row(2).dot(b)); + if (diff > 0) { + squaredLowerBoundDistance += diff*diff; + } + + if (squaredLowerBoundDistance > breakDistance2) + return true; + + squaredLowerBoundDistance = 0; + + // B1 x B2 = B0 + s = B.col(0).dot(T); + t = ((s < 0.0) ? -s : s); + + diff = t - (b[0] + Bf.col(0).dot(a)); + if (diff > 0) { + squaredLowerBoundDistance += diff*diff; + } + + // B2 x B0 = B1 + s = B.col(1).dot(T); + t = ((s < 0.0) ? -s : s); + + diff = t - (b[1] + Bf.col(1).dot(a)); + if (diff > 0) { + squaredLowerBoundDistance += diff*diff; + } + + // B0 x B1 = B2 + s = B.col(2).dot(T); + t = ((s < 0.0) ? -s : s); + + diff = t - (b[2] + Bf.col(2).dot(a)); + if (diff > 0) { + squaredLowerBoundDistance += diff*diff; + } + + if (squaredLowerBoundDistance > breakDistance2) + return true; + + // A0 x B0 + s = T[2] * B(1, 0) - T[1] * B(2, 0); + t = ((s < 0.0) ? -s : s); + + FCL_REAL sinus2; + diff = t - (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + + b[1] * Bf(0, 2) + b[2] * Bf(0, 1)); + // We need to divide by the norm || A0 x B0 || + // As ||A0|| = ||B0|| = 1, + // 2 2 + // || A0 x B0 || + (A0 | B0) = 1 + if (diff > 0) { + sinus2 = 1 - Bf (0,0) * Bf (0,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A0 x B1 + s = T[2] * B(1, 1) - T[1] * B(2, 1); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + + b[0] * Bf(0, 2) + b[2] * Bf(0, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (0,1) * Bf (0,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A0 x B2 + s = T[2] * B(1, 2) - T[1] * B(2, 2); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + + b[0] * Bf(0, 1) + b[1] * Bf(0, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (0,2) * Bf (0,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B0 + s = T[0] * B(2, 0) - T[2] * B(0, 0); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + + b[1] * Bf(1, 2) + b[2] * Bf(1, 1)); + if (diff > 0) { + sinus2 = 1 - Bf (1,0) * Bf (1,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B1 + s = T[0] * B(2, 1) - T[2] * B(0, 1); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + + b[0] * Bf(1, 2) + b[2] * Bf(1, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (1,1) * Bf (1,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A1 x B2 + s = T[0] * B(2, 2) - T[2] * B(0, 2); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + + b[0] * Bf(1, 1) + b[1] * Bf(1, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (1,2) * Bf (1,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B0 + s = T[1] * B(0, 0) - T[0] * B(1, 0); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + + b[1] * Bf(2, 2) + b[2] * Bf(2, 1)); + if (diff > 0) { + sinus2 = 1 - Bf (2,0) * Bf (2,0); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B1 + s = T[1] * B(0, 1) - T[0] * B(1, 1); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + + b[0] * Bf(2, 2) + b[2] * Bf(2, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (2,1) * Bf (2,1); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + // A2 x B2 + s = T[1] * B(0, 2) - T[0] * B(1, 2); + t = ((s < 0.0) ? -s : s); + + diff = t - (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + + b[0] * Bf(2, 1) + b[1] * Bf(2, 0)); + if (diff > 0) { + sinus2 = 1 - Bf (2,2) * Bf (2,2); + if (sinus2 > 1e-6) { + squaredLowerBoundDistance = diff * diff / sinus2; + if (squaredLowerBoundDistance > breakDistance2) { + return true; + } + } + } + + return false; + + } + + // ------------------------ 6 -------------------------------------- + bool originalWithNoLowerBound (const Matrix3f& B, const Vec3f& T, const Vec3f& a, const Vec3f& b, const FCL_REAL& , FCL_REAL& squaredLowerBoundDistance) + { + register FCL_REAL t, s; + const FCL_REAL reps = 1e-6; + + squaredLowerBoundDistance = 0; + + Matrix3f Bf (B.array().abs() + reps); + // Bf += reps; + + // if any of these tests are one-sided, then the polyhedra are disjoint + + // A1 x A2 = A0 + t = ((T[0] < 0.0) ? -T[0] : T[0]); + + // if(t > (a[0] + Bf.dotX(b))) + if(t > (a[0] + Bf.row(0).dot(b))) + return true; + + // B1 x B2 = B0 + // s = B.transposeDotX(T); + s = B.col(0).dot(T); + t = ((s < 0.0) ? -s : s); + + // if(t > (b[0] + Bf.transposeDotX(a))) + if(t > (b[0] + Bf.col(0).dot(a))) + return true; + + // A2 x A0 = A1 + t = ((T[1] < 0.0) ? -T[1] : T[1]); + + // if(t > (a[1] + Bf.dotY(b))) + if(t > (a[1] + Bf.row(1).dot(b))) + return true; + + // A0 x A1 = A2 + t =((T[2] < 0.0) ? -T[2] : T[2]); + + // if(t > (a[2] + Bf.dotZ(b))) + if(t > (a[2] + Bf.row(2).dot(b))) + return true; + + // B2 x B0 = B1 + // s = B.transposeDotY(T); + s = B.col(1).dot(T); + t = ((s < 0.0) ? -s : s); + + // if(t > (b[1] + Bf.transposeDotY(a))) + if(t > (b[1] + Bf.col(1).dot(a))) + return true; + + // B0 x B1 = B2 + // s = B.transposeDotZ(T); + s = B.col(2).dot(T); + t = ((s < 0.0) ? -s : s); + + // if(t > (b[2] + Bf.transposeDotZ(a))) + if(t > (b[2] + Bf.col(2).dot(a))) + return true; + + // A0 x B0 + s = T[2] * B(1, 0) - T[1] * B(2, 0); + t = ((s < 0.0) ? -s : s); + + if(t > (a[1] * Bf(2, 0) + a[2] * Bf(1, 0) + + b[1] * Bf(0, 2) + b[2] * Bf(0, 1))) + return true; + + // A0 x B1 + s = T[2] * B(1, 1) - T[1] * B(2, 1); + t = ((s < 0.0) ? -s : s); + + if(t > (a[1] * Bf(2, 1) + a[2] * Bf(1, 1) + + b[0] * Bf(0, 2) + b[2] * Bf(0, 0))) + return true; + + // A0 x B2 + s = T[2] * B(1, 2) - T[1] * B(2, 2); + t = ((s < 0.0) ? -s : s); + + if(t > (a[1] * Bf(2, 2) + a[2] * Bf(1, 2) + + b[0] * Bf(0, 1) + b[1] * Bf(0, 0))) + return true; + + // A1 x B0 + s = T[0] * B(2, 0) - T[2] * B(0, 0); + t = ((s < 0.0) ? -s : s); + + if(t > (a[0] * Bf(2, 0) + a[2] * Bf(0, 0) + + b[1] * Bf(1, 2) + b[2] * Bf(1, 1))) + return true; + + // A1 x B1 + s = T[0] * B(2, 1) - T[2] * B(0, 1); + t = ((s < 0.0) ? -s : s); + + if(t > (a[0] * Bf(2, 1) + a[2] * Bf(0, 1) + + b[0] * Bf(1, 2) + b[2] * Bf(1, 0))) + return true; + + // A1 x B2 + s = T[0] * B(2, 2) - T[2] * B(0, 2); + t = ((s < 0.0) ? -s : s); + + if(t > (a[0] * Bf(2, 2) + a[2] * Bf(0, 2) + + b[0] * Bf(1, 1) + b[1] * Bf(1, 0))) + return true; + + // A2 x B0 + s = T[1] * B(0, 0) - T[0] * B(1, 0); + t = ((s < 0.0) ? -s : s); + + if(t > (a[0] * Bf(1, 0) + a[1] * Bf(0, 0) + + b[1] * Bf(2, 2) + b[2] * Bf(2, 1))) + return true; + + // A2 x B1 + s = T[1] * B(0, 1) - T[0] * B(1, 1); + t = ((s < 0.0) ? -s : s); + + if(t > (a[0] * Bf(1, 1) + a[1] * Bf(0, 1) + + b[0] * Bf(2, 2) + b[2] * Bf(2, 0))) + return true; + + // A2 x B2 + s = T[1] * B(0, 2) - T[0] * B(1, 2); + t = ((s < 0.0) ? -s : s); + + if(t > (a[0] * Bf(1, 2) + a[1] * Bf(0, 2) + + b[0] * Bf(2, 1) + b[1] * Bf(2, 0))) + return true; + + return false; + + } +} + +struct BenchmarkResult +{ + /// The test ID: + /// - 0-10 identifies a separating axes. + /// - 11 means no separatins axes could be found. (distance should be <= 0) + int ifId; + FCL_REAL distance; + FCL_REAL squaredLowerBoundDistance; + duration_type duration[NB_METHODS]; + bool failure; + + static std::ostream& headers (std::ostream& os) + { + duration_type dummy (1); + std::string unit = " (" + boost::chrono::duration_units_default<>().get_unit (boost::chrono::duration_style::symbol, dummy) + ")"; + os << boost::chrono::symbol_format + << "separating axis" + << sep << "distance lower bound" + << sep << "distance" + << sep << "failure" + << sep << "Runtime Loop" << unit + << sep << "Manual Loop Unrolling 1" << unit + << sep << "Manual Loop Unrolling 2" << unit + << sep << "Template Unrolling" << unit + << sep << "Partial Template Unrolling" << unit + << sep << "Original (LowerBound)" << unit + << sep << "Original (NoLowerBound)" << unit + ; + return os; + } + + std::ostream& print (std::ostream& os) const + { + os << ifId + << sep << std::sqrt(squaredLowerBoundDistance) + << sep << distance + << sep << failure; + for (int i = 0; i < NB_METHODS; ++i) os << sep << duration[i].count(); + return os; + } +}; + +std::ostream& operator<< (std::ostream& os, const BenchmarkResult& br) +{ + return br.print (os); +} + +BenchmarkResult benchmark_obb_case ( + const Matrix3f& B, const Vec3f& T, + const Vec3f& a, const Vec3f& b, + const CollisionRequest& request, + std::size_t N) +{ + const FCL_REAL breakDistance (request.break_distance + request.security_margin); + const FCL_REAL breakDistance2 = breakDistance * breakDistance; + + BenchmarkResult result; + // First determine which axis provide the answer + result.ifId = obbDisjoint_impls::separatingAxisId (B, T, a, b, breakDistance2, + result.squaredLowerBoundDistance); + bool disjoint = obbDisjoint_impls::distance (B, T, a, b, result.distance); + assert (0 <= result.ifId && result.ifId <= 11); + + // Sanity check + result.failure = true; + bool overlap = (result.ifId == 11); + FCL_REAL dist_thr = request.break_distance + request.security_margin; + if ( !overlap && result.distance <= 0) { + std::cerr << "Failure: negative distance for disjoint OBBs."; + } else if (!overlap && result.squaredLowerBoundDistance < 0) { + std::cerr << "Failure: negative distance lower bound."; + } else if (!overlap && eps < std::sqrt (result.squaredLowerBoundDistance) - result.distance) { + std::cerr << "Failure: distance is inferior to its lower bound (diff = " << + std::sqrt (result.squaredLowerBoundDistance) - result.distance << ")."; + } else if (overlap != !disjoint && result.distance >= dist_thr - eps) { + std::cerr << "Failure: overlapping test and distance query mismatch."; + } else if (overlap && result.distance >= dist_thr - eps) { + std::cerr << "Failure: positive distance for overlapping OBBs."; + } else { + result.failure = false; + } + if (result.failure) { + std::cerr + << "\nR = " << Quaternion3f(B).coeffs().transpose().format (py_fmt) + << "\nT = " << T.transpose().format (py_fmt) + << "\na = " << a.transpose().format (py_fmt) + << "\nb = " << b.transpose().format (py_fmt) + << "\nresult = " << result + << '\n' << std::endl; + } + + // Compute time + FCL_REAL tmp; + clock_type::time_point start, end; + + // ------------------------ 0 -------------------------------------- + start = clock_type::now(); + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::withRuntimeLoop (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[0] = (end - start) / N; + + // ------------------------ 1 -------------------------------------- + start = clock_type::now(); + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::withManualLoopUnrolling_1 (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[1] = (end - start) / N; + + // ------------------------ 2 -------------------------------------- + start = clock_type::now(); + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::withManualLoopUnrolling_2 (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[2] = (end - start) / N; + + // ------------------------ 3 -------------------------------------- + start = clock_type::now(); + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::withTemplateLoopUnrolling_1 (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[3] = (end - start) / N; + + // ------------------------ 4 -------------------------------------- + start = clock_type::now(); + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::withPartialTemplateLoopUnrolling_1 (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[4] = (end - start) / N; + + // ------------------------ 5 -------------------------------------- + start = clock_type::now(); + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::originalWithLowerBound (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[5] = (end - start) / N; + + // ------------------------ 6 -------------------------------------- + start = clock_type::now(); + // The 2 last arguments are unused. + for (std::size_t i = 0; i < N; ++i) + obbDisjoint_impls::originalWithNoLowerBound (B, T, a, b, breakDistance2, tmp); + end = clock_type::now(); + result.duration[6] = (end - start) / N; + + return result; +} + +std::size_t obb_overlap_and_lower_bound_distance(std::ostream* output) +{ + std::size_t nbFailure = 0; + + // Create two OBBs axis + Vec3f a, b; + Matrix3f B; + Vec3f T; + CollisionRequest request; + + static const size_t nbRandomOBB = 100; + static const size_t nbTransformPerOBB = 100; + static const size_t nbRunForTimeMeas = 1000; + static const FCL_REAL extentNorm = 1.; + + if (output != NULL) *output << BenchmarkResult::headers << '\n'; + + BenchmarkResult result; + for (std::size_t iobb = 0; iobb < nbRandomOBB; ++iobb) { + randomOBBs (a, b, extentNorm); + for (std::size_t itf = 0; itf < nbTransformPerOBB; ++itf) { + randomTransform (B, T, a, b, extentNorm); + result = benchmark_obb_case (B, T, a, b, request, nbRunForTimeMeas); + if (output != NULL) *output << result << '\n'; + if (result.failure) nbFailure++; + } + } + return nbFailure; +} + +int main (int argc, char** argv) +{ + std::ostream* output = NULL; + if (argc > 1 && strcmp(argv[1], "--generate-output") == 0) + { + output = &std::cout; + } + + bool cpuScalingEnabled = checkCpuScalingEnabled(); + if (cpuScalingEnabled) + std::cerr << + "CPU scaling is enabled." + "\n\tThe benchmark real time measurements may be noisy and will incur extra overhead." + "\n\tUse the following commands to turn on and off." + "\n\t\tsudo cpufreq-set --governor performance" + "\n\t\tsudo cpufreq-set --governor powersave" + "\n" + ; + + std::size_t nbFailure = obb_overlap_and_lower_bound_distance(output); + if (nbFailure > INT_MAX) return INT_MAX; + return (int)nbFailure; +} diff --git a/test/test_fcl_octree.cpp b/test/octree.cpp similarity index 98% rename from test/test_fcl_octree.cpp rename to test/octree.cpp index 40951efe67872bcf486440898a3242d554e4015e..5632a496190508769b5f5e174002d88299966b9c 100644 --- a/test/test_fcl_octree.cpp +++ b/test/octree.cpp @@ -38,14 +38,16 @@ #define BOOST_TEST_DYN_LINK #include <fstream> #include <boost/test/unit_test.hpp> +#include <boost/filesystem.hpp> #include <hpp/fcl/BVH/BVH_model.h> #include <hpp/fcl/collision.h> #include <hpp/fcl/distance.h> #include <hpp/fcl/shape/geometric_shapes.h> -#include "test_fcl_utility.h" +#include <hpp/fcl/internal/BV_splitter.h> + +#include "utility.h" #include "fcl_resources/config.h" -#include <boost/filesystem.hpp> using hpp::fcl::Vec3f; using hpp::fcl::Triangle; diff --git a/test/test_fcl_profiling.cpp b/test/profiling.cpp similarity index 97% rename from test/test_fcl_profiling.cpp rename to test/profiling.cpp index f62e49bf5757fc02dc9efa94362e0bd7f0adfe8f..2e96e4c82abe0ece23c4d3c4398b91c708441db2 100644 --- a/test/test_fcl_profiling.cpp +++ b/test/profiling.cpp @@ -26,12 +26,12 @@ #include <hpp/fcl/collision_func_matrix.h> #include <hpp/fcl/narrowphase/narrowphase.h> #include <hpp/fcl/mesh_loader/assimp.h> -#include "test_fcl_utility.h" +#include "utility.h" #include "fcl_resources/config.h" using namespace hpp::fcl; -CollisionFunctionMatrix<GJKSolver_indep> lookupTable; +CollisionFunctionMatrix lookupTable; bool supportedPair(const CollisionGeometry* o1, const CollisionGeometry* o2) { OBJECT_TYPE object_type1 = o1->getObjectType(); @@ -253,8 +253,8 @@ int main(int argc, char** argv) geoms.push_back(Geometry ("Capsule" , new Capsule (2, 1) )); geoms.push_back(Geometry ("Cone" , new Cone (2, 1) )); geoms.push_back(Geometry ("Cylinder" , new Cylinder (2, 1) )); - geoms.push_back(Geometry ("Plane" , new Plane (Vec3f(1,1,1).normalized(), 0) )); - geoms.push_back(Geometry ("Halfspace" , new Halfspace (Vec3f(1,1,1).normalized(), 0) )); + //geoms.push_back(Geometry ("Plane" , new Plane (Vec3f(1,1,1).normalized(), 0) )); + //geoms.push_back(Geometry ("Halfspace" , new Halfspace (Vec3f(1,1,1).normalized(), 0) )); // not implemented // geoms.push_back(Geometry ("TriangleP" , new TriangleP (Vec3f(0,1,0), Vec3f(0,0,1), Vec3f(-1,0,0)) )); geoms.push_back(Geometry ("rob BVHModel<OBB>" , objToGeom<OBB> ((path / "rob.obj").string()))); diff --git a/test/python_unit/CMakeLists.txt b/test/python_unit/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d62837aee6187fd6b7e0d3665b3090cc6e0efb2 --- /dev/null +++ b/test/python_unit/CMakeLists.txt @@ -0,0 +1,7 @@ +SET(${PROJECT_NAME}_PYTHON_TESTS + geometric_shapes + ) + +FOREACH(TEST ${${PROJECT_NAME}_PYTHON_TESTS}) + ADD_PYTHON_UNIT_TEST("py-${TEST}" "test/python_unit/${TEST}.py" "python") +ENDFOREACH(TEST ${${PROJECT_NAME}_PYTHON_TESTS}) diff --git a/test/python_unit/geometric_shapes.py b/test/python_unit/geometric_shapes.py new file mode 100644 index 0000000000000000000000000000000000000000..6e9109e0f054535156ba27904ecd746accbe6a47 --- /dev/null +++ b/test/python_unit/geometric_shapes.py @@ -0,0 +1,80 @@ +import unittest +import hppfcl +hppfcl.switchToNumpyMatrix() +import numpy as np + +class TestGeometricShapes(unittest.TestCase): + + def test_capsule(self): + capsule = hppfcl.Capsule(1.,2.) + self.assertIsInstance(capsule, hppfcl.Capsule) + self.assertIsInstance(capsule, hppfcl.ShapeBase) + self.assertIsInstance(capsule, hppfcl.CollisionGeometry) + self.assertEqual(capsule.getNodeType(), hppfcl.NODE_TYPE.GEOM_CAPSULE) + self.assertEqual(capsule.radius,1.) + self.assertEqual(capsule.halfLength,1.) + capsule.radius = 3. + capsule.halfLength = 4. + self.assertEqual(capsule.radius,3.) + self.assertEqual(capsule.halfLength,4.) + + def test_box1(self): + box = hppfcl.Box(np.matrix([1.,2.,3.]).T) + self.assertIsInstance(box, hppfcl.Box) + self.assertIsInstance(box, hppfcl.ShapeBase) + self.assertIsInstance(box, hppfcl.CollisionGeometry) + self.assertEqual(box.getNodeType(), hppfcl.NODE_TYPE.GEOM_BOX) + self.assertTrue(np.array_equal(box.halfSide,np.matrix([.5,1.,1.5]).T)) + box.halfSide = np.matrix([4.,5.,6.]).T + self.assertTrue(np.array_equal(box.halfSide,np.matrix([4.,5.,6.]).T)) + + def test_box2(self): + box = hppfcl.Box(1.,2.,3) + self.assertIsInstance(box, hppfcl.Box) + self.assertIsInstance(box, hppfcl.ShapeBase) + self.assertIsInstance(box, hppfcl.CollisionGeometry) + self.assertEqual(box.getNodeType(), hppfcl.NODE_TYPE.GEOM_BOX) + self.assertEqual(box.halfSide[0],0.5) + self.assertEqual(box.halfSide[1],1.0) + self.assertEqual(box.halfSide[2],1.5) + box.halfSide[0] = 4. + box.halfSide[0] = 5. + box.halfSide[0] = 6. +# self.assertEqual(box.halfSide[0],4.) +# self.assertEqual(box.halfSide[1],5.) +# self.assertEqual(box.halfSide[2],6.) + + def test_sphere(self): + sphere = hppfcl.Sphere(1.) + self.assertIsInstance(sphere, hppfcl.Sphere) + self.assertIsInstance(sphere, hppfcl.ShapeBase) + self.assertIsInstance(sphere, hppfcl.CollisionGeometry) + self.assertEqual(sphere.getNodeType(), hppfcl.NODE_TYPE.GEOM_SPHERE) + self.assertEqual(sphere.radius,1.) + sphere.radius = 2. + self.assertEqual(sphere.radius,2.) + + def test_cylinder(self): + cylinder = hppfcl.Cylinder(1.,2.) + self.assertIsInstance(cylinder, hppfcl.Cylinder) + self.assertIsInstance(cylinder, hppfcl.ShapeBase) + self.assertIsInstance(cylinder, hppfcl.CollisionGeometry) + self.assertEqual(cylinder.getNodeType(), hppfcl.NODE_TYPE.GEOM_CYLINDER) + self.assertEqual(cylinder.radius,1.) + self.assertEqual(cylinder.halfLength,1.) + + def test_cone(self): + cone = hppfcl.Cone(1.,2.) + self.assertIsInstance(cone, hppfcl.Cone) + self.assertIsInstance(cone, hppfcl.ShapeBase) + self.assertIsInstance(cone, hppfcl.CollisionGeometry) + self.assertEqual(cone.getNodeType(), hppfcl.NODE_TYPE.GEOM_CONE) + self.assertEqual(cone.radius,1.) + self.assertEqual(cone.halfLength,1.) + cone.radius = 3. + cone.halfLength = 4. + self.assertEqual(cone.radius,3.) + self.assertEqual(cone.halfLength,4.) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/scripts/collision-bench.py b/test/scripts/collision-bench.py new file mode 100644 index 0000000000000000000000000000000000000000..3497c83a26441f8f3474c2a753a01496a04864a7 --- /dev/null +++ b/test/scripts/collision-bench.py @@ -0,0 +1,76 @@ +import matplotlib.pyplot as plt +import csv, sys, numpy as np +from math import sqrt + +filename = sys.argv[1] + +with open(filename, 'r') as file: + reader = csv.reader (file, strict = True) + fieldnames = None + #fieldnames = reader.fieldnames + converters = (str, int, int, int, float, lambda x: float(x)*1e-3) + + for row in reader: + if fieldnames is None: + fieldnames = [ n.strip() for n in row] + values = [] + continue + + values.append ( [ c(v) for v, c in zip(row, converters) ] ) + +request1 = values[:int(len(values)/2)] +request2 = values[int(len(values)/2):] + +Ntransforms = 1 +while values[0][0:3] == values[Ntransforms][0:3]: + Ntransforms += 1 + +splitMethods = ['avg', 'med', 'cen'] +type = ["o", "or", "r", ] +BVs = sorted (list (set ([ v[0] for v in request1[::Ntransforms] ]))) +xvals = [ BVs.index(v[0]) + len(BVs)*v[2] + 3*len(BVs)*v[1] for v in request1[::Ntransforms] ] +cases = [ v[0] + " " + type[v[1]] + " " + splitMethods[v[2]] for v in request1[::Ntransforms] ] + +idx_reorder = sorted (list(range(len(xvals))), key=lambda i: xvals[i]) +def reorder (l): return [ l[i] for i in idx_reorder ] + +xvals_s = reorder (xvals) +cases_s = reorder (cases) + +onlyLB = True +# Time +plt.figure(0) +for i in range(Ntransforms): + if not onlyLB: + plt.plot(xvals_s, reorder([ v[5] for v in request1[i::Ntransforms] ]) , '-.o', label=str(i)) + plt.plot(xvals_s, reorder([ v[5] for v in request2[i::Ntransforms] ]) , ':+', label=str(i)+"+lb") + +plt.legend() +plt.xticks(ticks=xvals_s, labels=cases_s, rotation=90) +plt.ylabel('Time (us)') +plt.yscale('log') + +# Time +plt.figure(2) +for k in range (0, len(request1), Ntransforms): + if not onlyLB: + plt.plot([ xvals[int(k/Ntransforms)], ], sum([ v[5] for v in request1[k:k+Ntransforms] ])/Ntransforms) + plt.plot([ xvals[int(k/Ntransforms)], ], sum([ v[5] for v in request2[k:k+Ntransforms] ])/Ntransforms) + +plt.plot(xvals_s, reorder ([ sum([ v[5] for v in request2[k:k+Ntransforms] ])/Ntransforms for k in range (0, len(request1), Ntransforms) ])) + +plt.xticks(ticks=xvals_s, labels=cases_s, rotation=90) +plt.ylabel('Time (us)') +plt.yscale('log') + +# Distance lower bound +plt.figure(1) +for i in range(Ntransforms): + if request2[i][3] > 0: continue + plt.plot(xvals_s, reorder([ v[4] for v in request2[i::Ntransforms] ]) , ':+', label=str(i)+"+lb") + +plt.legend() +plt.ylabel('Distance lower bound') +plt.xticks(ticks=xvals_s, labels=cases_s, rotation=90) + +plt.show() diff --git a/test/test_fcl_collision.py b/test/scripts/collision.py similarity index 100% rename from test/test_fcl_collision.py rename to test/scripts/collision.py diff --git a/test/test_fcl_distance_lower_bound.py b/test/scripts/distance_lower_bound.py similarity index 100% rename from test/test_fcl_distance_lower_bound.py rename to test/scripts/distance_lower_bound.py diff --git a/test/test_fcl_geometric_shapes.py b/test/scripts/geometric_shapes.py similarity index 100% rename from test/test_fcl_geometric_shapes.py rename to test/scripts/geometric_shapes.py diff --git a/test/test_fcl_gjk.py b/test/scripts/gjk.py similarity index 100% rename from test/test_fcl_gjk.py rename to test/scripts/gjk.py diff --git a/test/scripts/obb.py b/test/scripts/obb.py new file mode 100644 index 0000000000000000000000000000000000000000..1f9141cd74306a72d64ac3229b4f2800e67d9bf1 --- /dev/null +++ b/test/scripts/obb.py @@ -0,0 +1,110 @@ +import matplotlib.pyplot as plt +import csv, sys, numpy as np +from math import sqrt + +filename = sys.argv[1] + +with open(filename, 'r') as file: + reader = csv.reader (file, strict = True) + fieldnames = None + #fieldnames = reader.fieldnames + for row in reader: + if fieldnames is None: + fieldnames = [ n.strip() for n in row] + values = [ [] for _ in fieldnames ] + continue + + values[0].append (int(row[0])) + for i, v in enumerate(row[1:]): + values[i+1].append (float(v)) + +# Compute mean and variance for each values, for each separating axis +means = [ [ 0., ] * 12 for _ in fieldnames[4:] ] +stddevs = [ [ 0., ] * 12 for _ in fieldnames[4:] ] +nb_occurence = [ 0, ] * 12 + +for i, id in enumerate(values[0]): + nb_occurence[id] += 1 + +for i, id in enumerate(values[0]): + for k, n in enumerate(fieldnames[4:]): + v = values[k+4][i] + means [k][id] += v / nb_occurence[id] + stddevs[k][id] += v * v / nb_occurence[id] + +for k, n in enumerate(fieldnames[4:]): + for id in range(12): + #means [k][id] /= nb_occurence[id] + #stddevs[k][id] = sqrt (stddevs[k][id]) / nb_occurence[id] - means[k][id]) + stddevs[k][id] = sqrt (stddevs[k][id] - means[k][id]*means[k][id]) + +subplots = False +Nrows = 1 +Ncols = 3 +iplot = 1 +time_vs_sep_axis = True +nb_occ_sep_axis = False +avg_time_vs_impl = True + +if time_vs_sep_axis: + if subplots: plt.subplot (Nrows, Ncols, iplot) + else: plt.figure (iplot) + plt.title ("Time, with std dev, versus separating axis") + for k, n in enumerate(fieldnames[4:]): + #plt.errorbar ([ np.linspace(0, 11, 12) + shift for shift in np.linspace (-0.2, 0.2, ) ], means[k], stddevs[k], label=n) + plt.errorbar (np.linspace(0, 11, 12), means[k], stddevs[k], label=n) + # plt.errorbar (np.linspace(0, 11, 12), means[k], [ [ 0 ] * len(stddevs[k]), stddevs[k] ], label=n) + plt.xlim([-0.5,11.5]) + plt.ylabel('Time (ns)') + plt.xlabel('Separating axis') + plt.legend(loc='upper left') + + axx = plt.gca().twinx() + axx.hist (values[0], bins=[ i-0.5 for i in range(13) ], bottom=-0.5, cumulative=True, + rwidth=0.5, fill=False, label='Cumulative occurence') + axx.set_ylabel('Nb occurence of a separating axis.') + plt.legend(loc='lower right') + +iplot += 1 +if nb_occ_sep_axis: + if subplots: plt.subplot (Nrows, Ncols, iplot) + else: plt.figure (iplot) + plt.title ("Nb of occurence per separating axis") + plt.hist (values[0], bins=[ i-0.5 for i in range(13) ]) + plt.ylabel('Nb occurence') + plt.xlabel('Separating axis') + dlb_id = 1 + d_id = 2 + #plt.title ("Time, with std dev, versus distance") + #for k, n in enumerate(fieldnames[4:]): + #plt.plot (values[dlb_id], values[k+4], '.', label=n) + +iplot += 1 +if avg_time_vs_impl: + if subplots: plt.subplot (Nrows, Ncols, iplot) + else: plt.figure (iplot) + plt.title ("Average time versus the implementation") + #plt.boxplot(values[4:], labels=fieldnames[4:], showmeans=True) + _mins = np.min (values[4:], axis=1) + _maxs = np.max (values[4:], axis=1) + _means = np.mean (values[4:], axis=1) + _stddev = np.std (values[4:], axis=1) + _sorted = sorted ( zip(fieldnames[4:], _means, _stddev, _mins, _maxs), key=lambda x: x[1]) + plt.errorbar( + [ f for f,m,s,l,u in _sorted], + [ m for f,m,s,l,u in _sorted], + [ s for f,m,s,l,u in _sorted], + fmt='go', linestyle='', label='mean and std deviation') + plt.plot ( + [ f for f,m,s,l,u in _sorted], + [ l for f,m,s,l,u in _sorted], + 'b+', ls='', label='min') + plt.plot ( + [ f for f,m,s,l,u in _sorted], + [ u for f,m,s,l,u in _sorted], + 'r+', ls='', label='max') + plt.ylabel('Time (ns)') + plt.xticks(rotation=20) + plt.legend() + +plt.show() diff --git a/test/test_fcl_octree.py b/test/scripts/octree.py similarity index 100% rename from test/test_fcl_octree.py rename to test/scripts/octree.py diff --git a/test/test_fcl_shape_mesh_consistency.cpp b/test/shape_mesh_consistency.cpp similarity index 99% rename from test/test_fcl_shape_mesh_consistency.cpp rename to test/shape_mesh_consistency.cpp index f2471bf25d43bdc4659288a6a128b79f78c29041..226f15898e91ddccbabef13a2804f26f9e653920 100644 --- a/test/test_fcl_shape_mesh_consistency.cpp +++ b/test/shape_mesh_consistency.cpp @@ -44,7 +44,7 @@ #include <hpp/fcl/shape/geometric_shape_to_BVH_model.h> #include <hpp/fcl/distance.h> #include <hpp/fcl/collision.h> -#include "test_fcl_utility.h" +#include "utility.h" using namespace hpp::fcl; diff --git a/test/test_fcl_simple.cpp b/test/simple.cpp similarity index 96% rename from test/test_fcl_simple.cpp rename to test/simple.cpp index 725f6ac657d43743e8a668afdc36f9428d962979..54cd915c89756a0165696e11f9a3154d0e7f574b 100644 --- a/test/test_fcl_simple.cpp +++ b/test/simple.cpp @@ -3,7 +3,7 @@ #include <boost/test/unit_test.hpp> #include <boost/utility/binary.hpp> -#include <hpp/fcl/intersect.h> +#include <hpp/fcl/internal/intersect.h> #include <hpp/fcl/collision.h> #include <hpp/fcl/BVH/BVH_model.h> #include "fcl_resources/config.h" diff --git a/test/test_fcl_sphere_capsule.cpp b/test/sphere_capsule.cpp similarity index 100% rename from test/test_fcl_sphere_capsule.cpp rename to test/sphere_capsule.cpp diff --git a/test/test_fcl_collision.cpp b/test/test_fcl_collision.cpp deleted file mode 100644 index 2330248b60a98519ab5afbb4562c78d7aae75562..0000000000000000000000000000000000000000 --- a/test/test_fcl_collision.cpp +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2011-2014, Willow Garage, Inc. - * Copyright (c) 2014-2015, Open Source Robotics Foundation - * 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 Open Source Robotics Foundation 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 */ - -#define BOOST_TEST_MODULE FCL_COLLISION -#define BOOST_TEST_DYN_LINK -#include <boost/test/unit_test.hpp> -#include <boost/utility/binary.hpp> - -#include <hpp/fcl/traversal/traversal_node_bvhs.h> -#include <hpp/fcl/traversal/traversal_node_setup.h> -#include <hpp/fcl/collision_node.h> -#include <hpp/fcl/collision.h> -#include <hpp/fcl/BV/BV.h> -#include <hpp/fcl/shape/geometric_shapes.h> -#include <hpp/fcl/narrowphase/narrowphase.h> -#include "test_fcl_utility.h" -#include "fcl_resources/config.h" -#include <boost/filesystem.hpp> - -using namespace hpp::fcl; - -template<typename BV> -bool collide_Test(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose = true); - -template<typename BV> -bool collide_Test2(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose = true); - -template<typename BV, typename TraversalNode> -bool collide_Test_Oriented(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose = true); - - -template<typename BV> -bool test_collide_func(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method); - -int num_max_contacts = std::numeric_limits<int>::max(); - -std::vector<Contact> global_pairs; -std::vector<Contact> global_pairs_now; - -BOOST_AUTO_TEST_CASE(OBB_Box_test) -{ - FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; - std::vector<Transform3f> rotate_transform; - generateRandomTransforms(r_extents, rotate_transform, 1); - - AABB aabb1; - aabb1.min_ = Vec3f(-600, -600, -600); - aabb1.max_ = Vec3f(600, 600, 600); - - OBB obb1; - convertBV(aabb1, rotate_transform[0], obb1); - Box box1; - Transform3f box1_tf; - constructBox(aabb1, rotate_transform[0], box1, box1_tf); - - FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; - std::size_t n = 1000; - - std::vector<Transform3f> transforms; - generateRandomTransforms(extents, transforms, n); - - for(std::size_t i = 0; i < transforms.size(); ++i) - { - AABB aabb; - aabb.min_ = aabb1.min_ * 0.5; - aabb.max_ = aabb1.max_ * 0.5; - - OBB obb2; - convertBV(aabb, transforms[i], obb2); - - Box box2; - Transform3f box2_tf; - constructBox(aabb, transforms[i], box2, box2_tf); - - GJKSolver_indep solver; - - bool overlap_obb = obb1.overlap(obb2); - bool overlap_box = solver.shapeIntersect(box1, box1_tf, box2, box2_tf, NULL, NULL, NULL); - - BOOST_CHECK(overlap_obb == overlap_box); - } -} - -BOOST_AUTO_TEST_CASE(OBB_shape_test) -{ - FCL_REAL r_extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; - std::vector<Transform3f> rotate_transform; - generateRandomTransforms(r_extents, rotate_transform, 1); - - AABB aabb1; - aabb1.min_ = Vec3f(-600, -600, -600); - aabb1.max_ = Vec3f(600, 600, 600); - - OBB obb1; - convertBV(aabb1, rotate_transform[0], obb1); - Box box1; - Transform3f box1_tf; - constructBox(aabb1, rotate_transform[0], box1, box1_tf); - - FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; - std::size_t n = 1000; - - std::vector<Transform3f> transforms; - generateRandomTransforms(extents, transforms, n); - - for(std::size_t i = 0; i < transforms.size(); ++i) - { - FCL_REAL len = (aabb1.max_[0] - aabb1.min_[0]) * 0.5; - OBB obb2; - GJKSolver_indep solver; - - { - Sphere sphere(len); - computeBV(sphere, transforms[i], obb2); - - bool overlap_obb = obb1.overlap(obb2); - bool overlap_sphere = solver.shapeIntersect(box1, box1_tf, sphere, transforms[i], NULL, NULL, NULL); - BOOST_CHECK(overlap_obb >= overlap_sphere); - } - - { - Capsule capsule(len, 2 * len); - computeBV(capsule, transforms[i], obb2); - - bool overlap_obb = obb1.overlap(obb2); - bool overlap_capsule = solver.shapeIntersect(box1, box1_tf, capsule, transforms[i], NULL, NULL, NULL); - BOOST_CHECK(overlap_obb >= overlap_capsule); - } - - { - Cone cone(len, 2 * len); - computeBV(cone, transforms[i], obb2); - - bool overlap_obb = obb1.overlap(obb2); - bool overlap_cone = solver.shapeIntersect(box1, box1_tf, cone, transforms[i], NULL, NULL, NULL); - BOOST_CHECK(overlap_obb >= overlap_cone); - } - - { - Cylinder cylinder(len, 2 * len); - computeBV(cylinder, transforms[i], obb2); - - bool overlap_obb = obb1.overlap(obb2); - bool overlap_cylinder = solver.shapeIntersect(box1, box1_tf, cylinder, transforms[i], NULL, NULL, NULL); - BOOST_CHECK(overlap_obb >= overlap_cylinder); - } - } -} - -BOOST_AUTO_TEST_CASE(OBB_AABB_test) -{ - FCL_REAL extents[] = {-1000, -1000, -1000, 1000, 1000, 1000}; - std::size_t n = 1000; - - std::vector<Transform3f> transforms; - generateRandomTransforms(extents, transforms, n); - - AABB aabb1; - aabb1.min_ = Vec3f(-600, -600, -600); - aabb1.max_ = Vec3f(600, 600, 600); - - OBB obb1; - convertBV(aabb1, Transform3f(), obb1); - - for(std::size_t i = 0; i < transforms.size(); ++i) - { - AABB aabb; - aabb.min_ = aabb1.min_ * 0.5; - aabb.max_ = aabb1.max_ * 0.5; - - AABB aabb2 = translate(aabb, transforms[i].getTranslation()); - - OBB obb2; - convertBV(aabb, Transform3f(transforms[i].getTranslation()), obb2); - - bool overlap_aabb = aabb1.overlap(aabb2); - bool overlap_obb = obb1.overlap(obb2); - if(overlap_aabb != overlap_obb) - { - std::cout << aabb1.min_ << " " << aabb1.max_ << std::endl; - std::cout << aabb2.min_ << " " << aabb2.max_ << std::endl; - std::cout << obb1.To << " " << obb1.extent << " " << obb1.axes << std::endl; - std::cout << obb2.To << " " << obb2.extent << " " << obb2.axes << std::endl; - } - - BOOST_CHECK(overlap_aabb == overlap_obb); - } - std::cout << std::endl; -} - -// This test -// 1. load two objects "env.obj" and "rob.obj" from directory -// fcl_resources, -// 2. generates n random transformation and for each of them denote tf, -// 2.1 performs a collision test where object 1 is in pose tf. All -// the contacts are stored in vector global_pairs. -// 2.2 performs a series of collision tests with the same object and -// the same poses using various methods and various types of bounding -// volumes. Each time the contacts are stored in vector global_pairs_now. -// -// The methods used to test collision are -// - collide_Test that calls function collide with tf for object1 pose and -// identity for the second object pose, -// - collide_Test2 that moves all vertices of object1 in pose tf and that -// calls function collide with identity for both object poses, -// -BOOST_AUTO_TEST_CASE(mesh_mesh) -{ - std::vector<Vec3f> p1, p2; - std::vector<Triangle> t1, t2; - boost::filesystem::path path(TEST_RESOURCES_DIR); - - loadOBJFile((path / "env.obj").string().c_str(), p1, t1); - loadOBJFile((path / "rob.obj").string().c_str(), p2, t2); - - std::vector<Transform3f> transforms; - FCL_REAL extents[] = {-3000, -3000, 0, 3000, 3000, 3000}; - std::size_t n = 10; - bool verbose = false; - - generateRandomTransforms(extents, transforms, n); - - // collision - for(std::size_t i = 0; i < transforms.size(); ++i) - { - Eigen::IOFormat f (Eigen::FullPrecision, 0, ", ", ",", "", "", "(", ")"); - - std::cerr - << "q1=" << transforms [i].getTranslation ().format (f) << "+" << - transforms [i].getQuatRotation ().coeffs ().format (f) << std::endl; - global_pairs.clear(); - global_pairs_now.clear(); - - // First test: constacts are stored in vector global_pairs - collide_Test<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - - collide_Test<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<24> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<18> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<KDOP<16> >(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<OBB, MeshCollisionTraversalNodeOBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<OBB, MeshCollisionTraversalNodeOBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<OBB, MeshCollisionTraversalNodeOBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<RSS, MeshCollisionTraversalNodeRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<RSS, MeshCollisionTraversalNodeRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<RSS, MeshCollisionTraversalNodeRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<RSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<OBB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<AABB>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - - collide_Test<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<kIOS, MeshCollisionTraversalNodekIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<kIOS, MeshCollisionTraversalNodekIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<kIOS, MeshCollisionTraversalNodekIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<kIOS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test2<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<OBBRSS, MeshCollisionTraversalNodeOBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<OBBRSS, MeshCollisionTraversalNodeOBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - collide_Test_Oriented<OBBRSS, MeshCollisionTraversalNodeOBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER, verbose); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_MEDIAN); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - - test_collide_func<OBBRSS>(transforms[i], p1, t1, p2, t2, SPLIT_METHOD_BV_CENTER); - assert (global_pairs.size() == global_pairs_now.size()); - for(std::size_t j = 0; j < global_pairs.size(); ++j) - { - BOOST_CHECK(global_pairs[j].b1 == global_pairs_now[j].b1); - BOOST_CHECK(global_pairs[j].b2 == global_pairs_now[j].b2); - } - } -} - - -template<typename BV> -bool collide_Test2(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose) -{ - BVHModel<BV> m1; - BVHModel<BV> m2; - m1.bv_splitter.reset(new BVSplitter<BV>(split_method)); - m2.bv_splitter.reset(new BVSplitter<BV>(split_method)); - - std::vector<Vec3f> vertices1_new(vertices1.size()); - for(unsigned int i = 0; i < vertices1_new.size(); ++i) - { - vertices1_new[i] = tf.transform(vertices1[i]); - } - - - m1.beginModel(); - m1.addSubModel(vertices1_new, triangles1); - m1.endModel(); - - m2.beginModel(); - m2.addSubModel(vertices2, triangles2); - m2.endModel(); - - Transform3f pose1, pose2; - - CollisionResult local_result; - CollisionRequest request (CONTACT, num_max_contacts); - MeshCollisionTraversalNode<BV> node (request); - - bool success = initialize <BV> (node, m1, pose1, m2, pose2, local_result); - assert (success); - - node.enable_statistics = verbose; - - collide(&node, request, local_result); - - if(local_result.numContacts() > 0) - { - if(global_pairs.size() == 0) - { - local_result.getContacts(global_pairs); - std::sort(global_pairs.begin(), global_pairs.end()); - } - else - { - local_result.getContacts(global_pairs_now); - std::sort(global_pairs_now.begin(), global_pairs_now.end()); - } - - - if(verbose) - std::cout << "in collision " << local_result.numContacts() << ": " << std::endl; - if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl; - return true; - } - else - { - if(verbose) std::cout << "collision free " << std::endl; - if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl; - return false; - } -} - -// Test collision between two sets of triangles -// first object is in pose tf, second object is in pose identity. -template<typename BV> -bool collide_Test(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose) -{ - BVHModel<BV> m1; - BVHModel<BV> m2; - m1.bv_splitter.reset(new BVSplitter<BV>(split_method)); - m2.bv_splitter.reset(new BVSplitter<BV>(split_method)); - - m1.beginModel(); - m1.addSubModel(vertices1, triangles1); - m1.endModel(); - - m2.beginModel(); - m2.addSubModel(vertices2, triangles2); - m2.endModel(); - - Transform3f pose1(tf), pose2; - - CollisionResult local_result; - CollisionRequest request (CONTACT, num_max_contacts); - MeshCollisionTraversalNode<BV> node (request); - - bool success = initialize <BV> (node, m1, pose1, m2, pose2, local_result); - assert (success); - - node.enable_statistics = verbose; - - collide(&node, request, local_result); - - if(local_result.numContacts() > 0) - { - if(global_pairs.size() == 0) - { - local_result.getContacts(global_pairs); - std::sort(global_pairs.begin(), global_pairs.end()); - } - else - { - local_result.getContacts(global_pairs_now); - std::sort(global_pairs_now.begin(), global_pairs_now.end()); - } - - if(verbose) - std::cout << "in collision " << local_result.numContacts() << ": " << std::endl; - if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl; - return true; - } - else - { - if(verbose) std::cout << "collision free " << std::endl; - if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl; - return false; - } -} - -// This function is the same as collide_Test, except that the type of traversal -// node is chosen via template argument. -template<typename BV, typename TraversalNode> -bool collide_Test_Oriented(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method, bool verbose) -{ - BVHModel<BV> m1; - BVHModel<BV> m2; - m1.bv_splitter.reset(new BVSplitter<BV>(split_method)); - m2.bv_splitter.reset(new BVSplitter<BV>(split_method)); - - m1.beginModel(); - m1.addSubModel(vertices1, triangles1); - m1.endModel(); - - m2.beginModel(); - m2.addSubModel(vertices2, triangles2); - m2.endModel(); - - Transform3f pose1(tf), pose2; - - CollisionResult local_result; - CollisionRequest request (CONTACT, num_max_contacts); - TraversalNode node (request); - bool success = initialize (node, (const BVHModel<BV>&)m1, pose1, - (const BVHModel<BV>&)m2, pose2, local_result); - assert (success); - - node.enable_statistics = verbose; - - collide(&node, request, local_result); - - if(local_result.numContacts() > 0) - { - if(global_pairs.size() == 0) - { - local_result.getContacts(global_pairs); - std::sort(global_pairs.begin(), global_pairs.end()); - } - else - { - local_result.getContacts(global_pairs_now); - std::sort(global_pairs_now.begin(), global_pairs_now.end()); - } - - if(verbose) - std::cout << "in collision " << local_result.numContacts() << ": " << std::endl; - if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl; - return true; - } - else - { - if(verbose) std::cout << "collision free " << std::endl; - if(verbose) std::cout << node.num_bv_tests << " " << node.num_leaf_tests << std::endl; - return false; - } -} - - -template<typename BV> -bool test_collide_func(const Transform3f& tf, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2, SplitMethodType split_method) -{ - BVHModel<BV> m1; - BVHModel<BV> m2; - m1.bv_splitter.reset(new BVSplitter<BV>(split_method)); - m2.bv_splitter.reset(new BVSplitter<BV>(split_method)); - - m1.beginModel(); - m1.addSubModel(vertices1, triangles1); - m1.endModel(); - - m2.beginModel(); - m2.addSubModel(vertices2, triangles2); - m2.endModel(); - - Transform3f pose1(tf), pose2; - - std::vector<Contact> contacts; - - CollisionRequest request (CONTACT, num_max_contacts); - CollisionResult result; - int num_contacts = collide(&m1, pose1, &m2, pose2, - request, result); - - result.getContacts(contacts); - - global_pairs_now.resize(num_contacts); - - for(int i = 0; i < num_contacts; ++i) - { - global_pairs_now[i].b1 = contacts[i].b1; - global_pairs_now[i].b2 = contacts[i].b2; - } - - std::sort(global_pairs_now.begin(), global_pairs_now.end()); - - if(num_contacts > 0) return true; - else return false; -} diff --git a/test/test_fcl_obb.cpp b/test/test_fcl_obb.cpp deleted file mode 100644 index 9e38af65e41144d0731dd9f7e4339c62e1c50cb0..0000000000000000000000000000000000000000 --- a/test/test_fcl_obb.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2014-2016, CNRS-LAAS - * Author: Florent Lamiraux - * 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 CNRS 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. - */ - -#define BOOST_TEST_MODULE FCL_DISTANCE_OBB -#define BOOST_TEST_DYN_LINK -#include <boost/test/unit_test.hpp> -#include <boost/utility/binary.hpp> - -#define CHECK_CLOSE_TO_0(x, eps) BOOST_CHECK_CLOSE ((x + 1.0), (1.0), (eps)) - -#include <boost/test/included/unit_test.hpp> -#include <hpp/fcl/narrowphase/narrowphase.h> - -#include "../src/BV/OBB.h" -#include "../src/distance_func_matrix.h" - -using hpp::fcl::FCL_REAL; - -struct Sample -{ - hpp::fcl::Matrix3f R; - hpp::fcl::Vec3f T; - hpp::fcl::Vec3f extent1; - hpp::fcl::Vec3f extent2; -}; - -struct Result -{ - bool overlap; - FCL_REAL distance; -}; - -BOOST_AUTO_TEST_CASE(obb_overlap) -{ - static const size_t nbSamples = 10000; - Sample sample [nbSamples]; - FCL_REAL range = 2; - FCL_REAL sumDistance = 0, sumDistanceLowerBound = 0; - for (std::size_t i=0; i<nbSamples; ++i) { - // sample unit quaternion - FCL_REAL u1 = (FCL_REAL) rand() / RAND_MAX; - FCL_REAL u2 = (FCL_REAL) rand() / RAND_MAX; - FCL_REAL u3 = (FCL_REAL) rand() / RAND_MAX; - - FCL_REAL q1 = sqrt (1-u1)*sin(2*M_PI*u2); - FCL_REAL q2 = sqrt (1-u1)*cos(2*M_PI*u2); - FCL_REAL q3 = sqrt (u1) * sin(2*M_PI*u3); - FCL_REAL q4 = sqrt (u1) * cos(2*M_PI*u3); - hpp::fcl::Quaternion3f (q1, q2, q3, q4).toRotation (sample [i].R); - - // sample translation - sample [i].T = hpp::fcl::Vec3f ((FCL_REAL) range * rand() / RAND_MAX, - (FCL_REAL) range * rand() / RAND_MAX, - (FCL_REAL) range * rand() / RAND_MAX); - - // sample extents - sample [i].extent1 = hpp::fcl::Vec3f ((FCL_REAL) rand() / RAND_MAX, - (FCL_REAL) rand() / RAND_MAX, - (FCL_REAL) rand() / RAND_MAX); - - sample [i].extent2 = hpp::fcl::Vec3f ((FCL_REAL) rand() / RAND_MAX, - (FCL_REAL) rand() / RAND_MAX, - (FCL_REAL) rand() / RAND_MAX); - } - - // Compute result for each function - Result resultDistance [nbSamples]; - Result resultDisjoint [nbSamples]; - Result resultDisjointAndLowerBound [nbSamples]; - - hpp::fcl::Transform3f tf1; - hpp::fcl::Transform3f tf2; - hpp::fcl::Box box1 (0, 0, 0); - hpp::fcl::Box box2 (0, 0, 0); - hpp::fcl::DistanceRequest request (false, 0, 0, hpp::fcl::GST_INDEP); - hpp::fcl::DistanceResult result; - FCL_REAL distance; - FCL_REAL squaredDistance; - timeval t0, t1; - hpp::fcl::GJKSolver_indep gjkSolver; - - // ShapeShapeDistance - gettimeofday (&t0, NULL); - for (std::size_t i=0; i<nbSamples; ++i) { - box1.side = 2*sample [i].extent1; - box2.side = 2*sample [i].extent2; - tf2.setTransform (sample [i].R, sample [i].T); - resultDistance [i].distance = - hpp::fcl::ShapeShapeDistance<hpp::fcl::Box, hpp::fcl::Box, hpp::fcl::GJKSolver_indep> - (&box1, tf1, &box2, tf2, &gjkSolver, request, result); - resultDistance [i].overlap = (resultDistance [i].distance < 0); - if (resultDistance [i].distance < 0) { - resultDistance [i].distance = 0; - } - result.clear (); - } - gettimeofday (&t1, NULL); - double t = (t1.tv_sec - t0.tv_sec) + 1e-6*(t1.tv_usec - t0.tv_usec + 0.); - std::cout << "Time for " << nbSamples - << " calls to ShapeShapeDistance (in seconds): " - << t << std::endl; - - // obbDisjointAndLowerBoundDistance - gettimeofday (&t0, NULL); - for (std::size_t i=0; i<nbSamples; ++i) { - resultDisjointAndLowerBound [i].overlap = - !obbDisjointAndLowerBoundDistance (sample [i].R, sample [i].T, - sample [i].extent1, - sample [i].extent2, - squaredDistance); - resultDisjointAndLowerBound [i].distance = sqrt (squaredDistance); - } - gettimeofday (&t1, NULL); - t = (t1.tv_sec - t0.tv_sec) + 1e-6*(t1.tv_usec - t0.tv_usec + 0.); - std::cout << "Time for " << nbSamples - << " calls to obbDisjointAndLowerBoundDistance" - << " (in seconds): " - << t << std::endl; - - gettimeofday (&t0, NULL); - for (std::size_t i=0; i<nbSamples; ++i) { - resultDisjoint [i].overlap = - !obbDisjoint (sample [i].R, sample [i].T, - sample [i].extent1, - sample [i].extent2); - resultDisjoint [i].distance = 0; - } - gettimeofday (&t1, NULL); - t = (t1.tv_sec - t0.tv_sec) + 1e-6*(t1.tv_usec - t0.tv_usec + 0.); - std::cout << "Time for " << nbSamples << " calls to obbDisjoint" - << " (in seconds): " - << t << std::endl; - - // Test correctness of results - bool res1, res2, res3; - for (std::size_t i=0; i<nbSamples; ++i) { - res1 = resultDisjoint [i].overlap; - res2 = resultDisjointAndLowerBound [i].overlap; - res3 = resultDistance [i].overlap; - sumDistanceLowerBound += resultDisjointAndLowerBound [i].distance; - sumDistance += resultDistance [i].distance; - -#if 0 - std::cout << "ShapeShapeDistance: overlap: " - << resultDistance [i].overlap - << ", distance: " << resultDistance [i].distance << std::endl; - std::cout << "disjoint: overlap: " - << resultDisjoint [i].overlap - << ", distance: " << resultDisjoint [i].distance << std::endl; - std::cout << "disjointAndLowerBound: overlap: " - << resultDisjointAndLowerBound [i].overlap - << ", distance: " << resultDisjointAndLowerBound [i].distance - << std::endl << std::endl; -#endif - BOOST_CHECK (res1 == res2); - BOOST_CHECK (res1 == res3); - BOOST_CHECK ((!res1 && resultDisjointAndLowerBound [i].distance > 0) || - (res1 && resultDisjointAndLowerBound [i].distance == 0)); - BOOST_CHECK (resultDisjointAndLowerBound [i].distance <= - resultDistance [i].distance); - } - std::cout << "Sum distances ShapeShapeDistance: " - << sumDistance << std::endl; - std::cout << "Sum distances obbDisjointAndLowerBoundDistance: " - << sumDistanceLowerBound << std::endl; -} diff --git a/test/test_fcl_utility.cpp b/test/utility.cpp similarity index 86% rename from test/test_fcl_utility.cpp rename to test/utility.cpp index 9a22a9dffeac0c854e64a551ed151c1529a71e98..a107faf800e65c71051f954a91e6124b10761609 100644 --- a/test/test_fcl_utility.cpp +++ b/test/utility.cpp @@ -1,16 +1,16 @@ -#include "test_fcl_utility.h" +#include "utility.h" #include <hpp/fcl/collision.h> #include <hpp/fcl/distance.h> #include <cstdio> #include <cstddef> #include <fstream> +#include <iostream> namespace hpp { namespace fcl { - Timer::Timer() { #ifdef _WIN32 @@ -94,6 +94,13 @@ double Timer::getElapsedTime() } +const Eigen::IOFormat vfmt = Eigen::IOFormat (Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "", ""); +const Eigen::IOFormat pyfmt = Eigen::IOFormat (Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "[", "]"); + +const Vec3f UnitX = Vec3f(1, 0, 0); +const Vec3f UnitY = Vec3f(0, 1, 0); +const Vec3f UnitZ = Vec3f(0, 0, 1); + FCL_REAL rand_interval(FCL_REAL rmin, FCL_REAL rmax) { FCL_REAL t = rand() / ((FCL_REAL)RAND_MAX + 1); @@ -332,51 +339,6 @@ void generateRandomTransforms(FCL_REAL extents[6], FCL_REAL delta_trans[3], FCL_ } } -void generateRandomTransform_ccd(FCL_REAL extents[6], std::vector<Transform3f>& transforms, std::vector<Transform3f>& transforms2, FCL_REAL delta_trans[3], FCL_REAL delta_rot, std::size_t n, - const std::vector<Vec3f>& /*vertices1*/, const std::vector<Triangle>& /*riangles1*/, - const std::vector<Vec3f>& /*vertices2*/, const std::vector<Triangle>& /*riangles2*/) -{ - transforms.resize(n); - transforms2.resize(n); - - for(std::size_t i = 0; i < n;) - { - FCL_REAL x = rand_interval(extents[0], extents[3]); - FCL_REAL y = rand_interval(extents[1], extents[4]); - FCL_REAL z = rand_interval(extents[2], extents[5]); - - const FCL_REAL pi = 3.1415926; - FCL_REAL a = rand_interval(0, 2 * pi); - FCL_REAL b = rand_interval(0, 2 * pi); - FCL_REAL c = rand_interval(0, 2 * pi); - - - Matrix3f R; - eulerToMatrix(a, b, c, R); - Vec3f T(x, y, z); - Transform3f tf(R, T); - - std::vector<std::pair<int, int> > results; - { - transforms[i] = tf; - - FCL_REAL deltax = rand_interval(-delta_trans[0], delta_trans[0]); - FCL_REAL deltay = rand_interval(-delta_trans[1], delta_trans[1]); - FCL_REAL deltaz = rand_interval(-delta_trans[2], delta_trans[2]); - - FCL_REAL deltaa = rand_interval(-delta_rot, delta_rot); - FCL_REAL deltab = rand_interval(-delta_rot, delta_rot); - FCL_REAL deltac = rand_interval(-delta_rot, delta_rot); - - Matrix3f R2; - eulerToMatrix(a + deltaa, b + deltab, c + deltac, R2); - Vec3f T2(x + deltax, y + deltay, z + deltaz); - transforms2[i].setTransform(R2, T2); - ++i; - } - } -} - bool defaultCollisionFunction(CollisionObject* o1, CollisionObject* o2, void* cdata_) { CollisionData* cdata = static_cast<CollisionData*>(cdata_); @@ -473,6 +435,15 @@ Quaternion3f makeQuat(FCL_REAL w, FCL_REAL x, FCL_REAL y, FCL_REAL z) return q; } +std::ostream& operator<< (std::ostream& os, const Transform3f& tf) +{ + return os << "[ " << + tf.getTranslation().format(vfmt) + << ", " + << tf.getQuatRotation().coeffs().format(vfmt) + << " ]" ; +} + } } // namespace hpp diff --git a/test/test_fcl_utility.h b/test/utility.h similarity index 89% rename from test/test_fcl_utility.h rename to test/utility.h index 80bab48ebdc7a24282a2543fe98a4d9fe8ddff86..dcefa68407e78a52928ba54432d8cc602445425d 100644 --- a/test/test_fcl_utility.h +++ b/test/utility.h @@ -92,6 +92,12 @@ private: #endif }; +extern const Eigen::IOFormat vfmt; +extern const Eigen::IOFormat pyfmt; +typedef Eigen::AngleAxis<FCL_REAL> AngleAxis; +extern const Vec3f UnitX; +extern const Vec3f UnitY; +extern const Vec3f UnitZ; /// @brief Load an obj mesh file void loadOBJFile(const char* filename, std::vector<Vec3f>& points, std::vector<Triangle>& triangles); @@ -112,12 +118,6 @@ void generateRandomTransforms(FCL_REAL extents[6], std::vector<Transform3f>& tra /// @brief Generate n random transforms whose translations are constrained by extents. Also generate another transforms2 which have additional random translation & rotation to the transforms generated. void generateRandomTransforms(FCL_REAL extents[6], FCL_REAL delta_trans[3], FCL_REAL delta_rot, std::vector<Transform3f>& transforms, std::vector<Transform3f>& transforms2, std::size_t n); -/// @brief Generate n random tranforms and transform2 with addtional random translation/rotation. The transforms and transform2 are used as initial and goal configurations for the first mesh. The second mesh is in I. This is used for continuous collision detection checking. -void generateRandomTransforms_ccd(FCL_REAL extents[6], std::vector<Transform3f>& transforms, std::vector<Transform3f>& transforms2, FCL_REAL delta_trans[3], FCL_REAL delta_rot, std::size_t n, - const std::vector<Vec3f>& vertices1, const std::vector<Triangle>& triangles1, - const std::vector<Vec3f>& vertices2, const std::vector<Triangle>& triangles2); - - /// @ brief Structure for minimum distance between two meshes and the corresponding nearest point pair struct DistanceRes { @@ -176,6 +176,8 @@ std::string getGJKSolverName(GJKSolverType solver_type); Quaternion3f makeQuat(FCL_REAL w, FCL_REAL x, FCL_REAL y, FCL_REAL z); +std::ostream& operator<< (std::ostream& os, const Transform3f& tf); + } } // namespace hpp diff --git a/travis_custom/custom_before_install_linux.sh b/travis_custom/custom_before_install_linux.sh new file mode 100755 index 0000000000000000000000000000000000000000..37285b80c268fc4b86cb0b224e4a407bbf44d8bb --- /dev/null +++ b/travis_custom/custom_before_install_linux.sh @@ -0,0 +1,11 @@ +# Add robotpkg +sudo sh -c "echo \"deb [arch=amd64] http://robotpkg.openrobots.org/packages/debian/pub $(lsb_release -cs) robotpkg\" >> /etc/apt/sources.list" +curl http://robotpkg.openrobots.org/packages/debian/robotpkg.key | sudo apt-key add - +sudo apt-get update + +# install eigenpy +sudo apt-get -qqy install robotpkg-py27-eigenpy + +# set environment variables +export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/opt/openrobots/lib/pkgconfig" +export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/opt/openrobots/lib" \ No newline at end of file diff --git a/travis_custom/custom_before_install_osx.sh b/travis_custom/custom_before_install_osx.sh new file mode 100755 index 0000000000000000000000000000000000000000..b2d8bb1153c3c8a083f8aad1548a883c0c225df0 --- /dev/null +++ b/travis_custom/custom_before_install_osx.sh @@ -0,0 +1,11 @@ +brew update + +# Add gepetto tap +brew tap gepetto/homebrew-gepetto + +# install eigenpy +brew install boost assimp eigen octomap eigenpy + +# set environment variables +export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/opt/openrobots/lib/pkgconfig" +export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/opt/openrobots/lib"