diff --git a/.github/workflows/macos-linux-conda.yml b/.github/workflows/macos-linux-conda.yml index ad139d6..fa05fda 100644 --- a/.github/workflows/macos-linux-conda.yml +++ b/.github/workflows/macos-linux-conda.yml @@ -13,7 +13,7 @@ jobs: os: ["ubuntu-latest", "macos-latest"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive @@ -24,6 +24,13 @@ jobs: environment-file: .github/workflows/conda/conda-env.yml python-version: 3.7 + - name: Install compilers on OSX + if: contains(matrix.os, 'macos') + shell: bash -l {0} + run: | + conda activate hpp-fcl + conda install compilers=1.4.2 -c conda-forge + - name: Install cmake and update conda shell: bash -l {0} run: | @@ -35,6 +42,7 @@ jobs: shell: bash -l {0} run: | conda activate hpp-fcl + conda list echo $CONDA_PREFIX mkdir build diff --git a/.github/workflows/ros_ci.yml b/.github/workflows/ros_ci.yml index 61895de..2441baa 100644 --- a/.github/workflows/ros_ci.yml +++ b/.github/workflows/ros_ci.yml @@ -14,23 +14,21 @@ jobs: - {ROS_DISTRO: melodic, PRERELEASE: false} - {ROS_DISTRO: noetic} - {ROS_DISTRO: foxy} - - {ROS_DISTRO: galactic} - {ROS_DISTRO: rolling} - - {ROS_DISTRO: humble} env: CCACHE_DIR: /github/home/.ccache # Enable ccache BUILDER: colcon PRERELEASE: true runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive # This step will fetch/store the directory used by ccache before/after the ci run - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: ${{ env.CCACHE_DIR }} key: ccache-${{ matrix.env.ROS_DISTRO }}-${{ matrix.env.ROS_REPO }} # Run industrial_ci - - uses: 'ros-industrial/industrial_ci@master' + - uses: 'ros-industrial/industrial_ci@6a8f546cbd31fbd5c9f77e3409265c8b39abc3d6' env: ${{ matrix.env }} diff --git a/.github/workflows/windows-conda-clang.yml b/.github/workflows/windows-conda-clang.yml index 9fda971..1a7eebd 100644 --- a/.github/workflows/windows-conda-clang.yml +++ b/.github/workflows/windows-conda-clang.yml @@ -15,7 +15,7 @@ jobs: compiler: clang-cl steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - uses: goanpeca/setup-miniconda@v1 diff --git a/.github/workflows/windows-conda-v142.yml b/.github/workflows/windows-conda-v142.yml index 9776b53..7c05a83 100644 --- a/.github/workflows/windows-conda-v142.yml +++ b/.github/workflows/windows-conda-v142.yml @@ -14,7 +14,7 @@ jobs: os: windows-2019 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - uses: goanpeca/setup-miniconda@v1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1bf4d00..cf17bb7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,8 @@ +ci: + autoupdate_branch: 'devel' repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v15.0.4 + rev: v15.0.7 hooks: - id: clang-format args: ['--style={BasedOnStyle: Google, SortIncludes: false}'] @@ -9,6 +11,6 @@ repos: hooks: - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 23.1.0 hooks: - id: black diff --git a/CMakeLists.txt b/CMakeLists.txt index 73e0231..58dd41d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # # Software License Agreement (BSD License) # -# Copyright (c) 2014-2022 CNRS-LAAS, INRIA +# Copyright (c) 2014-2023 CNRS-LAAS, INRIA # Author: Florent Lamiraux, Joseph Mirabel # All rights reserved. # @@ -267,7 +267,9 @@ add_subdirectory(src) if (BUILD_PYTHON_INTERFACE) add_subdirectory(python) endif () -add_subdirectory(test) +if(BUILD_TESTING) + add_subdirectory(test) +endif(BUILD_TESTING) pkg_config_append_libs("hpp-fcl") IF(HPP_FCL_HAS_OCTOMAP) diff --git a/INSTALL b/INSTALL index a70b862..0f327aa 100644 --- a/INSTALL +++ b/INSTALL @@ -3,7 +3,8 @@ Dependencies: ============ - Eigen - - Boost (thread, date_time, unit_test_framework, filesystem) + - Boost (thread, date_time, filesystem) + - assimp - octomap (optional dependency, available at http://octomap.github.com) - Qhull (optional dependency, available at http://www.qhull.org) @@ -12,6 +13,12 @@ collision detection with octrees will not be possible. For installation, CMake will also be needed (http://cmake.org). +Test dependencies: +================= + +When building tests (BUILD_TESTING=ON), additional dependencies are required: + - Boost (unit_test_framework, timer) + Install: ======= diff --git a/README.md b/README.md index 5598573..ba47568 100644 --- a/README.md +++ b/README.md @@ -3,25 +3,37 @@ HPP-FCL — An extension of the Flexible Collision Library

Pipeline status + Documentation Coverage report Conda Downloads Conda Version PyPI version

-[FCL](https://github.com/flexible-collision-library/fcl) was forked in 2015. Since then, a large part of the code has been rewritten or removed (for the unused part). +[FCL](https://github.com/flexible-collision-library/fcl) was forked in 2015. Since then, a large part of the code has been rewritten or removed (for the unused and untested part). The broadphase was reintroduced by J. Carpentier in 2022 based on the FCL version 0.7.0. +## New features + Compared to the original [FCL](https://github.com/flexible-collision-library/fcl) library, the main new features are: -- a dedicated implementation of the GJK algorithm (we do not rely anymore on [libccd](https://github.com/danfis/libccd)) -- the use of a safety margin when detecting collision +- a dedicated and efficient implementation of the GJK algorithm (we do not rely anymore on [libccd](https://github.com/danfis/libccd)) +- the support of safety margins for collision detection - an accelerated version of Collision Detection *à la Nesterov* which leads to increased performances (up to a factor 2). More details are available in this [paper](https://hal.archives-ouvertes.fr/hal-03662157/) - the computation of a lower bound of the distance between two objects when collision checking is performed and no collision is found - the implementation of Python bindings for easy code prototyping +- the support of height fields, capsule shapes, etc. - the fix of various bugs This project is now used in many robotics frameworks such as [Pinocchio](https://github.com/stack-of-tasks/pinocchio), an open-source software which implements efficient and versatile rigid body dynamics algorithms and the [Humanoid Path Planner](https://humanoid-path-planner.github.io/hpp-doc), an open-source software for Motion and Manipulation Planning. +## Performances + +Unlike the original FCL library, HPP-FCL implements the well-established GJK algorithm and [its variants](https://hal.archives-ouvertes.fr/hal-03662157/) for collision detection and distance computation. These implementations lead to state-of-the-art performances, as depicted by the figure below. In particular, you can observe that GJK-based approaches largely outperform solutions based on classic optimization solvers (e.g., QP solver like [ProxQP](https://github.com/Simple-Robotics/proxsuite)), notably for large geometries composed of tens or hundred of vertices. + +

+ HPP-FCL performances +

+ ## Acknowledgments The development of **HPP-FCL** is actively supported by the [Gepetto team](http://projects.laas.fr/gepetto/) [@LAAS-CNRS](http://www.laas.fr), the [Willow team](https://www.di.ens.fr/willow/) [@INRIA](http://www.inria.fr) and, to some extend, [Eureka Robotics](https://eurekarobotics.com/). diff --git a/cmake/.docs/cmake.py b/cmake/.docs/cmake.py index 1c4a7ac..d93852b 100644 --- a/cmake/.docs/cmake.py +++ b/cmake/.docs/cmake.py @@ -188,7 +188,6 @@ def _cmake_object_inventory(env, document, line, objtype, targetid): class CMakeTransform(Transform): - # Run this transform early since we insert nodes we want # treated as if they were written in the documents. default_priority = 210 @@ -281,7 +280,6 @@ def add_target_and_index(self, name, sig, signode): class CMakeXRefRole(XRefRole): - # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'. _re = re.compile(r"^(.+?)(\s*)(?$", re.DOTALL) _re_sub = re.compile(r"^([^()\s]+)\s*\(([^()]*)\)$", re.DOTALL) @@ -318,7 +316,6 @@ def __call__(self, typ, rawtext, text, *args, **keys): class CMakeXRefTransform(Transform): - # Run this transform early since we insert nodes we want # treated as if they were written in the documents, but # after the sphinx (210) and docutils (220) substitutions. diff --git a/cmake/.docs/conf.py b/cmake/.docs/conf.py index 2823914..b023327 100644 --- a/cmake/.docs/conf.py +++ b/cmake/.docs/conf.py @@ -49,7 +49,6 @@ class IfMode(Directive): - has_content = True required_arguments = 1 optional_arguments = 0 diff --git a/cmake/.pre-commit-config.yaml b/cmake/.pre-commit-config.yaml index 1be1f8d..d916008 100644 --- a/cmake/.pre-commit-config.yaml +++ b/cmake/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: check-useless-excludes - id: check-hooks-apply - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v15.0.4 + rev: v15.0.7 hooks: - id: clang-format args: [--style=Google] @@ -25,7 +25,7 @@ repos: - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 23.1.0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 diff --git a/cmake/base.cmake b/cmake/base.cmake index a3d2f4d..fed3c94 100644 --- a/cmake/base.cmake +++ b/cmake/base.cmake @@ -164,6 +164,8 @@ foreach(VARIABLE ${REQUIRED_VARIABLES}) endif(NOT DEFINED ${VARIABLE}) endforeach(VARIABLE) +message(STATUS "Configuring \"${PROJECT_NAME}\" (${PROJECT_URL})") + # If the project version number is not set, compute it automatically. if(NOT DEFINED PROJECT_VERSION) version_compute() diff --git a/cmake/cython/setup.in.py b/cmake/cython/setup.in.py index d520b3d..1571c19 100644 --- a/cmake/cython/setup.in.py +++ b/cmake/cython/setup.in.py @@ -177,7 +177,7 @@ def GenExtension(name): setup( name="@CYTHON_BINDINGS_PACKAGE_NAME@", - version="@CYTHON_BINDINGS_VERSION@-{}".format(version_hash), + version="@CYTHON_BINDINGS_VERSION@+{}".format(version_hash), ext_modules=extensions, packages=packages, package_data=package_data, diff --git a/cmake/doxygen.cmake b/cmake/doxygen.cmake index 8edadee..6a9c08f 100644 --- a/cmake/doxygen.cmake +++ b/cmake/doxygen.cmake @@ -35,6 +35,11 @@ # whether the documentation should be installed. Turning this to OFF does not # prevent the documentation generation. # +# .. variable:: BUILD_DOCUMENTATION +# +# This variable controls cmake searches for Doxygen and if the documentation is +# be generated. +# # .. _Doxygen: http://www.doxygen.nl # .rst: .. ifmode:: internal @@ -492,8 +497,20 @@ macro(_SETUP_PROJECT_DOCUMENTATION) if(NOT DOXYGEN_FOUND) message( - WARNING "Failed to find Doxygen, documentation will not be generated.") + STATUS "Failed to find Doxygen, documentation will not be generated.") else(NOT DOXYGEN_FOUND) + get_directory_property(has_parent_scope PARENT_DIRECTORY) + set(JRL_CMAKEMODULE_DOXYFILE_PATH "${PROJECT_BINARY_DIR}/doc/Doxyfile") + if(has_parent_scope) + set(DOXYGEN_FOUND + ${DOXYGEN_FOUND} + PARENT_SCOPE) + set(JRL_CMAKEMODULE_DOXYFILE_PATH + ${JRL_CMAKEMODULE_DOXYFILE_PATH} + PARENT_SCOPE) + endif(has_parent_scope) + unset(has_parent_scope) + _setup_doxygen_default_options() # Generate variable to be substitued in Doxyfile.in for dot use. if(DOXYGEN_DOT_FOUND) @@ -506,13 +523,13 @@ macro(_SETUP_PROJECT_DOCUMENTATION) # install, so put the target in ALL instead. add_custom_target( doc ALL - COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile + COMMAND ${DOXYGEN_EXECUTABLE} ${JRL_CMAKEMODULE_DOXYFILE_PATH} WORKING_DIRECTORY doc COMMENT "Generating Doxygen documentation") else(MSVC) add_custom_target( doc - COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile + COMMAND ${DOXYGEN_EXECUTABLE} ${JRL_CMAKEMODULE_DOXYFILE_PATH} WORKING_DIRECTORY doc COMMENT "Generating Doxygen documentation") @@ -525,20 +542,19 @@ macro(_SETUP_PROJECT_DOCUMENTATION) add_custom_target( generate-template-css COMMAND - ${DOXYGEN_EXECUTABLE} -w html - ${CMAKE_CURRENT_BINARY_DIR}/doc/header.html - ${CMAKE_CURRENT_BINARY_DIR}/doc/footer.html - ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen.css - BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/doc/header.html - ${CMAKE_CURRENT_BINARY_DIR}/doc/footer.html - ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen.css) + ${DOXYGEN_EXECUTABLE} -w html ${PROJECT_BINARY_DIR}/doc/header.html + ${PROJECT_BINARY_DIR}/doc/footer.html + ${PROJECT_BINARY_DIR}/doc/doxygen.css + BYPRODUCTS ${PROJECT_BINARY_DIR}/doc/header.html + ${PROJECT_BINARY_DIR}/doc/footer.html + ${PROJECT_BINARY_DIR}/doc/doxygen.css) add_dependencies(doc generate-template-css) _set_if_undefined(DOXYGEN_HTML_HEADER - "${CMAKE_CURRENT_BINARY_DIR}/doc/header.html") + "${PROJECT_BINARY_DIR}/doc/header.html") _set_if_undefined(DOXYGEN_HTML_FOOTER - "${CMAKE_CURRENT_BINARY_DIR}/doc/footer.html") + "${PROJECT_BINARY_DIR}/doc/footer.html") _set_if_undefined(DOXYGEN_HTML_STYLESHEET - "${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen.css") + "${PROJECT_BINARY_DIR}/doc/doxygen.css") else(DOXYGEN_USE_TEMPLATE_CSS) _set_if_undefined(DOXYGEN_HTML_FOOTER "${PROJECT_JRL_CMAKE_MODULE_DIR}/doxygen/footer.html") @@ -547,9 +563,9 @@ macro(_SETUP_PROJECT_DOCUMENTATION) endif(DOXYGEN_USE_TEMPLATE_CSS) add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag - ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen-html - COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile + OUTPUT ${PROJECT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag + ${PROJECT_BINARY_DIR}/doc/doxygen-html + COMMAND ${DOXYGEN_EXECUTABLE} ${JRL_CMAKEMODULE_DOXYFILE_PATH} WORKING_DIRECTORY doc COMMENT "Generating Doxygen documentation") @@ -558,23 +574,23 @@ macro(_SETUP_PROJECT_DOCUMENTATION) DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - ${CMAKE_CURRENT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag - ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen.log - ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen-html) + ${PROJECT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag + ${PROJECT_BINARY_DIR}/doc/doxygen.log + ${PROJECT_BINARY_DIR}/doc/doxygen-html) # Install MathJax minimal version. if("${DOXYGEN_USE_MATHJAX}" STREQUAL "YES") file(COPY ${PROJECT_JRL_CMAKE_MODULE_DIR}/doxygen/MathJax - DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen-html) + DESTINATION ${PROJECT_BINARY_DIR}/doc/doxygen-html) endif() # Install generated files. if(INSTALL_DOCUMENTATION) - if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag + if(EXISTS ${PROJECT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag) + install(FILES ${PROJECT_BINARY_DIR}/doc/${PROJECT_NAME}.doxytag DESTINATION ${CMAKE_INSTALL_DOCDIR}/doxygen-html) endif() - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen-html + install(DIRECTORY ${PROJECT_BINARY_DIR}/doc/doxygen-html DESTINATION ${CMAKE_INSTALL_DOCDIR}) if(EXISTS ${PROJECT_SOURCE_DIR}/doc/pictures) @@ -694,25 +710,24 @@ macro(_SETUP_PROJECT_DOCUMENTATION_FINALIZE) "${DOXYGEN_EXAMPLE_PATH} \"${PROJECT_SOURCE_DIR}/tests\"") endif() set(DOXYGEN_INCLUDE_PATH - "${DOXYGEN_INCLUDE_PATH} \"${CMAKE_BINARY_DIR}/include\"") + "${DOXYGEN_INCLUDE_PATH} \"${PROJECT_BINARY_DIR}/include\"") # Generate Doxyfile and Doxyfile.extra. if(EXISTS ${PROJECT_SOURCE_DIR}/doc/Doxyfile.extra.in) configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile.extra.in - ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile.extra @ONLY) + ${PROJECT_BINARY_DIR}/doc/Doxyfile.extra @ONLY) # Generate Doxyfile. - _setup_doxygen_config_file("${CMAKE_BINARY_DIR}/doc/Doxyfile") - file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile.extra - doxyfile_extra) + _setup_doxygen_config_file(${JRL_CMAKEMODULE_DOXYFILE_PATH}) + file(STRINGS ${PROJECT_BINARY_DIR}/doc/Doxyfile.extra doxyfile_extra) foreach(x ${doxyfile_extra}) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/doc/Doxyfile ${x} "\n") + file(APPEND ${JRL_CMAKEMODULE_DOXYFILE_PATH} ${x} "\n") endforeach(x in doxyfile_extra) else() # This is kept for bacward compatibility. It was the only thing left in # doxygen/Doxyfile.extra.in set(DOXYGEN_IMAGE_PATH "${PROJECT_SOURCE_DIR}/doc/pictures") # Generate Doxyfile. - _setup_doxygen_config_file("${CMAKE_BINARY_DIR}/doc/Doxyfile") + _setup_doxygen_config_file(${JRL_CMAKEMODULE_DOXYFILE_PATH}) endif() endif(DOXYGEN_FOUND) endmacro(_SETUP_PROJECT_DOCUMENTATION_FINALIZE) diff --git a/cmake/find-external/GMP/FindGMP.cmake b/cmake/find-external/GMP/FindGMP.cmake index 5d84d71..19b7040 100644 --- a/cmake/find-external/GMP/FindGMP.cmake +++ b/cmake/find-external/GMP/FindGMP.cmake @@ -10,15 +10,20 @@ find_path( NAMES gmp.h PATHS $ENV{GMPDIR} ${INCLUDE_INSTALL_DIR}) -find_library(GMP_LIBRARIES gmp PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR}) +find_library( + GMP_LIBRARIES + NAMES gmp + PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GMP DEFAULT_MSG GMP_INCLUDES GMP_LIBRARIES) # Set gmp target if(GMP_FOUND) - add_library(gmp INTERFACE IMPORTED ${GMP_LIBRARIES}) - set_target_properties(gmp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - "${GMP_INCLUDE_DIR}") + add_library(gmp SHARED IMPORTED) + set_target_properties( + gmp PROPERTIES IMPORTED_LOCATION ${GMP_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDE_DIR}") endif() -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GMP DEFAULT_MSG GMP_INCLUDES GMP_LIBRARIES) mark_as_advanced(GMP_INCLUDES GMP_LIBRARIES) diff --git a/cmake/find-external/MPFR/FindMPFR.cmake b/cmake/find-external/MPFR/FindMPFR.cmake index e11aac9..dc2c979 100644 --- a/cmake/find-external/MPFR/FindMPFR.cmake +++ b/cmake/find-external/MPFR/FindMPFR.cmake @@ -74,16 +74,17 @@ endif(MPFR_INCLUDES) find_library(MPFR_LIBRARIES mpfr PATHS $ENV{GMPDIR} ${LIB_INSTALL_DIR}) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MPFR DEFAULT_MSG MPFR_INCLUDES MPFR_LIBRARIES + MPFR_VERSION_OK) + # Set mpfr target if(MPFR_FOUND) - add_library(mpfr INTERFACE IMPORTED ${MPFR_LIBRARIES}) - set_target_properties(mpfr PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - "${MPFR_INCLUDE_DIR}") + add_library(mpfr SHARED IMPORTED) + set_target_properties( + mpfr PROPERTIES IMPORTED_LOCATION ${MPFR_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES "${MPFR_INCLUDE_DIR}") endif() # Epilogue - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MPFR DEFAULT_MSG MPFR_INCLUDES MPFR_LIBRARIES - MPFR_VERSION_OK) mark_as_advanced(MPFR_INCLUDES MPFR_LIBRARIES) diff --git a/cmake/logging.cmake b/cmake/logging.cmake index cbd6466..bab05a3 100644 --- a/cmake/logging.cmake +++ b/cmake/logging.cmake @@ -23,7 +23,13 @@ # # Logging file. -set(LOGGING_FILENAME "${CMAKE_BINARY_DIR}/config.log") +set(JRL_CMAKEMODULE_LOGGING_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/config.log") +get_directory_property(has_parent_scope PARENT_DIRECTORY) +if(has_parent_scope) + set(JRL_CMAKEMODULE_LOGGING_FILENAME + ${JRL_CMAKEMODULE_LOGGING_FILENAME} + PARENT_SCOPE) +endif(has_parent_scope) # Watched variables list. All watched variables final value will be displayed in # the logging file. @@ -68,20 +74,20 @@ function(LOGGING_INITIALIZE) endif() # Write logging file. - file(REMOVE ${LOGGING_FILENAME}) + file(REMOVE ${JRL_CMAKEMODULE_LOGGING_FILENAME}) - file(APPEND ${LOGGING_FILENAME} + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "This file contains any messages produced by compilers while\n" "running CMake, to aid debugging if configure makes a mistake.\n\n") file( - APPEND ${LOGGING_FILENAME} + APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "It was created by ${CMAKE_PROJECT_NAME} CMake configuration process " "${PROJECT_VERSION}, which was\n" "generated by CMake ${CMAKE_VERSION}.\n\n") file( - APPEND ${LOGGING_FILENAME} + APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "## --------- ##\n" "## Platform. ##\n" "## --------- ##\n" @@ -97,7 +103,7 @@ function(LOGGING_INITIALIZE) else() set(PATH undefined) endif() - file(APPEND ${LOGGING_FILENAME} "PATH " ${PATH} "\n\n") + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "PATH " ${PATH} "\n\n") if(NOT "$ENV{PKG_CONFIG_PATH}" STREQUAL "") string(REPLACE "${LIST_SEPARATOR}" "\nPKG_CONFIG_PATH " PKG_CONFIG_PATH @@ -105,7 +111,8 @@ function(LOGGING_INITIALIZE) else() set(PKG_CONFIG_PATH "undefined") endif() - file(APPEND ${LOGGING_FILENAME} "PKG_CONFIG_PATH " ${PKG_CONFIG_PATH} "\n\n") + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "PKG_CONFIG_PATH " + ${PKG_CONFIG_PATH} "\n\n") endfunction(LOGGING_INITIALIZE) @@ -116,7 +123,7 @@ endfunction(LOGGING_INITIALIZE) # function(LOGGING_FINALIZE) file( - APPEND ${LOGGING_FILENAME} + APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "## ---------------- ##\n" "## CMake variables. ##\n" "## ---------------- ##\n" @@ -160,7 +167,7 @@ function(LOGGING_FINALIZE) "CMAKE_SHARED_MODULE_SUFFIX = ${CMAKE_SHARED_MODULE_SUFFIX}\n" "\n") - file(APPEND ${LOGGING_FILENAME} + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "## ------------------ ##\n" "## Watched variables. ##\n" "## ------------------ ##\n" "\n") @@ -169,10 +176,10 @@ function(LOGGING_FINALIZE) if(NOT DEFINED ${VAR}) set(${VAR} "undefined") endif() - file(APPEND ${LOGGING_FILENAME} "${VAR} = ${${VAR}}\n") + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "${VAR} = ${${VAR}}\n") endforeach() - file(APPEND ${LOGGING_FILENAME} + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "## ---------------- ##\n" "## Watched targets. ##\n" "## ---------------- ##\n" "\n") @@ -180,8 +187,9 @@ function(LOGGING_FINALIZE) foreach(TARGET ${LOGGING_WATCHED_TARGETS}) foreach(PROPERTY ${LOGGING_WATCHED_TARGETS_PROPERTIES}) get_target_property(VALUE ${TARGET} ${PROPERTY}) - file(APPEND ${LOGGING_FILENAME} "${TARGET}_${PROPERTY} = ${VALUE}\n") + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} + "${TARGET}_${PROPERTY} = ${VALUE}\n") endforeach() - file(APPEND ${LOGGING_FILENAME} "\n") + file(APPEND ${JRL_CMAKEMODULE_LOGGING_FILENAME} "\n") endforeach() endfunction(LOGGING_FINALIZE) diff --git a/cmake/post-project.cmake b/cmake/post-project.cmake index d2012f2..ab5f941 100644 --- a/cmake/post-project.cmake +++ b/cmake/post-project.cmake @@ -38,7 +38,8 @@ else(${ARGC}) set(CMAKE_VERBOSE_MAKEFILE TRUE) endif(${ARGC}) -option(INSTALL_DOCUMENTATION "Generate and install the documentation" ON) +option(BUILD_DOCUMENTATION "Build the documentation." ON) +option(INSTALL_DOCUMENTATION "Install the documentation." ON) option(INSTALL_GENERATED_HEADERS "Generate and install standard headers" ON) option(INSTALL_PKG_CONFIG_FILE "Generate and install standard .pc file" ON) @@ -56,5 +57,7 @@ release_setup() _setup_project_deb() _setup_project_uninstall() _setup_project_pkg_config() -_setup_project_documentation() +if(BUILD_DOCUMENTATION) + _setup_project_documentation() +endif(BUILD_DOCUMENTATION) _setup_project_package_init() diff --git a/cmake/python.cmake b/cmake/python.cmake index aa5c452..f715def 100644 --- a/cmake/python.cmake +++ b/cmake/python.cmake @@ -339,9 +339,13 @@ macro(FINDPYTHON) if(PYTHON_EXPORT_DEPENDENCY) install_jrl_cmakemodules_file("python.cmake") - string(CONCAT PYTHON_EXPORT_DEPENDENCY_MACROS - "list(APPEND PYTHON_COMPONENTS ${PYTHON_COMPONENTS})\n" - "list(REMOVE_DUPLICATES PYTHON_COMPONENTS)\n" "FINDPYTHON()") + string( + CONCAT PYTHON_EXPORT_DEPENDENCY_MACROS + "list(APPEND PYTHON_COMPONENTS ${PYTHON_COMPONENTS})\n" + "list(REMOVE_DUPLICATES PYTHON_COMPONENTS)\n" + "if(NOT FINDPYTHON_ALREADY_CALLED)\n" + "FINDPYTHON()\n" + "endif()\n") endif() if(SEARCH_FOR_NUMPY) diff --git a/cmake/test.cmake b/cmake/test.cmake index 884cf89..d2877fe 100644 --- a/cmake/test.cmake +++ b/cmake/test.cmake @@ -158,6 +158,7 @@ macro(ADD_PYTHON_UNIT_TEST NAME SOURCE) OUTPUT_VARIABLE PATHSEP OUTPUT_STRIP_TRAILING_WHITESPACE) + list(REMOVE_DUPLICATES PYTHONPATH) if(WIN32) # ensure that severals paths stay together as ENV variable PYTHONPATH when # passed to python test via PROPERTIES diff --git a/doc/images/hpp-fcl-performances.jpg b/doc/images/hpp-fcl-performances.jpg new file mode 100644 index 0000000..a90a945 Binary files /dev/null and b/doc/images/hpp-fcl-performances.jpg differ diff --git a/include/hpp/fcl/narrowphase/gjk.h b/include/hpp/fcl/narrowphase/gjk.h index 45a051b..cce65d0 100644 --- a/include/hpp/fcl/narrowphase/gjk.h +++ b/include/hpp/fcl/narrowphase/gjk.h @@ -162,7 +162,7 @@ struct HPP_FCL_DLLAPI GJK { /// Valid: GJK converged and the shapes are not in collision. /// Inside: GJK converged and the shapes are in collision. /// Failed: GJK did not converge. - enum Status { Valid, Inside, Failed }; + enum Status { Valid, Inside, Failed, EarlyStopped }; MinkowskiDiff const* shape; Vec3f ray; diff --git a/include/hpp/fcl/narrowphase/narrowphase.h b/include/hpp/fcl/narrowphase/narrowphase.h index f93a0e9..9abdcd9 100644 --- a/include/hpp/fcl/narrowphase/narrowphase.h +++ b/include/hpp/fcl/narrowphase/narrowphase.h @@ -300,6 +300,11 @@ struct HPP_FCL_DLLAPI GJKSolver { p1 = tf1.transform(p1); p2 = tf1.transform(p2); return true; + } else if (gjk_status == details::GJK::EarlyStopped) { + distance = gjk.distance; + p1 = p2 = normal = + Vec3f::Constant(std::numeric_limits::quiet_NaN()); + return true; } else { assert(gjk_status == details::GJK::Inside); if (gjk.hasPenetrationInformation(shape)) { diff --git a/package.xml b/package.xml index 6404db1..34a7fce 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ hpp-fcl - 2.2.0 + 2.3.0 An extension of the Flexible Collision Library. diff --git a/src/narrowphase/gjk.cpp b/src/narrowphase/gjk.cpp index 9a61228..4d4b137 100644 --- a/src/narrowphase/gjk.cpp +++ b/src/narrowphase/gjk.cpp @@ -715,6 +715,7 @@ GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess, FCL_REAL omega = dir.dot(w) / dir.norm(); if (omega > upper_bound) { distance = omega - inflation; + status = EarlyStopped; break; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6056713..a812543 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,11 +23,7 @@ endmacro(add_fcl_test) include_directories(${CMAKE_CURRENT_BINARY_DIR}) -IF(BUILD_TESTING) - add_library(utility STATIC utility.cpp) -ELSE() - add_library(utility STATIC EXCLUDE_FROM_ALL utility.cpp) -ENDIF() +add_library(utility STATIC utility.cpp) target_link_libraries(utility PUBLIC ${PROJECT_NAME}) add_fcl_test(math math.cpp) @@ -45,6 +41,7 @@ SET_TESTS_PROPERTIES(frontlist PROPERTIES TIMEOUT 7200) # 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(box_box_collision box_box_collision.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) @@ -73,11 +70,7 @@ add_fcl_test(broadphase_collision_1 broadphase_collision_1.cpp) add_fcl_test(broadphase_collision_2 broadphase_collision_2.cpp) ## Benchmark -IF(BUILD_TESTING) - add_executable(test-benchmark benchmark.cpp) -ELSE() - add_executable(test-benchmark EXCLUDE_FROM_ALL benchmark.cpp) -ENDIF() +add_executable(test-benchmark benchmark.cpp) target_link_libraries(test-benchmark PUBLIC utility diff --git a/test/box_box_collision.cpp b/test/box_box_collision.cpp new file mode 100644 index 0000000..b3276a1 --- /dev/null +++ b/test/box_box_collision.cpp @@ -0,0 +1,47 @@ +#define BOOST_TEST_MODULE BOX_BOX_COLLISION +#include + +#include +#include +#include +#include + +#include "utility.h" + +using hpp::fcl::Box; +using hpp::fcl::collide; +using hpp::fcl::CollisionRequest; +using hpp::fcl::CollisionResult; +using hpp::fcl::ComputeCollision; +using hpp::fcl::FCL_REAL; +using hpp::fcl::Transform3f; +using hpp::fcl::Vec3f; + +BOOST_AUTO_TEST_CASE(box_box_collision) { + // Define boxes + Box shape1(1, 1, 1); + Box shape2(1, 1, 1); + + // Define transforms + Transform3f T1 = Transform3f::Identity(); + Transform3f T2 = Transform3f::Identity(); + + // Compute collision + CollisionRequest req; + req.enable_cached_gjk_guess = true; + req.distance_upper_bound = 1e-6; + CollisionResult res; + ComputeCollision collide_functor(&shape1, &shape2); + + T1.setTranslation(Vec3f(0, 0, 0)); + res.clear(); + BOOST_CHECK(collide(&shape1, T1, &shape2, T2, req, res) == true); + res.clear(); + BOOST_CHECK(collide_functor(T1, T2, req, res) == true); + + T1.setTranslation(Vec3f(2, 0, 0)); + res.clear(); + BOOST_CHECK(collide(&shape1, T1, &shape2, T2, req, res) == false); + res.clear(); + BOOST_CHECK(collide_functor(T1, T2, req, res) == false); +}