first
This commit is contained in:
commit
a57eba035e
|
@ -0,0 +1,2 @@
|
||||||
|
Nate Koenig <nkoenig@osrfoundation.org>
|
||||||
|
John Hsu <hsu@osrfoundation.org>
|
|
@ -0,0 +1,428 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.6 FATAL_ERROR)
|
||||||
|
|
||||||
|
if(COMMAND CMAKE_POLICY)
|
||||||
|
CMAKE_POLICY(SET CMP0003 NEW)
|
||||||
|
CMAKE_POLICY(SET CMP0004 NEW)
|
||||||
|
endif(COMMAND CMAKE_POLICY)
|
||||||
|
|
||||||
|
project (Gazebo)
|
||||||
|
string (TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
|
||||||
|
string (TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER)
|
||||||
|
|
||||||
|
set (GAZEBO_MAJOR_VERSION 7)
|
||||||
|
set (GAZEBO_MINOR_VERSION 14)
|
||||||
|
# The patch version may have been bumped for prerelease purposes; be sure to
|
||||||
|
# check gazebo-release/ubuntu/debian/changelog@default to determine what the
|
||||||
|
# next patch version should be for a regular release.
|
||||||
|
set (GAZEBO_PATCH_VERSION 0)
|
||||||
|
|
||||||
|
set (GAZEBO_VERSION ${GAZEBO_MAJOR_VERSION}.${GAZEBO_MINOR_VERSION})
|
||||||
|
set (GAZEBO_VERSION_FULL ${GAZEBO_MAJOR_VERSION}.${GAZEBO_MINOR_VERSION}.${GAZEBO_PATCH_VERSION})
|
||||||
|
|
||||||
|
message (STATUS "${PROJECT_NAME} version ${GAZEBO_VERSION_FULL}")
|
||||||
|
|
||||||
|
set (gazebo_cmake_dir ${PROJECT_SOURCE_DIR}/cmake CACHE PATH "Location of CMake scripts")
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Package Creation:
|
||||||
|
include (${gazebo_cmake_dir}/gazebo_cpack.cmake)
|
||||||
|
set (CPACK_PACKAGE_VERSION "${GAZEBO_VERSION_FULL}")
|
||||||
|
set (CPACK_PACKAGE_VERSION_MAJOR "${GAZEBO_MAJOR_VERSION}")
|
||||||
|
set (CPACK_PACKAGE_VERSION_MINOR "${GAZEBO_MINOR_VERSION}")
|
||||||
|
set (CPACK_PACKAGE_VERSION_PATCH "${GAZEBO_PATCH_VERSION}")
|
||||||
|
|
||||||
|
if (CPACK_GENERATOR)
|
||||||
|
message(STATUS "Found CPack generators: ${CPACK_GENERATOR}")
|
||||||
|
|
||||||
|
configure_file("${gazebo_cmake_dir}/cpack_options.cmake.in" ${GAZEBO_CPACK_CFG_FILE} @ONLY)
|
||||||
|
set(CPACK_PROJECT_CONFIG_FILE ${GAZEBO_CPACK_CFG_FILE})
|
||||||
|
include (CPack)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# If we're configuring only to package source, stop here
|
||||||
|
if (PACKAGE_SOURCE_ONLY)
|
||||||
|
message(WARNING "Configuration was done in PACKAGE_SOURCE_ONLY mode. You can build a tarball (make package_source), but nothing else.")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
add_subdirectory(doc)
|
||||||
|
|
||||||
|
# Configure documentation uploader
|
||||||
|
configure_file("${CMAKE_SOURCE_DIR}/cmake/upload_doc.sh.in"
|
||||||
|
${CMAKE_BINARY_DIR}/upload_doc.sh @ONLY)
|
||||||
|
|
||||||
|
# If we're configuring only to build docs, stop here
|
||||||
|
if (DOC_ONLY)
|
||||||
|
message(WARNING "Configuration was done in DOC_ONLY mode. You can build documentation (make doc), but nothing else.")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
# Use GNUInstallDirst to get canonical paths
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
# with -fPIC
|
||||||
|
if(UNIX AND NOT WIN32)
|
||||||
|
set (CMAKE_INSTALL_PREFIX "/usr" CACHE STRING "Install Prefix")
|
||||||
|
find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin )
|
||||||
|
if(CMAKE_UNAME)
|
||||||
|
exec_program(uname ARGS -m OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR} CACHE INTERNAL
|
||||||
|
"processor type (i386 and x86_64)")
|
||||||
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||||
|
ADD_DEFINITIONS(-fPIC)
|
||||||
|
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||||
|
endif(CMAKE_UNAME)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
|
||||||
|
|
||||||
|
|
||||||
|
# developer's option to cache PKG_CONFIG_PATH and
|
||||||
|
# LD_LIBRARY_PATH for local installs
|
||||||
|
if(PKG_CONFIG_PATH)
|
||||||
|
set (ENV{PKG_CONFIG_PATH} ${PKG_CONFIG_PATH}:$ENV{PKG_CONFIG_PATH})
|
||||||
|
endif()
|
||||||
|
if(LD_LIBRARY_PATH)
|
||||||
|
set (ENV{LD_LIBRARY_PATH} ${LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/gazebo-${GAZEBO_MAJOR_VERSION}/gazebo")
|
||||||
|
set (LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
set (BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
|
set (BUILD_GAZEBO ON CACHE INTERNAL "Build Gazebo" FORCE)
|
||||||
|
set (build_errors "" CACHE INTERNAL "build errors" FORCE)
|
||||||
|
set (build_warnings "" CACHE INTERNAL "build warnings" FORCE)
|
||||||
|
|
||||||
|
|
||||||
|
set (MIN_OGRE_VERSION 1.7.4 CACHE INTERNAL "Ogre version requirement" FORCE)
|
||||||
|
set (MIN_BOOST_VERSION 1.40.0 CACHE INTERNAL "Boost min version requirement" FORCE)
|
||||||
|
|
||||||
|
set (FREEIMAGE_MAJOR_VERSION 3 CACHE INTERNAL "FreeImage major version requirement" FORCE)
|
||||||
|
set (FREEIMAGE_MINOR_VERSION 9 CACHE INTERNAL "FreeImage minor version requirement" FORCE)
|
||||||
|
set (MIN_FREEIMAGE_VERSION ${FREEIMAGE_MAJOR_VERSION}.${FREEIMAGE_MINOR_VERSION}.0 CACHE INTERNAL "FreeImage version requirement" FORCE)
|
||||||
|
|
||||||
|
include (${gazebo_cmake_dir}/DissectVersion.cmake)
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# Check for low memory version to use in some tests
|
||||||
|
if(NOT DEFINED USE_LOW_MEMORY_TESTS)
|
||||||
|
set (USE_LOW_MEMORY_TESTS FALSE)
|
||||||
|
message (STATUS "High memory tests: enabled")
|
||||||
|
else()
|
||||||
|
set (USE_LOW_MEMORY_TEST TRUE)
|
||||||
|
message (STATUS "High memory tests: disabled, low memory versions will be used")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
######################################
|
||||||
|
# Enable screen tests by default
|
||||||
|
if(NOT DEFINED ENABLE_SCREEN_TESTS)
|
||||||
|
set(ENABLE_SCREEN_TESTS TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message (STATUS "\n\n====== Finding 3rd Party Packages ======")
|
||||||
|
include (${gazebo_cmake_dir}/SearchForStuff.cmake)
|
||||||
|
message (STATUS "----------------------------------------\n")
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# Define some variables that are going to be used in two places:
|
||||||
|
# 1. In CMake code to pass preprocessor definitions to certain source files
|
||||||
|
# (especially in common/CMakeLists.txt).
|
||||||
|
# 2. In the generation of cmake/setup.sh from cmake/setup.sh.in
|
||||||
|
set(GAZEBO_DEFAULT_MASTER_HOST localhost)
|
||||||
|
set(GAZEBO_DEFAULT_MASTER_PORT 11345)
|
||||||
|
set(GAZEBO_PLUGIN_PATH ${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/gazebo-${GAZEBO_MAJOR_VERSION}/plugins)
|
||||||
|
set(GAZEBO_MODEL_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gazebo-${GAZEBO_MAJOR_VERSION}/models)
|
||||||
|
set(GAZEBO_RESOURCE_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gazebo-${GAZEBO_MAJOR_VERSION})
|
||||||
|
set(GAZEBO_MODEL_DATABASE_URI http://models.gazebosim.org)
|
||||||
|
set(OGRE_RESOURCE_PATH ${OGRE_PLUGINDIR})
|
||||||
|
# Seems that OGRE_PLUGINDIR can end in a newline, which will cause problems when
|
||||||
|
# we pass it to the compiler later.
|
||||||
|
string(REPLACE "\n" "" OGRE_RESOURCE_PATH ${OGRE_RESOURCE_PATH})
|
||||||
|
|
||||||
|
|
||||||
|
# Check for DRI capable Display
|
||||||
|
include (${gazebo_cmake_dir}/CheckDRIDisplay.cmake)
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
MESSAGE(STATUS "Checking gazebo build type")
|
||||||
|
# Set the default build type
|
||||||
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
set (CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
|
||||||
|
"Choose the type of build, options are: Debug Release RelWithDebInfo Profile Check" FORCE)
|
||||||
|
endif (NOT CMAKE_BUILD_TYPE)
|
||||||
|
# TODO: still convert to uppercase to keep backwards compatibility with
|
||||||
|
# uppercase old supported and deprecated modes
|
||||||
|
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPERCASE)
|
||||||
|
|
||||||
|
if (NOT DEFINED HDF5_INSTRUMENT)
|
||||||
|
set (HDF5_INSTRUMENT FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set (BUILD_TYPE_PROFILE FALSE)
|
||||||
|
set (BUILD_TYPE_RELEASE FALSE)
|
||||||
|
set (BUILD_TYPE_RELWITHDEBINFO FALSE)
|
||||||
|
set (BUILD_TYPE_DEBUG FALSE)
|
||||||
|
set (BUILD_TYPE_COVERAGE FALSE)
|
||||||
|
|
||||||
|
if ("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "PROFILE")
|
||||||
|
set (BUILD_TYPE_PROFILE TRUE)
|
||||||
|
elseif ("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "RELEASE")
|
||||||
|
set (BUILD_TYPE_RELEASE TRUE)
|
||||||
|
elseif ("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "RELWITHDEBINFO")
|
||||||
|
set (BUILD_TYPE_RELWITHDEBINFO TRUE)
|
||||||
|
elseif ("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "DEBUG")
|
||||||
|
set (BUILD_TYPE_DEBUG TRUE)
|
||||||
|
elseif ("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "COVERAGE")
|
||||||
|
BUILD_WARNING ("Simbody physics engine not supported during Coverage builds (issue #1849).")
|
||||||
|
set (HAVE_SIMBODY FALSE)
|
||||||
|
BUILD_WARNING ("DART physics engine not supported during Coverage builds (issue #1160).")
|
||||||
|
set (HAVE_DART FALSE)
|
||||||
|
set (BUILD_TYPE_COVERAGE TRUE)
|
||||||
|
include (${gazebo_cmake_dir}/CodeCoverage.cmake)
|
||||||
|
setup_target_for_coverage(coverage coverage)
|
||||||
|
else()
|
||||||
|
build_error("CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} unknown. Valid options are: Debug Release RelWithDebInfo Profile Check")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# Handle CFlags
|
||||||
|
# USE_UPSTREAM_CFLAGS (default TRUE)
|
||||||
|
if(NOT DEFINED USE_UPSTREAM_CFLAGS)
|
||||||
|
set (USE_UPSTREAM_CFLAGS True)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
unset (CMAKE_C_FLAGS_ALL CACHE)
|
||||||
|
|
||||||
|
# USE_HOST_CFLAGS (default TRUE)
|
||||||
|
# Will check building host machine for proper cflags
|
||||||
|
if(NOT DEFINED USE_HOST_CFLAGS OR USE_HOST_CFLAGS)
|
||||||
|
message(STATUS "Enable host CFlags")
|
||||||
|
include (${gazebo_cmake_dir}/HostCFlags.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Will use predefined gazebo developers cflags
|
||||||
|
# this needs to be called after HostCFlags
|
||||||
|
if(USE_UPSTREAM_CFLAGS)
|
||||||
|
# use gazebo own set of flags
|
||||||
|
unset (CMAKE_CXX_FLAGS CACHE)
|
||||||
|
message(STATUS "Enable upstream CFlags")
|
||||||
|
include(${gazebo_cmake_dir}/DefaultCFlags.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if warning options are avaliable for the compiler and return WARNING_CXX_FLAGS variable
|
||||||
|
filter_valid_compiler_flags(-Wall -Wextra -Wno-long-long -Wno-unused-value -Wno-unused-value
|
||||||
|
-Wno-unused-value -Wno-unused-value -Wfloat-equal -Wshadow
|
||||||
|
-Winit-self -Wswitch-default -Wmissing-include-dirs -pedantic)
|
||||||
|
|
||||||
|
# Check and add visibility hidden by default. Only in UNIX
|
||||||
|
# Windows and MacosX does not handled properly the hidden compilation
|
||||||
|
if (UNIX AND NOT APPLE)
|
||||||
|
filter_valid_compiler_flags(-fvisibility=hidden -fvisibility-inlines-hidden)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# Unable to be filtered flags (failing due to limitations in filter_valid_compiler_warnings)
|
||||||
|
# Handling exceptions rightly
|
||||||
|
set(UNFILTERED_FLAGS "/EHsc")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Visual Studio enables c++11 support by default
|
||||||
|
if (NOT MSVC)
|
||||||
|
set(UNFILTERED_FLAGS "-std=c++11")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VALID_CXX_FLAGS} ${UNFILTERED_FLAGS}")
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# OS Specific initialization
|
||||||
|
if (UNIX)
|
||||||
|
gz_setup_unix()
|
||||||
|
else (WIN32)
|
||||||
|
gz_setup_windows()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
gz_setup_apple()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Main includes for compilation
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
|
||||||
|
include_directories(SYSTEM
|
||||||
|
${IGNITION-MATH_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Configure 3rd Party Packages after OS Specific initialization
|
||||||
|
message (STATUS "\n\n====== Configuring 3rd Party Packages ======")
|
||||||
|
add_subdirectory(deps)
|
||||||
|
message (STATUS "----------------------------------------\n")
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Print warnings and errors
|
||||||
|
if ( build_warnings )
|
||||||
|
message(STATUS "BUILD WARNINGS")
|
||||||
|
foreach (msg ${build_warnings})
|
||||||
|
message(STATUS ${msg})
|
||||||
|
endforeach ()
|
||||||
|
message(STATUS "END BUILD WARNINGS\n")
|
||||||
|
endif (build_warnings)
|
||||||
|
|
||||||
|
########### Add uninstall target ###############
|
||||||
|
configure_file(
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
|
||||||
|
IMMEDIATE @ONLY)
|
||||||
|
add_custom_target(uninstall
|
||||||
|
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake")
|
||||||
|
|
||||||
|
if (build_errors)
|
||||||
|
message(STATUS "BUILD ERRORS: These must be resolved before compiling.")
|
||||||
|
foreach (msg ${build_errors})
|
||||||
|
message(STATUS ${msg})
|
||||||
|
endforeach ()
|
||||||
|
message(STATUS "END BUILD ERRORS\n")
|
||||||
|
message (FATAL_ERROR "Errors encountered in build. Please see the BUILD ERRORS above.")
|
||||||
|
else (build_errors)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Write the config.h file
|
||||||
|
configure_file (${gazebo_cmake_dir}/gazebo_config.h.in ${PROJECT_BINARY_DIR}/gazebo/gazebo_config.h)
|
||||||
|
gz_install_includes("" ${PROJECT_BINARY_DIR}/gazebo/gazebo_config.h)
|
||||||
|
|
||||||
|
configure_file(${CMAKE_SOURCE_DIR}/cmake/setup.sh.in ${PROJECT_BINARY_DIR}/setup.sh @ONLY)
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/setup.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gazebo-${GAZEBO_MAJOR_VERSION}/)
|
||||||
|
# Also install the setup.sh in an unversioned location
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/setup.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/gazebo/)
|
||||||
|
|
||||||
|
|
||||||
|
if (DEFINED CMAKE_CXX_FLAGS)
|
||||||
|
message (STATUS "Custom CFlags:${CMAKE_CXX_FLAGS}")
|
||||||
|
else()
|
||||||
|
message (STATUS "Use default CFlags")
|
||||||
|
endif()
|
||||||
|
message (STATUS "Build Type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
message (STATUS "Install path: ${CMAKE_INSTALL_PREFIX}")
|
||||||
|
|
||||||
|
if (BUILD_GAZEBO)
|
||||||
|
set(TEST_TYPE "UNIT")
|
||||||
|
add_subdirectory(gazebo)
|
||||||
|
add_subdirectory(media)
|
||||||
|
add_subdirectory(test)
|
||||||
|
add_subdirectory(tools)
|
||||||
|
add_subdirectory(plugins)
|
||||||
|
add_subdirectory(interfaces)
|
||||||
|
add_subdirectory(worlds)
|
||||||
|
add_subdirectory(models)
|
||||||
|
endif (BUILD_GAZEBO)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Make the package config files
|
||||||
|
set (pkgconfig_files gazebo_ode gazebo_transport gazebo)
|
||||||
|
|
||||||
|
# set boost pkgconfig cflags
|
||||||
|
set (Boost_PKGCONFIG_CFLAGS ${Boost_INCLUDE_DIRS})
|
||||||
|
if (NOT "${Boost_PKGCONFIG_CFLAGS}" STREQUAL "")
|
||||||
|
set (Boost_PKGCONFIG_CFLAGS "-I${Boost_PKGCONFIG_CFLAGS}")
|
||||||
|
endif (NOT "${Boost_PKGCONFIG_CFLAGS}" STREQUAL "")
|
||||||
|
string (REPLACE ";" " -I" Boost_PKGCONFIG_CFLAGS "${Boost_PKGCONFIG_CFLAGS}")
|
||||||
|
|
||||||
|
# set boost pkgconfig libs
|
||||||
|
set (Boost_PKGCONFIG_LIBS ${Boost_LIBRARY_DIRS})
|
||||||
|
if (NOT "${Boost_PKGCONFIG_LIBS}" STREQUAL "")
|
||||||
|
set (Boost_PKGCONFIG_LIBS "-L${Boost_PKGCONFIG_LIBS}")
|
||||||
|
endif(NOT "${Boost_PKGCONFIG_LIBS}" STREQUAL "")
|
||||||
|
string (REPLACE ";" " -L" Boost_PKGCONFIG_LIBS "${Boost_PKGCONFIG_LIBS}")
|
||||||
|
|
||||||
|
foreach (b ${Boost_LIBRARIES})
|
||||||
|
get_filename_component(bname ${b} NAME_WE)
|
||||||
|
# Prefix always -l
|
||||||
|
set (bname "-l${bname}")
|
||||||
|
# Remove the prefix lib (not always present, like in pthread)
|
||||||
|
string (REPLACE "lib" "" bname "${bname}")
|
||||||
|
set (Boost_PKGCONFIG_LIBS "${Boost_PKGCONFIG_LIBS} ${bname}")
|
||||||
|
endforeach(b)
|
||||||
|
|
||||||
|
foreach (pkgconfig ${pkgconfig_files})
|
||||||
|
configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig/${pkgconfig}.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/pkgconfig/${pkgconfig}.pc @ONLY)
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/pkgconfig/${pkgconfig}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig COMPONENT pkgconfig)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Make the cmake config files
|
||||||
|
set(PKG_NAME ${PROJECT_NAME_UPPER})
|
||||||
|
|
||||||
|
# Order is important, if A depends on B, please add B after A.
|
||||||
|
# The list should have at the very end the libraries
|
||||||
|
# without internal interdependencies
|
||||||
|
set(PKG_LIBRARIES
|
||||||
|
gazebo
|
||||||
|
gazebo_client
|
||||||
|
gazebo_gui
|
||||||
|
gazebo_sensors
|
||||||
|
gazebo_rendering
|
||||||
|
)
|
||||||
|
|
||||||
|
if (INCLUDE_PLAYER)
|
||||||
|
set(PKG_LIBRARIES ${PKG_LIBRARIES} gazebo_player)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(PKG_LIBRARIES ${PKG_LIBRARIES}
|
||||||
|
gazebo_physics
|
||||||
|
gazebo_ode
|
||||||
|
)
|
||||||
|
|
||||||
|
set(PKG_LIBRARIES ${PKG_LIBRARIES}
|
||||||
|
gazebo_transport
|
||||||
|
gazebo_msgs
|
||||||
|
gazebo_util
|
||||||
|
gazebo_common)
|
||||||
|
|
||||||
|
# No other internal dependencies:
|
||||||
|
set(PKG_LIBRARIES ${PKG_LIBRARIES}
|
||||||
|
gazebo_gimpact
|
||||||
|
gazebo_opcode
|
||||||
|
gazebo_opende_ou
|
||||||
|
gazebo_math
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT CCD_FOUND)
|
||||||
|
set(PKG_LIBRARIES ${PKG_LIBRARIES} gazebo_ccd)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(PKG_DEPENDS Boost Protobuf SDFormat OGRE)
|
||||||
|
|
||||||
|
set(cmake_conf_file "cmake/gazebo-config.cmake")
|
||||||
|
set(cmake_conf_version_file "cmake/gazebo-config-version.cmake")
|
||||||
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${cmake_conf_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${cmake_conf_file}" @ONLY)
|
||||||
|
# Use write_basic_package_version_file to generate a ConfigVersion file that
|
||||||
|
# allow users of gazebo to specify the API or version to depend on
|
||||||
|
# TODO: keep this instruction until deprecate Ubuntu/Precise and update with
|
||||||
|
# https://github.com/Kitware/CMake/blob/v2.8.8/Modules/CMakePackageConfigHelpers.cmake
|
||||||
|
include(WriteBasicConfigVersionFile)
|
||||||
|
write_basic_config_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${cmake_conf_version_file}
|
||||||
|
VERSION "${GAZEBO_VERSION_FULL}"
|
||||||
|
COMPATIBILITY SameMajorVersion)
|
||||||
|
install(FILES
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${cmake_conf_file}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/${cmake_conf_version_file}
|
||||||
|
DESTINATION
|
||||||
|
${LIB_INSTALL_DIR}/cmake/${PROJECT_NAME_LOWER}/
|
||||||
|
COMPONENT cmake)
|
||||||
|
########################################
|
||||||
|
# If present, load platform-specific build hooks. This system is used,
|
||||||
|
# for example, by the Ubuntu overlay (in the gazebo-release repo), to
|
||||||
|
# arrange for installation of Ubuntu-specific application-launching
|
||||||
|
# configuration.
|
||||||
|
if (EXISTS ${PROJECT_SOURCE_DIR}/cmake/packager-hooks/CMakeLists.txt)
|
||||||
|
message(STATUS "Loading packager build hooks from cmake/packager-hooks")
|
||||||
|
add_subdirectory(cmake/packager-hooks)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Configuration successful. Type make to compile gazebo")
|
||||||
|
endif(build_errors)
|
|
@ -0,0 +1,341 @@
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Interested in developing new features, fixing bugs, or making any other
|
||||||
|
kind of contribution which touches Gazebo's codebase? Read on to find out how!
|
||||||
|
|
||||||
|
## Development process
|
||||||
|
|
||||||
|
We follow a development process designed to reduce errors, encourage
|
||||||
|
collaboration, and make high quality code. The process may seem rigid and
|
||||||
|
tedious, but every step is worth the effort.
|
||||||
|
|
||||||
|
### Steps to follow
|
||||||
|
|
||||||
|
1. Are you sure?
|
||||||
|
|
||||||
|
Run through this mental checklist before getting started.
|
||||||
|
|
||||||
|
1. Has your idea already been done, or maybe someone is already working on it?
|
||||||
|
|
||||||
|
Check [answers.gazebosim.org](http://answers.gazebosim.org) and the [issue tracker](https://bitbucket.org/osrf/gazebo/issues).
|
||||||
|
|
||||||
|
1. Get feedback from the Gazebo core team.
|
||||||
|
|
||||||
|
Send an email to the
|
||||||
|
[mailing list](https://groups.google.com/a/osrfoundation.org/forum/#!forum/gazebo),
|
||||||
|
post a question on [Gazebo Answers](http://answers.gazebosim.org), or use the
|
||||||
|
[issue tracker](https://bitbucket.org/osrf/gazebo/issues) to get feedback from
|
||||||
|
Gazebo developers.
|
||||||
|
|
||||||
|
1. [Fork Gazebo](https://bitbucket.org/osrf/gazebo/fork)
|
||||||
|
|
||||||
|
This will create your own personal copy of Gazebo. All of your development
|
||||||
|
should take place in your fork.
|
||||||
|
|
||||||
|
1. Choose a base branch
|
||||||
|
|
||||||
|
If your changes will break API or ABI, then base your new branch off of
|
||||||
|
`default`. If your changes don't break API/ABI and you would like them
|
||||||
|
to be released to an existing gazebo release with major version `N`,
|
||||||
|
then use branch `gazeboN` as the base.
|
||||||
|
|
||||||
|
1. Work out of a branch
|
||||||
|
|
||||||
|
Always work out of a new branch, never off of the base branch. This is a
|
||||||
|
good habit to get in, and will make your life easier.
|
||||||
|
|
||||||
|
1. Write your code.
|
||||||
|
|
||||||
|
This is the fun part.
|
||||||
|
|
||||||
|
1. Write tests
|
||||||
|
|
||||||
|
In most cases, a pull request will only be accepted if it has tests. See the
|
||||||
|
"Write tests" section below for more information.
|
||||||
|
|
||||||
|
1. Compiler warnings
|
||||||
|
|
||||||
|
Code must have zero compile warnings, or at least make sure your pull
|
||||||
|
request is not adding new warnings.
|
||||||
|
|
||||||
|
1. Style
|
||||||
|
|
||||||
|
Static code checking analyzes your code for bugs, such as potential memory
|
||||||
|
leaks, and style. Gazebo's static code checker uses `cppcheck`, and a
|
||||||
|
modified `cpplint`. You'll need to install cppcheck on your system. Ubuntu
|
||||||
|
users can install via:
|
||||||
|
|
||||||
|
sudo apt-get install cppcheck
|
||||||
|
|
||||||
|
To check your code, run the following script from the root of the Gazebo
|
||||||
|
sources:
|
||||||
|
|
||||||
|
sh tools/code_check.sh
|
||||||
|
|
||||||
|
It takes a few minutes to run. Fix all errors and warnings until the output
|
||||||
|
looks like:
|
||||||
|
|
||||||
|
Total errors found: 0
|
||||||
|
|
||||||
|
The tool does not catch all style errors. See the "Style" section below for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
1. Tests pass
|
||||||
|
|
||||||
|
There must be no failing tests. You can check by running `make test` in
|
||||||
|
your build directory.
|
||||||
|
|
||||||
|
Running all tests in Gazebo may take a long time. If you expect your changes
|
||||||
|
to only affect a few different tests, it should be enough to run each one
|
||||||
|
of them individually from the build directory, for example:
|
||||||
|
|
||||||
|
./test/integration/INTEGRATION_world
|
||||||
|
|
||||||
|
1. Documentation.
|
||||||
|
|
||||||
|
Document all your code. Every class, function, member variable must have
|
||||||
|
doxygen comments. All code in source files must have documentation that
|
||||||
|
describes the functionality. This will help reviewers and future developers.
|
||||||
|
|
||||||
|
1. Review your code.
|
||||||
|
|
||||||
|
Before submitting your code through a pull request, take some time to
|
||||||
|
review everything line-by-line. The review process will go much faster if
|
||||||
|
you make sure everything is perfect before other people look at your code.
|
||||||
|
There is a bit of the human-condition involved here. Folks are less likely
|
||||||
|
to spend time reviewing your code if it's sloppy.
|
||||||
|
|
||||||
|
1. Small pull requests
|
||||||
|
|
||||||
|
A large pull request is hard to review, and will take a long time. It is
|
||||||
|
worth your time to split a large pull request into multiple smaller pull
|
||||||
|
requests. For reference, here are a few examples:
|
||||||
|
|
||||||
|
* [Small, very nice](https://bitbucket.org/osrf/gazebo/pull-request/1732)
|
||||||
|
|
||||||
|
* [Medium, still okay](https://bitbucket.org/osrf/gazebo/pull-request/1700/)
|
||||||
|
|
||||||
|
* [Too large](https://bitbucket.org/osrf/gazebo/pull-request/30)
|
||||||
|
|
||||||
|
1. [Make a pull request](https://bitbucket.org/osrf/gazebo/pull-request/new)
|
||||||
|
|
||||||
|
Submit a pull request when you're ready.
|
||||||
|
|
||||||
|
1. Continuous integration
|
||||||
|
|
||||||
|
The moment you make a pull request, a few jobs in our
|
||||||
|
[continuous integration](http://build.osrfoundation.org/)
|
||||||
|
server will be started. These jobs will build your branch on Linux, Mac and
|
||||||
|
Windows, run all tests and check for warnings.
|
||||||
|
|
||||||
|
Your pull request will be updated with the status of these builds. Take some
|
||||||
|
time to check these builds and see if you've introduced test failures,
|
||||||
|
warnings or broke some build. If you did and know how to fix it, do so. If
|
||||||
|
you don't know, speak up and someone may try to help you.
|
||||||
|
|
||||||
|
1. Review
|
||||||
|
|
||||||
|
At least two other people have to approve your pull request before it can
|
||||||
|
be merged. Please be responsive to any questions and comments.
|
||||||
|
|
||||||
|
1. Done, phew.
|
||||||
|
|
||||||
|
Once you have met all the requirements, you're code will be merged. Thanks
|
||||||
|
for improving Gazebo!
|
||||||
|
|
||||||
|
### Internal Developers
|
||||||
|
|
||||||
|
This section is targeted mostly at people who have commit access to the main
|
||||||
|
repositories.
|
||||||
|
|
||||||
|
In addition to the general development process, please follow these steps
|
||||||
|
before submitting a pull request. Each step is pass/fail, where the test or
|
||||||
|
check must pass before continuing to the next step.
|
||||||
|
|
||||||
|
1. Run the style checker on your personal computer
|
||||||
|
1. Run all, or only relevant, tests on your personal computer
|
||||||
|
1. Run your branch through a Jenkins Linux no-gpu build
|
||||||
|
1. Run your branch through a Jenkins Linux Nvidia build
|
||||||
|
1. Run your branch through a Jenkins Homebrew build
|
||||||
|
1. Run your branch through a Jenkins Windows build
|
||||||
|
1. Run your branch through the ABI/API checker if targeting a release branch
|
||||||
|
1. Submit the pull request, and make sure the following are included
|
||||||
|
(a set of jenkins jobs will run automatically once the pull request is created,
|
||||||
|
if not included automatically, you must add them manually):
|
||||||
|
1. Link to a coverage report
|
||||||
|
1. Link to a passing Homebrew build
|
||||||
|
1. Link to a passing Linux no-gpu build
|
||||||
|
1. Link to a passing Linux Nvidia build
|
||||||
|
1. Link to a passing Windows build
|
||||||
|
1. Link to a passing ABI/API report if the pull request is targeted at a release branch
|
||||||
|
|
||||||
|
# Style
|
||||||
|
|
||||||
|
In general, we follow [Google's style guide](https://google.github.io/styleguide/cppguide.html). However, we add in some extras.
|
||||||
|
|
||||||
|
1. **This pointer**
|
||||||
|
> All class attributes and member functions must be accessed using the `this->` pointer. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Base.cc#cl-40).
|
||||||
|
|
||||||
|
1. **Underscore function parameters**
|
||||||
|
> All function parameters must start with an underscore. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Base.cc#cl-77).
|
||||||
|
|
||||||
|
1. **Do not cuddle braces**
|
||||||
|
> All braces must be on their own line. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Base.cc#cl-131).
|
||||||
|
|
||||||
|
1. **Multi-line code blocks**
|
||||||
|
> If a block of code spans multiple lines and is part of a flow control statement, such as an `if`, then it must be wrapped in braces. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Base.cc#cl-249)
|
||||||
|
|
||||||
|
1. **++ operator**
|
||||||
|
> This occurs mostly in `for` loops. Prefix the `++` operator, which is [slightly more efficient than postfix in some cases](http://programmers.stackexchange.com/questions/59880/avoid-postfix-increment-operator).
|
||||||
|
|
||||||
|
1. **PIMPL/Opaque pointer**
|
||||||
|
> If you are writing a new class, it must use a private data pointer. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/World.hh?at=default#cl-479), and you can read more [here](https://en.wikipedia.org/wiki/Opaque_pointer).
|
||||||
|
|
||||||
|
1. **const functions**
|
||||||
|
> Any class function that does not change a member variable should be marked as `const`. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Entity.cc?at=default#cl-175).
|
||||||
|
|
||||||
|
1. **const parameters**
|
||||||
|
> All parameters that are not modified by a function should be marked as `const`. This applies to parameters that are passed by reference, pointer, and value. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Entity.cc?at=default#cl-217).
|
||||||
|
|
||||||
|
1. **Pointer and reference variables**
|
||||||
|
> Place the `*` and `&` next to the varaible name, not next to the type. For example: `int &variable` is good, but `int& variable` is not. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Entity.cc?at=default#cl-217).
|
||||||
|
|
||||||
|
1. **Camel case**
|
||||||
|
> In general, everything should use camel case. Exceptions include SDF element names, and protobuf variable names. Here is an [example](https://bitbucket.org/osrf/gazebo/src/default/gazebo/physics/Entity.cc?at=default#cl-217).
|
||||||
|
|
||||||
|
1. **Class function names**
|
||||||
|
> Class functions must start with a capital letter, and capitalize every word.
|
||||||
|
>
|
||||||
|
> `void MyFunction();` : Good
|
||||||
|
>
|
||||||
|
> `void myFunction();` : Bad
|
||||||
|
>
|
||||||
|
> `void my_function();` : Bad
|
||||||
|
|
||||||
|
1. **Variable names**
|
||||||
|
> Variables must start with a lower case letter, and capitalize every word thereafter.
|
||||||
|
>
|
||||||
|
> `int myVariable;` : Good
|
||||||
|
>
|
||||||
|
> `int myvariable;` : Bad
|
||||||
|
>
|
||||||
|
> `int my_variable;` : Bad
|
||||||
|
|
||||||
|
1. **No inline comments**
|
||||||
|
> `//` style comments may not be placed on the same line as code.
|
||||||
|
>
|
||||||
|
> `speed *= 0.44704; // miles per hour to meters per second` : Bad
|
||||||
|
|
||||||
|
# Write tests
|
||||||
|
|
||||||
|
Gazebo uses [GTest](http://code.google.com/p/googletest) for general testing
|
||||||
|
and [QTest](http://doc.qt.io/qt-5/qtest.html) for GUI tests. There are a few
|
||||||
|
kinds of tests:
|
||||||
|
|
||||||
|
1. Unit tests: all classes should have corresponding unit tests. These live
|
||||||
|
in the same directory as the source code and are prefixed by `_TEST`.
|
||||||
|
|
||||||
|
1. Integration tests: tests which verify how many classes are working together
|
||||||
|
go under the `tests/integration` directory.
|
||||||
|
|
||||||
|
1. Regression tests: tests which fix broken features go under `tests/regression`
|
||||||
|
and are prefixed by the issue number on Gazebo's
|
||||||
|
[issue tracker](https://bitbucket.org/osrf/gazebo/issues).
|
||||||
|
|
||||||
|
Before creating a new integration or regression test file, check the current
|
||||||
|
test files. If one closely matches the topic of your new code, simply add a new
|
||||||
|
test function to the file. Otherwise, create a new test file, and write your
|
||||||
|
test.
|
||||||
|
|
||||||
|
## Test coverage
|
||||||
|
|
||||||
|
The goal is to achieve 100% line and branch coverage. However, this is not
|
||||||
|
always possible due to complexity issues, analysis tools misreporting
|
||||||
|
coverage, and time constraints. Try to write as complete of a test suite as
|
||||||
|
possible, and use the coverage analysis tools as guide. If you have trouble
|
||||||
|
writing a test please ask for help in your pull request.
|
||||||
|
|
||||||
|
Gazebo has a build target called `make coverage` that will produce a code
|
||||||
|
coverage report. You'll need to have
|
||||||
|
[lcov](http://ltp.sourceforge.net/coverage/lcov.php) and
|
||||||
|
[gcov](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html) installed.
|
||||||
|
|
||||||
|
1. In your `build` folder, compile Gazebo with `-DCMAKE_BUILD_TYPE=Coverage`
|
||||||
|
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Coverage ..\
|
||||||
|
make
|
||||||
|
|
||||||
|
1. Run a single test, or all the tests
|
||||||
|
|
||||||
|
make test
|
||||||
|
|
||||||
|
1. Make the coverage report
|
||||||
|
|
||||||
|
make coverage
|
||||||
|
|
||||||
|
1. View the coverage report
|
||||||
|
|
||||||
|
firefox coverage/index.html
|
||||||
|
|
||||||
|
## Gazebo assertions
|
||||||
|
|
||||||
|
### What is an assertion?
|
||||||
|
|
||||||
|
An assertion is a check, which always produces a boolean result, that
|
||||||
|
developers place in the code when want to be sure that check is always true.
|
||||||
|
They are aimed to detect programming errors and should check for impossible
|
||||||
|
situations in the code. If the assertion check failed, the assertion will
|
||||||
|
stop the program immediately.
|
||||||
|
|
||||||
|
Object * p = some_crazy_function()
|
||||||
|
GZ_ASSERT(p != nullptr, "Object from some_crazy_function should never point to NULL")
|
||||||
|
p->run()
|
||||||
|
|
||||||
|
### Gazebo runtime assertions: GZ_ASSERT
|
||||||
|
|
||||||
|
In Gazebo, the GZ_ASSERT macro id designed to handle all our runtime assertions
|
||||||
|
|
||||||
|
GZ_ASSERT(<condition to check>,<fail msg>)
|
||||||
|
|
||||||
|
* `condition-to-check`: anything returning a boolean value that should always be true.
|
||||||
|
* `fail msg`: message displayed when assertion is thrown
|
||||||
|
|
||||||
|
### Benefits of the assertions
|
||||||
|
|
||||||
|
Some of the benefits of using the assertions:
|
||||||
|
|
||||||
|
* They are really useful for not having to debug all kind of weird and unexpected errors, especially in runtime. Exact failure point appears when pass by an assertion.
|
||||||
|
* Developer can be sure that some conditions are met at a given code point. Code turns more reliable.
|
||||||
|
* Help to detect no so obvious errors happening (affecting performance for example)
|
||||||
|
|
||||||
|
### Difference between Assertion and Exception
|
||||||
|
|
||||||
|
While assertions are aimed at impossible situations generated from
|
||||||
|
programming errors, exceptions handle all kind of expected errors and unusual
|
||||||
|
but logically possible code situations.
|
||||||
|
|
||||||
|
Lets review an example: suppose we are writing a math library and created a really fast method to calculate square roots but it only works for positive numbers. Something declared as:
|
||||||
|
|
||||||
|
double sqrt_for_positives(double number)
|
||||||
|
|
||||||
|
So what could be an assertion and what an exception for our revolutionary function?
|
||||||
|
|
||||||
|
* Exception: if the incoming number is negative (our function only accepts positive numbers), then we will thrown an exception. It was an error by the user but we should consider it a possible scenario since we are offering a public interface.
|
||||||
|
|
||||||
|
* Assertion: our square root should never return a negative number. This is not a logical error, it's a completely unexpected error.
|
||||||
|
|
||||||
|
## Debugging Gazebo
|
||||||
|
|
||||||
|
### Meaningful backtraces
|
||||||
|
|
||||||
|
In order to provide meaningful backtraces when using a debugger, such as GDB, Gazebo should be compiled with debugging support enabled. When using the ubuntu packages, specially the ''-dbg'' package, this support is limited but could be enough in most of the situations. This are the three level of traces which can be obtained:
|
||||||
|
|
||||||
|
**Maximum level of debugging support**
|
||||||
|
:This only can be obtained compiling Gazebo from source and setting the `CMAKE_BUILD_TYPE` to `DEBUG`. This will set up no optimizations and debugging symbols. It can be required by developers in situations specially difficult to reproduce.
|
||||||
|
|
||||||
|
**Medium level of debugging support**
|
||||||
|
:This can be obtained installing the ''gazebo-dbg'' package (since 1.4 version) or compiling Gazebo from source using the `RELWITHDEBINFO` `CMAKE_BUILD_TYPE` mode (which is the default if no mode is provided). This will set up ''-O2'' optimization level but provide debugging symbols. This should be the default when firing up gdb to explore errors and submit traces.
|
||||||
|
|
||||||
|
**Minimum level of debugging support**
|
||||||
|
:This one is present in package versions previous to 1.4 (no ''-dbg'' package present) or compiling Gazebo from source using the `RELEASE` `CMAKE_BUILD_TYPE` option. This will set up the maximum level of optimizations and does not provide any debugging symbol information. This traces are particularly difficult to follow.
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
Software License Agreement (Apache License)
|
||||||
|
|
||||||
|
Copyright (C) 2012 Open Source Robotics Foundation
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
||||||
|
Gazebo - A dynamic multi-robot simulator
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
This is the Gazebo simulator. Gazebo simulates multiple robots in a
|
||||||
|
3D environment, with extensive dynamic interaction between objects.
|
||||||
|
|
||||||
|
http://gazebosim.org
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Instructions are located at
|
||||||
|
|
||||||
|
http://gazebosim.org/install
|
||||||
|
|
||||||
|
Gazebo cmake parameters available at configuring time:
|
||||||
|
|
||||||
|
- ENABLE_DIAGNOSTICS
|
||||||
|
If this is defined, it will enable diagnostic timers using the macros
|
||||||
|
from Diagnostics.hh (see also the standalone diagnostics example):
|
||||||
|
DIAG_TIMER_START("name")
|
||||||
|
DIAG_TIMER_LAP("name")
|
||||||
|
DIAG_TIMER_STOP("name")
|
||||||
|
- USE_HOST_CFLAGS (bool) [default True]
|
||||||
|
Check the building machine for supported compiler optimizations and use
|
||||||
|
them to build the software.
|
||||||
|
- USE_UPSTREAM_CFLAGS (bool) [default True]
|
||||||
|
Use the recommend gazebo developers compiler optimizations flags
|
||||||
|
- ENABLE_TESTS_COMPILATION (bool) [default True]
|
||||||
|
Enabled or disable the test suite compilation.
|
||||||
|
- USE_LOW_MEMORY_TEST (bool) [default False]
|
||||||
|
Use reduced version of tests which need less quantity of RAM memory
|
||||||
|
available.
|
||||||
|
- FORCE_GRAPHIC_TESTS_COMPILATION (bool) [default False]
|
||||||
|
Ignore system checks to look for graphic and acceleration support and
|
||||||
|
compile all the test suite.
|
||||||
|
- ENABLE_SCREEN_TESTS (bool) [default True]
|
||||||
|
Enable or disable tests that need screen rendering to run properly.
|
||||||
|
Headless machines or machines with the screen turned off should set this to
|
||||||
|
False
|
||||||
|
|
||||||
|
Uninstallation
|
||||||
|
--------------
|
||||||
|
Read the uninstallation instructions (http://gazebosim.org/uninstall)
|
||||||
|
in the online manual for generic instructions. For most people, the following sequence will suffice:
|
||||||
|
|
||||||
|
$ make uninstall (inside the gazebo-trunk/build directory)
|
||||||
|
|
||||||
|
|
||||||
|
- Nate Koenig
|
|
@ -0,0 +1,77 @@
|
||||||
|
# FindDRI support
|
||||||
|
# Check for existance of glxinfo application
|
||||||
|
# Check for existance of support for pyopengl
|
||||||
|
MESSAGE(STATUS "Looking for display capabilities")
|
||||||
|
|
||||||
|
IF ((DEFINED FORCE_GRAPHIC_TESTS_COMPILATION) AND (${FORCE_GRAPHIC_TESTS_COMPILATION}))
|
||||||
|
SET (VALID_DISPLAY TRUE)
|
||||||
|
SET (VALID_DRI_DISPLAY TRUE)
|
||||||
|
MESSAGE(STATUS " + Force requested. All capabilities on without checking")
|
||||||
|
RETURN()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
SET (VALID_DISPLAY FALSE)
|
||||||
|
SET (VALID_DRI_DISPLAY FALSE)
|
||||||
|
SET (CHECKER_ERROR "(no glxinfo or pyopengl)")
|
||||||
|
|
||||||
|
IF((DEFINED ENV{DISPLAY}) AND NOT ("$ENV{DISPLAY}" STREQUAL ""))
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND xwininfo -root
|
||||||
|
RESULT_VARIABLE DISPLAY_FAIL_RESULT
|
||||||
|
ERROR_QUIET
|
||||||
|
OUTPUT_QUIET)
|
||||||
|
IF (NOT DISPLAY_FAIL_RESULT)
|
||||||
|
MESSAGE(STATUS " + found a display available ($DISPLAY is set)")
|
||||||
|
SET (VALID_DISPLAY TRUE)
|
||||||
|
|
||||||
|
# Continue check for DRI support in the display
|
||||||
|
# Try to run glxinfo. If not found, variable will be empty
|
||||||
|
FIND_PROGRAM(GLXINFO glxinfo)
|
||||||
|
|
||||||
|
# If not display found, it will throw an error
|
||||||
|
# Another grep pattern: "direct rendering:[[:space:]]*Yes[[:space:]]*"
|
||||||
|
IF (GLXINFO)
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND glxinfo
|
||||||
|
COMMAND grep "direct rendering:[[:space:]]*Yes[[:space:]]*"
|
||||||
|
ERROR_QUIET
|
||||||
|
OUTPUT_VARIABLE GLX)
|
||||||
|
|
||||||
|
IF (GLX)
|
||||||
|
MESSAGE(STATUS " + found a valid dri display (glxinfo)")
|
||||||
|
SET (VALID_DRI_DISPLAY TRUE)
|
||||||
|
ELSE()
|
||||||
|
SET (CHECKER_ERROR "using glxinfo")
|
||||||
|
ENDIF ()
|
||||||
|
ELSE ()
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
# RESULT_VARIABLE is store in a FAIL variable since the command
|
||||||
|
# returns 0 if ok and 1 if error (inverse than cmake IF)
|
||||||
|
COMMAND ${PROJECT_SOURCE_DIR}/tools/gl-test.py
|
||||||
|
RESULT_VARIABLE GL_FAIL_RESULT
|
||||||
|
ERROR_VARIABLE GL_ERROR
|
||||||
|
OUTPUT_QUIET)
|
||||||
|
|
||||||
|
IF (NOT GL_FAIL_RESULT)
|
||||||
|
MESSAGE(STATUS " + found a valid dri display (pyopengl)")
|
||||||
|
SET (VALID_DRI_DISPLAY TRUE)
|
||||||
|
ELSE()
|
||||||
|
# Check error string: no python module means no pyopengl
|
||||||
|
STRING(FIND ${GL_ERROR}
|
||||||
|
"ImportError: No module named OpenGL.GLUT" ERROR_POS)
|
||||||
|
# -1 will imply pyopengl is present but real DRI test fails
|
||||||
|
IF ("${ERROR_POS}" STREQUAL "-1")
|
||||||
|
SET (CHECKER_ERROR "using pyopengl")
|
||||||
|
ENDIF ()
|
||||||
|
ENDIF ()
|
||||||
|
ENDIF ()
|
||||||
|
ENDIF ()
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (NOT VALID_DISPLAY)
|
||||||
|
MESSAGE(STATUS " ! valid display not found")
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (NOT VALID_DRI_DISPLAY)
|
||||||
|
MESSAGE(STATUS " ! valid dri display not found ${CHECKER_ERROR}")
|
||||||
|
ENDIF ()
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Check prereqs
|
||||||
|
find_program(LCOV_PATH lcov)
|
||||||
|
find_program(GENHTML_PATH genhtml)
|
||||||
|
|
||||||
|
if(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
# Clang version 3.0.0 and greater now supports gcov as well.
|
||||||
|
message(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.")
|
||||||
|
|
||||||
|
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
|
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
||||||
|
endif()
|
||||||
|
endif() # NOT CMAKE_COMPILER_IS_GNUCXX
|
||||||
|
|
||||||
|
if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR
|
||||||
|
CMAKE_BUILD_TYPE STREQUAL "Coverage"))
|
||||||
|
message( WARNING "Code coverage results with an optimized (non-Debug) "
|
||||||
|
"build may be misleading" )
|
||||||
|
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
|
||||||
|
|
||||||
|
# Param _targetname The name of new the custom make target
|
||||||
|
# Param _outputname lcov output is generated as _outputname.info
|
||||||
|
# HTML report is generated in _outputname/index.html
|
||||||
|
function(setup_target_for_coverage _targetname _outputname)
|
||||||
|
|
||||||
|
if(NOT LCOV_PATH)
|
||||||
|
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||||
|
endif() # NOT LCOV_PATH
|
||||||
|
|
||||||
|
if(NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif() # NOT GENHTML_PATH
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${_targetname}
|
||||||
|
COMMAND ${LCOV_PATH} -q --zerocounters --directory ${PROJECT_BINARY_PATH}/gazebo
|
||||||
|
# Capturing lcov counters and generating report
|
||||||
|
COMMAND ${LCOV_PATH} --quiet --no-checksum --directory ${PROJECT_BINARY_DIR}/gazebo --capture --output-file ${_outputname}.info 2>/dev/null
|
||||||
|
COMMAND ${LCOV_PATH} -q --remove ${_outputname}.info 'include/sdformat*' 'include/SimTK*' 'include/simbody*' 'include/simmath*' 'deps/*' 'build/*' 'test/*' '/usr/*' --output-file ${_outputname}.info.cleaned
|
||||||
|
COMMAND ${GENHTML_PATH} -q --legend -o ${_outputname} ${_outputname}.info.cleaned
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info
|
||||||
|
${_outputname}.info.cleaned
|
||||||
|
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
|
COMMENT "Resetting code coverage counters to zero.\n"
|
||||||
|
"Processing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report. And cleanup
|
||||||
|
add_custom_command(TARGET ${_targetname} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report.")
|
||||||
|
|
||||||
|
endfunction() # SETUP_TARGET_FOR_COVERAGE
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Build type link flags
|
||||||
|
set (CMAKE_LINK_FLAGS_RELEASE " " CACHE INTERNAL "Link flags for release" FORCE)
|
||||||
|
set (CMAKE_LINK_FLAGS_RELWITHDEBINFO " " CACHE INTERNAL "Link flags for release with debug support" FORCE)
|
||||||
|
set (CMAKE_LINK_FLAGS_DEBUG " " CACHE INTERNAL "Link flags for debug" FORCE)
|
||||||
|
set (CMAKE_LINK_FLAGS_PROFILE " -pg" CACHE INTERNAL "Link flags for profile" FORCE)
|
||||||
|
set (CMAKE_LINK_FLAGS_COVERAGE " --coverage" CACHE INTERNAL "Link flags for static code coverage" FORCE)
|
||||||
|
|
||||||
|
set (CMAKE_C_FLAGS_RELEASE "")
|
||||||
|
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT MSVC)
|
||||||
|
# -s doesn't work with clang or Visual Studio, see alternative in link below:
|
||||||
|
# http://stackoverflow.com/questions/6085491/gcc-vs-clang-symbol-strippingu
|
||||||
|
set (CMAKE_C_FLAGS_RELEASE "-s")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT MSVC)
|
||||||
|
set (CMAKE_C_FLAGS_RELEASE " ${CMAKE_C_FLAGS_RELEASE} -O3 -DNDEBUG ${CMAKE_C_FLAGS_ALL}" CACHE INTERNAL "C Flags for release" FORCE)
|
||||||
|
set (CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
|
||||||
|
|
||||||
|
set (CMAKE_C_FLAGS_RELWITHDEBINFO " -g -O2 ${CMAKE_C_FLAGS_ALL}" CACHE INTERNAL "C Flags for release with debug support" FORCE)
|
||||||
|
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO})
|
||||||
|
|
||||||
|
set (CMAKE_C_FLAGS_DEBUG " -ggdb3 ${CMAKE_C_FLAGS_ALL}" CACHE INTERNAL "C Flags for debug" FORCE)
|
||||||
|
set (CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
|
||||||
|
|
||||||
|
set (CMAKE_C_FLAGS_PROFILE " -fno-omit-frame-pointer -g -pg ${CMAKE_C_FLAGS_ALL}" CACHE INTERNAL "C Flags for profile" FORCE)
|
||||||
|
set (CMAKE_CXX_FLAGS_PROFILE ${CMAKE_C_FLAGS_PROFILE})
|
||||||
|
|
||||||
|
set (CMAKE_C_FLAGS_COVERAGE " -g -O0 -Wformat=2 --coverage -fno-inline ${CMAKE_C_FLAGS_ALL}" CACHE INTERNAL "C Flags for static code coverage" FORCE)
|
||||||
|
set (CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE}")
|
||||||
|
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
|
# -fno-default-inline -fno-implicit-inline-templates are unimplemented, cause errors in clang
|
||||||
|
# -fno-elide-constructors can cause seg-faults in clang 3.4 and earlier
|
||||||
|
# http://llvm.org/bugs/show_bug.cgi?id=12208
|
||||||
|
set (CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -fno-default-inline -fno-implicit-inline-templates -fno-elide-constructors")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# Set all the global build flags
|
||||||
|
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}}")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_LINK_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}}")
|
||||||
|
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_LINK_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}}")
|
||||||
|
set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_LINK_FLAGS_${CMAKE_BUILD_TYPE_UPPERCASE}}")
|
||||||
|
|
||||||
|
# Compiler-specific C++11 activation.
|
||||||
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
if (NOT (GCC_VERSION VERSION_GREATER 4.7))
|
||||||
|
message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.8 or greater.")
|
||||||
|
endif ()
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CLANG_VERSION)
|
||||||
|
if (NOT (CLANG_VERSION VERSION_GREATER 3.2))
|
||||||
|
message(FATAL_ERROR "${PROJECT_NAME} requires clang 3.3 or greater.")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||||
|
endif ()
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
|
if (NOT MSVC12)
|
||||||
|
message(FATAL_ERROR "${PROJECT_NAME} requires VS 2013 or greater.")
|
||||||
|
endif()
|
||||||
|
else ()
|
||||||
|
message(FATAL_ERROR "Your C++ compiler does not support C++11.")
|
||||||
|
endif ()
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Find version components
|
||||||
|
STRING (REGEX REPLACE "^([0-9]+).*" "\\1" GAZEBO_MAJOR_VERSION "${GAZEBO_VERSION_FULL}")
|
||||||
|
STRING (REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" GAZEBO_MINOR_VERSION "${GAZEBO_VERSION_FULL}")
|
||||||
|
STRING (REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" GAZEBO_REVISION_VERSION ${GAZEBO_VERSION_FULL})
|
||||||
|
STRING (REGEX REPLACE "^[0-9]+\\.[0-9]+\\.[0-9]+(.*)" "\\1" GAZEBO_CANDIDATE_VERSION ${GAZEBO_VERSION_FULL})
|
|
@ -0,0 +1,52 @@
|
||||||
|
include (FindPkgConfig)
|
||||||
|
include (${gazebo_cmake_dir}/GazeboUtils.cmake)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find packages
|
||||||
|
if (PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(freeimage freeimage>=${MIN_FREEIMAGE_VERSION})
|
||||||
|
if (NOT freeimage_FOUND)
|
||||||
|
message (STATUS " freeimage.pc not found, trying freeimage_include_dir and freeimage_library_dir flags.")
|
||||||
|
endif (NOT freeimage_FOUND)
|
||||||
|
endif (PKG_CONFIG_FOUND)
|
||||||
|
|
||||||
|
if (NOT freeimage_FOUND)
|
||||||
|
find_path(freeimage_INCLUDE_DIRS FreeImage.h)
|
||||||
|
if (NOT freeimage_INCLUDE_DIRS)
|
||||||
|
message (STATUS " Looking for FreeImage.h - not found")
|
||||||
|
BUILD_ERROR("Missing: Unable to find FreeImage.h")
|
||||||
|
else (NOT freeimage_INCLUDE_DIRS)
|
||||||
|
message (STATUS " Found ${freeimage_INCLUDE_DIRS}/FreeImage.h")
|
||||||
|
# Check the FreeImage header for the right version
|
||||||
|
set (testFreeImageSource ${CMAKE_CURRENT_BINARY_DIR}/CMakeTmp/test_freeimage.cc)
|
||||||
|
file (WRITE ${testFreeImageSource}
|
||||||
|
"#include <FreeImage.h>\nint main () { if (FREEIMAGE_MAJOR_VERSION >= ${FREEIMAGE_MAJOR_VERSION} && FREEIMAGE_MINOR_VERSION >= ${FREEIMAGE_MINOR_VERSION}) return 1; else return 0;} \n")
|
||||||
|
try_run(FREEIMAGE_RUNS FREEIMAGE_COMPILES ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
${testFreeImageSource}
|
||||||
|
COMPILE_DEFINITIONS "-I${freeimage_INCLUDE_DIRS}"
|
||||||
|
COMPILE_OUTPUT_VARIABLE FREEIMAGE_COMPILE_OUTPUT)
|
||||||
|
if (NOT FREEIMAGE_RUNS)
|
||||||
|
message (STATUS "${FREEIMAGE_COMPILE_OUTPUT}")
|
||||||
|
BUILD_ERROR("Invalid FreeImage Version. Requires ${MIN_FREEIMAGE_VERSION}")
|
||||||
|
else (NOT FREEIMAGE_RUNS)
|
||||||
|
message (STATUS " Looking for FreeImage.h - found")
|
||||||
|
endif (NOT FREEIMAGE_RUNS)
|
||||||
|
endif (NOT freeimage_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
|
find_library(freeimage_LIBRARIES FreeImaged)
|
||||||
|
else()
|
||||||
|
find_library(freeimage_LIBRARIES FreeImage)
|
||||||
|
endif()
|
||||||
|
else(WIN32)
|
||||||
|
find_library(freeimage_LIBRARIES freeimage)
|
||||||
|
endif(WIN32)
|
||||||
|
if (NOT freeimage_LIBRARIES)
|
||||||
|
message (STATUS " Looking for libfreeimage - not found")
|
||||||
|
BUILD_ERROR("Missing: Unable to find libfreeimage")
|
||||||
|
else (NOT freeimage_LIBRARIES)
|
||||||
|
message (STATUS " Looking for libfreeimage - found")
|
||||||
|
include_directories(${freeimage_INCLUDE_DIRS})
|
||||||
|
endif (NOT freeimage_LIBRARIES)
|
||||||
|
endif (NOT freeimage_FOUND)
|
|
@ -0,0 +1,66 @@
|
||||||
|
# -*- cmake -*-
|
||||||
|
|
||||||
|
# - Find Google perftools
|
||||||
|
# Find the Google perftools includes and libraries
|
||||||
|
# This module defines
|
||||||
|
# GOOGLE_PERFTOOLS_INCLUDE_DIR, where to find heap-profiler.h, etc.
|
||||||
|
# GOOGLE_PERFTOOLS_FOUND, If false, do not try to use Google perftools.
|
||||||
|
# also defined for general use are
|
||||||
|
# TCMALLOC_LIBRARIES, where to find the tcmalloc library.
|
||||||
|
# STACKTRACE_LIBRARIES, where to find the stacktrace library.
|
||||||
|
# PROFILER_LIBRARIES, where to find the profiler library.
|
||||||
|
|
||||||
|
FIND_PATH(GOOGLE_PERFTOOLS_INCLUDE_DIR google/heap-profiler.h
|
||||||
|
/usr/local/include
|
||||||
|
/usr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(TCMALLOC_NAMES ${TCMALLOC_NAMES} tcmalloc)
|
||||||
|
FIND_LIBRARY(TCMALLOC_LIBRARY
|
||||||
|
NAMES ${TCMALLOC_NAMES}
|
||||||
|
PATHS /usr/lib /usr/local/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
IF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
SET(TCMALLOC_LIBRARIES ${TCMALLOC_LIBRARY})
|
||||||
|
SET(GOOGLE_PERFTOOLS_FOUND "YES")
|
||||||
|
ELSE (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
SET(GOOGLE_PERFTOOLS_FOUND "NO")
|
||||||
|
ENDIF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
|
||||||
|
SET(STACKTRACE_NAMES ${STACKTRACE_NAMES} stacktrace)
|
||||||
|
FIND_LIBRARY(STACKTRACE_LIBRARY
|
||||||
|
NAMES ${STACKTRACE_LIBRARY}
|
||||||
|
PATHS /usr/lib /usr/local/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
IF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
SET(STACKTRACE_LIBRARIES ${STACKTRACE_LIBRARY})
|
||||||
|
ENDIF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
|
||||||
|
SET(PROFILER_NAMES ${PROFILER_NAMES} profiler)
|
||||||
|
FIND_LIBRARY(PROFILER_LIBRARY
|
||||||
|
NAMES ${PROFILER_LIBRARY}
|
||||||
|
PATHS /usr/lib /usr/local/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
IF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
SET(PROFILER_LIBRARIES ${PROFILER_LIBRARY})
|
||||||
|
ENDIF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
|
||||||
|
|
||||||
|
IF (GOOGLE_PERFTOOLS_FOUND)
|
||||||
|
IF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY)
|
||||||
|
MESSAGE(STATUS "Found Google perftools: ${GOOGLE_PERFTOOLS_LIBRARIES}")
|
||||||
|
ENDIF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY)
|
||||||
|
ELSE (GOOGLE_PERFTOOLS_FOUND)
|
||||||
|
IF (GOOGLE_PERFTOOLS_FIND_REQUIRED)
|
||||||
|
MESSAGE(FATAL_ERROR "Could not find Google perftools library")
|
||||||
|
ENDIF (GOOGLE_PERFTOOLS_FIND_REQUIRED)
|
||||||
|
ENDIF (GOOGLE_PERFTOOLS_FOUND)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(
|
||||||
|
TCMALLOC_LIBRARY
|
||||||
|
STACKTRACE_LIBRARY
|
||||||
|
PROFILER_LIBRARY
|
||||||
|
GOOGLE_PERFTOOLS_INCLUDE_DIR
|
||||||
|
)
|
|
@ -0,0 +1,101 @@
|
||||||
|
# - Try to find Graphviz cgraph library
|
||||||
|
# Once done this will define
|
||||||
|
#
|
||||||
|
# GRAPHVIZ_FOUND - system has Graphviz installed
|
||||||
|
# GRAPHVIZ_INCLUDE_DIR
|
||||||
|
# GRAPHVIZ_GVC_LIBRARY
|
||||||
|
# GRAPHVIZ_CGRAPH_LIBRARY
|
||||||
|
# GRAPHVIZ_CDT_LIBRARY
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
if ( GRAPHVIZ_CGRAPH_LIBRARY )
|
||||||
|
# in cache already
|
||||||
|
SET(Graphviz_FIND_QUIETLY TRUE)
|
||||||
|
endif ( GRAPHVIZ_CGRAPH_LIBRARY )
|
||||||
|
|
||||||
|
# use pkg-config to get the directories and then use these values
|
||||||
|
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||||
|
if( NOT WIN32 )
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(GRAPHVIZ_GVC_PKG libgvc)
|
||||||
|
pkg_check_modules(GRAPHVIZ_CGRAPH_PKG libcgraph)
|
||||||
|
pkg_check_modules(GRAPHVIZ_CDT_PKG libcdt)
|
||||||
|
endif( NOT WIN32 )
|
||||||
|
|
||||||
|
FIND_LIBRARY(GRAPHVIZ_GVC_LIBRARY NAMES gvc libgvc
|
||||||
|
PATHS
|
||||||
|
/usr/lib
|
||||||
|
/usr/local/lib
|
||||||
|
HINTS
|
||||||
|
${GRAPHVIZ_GVC_PKG_LIBRARY_DIRS} # Generated by pkg-config
|
||||||
|
)
|
||||||
|
IF ( NOT(GRAPHVIZ_GVC_LIBRARY) )
|
||||||
|
# MESSAGE(STATUS "Could not find libgvc." )
|
||||||
|
SET(GRAPHVIZ_GVC_FOUND FALSE)
|
||||||
|
ELSE ()
|
||||||
|
SET(GRAPHVIZ_GVC_FOUND TRUE)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
FIND_LIBRARY(GRAPHVIZ_CGRAPH_LIBRARY NAMES cgraph libcgraph
|
||||||
|
PATHS
|
||||||
|
/usr/lib
|
||||||
|
/usr/local/lib
|
||||||
|
HINTS
|
||||||
|
${GRAPHVIZ_CGRAPH_PKG_LIBRARY_DIRS} # Generated by pkg-config
|
||||||
|
)
|
||||||
|
IF ( NOT(GRAPHVIZ_CGRAPH_LIBRARY) )
|
||||||
|
# MESSAGE(STATUS "Could not find libcgraph." )
|
||||||
|
SET(GRAPHVIZ_CGRAPH_FOUND FALSE)
|
||||||
|
ELSE ()
|
||||||
|
SET(GRAPHVIZ_CGRAPH_FOUND TRUE)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
FIND_LIBRARY(GRAPHVIZ_CDT_LIBRARY NAMES cdt libcdt
|
||||||
|
PATHS
|
||||||
|
/usr/lib
|
||||||
|
/usr/local/lib
|
||||||
|
HINTS
|
||||||
|
${GRAPHVIZ_CDT_PKG_LIBRARY_DIRS} # Generated by pkg-config
|
||||||
|
)
|
||||||
|
IF ( NOT(GRAPHVIZ_CDT_LIBRARY) )
|
||||||
|
# MESSAGE(STATUS "Could not find libcdt." )
|
||||||
|
SET(GRAPHVIZ_CDT_FOUND FALSE)
|
||||||
|
ELSE ()
|
||||||
|
SET(GRAPHVIZ_CDT_FOUND TRUE)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
FIND_PATH(GRAPHVIZ_INCLUDE_DIR NAMES cgraph.h
|
||||||
|
PATHS
|
||||||
|
/usr/include/graphviz
|
||||||
|
/usr/local/include
|
||||||
|
HINTS
|
||||||
|
${GRAPHVIZ_GVC_PKG_INCLUDE_DIRS} # Generated by pkg-config
|
||||||
|
)
|
||||||
|
IF ( NOT(GRAPHVIZ_INCLUDE_DIR) )
|
||||||
|
MESSAGE(STATUS "Could not find graphviz headers." )
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Graphviz_Gvc DEFAULT_MSG GRAPHVIZ_GVC_LIBRARY )
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Graphviz_Cgraph DEFAULT_MSG GRAPHVIZ_CGRAPH_LIBRARY )
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Graphviz_Cdt DEFAULT_MSG GRAPHVIZ_CDT_LIBRARY )
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS("Graphviz Headers" DEFAULT_MSG GRAPHVIZ_INCLUDE_DIR )
|
||||||
|
|
||||||
|
|
||||||
|
# show the POPPLER_(XPDF/QT4)_INCLUDE_DIR and POPPLER_LIBRARIES variables only in the advanced view
|
||||||
|
MARK_AS_ADVANCED(GRAPHVIZ_INCLUDE_DIR GRAPHVIZ_GVC_LIBRARY GRAPHVIZ_CGRAPH_LIBRARY GRAPHVIZ_CDT_LIBRARY)
|
||||||
|
|
||||||
|
if (GRAPHVIZ_INCLUDE_DIR AND
|
||||||
|
GRAPHVIZ_CDT_LIBRARY AND
|
||||||
|
GRAPHVIZ_CGRAPH_LIBRARY AND
|
||||||
|
GRAPHVIZ_GVC_LIBRARY)
|
||||||
|
set(GRAPHVIZ_FOUND TRUE)
|
||||||
|
set(GRAPHVIZ_LIBRARIES
|
||||||
|
${GRAPHVIZ_CDT_LIBRARY}
|
||||||
|
${GRAPHVIZ_CGRAPH_LIBRARY}
|
||||||
|
${GRAPHVIZ_GVC_LIBRARY})
|
||||||
|
else ()
|
||||||
|
set(GRAPHVIZ_FOUND FALSE)
|
||||||
|
endif ()
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Check the OS type.
|
||||||
|
|
||||||
|
# CMake does not distinguish Linux from other Unices.
|
||||||
|
STRING (REGEX MATCH "Linux" PLAYER_OS_LINUX ${CMAKE_SYSTEM_NAME})
|
||||||
|
# Nor *BSD
|
||||||
|
STRING (REGEX MATCH "BSD" PLAYER_OS_BSD ${CMAKE_SYSTEM_NAME})
|
||||||
|
# Or Solaris. I'm seeing a trend, here
|
||||||
|
STRING (REGEX MATCH "SunOS" PLAYER_OS_SOLARIS ${CMAKE_SYSTEM_NAME})
|
||||||
|
|
||||||
|
# Windows is easy (for once)
|
||||||
|
IF (WIN32)
|
||||||
|
SET (PLAYER_OS_WIN TRUE BOOL INTERNAL)
|
||||||
|
ENDIF (WIN32)
|
||||||
|
|
||||||
|
# Check if it's an Apple OS
|
||||||
|
IF (APPLE)
|
||||||
|
# Check if it's OS X or another MacOS (that's got to be pretty unlikely)
|
||||||
|
STRING (REGEX MATCH "Darwin" PLAYER_OS_OSX ${CMAKE_SYSTEM_NAME})
|
||||||
|
IF (NOT PLAYER_OS_OSX)
|
||||||
|
SET (PLAYER_OS_MACOS TRUE BOOL INTERNAL)
|
||||||
|
ENDIF (NOT PLAYER_OS_OSX)
|
||||||
|
ENDIF (APPLE)
|
||||||
|
|
||||||
|
# QNX
|
||||||
|
IF (QNXNTO)
|
||||||
|
SET (PLAYER_OS_QNX TRUE BOOL INTERNAL)
|
||||||
|
ENDIF (QNXNTO)
|
||||||
|
|
||||||
|
IF (PLAYER_OS_LINUX)
|
||||||
|
MESSAGE (STATUS "Operating system is Linux")
|
||||||
|
ELSEIF (PLAYER_OS_BSD)
|
||||||
|
MESSAGE (STATUS "Operating system is BSD")
|
||||||
|
ELSEIF (PLAYER_OS_WIN)
|
||||||
|
MESSAGE (STATUS "Operating system is Windows")
|
||||||
|
ELSEIF (PLAYER_OS_OSX)
|
||||||
|
MESSAGE (STATUS "Operating system is Apple MacOS X")
|
||||||
|
ELSEIF (PLAYER_OS_MACOS)
|
||||||
|
MESSAGE (STATUS "Operating system is Apple MacOS (not OS X)")
|
||||||
|
ELSEIF (PLAYER_OS_QNX)
|
||||||
|
MESSAGE (STATUS "Operating system is QNX")
|
||||||
|
ELSEIF (PLAYER_OS_SOLARIS)
|
||||||
|
MESSAGE (STATUS "Operating system is Solaris")
|
||||||
|
ELSE (PLAYER_OS_LINUX)
|
||||||
|
MESSAGE (STATUS "Operating system is generic Unix")
|
||||||
|
ENDIF (PLAYER_OS_LINUX)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Check for non-case-sensitive filesystems
|
||||||
|
execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/case_sensitive_filesystem
|
||||||
|
RESULT_VARIABLE FILESYSTEM_CASE_SENSITIVE_RETURN)
|
||||||
|
if (${FILESYSTEM_CASE_SENSITIVE_RETURN} EQUAL 0)
|
||||||
|
set(FILESYSTEM_CASE_SENSITIVE TRUE)
|
||||||
|
else()
|
||||||
|
set(FILESYSTEM_CASE_SENSITIVE FALSE)
|
||||||
|
endif()
|
|
@ -0,0 +1,113 @@
|
||||||
|
# Check if SSE instructions are available on the machine where
|
||||||
|
# the project is compiled.
|
||||||
|
|
||||||
|
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
|
EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*(sse2).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "sse2" "${SSE_THERE}" SSE2_TRUE)
|
||||||
|
IF (SSE2_TRUE)
|
||||||
|
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
|
||||||
|
ELSE (SSE2_TRUE)
|
||||||
|
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
|
||||||
|
ENDIF (SSE2_TRUE)
|
||||||
|
|
||||||
|
# /proc/cpuinfo apparently omits sse3 :(
|
||||||
|
STRING(REGEX REPLACE "^.*[^s](sse3).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "sse3" "${SSE_THERE}" SSE3_TRUE)
|
||||||
|
IF (NOT SSE3_TRUE)
|
||||||
|
STRING(REGEX REPLACE "^.*(T2300).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "T2300" "${SSE_THERE}" SSE3_TRUE)
|
||||||
|
ENDIF (NOT SSE3_TRUE)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*(ssse3).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "ssse3" "${SSE_THERE}" SSSE3_TRUE)
|
||||||
|
IF (SSE3_TRUE OR SSSE3_TRUE)
|
||||||
|
set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
|
||||||
|
ELSE (SSE3_TRUE OR SSSE3_TRUE)
|
||||||
|
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
|
||||||
|
ENDIF (SSE3_TRUE OR SSSE3_TRUE)
|
||||||
|
IF (SSSE3_TRUE)
|
||||||
|
set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
|
||||||
|
ELSE (SSSE3_TRUE)
|
||||||
|
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
|
||||||
|
ENDIF (SSSE3_TRUE)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*(sse4_1).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "sse4_1" "${SSE_THERE}" SSE41_TRUE)
|
||||||
|
IF (SSE41_TRUE)
|
||||||
|
set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
|
||||||
|
ELSE (SSE41_TRUE)
|
||||||
|
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
|
||||||
|
ENDIF (SSE41_TRUE)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*(sse4_2).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE)
|
||||||
|
IF (SSE42_TRUE)
|
||||||
|
set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host")
|
||||||
|
ELSE (SSE42_TRUE)
|
||||||
|
set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host")
|
||||||
|
ENDIF (SSE42_TRUE)
|
||||||
|
|
||||||
|
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||||
|
EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE
|
||||||
|
CPUINFO)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*[^S](SSE2).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "SSE2" "${SSE_THERE}" SSE2_TRUE)
|
||||||
|
IF (SSE2_TRUE)
|
||||||
|
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
|
||||||
|
ELSE (SSE2_TRUE)
|
||||||
|
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
|
||||||
|
ENDIF (SSE2_TRUE)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*[^S](SSE3).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "SSE3" "${SSE_THERE}" SSE3_TRUE)
|
||||||
|
IF (SSE3_TRUE)
|
||||||
|
set(SSE3_FOUND true CACHE BOOL "SSE3 available on host")
|
||||||
|
ELSE (SSE3_TRUE)
|
||||||
|
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
|
||||||
|
ENDIF (SSE3_TRUE)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*(SSSE3).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "SSSE3" "${SSE_THERE}" SSSE3_TRUE)
|
||||||
|
IF (SSSE3_TRUE)
|
||||||
|
set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host")
|
||||||
|
ELSE (SSSE3_TRUE)
|
||||||
|
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
|
||||||
|
ENDIF (SSSE3_TRUE)
|
||||||
|
|
||||||
|
STRING(REGEX REPLACE "^.*(SSE4.1).*$" "\\1" SSE_THERE ${CPUINFO})
|
||||||
|
STRING(COMPARE EQUAL "SSE4.1" "${SSE_THERE}" SSE41_TRUE)
|
||||||
|
IF (SSE41_TRUE)
|
||||||
|
set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host")
|
||||||
|
ELSE (SSE41_TRUE)
|
||||||
|
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
|
||||||
|
ENDIF (SSE41_TRUE)
|
||||||
|
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
# TODO
|
||||||
|
set(SSE2_FOUND false CACHE BOOL "SSE2 available on host")
|
||||||
|
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
|
||||||
|
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
|
||||||
|
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
|
||||||
|
ELSE(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
|
set(SSE2_FOUND true CACHE BOOL "SSE2 available on host")
|
||||||
|
set(SSE3_FOUND false CACHE BOOL "SSE3 available on host")
|
||||||
|
set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host")
|
||||||
|
set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host")
|
||||||
|
ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
|
|
||||||
|
if(NOT SSE2_FOUND)
|
||||||
|
MESSAGE(STATUS "Could not find hardware support for SSE2 on this machine.")
|
||||||
|
endif(NOT SSE2_FOUND)
|
||||||
|
if(NOT SSE3_FOUND)
|
||||||
|
MESSAGE(STATUS "Could not find hardware support for SSE3 on this machine.")
|
||||||
|
endif(NOT SSE3_FOUND)
|
||||||
|
if(NOT SSSE3_FOUND)
|
||||||
|
MESSAGE(STATUS "Could not find hardware support for SSSE3 on this machine.")
|
||||||
|
endif(NOT SSSE3_FOUND)
|
||||||
|
if(NOT SSE4_1_FOUND)
|
||||||
|
MESSAGE(STATUS "Could not find hardware support for SSE4.1 on this machine.")
|
||||||
|
endif(NOT SSE4_1_FOUND)
|
||||||
|
|
||||||
|
mark_as_advanced(SSE2_FOUND SSE3_FOUND SSSE3_FOUND SSE4_1_FOUND)
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
|
@ -0,0 +1,147 @@
|
||||||
|
#################################################
|
||||||
|
# VAR: GZ_BUILD_TESTS_EXTRA_EXE_SRCS
|
||||||
|
# Hack: extra sources to build binaries can be supplied to gz_build_tests in
|
||||||
|
# the variable GZ_BUILD_TESTS_EXTRA_EXE_SRCS. This variable will be clean up
|
||||||
|
# at the end of the function
|
||||||
|
#
|
||||||
|
# ARG: EXTRA_LIBS
|
||||||
|
# List extra libraries that the sources should be linked against after the
|
||||||
|
# EXTRA_LIBS tag. Example:
|
||||||
|
# gz_build_tests(${test_sources} EXTRA_LIBS ${test_libraries})
|
||||||
|
#
|
||||||
|
macro (gz_build_tests)
|
||||||
|
set(_append_sources TRUE)
|
||||||
|
|
||||||
|
set(_sources)
|
||||||
|
set(_extra_libs)
|
||||||
|
|
||||||
|
foreach(arg ${ARGN})
|
||||||
|
if ("${arg}" STREQUAL "EXTRA_LIBS")
|
||||||
|
set(_append_sources FALSE)
|
||||||
|
else()
|
||||||
|
if (_append_sources)
|
||||||
|
list(APPEND _sources ${arg})
|
||||||
|
else()
|
||||||
|
list(APPEND _extra_libs ${arg})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Build all the tests
|
||||||
|
foreach(GTEST_SOURCE_file ${_sources})
|
||||||
|
string(REGEX REPLACE "\\.cc" "" BINARY_NAME ${GTEST_SOURCE_file})
|
||||||
|
set(BINARY_NAME ${TEST_TYPE}_${BINARY_NAME})
|
||||||
|
if(USE_LOW_MEMORY_TESTS)
|
||||||
|
add_definitions(-DUSE_LOW_MEMORY_TESTS=1)
|
||||||
|
endif(USE_LOW_MEMORY_TESTS)
|
||||||
|
add_executable(${BINARY_NAME} ${GTEST_SOURCE_file}
|
||||||
|
${GZ_BUILD_TESTS_EXTRA_EXE_SRCS})
|
||||||
|
|
||||||
|
link_directories(${PROJECT_BINARY_DIR}/test)
|
||||||
|
target_link_libraries(${BINARY_NAME}
|
||||||
|
gtest
|
||||||
|
gtest_main
|
||||||
|
${_extra_libs}
|
||||||
|
)
|
||||||
|
if (UNIX)
|
||||||
|
# gtest uses pthread on UNIX
|
||||||
|
target_link_libraries(${BINARY_NAME} pthread)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_test(${BINARY_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}
|
||||||
|
--gtest_output=xml:${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml)
|
||||||
|
|
||||||
|
set(_env_vars)
|
||||||
|
list(APPEND _env_vars "CMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}:${CMAKE_PREFIX_PATH}")
|
||||||
|
list(APPEND _env_vars "GAZEBO_PLUGIN_PATH=${CMAKE_BINARY_DIR}/plugins:${CMAKE_BINARY_DIR}/plugins/events:${CMAKE_BINARY_DIR}/plugins/rest_web")
|
||||||
|
list(APPEND _env_vars "GAZEBO_RESOURCE_PATH=${CMAKE_SOURCE_DIR}")
|
||||||
|
list(APPEND _env_vars "PATH=${CMAKE_BINARY_DIR}/gazebo:${CMAKE_BINARY_DIR}/tools:$ENV{PATH}")
|
||||||
|
list(APPEND _env_vars "PKG_CONFIG_PATH=${CMAKE_BINARY_DIR}/cmake/pkgconfig:$PKG_CONFIG_PATH")
|
||||||
|
set_tests_properties(${BINARY_NAME} PROPERTIES
|
||||||
|
TIMEOUT 240
|
||||||
|
ENVIRONMENT "${_env_vars}")
|
||||||
|
|
||||||
|
# Check that the test produced a result and create a failure if it didn't.
|
||||||
|
# Guards against crashed and timed out tests.
|
||||||
|
add_test(check_${BINARY_NAME} ${PROJECT_SOURCE_DIR}/tools/check_test_ran.py
|
||||||
|
${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml)
|
||||||
|
|
||||||
|
if(GAZEBO_RUN_VALGRIND_TESTS AND VALGRIND_PROGRAM)
|
||||||
|
add_test(memcheck_${BINARY_NAME} ${VALGRIND_PROGRAM} --leak-check=full
|
||||||
|
--error-exitcode=1 --show-leak-kinds=all ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(GZ_BUILD_TESTS_EXTRA_EXE_SRCS "")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
if (VALID_DISPLAY)
|
||||||
|
# Redefine build display tests
|
||||||
|
macro (gz_build_display_tests)
|
||||||
|
gz_build_tests(${ARGV})
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Redefine build qt tests
|
||||||
|
macro (gz_build_qt_tests)
|
||||||
|
# Build all the tests
|
||||||
|
foreach(QTEST_SOURCE_file ${ARGN})
|
||||||
|
string(REGEX REPLACE ".cc" "" BINARY_NAME ${QTEST_SOURCE_file})
|
||||||
|
string(REGEX REPLACE ".cc" ".hh" QTEST_HEADER_file ${QTEST_SOURCE_file})
|
||||||
|
set(BINARY_NAME ${TEST_TYPE}_${BINARY_NAME})
|
||||||
|
QT4_WRAP_CPP(${BINARY_NAME}_MOC ${QTEST_HEADER_file} ${CMAKE_SOURCE_DIR}/gazebo/gui/QTestFixture.hh)
|
||||||
|
|
||||||
|
add_executable(${BINARY_NAME}
|
||||||
|
${${BINARY_NAME}_MOC} ${QTEST_SOURCE_file} ${CMAKE_SOURCE_DIR}/gazebo/gui/QTestFixture.cc)
|
||||||
|
|
||||||
|
add_dependencies(${BINARY_NAME}
|
||||||
|
gazebo_gui
|
||||||
|
gazebo_common
|
||||||
|
gazebo_math
|
||||||
|
gazebo_physics
|
||||||
|
gazebo_sensors
|
||||||
|
gazebo_rendering
|
||||||
|
gazebo_msgs
|
||||||
|
gazebo_transport
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${BINARY_NAME}
|
||||||
|
# gazebo_gui and libgazebo will bring all most of gazebo
|
||||||
|
# libraries as dependencies
|
||||||
|
libgazebo
|
||||||
|
gazebo_gui
|
||||||
|
${QT_QTTEST_LIBRARY}
|
||||||
|
${QT_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
# QTest need and extra -o parameter to write logging information to a file
|
||||||
|
add_test(${BINARY_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}
|
||||||
|
-xml -o ${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml)
|
||||||
|
|
||||||
|
set(_env_vars)
|
||||||
|
list(APPEND _env_vars "CMAKE_PREFIX_PATH=${CMAKE_BINARY_DIR}:${CMAKE_PREFIX_PATH}")
|
||||||
|
list(APPEND _env_vars "GAZEBO_PLUGIN_PATH=${CMAKE_BINARY_DIR}/plugins:${CMAKE_BINARY_DIR}/plugins/events:${CMAKE_BINARY_DIR}/plugins/rest_web")
|
||||||
|
list(APPEND _env_vars "GAZEBO_RESOURCE_PATH=${CMAKE_SOURCE_DIR}")
|
||||||
|
list(APPEND _env_vars "PATH=${CMAKE_BINARY_DIR}/gazebo:${CMAKE_BINARY_DIR}/tools:$ENV{PATH}")
|
||||||
|
list(APPEND _env_vars "PKG_CONFIG_PATH=${CMAKE_BINARY_DIR}/cmake/pkgconfig:$PKG_CONFIG_PATH")
|
||||||
|
set_tests_properties(${BINARY_NAME} PROPERTIES
|
||||||
|
TIMEOUT 240
|
||||||
|
ENVIRONMENT "${_env_vars}")
|
||||||
|
|
||||||
|
# Check that the test produced a result and create a failure if it didn't.
|
||||||
|
# Guards against crashed and timed out tests.
|
||||||
|
add_test(check_${BINARY_NAME} ${PROJECT_SOURCE_DIR}/tools/check_test_ran.py
|
||||||
|
${CMAKE_BINARY_DIR}/test_results/${BINARY_NAME}.xml)
|
||||||
|
|
||||||
|
if(GAZEBO_RUN_VALGRIND_TESTS AND VALGRIND_PROGRAM)
|
||||||
|
add_test(memcheck_${BINARY_NAME} ${VALGRIND_PROGRAM} --leak-check=full
|
||||||
|
--error-exitcode=1 --show-leak-kinds=all ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (VALID_DRI_DISPLAY)
|
||||||
|
macro (gz_build_dri_tests)
|
||||||
|
gz_build_tests(${ARGV})
|
||||||
|
endmacro()
|
||||||
|
endif()
|
|
@ -0,0 +1,238 @@
|
||||||
|
################################################################################
|
||||||
|
#APPEND_TO_CACHED_STRING(_string _cacheDesc [items...])
|
||||||
|
# Appends items to a cached list.
|
||||||
|
MACRO (APPEND_TO_CACHED_STRING _string _cacheDesc)
|
||||||
|
FOREACH (newItem ${ARGN})
|
||||||
|
SET (${_string} "${${_string}} ${newItem}" CACHE INTERNAL ${_cacheDesc} FORCE)
|
||||||
|
ENDFOREACH (newItem ${ARGN})
|
||||||
|
#STRING(STRIP ${${_string}} ${_string})
|
||||||
|
ENDMACRO (APPEND_TO_CACHED_STRING)
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# APPEND_TO_CACHED_LIST (_list _cacheDesc [items...]
|
||||||
|
# Appends items to a cached list.
|
||||||
|
MACRO (APPEND_TO_CACHED_LIST _list _cacheDesc)
|
||||||
|
SET (tempList ${${_list}})
|
||||||
|
FOREACH (newItem ${ARGN})
|
||||||
|
LIST (APPEND tempList ${newItem})
|
||||||
|
ENDFOREACH (newItem ${newItem})
|
||||||
|
SET (${_list} ${tempList} CACHE INTERNAL ${_cacheDesc} FORCE)
|
||||||
|
ENDMACRO(APPEND_TO_CACHED_LIST)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Append sources to the server sources list
|
||||||
|
MACRO (APPEND_TO_SERVER_SOURCES)
|
||||||
|
FOREACH (src ${ARGN})
|
||||||
|
APPEND_TO_CACHED_LIST(gazeboserver_sources
|
||||||
|
${gazeboserver_sources_desc}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${src})
|
||||||
|
ENDFOREACH (src ${ARGN})
|
||||||
|
ENDMACRO (APPEND_TO_SERVER_SOURCES)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Append headers to the server headers list
|
||||||
|
MACRO (APPEND_TO_SERVER_HEADERS)
|
||||||
|
FOREACH (src ${ARGN})
|
||||||
|
APPEND_TO_CACHED_LIST(gazeboserver_headers
|
||||||
|
${gazeboserver_headers_desc}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${src})
|
||||||
|
APPEND_TO_CACHED_LIST(gazeboserver_headers_nopath
|
||||||
|
"gazeboserver_headers_nopath"
|
||||||
|
${src})
|
||||||
|
ENDFOREACH (src ${ARGN})
|
||||||
|
ENDMACRO (APPEND_TO_SERVER_HEADERS)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Append sources to the sensor sources list
|
||||||
|
MACRO (APPEND_TO_SENSOR_SOURCES)
|
||||||
|
FOREACH (src ${ARGN})
|
||||||
|
APPEND_TO_CACHED_LIST(gazebosensor_sources
|
||||||
|
${gazebosensor_sources_desc}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${src})
|
||||||
|
ENDFOREACH (src ${ARGN})
|
||||||
|
ENDMACRO (APPEND_TO_SENSOR_SOURCES)
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Append sources to the controller sources list
|
||||||
|
MACRO (APPEND_TO_CONTROLLER_SOURCES)
|
||||||
|
FOREACH (src ${ARGN})
|
||||||
|
APPEND_TO_CACHED_LIST(gazebocontroller_sources
|
||||||
|
${gazebocontroller_sources_desc}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${src})
|
||||||
|
ENDFOREACH (src ${ARGN})
|
||||||
|
ENDMACRO (APPEND_TO_CONTROLLER_SOURCES)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Macro to turn a list into a string (why doesn't CMake have this built-in?)
|
||||||
|
MACRO (LIST_TO_STRING _string _list)
|
||||||
|
SET (${_string})
|
||||||
|
FOREACH (_item ${_list})
|
||||||
|
SET (${_string} "${${_string}} ${_item}")
|
||||||
|
ENDFOREACH (_item)
|
||||||
|
#STRING(STRIP ${${_string}} ${_string})
|
||||||
|
ENDMACRO (LIST_TO_STRING)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# BUILD ERROR macro
|
||||||
|
macro (BUILD_ERROR)
|
||||||
|
foreach (str ${ARGN})
|
||||||
|
SET (msg "\t${str}")
|
||||||
|
MESSAGE (STATUS ${msg})
|
||||||
|
APPEND_TO_CACHED_LIST(build_errors "build errors" ${msg})
|
||||||
|
endforeach ()
|
||||||
|
endmacro (BUILD_ERROR)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# BUILD WARNING macro
|
||||||
|
macro (BUILD_WARNING)
|
||||||
|
foreach (str ${ARGN})
|
||||||
|
SET (msg "\t${str}" )
|
||||||
|
MESSAGE (STATUS ${msg} )
|
||||||
|
APPEND_TO_CACHED_LIST(build_warnings "build warning" ${msg})
|
||||||
|
endforeach (str ${ARGN})
|
||||||
|
endmacro (BUILD_WARNING)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_add_library _name)
|
||||||
|
# Not defining STATIC or SHARED will use BUILD_SHARED_LIBS variable
|
||||||
|
add_library(${_name} ${ARGN})
|
||||||
|
target_link_libraries (${_name} ${general_libraries})
|
||||||
|
endmacro ()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_add_executable _name)
|
||||||
|
add_executable(${_name} ${ARGN})
|
||||||
|
target_link_libraries (${_name} ${general_libraries})
|
||||||
|
endmacro ()
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_install_includes _subdir)
|
||||||
|
install(FILES ${ARGN} DESTINATION ${INCLUDE_INSTALL_DIR}/${_subdir} COMPONENT headers)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_install_library _name)
|
||||||
|
set_target_properties(${_name} PROPERTIES SOVERSION ${GAZEBO_MAJOR_VERSION} VERSION ${GAZEBO_VERSION_FULL})
|
||||||
|
install (TARGETS ${_name} DESTINATION ${LIB_INSTALL_DIR} COMPONENT shlib)
|
||||||
|
endmacro ()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_install_executable _name)
|
||||||
|
set_target_properties(${_name} PROPERTIES VERSION ${GAZEBO_VERSION_FULL})
|
||||||
|
install (TARGETS ${_name} DESTINATION ${BIN_INSTALL_DIR})
|
||||||
|
endmacro ()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_setup_unix)
|
||||||
|
# Using dynamic linking in UNIX by default
|
||||||
|
set(BUILD_SHARED_LIBS TRUE)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_setup_windows)
|
||||||
|
# Using static linking in Windows by default
|
||||||
|
set(BUILD_SHARED_LIBS FALSE)
|
||||||
|
add_definitions(-DBUILDING_STATIC_LIBS -DWIN32_LEAN_AND_MEAN)
|
||||||
|
|
||||||
|
# Need for M_PI constant
|
||||||
|
add_definitions(-D_USE_MATH_DEFINES)
|
||||||
|
|
||||||
|
# Don't pull in the Windows min/max macros
|
||||||
|
add_definitions(-DNOMINMAX)
|
||||||
|
|
||||||
|
#use static libraries for FREEIMAGE
|
||||||
|
add_definitions(-DFREEIMAGE_LIB)
|
||||||
|
|
||||||
|
# Use dynamic linking for boost
|
||||||
|
add_definitions(-DBOOST_ALL_DYN_LINK)
|
||||||
|
|
||||||
|
# And force linking to MSVC dynamic runtime
|
||||||
|
if ("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "DEBUG")
|
||||||
|
add_definitions("/MDd")
|
||||||
|
else()
|
||||||
|
add_definitions("/MD")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# And we want exceptions
|
||||||
|
add_definitions("/EHsc")
|
||||||
|
|
||||||
|
if (MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
# Not need if proper cmake gnerator (-G "...Win64") is passed to cmake
|
||||||
|
# Enable as a second measure to workaround over bug
|
||||||
|
# http://www.cmake.org/Bug/print_bug_page.php?bug_id=11240
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "/machine:x64")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
macro (gz_setup_apple)
|
||||||
|
# NOTE MacOSX provides different system versions than CMake is parsing.
|
||||||
|
# The following table lists the most recent OSX versions
|
||||||
|
# 9.x.x = Mac OSX Leopard (10.5)
|
||||||
|
# 10.x.x = Mac OSX Snow Leopard (10.6)
|
||||||
|
# 11.x.x = Mac OSX Lion (10.7)
|
||||||
|
# 12.x.x = Mac OSX Mountain Lion (10.8)
|
||||||
|
if (${CMAKE_SYSTEM_VERSION} LESS 10)
|
||||||
|
add_definitions(-DMAC_OS_X_VERSION=1050)
|
||||||
|
elseif (${CMAKE_SYSTEM_VERSION} GREATER 10 AND ${CMAKE_SYSTEM_VERSION} LESS 11)
|
||||||
|
add_definitions(-DMAC_OS_X_VERSION=1060)
|
||||||
|
elseif (${CMAKE_SYSTEM_VERSION} GREATER 11 AND ${CMAKE_SYSTEM_VERSION} LESS 12)
|
||||||
|
add_definitions(-DMAC_OS_X_VERSION=1070)
|
||||||
|
elseif (${CMAKE_SYSTEM_VERSION} GREATER 12 OR ${CMAKE_SYSTEM_VERSION} EQUAL 12)
|
||||||
|
add_definitions(-DMAC_OS_X_VERSION=1080)
|
||||||
|
else ()
|
||||||
|
add_definitions(-DMAC_OS_X_VERSION=0)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# libstdc++ used on 10.8 and earlier
|
||||||
|
# libc++ after that
|
||||||
|
if (${CMAKE_SYSTEM_VERSION} LESS 13)
|
||||||
|
set (APPLE_PKGCONFIG_LIBS "${APPLE_PKGCONFIG_LIBS} -lstdc++")
|
||||||
|
else()
|
||||||
|
set (APPLE_PKGCONFIG_LIBS "${APPLE_PKGCONFIG_LIBS} -lc++")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined -Wl,dynamic_lookup")
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# This should be migrated to more fine control solution based on set_property APPEND
|
||||||
|
# directories. It's present on cmake 2.8.8 while precise version is 2.8.7
|
||||||
|
link_directories(${PROJECT_BINARY_DIR}/test)
|
||||||
|
include_directories("${PROJECT_SOURCE_DIR}/test/gtest/include")
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Enable tests compilation by default
|
||||||
|
if (NOT DEFINED ENABLE_TESTS_COMPILATION)
|
||||||
|
set (ENABLE_TESTS_COMPILATION True)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Define testing macros as empty and redefine them if support is found and
|
||||||
|
# ENABLE_TESTS_COMPILATION is set to true
|
||||||
|
macro (gz_build_tests)
|
||||||
|
endmacro()
|
||||||
|
macro (gz_build_qt_tests)
|
||||||
|
endmacro()
|
||||||
|
macro (gz_build_display_tests)
|
||||||
|
endmacro()
|
||||||
|
macro (gz_build_dri_tests)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
if (ENABLE_TESTS_COMPILATION)
|
||||||
|
include (${gazebo_cmake_dir}/GazeboTestUtils.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Macro to setup supported compiler flags
|
||||||
|
# Based on work of Florent Lamiraux, Thomas Moulard, JRL, CNRS/AIST.
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
|
macro(filter_valid_compiler_flags)
|
||||||
|
foreach(flag ${ARGN})
|
||||||
|
CHECK_CXX_COMPILER_FLAG(${flag} R${flag})
|
||||||
|
if(${R${flag}})
|
||||||
|
set(VALID_CXX_FLAGS "${VALID_CXX_FLAGS} ${flag}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
|
@ -0,0 +1,28 @@
|
||||||
|
include (${gazebo_cmake_dir}/FindSSE.cmake)
|
||||||
|
|
||||||
|
if (SSE2_FOUND)
|
||||||
|
set (CMAKE_C_FLAGS_ALL "-msse -msse2 ${CMAKE_C_FLAGS_ALL}")
|
||||||
|
if (NOT APPLE)
|
||||||
|
set (CMAKE_C_FLAGS_ALL "-mfpmath=sse ${CMAKE_C_FLAGS_ALL}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (SSE3_FOUND)
|
||||||
|
set (CMAKE_C_FLAGS_ALL "-msse3 ${CMAKE_C_FLAGS_ALL}")
|
||||||
|
endif()
|
||||||
|
if (SSSE3_FOUND)
|
||||||
|
set (CMAKE_C_FLAGS_ALL "-mssse3 ${CMAKE_C_FLAGS_ALL}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_SSE4)
|
||||||
|
message(STATUS "\nSSE4 will be enabled if system supports it.\n")
|
||||||
|
if (SSE4_1_FOUND)
|
||||||
|
set (CMAKE_C_FLAGS_ALL "-msse4.1 ${CMAKE_C_FLAGS_ALL}")
|
||||||
|
endif()
|
||||||
|
if (SSE4_2_FOUND)
|
||||||
|
set (CMAKE_C_FLAGS_ALL "-msse4.2 ${CMAKE_C_FLAGS_ALL}")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "\nSSE4 disabled.\n")
|
||||||
|
endif()
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
macro(ADD_MANPAGE_TARGET)
|
||||||
|
# It is not possible add a dependency to target 'install'
|
||||||
|
# Run hard-coded 'make man' when 'make install' is invoked
|
||||||
|
install(CODE "EXECUTE_PROCESS(COMMAND make man)")
|
||||||
|
add_custom_target(man)
|
||||||
|
endmacro(ADD_MANPAGE_TARGET)
|
||||||
|
|
||||||
|
find_program(GZIP gzip)
|
||||||
|
|
||||||
|
if (NOT GZIP)
|
||||||
|
BUILD_WARNING ("gzip not found, manpages won't be generated")
|
||||||
|
macro(roffman MANFILE)
|
||||||
|
endmacro(roffman)
|
||||||
|
else (NOT GZIP)
|
||||||
|
message (STATUS "Looking for gzip to generate manpages - found")
|
||||||
|
|
||||||
|
macro(roffman _source _section)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_source}.${_section}.gz
|
||||||
|
COMMAND ${GZIP} -c ${CMAKE_CURRENT_SOURCE_DIR}/${_source}.${_section}.roff
|
||||||
|
> ${CMAKE_CURRENT_BINARY_DIR}/${_source}.${_section}.gz
|
||||||
|
)
|
||||||
|
|
||||||
|
set(MANPAGE_TARGET "man-${_source}")
|
||||||
|
|
||||||
|
add_custom_target(${MANPAGE_TARGET}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${_source}.${_section}.gz)
|
||||||
|
add_dependencies(man ${MANPAGE_TARGET})
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_source}.${_section}.gz
|
||||||
|
DESTINATION share/man/man${_section}
|
||||||
|
)
|
||||||
|
endmacro(roffman _source _section)
|
||||||
|
endif(NOT GZIP)
|
|
@ -0,0 +1,52 @@
|
||||||
|
#
|
||||||
|
# Based on work of Emmanuel Roullit <emmanuel@netsniff-ng.org>
|
||||||
|
# Copyright 2009, 2012 Emmanuel Roullit.
|
||||||
|
# Subject to the GPL, version 2.
|
||||||
|
#
|
||||||
|
FIND_PROGRAM(RONN ronn)
|
||||||
|
FIND_PROGRAM(GZIP gzip)
|
||||||
|
|
||||||
|
IF (NOT RONN OR NOT GZIP)
|
||||||
|
IF (NOT RONN)
|
||||||
|
BUILD_WARNING ("ronn not found, manpages won't be generated")
|
||||||
|
ENDIF(NOT RONN)
|
||||||
|
IF (NOT GZIP)
|
||||||
|
BUILD_WARNING ("gzip not found, manpages won't be generated")
|
||||||
|
ENDIF(NOT GZIP)
|
||||||
|
# empty macro
|
||||||
|
MACRO(manpage MANFILE)
|
||||||
|
ENDMACRO(manpage)
|
||||||
|
SET (MANPAGES_SUPPORT FALSE)
|
||||||
|
ELSE (NOT RONN OR NOT GZIP)
|
||||||
|
MESSAGE (STATUS "Looking for ronn to generate manpages - found")
|
||||||
|
SET (MANPAGES_SUPPORT TRUE)
|
||||||
|
|
||||||
|
MACRO(manpage RONNFILE SECTION)
|
||||||
|
SET(RONNFILE_FULL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${RONNFILE})
|
||||||
|
|
||||||
|
ADD_CUSTOM_COMMAND(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
|
||||||
|
DEPENDS ${RONNFILE}
|
||||||
|
COMMAND ${RONN}
|
||||||
|
ARGS -r --pipe ${RONNFILE_FULL_PATH}.${SECTION}.ronn
|
||||||
|
> ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
|
||||||
|
)
|
||||||
|
|
||||||
|
ADD_CUSTOM_COMMAND(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz
|
||||||
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
|
||||||
|
COMMAND ${GZIP} -c ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}
|
||||||
|
> ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(MANPAGE_TARGET "man-${RONNFILE}")
|
||||||
|
|
||||||
|
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz)
|
||||||
|
ADD_DEPENDENCIES(man ${MANPAGE_TARGET})
|
||||||
|
|
||||||
|
INSTALL(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz
|
||||||
|
DESTINATION share/man/man${SECTION}
|
||||||
|
)
|
||||||
|
ENDMACRO(manpage RONNFILE SECTION)
|
||||||
|
ENDIF(NOT RONN OR NOT GZIP)
|
|
@ -0,0 +1,731 @@
|
||||||
|
include (${gazebo_cmake_dir}/GazeboUtils.cmake)
|
||||||
|
include (CheckCXXSourceCompiles)
|
||||||
|
|
||||||
|
include (${gazebo_cmake_dir}/FindOS.cmake)
|
||||||
|
include (FindPkgConfig)
|
||||||
|
include (${gazebo_cmake_dir}/FindFreeimage.cmake)
|
||||||
|
|
||||||
|
execute_process(COMMAND pkg-config --modversion protobuf
|
||||||
|
OUTPUT_VARIABLE PROTOBUF_VERSION
|
||||||
|
RESULT_VARIABLE protobuf_modversion_failed)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# 1. can not use BUILD_TYPE_PROFILE is defined after include this module
|
||||||
|
# 2. TODO: TOUPPER is a hack until we fix the build system to support standard build names
|
||||||
|
if (CMAKE_BUILD_TYPE)
|
||||||
|
string(TOUPPER ${CMAKE_BUILD_TYPE} TMP_CMAKE_BUILD_TYPE)
|
||||||
|
if ("${TMP_CMAKE_BUILD_TYPE}" STREQUAL "PROFILE")
|
||||||
|
include (${gazebo_cmake_dir}/FindGooglePerfTools.cmake)
|
||||||
|
if (GOOGLE_PERFTOOLS_FOUND)
|
||||||
|
message(STATUS "Include google-perftools")
|
||||||
|
else()
|
||||||
|
BUILD_ERROR("Need google/heap-profiler.h (libgoogle-perftools-dev) tools to compile in Profile mode")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
if (PROTOBUF_VERSION LESS 2.3.0)
|
||||||
|
BUILD_ERROR("Incorrect version: Gazebo requires protobuf version 2.3.0 or greater")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# The Google Protobuf library for message generation + serialization
|
||||||
|
find_package(Protobuf REQUIRED)
|
||||||
|
if (NOT PROTOBUF_FOUND)
|
||||||
|
BUILD_ERROR ("Missing: Google Protobuf (libprotobuf-dev)")
|
||||||
|
endif()
|
||||||
|
if (NOT PROTOBUF_PROTOC_EXECUTABLE)
|
||||||
|
BUILD_ERROR ("Missing: Google Protobuf Compiler (protobuf-compiler)")
|
||||||
|
endif()
|
||||||
|
if (NOT PROTOBUF_PROTOC_LIBRARY)
|
||||||
|
BUILD_ERROR ("Missing: Google Protobuf Compiler Library (libprotoc-dev)")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
|
set (GZ_PROTOBUF_LIBRARY ${PROTOBUF_LIBRARY_DEBUG})
|
||||||
|
set (GZ_PROTOBUF_PROTOC_LIBRARY ${PROTOBUF_PROTOC_LIBRARY_DEBUG})
|
||||||
|
else()
|
||||||
|
set (GZ_PROTOBUF_LIBRARY ${PROTOBUF_LIBRARY})
|
||||||
|
set (GZ_PROTOBUF_PROTOC_LIBRARY ${PROTOBUF_PROTOC_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
include (FindOpenGL)
|
||||||
|
if (NOT OPENGL_FOUND)
|
||||||
|
BUILD_ERROR ("Missing: OpenGL")
|
||||||
|
set (HAVE_OPENGL FALSE)
|
||||||
|
else ()
|
||||||
|
if (OPENGL_INCLUDE_DIR)
|
||||||
|
APPEND_TO_CACHED_LIST(gazeboserver_include_dirs
|
||||||
|
${gazeboserver_include_dirs_desc}
|
||||||
|
${OPENGL_INCLUDE_DIR})
|
||||||
|
set (HAVE_OPENGL TRUE)
|
||||||
|
add_definitions(-DHAVE_OPENGL)
|
||||||
|
endif()
|
||||||
|
if (OPENGL_LIBRARIES)
|
||||||
|
APPEND_TO_CACHED_LIST(gazeboserver_link_libs
|
||||||
|
${gazeboserver_link_libs_desc}
|
||||||
|
${OPENGL_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
include (FindOpenAL)
|
||||||
|
if (NOT OPENAL_FOUND)
|
||||||
|
BUILD_WARNING ("OpenAL not found, audio support will be disabled.")
|
||||||
|
set (HAVE_OPENAL OFF CACHE BOOL "HAVE OpenAL" FORCE)
|
||||||
|
else ()
|
||||||
|
set (HAVE_OPENAL ON CACHE BOOL "HAVE OpenAL" FORCE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
find_package(HDF5 COMPONENTS C CXX)
|
||||||
|
|
||||||
|
if (NOT HDF5_FOUND)
|
||||||
|
BUILD_WARNING("HDF5 not found")
|
||||||
|
else ()
|
||||||
|
message(STATUS "HDF5 Found")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find packages
|
||||||
|
|
||||||
|
# In Visual Studio we use configure.bat to trick all path cmake
|
||||||
|
# variables so let's consider that as a replacement for pkgconfig
|
||||||
|
if (MSVC)
|
||||||
|
set (PKG_CONFIG_FOUND TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(CURL libcurl)
|
||||||
|
if (NOT CURL_FOUND)
|
||||||
|
BUILD_ERROR ("Missing: libcurl. Required for connection to model database.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
pkg_check_modules(PROFILER libprofiler)
|
||||||
|
if (PROFILER_FOUND)
|
||||||
|
set (CMAKE_LINK_FLAGS_PROFILE "-Wl,--no-as-needed -lprofiler -Wl,--as-needed ${CMAKE_LINK_FLAGS_PROFILE}" CACHE INTERNAL "Link flags for profile")
|
||||||
|
else ()
|
||||||
|
find_library(PROFILER profiler)
|
||||||
|
if (PROFILER)
|
||||||
|
message (STATUS "Looking for libprofiler - found")
|
||||||
|
set (CMAKE_LINK_FLAGS_PROFILE "-Wl,--no-as-needed -lprofiler -Wl,--as-needed ${CMAKE_LINK_FLAGS_PROFILE}" CACHE INTERNAL "Link flags for profile")
|
||||||
|
else()
|
||||||
|
message (STATUS "Looking for libprofiler - not found")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
pkg_check_modules(TCMALLOC libtcmalloc)
|
||||||
|
if (TCMALLOC_FOUND)
|
||||||
|
set (CMAKE_LINK_FLAGS_PROFILE "${CMAKE_LINK_FLAGS_PROFILE} -Wl,--no-as-needed -ltcmalloc -Wl,--no-as-needed"
|
||||||
|
CACHE INTERNAL "Link flags for profile" FORCE)
|
||||||
|
else ()
|
||||||
|
find_library(TCMALLOC tcmalloc)
|
||||||
|
if (TCMALLOC)
|
||||||
|
message (STATUS "Looking for libtcmalloc - found")
|
||||||
|
set (CMAKE_LINK_FLAGS_PROFILE "${CMAKE_LINK_FLAGS_PROFILE} -ltcmalloc"
|
||||||
|
CACHE INTERNAL "Link flags for profile" FORCE)
|
||||||
|
else ()
|
||||||
|
message (STATUS "Looking for libtcmalloc - not found")
|
||||||
|
endif()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find Simbody
|
||||||
|
set(SimTK_INSTALL_DIR ${SimTK_INSTALL_PREFIX})
|
||||||
|
#list(APPEND CMAKE_MODULE_PATH ${SimTK_INSTALL_PREFIX}/share/cmake)
|
||||||
|
find_package(Simbody)
|
||||||
|
if (Simbody_FOUND)
|
||||||
|
set (HAVE_SIMBODY TRUE)
|
||||||
|
else()
|
||||||
|
BUILD_WARNING ("Simbody not found, for simbody physics engine option, please install libsimbody-dev.")
|
||||||
|
set (HAVE_SIMBODY FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find DART
|
||||||
|
find_package(DARTCore 4.3.3 QUIET)
|
||||||
|
if (DARTCore_FOUND)
|
||||||
|
message (STATUS "Looking for DARTCore - found")
|
||||||
|
set (HAVE_DART TRUE)
|
||||||
|
else()
|
||||||
|
message (STATUS "Looking for DARTCore - not found")
|
||||||
|
BUILD_WARNING ("DART not found, for dart physics engine option, please install libdart-core4-dev.")
|
||||||
|
set (HAVE_DART FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find tinyxml. Only debian distributions package tinyxml with a pkg-config
|
||||||
|
# Use pkg_check_modules and fallback to manual detection
|
||||||
|
# (needed, at least, for MacOS)
|
||||||
|
|
||||||
|
# Use system installation on UNIX and Apple, and internal copy on Windows
|
||||||
|
if (UNIX OR APPLE)
|
||||||
|
message (STATUS "Using system tinyxml.")
|
||||||
|
set (USE_EXTERNAL_TINYXML True)
|
||||||
|
elseif(WIN32)
|
||||||
|
message (STATUS "Using internal tinyxml.")
|
||||||
|
set (USE_EXTERNAL_TINYXML False)
|
||||||
|
add_definitions(-DTIXML_USE_STL)
|
||||||
|
else()
|
||||||
|
message (STATUS "Unknown platform, unable to configure tinyxml.")
|
||||||
|
BUILD_ERROR("Unknown platform")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (USE_EXTERNAL_TINYXML)
|
||||||
|
pkg_check_modules(tinyxml tinyxml)
|
||||||
|
if (NOT tinyxml_FOUND)
|
||||||
|
find_path (tinyxml_INCLUDE_DIRS tinyxml.h ${tinyxml_INCLUDE_DIRS} ENV CPATH)
|
||||||
|
find_library(tinyxml_LIBRARIES NAMES tinyxml)
|
||||||
|
set (tinyxml_FAIL False)
|
||||||
|
if (NOT tinyxml_INCLUDE_DIRS)
|
||||||
|
message (STATUS "Looking for tinyxml headers - not found")
|
||||||
|
set (tinyxml_FAIL True)
|
||||||
|
endif()
|
||||||
|
if (NOT tinyxml_LIBRARIES)
|
||||||
|
message (STATUS "Looking for tinyxml library - not found")
|
||||||
|
set (tinyxml_FAIL True)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (tinyxml_FAIL)
|
||||||
|
message (STATUS "Looking for tinyxml.h - not found")
|
||||||
|
BUILD_ERROR("Missing: tinyxml")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# Needed in WIN32 since in UNIX the flag is added in the code installed
|
||||||
|
message (STATUS "Skipping search for tinyxml")
|
||||||
|
set (tinyxml_INCLUDE_DIRS "")
|
||||||
|
set (tinyxml_LIBRARIES "")
|
||||||
|
set (tinyxml_LIBRARY_DIRS "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find tinyxml2. Only debian distributions package tinyxml with a pkg-config
|
||||||
|
# Use pkg_check_modules and fallback to manual detection
|
||||||
|
# (needed, at least, for MacOS)
|
||||||
|
|
||||||
|
# Use system installation on UNIX and Apple, and internal copy on Windows
|
||||||
|
if (UNIX OR APPLE)
|
||||||
|
message (STATUS "Using system tinyxml2.")
|
||||||
|
set (USE_EXTERNAL_TINYXML2 True)
|
||||||
|
elseif(WIN32)
|
||||||
|
message (STATUS "Using internal tinyxml2.")
|
||||||
|
set (USE_EXTERNAL_TINYXML2 False)
|
||||||
|
else()
|
||||||
|
message (STATUS "Unknown platform, unable to configure tinyxml2.")
|
||||||
|
BUILD_ERROR("Unknown platform")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (USE_EXTERNAL_TINYXML2)
|
||||||
|
pkg_check_modules(tinyxml2 tinyxml2)
|
||||||
|
if (NOT tinyxml2_FOUND)
|
||||||
|
find_path (tinyxml2_INCLUDE_DIRS tinyxml2.h ${tinyxml2_INCLUDE_DIRS} ENV CPATH)
|
||||||
|
find_library(tinyxml2_LIBRARIES NAMES tinyxml2)
|
||||||
|
set (tinyxml2_FAIL False)
|
||||||
|
if (NOT tinyxml2_INCLUDE_DIRS)
|
||||||
|
message (STATUS "Looking for tinyxml2 headers - not found")
|
||||||
|
set (tinyxml2_FAIL True)
|
||||||
|
endif()
|
||||||
|
if (NOT tinyxml2_LIBRARIES)
|
||||||
|
message (STATUS "Looking for tinyxml2 library - not found")
|
||||||
|
set (tinyxml2_FAIL True)
|
||||||
|
endif()
|
||||||
|
if (NOT tinyxml2_LIBRARY_DIRS)
|
||||||
|
message (STATUS "Looking for tinyxml2 library dirs - not found")
|
||||||
|
set (tinyxml2_FAIL True)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (tinyxml2_FAIL)
|
||||||
|
message (STATUS "Looking for tinyxml2.h - not found")
|
||||||
|
BUILD_ERROR("Missing: tinyxml2")
|
||||||
|
else()
|
||||||
|
include_directories(${tinyxml2_INCLUDE_DIRS})
|
||||||
|
link_directories(${tinyxml2_LIBRARY_DIRS})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# Needed in WIN32 since in UNIX the flag is added in the code installed
|
||||||
|
message (STATUS "Skipping search for tinyxml2")
|
||||||
|
set (tinyxml2_INCLUDE_DIRS "")
|
||||||
|
set (tinyxml2_LIBRARIES "")
|
||||||
|
set (tinyxml2_LIBRARY_DIRS "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
#################################################
|
||||||
|
# Find libtar.
|
||||||
|
find_path (libtar_INCLUDE_DIRS libtar.h)
|
||||||
|
find_library(libtar_LIBRARIES tar)
|
||||||
|
set (LIBTAR_FOUND True)
|
||||||
|
|
||||||
|
if (NOT libtar_INCLUDE_DIRS)
|
||||||
|
message (STATUS "Looking for libtar.h - not found")
|
||||||
|
set (LIBTAR_FOUND False)
|
||||||
|
else ()
|
||||||
|
message (STATUS "Looking for libtar.h - found")
|
||||||
|
include_directories(${libtar_INCLUDE_DIRS})
|
||||||
|
endif ()
|
||||||
|
if (NOT libtar_LIBRARIES)
|
||||||
|
message (STATUS "Looking for libtar.so - not found")
|
||||||
|
set (LIBTAR_FOUND False)
|
||||||
|
else ()
|
||||||
|
message (STATUS "Looking for libtar.so - found")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT LIBTAR_FOUND)
|
||||||
|
BUILD_ERROR("Missing: libtar")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(libtar_LIBRARIES "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find TBB
|
||||||
|
pkg_check_modules(TBB tbb)
|
||||||
|
set (TBB_PKG_CONFIG "tbb")
|
||||||
|
if (NOT TBB_FOUND)
|
||||||
|
message(STATUS "TBB not found, attempting to detect manually")
|
||||||
|
set (TBB_PKG_CONFIG "")
|
||||||
|
|
||||||
|
find_library(tbb_library tbb ENV LD_LIBRARY_PATH)
|
||||||
|
if (tbb_library)
|
||||||
|
set(TBB_FOUND true)
|
||||||
|
set(TBB_LIBRARIES ${tbb_library})
|
||||||
|
else (tbb_library)
|
||||||
|
BUILD_ERROR ("Missing: TBB - Threading Building Blocks")
|
||||||
|
endif(tbb_library)
|
||||||
|
endif (NOT TBB_FOUND)
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find OGRE
|
||||||
|
# On Windows, we assume that all the OGRE* defines are passed in manually
|
||||||
|
# to CMake.
|
||||||
|
if (NOT WIN32)
|
||||||
|
execute_process(COMMAND pkg-config --modversion OGRE
|
||||||
|
OUTPUT_VARIABLE OGRE_VERSION)
|
||||||
|
string(REPLACE "\n" "" OGRE_VERSION ${OGRE_VERSION})
|
||||||
|
|
||||||
|
string (REGEX REPLACE "^([0-9]+).*" "\\1"
|
||||||
|
OGRE_MAJOR_VERSION "${OGRE_VERSION}")
|
||||||
|
string (REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1"
|
||||||
|
OGRE_MINOR_VERSION "${OGRE_VERSION}")
|
||||||
|
string (REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1"
|
||||||
|
OGRE_PATCH_VERSION ${OGRE_VERSION})
|
||||||
|
|
||||||
|
set(OGRE_VERSION
|
||||||
|
${OGRE_MAJOR_VERSION}.${OGRE_MINOR_VERSION}.${OGRE_PATCH_VERSION})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
pkg_check_modules(OGRE-RTShaderSystem
|
||||||
|
OGRE-RTShaderSystem>=${MIN_OGRE_VERSION})
|
||||||
|
|
||||||
|
if (OGRE-RTShaderSystem_FOUND)
|
||||||
|
set(ogre_ldflags ${OGRE-RTShaderSystem_LDFLAGS})
|
||||||
|
set(ogre_include_dirs ${OGRE-RTShaderSystem_INCLUDE_DIRS})
|
||||||
|
set(ogre_libraries ${OGRE-RTShaderSystem_LIBRARIES})
|
||||||
|
set(ogre_library_dirs ${OGRE-RTShaderSystem_LIBRARY_DIRS})
|
||||||
|
set(ogre_cflags ${OGRE-RTShaderSystem_CFLAGS})
|
||||||
|
|
||||||
|
set (INCLUDE_RTSHADER ON CACHE BOOL "Enable GPU shaders")
|
||||||
|
else ()
|
||||||
|
set (INCLUDE_RTSHADER OFF CACHE BOOL "Enable GPU shaders")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
pkg_check_modules(OGRE OGRE>=${MIN_OGRE_VERSION})
|
||||||
|
# There are some runtime problems to solve with ogre-1.9.
|
||||||
|
# Please read gazebo issues: 994, 995
|
||||||
|
if (NOT OGRE_FOUND)
|
||||||
|
BUILD_ERROR("Missing: Ogre3d version >=${MIN_OGRE_VERSION}(http://www.orge3d.org)")
|
||||||
|
else ()
|
||||||
|
set(ogre_ldflags ${ogre_ldflags} ${OGRE_LDFLAGS})
|
||||||
|
set(ogre_include_dirs ${ogre_include_dirs} ${OGRE_INCLUDE_DIRS})
|
||||||
|
set(ogre_libraries ${ogre_libraries};${OGRE_LIBRARIES})
|
||||||
|
set(ogre_library_dirs ${ogre_library_dirs} ${OGRE_LIBRARY_DIRS})
|
||||||
|
set(ogre_cflags ${ogre_cflags} ${OGRE_CFLAGS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
pkg_check_modules(OGRE-Terrain OGRE-Terrain)
|
||||||
|
if (OGRE-Terrain_FOUND)
|
||||||
|
set(ogre_ldflags ${ogre_ldflags} ${OGRE-Terrain_LDFLAGS})
|
||||||
|
set(ogre_include_dirs ${ogre_include_dirs} ${OGRE-Terrain_INCLUDE_DIRS})
|
||||||
|
set(ogre_libraries ${ogre_libraries};${OGRE-Terrain_LIBRARIES})
|
||||||
|
set(ogre_library_dirs ${ogre_library_dirs} ${OGRE-Terrain_LIBRARY_DIRS})
|
||||||
|
set(ogre_cflags ${ogre_cflags} ${OGRE-Terrain_CFLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
pkg_check_modules(OGRE-Overlay OGRE-Overlay)
|
||||||
|
if (OGRE-Overlay_FOUND)
|
||||||
|
set(ogre_ldflags ${ogre_ldflags} ${OGRE-Overlay_LDFLAGS})
|
||||||
|
set(ogre_include_dirs ${ogre_include_dirs} ${OGRE-Overlay_INCLUDE_DIRS})
|
||||||
|
set(ogre_libraries ${ogre_libraries};${OGRE-Overlay_LIBRARIES})
|
||||||
|
set(ogre_library_dirs ${ogre_library_dirs} ${OGRE-Overlay_LIBRARY_DIRS})
|
||||||
|
set(ogre_cflags ${ogre_cflags} ${OGRE-Overlay_CFLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
set (OGRE_INCLUDE_DIRS ${ogre_include_dirs}
|
||||||
|
CACHE INTERNAL "Ogre include path")
|
||||||
|
|
||||||
|
# Also find OGRE's plugin directory, which is provided in its .pc file as the
|
||||||
|
# `plugindir` variable. We have to call pkg-config manually to get it.
|
||||||
|
# On Windows, we assume that all the OGRE* defines are passed in manually
|
||||||
|
# to CMake.
|
||||||
|
if (NOT WIN32)
|
||||||
|
execute_process(COMMAND pkg-config --variable=plugindir OGRE
|
||||||
|
OUTPUT_VARIABLE _pkgconfig_invoke_result
|
||||||
|
RESULT_VARIABLE _pkgconfig_failed)
|
||||||
|
if(_pkgconfig_failed)
|
||||||
|
BUILD_WARNING ("Failed to find OGRE's plugin directory. The build will succeed, but gazebo will likely fail to run.")
|
||||||
|
else()
|
||||||
|
# This variable will be substituted into cmake/setup.sh.in
|
||||||
|
set (OGRE_PLUGINDIR ${_pkgconfig_invoke_result})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Check and find libccd (if needed)
|
||||||
|
pkg_check_modules(CCD ccd>=1.4)
|
||||||
|
if (NOT CCD_FOUND)
|
||||||
|
message(STATUS "Using internal copy of libccd")
|
||||||
|
set(CCD_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/deps/libccd/include")
|
||||||
|
set(CCD_LIBRARY_DIRS "${CMAKE_BINARY_DIR}/deps/libccd")
|
||||||
|
set(CCD_LIBRARIES gazebo_ccd)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find OpenAL
|
||||||
|
# pkg_check_modules(OAL openal)
|
||||||
|
# if (NOT OAL_FOUND)
|
||||||
|
# BUILD_WARNING ("Openal not found. Audio capabilities will be disabled.")
|
||||||
|
# set (HAVE_OPENAL FALSE)
|
||||||
|
# else (NOT OAL_FOUND)
|
||||||
|
# set (HAVE_OPENAL TRUE)
|
||||||
|
# endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find libswscale format
|
||||||
|
pkg_check_modules(libswscale libswscale)
|
||||||
|
if (NOT libswscale_FOUND)
|
||||||
|
BUILD_WARNING ("libswscale not found. Audio-video capabilities will be disabled.")
|
||||||
|
else()
|
||||||
|
include_directories(${libswscale_INCLUDE_DIRS})
|
||||||
|
link_directories(${libswscale_LIBRARY_DIRS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find AV format
|
||||||
|
pkg_check_modules(libavformat libavformat)
|
||||||
|
if (NOT libavformat_FOUND)
|
||||||
|
BUILD_WARNING ("libavformat not found. Audio-video capabilities will be disabled.")
|
||||||
|
else()
|
||||||
|
include_directories(${libavformat_INCLUDE_DIRS})
|
||||||
|
link_directories(${libavformat_LIBRARY_DIRS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find avcodec
|
||||||
|
pkg_check_modules(libavcodec libavcodec)
|
||||||
|
if (NOT libavcodec_FOUND)
|
||||||
|
BUILD_WARNING ("libavcodec not found. Audio-video capabilities will be disabled.")
|
||||||
|
else()
|
||||||
|
include_directories(${libavcodec_INCLUDE_DIRS})
|
||||||
|
link_directories(${libavcodec_LIBRARY_DIRS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find avutil
|
||||||
|
pkg_check_modules(libavutil libavutil)
|
||||||
|
if (NOT libavutil_FOUND)
|
||||||
|
BUILD_WARNING ("libavutil not found. Audio-video capabilities will be disabled.")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
if (libavutil_FOUND AND libavformat_FOUND AND libavcodec_FOUND AND libswscale_FOUND)
|
||||||
|
set (HAVE_FFMPEG TRUE)
|
||||||
|
else ()
|
||||||
|
set (HAVE_FFMPEG FALSE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find Player
|
||||||
|
pkg_check_modules(PLAYER playercore>=3.0 playerc++ playerwkb)
|
||||||
|
if (NOT PLAYER_FOUND)
|
||||||
|
set (INCLUDE_PLAYER OFF CACHE BOOL "Build gazebo plugin for player")
|
||||||
|
BUILD_WARNING ("Player not found, gazebo plugin for player will not be built.")
|
||||||
|
else (NOT PLAYER_FOUND)
|
||||||
|
set (INCLUDE_PLAYER ON CACHE BOOL "Build gazebo plugin for player")
|
||||||
|
set (PLAYER_INCLUDE_DIRS ${PLAYER_INCLUDE_DIRS} CACHE INTERNAL
|
||||||
|
"Player include directory")
|
||||||
|
set (PLAYER_LINK_DIRS ${PLAYER_LINK_DIRS} CACHE INTERNAL
|
||||||
|
"Player link directory")
|
||||||
|
set (PLAYER_LINK_LIBS ${PLAYER_LIBRARIES} CACHE INTERNAL
|
||||||
|
"Player libraries")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find GNU Triangulation Surface Library
|
||||||
|
pkg_check_modules(gts gts)
|
||||||
|
if (gts_FOUND)
|
||||||
|
message (STATUS "Looking for GTS - found")
|
||||||
|
set (HAVE_GTS TRUE)
|
||||||
|
else ()
|
||||||
|
set (HAVE_GTS FALSE)
|
||||||
|
BUILD_WARNING ("GNU Triangulation Surface library not found - Gazebo will not have CSG support.")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find bullet
|
||||||
|
# First and preferred option is to look for bullet standard pkgconfig,
|
||||||
|
# so check it first. if it is not present, check for the OSRF
|
||||||
|
# custom bullet2.82.pc file
|
||||||
|
pkg_check_modules(BULLET bullet>=2.82)
|
||||||
|
if (NOT BULLET_FOUND)
|
||||||
|
pkg_check_modules(BULLET bullet2.82>=2.82)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (BULLET_FOUND)
|
||||||
|
set (HAVE_BULLET TRUE)
|
||||||
|
add_definitions( -DLIBBULLET_VERSION=${BULLET_VERSION} )
|
||||||
|
else()
|
||||||
|
set (HAVE_BULLET FALSE)
|
||||||
|
add_definitions( -DLIBBULLET_VERSION=0.0 )
|
||||||
|
BUILD_WARNING ("Bullet > 2.82 not found, for bullet physics engine option, please install libbullet2.82-dev.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (BULLET_VERSION VERSION_GREATER 2.82)
|
||||||
|
add_definitions( -DLIBBULLET_VERSION_GT_282 )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find libusb
|
||||||
|
pkg_check_modules(libusb-1.0 libusb-1.0)
|
||||||
|
if (NOT libusb-1.0_FOUND)
|
||||||
|
BUILD_WARNING ("libusb-1.0 not found. USB peripherals support will be disabled.")
|
||||||
|
set (HAVE_USB OFF CACHE BOOL "HAVE USB" FORCE)
|
||||||
|
else()
|
||||||
|
message (STATUS "Looking for libusb-1.0 - found. USB peripherals support enabled.")
|
||||||
|
set (HAVE_USB ON CACHE BOOL "HAVE USB" FORCE)
|
||||||
|
include_directories(${libusb-1.0_INCLUDE_DIRS})
|
||||||
|
link_directories(${libusb-1.0_LIBRARY_DIRS})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Find Oculus SDK.
|
||||||
|
pkg_check_modules(OculusVR OculusVR)
|
||||||
|
|
||||||
|
if (HAVE_USB AND OculusVR_FOUND)
|
||||||
|
message (STATUS "Oculus Rift support enabled.")
|
||||||
|
set (HAVE_OCULUS ON CACHE BOOL "HAVE OCULUS" FORCE)
|
||||||
|
include_directories(SYSTEM ${OculusVR_INCLUDE_DIRS})
|
||||||
|
link_directories(${OculusVR_LIBRARY_DIRS})
|
||||||
|
else ()
|
||||||
|
BUILD_WARNING ("Oculus Rift support will be disabled.")
|
||||||
|
set (HAVE_OCULUS OFF CACHE BOOL "HAVE OCULUS" FORCE)
|
||||||
|
endif()
|
||||||
|
else (PKG_CONFIG_FOUND)
|
||||||
|
set (BUILD_GAZEBO OFF CACHE INTERNAL "Build Gazebo" FORCE)
|
||||||
|
BUILD_ERROR ("Error: pkg-config not found")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find SDFormat
|
||||||
|
set (SDFormat_MIN_VERSION 4.1.0)
|
||||||
|
find_package(SDFormat ${SDFormat_MIN_VERSION})
|
||||||
|
|
||||||
|
if (NOT SDFormat_FOUND)
|
||||||
|
message (STATUS "Looking for SDFormat - not found")
|
||||||
|
BUILD_ERROR ("Missing: SDF version >=${SDFormat_MIN_VERSION}. Required for reading and writing SDF files.")
|
||||||
|
else()
|
||||||
|
message (STATUS "Looking for SDFormat - found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find QT
|
||||||
|
find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED)
|
||||||
|
if (NOT QT4_FOUND)
|
||||||
|
BUILD_ERROR("Missing: Qt4")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find Boost, if not specified manually
|
||||||
|
include(FindBoost)
|
||||||
|
find_package(Boost ${MIN_BOOST_VERSION} REQUIRED thread signals system filesystem program_options regex iostreams date_time)
|
||||||
|
|
||||||
|
if (NOT Boost_FOUND)
|
||||||
|
set (BUILD_GAZEBO OFF CACHE INTERNAL "Build Gazebo" FORCE)
|
||||||
|
BUILD_ERROR ("Boost not found. Please install thread signals system filesystem program_options regex date_time boost version ${MIN_BOOST_VERSION} or higher.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find libdl
|
||||||
|
find_path(libdl_include_dir dlfcn.h /usr/include /usr/local/include)
|
||||||
|
if (NOT libdl_include_dir)
|
||||||
|
message (STATUS "Looking for dlfcn.h - not found")
|
||||||
|
BUILD_ERROR ("Missing libdl: Required for plugins.")
|
||||||
|
set (libdl_include_dir /usr/include)
|
||||||
|
else (NOT libdl_include_dir)
|
||||||
|
message (STATUS "Looking for dlfcn.h - found")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
find_library(libdl_library dl /usr/lib /usr/local/lib)
|
||||||
|
if (NOT libdl_library)
|
||||||
|
message (STATUS "Looking for libdl - not found")
|
||||||
|
BUILD_ERROR ("Missing libdl: Required for plugins.")
|
||||||
|
set(libdl_library "")
|
||||||
|
else (NOT libdl_library)
|
||||||
|
message (STATUS "Looking for libdl - found")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find gdal
|
||||||
|
include (FindGDAL)
|
||||||
|
if (NOT GDAL_FOUND)
|
||||||
|
message (STATUS "Looking for libgdal - not found")
|
||||||
|
BUILD_WARNING ("GDAL not found, Digital elevation terrains support will be disabled.")
|
||||||
|
set (HAVE_GDAL OFF CACHE BOOL "HAVE GDAL" FORCE)
|
||||||
|
else ()
|
||||||
|
message (STATUS "Looking for libgdal - found")
|
||||||
|
set (HAVE_GDAL ON CACHE BOOL "HAVE GDAL" FORCE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Include man pages stuff
|
||||||
|
include (${gazebo_cmake_dir}/Ronn2Man.cmake)
|
||||||
|
include (${gazebo_cmake_dir}/Man.cmake)
|
||||||
|
add_manpage_target()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find Space Navigator header and library
|
||||||
|
find_library(SPNAV_LIBRARY NAMES spnav)
|
||||||
|
find_file(SPNAV_HEADER NAMES spnav.h)
|
||||||
|
if (SPNAV_LIBRARY AND SPNAV_HEADER)
|
||||||
|
message(STATUS "Looking for libspnav and spnav.h - found")
|
||||||
|
set(HAVE_SPNAV TRUE)
|
||||||
|
else()
|
||||||
|
message(STATUS "Looking for libspnav and spnav.h - not found")
|
||||||
|
set(HAVE_SPNAV FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find xsltproc, which is used by tools/check_test_ran.py
|
||||||
|
find_program(XSLTPROC xsltproc)
|
||||||
|
if (NOT EXISTS ${XSLTPROC})
|
||||||
|
BUILD_WARNING("xsltproc not found. The check_test_ran.py script will cause tests to fail.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find uuid-dev Library
|
||||||
|
#pkg_check_modules(uuid uuid)
|
||||||
|
#if (uuid_FOUND)
|
||||||
|
# message (STATUS "Looking for uuid - found")
|
||||||
|
# set (HAVE_UUID TRUE)
|
||||||
|
#else ()
|
||||||
|
# set (HAVE_UUID FALSE)
|
||||||
|
# BUILD_WARNING ("uuid-dev library not found - Gazebo will not have uuid support.")
|
||||||
|
#endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find uuid
|
||||||
|
# - In UNIX we use uuid library.
|
||||||
|
# - In Windows the native RPC call, no dependency needed.
|
||||||
|
if (UNIX)
|
||||||
|
pkg_check_modules(uuid uuid)
|
||||||
|
if (uuid_FOUND)
|
||||||
|
message (STATUS "Looking for uuid - found")
|
||||||
|
set (HAVE_UUID TRUE)
|
||||||
|
else ()
|
||||||
|
set (HAVE_UUID FALSE)
|
||||||
|
BUILD_WARNING ("uuid-dev library not found - Gazebo will not have uuid support.")
|
||||||
|
endif ()
|
||||||
|
else()
|
||||||
|
message (STATUS "Using Windows RPC UuidCreate function")
|
||||||
|
set (HAVE_UUID TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find graphviz
|
||||||
|
include (${gazebo_cmake_dir}/FindGraphviz.cmake)
|
||||||
|
if (NOT GRAPHVIZ_FOUND)
|
||||||
|
message (STATUS "Looking for libgraphviz-dev - not found")
|
||||||
|
BUILD_WARNING ("Graphviz not found, Model editor's schematic view will be disabled.")
|
||||||
|
set (HAVE_GRAPHVIZ OFF CACHE BOOL "HAVE GRAPHVIZ" FORCE)
|
||||||
|
else ()
|
||||||
|
message (STATUS "Looking for libgraphviz-dev - found")
|
||||||
|
set (HAVE_GRAPHVIZ ON CACHE BOOL "HAVE GRAPHVIZ" FORCE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find ignition math in unix platforms
|
||||||
|
# In Windows we expect a call from configure.bat script with the paths
|
||||||
|
if (NOT WIN32)
|
||||||
|
find_package(ignition-math2 2.4 QUIET)
|
||||||
|
if (NOT ignition-math2_FOUND)
|
||||||
|
message(STATUS "Looking for ignition-math2-config.cmake - not found")
|
||||||
|
BUILD_ERROR ("Missing: Ignition math2 library.")
|
||||||
|
else()
|
||||||
|
message(STATUS "Looking for ignition-math2-config.cmake - found")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find the Ignition_Transport library
|
||||||
|
# In Windows we expect a call from configure.bat script with the paths
|
||||||
|
if (NOT WIN32)
|
||||||
|
find_package(ignition-transport2 QUIET)
|
||||||
|
if (NOT ignition-transport2_FOUND)
|
||||||
|
find_package(ignition-transport1 QUIET)
|
||||||
|
if (NOT ignition-transport1_FOUND)
|
||||||
|
BUILD_WARNING ("Missing: Ignition Transport (libignition-transport-dev or libignition-transport2-dev")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (ignition-transport2_FOUND OR ignition-transport1_FOUND)
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IGNITION-TRANSPORT_CXX_FLAGS}")
|
||||||
|
include_directories(${IGNITION-TRANSPORT_INCLUDE_DIRS})
|
||||||
|
link_directories(${IGNITION-TRANSPORT_LIBRARY_DIRS})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
################################################
|
||||||
|
# Find Valgrind for checking memory leaks in the
|
||||||
|
# tests
|
||||||
|
find_program(VALGRIND_PROGRAM NAMES valgrind PATH ${VALGRIND_ROOT}/bin)
|
||||||
|
option(GAZEBO_RUN_VALGRIND_TESTS "Run gazebo tests with Valgrind" FALSE)
|
||||||
|
mark_as_advanced(GAZEBO_RUN_VALGRIND_TESTS)
|
||||||
|
if (GAZEBO_RUN_VALGRIND_TESTS AND NOT VALGRIND_PROGRAM)
|
||||||
|
BUILD_WARNING("valgrind not found. Memory check tests will be skipped.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Find QWT (QT graphing library)
|
||||||
|
#find_path(QWT_INCLUDE_DIR NAMES qwt.h PATHS
|
||||||
|
# /usr/include
|
||||||
|
# /usr/local/include
|
||||||
|
# "$ENV{LIB_DIR}/include"
|
||||||
|
# "$ENV{INCLUDE}"
|
||||||
|
# PATH_SUFFIXES qwt-qt4 qwt qwt5
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
#find_library(QWT_LIBRARY NAMES qwt qwt6 qwt5 PATHS
|
||||||
|
# /usr/lib
|
||||||
|
# /usr/local/lib
|
||||||
|
# "$ENV{LIB_DIR}/lib"
|
||||||
|
# "$ENV{LIB}/lib"
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
#if (QWT_INCLUDE_DIR AND QWT_LIBRARY)
|
||||||
|
# set(HAVE_QWT TRUE)
|
||||||
|
#endif (QWT_INCLUDE_DIR AND QWT_LIBRARY)
|
||||||
|
#
|
||||||
|
#if (HAVE_QWT)
|
||||||
|
# if (NOT QWT_FIND_QUIETLY)
|
||||||
|
# message(STATUS "Found Qwt: ${QWT_LIBRARY}")
|
||||||
|
# endif (NOT QWT_FIND_QUIETLY)
|
||||||
|
#else ()
|
||||||
|
# if (QWT_FIND_REQUIRED)
|
||||||
|
# BUILD_WARNING ("Could not find libqwt-dev. Plotting features will be disabled.")
|
||||||
|
# endif (QWT_FIND_REQUIRED)
|
||||||
|
#endif ()
|
|
@ -0,0 +1,21 @@
|
||||||
|
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||||
|
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||||
|
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||||
|
|
||||||
|
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||||
|
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||||
|
foreach(file ${files})
|
||||||
|
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
||||||
|
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||||
|
exec_program(
|
||||||
|
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||||
|
OUTPUT_VARIABLE rm_out
|
||||||
|
RETURN_VALUE rm_retval
|
||||||
|
)
|
||||||
|
if(NOT "${rm_retval}" STREQUAL 0)
|
||||||
|
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
||||||
|
endif(NOT "${rm_retval}" STREQUAL 0)
|
||||||
|
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||||
|
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
||||||
|
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||||
|
endforeach(file)
|
|
@ -0,0 +1,24 @@
|
||||||
|
set(CPACK_PACKAGE_NAME "@PROJECT_NAME@")
|
||||||
|
set(CPACK_PACKAGE_VENDOR "gazebosim.org")
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A 3D dynamics simulator for robotics")
|
||||||
|
set(CPACK_PACKAGE_INSTALL_DIRECTORY "@PROJECT_NAME_LOWER@")
|
||||||
|
set(CPACK_RESOURCE_FILE_LICENSE "@CMAKE_CURRENT_SOURCE_DIR@/LICENSE")
|
||||||
|
set(CPACK_RESOURCE_FILE_README "@CMAKE_CURRENT_SOURCE_DIR@/README")
|
||||||
|
set(CPACK_PACKAGE_DESCRIPTION_FILE "@CMAKE_CURRENT_SOURCE_DIR@/README")
|
||||||
|
set(CPACK_PACKAGE_MAINTAINER "Nate Koenig <gazebo@gazebosim.org>")
|
||||||
|
set(CPACK_PACKAGE_CONTACT "Nate Koenig <gazebo@gazebosim.org>")
|
||||||
|
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "@DPKG_ARCH@")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "@DEBIAN_PACKAGE_DEPENDS@")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A 3D dynamics simulator for robotics")
|
||||||
|
|
||||||
|
set(CPACK_RPM_PACKAGE_ARCHITECTURE "@DPKG_ARCH@")
|
||||||
|
set(CPACK_RPM_PACKAGE_REQUIRES "@DEBIAN_PACKAGE_DEPENDS@")
|
||||||
|
set(CPACK_RPM_PACKAGE_DESCRIPTION "A 3D dynamics simulator for robotics")
|
||||||
|
|
||||||
|
|
||||||
|
set (CPACK_PACKAGE_FILE_NAME "@PROJECT_NAME_LOWER@-@GAZEBO_VERSION_FULL@")
|
||||||
|
set (CPACK_SOURCE_PACKAGE_FILE_NAME "@PROJECT_NAME_LOWER@-@GAZEBO_VERSION_FULL@")
|
|
@ -0,0 +1,138 @@
|
||||||
|
if (@PKG_NAME@_CONFIG_INCLUDED)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(@PKG_NAME@_CONFIG_INCLUDED TRUE)
|
||||||
|
set(@PKG_NAME@_VERSION @GAZEBO_VERSION@)
|
||||||
|
set(@PKG_NAME@_MAJOR_VERSION @GAZEBO_MAJOR_VERSION@)
|
||||||
|
|
||||||
|
set(@PKG_NAME@_PLUGIN_PATH "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/plugins")
|
||||||
|
|
||||||
|
# The media path contains the location on disk where images,
|
||||||
|
# materials scripts, shaders, and other related resources are stored.
|
||||||
|
set(@PKG_NAME@_MEDIA_PATH "@CMAKE_INSTALL_PREFIX@/share/gazebo-@GAZEBO_MAJOR_VERSION@/media")
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# @PKG_NAME@_PROTO_PATH, @PKG_NAME@_PROTO_INCLUDE_DIRS, and
|
||||||
|
# @PKG_NAME@_PROTO_LIBRARIES
|
||||||
|
#
|
||||||
|
# These three variables allow Gazebo messages to be used in other projects.
|
||||||
|
#
|
||||||
|
# The following examples are for demonstration purposes and are
|
||||||
|
# incomplete. The first example shows how to use a Gazebo message in a
|
||||||
|
# custom proto file. The second example shows how to run 'protoc' against
|
||||||
|
# custom proto files that make use Gazebo message definitions. The third
|
||||||
|
# example shows how to include the correct directory when compiling a library
|
||||||
|
# or executable that uses your custom messages.
|
||||||
|
#
|
||||||
|
# 1. Use a Gazebo message in a custom proto file:
|
||||||
|
#
|
||||||
|
# package my.msgs;
|
||||||
|
# import "vector3d.proto";
|
||||||
|
#
|
||||||
|
# message MyMessage
|
||||||
|
# {
|
||||||
|
# required gazebo.msgs.Vector3d p = 1;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# 2. Run protoc from a CMakeLists.txt to generate your message's
|
||||||
|
# header and source files:
|
||||||
|
#
|
||||||
|
# add_custom_command(
|
||||||
|
# OUTPUT
|
||||||
|
# "${proto_filename}.pb.cc"
|
||||||
|
# "${proto_filename}.pb.h"
|
||||||
|
# COMMAND protoc
|
||||||
|
# ARGS --proto_path ${GAZEBO_PROTO_PATH} ${proto_file_out}
|
||||||
|
# COMMENT "Running C++ protocol buffer compiler on ${proto_filename}"
|
||||||
|
# VERBATIM)
|
||||||
|
#
|
||||||
|
# 3. When compiling your library or executable, make sure to use the following
|
||||||
|
# in the CMakeLists.txt file:
|
||||||
|
#
|
||||||
|
# include_directories(@PKG_NAME@_PROTO_INCLUDE_DIRS)
|
||||||
|
# target_link_libraries(your_package @PKG_NAME@_PROTO_LIBRARIES)
|
||||||
|
#
|
||||||
|
set(@PKG_NAME@_PROTO_PATH
|
||||||
|
"@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/gazebo/msgs/proto")
|
||||||
|
find_library(gazebo_proto_msgs_lib gazebo_msgs
|
||||||
|
PATHS "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@" NO_DEFAULT_PATH)
|
||||||
|
list(APPEND @PKG_NAME@_PROTO_LIBRARIES ${gazebo_proto_msgs_lib})
|
||||||
|
list(APPEND @PKG_NAME@_PROTO_INCLUDE_DIRS
|
||||||
|
"@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/gazebo/msgs")
|
||||||
|
# End @PKG_NAME@_PROTO_PATH, @PKG_NAME@_PROTO_INCLUDE_DIRS, and
|
||||||
|
# @PKG_NAME@_PROTO_LIBRARIES
|
||||||
|
|
||||||
|
list(APPEND @PKG_NAME@_INCLUDE_DIRS @CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@)
|
||||||
|
list(APPEND @PKG_NAME@_INCLUDE_DIRS @CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@/gazebo-@GAZEBO_MAJOR_VERSION@)
|
||||||
|
|
||||||
|
list(APPEND @PKG_NAME@_LIBRARY_DIRS @CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@)
|
||||||
|
list(APPEND @PKG_NAME@_LIBRARY_DIRS @CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/plugins)
|
||||||
|
|
||||||
|
list(APPEND @PKG_NAME@_CFLAGS -I@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@)
|
||||||
|
list(APPEND @PKG_NAME@_CFLAGS -I@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@/gazebo-@GAZEBO_MAJOR_VERSION@)
|
||||||
|
|
||||||
|
# Visual Studio enables c++11 support by default
|
||||||
|
if (NOT MSVC)
|
||||||
|
list(APPEND @PKG_NAME@_CXX_FLAGS -std=c++11)
|
||||||
|
endif()
|
||||||
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND
|
||||||
|
"${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||||
|
set(@PKG_NAME@_CXX_FLAGS "${@PKG_NAME@_CXX_FLAGS} -stdlib=libc++")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
foreach(lib @PKG_LIBRARIES@)
|
||||||
|
set(onelib "${lib}-NOTFOUND")
|
||||||
|
find_library(onelib ${lib}
|
||||||
|
PATHS "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@"
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
if(NOT onelib)
|
||||||
|
message(FATAL_ERROR "Library '${lib}' in package @PKG_NAME@ is not installed properly")
|
||||||
|
endif()
|
||||||
|
list(APPEND @PKG_NAME@_LIBRARIES ${onelib})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Get the install prefix for OGRE
|
||||||
|
execute_process(COMMAND pkg-config --variable=prefix OGRE
|
||||||
|
OUTPUT_VARIABLE OGRE_INSTALL_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
# Add the OGRE cmake path to CMAKE_MODULE_PATH
|
||||||
|
set(CMAKE_MODULE_PATH
|
||||||
|
"${OGRE_INSTALL_PREFIX}/share/OGRE/cmake/modules;${OGRE_INSTALL_PREFIX}/lib/OGRE/cmake;${OGRE_INSTALL_PREFIX}/CMake;${CMAKE_MODULE_PATH}")
|
||||||
|
|
||||||
|
foreach(dep @PKG_DEPENDS@)
|
||||||
|
if(NOT ${dep}_FOUND)
|
||||||
|
if (${dep} MATCHES "Boost")
|
||||||
|
find_package(Boost @MIN_BOOST_VERSION@ REQUIRED thread signals system filesystem program_options regex iostreams date_time)
|
||||||
|
else()
|
||||||
|
find_package(${dep} REQUIRED)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
list(APPEND @PKG_NAME@_INCLUDE_DIRS ${${dep}_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# Protobuf needs to be capitalized to match PROTOBUF_LIBRARIES
|
||||||
|
if (${dep} STREQUAL "Protobuf")
|
||||||
|
string (TOUPPER ${dep} dep_lib)
|
||||||
|
else()
|
||||||
|
set (dep_lib ${dep})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND @PKG_NAME@_LIBRARIES ${${dep_lib}_LIBRARIES})
|
||||||
|
|
||||||
|
# When including OGRE, also include the Terrain and Paging components
|
||||||
|
if (${dep} STREQUAL "OGRE")
|
||||||
|
list(APPEND GAZEBO_INCLUDE_DIRS ${OGRE_Terrain_INCLUDE_DIRS}
|
||||||
|
${OGRE_Paging_INCLUDE_DIRS})
|
||||||
|
list(APPEND GAZEBO_LIBRARIES ${OGRE_Terrain_LIBRARIES}
|
||||||
|
${OGRE_Paging_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
find_package(ignition-math2 REQUIRED)
|
||||||
|
list(APPEND @PKG_NAME@_INCLUDE_DIRS ${IGNITION-MATH_INCLUDE_DIRS})
|
||||||
|
list(APPEND @PKG_NAME@_LIBRARY_DIRS ${IGNITION-MATH_LIBRARY_DIRS})
|
||||||
|
list(APPEND @PKG_NAME@_LIBRARIES ${IGNITION-MATH_LIBRARIES})
|
||||||
|
|
||||||
|
list(APPEND @PKG_NAME@_LDFLAGS -Wl,-rpath,@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/plugins)
|
||||||
|
list(APPEND @PKG_NAME@_LDFLAGS -L@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@)
|
||||||
|
list(APPEND @PKG_NAME@_LDFLAGS -L@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/plugins)
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* config.h. Generated by CMake for @PROJECT_NAME@. */
|
||||||
|
#ifndef _GAZEBO_CONFIG_H_
|
||||||
|
#define _GAZEBO_CONFIG_H_
|
||||||
|
|
||||||
|
/* Version number */
|
||||||
|
#define GAZEBO_MAJOR_VERSION ${GAZEBO_MAJOR_VERSION}
|
||||||
|
#define GAZEBO_MINOR_VERSION ${GAZEBO_MINOR_VERSION}
|
||||||
|
#define GAZEBO_PATCH_VERSION ${GAZEBO_PATCH_VERSION}
|
||||||
|
|
||||||
|
#define GAZEBO_VERSION "${GAZEBO_VERSION}"
|
||||||
|
#define GAZEBO_VERSION_FULL "${GAZEBO_VERSION_FULL}"
|
||||||
|
|
||||||
|
#define GAZEBO_VERSION_HEADER "Gazebo multi-robot simulator, version ${GAZEBO_VERSION_FULL}\nCopyright (C) 2012 Open Source Robotics Foundation.\nReleased under the Apache 2 License.\nhttp://gazebosim.org\n\n"
|
||||||
|
|
||||||
|
#cmakedefine BUILD_TYPE_PROFILE 1
|
||||||
|
#cmakedefine BUILD_TYPE_DEBUG 1
|
||||||
|
#cmakedefine BUILD_TYPE_RELEASE 1
|
||||||
|
#cmakedefine BUILD_TYPE_COVERAGE 1
|
||||||
|
#cmakedefine HAVE_OPENAL 1
|
||||||
|
#cmakedefine HAVE_FFMPEG 1
|
||||||
|
#cmakedefine ENABLE_SHADOWS 1
|
||||||
|
#cmakedefine HAVE_BULLET 1
|
||||||
|
#cmakedefine HAVE_SIMBODY 1
|
||||||
|
#cmakedefine HAVE_DART 1
|
||||||
|
#cmakedefine INCLUDE_RTSHADER 1
|
||||||
|
#cmakedefine HAVE_GTS 1
|
||||||
|
#cmakedefine HAVE_QWT 1
|
||||||
|
#cmakedefine ENABLE_DIAGNOSTICS 1
|
||||||
|
#cmakedefine HAVE_GDAL 1
|
||||||
|
#cmakedefine HAVE_USB 1
|
||||||
|
#cmakedefine HAVE_OCULUS 1
|
||||||
|
#cmakedefine HAVE_SPNAV 1
|
||||||
|
#cmakedefine HDF5_INSTRUMENT 1
|
||||||
|
#cmakedefine HAVE_GRAPHVIZ 1
|
||||||
|
#cmakedefine HAVE_UUID 1
|
||||||
|
|
||||||
|
#ifdef BUILD_TYPE_PROFILE
|
||||||
|
#include <google/heap-checker.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ifndef _GAZEBO_CONFIG_H_
|
||||||
|
#endif
|
|
@ -0,0 +1,25 @@
|
||||||
|
################################################################################
|
||||||
|
#Find available package generators
|
||||||
|
|
||||||
|
# DEB
|
||||||
|
if ("${CMAKE_SYSTEM}" MATCHES "Linux")
|
||||||
|
find_program(DPKG_PROGRAM dpkg)
|
||||||
|
if (EXISTS ${DPKG_PROGRAM})
|
||||||
|
list (APPEND CPACK_GENERATOR "DEB")
|
||||||
|
endif(EXISTS ${DPKG_PROGRAM})
|
||||||
|
|
||||||
|
find_program(RPMBUILD_PROGRAM rpmbuild)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list (APPEND CPACK_SOURCE_GENERATOR "TBZ2")
|
||||||
|
list (APPEND CPACK_SOURCE_GENERATOR "ZIP")
|
||||||
|
list (APPEND CPACK_SOURCE_IGNORE_FILES ";Ogre.log;TODO;/.hg/;.swp$;/build/;.hgtags")
|
||||||
|
|
||||||
|
include (InstallRequiredSystemLibraries)
|
||||||
|
|
||||||
|
#execute_process(COMMAND dpkg --print-architecture _NPROCE)
|
||||||
|
set (DEBIAN_PACKAGE_DEPENDS "libogre-dev, libfreeimage-dev, libqt4-dev, libprotobuf-dev, libprotoc-dev, libtbb2, libboost-all-dev")
|
||||||
|
|
||||||
|
set (RPM_PACKAGE_DEPENDS "libogre-dev, libfreeimage-dev, libqt4-dev, libprotobuf-dev, libprotoc-dev, libtbb2, libboost-all-dev")
|
||||||
|
|
||||||
|
set (GAZEBO_CPACK_CFG_FILE "${PROJECT_BINARY_DIR}/cpack_options.cmake")
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<gazeborc>
|
||||||
|
<gazeboPath>@CMAKE_INSTALL_PREFIX@/share/gazebo</gazeboPath>
|
||||||
|
<ogrePath>@OGRE_LIBRARY_PATH@/OGRE</ogrePath>
|
||||||
|
</gazeborc>
|
|
@ -0,0 +1,10 @@
|
||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
|
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: gazebo
|
||||||
|
Description: Gazebo Libraries
|
||||||
|
Version: @GAZEBO_VERSION_FULL@
|
||||||
|
Requires: sdformat protobuf @TBB_PKG_CONFIG@ ignition-math2
|
||||||
|
Libs: -Wl,-rpath,${prefix}/@CMAKE_INSTALL_LIBDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/plugins -L${libdir} -L${prefix}/@CMAKE_INSTALL_LIBDIR@/gazebo-@GAZEBO_MAJOR_VERSION@/plugins -lgazebo_transport -lgazebo_physics -lgazebo_sensors -lgazebo_rendering -lgazebo_gui -lgazebo_client -lgazebo_msgs -lgazebo_math -lgazebo_common -lgazebo @Boost_PKGCONFIG_LIBS@ @APPLE_PKGCONFIG_LIBS@
|
||||||
|
CFlags: -I${includedir}/gazebo-@GAZEBO_MAJOR_VERSION@ @Boost_PKGCONFIG_CFLAGS@ -std=c++11
|
|
@ -0,0 +1,10 @@
|
||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
|
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: gazebo
|
||||||
|
Description: Gazebo Exported ODE Libraries
|
||||||
|
Version: @GAZEBO_VERSION_FULL@
|
||||||
|
Requires:
|
||||||
|
Libs: -Wl,-rpath,${prefix}/@CMAKE_INSTALL_LIBDIR@ -L${prefix}/@CMAKE_INSTALL_LIBDIR@ -lgazebo_ode
|
||||||
|
CFlags: -I${includedir}/gazebo-@GAZEBO_MAJOR_VERSION@
|
|
@ -0,0 +1,10 @@
|
||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
|
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: gazebo_transport
|
||||||
|
Description: Gazebo Transport Library
|
||||||
|
Version: @GAZEBO_VERSION_FULL@
|
||||||
|
Requires:
|
||||||
|
Libs: -L${libdir} -lgazebo_transport -lgazebo_msgs
|
||||||
|
CFlags: -I${includedir}/gazebo-@GAZEBO_MAJOR_VERSION@
|
|
@ -0,0 +1,7 @@
|
||||||
|
export GAZEBO_MASTER_URI=http://@GAZEBO_DEFAULT_MASTER_HOST@:@GAZEBO_DEFAULT_MASTER_PORT@
|
||||||
|
export GAZEBO_MODEL_DATABASE_URI=@GAZEBO_MODEL_DATABASE_URI@
|
||||||
|
export GAZEBO_RESOURCE_PATH=@GAZEBO_RESOURCE_PATH@:${GAZEBO_RESOURCE_PATH}
|
||||||
|
export GAZEBO_PLUGIN_PATH=@GAZEBO_PLUGIN_PATH@:${GAZEBO_PLUGIN_PATH}
|
||||||
|
export GAZEBO_MODEL_PATH=@GAZEBO_MODEL_PATH@:${GAZEBO_MODEL_PATH}
|
||||||
|
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:@GAZEBO_PLUGIN_PATH@
|
||||||
|
export OGRE_RESOURCE_PATH=@OGRE_RESOURCE_PATH@
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Check if the node was configured to use s3cmd
|
||||||
|
# This is done by running s3cmd --configure
|
||||||
|
if [ ! -f "${HOME}/.s3cfg" ]; then
|
||||||
|
echo "No $HOME/.s3cfg file found. Please config the software first in your system"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make documentation if not build
|
||||||
|
make doc
|
||||||
|
if [ ! -f "@CMAKE_BINARY_DIR@/doxygen/html/index.html" ]; then
|
||||||
|
echo "Documentation not present. Install doxygen, and run `make doc` in the build directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The code API
|
||||||
|
s3cmd sync @CMAKE_BINARY_DIR@/doxygen/html/* s3://osrf-distributions/gazebo/api/@GAZEBO_VERSION_FULL@/ --dry-run -v
|
||||||
|
|
||||||
|
echo -n "Upload code API(Y/n)? "
|
||||||
|
read ans
|
||||||
|
|
||||||
|
if [ "$ans" = "y" ] || [ "$ans" = "Y" ]; then
|
||||||
|
s3cmd sync @CMAKE_BINARY_DIR@/doxygen/html/* s3://osrf-distributions/gazebo/api/@GAZEBO_VERSION_FULL@/ -v
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# The msgs API
|
||||||
|
s3cmd sync @CMAKE_BINARY_DIR@/doxygen_msgs/html/* s3://osrf-distributions/gazebo/api/@GAZEBO_VERSION_FULL@/ --dry-run -v
|
||||||
|
|
||||||
|
echo -n "Upload msg API (Y/n)? "
|
||||||
|
read ans
|
||||||
|
|
||||||
|
if [ "$ans" = "y" ] || [ "$ans" = "Y" ]; then
|
||||||
|
s3cmd sync @CMAKE_BINARY_DIR@/doxygen_msgs/html/* s3://osrf-distributions/gazebo/msg-api/@GAZEBO_VERSION_FULL@/ -v
|
||||||
|
fi
|
|
@ -0,0 +1,100 @@
|
||||||
|
:: This file is a helper for gazebo configuration (cmake) on Windows
|
||||||
|
::
|
||||||
|
:: It is designed to work with a workspace detailed in the INSTALL_WIN32.md
|
||||||
|
:: file. Please follow the instructions there. The workspace layout should be:
|
||||||
|
::
|
||||||
|
:: gz-ws/
|
||||||
|
:: sdformat/
|
||||||
|
:: ... # all dependencies detailed in the INSTALL file
|
||||||
|
:: #dep1/
|
||||||
|
:: #dep2/
|
||||||
|
:: ...
|
||||||
|
:: gazebo/
|
||||||
|
::
|
||||||
|
:: Usage: cd gz-ws/gazebo/build && ../configure <Release|Debug>
|
||||||
|
@set build_type=Release
|
||||||
|
@if not "%1"=="" set build_type=%1
|
||||||
|
@echo Configuring for build type %build_type%
|
||||||
|
|
||||||
|
@set BOOST_PATH=%cd%\..\..\boost_1_56_0
|
||||||
|
@set BOOST_LIBRARY_DIR=%BOOST_PATH%\lib64-msvc-12.0
|
||||||
|
|
||||||
|
@set PROTOBUF_PATH=%cd%\..\..\protobuf-2.6.0-win64-vc12
|
||||||
|
|
||||||
|
@set CURL_PATH=%cd%\..\..\libcurl-vc12-x64-release-debug-static-ipv6-sspi-winssl\%build_type%
|
||||||
|
@set CURL_INCLUDE_DIR=%CURL_PATH%\include
|
||||||
|
@set CURL_LIBRARY_DIR=%CURL_PATH%\lib
|
||||||
|
set CURL_LIBRARY_NAME=libcurl_a
|
||||||
|
@if "%build_type%"=="Debug" set CURL_LIBRARY_NAME=libcurl_a_debug
|
||||||
|
|
||||||
|
@set FREEIMAGE_PATH=%cd%\..\..\FreeImage-vc12-x64-release-debug
|
||||||
|
@set FREEIMAGE_LIBRARY_DIR=%FREEIMAGE_PATH%\x64\%build_type%\DLL
|
||||||
|
@set FREEIMAGE_INCLUDE_DIR=%FREEIMAGE_PATH%\Source
|
||||||
|
|
||||||
|
@set SDFORMAT_PATH=%cd%\..\..\sdformat\build\install\%build_type%
|
||||||
|
@set IGNITION-MATH_PATH=%cd%\..\..\ign-math\build\install\%build_type%
|
||||||
|
@set IGNITION-TRANSPORT_PATH=%cd%\..\..\ign-transport\build\install\%build_type%
|
||||||
|
@set IGNITION-TRANSPORT_CMAKE_PREFIX_PATH=%IGNITION-TRANSPORT_PATH%\lib\cmake\ignition-transport0
|
||||||
|
|
||||||
|
@set TBB_PATH=%cd%\..\..\tbb43_20141023oss
|
||||||
|
@set TBB_LIBRARY_DIR=%TBB_PATH%\lib\intel64\vc12
|
||||||
|
@set TBB_INCLUDEDIR=%TBB_PATH%\include
|
||||||
|
|
||||||
|
@set OGRE_VERSION=1.8.1
|
||||||
|
@set OGRE_PATH=%cd%\..\..\ogre_src_v1-8-1-vc12-x64-release-debug\build\install\%build_type%
|
||||||
|
@set OGRE_INCLUDE_DIR=%OGRE_PATH%\include;%OGRE_PATH%\include\OGRE;%OGRE_PATH%\include\OGRE\RTShaderSystem;%OGRE_PATH%\include\OGRE\Terrain;%OGRE_PATH%\include\OGRE\Paging
|
||||||
|
@set OGRE_LIBRARY_DIR=%OGRE_PATH%\lib\%build_type%
|
||||||
|
@set OGRE_PLUGIN_DIR=%OGRE_LIBRARY_DIR%\opt
|
||||||
|
set OGRE_LIB_SUFFIX=.lib
|
||||||
|
@if "%build_type%"=="Debug" set OGRE_LIB_SUFFIX=_d.lib
|
||||||
|
@set OGRE_LIBS=%OGRE_LIBRARY_DIR%\OgreMain%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgreOverlay%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgreRTShaderSystem%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgreTerrain%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgrePaging%OGRE_LIB_SUFFIX%
|
||||||
|
@set OGRE_LIBS=%OGRE_LIBRARY_DIR%\OgreMain%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgreRTShaderSystem%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgreTerrain%OGRE_LIB_SUFFIX%;%OGRE_LIBRARY_DIR%\OgrePaging%OGRE_LIB_SUFFIX%
|
||||||
|
|
||||||
|
@set DLFCN_WIN32_PATH=%cd%\..\..\dlfcn-win32-vc12-x64-release-debug\build\install\%build_type%
|
||||||
|
@set DLFCN_WIN32_LIBRARY_DIR=%DLFCN_WIN32_PATH%\lib
|
||||||
|
@set DLFCN_WIN32_INCLUDE_DIR=%DLFCN_WIN32_PATH%\include
|
||||||
|
|
||||||
|
@set QT4_PATH=C:\Qt\4.8.6\x64\msvc2013
|
||||||
|
@set QT4_BIN_DIR=%QT4_PATH%\bin
|
||||||
|
|
||||||
|
@set IGN_MATH_PATH=%cd%\..\..\ign-math\build\install\%build_type%
|
||||||
|
|
||||||
|
@set ZEROMQ_PATH=%cd%\..\..\ZeroMQ-3.2.4
|
||||||
|
|
||||||
|
@set CPPZMQ_PATH=%cd%\..\..\cppzmq
|
||||||
|
|
||||||
|
@set INCLUDE=%FREEIMAGE_INCLUDE_DIR%;%TBB_INCLUDEDIR%;%DLFCN_WIN32_INCLUDE_DIR%;%INCLUDE%
|
||||||
|
@set LIB=%FREEIMAGE_LIBRARY_DIR%;%BOOST_LIBRARY_DIR%;%TBB_LIBRARY_DIR%;%DLFCN_WIN32_LIBRARY_DIR%;%LIB%
|
||||||
|
@set PATH=%QT4_BIN_DIR%;%PATH%
|
||||||
|
|
||||||
|
cmake -G "NMake Makefiles"^
|
||||||
|
-DCMAKE_PREFIX_PATH="%SDFORMAT_PATH%;%IGNITION-MATH_PATH%;%IGNITION-TRANSPORT_CMAKE_PREFIX_PATH%"^
|
||||||
|
-DUSE_EXTERNAL_TINYXML:BOOL=False^
|
||||||
|
-DUSE_EXTERNAL_TINYXML2:BOOL=False^
|
||||||
|
-DFREEIMAGE_RUNS=1^
|
||||||
|
-DPROTOBUF_SRC_ROOT_FOLDER="%PROTOBUF_PATH%"^
|
||||||
|
-DBOOST_ROOT:STRING="%BOOST_PATH%"^
|
||||||
|
-DBOOST_LIBRARYDIR:STRING="%BOOST_LIBRARY_DIR%"^
|
||||||
|
-DOGRE_FOUND=1^
|
||||||
|
-DOGRE-RTShaderSystem_FOUND=1^
|
||||||
|
-DOGRE-Terrain_FOUND=1^
|
||||||
|
-DOGRE_VERSION=%OGRE_VERSION%^
|
||||||
|
-DOGRE_PLUGINDIR="%OGRE_PLUGIN_DIR%"^
|
||||||
|
-DOGRE_INCLUDE_DIRS="%OGRE_INCLUDE_DIR%"^
|
||||||
|
-DOGRE_LIBRARIES="%OGRE_LIBS%"^
|
||||||
|
-DCURL_FOUND=1^
|
||||||
|
-DCURL_INCLUDEDIR="%CURL_INCLUDE_DIR%"^
|
||||||
|
-DCURL_LIBDIR="%CURL_LIBRARY_DIR%"^
|
||||||
|
-DCURL_LIBRARIES="%CURL_LIBRARY_NAME%"^
|
||||||
|
-DTBB_FOUND=1^
|
||||||
|
-DTBB_INCLUDEDIR="%TBB_INCLUDEDIR%"^
|
||||||
|
-DTBB_LIBRARY_DIR="%TBB_LIBRARY_DIR%"^
|
||||||
|
-DIGNITION-MATH_INCLUDE_DIRS:STRING="%IGN_MATH_PATH%\include\ignition\math2"^
|
||||||
|
-DIGNITION-MATH_LIBRARY_DIRS:STRING="%IGN_MATH_PATH%\lib"^
|
||||||
|
-DIGNITION-MATH_LIBRARIES="ignition-math2"^
|
||||||
|
-DZeroMQ_ROOT_DIR="@ZEROMQ_PATH@"^
|
||||||
|
-DCPPZMQ_HEADER_PATH="@CPPZMQ_PATH@"^
|
||||||
|
-DCMAKE_INSTALL_PREFIX="install\%build_type%"^
|
||||||
|
-DCMAKE_BUILD_TYPE="%build_type%"^
|
||||||
|
-DENABLE_TESTS_COMPILATION:BOOL=False^
|
||||||
|
..
|
|
@ -0,0 +1,7 @@
|
||||||
|
add_subdirectory(opende)
|
||||||
|
|
||||||
|
if (NOT CCD_FOUND)
|
||||||
|
add_subdirectory(libccd)
|
||||||
|
endif()
|
||||||
|
# add_subdirectory(ann)
|
||||||
|
# add_subdirectory(fcl)
|
|
@ -0,0 +1,33 @@
|
||||||
|
add_definitions(-DUSE_PQP=0)
|
||||||
|
add_definitions(-DUSE_SVMLIGHT=0)
|
||||||
|
|
||||||
|
set (sources
|
||||||
|
src/ANN.cpp
|
||||||
|
src/bd_fix_rad_search.cpp
|
||||||
|
src/bd_pr_search.cpp
|
||||||
|
src/bd_search.cpp
|
||||||
|
src/bd_tree.cpp
|
||||||
|
src/bd_tree.h
|
||||||
|
src/brute.cpp
|
||||||
|
src/kd_dump.cpp
|
||||||
|
src/kd_fix_rad_search.cpp
|
||||||
|
src/kd_fix_rad_search.h
|
||||||
|
src/kd_pr_search.cpp
|
||||||
|
src/kd_pr_search.h
|
||||||
|
src/kd_search.cpp
|
||||||
|
src/kd_search.h
|
||||||
|
src/kd_split.cpp
|
||||||
|
src/kd_split.h
|
||||||
|
src/kd_tree.cpp
|
||||||
|
src/kd_tree.h
|
||||||
|
src/kd_util.cpp
|
||||||
|
src/kd_util.h
|
||||||
|
src/perf.cpp
|
||||||
|
src/pr_queue.h
|
||||||
|
src/pr_queue_k.h
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/deps/ann/include )
|
||||||
|
|
||||||
|
gz_add_library(gazebo_ann ${sources})
|
||||||
|
gz_install_library(gazebo_ann)
|
|
@ -0,0 +1,830 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: ANN.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Basic include file for approximate nearest
|
||||||
|
// neighbor searching.
|
||||||
|
// Last modified: 01/27/10 (Version 1.1.2)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2015 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Added copyright and revision information
|
||||||
|
// Added ANNcoordPrec for coordinate precision.
|
||||||
|
// Added methods theDim, nPoints, maxPoints, thePoints to ANNpointSet.
|
||||||
|
// Cleaned up C++ structure for modern compilers
|
||||||
|
// Revision 1.1 05/03/05
|
||||||
|
// Added fixed-radius k-NN searching
|
||||||
|
// Revision 1.1.2 01/27/10
|
||||||
|
// Fixed minor compilation bugs for new versions of gcc
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANN - approximate nearest neighbor searching
|
||||||
|
// ANN is a library for approximate nearest neighbor searching,
|
||||||
|
// based on the use of standard and priority search in kd-trees
|
||||||
|
// and balanced box-decomposition (bbd) trees. Here are some
|
||||||
|
// references to the main algorithmic techniques used here:
|
||||||
|
//
|
||||||
|
// kd-trees:
|
||||||
|
// Friedman, Bentley, and Finkel, ``An algorithm for finding
|
||||||
|
// best matches in logarithmic expected time,'' ACM
|
||||||
|
// Transactions on Mathematical Software, 3(3):209-226, 1977.
|
||||||
|
//
|
||||||
|
// Priority search in kd-trees:
|
||||||
|
// Arya and Mount, ``Algorithms for fast vector quantization,''
|
||||||
|
// Proc. of DCC '93: Data Compression Conference, eds. J. A.
|
||||||
|
// Storer and M. Cohn, IEEE Press, 1993, 381-390.
|
||||||
|
//
|
||||||
|
// Approximate nearest neighbor search and bbd-trees:
|
||||||
|
// Arya, Mount, Netanyahu, Silverman, and Wu, ``An optimal
|
||||||
|
// algorithm for approximate nearest neighbor searching,''
|
||||||
|
// 5th Ann. ACM-SIAM Symposium on Discrete Algorithms,
|
||||||
|
// 1994, 573-582.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_H
|
||||||
|
#define ANN_H
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// For Microsoft Visual C++, externally accessible symbols must be
|
||||||
|
// explicitly indicated with DLL_API, which is somewhat like "extern."
|
||||||
|
//
|
||||||
|
// The following ifdef block is the standard way of creating macros
|
||||||
|
// which make exporting from a DLL simpler. All files within this DLL
|
||||||
|
// are compiled with the DLL_EXPORTS preprocessor symbol defined on the
|
||||||
|
// command line. In contrast, projects that use (or import) the DLL
|
||||||
|
// objects do not define the DLL_EXPORTS symbol. This way any other
|
||||||
|
// project whose source files include this file see DLL_API functions as
|
||||||
|
// being imported from a DLL, wheras this DLL sees symbols defined with
|
||||||
|
// this macro as being exported.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#ifdef DLL_EXPORTS
|
||||||
|
#define DLL_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define DLL_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// DLL_API is ignored for all other systems
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#else
|
||||||
|
#define DLL_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// basic includes
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <cstdlib> // standard lib includes
|
||||||
|
#include <cmath> // math includes
|
||||||
|
#include <iostream> // I/O streams
|
||||||
|
#include <cstring> // C-style strings
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Limits
|
||||||
|
// There are a number of places where we use the maximum double value as
|
||||||
|
// default initializers (and others may be used, depending on the
|
||||||
|
// data/distance representation). These can usually be found in limits.h
|
||||||
|
// (as LONG_MAX, INT_MAX) or in float.h (as DBL_MAX, FLT_MAX).
|
||||||
|
//
|
||||||
|
// Not all systems have these files. If you are using such a system,
|
||||||
|
// you should set the preprocessor symbol ANN_NO_LIMITS_H when
|
||||||
|
// compiling, and modify the statements below to generate the
|
||||||
|
// appropriate value. For practical purposes, this does not need to be
|
||||||
|
// the maximum double value. It is sufficient that it be at least as
|
||||||
|
// large than the maximum squared distance between between any two
|
||||||
|
// points.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#ifdef ANN_NO_LIMITS_H // limits.h unavailable
|
||||||
|
#include <cvalues> // replacement for limits.h
|
||||||
|
const double ANN_DBL_MAX = MAXDOUBLE; // insert maximum double
|
||||||
|
#else
|
||||||
|
#include <climits>
|
||||||
|
#include <cfloat>
|
||||||
|
const double ANN_DBL_MAX = DBL_MAX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ANNversion "1.1.2" // ANN version and information
|
||||||
|
#define ANNversionCmt ""
|
||||||
|
#define ANNcopyright "David M. Mount and Sunil Arya"
|
||||||
|
#define ANNlatestRev "Jan 27, 2010"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANNbool
|
||||||
|
// This is a simple boolean type. Although ANSI C++ is supposed
|
||||||
|
// to support the type bool, some compilers do not have it.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum ANNbool {ANNfalse = 0, ANNtrue = 1}; // ANN boolean type (non ANSI C++)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANNcoord, ANNdist
|
||||||
|
// ANNcoord and ANNdist are the types used for representing
|
||||||
|
// point coordinates and distances. They can be modified by the
|
||||||
|
// user, with some care. It is assumed that they are both numeric
|
||||||
|
// types, and that ANNdist is generally of an equal or higher type
|
||||||
|
// from ANNcoord. A variable of type ANNdist should be large
|
||||||
|
// enough to store the sum of squared components of a variable
|
||||||
|
// of type ANNcoord for the number of dimensions needed in the
|
||||||
|
// application. For example, the following combinations are
|
||||||
|
// legal:
|
||||||
|
//
|
||||||
|
// ANNcoord ANNdist
|
||||||
|
// --------- -------------------------------
|
||||||
|
// short short, int, long, float, double
|
||||||
|
// int int, long, float, double
|
||||||
|
// long long, float, double
|
||||||
|
// float float, double
|
||||||
|
// double double
|
||||||
|
//
|
||||||
|
// It is the user's responsibility to make sure that overflow does
|
||||||
|
// not occur in distance calculation.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef double ANNcoord; // coordinate data type
|
||||||
|
typedef double ANNdist; // distance data type
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANNidx
|
||||||
|
// ANNidx is a point index. When the data structure is built, the
|
||||||
|
// points are given as an array. Nearest neighbor results are
|
||||||
|
// returned as an integer index into this array. To make it
|
||||||
|
// clearer when this is happening, we define the integer type
|
||||||
|
// ANNidx. Indexing starts from 0.
|
||||||
|
//
|
||||||
|
// For fixed-radius near neighbor searching, it is possible that
|
||||||
|
// there are not k nearest neighbors within the search radius. To
|
||||||
|
// indicate this, the algorithm returns ANN_NULL_IDX as its result.
|
||||||
|
// It should be distinguishable from any valid array index.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef int ANNidx; // point index
|
||||||
|
const ANNidx ANN_NULL_IDX = -1; // a NULL point index
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Infinite distance:
|
||||||
|
// The code assumes that there is an "infinite distance" which it
|
||||||
|
// uses to initialize distances before performing nearest neighbor
|
||||||
|
// searches. It should be as larger or larger than any legitimate
|
||||||
|
// nearest neighbor distance.
|
||||||
|
//
|
||||||
|
// On most systems, these should be found in the standard include
|
||||||
|
// file <limits.h> or possibly <float.h>. If you do not have these
|
||||||
|
// file, some suggested values are listed below, assuming 64-bit
|
||||||
|
// long, 32-bit int and 16-bit short.
|
||||||
|
//
|
||||||
|
// ANNdist ANN_DIST_INF Values (see <limits.h> or <float.h>)
|
||||||
|
// ------- ------------ ------------------------------------
|
||||||
|
// double DBL_MAX 1.79769313486231570e+308
|
||||||
|
// float FLT_MAX 3.40282346638528860e+38
|
||||||
|
// long LONG_MAX 0x7fffffffffffffff
|
||||||
|
// int INT_MAX 0x7fffffff
|
||||||
|
// short SHRT_MAX 0x7fff
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const ANNdist ANN_DIST_INF = ANN_DBL_MAX;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Significant digits for tree dumps:
|
||||||
|
// When floating point coordinates are used, the routine that dumps
|
||||||
|
// a tree needs to know roughly how many significant digits there
|
||||||
|
// are in a ANNcoord, so it can output points to full precision.
|
||||||
|
// This is defined to be ANNcoordPrec. On most systems these
|
||||||
|
// values can be found in the standard include files <limits.h> or
|
||||||
|
// <float.h>. For integer types, the value is essentially ignored.
|
||||||
|
//
|
||||||
|
// ANNcoord ANNcoordPrec Values (see <limits.h> or <float.h>)
|
||||||
|
// -------- ------------ ------------------------------------
|
||||||
|
// double DBL_DIG 15
|
||||||
|
// float FLT_DIG 6
|
||||||
|
// long doesn't matter 19
|
||||||
|
// int doesn't matter 10
|
||||||
|
// short doesn't matter 5
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef DBL_DIG // number of sig. bits in ANNcoord
|
||||||
|
const int ANNcoordPrec = DBL_DIG;
|
||||||
|
#else
|
||||||
|
const int ANNcoordPrec = 15; // default precision
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Self match?
|
||||||
|
// In some applications, the nearest neighbor of a point is not
|
||||||
|
// allowed to be the point itself. This occurs, for example, when
|
||||||
|
// computing all nearest neighbors in a set. By setting the
|
||||||
|
// parameter ANN_ALLOW_SELF_MATCH to ANNfalse, the nearest neighbor
|
||||||
|
// is the closest point whose distance from the query point is
|
||||||
|
// strictly positive.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const ANNbool ANN_ALLOW_SELF_MATCH = ANNtrue;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Norms and metrics:
|
||||||
|
// ANN supports any Minkowski norm for defining distance. In
|
||||||
|
// particular, for any p >= 1, the L_p Minkowski norm defines the
|
||||||
|
// length of a d-vector (v0, v1, ..., v(d-1)) to be
|
||||||
|
//
|
||||||
|
// (|v0|^p + |v1|^p + ... + |v(d-1)|^p)^(1/p),
|
||||||
|
//
|
||||||
|
// (where ^ denotes exponentiation, and |.| denotes absolute
|
||||||
|
// value). The distance between two points is defined to be the
|
||||||
|
// norm of the vector joining them. Some common distance metrics
|
||||||
|
// include
|
||||||
|
//
|
||||||
|
// Euclidean metric p = 2
|
||||||
|
// Manhattan metric p = 1
|
||||||
|
// Max metric p = infinity
|
||||||
|
//
|
||||||
|
// In the case of the max metric, the norm is computed by taking
|
||||||
|
// the maxima of the absolute values of the components. ANN is
|
||||||
|
// highly "coordinate-based" and does not support general distances
|
||||||
|
// functions (e.g. those obeying just the triangle inequality). It
|
||||||
|
// also does not support distance functions based on
|
||||||
|
// inner-products.
|
||||||
|
//
|
||||||
|
// For the purpose of computing nearest neighbors, it is not
|
||||||
|
// necessary to compute the final power (1/p). Thus the only
|
||||||
|
// component that is used by the program is |v(i)|^p.
|
||||||
|
//
|
||||||
|
// ANN parameterizes the distance computation through the following
|
||||||
|
// macros. (Macros are used rather than procedures for
|
||||||
|
// efficiency.) Recall that the distance between two points is
|
||||||
|
// given by the length of the vector joining them, and the length
|
||||||
|
// or norm of a vector v is given by formula:
|
||||||
|
//
|
||||||
|
// |v| = ROOT(POW(v0) # POW(v1) # ... # POW(v(d-1)))
|
||||||
|
//
|
||||||
|
// where ROOT, POW are unary functions and # is an associative and
|
||||||
|
// commutative binary operator mapping the following types:
|
||||||
|
//
|
||||||
|
// ** POW: ANNcoord --> ANNdist
|
||||||
|
// ** #: ANNdist x ANNdist --> ANNdist
|
||||||
|
// ** ROOT: ANNdist (>0) --> double
|
||||||
|
//
|
||||||
|
// For early termination in distance calculation (partial distance
|
||||||
|
// calculation) we assume that POW and # together are monotonically
|
||||||
|
// increasing on sequences of arguments, meaning that for all
|
||||||
|
// v0..vk and y:
|
||||||
|
//
|
||||||
|
// POW(v0) #...# POW(vk) <= (POW(v0) #...# POW(vk)) # POW(y).
|
||||||
|
//
|
||||||
|
// Incremental Distance Calculation:
|
||||||
|
// The program uses an optimized method of computing distances for
|
||||||
|
// kd-trees and bd-trees, called incremental distance calculation.
|
||||||
|
// It is used when distances are to be updated when only a single
|
||||||
|
// coordinate of a point has been changed. In order to use this,
|
||||||
|
// we assume that there is an incremental update function DIFF(x,y)
|
||||||
|
// for #, such that if:
|
||||||
|
//
|
||||||
|
// s = x0 # ... # xi # ... # xk
|
||||||
|
//
|
||||||
|
// then if s' is equal to s but with xi replaced by y, that is,
|
||||||
|
//
|
||||||
|
// s' = x0 # ... # y # ... # xk
|
||||||
|
//
|
||||||
|
// then the length of s' can be computed by:
|
||||||
|
//
|
||||||
|
// |s'| = |s| # DIFF(xi,y).
|
||||||
|
//
|
||||||
|
// Thus, if # is + then DIFF(xi,y) is (yi-x). For the L_infinity
|
||||||
|
// norm we make use of the fact that in the program this function
|
||||||
|
// is only invoked when y > xi, and hence DIFF(xi,y)=y.
|
||||||
|
//
|
||||||
|
// Finally, for approximate nearest neighbor queries we assume
|
||||||
|
// that POW and ROOT are related such that
|
||||||
|
//
|
||||||
|
// v*ROOT(x) = ROOT(POW(v)*x)
|
||||||
|
//
|
||||||
|
// Here are the values for the various Minkowski norms:
|
||||||
|
//
|
||||||
|
// L_p: p even: p odd:
|
||||||
|
// ------------------------- ------------------------
|
||||||
|
// POW(v) = v^p POW(v) = |v|^p
|
||||||
|
// ROOT(x) = x^(1/p) ROOT(x) = x^(1/p)
|
||||||
|
// # = + # = +
|
||||||
|
// DIFF(x,y) = y - x DIFF(x,y) = y - x
|
||||||
|
//
|
||||||
|
// L_inf:
|
||||||
|
// POW(v) = |v|
|
||||||
|
// ROOT(x) = x
|
||||||
|
// # = max
|
||||||
|
// DIFF(x,y) = y
|
||||||
|
//
|
||||||
|
// By default the Euclidean norm is assumed. To change the norm,
|
||||||
|
// uncomment the appropriate set of macros below.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Use the following for the Euclidean norm
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#define ANN_POW(v) ((v)*(v))
|
||||||
|
#define ANN_ROOT(x) sqrt(x)
|
||||||
|
#define ANN_SUM(x,y) ((x) + (y))
|
||||||
|
#define ANN_DIFF(x,y) ((y) - (x))
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Use the following for the L_1 (Manhattan) norm
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// #define ANN_POW(v) fabs(v)
|
||||||
|
// #define ANN_ROOT(x) (x)
|
||||||
|
// #define ANN_SUM(x,y) ((x) + (y))
|
||||||
|
// #define ANN_DIFF(x,y) ((y) - (x))
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Use the following for a general L_p norm
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// #define ANN_POW(v) pow(fabs(v),p)
|
||||||
|
// #define ANN_ROOT(x) pow(fabs(x),1/p)
|
||||||
|
// #define ANN_SUM(x,y) ((x) + (y))
|
||||||
|
// #define ANN_DIFF(x,y) ((y) - (x))
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Use the following for the L_infinity (Max) norm
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// #define ANN_POW(v) fabs(v)
|
||||||
|
// #define ANN_ROOT(x) (x)
|
||||||
|
// #define ANN_SUM(x,y) ((x) > (y) ? (x) : (y))
|
||||||
|
// #define ANN_DIFF(x,y) (y)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Array types
|
||||||
|
// The following array types are of basic interest. A point is
|
||||||
|
// just a dimensionless array of coordinates, a point array is a
|
||||||
|
// dimensionless array of points. A distance array is a
|
||||||
|
// dimensionless array of distances and an index array is a
|
||||||
|
// dimensionless array of point indices. The latter two are used
|
||||||
|
// when returning the results of k-nearest neighbor queries.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef ANNcoord* ANNpoint; // a point
|
||||||
|
typedef ANNpoint* ANNpointArray; // an array of points
|
||||||
|
typedef ANNdist* ANNdistArray; // an array of distances
|
||||||
|
typedef ANNidx* ANNidxArray; // an array of point indices
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Basic point and array utilities:
|
||||||
|
// The following procedures are useful supplements to ANN's nearest
|
||||||
|
// neighbor capabilities.
|
||||||
|
//
|
||||||
|
// annDist():
|
||||||
|
// Computes the (squared) distance between a pair of points.
|
||||||
|
// Note that this routine is not used internally by ANN for
|
||||||
|
// computing distance calculations. For reasons of efficiency
|
||||||
|
// this is done using incremental distance calculation. Thus,
|
||||||
|
// this routine cannot be modified as a method of changing the
|
||||||
|
// metric.
|
||||||
|
//
|
||||||
|
// Because points (somewhat like strings in C) are stored as
|
||||||
|
// pointers. Consequently, creating and destroying copies of
|
||||||
|
// points may require storage allocation. These procedures do
|
||||||
|
// this.
|
||||||
|
//
|
||||||
|
// annAllocPt() and annDeallocPt():
|
||||||
|
// Allocate a deallocate storage for a single point, and
|
||||||
|
// return a pointer to it. The argument to AllocPt() is
|
||||||
|
// used to initialize all components.
|
||||||
|
//
|
||||||
|
// annAllocPts() and annDeallocPts():
|
||||||
|
// Allocate and deallocate an array of points as well a
|
||||||
|
// place to store their coordinates, and initializes the
|
||||||
|
// points to point to their respective coordinates. It
|
||||||
|
// allocates point storage in a contiguous block large
|
||||||
|
// enough to store all the points. It performs no
|
||||||
|
// initialization.
|
||||||
|
//
|
||||||
|
// annCopyPt():
|
||||||
|
// Creates a copy of a given point, allocating space for
|
||||||
|
// the new point. It returns a pointer to the newly
|
||||||
|
// allocated copy.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
DLL_API ANNdist annDist(
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNpoint p, // points
|
||||||
|
ANNpoint q);
|
||||||
|
|
||||||
|
DLL_API ANNpoint annAllocPt(
|
||||||
|
int dim, // dimension
|
||||||
|
ANNcoord c = 0); // coordinate value (all equal)
|
||||||
|
|
||||||
|
DLL_API ANNpointArray annAllocPts(
|
||||||
|
int n, // number of points
|
||||||
|
int dim); // dimension
|
||||||
|
|
||||||
|
DLL_API void annDeallocPt(
|
||||||
|
ANNpoint &p); // deallocate 1 point
|
||||||
|
|
||||||
|
DLL_API void annDeallocPts(
|
||||||
|
ANNpointArray &pa); // point array
|
||||||
|
|
||||||
|
DLL_API ANNpoint annCopyPt(
|
||||||
|
int dim, // dimension
|
||||||
|
ANNpoint source); // point to copy
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
//Overall structure: ANN supports a number of different data structures
|
||||||
|
//for approximate and exact nearest neighbor searching. These are:
|
||||||
|
//
|
||||||
|
// ANNbruteForce A simple brute-force search structure.
|
||||||
|
// ANNkd_tree A kd-tree tree search structure. ANNbd_tree
|
||||||
|
// A bd-tree tree search structure (a kd-tree with shrink
|
||||||
|
// capabilities).
|
||||||
|
//
|
||||||
|
// At a minimum, each of these data structures support k-nearest
|
||||||
|
// neighbor queries. The nearest neighbor query, annkSearch,
|
||||||
|
// returns an integer identifier and the distance to the nearest
|
||||||
|
// neighbor(s) and annRangeSearch returns the nearest points that
|
||||||
|
// lie within a given query ball.
|
||||||
|
//
|
||||||
|
// Each structure is built by invoking the appropriate constructor
|
||||||
|
// and passing it (at a minimum) the array of points, the total
|
||||||
|
// number of points and the dimension of the space. Each structure
|
||||||
|
// is also assumed to support a destructor and member functions
|
||||||
|
// that return basic information about the point set.
|
||||||
|
//
|
||||||
|
// Note that the array of points is not copied by the data
|
||||||
|
// structure (for reasons of space efficiency), and it is assumed
|
||||||
|
// to be constant throughout the lifetime of the search structure.
|
||||||
|
//
|
||||||
|
// The search algorithm, annkSearch, is given the query point (q),
|
||||||
|
// and the desired number of nearest neighbors to report (k), and
|
||||||
|
// the error bound (eps) (whose default value is 0, implying exact
|
||||||
|
// nearest neighbors). It returns two arrays which are assumed to
|
||||||
|
// contain at least k elements: one (nn_idx) contains the indices
|
||||||
|
// (within the point array) of the nearest neighbors and the other
|
||||||
|
// (dd) contains the squared distances to these nearest neighbors.
|
||||||
|
//
|
||||||
|
// The search algorithm, annkFRSearch, is a fixed-radius kNN
|
||||||
|
// search. In addition to a query point, it is given a (squared)
|
||||||
|
// radius bound. (This is done for consistency, because the search
|
||||||
|
// returns distances as squared quantities.) It does two things.
|
||||||
|
// First, it computes the k nearest neighbors within the radius
|
||||||
|
// bound, and second, it returns the total number of points lying
|
||||||
|
// within the radius bound. It is permitted to set k = 0, in which
|
||||||
|
// case it effectively answers a range counting query. If the
|
||||||
|
// error bound epsilon is positive, then the search is approximate
|
||||||
|
// in the sense that it is free to ignore any point that lies
|
||||||
|
// outside a ball of radius r/(1+epsilon), where r is the given
|
||||||
|
// (unsquared) radius bound.
|
||||||
|
//
|
||||||
|
// The generic object from which all the search structures are
|
||||||
|
// dervied is given below. It is a virtual object, and is useless
|
||||||
|
// by itself.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DLL_API ANNpointSet {
|
||||||
|
public:
|
||||||
|
virtual ~ANNpointSet() {} // virtual distructor
|
||||||
|
|
||||||
|
virtual void annkSearch( // approx k near neighbor search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0 // error bound
|
||||||
|
) = 0; // pure virtual (defined elsewhere)
|
||||||
|
|
||||||
|
virtual int annkFRSearch( // approx fixed-radius kNN search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
ANNdist sqRad, // squared radius
|
||||||
|
int k = 0, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx = NULL, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd = NULL, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0 // error bound
|
||||||
|
) = 0; // pure virtual (defined elsewhere)
|
||||||
|
|
||||||
|
virtual int theDim() = 0; // return dimension of space
|
||||||
|
virtual int nPoints() = 0; // return number of points
|
||||||
|
// return pointer to points
|
||||||
|
virtual ANNpointArray thePoints() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Brute-force nearest neighbor search:
|
||||||
|
// The brute-force search structure is very simple but inefficient.
|
||||||
|
// It has been provided primarily for the sake of comparison with
|
||||||
|
// and validation of the more complex search structures.
|
||||||
|
//
|
||||||
|
// Query processing is the same as described above, but the value
|
||||||
|
// of epsilon is ignored, since all distance calculations are
|
||||||
|
// performed exactly.
|
||||||
|
//
|
||||||
|
// WARNING: This data structure is very slow, and should not be
|
||||||
|
// used unless the number of points is very small.
|
||||||
|
//
|
||||||
|
// Internal information:
|
||||||
|
// ---------------------
|
||||||
|
// This data structure bascially consists of the array of points
|
||||||
|
// (each a pointer to an array of coordinates). The search is
|
||||||
|
// performed by a simple linear scan of all the points.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DLL_API ANNbruteForce: public ANNpointSet {
|
||||||
|
int dim; // dimension
|
||||||
|
int n_pts; // number of points
|
||||||
|
ANNpointArray pts; // point array
|
||||||
|
public:
|
||||||
|
ANNbruteForce( // constructor from point array
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
int n, // number of points
|
||||||
|
int dd); // dimension
|
||||||
|
|
||||||
|
~ANNbruteForce(); // destructor
|
||||||
|
|
||||||
|
void annkSearch( // approx k near neighbor search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0); // error bound
|
||||||
|
|
||||||
|
int annkFRSearch( // approx fixed-radius kNN search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
ANNdist sqRad, // squared radius
|
||||||
|
int k = 0, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx = NULL, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd = NULL, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0); // error bound
|
||||||
|
|
||||||
|
int theDim() // return dimension of space
|
||||||
|
{ return dim; }
|
||||||
|
|
||||||
|
int nPoints() // return number of points
|
||||||
|
{ return n_pts; }
|
||||||
|
|
||||||
|
ANNpointArray thePoints() // return pointer to points
|
||||||
|
{ return pts; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd- and bd-tree splitting and shrinking rules
|
||||||
|
// kd-trees supports a collection of different splitting rules.
|
||||||
|
// In addition to the standard kd-tree splitting rule proposed
|
||||||
|
// by Friedman, Bentley, and Finkel, we have introduced a
|
||||||
|
// number of other splitting rules, which seem to perform
|
||||||
|
// as well or better (for the distributions we have tested).
|
||||||
|
//
|
||||||
|
// The splitting methods given below allow the user to tailor
|
||||||
|
// the data structure to the particular data set. They are
|
||||||
|
// are described in greater details in the kd_split.cc source
|
||||||
|
// file. The method ANN_KD_SUGGEST is the method chosen (rather
|
||||||
|
// subjectively) by the implementors as the one giving the
|
||||||
|
// fastest performance, and is the default splitting method.
|
||||||
|
//
|
||||||
|
// As with splitting rules, there are a number of different
|
||||||
|
// shrinking rules. The shrinking rule ANN_BD_NONE does no
|
||||||
|
// shrinking (and hence produces a kd-tree tree). The rule
|
||||||
|
// ANN_BD_SUGGEST uses the implementors favorite rule.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum ANNsplitRule {
|
||||||
|
ANN_KD_STD = 0, // the optimized kd-splitting rule
|
||||||
|
ANN_KD_MIDPT = 1, // midpoint split
|
||||||
|
ANN_KD_FAIR = 2, // fair split
|
||||||
|
ANN_KD_SL_MIDPT = 3, // sliding midpoint splitting method
|
||||||
|
ANN_KD_SL_FAIR = 4, // sliding fair split method
|
||||||
|
ANN_KD_SUGGEST = 5}; // the authors' suggestion for best
|
||||||
|
const int ANN_N_SPLIT_RULES = 6; // number of split rules
|
||||||
|
|
||||||
|
enum ANNshrinkRule {
|
||||||
|
ANN_BD_NONE = 0, // no shrinking at all (just kd-tree)
|
||||||
|
ANN_BD_SIMPLE = 1, // simple splitting
|
||||||
|
ANN_BD_CENTROID = 2, // centroid splitting
|
||||||
|
ANN_BD_SUGGEST = 3}; // the authors' suggested choice
|
||||||
|
const int ANN_N_SHRINK_RULES = 4; // number of shrink rules
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd-tree:
|
||||||
|
// The main search data structure supported by ANN is a kd-tree.
|
||||||
|
// The main constructor is given a set of points and a choice of
|
||||||
|
// splitting method to use in building the tree.
|
||||||
|
//
|
||||||
|
// Construction:
|
||||||
|
// -------------
|
||||||
|
// The constructor is given the point array, number of points,
|
||||||
|
// dimension, bucket size (default = 1), and the splitting rule
|
||||||
|
// (default = ANN_KD_SUGGEST). The point array is not copied, and
|
||||||
|
// is assumed to be kept constant throughout the lifetime of the
|
||||||
|
// search structure. There is also a "load" constructor that
|
||||||
|
// builds a tree from a file description that was created by the
|
||||||
|
// Dump operation.
|
||||||
|
//
|
||||||
|
// Search:
|
||||||
|
// -------
|
||||||
|
// There are two search methods:
|
||||||
|
//
|
||||||
|
// Standard search (annkSearch()):
|
||||||
|
// Searches nodes in tree-traversal order, always visiting
|
||||||
|
// the closer child first.
|
||||||
|
// Priority search (annkPriSearch()):
|
||||||
|
// Searches nodes in order of increasing distance of the
|
||||||
|
// associated cell from the query point. For many
|
||||||
|
// distributions the standard search seems to work just
|
||||||
|
// fine, but priority search is safer for worst-case
|
||||||
|
// performance.
|
||||||
|
//
|
||||||
|
// Printing:
|
||||||
|
// ---------
|
||||||
|
// There are two methods provided for printing the tree. Print()
|
||||||
|
// is used to produce a "human-readable" display of the tree, with
|
||||||
|
// indenation, which is handy for debugging. Dump() produces a
|
||||||
|
// format that is suitable reading by another program. There is a
|
||||||
|
// "load" constructor, which constructs a tree which is assumed to
|
||||||
|
// have been saved by the Dump() procedure.
|
||||||
|
//
|
||||||
|
// Performance and Structure Statistics:
|
||||||
|
// -------------------------------------
|
||||||
|
// The procedure getStats() collects statistics information on the
|
||||||
|
// tree (its size, height, etc.) See ANNperf.h for information on
|
||||||
|
// the stats structure it returns.
|
||||||
|
//
|
||||||
|
// Internal information:
|
||||||
|
// ---------------------
|
||||||
|
// The data structure consists of three major chunks of storage.
|
||||||
|
// The first (implicit) storage are the points themselves (pts),
|
||||||
|
// which have been provided by the users as an argument to the
|
||||||
|
// constructor, or are allocated dynamically if the tree is built
|
||||||
|
// using the load constructor). These should not be changed during
|
||||||
|
// the lifetime of the search structure. It is the user's
|
||||||
|
// responsibility to delete these after the tree is destroyed.
|
||||||
|
//
|
||||||
|
// The second is the tree itself (which is dynamically allocated in
|
||||||
|
// the constructor) and is given as a pointer to its root node
|
||||||
|
// (root). These nodes are automatically deallocated when the tree
|
||||||
|
// is deleted. See the file src/kd_tree.h for further information
|
||||||
|
// on the structure of the tree nodes.
|
||||||
|
//
|
||||||
|
// Each leaf of the tree does not contain a pointer directly to a
|
||||||
|
// point, but rather contains a pointer to a "bucket", which is an
|
||||||
|
// array consisting of point indices. The third major chunk of
|
||||||
|
// storage is an array (pidx), which is a large array in which all
|
||||||
|
// these bucket subarrays reside. (The reason for storing them
|
||||||
|
// separately is the buckets are typically small, but of varying
|
||||||
|
// sizes. This was done to avoid fragmentation.) This array is
|
||||||
|
// also deallocated when the tree is deleted.
|
||||||
|
//
|
||||||
|
// In addition to this, the tree consists of a number of other
|
||||||
|
// pieces of information which are used in searching and for
|
||||||
|
// subsequent tree operations. These consist of the following:
|
||||||
|
//
|
||||||
|
// dim Dimension of space
|
||||||
|
// n_pts Number of points currently in the tree
|
||||||
|
// n_max Maximum number of points that are allowed
|
||||||
|
// in the tree
|
||||||
|
// bkt_size Maximum bucket size (no. of points per leaf)
|
||||||
|
// bnd_box_lo Bounding box low point
|
||||||
|
// bnd_box_hi Bounding box high point
|
||||||
|
// splitRule Splitting method used
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Some types and objects used by kd-tree functions
|
||||||
|
// See src/kd_tree.h and src/kd_tree.cpp for definitions
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
class ANNkdStats; // stats on kd-tree
|
||||||
|
class ANNkd_node; // generic node in a kd-tree
|
||||||
|
typedef ANNkd_node *ANNkd_ptr; // pointer to a kd-tree node
|
||||||
|
|
||||||
|
class DLL_API ANNkd_tree: public ANNpointSet {
|
||||||
|
protected:
|
||||||
|
int dim; // dimension of space
|
||||||
|
int n_pts; // number of points in tree
|
||||||
|
int bkt_size; // bucket size
|
||||||
|
ANNpointArray pts; // the points
|
||||||
|
ANNidxArray pidx; // point indices (to pts array)
|
||||||
|
ANNkd_ptr root; // root of kd-tree
|
||||||
|
ANNpoint bnd_box_lo; // bounding box low point
|
||||||
|
ANNpoint bnd_box_hi; // bounding box high point
|
||||||
|
|
||||||
|
void SkeletonTree( // construct skeleton tree
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs, // bucket size
|
||||||
|
ANNpointArray pa = NULL, // point array (optional)
|
||||||
|
ANNidxArray pi = NULL); // point indices (optional)
|
||||||
|
|
||||||
|
public:
|
||||||
|
ANNkd_tree( // build skeleton tree
|
||||||
|
int n = 0, // number of points
|
||||||
|
int dd = 0, // dimension
|
||||||
|
int bs = 1); // bucket size
|
||||||
|
|
||||||
|
ANNkd_tree( // build from point array
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs = 1, // bucket size
|
||||||
|
ANNsplitRule split = ANN_KD_SUGGEST); // splitting method
|
||||||
|
|
||||||
|
ANNkd_tree( // build from dump file
|
||||||
|
std::istream& in); // input stream for dump file
|
||||||
|
|
||||||
|
~ANNkd_tree(); // tree destructor
|
||||||
|
|
||||||
|
void annkSearch( // approx k near neighbor search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0); // error bound
|
||||||
|
|
||||||
|
void annkPriSearch( // priority k near neighbor search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0); // error bound
|
||||||
|
|
||||||
|
int annkFRSearch( // approx fixed-radius kNN search
|
||||||
|
ANNpoint q, // the query point
|
||||||
|
ANNdist sqRad, // squared radius of query ball
|
||||||
|
int k, // number of neighbors to return
|
||||||
|
ANNidxArray nn_idx = NULL, // nearest neighbor array (modified)
|
||||||
|
ANNdistArray dd = NULL, // dist to near neighbors (modified)
|
||||||
|
double eps=0.0); // error bound
|
||||||
|
|
||||||
|
int theDim() // return dimension of space
|
||||||
|
{ return dim; }
|
||||||
|
|
||||||
|
int nPoints() // return number of points
|
||||||
|
{ return n_pts; }
|
||||||
|
|
||||||
|
ANNpointArray thePoints() // return pointer to points
|
||||||
|
{ return pts; }
|
||||||
|
|
||||||
|
virtual void Print( // print the tree (for debugging)
|
||||||
|
ANNbool with_pts, // print points as well?
|
||||||
|
std::ostream& out); // output stream
|
||||||
|
|
||||||
|
virtual void Dump( // dump entire tree
|
||||||
|
ANNbool with_pts, // print points as well?
|
||||||
|
std::ostream& out); // output stream
|
||||||
|
|
||||||
|
virtual void getStats( // compute tree statistics
|
||||||
|
ANNkdStats& st); // the statistics (modified)
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Box decomposition tree (bd-tree)
|
||||||
|
// The bd-tree is inherited from a kd-tree. The main difference
|
||||||
|
// in the bd-tree and the kd-tree is a new type of internal node
|
||||||
|
// called a shrinking node (in the kd-tree there is only one type
|
||||||
|
// of internal node, a splitting node). The shrinking node
|
||||||
|
// makes it possible to generate balanced trees in which the
|
||||||
|
// cells have bounded aspect ratio, by allowing the decomposition
|
||||||
|
// to zoom in on regions of dense point concentration. Although
|
||||||
|
// this is a nice idea in theory, few point distributions are so
|
||||||
|
// densely clustered that this is really needed.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DLL_API ANNbd_tree: public ANNkd_tree {
|
||||||
|
public:
|
||||||
|
ANNbd_tree( // build skeleton tree
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs = 1) // bucket size
|
||||||
|
: ANNkd_tree(n, dd, bs) {} // build base kd-tree
|
||||||
|
|
||||||
|
ANNbd_tree( // build from point array
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs = 1, // bucket size
|
||||||
|
ANNsplitRule split = ANN_KD_SUGGEST, // splitting rule
|
||||||
|
ANNshrinkRule shrink = ANN_BD_SUGGEST); // shrinking rule
|
||||||
|
|
||||||
|
ANNbd_tree( // build from dump file
|
||||||
|
std::istream& in); // input stream for dump file
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Other functions
|
||||||
|
// annMaxPtsVisit Sets a limit on the maximum number of points
|
||||||
|
// to visit in the search.
|
||||||
|
// annClose Can be called when all use of ANN is finished.
|
||||||
|
// It clears up a minor memory leak.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
DLL_API void annMaxPtsVisit( // max. pts to visit in search
|
||||||
|
int maxPts); // the limit
|
||||||
|
|
||||||
|
DLL_API void annClose(); // called to end use of ANN
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,223 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: ANNperf.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Last modified: 03/04/98 (Release 0.1)
|
||||||
|
// Description: Include file for ANN performance stats
|
||||||
|
//
|
||||||
|
// Some of the code for statistics gathering has been adapted
|
||||||
|
// from the SmplStat.h package in the g++ library.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Added ANN_ prefix to avoid name conflicts.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANNperf_H
|
||||||
|
#define ANNperf_H
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// basic includes
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <ann/ANN.h> // basic ANN includes
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd-tree stats object
|
||||||
|
// This object is used for collecting information about a kd-tree
|
||||||
|
// or bd-tree.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNkdStats { // stats on kd-tree
|
||||||
|
public:
|
||||||
|
int dim; // dimension of space
|
||||||
|
int n_pts; // no. of points
|
||||||
|
int bkt_size; // bucket size
|
||||||
|
int n_lf; // no. of leaves (including trivial)
|
||||||
|
int n_tl; // no. of trivial leaves (no points)
|
||||||
|
int n_spl; // no. of splitting nodes
|
||||||
|
int n_shr; // no. of shrinking nodes (for bd-trees)
|
||||||
|
int depth; // depth of tree
|
||||||
|
float sum_ar; // sum of leaf aspect ratios
|
||||||
|
float avg_ar; // average leaf aspect ratio
|
||||||
|
//
|
||||||
|
// reset stats
|
||||||
|
void reset(int d=0, int n=0, int bs=0)
|
||||||
|
{
|
||||||
|
dim = d; n_pts = n; bkt_size = bs;
|
||||||
|
n_lf = n_tl = n_spl = n_shr = depth = 0;
|
||||||
|
sum_ar = avg_ar = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNkdStats() // basic constructor
|
||||||
|
{ reset(); }
|
||||||
|
|
||||||
|
void merge(const ANNkdStats &st); // merge stats from child
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANNsampStat
|
||||||
|
// A sample stat collects numeric (double) samples and returns some
|
||||||
|
// simple statistics. Its main functions are:
|
||||||
|
//
|
||||||
|
// reset() Reset to no samples.
|
||||||
|
// += x Include sample x.
|
||||||
|
// samples() Return number of samples.
|
||||||
|
// mean() Return mean of samples.
|
||||||
|
// stdDev() Return standard deviation
|
||||||
|
// min() Return minimum of samples.
|
||||||
|
// max() Return maximum of samples.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
class DLL_API ANNsampStat {
|
||||||
|
int n; // number of samples
|
||||||
|
double sum; // sum
|
||||||
|
double sum2; // sum of squares
|
||||||
|
double minVal, maxVal; // min and max
|
||||||
|
public :
|
||||||
|
void reset() // reset everything
|
||||||
|
{
|
||||||
|
n = 0;
|
||||||
|
sum = sum2 = 0;
|
||||||
|
minVal = ANN_DBL_MAX;
|
||||||
|
maxVal = -ANN_DBL_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNsampStat() { reset(); } // constructor
|
||||||
|
|
||||||
|
void operator+=(double x) // add sample
|
||||||
|
{
|
||||||
|
n++; sum += x; sum2 += x*x;
|
||||||
|
if (x < minVal) minVal = x;
|
||||||
|
if (x > maxVal) maxVal = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int samples() { return n; } // number of samples
|
||||||
|
|
||||||
|
double mean() { return sum/n; } // mean
|
||||||
|
|
||||||
|
// standard deviation
|
||||||
|
double stdDev() { return sqrt((sum2 - (sum*sum)/n)/(n-1));}
|
||||||
|
|
||||||
|
double min() { return minVal; } // minimum
|
||||||
|
double max() { return maxVal; } // maximum
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Operation count updates
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef ANN_PERF
|
||||||
|
#define ANN_FLOP(n) {ann_Nfloat_ops += (n);}
|
||||||
|
#define ANN_LEAF(n) {ann_Nvisit_lfs += (n);}
|
||||||
|
#define ANN_SPL(n) {ann_Nvisit_spl += (n);}
|
||||||
|
#define ANN_SHR(n) {ann_Nvisit_shr += (n);}
|
||||||
|
#define ANN_PTS(n) {ann_Nvisit_pts += (n);}
|
||||||
|
#define ANN_COORD(n) {ann_Ncoord_hts += (n);}
|
||||||
|
#else
|
||||||
|
#define ANN_FLOP(n)
|
||||||
|
#define ANN_LEAF(n)
|
||||||
|
#define ANN_SPL(n)
|
||||||
|
#define ANN_SHR(n)
|
||||||
|
#define ANN_PTS(n)
|
||||||
|
#define ANN_COORD(n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Performance statistics
|
||||||
|
// The following data and routines are used for computing performance
|
||||||
|
// statistics for nearest neighbor searching. Because these routines
|
||||||
|
// can slow the code down, they can be activated and deactiviated by
|
||||||
|
// defining the ANN_PERF variable, by compiling with the option:
|
||||||
|
// -DANN_PERF
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global counters for performance measurement
|
||||||
|
//
|
||||||
|
// visit_lfs The number of leaf nodes visited in the
|
||||||
|
// tree.
|
||||||
|
//
|
||||||
|
// visit_spl The number of splitting nodes visited in the
|
||||||
|
// tree.
|
||||||
|
//
|
||||||
|
// visit_shr The number of shrinking nodes visited in the
|
||||||
|
// tree.
|
||||||
|
//
|
||||||
|
// visit_pts The number of points visited in all the
|
||||||
|
// leaf nodes visited. Equivalently, this
|
||||||
|
// is the number of points for which distance
|
||||||
|
// calculations are performed.
|
||||||
|
//
|
||||||
|
// coord_hts The number of times a coordinate of a
|
||||||
|
// data point is accessed. This is generally
|
||||||
|
// less than visit_pts*d if partial distance
|
||||||
|
// calculation is used. This count is low
|
||||||
|
// in the sense that if a coordinate is hit
|
||||||
|
// many times in the same routine we may
|
||||||
|
// count it only once.
|
||||||
|
//
|
||||||
|
// float_ops The number of floating point operations.
|
||||||
|
// This includes all operations in the heap
|
||||||
|
// as well as distance calculations to boxes.
|
||||||
|
//
|
||||||
|
// average_err The average error of each query (the
|
||||||
|
// error of the reported point to the true
|
||||||
|
// nearest neighbor). For k nearest neighbors
|
||||||
|
// the error is computed k times.
|
||||||
|
//
|
||||||
|
// rank_err The rank error of each query (the difference
|
||||||
|
// in the rank of the reported point and its
|
||||||
|
// true rank).
|
||||||
|
//
|
||||||
|
// data_pts The number of data points. This is not
|
||||||
|
// a counter, but used in stats computation.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern int ann_Ndata_pts; // number of data points
|
||||||
|
extern int ann_Nvisit_lfs; // number of leaf nodes visited
|
||||||
|
extern int ann_Nvisit_spl; // number of splitting nodes visited
|
||||||
|
extern int ann_Nvisit_shr; // number of shrinking nodes visited
|
||||||
|
extern int ann_Nvisit_pts; // visited points for one query
|
||||||
|
extern int ann_Ncoord_hts; // coordinate hits for one query
|
||||||
|
extern int ann_Nfloat_ops; // floating ops for one query
|
||||||
|
extern ANNsampStat ann_visit_lfs; // stats on leaf nodes visits
|
||||||
|
extern ANNsampStat ann_visit_spl; // stats on splitting nodes visits
|
||||||
|
extern ANNsampStat ann_visit_shr; // stats on shrinking nodes visits
|
||||||
|
extern ANNsampStat ann_visit_nds; // stats on total nodes visits
|
||||||
|
extern ANNsampStat ann_visit_pts; // stats on points visited
|
||||||
|
extern ANNsampStat ann_coord_hts; // stats on coordinate hits
|
||||||
|
extern ANNsampStat ann_float_ops; // stats on floating ops
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// The following need to be part of the public interface, because
|
||||||
|
// they are accessed outside the DLL in ann_test.cpp.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
DLL_API extern ANNsampStat ann_average_err; // average error
|
||||||
|
DLL_API extern ANNsampStat ann_rank_err; // rank error
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Declaration of externally accessible routines for statistics
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
DLL_API void annResetStats(int data_size); // reset stats for a set of queries
|
||||||
|
|
||||||
|
DLL_API void annResetCounts(); // reset counts for one queries
|
||||||
|
|
||||||
|
DLL_API void annUpdateStats(); // update stats with current counts
|
||||||
|
|
||||||
|
DLL_API void annPrintStats(ANNbool validate); // print statistics for a run
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,169 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: ANNx.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Internal include file for ANN
|
||||||
|
// Last modified: 01/27/10 (Version 1.1.2)
|
||||||
|
//
|
||||||
|
// These declarations are of use in manipulating some of
|
||||||
|
// the internal data objects appearing in ANN, but are not
|
||||||
|
// needed for applications just using the nearest neighbor
|
||||||
|
// search.
|
||||||
|
//
|
||||||
|
// Typical users of ANN should not need to access this file.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2015 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Changed LO, HI, IN, OUT to ANN_LO, ANN_HI, etc.
|
||||||
|
// Revision 1.1.2 01/27/10
|
||||||
|
// Fixed minor compilation bugs for new versions of gcc
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANNx_H
|
||||||
|
#define ANNx_H
|
||||||
|
|
||||||
|
#include <iomanip> // I/O manipulators
|
||||||
|
#include <ann/ANN.h> // ANN includes
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global constants and types
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
enum {ANN_LO=0, ANN_HI=1}; // splitting indices
|
||||||
|
enum {ANN_IN=0, ANN_OUT=1}; // shrinking indices
|
||||||
|
// what to do in case of error
|
||||||
|
enum ANNerr {ANNwarn = 0, ANNabort = 1};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Maximum number of points to visit
|
||||||
|
// We have an option for terminating the search early if the
|
||||||
|
// number of points visited exceeds some threshold. If the
|
||||||
|
// threshold is 0 (its default) this means there is no limit
|
||||||
|
// and the algorithm applies its normal termination condition.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern int ANNmaxPtsVisited; // maximum number of pts visited
|
||||||
|
extern int ANNptsVisited; // number of pts visited in search
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global function declarations
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annError( // ANN error routine
|
||||||
|
const char* msg, // error message
|
||||||
|
ANNerr level); // level of error
|
||||||
|
|
||||||
|
void annPrintPt( // print a point
|
||||||
|
ANNpoint pt, // the point
|
||||||
|
int dim, // the dimension
|
||||||
|
std::ostream &out); // output stream
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Orthogonal (axis aligned) rectangle
|
||||||
|
// Orthogonal rectangles are represented by two points, one
|
||||||
|
// for the lower left corner (min coordinates) and the other
|
||||||
|
// for the upper right corner (max coordinates).
|
||||||
|
//
|
||||||
|
// The constructor initializes from either a pair of coordinates,
|
||||||
|
// pair of points, or another rectangle. Note that all constructors
|
||||||
|
// allocate new point storage. The destructor deallocates this
|
||||||
|
// storage.
|
||||||
|
//
|
||||||
|
// BEWARE: Orthogonal rectangles should be passed ONLY BY REFERENCE.
|
||||||
|
// (C++'s default copy constructor will not allocate new point
|
||||||
|
// storage, then on return the destructor free's storage, and then
|
||||||
|
// you get into big trouble in the calling procedure.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNorthRect {
|
||||||
|
public:
|
||||||
|
ANNpoint lo; // rectangle lower bounds
|
||||||
|
ANNpoint hi; // rectangle upper bounds
|
||||||
|
//
|
||||||
|
ANNorthRect( // basic constructor
|
||||||
|
int dd, // dimension of space
|
||||||
|
ANNcoord l=0, // default is empty
|
||||||
|
ANNcoord h=0)
|
||||||
|
{ lo = annAllocPt(dd, l); hi = annAllocPt(dd, h); }
|
||||||
|
|
||||||
|
ANNorthRect( // (almost a) copy constructor
|
||||||
|
int dd, // dimension
|
||||||
|
const ANNorthRect &r) // rectangle to copy
|
||||||
|
{ lo = annCopyPt(dd, r.lo); hi = annCopyPt(dd, r.hi); }
|
||||||
|
|
||||||
|
ANNorthRect( // construct from points
|
||||||
|
int dd, // dimension
|
||||||
|
ANNpoint l, // low point
|
||||||
|
ANNpoint h) // hight point
|
||||||
|
{ lo = annCopyPt(dd, l); hi = annCopyPt(dd, h); }
|
||||||
|
|
||||||
|
~ANNorthRect() // destructor
|
||||||
|
{ annDeallocPt(lo); annDeallocPt(hi); }
|
||||||
|
|
||||||
|
ANNbool inside(int dim, ANNpoint p);// is point p inside rectangle?
|
||||||
|
};
|
||||||
|
|
||||||
|
void annAssignRect( // assign one rect to another
|
||||||
|
int dim, // dimension (both must be same)
|
||||||
|
ANNorthRect &dest, // destination (modified)
|
||||||
|
const ANNorthRect &source); // source
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Orthogonal (axis aligned) halfspace
|
||||||
|
// An orthogonal halfspace is represented by an integer cutting
|
||||||
|
// dimension cd, coordinate cutting value, cv, and side, sd, which is
|
||||||
|
// either +1 or -1. Our convention is that point q lies in the (closed)
|
||||||
|
// halfspace if (q[cd] - cv)*sd >= 0.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNorthHalfSpace {
|
||||||
|
public:
|
||||||
|
int cd; // cutting dimension
|
||||||
|
ANNcoord cv; // cutting value
|
||||||
|
int sd; // which side
|
||||||
|
//
|
||||||
|
ANNorthHalfSpace() // default constructor
|
||||||
|
{ cd = 0; cv = 0; sd = 0; }
|
||||||
|
|
||||||
|
ANNorthHalfSpace( // basic constructor
|
||||||
|
int cdd, // dimension of space
|
||||||
|
ANNcoord cvv, // cutting value
|
||||||
|
int sdd) // side
|
||||||
|
{ cd = cdd; cv = cvv; sd = sdd; }
|
||||||
|
|
||||||
|
ANNbool in(ANNpoint q) const // is q inside halfspace?
|
||||||
|
{ return (ANNbool) ((q[cd] - cv)*sd >= 0); }
|
||||||
|
|
||||||
|
ANNbool out(ANNpoint q) const // is q outside halfspace?
|
||||||
|
{ return (ANNbool) ((q[cd] - cv)*sd < 0); }
|
||||||
|
|
||||||
|
ANNdist dist(ANNpoint q) const // (squared) distance from q
|
||||||
|
{ return (ANNdist) ANN_POW(q[cd] - cv); }
|
||||||
|
|
||||||
|
void setLowerBound(int d, ANNpoint p)// set to lower bound at p[i]
|
||||||
|
{ cd = d; cv = p[d]; sd = +1; }
|
||||||
|
|
||||||
|
void setUpperBound(int d, ANNpoint p)// set to upper bound at p[i]
|
||||||
|
{ cd = d; cv = p[d]; sd = -1; }
|
||||||
|
|
||||||
|
void project(ANNpoint &q) // project q (modified) onto halfspace
|
||||||
|
{ if (out(q)) q[cd] = cv; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// array of halfspaces
|
||||||
|
typedef ANNorthHalfSpace *ANNorthHSArray;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,165 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
|
@ -0,0 +1,201 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: ANN.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Methods for ANN.h and ANNx.h
|
||||||
|
// Last modified: 01/27/10 (Version 1.1.2)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2010 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Added performance counting to annDist()
|
||||||
|
// Revision 1.1.2 01/27/10
|
||||||
|
// Fixed minor compilation bugs for new versions of gcc
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <cstdlib> // C standard lib defs
|
||||||
|
#include <ann/ANNx.h> // all ANN includes
|
||||||
|
#include <ann/ANNperf.h> // ANN performance
|
||||||
|
|
||||||
|
using namespace std; // make std:: accessible
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Point methods
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Distance utility.
|
||||||
|
// (Note: In the nearest neighbor search, most distances are
|
||||||
|
// computed using partial distance calculations, not this
|
||||||
|
// procedure.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNdist annDist( // interpoint squared distance
|
||||||
|
int dim,
|
||||||
|
ANNpoint p,
|
||||||
|
ANNpoint q)
|
||||||
|
{
|
||||||
|
register int d;
|
||||||
|
register ANNcoord diff;
|
||||||
|
register ANNcoord dist;
|
||||||
|
|
||||||
|
dist = 0;
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
diff = p[d] - q[d];
|
||||||
|
dist = ANN_SUM(dist, ANN_POW(diff));
|
||||||
|
}
|
||||||
|
ANN_FLOP(3*dim) // performance counts
|
||||||
|
ANN_PTS(1)
|
||||||
|
ANN_COORD(dim)
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annPrintPoint() prints a point to a given output stream.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annPrintPt( // print a point
|
||||||
|
ANNpoint pt, // the point
|
||||||
|
int dim, // the dimension
|
||||||
|
std::ostream &out) // output stream
|
||||||
|
{
|
||||||
|
for (int j = 0; j < dim; j++) {
|
||||||
|
out << pt[j];
|
||||||
|
if (j < dim-1) out << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Point allocation/deallocation:
|
||||||
|
//
|
||||||
|
// Because points (somewhat like strings in C) are stored
|
||||||
|
// as pointers. Consequently, creating and destroying
|
||||||
|
// copies of points may require storage allocation. These
|
||||||
|
// procedures do this.
|
||||||
|
//
|
||||||
|
// annAllocPt() and annDeallocPt() allocate a deallocate
|
||||||
|
// storage for a single point, and return a pointer to it.
|
||||||
|
//
|
||||||
|
// annAllocPts() allocates an array of points as well a place
|
||||||
|
// to store their coordinates, and initializes the points to
|
||||||
|
// point to their respective coordinates. It allocates point
|
||||||
|
// storage in a contiguous block large enough to store all the
|
||||||
|
// points. It performs no initialization.
|
||||||
|
//
|
||||||
|
// annDeallocPts() should only be used on point arrays allocated
|
||||||
|
// by annAllocPts since it assumes that points are allocated in
|
||||||
|
// a block.
|
||||||
|
//
|
||||||
|
// annCopyPt() copies a point taking care to allocate storage
|
||||||
|
// for the new point.
|
||||||
|
//
|
||||||
|
// annAssignRect() assigns the coordinates of one rectangle to
|
||||||
|
// another. The two rectangles must have the same dimension
|
||||||
|
// (and it is not possible to test this here).
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNpoint annAllocPt(int dim, ANNcoord c) // allocate 1 point
|
||||||
|
{
|
||||||
|
ANNpoint p = new ANNcoord[dim];
|
||||||
|
for (int i = 0; i < dim; i++) p[i] = c;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNpointArray annAllocPts(int n, int dim) // allocate n pts in dim
|
||||||
|
{
|
||||||
|
ANNpointArray pa = new ANNpoint[n]; // allocate points
|
||||||
|
ANNpoint p = new ANNcoord[n*dim]; // allocate space for coords
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
pa[i] = &(p[i*dim]);
|
||||||
|
}
|
||||||
|
return pa;
|
||||||
|
}
|
||||||
|
|
||||||
|
void annDeallocPt(ANNpoint &p) // deallocate 1 point
|
||||||
|
{
|
||||||
|
delete [] p;
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void annDeallocPts(ANNpointArray &pa) // deallocate points
|
||||||
|
{
|
||||||
|
delete [] pa[0]; // dealloc coordinate storage
|
||||||
|
delete [] pa; // dealloc points
|
||||||
|
pa = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNpoint annCopyPt(int dim, ANNpoint source) // copy point
|
||||||
|
{
|
||||||
|
ANNpoint p = new ANNcoord[dim];
|
||||||
|
for (int i = 0; i < dim; i++) p[i] = source[i];
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign one rect to another
|
||||||
|
void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dim; i++) {
|
||||||
|
dest.lo[i] = source.lo[i];
|
||||||
|
dest.hi[i] = source.hi[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// is point inside rectangle?
|
||||||
|
ANNbool ANNorthRect::inside(int dim, ANNpoint p)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dim; i++) {
|
||||||
|
if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse;
|
||||||
|
}
|
||||||
|
return ANNtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Error handler
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annError(const char* msg, ANNerr level)
|
||||||
|
{
|
||||||
|
if (level == ANNabort) {
|
||||||
|
cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Limit on number of points visited
|
||||||
|
// We have an option for terminating the search early if the
|
||||||
|
// number of points visited exceeds some threshold. If the
|
||||||
|
// threshold is 0 (its default) this means there is no limit
|
||||||
|
// and the algorithm applies its normal termination condition.
|
||||||
|
// This is for applications where there are real time constraints
|
||||||
|
// on the running time of the algorithm.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ANNmaxPtsVisited = 0; // maximum number of pts visited
|
||||||
|
int ANNptsVisited; // number of pts visited in search
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global function declarations
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annMaxPtsVisit( // set limit on max. pts to visit in search
|
||||||
|
int maxPts) // the limit
|
||||||
|
{
|
||||||
|
ANNmaxPtsVisited = maxPts;
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: bd_fix_rad_search.cpp
|
||||||
|
// Programmer: David Mount
|
||||||
|
// Description: Standard bd-tree search
|
||||||
|
// Last modified: 05/03/05 (Version 1.1)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 1.1 05/03/05
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "bd_tree.h" // bd-tree declarations
|
||||||
|
#include "kd_fix_rad_search.h" // kd-tree FR search declarations
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Approximate searching for bd-trees.
|
||||||
|
// See the file kd_FR_search.cpp for general information on the
|
||||||
|
// approximate nearest neighbor search algorithm. Here we
|
||||||
|
// include the extensions for shrinking nodes.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// bd_shrink::ann_FR_search - search a shrinking node
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNbd_shrink::ann_FR_search(ANNdist box_dist)
|
||||||
|
{
|
||||||
|
// check dist calc term cond.
|
||||||
|
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
|
||||||
|
|
||||||
|
ANNdist inner_dist = 0; // distance to inner box
|
||||||
|
for (int i = 0; i < n_bnds; i++) { // is query point in the box?
|
||||||
|
if (bnds[i].out(ANNkdFRQ)) { // outside this bounding side?
|
||||||
|
// add to inner distance
|
||||||
|
inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inner_dist <= box_dist) { // if inner box is closer
|
||||||
|
child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first
|
||||||
|
child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child
|
||||||
|
}
|
||||||
|
else { // if outer box is closer
|
||||||
|
child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first
|
||||||
|
child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child
|
||||||
|
}
|
||||||
|
ANN_FLOP(3*n_bnds) // increment floating ops
|
||||||
|
ANN_SHR(1) // one more shrinking node
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: bd_pr_search.cpp
|
||||||
|
// Programmer: David Mount
|
||||||
|
// Description: Priority search for bd-trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
//History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "bd_tree.h" // bd-tree declarations
|
||||||
|
#include "kd_pr_search.h" // kd priority search declarations
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Approximate priority searching for bd-trees.
|
||||||
|
// See the file kd_pr_search.cc for general information on the
|
||||||
|
// approximate nearest neighbor priority search algorithm. Here
|
||||||
|
// we include the extensions for shrinking nodes.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// bd_shrink::ann_search - search a shrinking node
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNbd_shrink::ann_pri_search(ANNdist box_dist)
|
||||||
|
{
|
||||||
|
ANNdist inner_dist = 0; // distance to inner box
|
||||||
|
for (int i = 0; i < n_bnds; i++) { // is query point in the box?
|
||||||
|
if (bnds[i].out(ANNprQ)) { // outside this bounding side?
|
||||||
|
// add to inner distance
|
||||||
|
inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inner_dist <= box_dist) { // if inner box is closer
|
||||||
|
if (child[ANN_OUT] != KD_TRIVIAL) // enqueue outer if not trivial
|
||||||
|
ANNprBoxPQ->insert(box_dist,child[ANN_OUT]);
|
||||||
|
// continue with inner child
|
||||||
|
child[ANN_IN]->ann_pri_search(inner_dist);
|
||||||
|
}
|
||||||
|
else { // if outer box is closer
|
||||||
|
if (child[ANN_IN] != KD_TRIVIAL) // enqueue inner if not trivial
|
||||||
|
ANNprBoxPQ->insert(inner_dist,child[ANN_IN]);
|
||||||
|
// continue with outer child
|
||||||
|
child[ANN_OUT]->ann_pri_search(box_dist);
|
||||||
|
}
|
||||||
|
ANN_FLOP(3*n_bnds) // increment floating ops
|
||||||
|
ANN_SHR(1) // one more shrinking node
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: bd_search.cpp
|
||||||
|
// Programmer: David Mount
|
||||||
|
// Description: Standard bd-tree search
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "bd_tree.h" // bd-tree declarations
|
||||||
|
#include "kd_search.h" // kd-tree search declarations
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Approximate searching for bd-trees.
|
||||||
|
// See the file kd_search.cpp for general information on the
|
||||||
|
// approximate nearest neighbor search algorithm. Here we
|
||||||
|
// include the extensions for shrinking nodes.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// bd_shrink::ann_search - search a shrinking node
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNbd_shrink::ann_search(ANNdist box_dist)
|
||||||
|
{
|
||||||
|
// check dist calc term cond.
|
||||||
|
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
|
||||||
|
|
||||||
|
ANNdist inner_dist = 0; // distance to inner box
|
||||||
|
for (int i = 0; i < n_bnds; i++) { // is query point in the box?
|
||||||
|
if (bnds[i].out(ANNkdQ)) { // outside this bounding side?
|
||||||
|
// add to inner distance
|
||||||
|
inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inner_dist <= box_dist) { // if inner box is closer
|
||||||
|
child[ANN_IN]->ann_search(inner_dist); // search inner child first
|
||||||
|
child[ANN_OUT]->ann_search(box_dist); // ...then outer child
|
||||||
|
}
|
||||||
|
else { // if outer box is closer
|
||||||
|
child[ANN_OUT]->ann_search(box_dist); // search outer child first
|
||||||
|
child[ANN_IN]->ann_search(inner_dist); // ...then outer child
|
||||||
|
}
|
||||||
|
ANN_FLOP(3*n_bnds) // increment floating ops
|
||||||
|
ANN_SHR(1) // one more shrinking node
|
||||||
|
}
|
|
@ -0,0 +1,417 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: bd_tree.cpp
|
||||||
|
// Programmer: David Mount
|
||||||
|
// Description: Basic methods for bd-trees.
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision l.0 04/01/05
|
||||||
|
// Fixed centroid shrink threshold condition to depend on the
|
||||||
|
// dimension.
|
||||||
|
// Moved dump routine to kd_dump.cpp.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "bd_tree.h" // bd-tree declarations
|
||||||
|
#include "kd_util.h" // kd-tree utilities
|
||||||
|
#include "kd_split.h" // kd-tree splitting rules
|
||||||
|
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Printing a bd-tree
|
||||||
|
// These routines print a bd-tree. See the analogous procedure
|
||||||
|
// in kd_tree.cpp for more information.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNbd_shrink::print( // print shrinking node
|
||||||
|
int level, // depth of node in tree
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
child[ANN_OUT]->print(level+1, out); // print out-child
|
||||||
|
|
||||||
|
out << " ";
|
||||||
|
for (int i = 0; i < level; i++) // print indentation
|
||||||
|
out << "..";
|
||||||
|
out << "Shrink";
|
||||||
|
for (int j = 0; j < n_bnds; j++) { // print sides, 2 per line
|
||||||
|
if (j % 2 == 0) {
|
||||||
|
out << "\n"; // newline and indentation
|
||||||
|
for (int i = 0; i < level+2; i++) out << " ";
|
||||||
|
}
|
||||||
|
out << " ([" << bnds[j].cd << "]"
|
||||||
|
<< (bnds[j].sd > 0 ? ">=" : "< ")
|
||||||
|
<< bnds[j].cv << ")";
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
|
||||||
|
child[ANN_IN]->print(level+1, out); // print in-child
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_tree statistics utility (for performance evaluation)
|
||||||
|
// This routine computes various statistics information for
|
||||||
|
// shrinking nodes. See file kd_tree.cpp for more information.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNbd_shrink::getStats( // get subtree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // stats (modified)
|
||||||
|
ANNorthRect &bnd_box) // bounding box
|
||||||
|
{
|
||||||
|
ANNkdStats ch_stats; // stats for children
|
||||||
|
ANNorthRect inner_box(dim); // inner box of shrink
|
||||||
|
|
||||||
|
annBnds2Box(bnd_box, // enclosing box
|
||||||
|
dim, // dimension
|
||||||
|
n_bnds, // number of bounds
|
||||||
|
bnds, // bounds array
|
||||||
|
inner_box); // inner box (modified)
|
||||||
|
// get stats for inner child
|
||||||
|
ch_stats.reset(); // reset
|
||||||
|
child[ANN_IN]->getStats(dim, ch_stats, inner_box);
|
||||||
|
st.merge(ch_stats); // merge them
|
||||||
|
// get stats for outer child
|
||||||
|
ch_stats.reset(); // reset
|
||||||
|
child[ANN_OUT]->getStats(dim, ch_stats, bnd_box);
|
||||||
|
st.merge(ch_stats); // merge them
|
||||||
|
|
||||||
|
st.depth++; // increment depth
|
||||||
|
st.n_shr++; // increment number of shrinks
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// bd-tree constructor
|
||||||
|
// This is the main constructor for bd-trees given a set of points.
|
||||||
|
// It first builds a skeleton kd-tree as a basis, then computes the
|
||||||
|
// bounding box of the data points, and then invokes rbd_tree() to
|
||||||
|
// actually build the tree, passing it the appropriate splitting
|
||||||
|
// and shrinking information.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_ptr rbd_tree( // recursive construction of bd-tree
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int bsp, // bucket space
|
||||||
|
ANNorthRect &bnd_box, // bounding box for current node
|
||||||
|
ANNkd_splitter splitter, // splitting routine
|
||||||
|
ANNshrinkRule shrink); // shrinking rule
|
||||||
|
|
||||||
|
ANNbd_tree::ANNbd_tree( // construct from point array
|
||||||
|
ANNpointArray pa, // point array (with at least n pts)
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs, // bucket size
|
||||||
|
ANNsplitRule split, // splitting rule
|
||||||
|
ANNshrinkRule shrink) // shrinking rule
|
||||||
|
: ANNkd_tree(n, dd, bs) // build skeleton base tree
|
||||||
|
{
|
||||||
|
pts = pa; // where the points are
|
||||||
|
if (n == 0) return; // no points--no sweat
|
||||||
|
|
||||||
|
ANNorthRect bnd_box(dd); // bounding box for points
|
||||||
|
// construct bounding rectangle
|
||||||
|
annEnclRect(pa, pidx, n, dd, bnd_box);
|
||||||
|
// copy to tree structure
|
||||||
|
bnd_box_lo = annCopyPt(dd, bnd_box.lo);
|
||||||
|
bnd_box_hi = annCopyPt(dd, bnd_box.hi);
|
||||||
|
|
||||||
|
switch (split) { // build by rule
|
||||||
|
case ANN_KD_STD: // standard kd-splitting rule
|
||||||
|
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink);
|
||||||
|
break;
|
||||||
|
case ANN_KD_MIDPT: // midpoint split
|
||||||
|
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink);
|
||||||
|
break;
|
||||||
|
case ANN_KD_SUGGEST: // best (in our opinion)
|
||||||
|
case ANN_KD_SL_MIDPT: // sliding midpoint split
|
||||||
|
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink);
|
||||||
|
break;
|
||||||
|
case ANN_KD_FAIR: // fair split
|
||||||
|
root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink);
|
||||||
|
break;
|
||||||
|
case ANN_KD_SL_FAIR: // sliding fair split
|
||||||
|
root = rbd_tree(pa, pidx, n, dd, bs,
|
||||||
|
bnd_box, sl_fair_split, shrink);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
annError("Illegal splitting method", ANNabort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Shrinking rules
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum ANNdecomp {SPLIT, SHRINK}; // decomposition methods
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// trySimpleShrink - Attempt a simple shrink
|
||||||
|
//
|
||||||
|
// We compute the tight bounding box of the points, and compute
|
||||||
|
// the 2*dim ``gaps'' between the sides of the tight box and the
|
||||||
|
// bounding box. If any of the gaps is large enough relative to
|
||||||
|
// the longest side of the tight bounding box, then we shrink
|
||||||
|
// all sides whose gaps are large enough. (The reason for
|
||||||
|
// comparing against the tight bounding box, is that after
|
||||||
|
// shrinking the longest box size will decrease, and if we use
|
||||||
|
// the standard bounding box, we may decide to shrink twice in
|
||||||
|
// a row. Since the tight box is fixed, we cannot shrink twice
|
||||||
|
// consecutively.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
const float BD_GAP_THRESH = 0.5; // gap threshold (must be < 1)
|
||||||
|
const int BD_CT_THRESH = 2; // min number of shrink sides
|
||||||
|
|
||||||
|
ANNdecomp trySimpleShrink( // try a simple shrink
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
const ANNorthRect &bnd_box, // current bounding box
|
||||||
|
ANNorthRect &inner_box) // inner box if shrinking (returned)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
// compute tight bounding box
|
||||||
|
annEnclRect(pa, pidx, n, dim, inner_box);
|
||||||
|
|
||||||
|
ANNcoord max_length = 0; // find longest box side
|
||||||
|
for (i = 0; i < dim; i++) {
|
||||||
|
ANNcoord length = inner_box.hi[i] - inner_box.lo[i];
|
||||||
|
if (length > max_length) {
|
||||||
|
max_length = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int shrink_ct = 0; // number of sides we shrunk
|
||||||
|
for (i = 0; i < dim; i++) { // select which sides to shrink
|
||||||
|
// gap between boxes
|
||||||
|
ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i];
|
||||||
|
// big enough gap to shrink?
|
||||||
|
if (gap_hi < max_length*BD_GAP_THRESH)
|
||||||
|
inner_box.hi[i] = bnd_box.hi[i]; // no - expand
|
||||||
|
else shrink_ct++; // yes - shrink this side
|
||||||
|
|
||||||
|
// repeat for high side
|
||||||
|
ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i];
|
||||||
|
if (gap_lo < max_length*BD_GAP_THRESH)
|
||||||
|
inner_box.lo[i] = bnd_box.lo[i]; // no - expand
|
||||||
|
else shrink_ct++; // yes - shrink this side
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shrink_ct >= BD_CT_THRESH) // did we shrink enough sides?
|
||||||
|
return SHRINK;
|
||||||
|
else return SPLIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// tryCentroidShrink - Attempt a centroid shrink
|
||||||
|
//
|
||||||
|
// We repeatedly apply the splitting rule, always to the larger subset
|
||||||
|
// of points, until the number of points decreases by the constant
|
||||||
|
// fraction BD_FRACTION. If this takes more than dim*BD_MAX_SPLIT_FAC
|
||||||
|
// splits for this to happen, then we shrink to the final inner box
|
||||||
|
// Otherwise we split.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const float BD_MAX_SPLIT_FAC = 0.5; // maximum number of splits allowed
|
||||||
|
const float BD_FRACTION = 0.5; // ...to reduce points by this fraction
|
||||||
|
// ...This must be < 1.
|
||||||
|
|
||||||
|
ANNdecomp tryCentroidShrink( // try a centroid shrink
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
const ANNorthRect &bnd_box, // current bounding box
|
||||||
|
ANNkd_splitter splitter, // splitting procedure
|
||||||
|
ANNorthRect &inner_box) // inner box if shrinking (returned)
|
||||||
|
{
|
||||||
|
int n_sub = n; // number of points in subset
|
||||||
|
int n_goal = (int) (n*BD_FRACTION); // number of point in goal
|
||||||
|
int n_splits = 0; // number of splits needed
|
||||||
|
// initialize inner box to bounding box
|
||||||
|
annAssignRect(dim, inner_box, bnd_box);
|
||||||
|
|
||||||
|
while (n_sub > n_goal) { // keep splitting until goal reached
|
||||||
|
int cd; // cut dim from splitter (ignored)
|
||||||
|
ANNcoord cv; // cut value from splitter (ignored)
|
||||||
|
int n_lo; // number of points on low side
|
||||||
|
// invoke splitting procedure
|
||||||
|
(*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo);
|
||||||
|
n_splits++; // increment split count
|
||||||
|
|
||||||
|
if (n_lo >= n_sub/2) { // most points on low side
|
||||||
|
inner_box.hi[cd] = cv; // collapse high side
|
||||||
|
n_sub = n_lo; // recurse on lower points
|
||||||
|
}
|
||||||
|
else { // most points on high side
|
||||||
|
inner_box.lo[cd] = cv; // collapse low side
|
||||||
|
pidx += n_lo; // recurse on higher points
|
||||||
|
n_sub -= n_lo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits
|
||||||
|
return SHRINK; // shrink to final subset
|
||||||
|
else
|
||||||
|
return SPLIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// selectDecomp - select which decomposition to use
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNdecomp selectDecomp( // select decomposition method
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
const ANNorthRect &bnd_box, // current bounding box
|
||||||
|
ANNkd_splitter splitter, // splitting procedure
|
||||||
|
ANNshrinkRule shrink, // shrinking rule
|
||||||
|
ANNorthRect &inner_box) // inner box if shrinking (returned)
|
||||||
|
{
|
||||||
|
ANNdecomp decomp = SPLIT; // decomposition
|
||||||
|
|
||||||
|
switch (shrink) { // check shrinking rule
|
||||||
|
case ANN_BD_NONE: // no shrinking allowed
|
||||||
|
decomp = SPLIT;
|
||||||
|
break;
|
||||||
|
case ANN_BD_SUGGEST: // author's suggestion
|
||||||
|
case ANN_BD_SIMPLE: // simple shrink
|
||||||
|
decomp = trySimpleShrink(
|
||||||
|
pa, pidx, // points and indices
|
||||||
|
n, dim, // number of points and dimension
|
||||||
|
bnd_box, // current bounding box
|
||||||
|
inner_box); // inner box if shrinking (returned)
|
||||||
|
break;
|
||||||
|
case ANN_BD_CENTROID: // centroid shrink
|
||||||
|
decomp = tryCentroidShrink(
|
||||||
|
pa, pidx, // points and indices
|
||||||
|
n, dim, // number of points and dimension
|
||||||
|
bnd_box, // current bounding box
|
||||||
|
splitter, // splitting procedure
|
||||||
|
inner_box); // inner box if shrinking (returned)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
annError("Illegal shrinking rule", ANNabort);
|
||||||
|
}
|
||||||
|
return decomp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// rbd_tree - recursive procedure to build a bd-tree
|
||||||
|
//
|
||||||
|
// This is analogous to rkd_tree, but for bd-trees. See the
|
||||||
|
// procedure rkd_tree() in kd_split.cpp for more information.
|
||||||
|
//
|
||||||
|
// If the number of points falls below the bucket size, then a
|
||||||
|
// leaf node is created for the points. Otherwise we invoke the
|
||||||
|
// procedure selectDecomp() which determines whether we are to
|
||||||
|
// split or shrink. If splitting is chosen, then we essentially
|
||||||
|
// do exactly as rkd_tree() would, and invoke the specified
|
||||||
|
// splitting procedure to the points. Otherwise, the selection
|
||||||
|
// procedure returns a bounding box, from which we extract the
|
||||||
|
// appropriate shrinking bounds, and create a shrinking node.
|
||||||
|
// Finally the points are subdivided, and the procedure is
|
||||||
|
// invoked recursively on the two subsets to form the children.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_ptr rbd_tree( // recursive construction of bd-tree
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int bsp, // bucket space
|
||||||
|
ANNorthRect &bnd_box, // bounding box for current node
|
||||||
|
ANNkd_splitter splitter, // splitting routine
|
||||||
|
ANNshrinkRule shrink) // shrinking rule
|
||||||
|
{
|
||||||
|
ANNdecomp decomp; // decomposition method
|
||||||
|
|
||||||
|
ANNorthRect inner_box(dim); // inner box (if shrinking)
|
||||||
|
|
||||||
|
if (n <= bsp) { // n small, make a leaf node
|
||||||
|
if (n == 0) // empty leaf node
|
||||||
|
return KD_TRIVIAL; // return (canonical) empty leaf
|
||||||
|
else // construct the node and return
|
||||||
|
return new ANNkd_leaf(n, pidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
decomp = selectDecomp( // select decomposition method
|
||||||
|
pa, pidx, // points and indices
|
||||||
|
n, dim, // number of points and dimension
|
||||||
|
bnd_box, // current bounding box
|
||||||
|
splitter, shrink, // splitting/shrinking methods
|
||||||
|
inner_box); // inner box if shrinking (returned)
|
||||||
|
|
||||||
|
if (decomp == SPLIT) { // split selected
|
||||||
|
int cd; // cutting dimension
|
||||||
|
ANNcoord cv; // cutting value
|
||||||
|
int n_lo; // number on low side of cut
|
||||||
|
// invoke splitting procedure
|
||||||
|
(*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
|
||||||
|
|
||||||
|
ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension
|
||||||
|
ANNcoord hv = bnd_box.hi[cd];
|
||||||
|
|
||||||
|
bnd_box.hi[cd] = cv; // modify bounds for left subtree
|
||||||
|
ANNkd_ptr lo = rbd_tree( // build left subtree
|
||||||
|
pa, pidx, n_lo, // ...from pidx[0..n_lo-1]
|
||||||
|
dim, bsp, bnd_box, splitter, shrink);
|
||||||
|
bnd_box.hi[cd] = hv; // restore bounds
|
||||||
|
|
||||||
|
bnd_box.lo[cd] = cv; // modify bounds for right subtree
|
||||||
|
ANNkd_ptr hi = rbd_tree( // build right subtree
|
||||||
|
pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
|
||||||
|
dim, bsp, bnd_box, splitter, shrink);
|
||||||
|
bnd_box.lo[cd] = lv; // restore bounds
|
||||||
|
// create the splitting node
|
||||||
|
return new ANNkd_split(cd, cv, lv, hv, lo, hi);
|
||||||
|
}
|
||||||
|
else { // shrink selected
|
||||||
|
int n_in; // number of points in box
|
||||||
|
int n_bnds; // number of bounding sides
|
||||||
|
|
||||||
|
annBoxSplit( // split points around inner box
|
||||||
|
pa, // points to split
|
||||||
|
pidx, // point indices
|
||||||
|
n, // number of points
|
||||||
|
dim, // dimension
|
||||||
|
inner_box, // inner box
|
||||||
|
n_in); // number of points inside (returned)
|
||||||
|
|
||||||
|
ANNkd_ptr in = rbd_tree( // build inner subtree pidx[0..n_in-1]
|
||||||
|
pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink);
|
||||||
|
ANNkd_ptr out = rbd_tree( // build outer subtree pidx[n_in..n]
|
||||||
|
pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink);
|
||||||
|
|
||||||
|
ANNorthHSArray bnds = NULL; // bounds (alloc in Box2Bnds and
|
||||||
|
// ...freed in bd_shrink destroyer)
|
||||||
|
|
||||||
|
annBox2Bnds( // convert inner box to bounds
|
||||||
|
inner_box, // inner box
|
||||||
|
bnd_box, // enclosing box
|
||||||
|
dim, // dimension
|
||||||
|
n_bnds, // number of bounds (returned)
|
||||||
|
bnds); // bounds array (modified)
|
||||||
|
|
||||||
|
// return shrinking node
|
||||||
|
return new ANNbd_shrink(n_bnds, bnds, in, out);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: bd_tree.h
|
||||||
|
// Programmer: David Mount
|
||||||
|
// Description: Declarations for standard bd-tree routines
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Changed IN, OUT to ANN_IN, ANN_OUT
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_bd_tree_H
|
||||||
|
#define ANN_bd_tree_H
|
||||||
|
|
||||||
|
#include <ann/ANNx.h> // all ANN includes
|
||||||
|
#include "kd_tree.h" // kd-tree includes
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// bd-tree shrinking node.
|
||||||
|
// The main addition in the bd-tree is the shrinking node, which
|
||||||
|
// is declared here.
|
||||||
|
//
|
||||||
|
// Shrinking nodes are defined by list of orthogonal halfspaces.
|
||||||
|
// These halfspaces define a (possibly unbounded) orthogonal
|
||||||
|
// rectangle. There are two children, in and out. Points that
|
||||||
|
// lie within this rectangle are stored in the in-child, and the
|
||||||
|
// other points are stored in the out-child.
|
||||||
|
//
|
||||||
|
// We use a list of orthogonal halfspaces rather than an
|
||||||
|
// orthogonal rectangle object because typically the number of
|
||||||
|
// sides of the shrinking box will be much smaller than the
|
||||||
|
// worst case bound of 2*dim.
|
||||||
|
//
|
||||||
|
// BEWARE: Note that constructor just copies the pointer to the
|
||||||
|
// bounding array, but the destructor deallocates it. This is
|
||||||
|
// rather poor practice, but happens to be convenient. The list
|
||||||
|
// is allocated in the bd-tree building procedure rbd_tree() just
|
||||||
|
// prior to construction, and is used for no other purposes.
|
||||||
|
//
|
||||||
|
// WARNING: In the near neighbor searching code it is assumed that
|
||||||
|
// the list of bounding halfspaces is irredundant, meaning that there
|
||||||
|
// are no two distinct halfspaces in the list with the same outward
|
||||||
|
// pointing normals.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNbd_shrink : public ANNkd_node // splitting node of a kd-tree
|
||||||
|
{
|
||||||
|
int n_bnds; // number of bounding halfspaces
|
||||||
|
ANNorthHSArray bnds; // list of bounding halfspaces
|
||||||
|
ANNkd_ptr child[2]; // in and out children
|
||||||
|
public:
|
||||||
|
ANNbd_shrink( // constructor
|
||||||
|
int nb, // number of bounding halfspaces
|
||||||
|
ANNorthHSArray bds, // list of bounding halfspaces
|
||||||
|
ANNkd_ptr ic=NULL, ANNkd_ptr oc=NULL) // children
|
||||||
|
{
|
||||||
|
n_bnds = nb; // cutting dimension
|
||||||
|
bnds = bds; // assign bounds
|
||||||
|
child[ANN_IN] = ic; // set children
|
||||||
|
child[ANN_OUT] = oc;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ANNbd_shrink() // destructor
|
||||||
|
{
|
||||||
|
if (child[ANN_IN]!= NULL && child[ANN_IN]!= KD_TRIVIAL)
|
||||||
|
delete child[ANN_IN];
|
||||||
|
if (child[ANN_OUT]!= NULL&& child[ANN_OUT]!= KD_TRIVIAL)
|
||||||
|
delete child[ANN_OUT];
|
||||||
|
if (bnds != NULL)
|
||||||
|
delete [] bnds; // delete bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void getStats( // get tree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // statistics
|
||||||
|
ANNorthRect &bnd_box); // bounding box
|
||||||
|
virtual void print(int level, ostream &out);// print node
|
||||||
|
virtual void dump(ostream &out); // dump node
|
||||||
|
|
||||||
|
virtual void ann_search(ANNdist); // standard search
|
||||||
|
virtual void ann_pri_search(ANNdist); // priority search
|
||||||
|
virtual void ann_FR_search(ANNdist); // fixed-radius search
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,109 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: brute.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Brute-force nearest neighbors
|
||||||
|
// Last modified: 05/03/05 (Version 1.1)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.1 05/03/05
|
||||||
|
// Added fixed-radius kNN search
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <ann/ANNx.h> // all ANN includes
|
||||||
|
#include "pr_queue_k.h" // k element priority queue
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Brute-force search simply stores a pointer to the list of
|
||||||
|
// data points and searches linearly for the nearest neighbor.
|
||||||
|
// The k nearest neighbors are stored in a k-element priority
|
||||||
|
// queue (which is implemented in a pretty dumb way as well).
|
||||||
|
//
|
||||||
|
// If ANN_ALLOW_SELF_MATCH is ANNfalse then data points at distance
|
||||||
|
// zero are not considered.
|
||||||
|
//
|
||||||
|
// Note that the error bound eps is passed in, but it is ignored.
|
||||||
|
// These routines compute exact nearest neighbors (which is needed
|
||||||
|
// for validation purposes in ann_test.cpp).
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNbruteForce::ANNbruteForce( // constructor from point array
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
int n, // number of points
|
||||||
|
int dd) // dimension
|
||||||
|
{
|
||||||
|
dim = dd; n_pts = n; pts = pa;
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNbruteForce::~ANNbruteForce() { } // destructor (empty)
|
||||||
|
|
||||||
|
void ANNbruteForce::annkSearch( // approx k near neighbor search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor indices (returned)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (returned)
|
||||||
|
double /*eps*/) // error bound (ignored)
|
||||||
|
{
|
||||||
|
ANNmin_k mk(k); // construct a k-limited priority queue
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (k > n_pts) { // too many near neighbors?
|
||||||
|
annError("Requesting more near neighbors than data points", ANNabort);
|
||||||
|
}
|
||||||
|
// run every point through queue
|
||||||
|
for (i = 0; i < n_pts; i++) {
|
||||||
|
// compute distance to point
|
||||||
|
ANNdist sqDist = annDist(dim, pts[i], q);
|
||||||
|
if (ANN_ALLOW_SELF_MATCH || sqDist != 0)
|
||||||
|
mk.insert(sqDist, i);
|
||||||
|
}
|
||||||
|
for (i = 0; i < k; i++) { // extract the k closest points
|
||||||
|
dd[i] = mk.ith_smallest_key(i);
|
||||||
|
nn_idx[i] = mk.ith_smallest_info(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ANNbruteForce::annkFRSearch( // approx fixed-radius kNN search
|
||||||
|
ANNpoint q, // query point
|
||||||
|
ANNdist sqRad, // squared radius
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor array (returned)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (returned)
|
||||||
|
double /*eps*/) // error bound
|
||||||
|
{
|
||||||
|
ANNmin_k mk(k); // construct a k-limited priority queue
|
||||||
|
int i;
|
||||||
|
int pts_in_range = 0; // number of points in query range
|
||||||
|
// run every point through queue
|
||||||
|
for (i = 0; i < n_pts; i++) {
|
||||||
|
// compute distance to point
|
||||||
|
ANNdist sqDist = annDist(dim, pts[i], q);
|
||||||
|
if (sqDist <= sqRad && // within radius bound
|
||||||
|
(ANN_ALLOW_SELF_MATCH || sqDist != 0)) { // ...and no self match
|
||||||
|
mk.insert(sqDist, i);
|
||||||
|
pts_in_range++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < k; i++) { // extract the k closest points
|
||||||
|
if (dd != NULL)
|
||||||
|
dd[i] = mk.ith_smallest_key(i);
|
||||||
|
if (nn_idx != NULL)
|
||||||
|
nn_idx[i] = mk.ith_smallest_info(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pts_in_range;
|
||||||
|
}
|
|
@ -0,0 +1,444 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_dump.cc
|
||||||
|
// Programmer: David Mount
|
||||||
|
// Description: Dump and Load for kd- and bd-trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Moved dump out of kd_tree.cc into this file.
|
||||||
|
// Added kd-tree load constructor.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This file contains routines for dumping kd-trees and bd-trees and
|
||||||
|
// reloading them. (It is an abuse of policy to include both kd- and
|
||||||
|
// bd-tree routines in the same file, sorry. There should be no problem
|
||||||
|
// in deleting the bd- versions of the routines if they are not
|
||||||
|
// desired.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree declarations
|
||||||
|
#include "bd_tree.h" // bd-tree declarations
|
||||||
|
|
||||||
|
using namespace std; // make std:: available
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const int STRING_LEN = 500; // maximum string length
|
||||||
|
const double EPSILON = 1E-5; // small number for float comparison
|
||||||
|
|
||||||
|
enum ANNtreeType {KD_TREE, BD_TREE}; // tree types (used in loading)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Procedure declarations
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
static ANNkd_ptr annReadDump( // read dump file
|
||||||
|
istream &in, // input stream
|
||||||
|
ANNtreeType tree_type, // type of tree expected
|
||||||
|
ANNpointArray &the_pts, // new points (if applic)
|
||||||
|
ANNidxArray &the_pidx, // point indices (returned)
|
||||||
|
int &the_dim, // dimension (returned)
|
||||||
|
int &the_n_pts, // number of points (returned)
|
||||||
|
int &the_bkt_size, // bucket size (returned)
|
||||||
|
ANNpoint &the_bnd_box_lo, // low bounding point
|
||||||
|
ANNpoint &the_bnd_box_hi); // high bounding point
|
||||||
|
|
||||||
|
static ANNkd_ptr annReadTree( // read tree-part of dump file
|
||||||
|
istream &in, // input stream
|
||||||
|
ANNtreeType tree_type, // type of tree expected
|
||||||
|
ANNidxArray the_pidx, // point indices (modified)
|
||||||
|
int &next_idx); // next index (modified)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANN kd- and bd-tree Dump Format
|
||||||
|
// The dump file begins with a header containing the version of
|
||||||
|
// ANN, an optional section containing the points, followed by
|
||||||
|
// a description of the tree. The tree is printed in preorder.
|
||||||
|
//
|
||||||
|
// Format:
|
||||||
|
// #ANN <version number> <comments> [END_OF_LINE]
|
||||||
|
// points <dim> <n_pts> (point coordinates: this is optional)
|
||||||
|
// 0 <xxx> <xxx> ... <xxx> (point indices and coordinates)
|
||||||
|
// 1 <xxx> <xxx> ... <xxx>
|
||||||
|
// ...
|
||||||
|
// tree <dim> <n_pts> <bkt_size>
|
||||||
|
// <xxx> <xxx> ... <xxx> (lower end of bounding box)
|
||||||
|
// <xxx> <xxx> ... <xxx> (upper end of bounding box)
|
||||||
|
// If the tree is null, then a single line "null" is
|
||||||
|
// output. Otherwise the nodes of the tree are printed
|
||||||
|
// one per line in preorder. Leaves and splitting nodes
|
||||||
|
// have the following formats:
|
||||||
|
// Leaf node:
|
||||||
|
// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
|
||||||
|
// Splitting nodes:
|
||||||
|
// split <cut_dim> <cut_val> <lo_bound> <hi_bound>
|
||||||
|
//
|
||||||
|
// For bd-trees:
|
||||||
|
//
|
||||||
|
// Shrinking nodes:
|
||||||
|
// shrink <n_bnds>
|
||||||
|
// <cut_dim> <cut_val> <side>
|
||||||
|
// <cut_dim> <cut_val> <side>
|
||||||
|
// ... (repeated n_bnds times)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_tree::Dump( // dump entire tree
|
||||||
|
ANNbool with_pts, // print points as well?
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
out << "#ANN " << ANNversion << "\n";
|
||||||
|
out.precision(ANNcoordPrec); // use full precision in dumping
|
||||||
|
if (with_pts) { // print point coordinates
|
||||||
|
out << "points " << dim << " " << n_pts << "\n";
|
||||||
|
for (int i = 0; i < n_pts; i++) {
|
||||||
|
out << i << " ";
|
||||||
|
annPrintPt(pts[i], dim, out);
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "tree " // print tree elements
|
||||||
|
<< dim << " "
|
||||||
|
<< n_pts << " "
|
||||||
|
<< bkt_size << "\n";
|
||||||
|
|
||||||
|
annPrintPt(bnd_box_lo, dim, out); // print lower bound
|
||||||
|
out << "\n";
|
||||||
|
annPrintPt(bnd_box_hi, dim, out); // print upper bound
|
||||||
|
out << "\n";
|
||||||
|
|
||||||
|
if (root == NULL) // empty tree?
|
||||||
|
out << "null\n";
|
||||||
|
else {
|
||||||
|
root->dump(out); // invoke printing at root
|
||||||
|
}
|
||||||
|
out.precision(0); // restore default precision
|
||||||
|
}
|
||||||
|
|
||||||
|
void ANNkd_split::dump( // dump a splitting node
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
out << "split " << cut_dim << " " << cut_val << " ";
|
||||||
|
out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n";
|
||||||
|
|
||||||
|
child[ANN_LO]->dump(out); // print low child
|
||||||
|
child[ANN_HI]->dump(out); // print high child
|
||||||
|
}
|
||||||
|
|
||||||
|
void ANNkd_leaf::dump( // dump a leaf node
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
if (this == KD_TRIVIAL) { // canonical trivial leaf node
|
||||||
|
out << "leaf 0\n"; // leaf no points
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
out << "leaf " << n_pts;
|
||||||
|
for (int j = 0; j < n_pts; j++) {
|
||||||
|
out << " " << bkt[j];
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ANNbd_shrink::dump( // dump a shrinking node
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
out << "shrink " << n_bnds << "\n";
|
||||||
|
for (int j = 0; j < n_bnds; j++) {
|
||||||
|
out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n";
|
||||||
|
}
|
||||||
|
child[ANN_IN]->dump(out); // print in-child
|
||||||
|
child[ANN_OUT]->dump(out); // print out-child
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Load kd-tree from dump file
|
||||||
|
// This rebuilds a kd-tree which was dumped to a file. The dump
|
||||||
|
// file contains all the basic tree information according to a
|
||||||
|
// preorder traversal. We assume that the dump file also contains
|
||||||
|
// point data. (This is to guarantee the consistency of the tree.)
|
||||||
|
// If not, then an error is generated.
|
||||||
|
//
|
||||||
|
// Indirectly, this procedure allocates space for points, point
|
||||||
|
// indices, all nodes in the tree, and the bounding box for the
|
||||||
|
// tree. When the tree is destroyed, all but the points are
|
||||||
|
// deallocated.
|
||||||
|
//
|
||||||
|
// This routine calls annReadDump to do all the work.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_tree::ANNkd_tree( // build from dump file
|
||||||
|
istream &in) // input stream for dump file
|
||||||
|
{
|
||||||
|
int the_dim; // local dimension
|
||||||
|
int the_n_pts; // local number of points
|
||||||
|
int the_bkt_size; // local number of points
|
||||||
|
ANNpoint the_bnd_box_lo; // low bounding point
|
||||||
|
ANNpoint the_bnd_box_hi; // high bounding point
|
||||||
|
ANNpointArray the_pts; // point storage
|
||||||
|
ANNidxArray the_pidx; // point index storage
|
||||||
|
ANNkd_ptr the_root; // root of the tree
|
||||||
|
|
||||||
|
the_root = annReadDump( // read the dump file
|
||||||
|
in, // input stream
|
||||||
|
KD_TREE, // expecting a kd-tree
|
||||||
|
the_pts, // point array (returned)
|
||||||
|
the_pidx, // point indices (returned)
|
||||||
|
the_dim, the_n_pts, the_bkt_size, // basic tree info (returned)
|
||||||
|
the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned)
|
||||||
|
|
||||||
|
// create a skeletal tree
|
||||||
|
SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
|
||||||
|
|
||||||
|
bnd_box_lo = the_bnd_box_lo;
|
||||||
|
bnd_box_hi = the_bnd_box_hi;
|
||||||
|
|
||||||
|
root = the_root; // set the root
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNbd_tree::ANNbd_tree( // build bd-tree from dump file
|
||||||
|
istream &in) : ANNkd_tree() // input stream for dump file
|
||||||
|
{
|
||||||
|
int the_dim; // local dimension
|
||||||
|
int the_n_pts; // local number of points
|
||||||
|
int the_bkt_size; // local number of points
|
||||||
|
ANNpoint the_bnd_box_lo; // low bounding point
|
||||||
|
ANNpoint the_bnd_box_hi; // high bounding point
|
||||||
|
ANNpointArray the_pts; // point storage
|
||||||
|
ANNidxArray the_pidx; // point index storage
|
||||||
|
ANNkd_ptr the_root; // root of the tree
|
||||||
|
|
||||||
|
the_root = annReadDump( // read the dump file
|
||||||
|
in, // input stream
|
||||||
|
BD_TREE, // expecting a bd-tree
|
||||||
|
the_pts, // point array (returned)
|
||||||
|
the_pidx, // point indices (returned)
|
||||||
|
the_dim, the_n_pts, the_bkt_size, // basic tree info (returned)
|
||||||
|
the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned)
|
||||||
|
|
||||||
|
// create a skeletal tree
|
||||||
|
SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx);
|
||||||
|
bnd_box_lo = the_bnd_box_lo;
|
||||||
|
bnd_box_hi = the_bnd_box_hi;
|
||||||
|
|
||||||
|
root = the_root; // set the root
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annReadDump - read a dump file
|
||||||
|
//
|
||||||
|
// This procedure reads a dump file, constructs a kd-tree
|
||||||
|
// and returns all the essential information needed to actually
|
||||||
|
// construct the tree. Because this procedure is used for
|
||||||
|
// constructing both kd-trees and bd-trees, the second argument
|
||||||
|
// is used to indicate which type of tree we are expecting.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
static ANNkd_ptr annReadDump(
|
||||||
|
istream &in, // input stream
|
||||||
|
ANNtreeType tree_type, // type of tree expected
|
||||||
|
ANNpointArray &the_pts, // new points (returned)
|
||||||
|
ANNidxArray &the_pidx, // point indices (returned)
|
||||||
|
int &the_dim, // dimension (returned)
|
||||||
|
int &the_n_pts, // number of points (returned)
|
||||||
|
int &the_bkt_size, // bucket size (returned)
|
||||||
|
ANNpoint &the_bnd_box_lo, // low bounding point (ret'd)
|
||||||
|
ANNpoint &the_bnd_box_hi) // high bounding point (ret'd)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
char str[STRING_LEN]; // storage for string
|
||||||
|
char version[STRING_LEN]; // ANN version number
|
||||||
|
ANNkd_ptr the_root = NULL;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// Input file header
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
in >> str; // input header
|
||||||
|
if (strcmp(str, "#ANN") != 0) { // incorrect header
|
||||||
|
annError("Incorrect header for dump file", ANNabort);
|
||||||
|
}
|
||||||
|
in.getline(version, STRING_LEN); // get version (ignore)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// Input the points
|
||||||
|
// An array the_pts is allocated and points are read from
|
||||||
|
// the dump file.
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
in >> str; // get major heading
|
||||||
|
if (strcmp(str, "points") == 0) { // points section
|
||||||
|
in >> the_dim; // input dimension
|
||||||
|
in >> the_n_pts; // number of points
|
||||||
|
// allocate point storage
|
||||||
|
the_pts = annAllocPts(the_n_pts, the_dim);
|
||||||
|
for (int i = 0; i < the_n_pts; i++) { // input point coordinates
|
||||||
|
ANNidx idx; // point index
|
||||||
|
in >> idx; // input point index
|
||||||
|
if (idx < 0 || idx >= the_n_pts) {
|
||||||
|
annError("Point index is out of range", ANNabort);
|
||||||
|
}
|
||||||
|
for (j = 0; j < the_dim; j++) {
|
||||||
|
in >> the_pts[idx][j]; // read point coordinates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in >> str; // get next major heading
|
||||||
|
}
|
||||||
|
else { // no points were input
|
||||||
|
annError("Points must be supplied in the dump file", ANNabort);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// Input the tree
|
||||||
|
// After the basic header information, we invoke annReadTree
|
||||||
|
// to do all the heavy work. We create our own array of
|
||||||
|
// point indices (so we can pass them to annReadTree())
|
||||||
|
// but we do not deallocate them. They will be deallocated
|
||||||
|
// when the tree is destroyed.
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
if (strcmp(str, "tree") == 0) { // tree section
|
||||||
|
in >> the_dim; // read dimension
|
||||||
|
in >> the_n_pts; // number of points
|
||||||
|
in >> the_bkt_size; // bucket size
|
||||||
|
the_bnd_box_lo = annAllocPt(the_dim); // allocate bounding box pts
|
||||||
|
the_bnd_box_hi = annAllocPt(the_dim);
|
||||||
|
|
||||||
|
for (j = 0; j < the_dim; j++) { // read bounding box low
|
||||||
|
in >> the_bnd_box_lo[j];
|
||||||
|
}
|
||||||
|
for (j = 0; j < the_dim; j++) { // read bounding box low
|
||||||
|
in >> the_bnd_box_hi[j];
|
||||||
|
}
|
||||||
|
the_pidx = new ANNidx[the_n_pts]; // allocate point index array
|
||||||
|
int next_idx = 0; // number of indices filled
|
||||||
|
// read the tree and indices
|
||||||
|
the_root = annReadTree(in, tree_type, the_pidx, next_idx);
|
||||||
|
if (next_idx != the_n_pts) { // didn't see all the points?
|
||||||
|
annError("Didn't see as many points as expected", ANNwarn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
annError("Illegal dump format. Expecting section heading", ANNabort);
|
||||||
|
}
|
||||||
|
return the_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annReadTree - input tree and return pointer
|
||||||
|
//
|
||||||
|
// annReadTree reads in a node of the tree, makes any recursive
|
||||||
|
// calls as needed to input the children of this node (if internal).
|
||||||
|
// It returns a pointer to the node that was created. An array
|
||||||
|
// of point indices is given along with a pointer to the next
|
||||||
|
// available location in the array. As leaves are read, their
|
||||||
|
// point indices are stored here, and the point buckets point
|
||||||
|
// to the first entry in the array.
|
||||||
|
//
|
||||||
|
// Recall that these are the formats. The tree is given in
|
||||||
|
// preorder.
|
||||||
|
//
|
||||||
|
// Leaf node:
|
||||||
|
// leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]>
|
||||||
|
// Splitting nodes:
|
||||||
|
// split <cut_dim> <cut_val> <lo_bound> <hi_bound>
|
||||||
|
//
|
||||||
|
// For bd-trees:
|
||||||
|
//
|
||||||
|
// Shrinking nodes:
|
||||||
|
// shrink <n_bnds>
|
||||||
|
// <cut_dim> <cut_val> <side>
|
||||||
|
// <cut_dim> <cut_val> <side>
|
||||||
|
// ... (repeated n_bnds times)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
static ANNkd_ptr annReadTree(
|
||||||
|
istream &in, // input stream
|
||||||
|
ANNtreeType tree_type, // type of tree expected
|
||||||
|
ANNidxArray the_pidx, // point indices (modified)
|
||||||
|
int &next_idx) // next index (modified)
|
||||||
|
{
|
||||||
|
char tag[STRING_LEN]; // tag (leaf, split, shrink)
|
||||||
|
int n_pts; // number of points in leaf
|
||||||
|
int cd; // cut dimension
|
||||||
|
ANNcoord cv; // cut value
|
||||||
|
ANNcoord lb; // low bound
|
||||||
|
ANNcoord hb; // high bound
|
||||||
|
int n_bnds; // number of bounding sides
|
||||||
|
int sd; // which side
|
||||||
|
|
||||||
|
in >> tag; // input node tag
|
||||||
|
|
||||||
|
if (strcmp(tag, "null") == 0) { // null tree
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// Read a leaf
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
if (strcmp(tag, "leaf") == 0) { // leaf node
|
||||||
|
|
||||||
|
in >> n_pts; // input number of points
|
||||||
|
int old_idx = next_idx; // save next_idx
|
||||||
|
if (n_pts == 0) { // trivial leaf
|
||||||
|
return KD_TRIVIAL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < n_pts; i++) { // input point indices
|
||||||
|
in >> the_pidx[next_idx++]; // store in array of indices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ANNkd_leaf(n_pts, &the_pidx[old_idx]);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// Read a splitting node
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
else if (strcmp(tag, "split") == 0) { // splitting node
|
||||||
|
|
||||||
|
in >> cd >> cv >> lb >> hb;
|
||||||
|
|
||||||
|
// read low and high subtrees
|
||||||
|
ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx);
|
||||||
|
ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx);
|
||||||
|
// create new node and return
|
||||||
|
return new ANNkd_split(cd, cv, lb, hb, lc, hc);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// Read a shrinking node (bd-tree only)
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
else if (strcmp(tag, "shrink") == 0) { // shrinking node
|
||||||
|
if (tree_type != BD_TREE) {
|
||||||
|
annError("Shrinking node not allowed in kd-tree", ANNabort);
|
||||||
|
}
|
||||||
|
|
||||||
|
in >> n_bnds; // number of bounding sides
|
||||||
|
// allocate bounds array
|
||||||
|
ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds];
|
||||||
|
for (int i = 0; i < n_bnds; i++) {
|
||||||
|
in >> cd >> cv >> sd; // input bounding halfspace
|
||||||
|
// copy to array
|
||||||
|
bds[i] = ANNorthHalfSpace(cd, cv, sd);
|
||||||
|
}
|
||||||
|
// read inner and outer subtrees
|
||||||
|
ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx);
|
||||||
|
ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx);
|
||||||
|
// create new node and return
|
||||||
|
return new ANNbd_shrink(n_bnds, bds, ic, oc);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
annError("Illegal node type in dump file", ANNabort);
|
||||||
|
exit(0); // to keep the compiler happy
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_fix_rad_search.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Standard kd-tree fixed-radius kNN search
|
||||||
|
// Last modified: 05/03/05 (Version 1.1)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 1.1 05/03/05
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_fix_rad_search.h" // kd fixed-radius search decls
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Approximate fixed-radius k nearest neighbor search
|
||||||
|
// The squared radius is provided, and this procedure finds the
|
||||||
|
// k nearest neighbors within the radius, and returns the total
|
||||||
|
// number of points lying within the radius.
|
||||||
|
//
|
||||||
|
// The method used for searching the kd-tree is a variation of the
|
||||||
|
// nearest neighbor search used in kd_search.cpp, except that the
|
||||||
|
// radius of the search ball is known. We refer the reader to that
|
||||||
|
// file for the explanation of the recursive search procedure.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// To keep argument lists short, a number of global variables
|
||||||
|
// are maintained which are common to all the recursive calls.
|
||||||
|
// These are given below.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ANNkdFRDim; // dimension of space
|
||||||
|
ANNpoint ANNkdFRQ; // query point
|
||||||
|
ANNdist ANNkdFRSqRad; // squared radius search bound
|
||||||
|
double ANNkdFRMaxErr; // max tolerable squared error
|
||||||
|
ANNpointArray ANNkdFRPts; // the points
|
||||||
|
ANNmin_k* ANNkdFRPointMK; // set of k closest points
|
||||||
|
int ANNkdFRPtsVisited; // total points visited
|
||||||
|
int ANNkdFRPtsInRange; // number of points in the range
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annkFRSearch - fixed radius search for k nearest neighbors
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ANNkd_tree::annkFRSearch(
|
||||||
|
ANNpoint q, // the query point
|
||||||
|
ANNdist sqRad, // squared radius search bound
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor indices (returned)
|
||||||
|
ANNdistArray dd, // the approximate nearest neighbor
|
||||||
|
double eps) // the error bound
|
||||||
|
{
|
||||||
|
ANNkdFRDim = dim; // copy arguments to static equivs
|
||||||
|
ANNkdFRQ = q;
|
||||||
|
ANNkdFRSqRad = sqRad;
|
||||||
|
ANNkdFRPts = pts;
|
||||||
|
ANNkdFRPtsVisited = 0; // initialize count of points visited
|
||||||
|
ANNkdFRPtsInRange = 0; // ...and points in the range
|
||||||
|
|
||||||
|
ANNkdFRMaxErr = ANN_POW(1.0 + eps);
|
||||||
|
ANN_FLOP(2) // increment floating op count
|
||||||
|
|
||||||
|
ANNkdFRPointMK = new ANNmin_k(k); // create set for closest k points
|
||||||
|
// search starting at the root
|
||||||
|
root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
|
||||||
|
|
||||||
|
for (int i = 0; i < k; i++) { // extract the k-th closest points
|
||||||
|
if (dd != NULL)
|
||||||
|
dd[i] = ANNkdFRPointMK->ith_smallest_key(i);
|
||||||
|
if (nn_idx != NULL)
|
||||||
|
nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete ANNkdFRPointMK; // deallocate closest point set
|
||||||
|
return ANNkdFRPtsInRange; // return final point count
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_split::ann_FR_search - search a splitting node
|
||||||
|
// Note: This routine is similar in structure to the standard kNN
|
||||||
|
// search. It visits the subtree that is closer to the query point
|
||||||
|
// first. For fixed-radius search, there is no benefit in visiting
|
||||||
|
// one subtree before the other, but we maintain the same basic
|
||||||
|
// code structure for the sake of uniformity.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_split::ann_FR_search(ANNdist box_dist)
|
||||||
|
{
|
||||||
|
// check dist calc term condition
|
||||||
|
if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return;
|
||||||
|
|
||||||
|
// distance to cutting plane
|
||||||
|
ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val;
|
||||||
|
|
||||||
|
if (cut_diff < 0) { // left of cutting plane
|
||||||
|
child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first
|
||||||
|
|
||||||
|
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim];
|
||||||
|
if (box_diff < 0) // within bounds - ignore
|
||||||
|
box_diff = 0;
|
||||||
|
// distance to further box
|
||||||
|
box_dist = (ANNdist) ANN_SUM(box_dist,
|
||||||
|
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
|
||||||
|
|
||||||
|
// visit further child if in range
|
||||||
|
if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
|
||||||
|
child[ANN_HI]->ann_FR_search(box_dist);
|
||||||
|
|
||||||
|
}
|
||||||
|
else { // right of cutting plane
|
||||||
|
child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first
|
||||||
|
|
||||||
|
ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI];
|
||||||
|
if (box_diff < 0) // within bounds - ignore
|
||||||
|
box_diff = 0;
|
||||||
|
// distance to further box
|
||||||
|
box_dist = (ANNdist) ANN_SUM(box_dist,
|
||||||
|
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
|
||||||
|
|
||||||
|
// visit further child if close enough
|
||||||
|
if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad)
|
||||||
|
child[ANN_LO]->ann_FR_search(box_dist);
|
||||||
|
|
||||||
|
}
|
||||||
|
ANN_FLOP(13) // increment floating ops
|
||||||
|
ANN_SPL(1) // one more splitting node visited
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_leaf::ann_FR_search - search points in a leaf node
|
||||||
|
// Note: The unreadability of this code is the result of
|
||||||
|
// some fine tuning to replace indexing by pointer operations.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_leaf::ann_FR_search(ANNdist /*box_dist*/)
|
||||||
|
{
|
||||||
|
register ANNdist dist; // distance to data point
|
||||||
|
register ANNcoord* pp; // data coordinate pointer
|
||||||
|
register ANNcoord* qq; // query coordinate pointer
|
||||||
|
register ANNcoord t;
|
||||||
|
register int d;
|
||||||
|
|
||||||
|
for (int i = 0; i < n_pts; i++) { // check points in bucket
|
||||||
|
|
||||||
|
pp = ANNkdFRPts[bkt[i]]; // first coord of next data point
|
||||||
|
qq = ANNkdFRQ; // first coord of query point
|
||||||
|
dist = 0;
|
||||||
|
|
||||||
|
for(d = 0; d < ANNkdFRDim; d++) {
|
||||||
|
ANN_COORD(1) // one more coordinate hit
|
||||||
|
ANN_FLOP(5) // increment floating ops
|
||||||
|
|
||||||
|
t = *(qq++) - *(pp++); // compute length and adv coordinate
|
||||||
|
// exceeds dist to k-th smallest?
|
||||||
|
if( (dist = ANN_SUM(dist, ANN_POW(t))) > ANNkdFRSqRad) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d >= ANNkdFRDim && // among the k best?
|
||||||
|
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
|
||||||
|
// add it to the list
|
||||||
|
ANNkdFRPointMK->insert(dist, bkt[i]);
|
||||||
|
ANNkdFRPtsInRange++; // increment point count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANN_LEAF(1) // one more leaf node visited
|
||||||
|
ANN_PTS(n_pts) // increment points visited
|
||||||
|
ANNkdFRPtsVisited += n_pts; // increment number of points visited
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_fix_rad_search.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Standard kd-tree fixed-radius kNN search
|
||||||
|
// Last modified: 05/03/05 (Version 1.1)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 1.1 05/03/05
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_kd_fix_rad_search_H
|
||||||
|
#define ANN_kd_fix_rad_search_H
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree declarations
|
||||||
|
#include "kd_util.h" // kd-tree utilities
|
||||||
|
#include "pr_queue_k.h" // k-element priority queue
|
||||||
|
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global variables
|
||||||
|
// These are active for the life of each call to
|
||||||
|
// annRangeSearch(). They are set to save the number of
|
||||||
|
// variables that need to be passed among the various search
|
||||||
|
// procedures.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern ANNpoint ANNkdFRQ; // query point (static copy)
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,221 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_pr_search.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Priority search for kd-trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_pr_search.h" // kd priority search declarations
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Approximate nearest neighbor searching by priority search.
|
||||||
|
// The kd-tree is searched for an approximate nearest neighbor.
|
||||||
|
// The point is returned through one of the arguments, and the
|
||||||
|
// distance returned is the SQUARED distance to this point.
|
||||||
|
//
|
||||||
|
// The method used for searching the kd-tree is called priority
|
||||||
|
// search. (It is described in Arya and Mount, ``Algorithms for
|
||||||
|
// fast vector quantization,'' Proc. of DCC '93: Data Compression
|
||||||
|
// Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
|
||||||
|
// 381--390.)
|
||||||
|
//
|
||||||
|
// The cell of the kd-tree containing the query point is located,
|
||||||
|
// and cells are visited in increasing order of distance from the
|
||||||
|
// query point. This is done by placing each subtree which has
|
||||||
|
// NOT been visited in a priority queue, according to the closest
|
||||||
|
// distance of the corresponding enclosing rectangle from the
|
||||||
|
// query point. The search stops when the distance to the nearest
|
||||||
|
// remaining rectangle exceeds the distance to the nearest point
|
||||||
|
// seen by a factor of more than 1/(1+eps). (Implying that any
|
||||||
|
// point found subsequently in the search cannot be closer by more
|
||||||
|
// than this factor.)
|
||||||
|
//
|
||||||
|
// The main entry point is annkPriSearch() which sets things up and
|
||||||
|
// then call the recursive routine ann_pri_search(). This is a
|
||||||
|
// recursive routine which performs the processing for one node in
|
||||||
|
// the kd-tree. There are two versions of this virtual procedure,
|
||||||
|
// one for splitting nodes and one for leaves. When a splitting node
|
||||||
|
// is visited, we determine which child to continue the search on
|
||||||
|
// (the closer one), and insert the other child into the priority
|
||||||
|
// queue. When a leaf is visited, we compute the distances to the
|
||||||
|
// points in the buckets, and update information on the closest
|
||||||
|
// points.
|
||||||
|
//
|
||||||
|
// Some trickery is used to incrementally update the distance from
|
||||||
|
// a kd-tree rectangle to the query point. This comes about from
|
||||||
|
// the fact that which each successive split, only one component
|
||||||
|
// (along the dimension that is split) of the squared distance to
|
||||||
|
// the child rectangle is different from the squared distance to
|
||||||
|
// the parent rectangle.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// To keep argument lists short, a number of global variables
|
||||||
|
// are maintained which are common to all the recursive calls.
|
||||||
|
// These are given below.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
double ANNprEps; // the error bound
|
||||||
|
int ANNprDim; // dimension of space
|
||||||
|
ANNpoint ANNprQ; // query point
|
||||||
|
double ANNprMaxErr; // max tolerable squared error
|
||||||
|
ANNpointArray ANNprPts; // the points
|
||||||
|
ANNpr_queue *ANNprBoxPQ; // priority queue for boxes
|
||||||
|
ANNmin_k *ANNprPointMK; // set of k closest points
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annkPriSearch - priority search for k nearest neighbors
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_tree::annkPriSearch(
|
||||||
|
ANNpoint q, // query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor indices (returned)
|
||||||
|
ANNdistArray dd, // dist to near neighbors (returned)
|
||||||
|
double eps) // error bound (ignored)
|
||||||
|
{
|
||||||
|
// max tolerable squared error
|
||||||
|
ANNprMaxErr = ANN_POW(1.0 + eps);
|
||||||
|
ANN_FLOP(2) // increment floating ops
|
||||||
|
|
||||||
|
ANNprDim = dim; // copy arguments to static equivs
|
||||||
|
ANNprQ = q;
|
||||||
|
ANNprPts = pts;
|
||||||
|
ANNptsVisited = 0; // initialize count of points visited
|
||||||
|
|
||||||
|
ANNprPointMK = new ANNmin_k(k); // create set for closest k points
|
||||||
|
|
||||||
|
// distance to root box
|
||||||
|
ANNdist box_dist = annBoxDistance(q,
|
||||||
|
bnd_box_lo, bnd_box_hi, dim);
|
||||||
|
|
||||||
|
ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes
|
||||||
|
ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue
|
||||||
|
|
||||||
|
while (ANNprBoxPQ->non_empty() &&
|
||||||
|
(!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) {
|
||||||
|
ANNkd_ptr np; // next box from prior queue
|
||||||
|
|
||||||
|
PQinfo pq;
|
||||||
|
// extract closest box from queue
|
||||||
|
ANNprBoxPQ->extr_min(box_dist, pq);
|
||||||
|
np = reinterpret_cast<ANNkd_node*>(pq);
|
||||||
|
|
||||||
|
ANN_FLOP(2) // increment floating ops
|
||||||
|
if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key())
|
||||||
|
break;
|
||||||
|
|
||||||
|
np->ann_pri_search(box_dist); // search this subtree.
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < k; i++) { // extract the k-th closest points
|
||||||
|
dd[i] = ANNprPointMK->ith_smallest_key(i);
|
||||||
|
nn_idx[i] = ANNprPointMK->ith_smallest_info(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete ANNprPointMK; // deallocate closest point set
|
||||||
|
delete ANNprBoxPQ; // deallocate priority queue
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_split::ann_pri_search - search a splitting node
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_split::ann_pri_search(ANNdist box_dist)
|
||||||
|
{
|
||||||
|
ANNdist new_dist; // distance to child visited later
|
||||||
|
// distance to cutting plane
|
||||||
|
ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val;
|
||||||
|
|
||||||
|
if (cut_diff < 0) { // left of cutting plane
|
||||||
|
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim];
|
||||||
|
if (box_diff < 0) // within bounds - ignore
|
||||||
|
box_diff = 0;
|
||||||
|
// distance to further box
|
||||||
|
new_dist = (ANNdist) ANN_SUM(box_dist,
|
||||||
|
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
|
||||||
|
|
||||||
|
if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial
|
||||||
|
ANNprBoxPQ->insert(new_dist, child[ANN_HI]);
|
||||||
|
// continue with closer child
|
||||||
|
child[ANN_LO]->ann_pri_search(box_dist);
|
||||||
|
}
|
||||||
|
else { // right of cutting plane
|
||||||
|
ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI];
|
||||||
|
if (box_diff < 0) // within bounds - ignore
|
||||||
|
box_diff = 0;
|
||||||
|
// distance to further box
|
||||||
|
new_dist = (ANNdist) ANN_SUM(box_dist,
|
||||||
|
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
|
||||||
|
|
||||||
|
if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial
|
||||||
|
ANNprBoxPQ->insert(new_dist, child[ANN_LO]);
|
||||||
|
// continue with closer child
|
||||||
|
child[ANN_HI]->ann_pri_search(box_dist);
|
||||||
|
}
|
||||||
|
ANN_SPL(1) // one more splitting node visited
|
||||||
|
ANN_FLOP(8) // increment floating ops
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_leaf::ann_pri_search - search points in a leaf node
|
||||||
|
//
|
||||||
|
// This is virtually identical to the ann_search for standard search.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_leaf::ann_pri_search(ANNdist /*box_dist*/)
|
||||||
|
{
|
||||||
|
register ANNdist dist; // distance to data point
|
||||||
|
register ANNcoord* pp; // data coordinate pointer
|
||||||
|
register ANNcoord* qq; // query coordinate pointer
|
||||||
|
register ANNdist min_dist; // distance to k-th closest point
|
||||||
|
register ANNcoord t;
|
||||||
|
register int d;
|
||||||
|
|
||||||
|
min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far
|
||||||
|
|
||||||
|
for (int i = 0; i < n_pts; i++) { // check points in bucket
|
||||||
|
|
||||||
|
pp = ANNprPts[bkt[i]]; // first coord of next data point
|
||||||
|
qq = ANNprQ; // first coord of query point
|
||||||
|
dist = 0;
|
||||||
|
|
||||||
|
for(d = 0; d < ANNprDim; d++) {
|
||||||
|
ANN_COORD(1) // one more coordinate hit
|
||||||
|
ANN_FLOP(4) // increment floating ops
|
||||||
|
|
||||||
|
t = *(qq++) - *(pp++); // compute length and adv coordinate
|
||||||
|
// exceeds dist to k-th smallest?
|
||||||
|
if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d >= ANNprDim && // among the k best?
|
||||||
|
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
|
||||||
|
// add it to the list
|
||||||
|
ANNprPointMK->insert(dist, bkt[i]);
|
||||||
|
min_dist = ANNprPointMK->max_key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANN_LEAF(1) // one more leaf node visited
|
||||||
|
ANN_PTS(n_pts) // increment points visited
|
||||||
|
ANNptsVisited += n_pts; // increment number of points visited
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_pr_search.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Priority kd-tree search
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_kd_pr_search_H
|
||||||
|
#define ANN_kd_pr_search_H
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree declarations
|
||||||
|
#include "kd_util.h" // kd-tree utilities
|
||||||
|
#include "pr_queue.h" // priority queue declarations
|
||||||
|
#include "pr_queue_k.h" // k-element priority queue
|
||||||
|
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global variables
|
||||||
|
// Active for the life of each call to Appx_Near_Neigh() or
|
||||||
|
// Appx_k_Near_Neigh().
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern double ANNprEps; // the error bound
|
||||||
|
extern int ANNprDim; // dimension of space
|
||||||
|
extern ANNpoint ANNprQ; // query point
|
||||||
|
extern double ANNprMaxErr; // max tolerable squared error
|
||||||
|
extern ANNpointArray ANNprPts; // the points
|
||||||
|
extern ANNpr_queue *ANNprBoxPQ; // priority queue for boxes
|
||||||
|
extern ANNmin_k *ANNprPointMK; // set of k closest points
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,210 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_search.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Standard kd-tree search
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Changed names LO, HI to ANN_LO, ANN_HI
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_search.h" // kd-search declarations
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Approximate nearest neighbor searching by kd-tree search
|
||||||
|
// The kd-tree is searched for an approximate nearest neighbor.
|
||||||
|
// The point is returned through one of the arguments, and the
|
||||||
|
// distance returned is the squared distance to this point.
|
||||||
|
//
|
||||||
|
// The method used for searching the kd-tree is an approximate
|
||||||
|
// adaptation of the search algorithm described by Friedman,
|
||||||
|
// Bentley, and Finkel, ``An algorithm for finding best matches
|
||||||
|
// in logarithmic expected time,'' ACM Transactions on Mathematical
|
||||||
|
// Software, 3(3):209-226, 1977).
|
||||||
|
//
|
||||||
|
// The algorithm operates recursively. When first encountering a
|
||||||
|
// node of the kd-tree we first visit the child which is closest to
|
||||||
|
// the query point. On return, we decide whether we want to visit
|
||||||
|
// the other child. If the box containing the other child exceeds
|
||||||
|
// 1/(1+eps) times the current best distance, then we skip it (since
|
||||||
|
// any point found in this child cannot be closer to the query point
|
||||||
|
// by more than this factor.) Otherwise, we visit it recursively.
|
||||||
|
// The distance between a box and the query point is computed exactly
|
||||||
|
// (not approximated as is often done in kd-tree), using incremental
|
||||||
|
// distance updates, as described by Arya and Mount in ``Algorithms
|
||||||
|
// for fast vector quantization,'' Proc. of DCC '93: Data Compression
|
||||||
|
// Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993,
|
||||||
|
// 381-390.
|
||||||
|
//
|
||||||
|
// The main entry points is annkSearch() which sets things up and
|
||||||
|
// then call the recursive routine ann_search(). This is a recursive
|
||||||
|
// routine which performs the processing for one node in the kd-tree.
|
||||||
|
// There are two versions of this virtual procedure, one for splitting
|
||||||
|
// nodes and one for leaves. When a splitting node is visited, we
|
||||||
|
// determine which child to visit first (the closer one), and visit
|
||||||
|
// the other child on return. When a leaf is visited, we compute
|
||||||
|
// the distances to the points in the buckets, and update information
|
||||||
|
// on the closest points.
|
||||||
|
//
|
||||||
|
// Some trickery is used to incrementally update the distance from
|
||||||
|
// a kd-tree rectangle to the query point. This comes about from
|
||||||
|
// the fact that which each successive split, only one component
|
||||||
|
// (along the dimension that is split) of the squared distance to
|
||||||
|
// the child rectangle is different from the squared distance to
|
||||||
|
// the parent rectangle.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// To keep argument lists short, a number of global variables
|
||||||
|
// are maintained which are common to all the recursive calls.
|
||||||
|
// These are given below.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ANNkdDim; // dimension of space
|
||||||
|
ANNpoint ANNkdQ; // query point
|
||||||
|
double ANNkdMaxErr; // max tolerable squared error
|
||||||
|
ANNpointArray ANNkdPts; // the points
|
||||||
|
ANNmin_k *ANNkdPointMK; // set of k closest points
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annkSearch - search for the k nearest neighbors
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_tree::annkSearch(
|
||||||
|
ANNpoint q, // the query point
|
||||||
|
int k, // number of near neighbors to return
|
||||||
|
ANNidxArray nn_idx, // nearest neighbor indices (returned)
|
||||||
|
ANNdistArray dd, // the approximate nearest neighbor
|
||||||
|
double eps) // the error bound
|
||||||
|
{
|
||||||
|
|
||||||
|
ANNkdDim = dim; // copy arguments to static equivs
|
||||||
|
ANNkdQ = q;
|
||||||
|
ANNkdPts = pts;
|
||||||
|
ANNptsVisited = 0; // initialize count of points visited
|
||||||
|
|
||||||
|
if (k > n_pts) { // too many near neighbors?
|
||||||
|
annError("Requesting more near neighbors than data points", ANNabort);
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNkdMaxErr = ANN_POW(1.0 + eps);
|
||||||
|
ANN_FLOP(2) // increment floating op count
|
||||||
|
|
||||||
|
ANNkdPointMK = new ANNmin_k(k); // create set for closest k points
|
||||||
|
// search starting at the root
|
||||||
|
root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim));
|
||||||
|
|
||||||
|
for (int i = 0; i < k; i++) { // extract the k-th closest points
|
||||||
|
dd[i] = ANNkdPointMK->ith_smallest_key(i);
|
||||||
|
nn_idx[i] = ANNkdPointMK->ith_smallest_info(i);
|
||||||
|
}
|
||||||
|
delete ANNkdPointMK; // deallocate closest point set
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_split::ann_search - search a splitting node
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_split::ann_search(ANNdist box_dist)
|
||||||
|
{
|
||||||
|
// check dist calc term condition
|
||||||
|
if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return;
|
||||||
|
|
||||||
|
// distance to cutting plane
|
||||||
|
ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val;
|
||||||
|
|
||||||
|
if (cut_diff < 0) { // left of cutting plane
|
||||||
|
child[ANN_LO]->ann_search(box_dist);// visit closer child first
|
||||||
|
|
||||||
|
ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim];
|
||||||
|
if (box_diff < 0) // within bounds - ignore
|
||||||
|
box_diff = 0;
|
||||||
|
// distance to further box
|
||||||
|
box_dist = (ANNdist) ANN_SUM(box_dist,
|
||||||
|
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
|
||||||
|
|
||||||
|
// visit further child if close enough
|
||||||
|
if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
|
||||||
|
child[ANN_HI]->ann_search(box_dist);
|
||||||
|
|
||||||
|
}
|
||||||
|
else { // right of cutting plane
|
||||||
|
child[ANN_HI]->ann_search(box_dist);// visit closer child first
|
||||||
|
|
||||||
|
ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI];
|
||||||
|
if (box_diff < 0) // within bounds - ignore
|
||||||
|
box_diff = 0;
|
||||||
|
// distance to further box
|
||||||
|
box_dist = (ANNdist) ANN_SUM(box_dist,
|
||||||
|
ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff)));
|
||||||
|
|
||||||
|
// visit further child if close enough
|
||||||
|
if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key())
|
||||||
|
child[ANN_LO]->ann_search(box_dist);
|
||||||
|
|
||||||
|
}
|
||||||
|
ANN_FLOP(10) // increment floating ops
|
||||||
|
ANN_SPL(1) // one more splitting node visited
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_leaf::ann_search - search points in a leaf node
|
||||||
|
// Note: The unreadability of this code is the result of
|
||||||
|
// some fine tuning to replace indexing by pointer operations.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_leaf::ann_search(ANNdist /*box_dist*/)
|
||||||
|
{
|
||||||
|
register ANNdist dist; // distance to data point
|
||||||
|
register ANNcoord* pp; // data coordinate pointer
|
||||||
|
register ANNcoord* qq; // query coordinate pointer
|
||||||
|
register ANNdist min_dist; // distance to k-th closest point
|
||||||
|
register ANNcoord t;
|
||||||
|
register int d;
|
||||||
|
|
||||||
|
min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far
|
||||||
|
|
||||||
|
for (int i = 0; i < n_pts; i++) { // check points in bucket
|
||||||
|
|
||||||
|
pp = ANNkdPts[bkt[i]]; // first coord of next data point
|
||||||
|
qq = ANNkdQ; // first coord of query point
|
||||||
|
dist = 0;
|
||||||
|
|
||||||
|
for(d = 0; d < ANNkdDim; d++) {
|
||||||
|
ANN_COORD(1) // one more coordinate hit
|
||||||
|
ANN_FLOP(4) // increment floating ops
|
||||||
|
|
||||||
|
t = *(qq++) - *(pp++); // compute length and adv coordinate
|
||||||
|
// exceeds dist to k-th smallest?
|
||||||
|
if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d >= ANNkdDim && // among the k best?
|
||||||
|
(ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem
|
||||||
|
// add it to the list
|
||||||
|
ANNkdPointMK->insert(dist, bkt[i]);
|
||||||
|
min_dist = ANNkdPointMK->max_key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANN_LEAF(1) // one more leaf node visited
|
||||||
|
ANN_PTS(n_pts) // increment points visited
|
||||||
|
ANNptsVisited += n_pts; // increment number of points visited
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_search.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Standard kd-tree search
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_kd_search_H
|
||||||
|
#define ANN_kd_search_H
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree declarations
|
||||||
|
#include "kd_util.h" // kd-tree utilities
|
||||||
|
#include "pr_queue_k.h" // k-element priority queue
|
||||||
|
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// More global variables
|
||||||
|
// These are active for the life of each call to annkSearch(). They
|
||||||
|
// are set to save the number of variables that need to be passed
|
||||||
|
// among the various search procedures.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern int ANNkdDim; // dimension of space (static copy)
|
||||||
|
extern ANNpoint ANNkdQ; // query point (static copy)
|
||||||
|
extern double ANNkdMaxErr; // max tolerable squared error
|
||||||
|
extern ANNpointArray ANNkdPts; // the points (static copy)
|
||||||
|
extern ANNmin_k *ANNkdPointMK; // set of k closest points
|
||||||
|
extern int ANNptsVisited; // number of points visited
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,428 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_split.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Methods for splitting kd-trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree definitions
|
||||||
|
#include "kd_util.h" // kd-tree utilities
|
||||||
|
#include "kd_split.h" // splitting functions
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const double ERR = 0.001; // a small value
|
||||||
|
const double FS_ASPECT_RATIO = 3.0; // maximum allowed aspect ratio
|
||||||
|
// in fair split. Must be >= 2.
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_split - Bentley's standard splitting routine for kd-trees
|
||||||
|
// Find the dimension of the greatest spread, and split
|
||||||
|
// just before the median point along this dimension.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void kd_split(
|
||||||
|
ANNpointArray pa, // point array (permuted on return)
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
const ANNorthRect &/*bnds*/, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo) // num of points on low side (returned)
|
||||||
|
{
|
||||||
|
// find dimension of maximum spread
|
||||||
|
cut_dim = annMaxSpread(pa, pidx, n, dim);
|
||||||
|
n_lo = n/2; // median rank
|
||||||
|
// split about median
|
||||||
|
annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// midpt_split - midpoint splitting rule for box-decomposition trees
|
||||||
|
//
|
||||||
|
// This is the simplest splitting rule that guarantees boxes
|
||||||
|
// of bounded aspect ratio. It simply cuts the box with the
|
||||||
|
// longest side through its midpoint. If there are ties, it
|
||||||
|
// selects the dimension with the maximum point spread.
|
||||||
|
//
|
||||||
|
// WARNING: This routine (while simple) doesn't seem to work
|
||||||
|
// well in practice in high dimensions, because it tends to
|
||||||
|
// generate a large number of trivial and/or unbalanced splits.
|
||||||
|
// Either kd_split(), sl_midpt_split(), or fair_split() are
|
||||||
|
// recommended, instead.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void midpt_split(
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo) // num of points on low side (returned)
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
|
||||||
|
ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
|
||||||
|
for (d = 1; d < dim; d++) { // find length of longest box side
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (length > max_length) {
|
||||||
|
max_length = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANNcoord max_spread = -1; // find long side with most spread
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
// is it among longest?
|
||||||
|
if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
|
||||||
|
// compute its spread
|
||||||
|
ANNcoord spr = annSpread(pa, pidx, n, d);
|
||||||
|
if (spr > max_spread) { // is it max so far?
|
||||||
|
max_spread = spr;
|
||||||
|
cut_dim = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// split along cut_dim at midpoint
|
||||||
|
cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2;
|
||||||
|
// permute points accordingly
|
||||||
|
int br1, br2;
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// On return: pa[0..br1-1] < cut_val
|
||||||
|
// pa[br1..br2-1] == cut_val
|
||||||
|
// pa[br2..n-1] > cut_val
|
||||||
|
//
|
||||||
|
// We can set n_lo to any value in the range [br1..br2].
|
||||||
|
// We choose split so that points are most evenly divided.
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
if (br1 > n/2) n_lo = br1;
|
||||||
|
else if (br2 < n/2) n_lo = br2;
|
||||||
|
else n_lo = n/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// sl_midpt_split - sliding midpoint splitting rule
|
||||||
|
//
|
||||||
|
// This is a modification of midpt_split, which has the nonsensical
|
||||||
|
// name "sliding midpoint". The idea is that we try to use the
|
||||||
|
// midpoint rule, by bisecting the longest side. If there are
|
||||||
|
// ties, the dimension with the maximum spread is selected. If,
|
||||||
|
// however, the midpoint split produces a trivial split (no points
|
||||||
|
// on one side of the splitting plane) then we slide the splitting
|
||||||
|
// (maintaining its orientation) until it produces a nontrivial
|
||||||
|
// split. For example, if the splitting plane is along the x-axis,
|
||||||
|
// and all the data points have x-coordinate less than the x-bisector,
|
||||||
|
// then the split is taken along the maximum x-coordinate of the
|
||||||
|
// data points.
|
||||||
|
//
|
||||||
|
// Intuitively, this rule cannot generate trivial splits, and
|
||||||
|
// hence avoids midpt_split's tendency to produce trees with
|
||||||
|
// a very large number of nodes.
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void sl_midpt_split(
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo) // num of points on low side (returned)
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
|
||||||
|
ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
|
||||||
|
for (d = 1; d < dim; d++) { // find length of longest box side
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (length > max_length) {
|
||||||
|
max_length = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANNcoord max_spread = -1; // find long side with most spread
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
// is it among longest?
|
||||||
|
if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) {
|
||||||
|
// compute its spread
|
||||||
|
ANNcoord spr = annSpread(pa, pidx, n, d);
|
||||||
|
if (spr > max_spread) { // is it max so far?
|
||||||
|
max_spread = spr;
|
||||||
|
cut_dim = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ideal split at midpoint
|
||||||
|
ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2;
|
||||||
|
|
||||||
|
ANNcoord min, max;
|
||||||
|
annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates
|
||||||
|
|
||||||
|
if (ideal_cut_val < min) // slide to min or max as needed
|
||||||
|
cut_val = min;
|
||||||
|
else if (ideal_cut_val > max)
|
||||||
|
cut_val = max;
|
||||||
|
else
|
||||||
|
cut_val = ideal_cut_val;
|
||||||
|
|
||||||
|
// permute points accordingly
|
||||||
|
int br1, br2;
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
// On return: pa[0..br1-1] < cut_val
|
||||||
|
// pa[br1..br2-1] == cut_val
|
||||||
|
// pa[br2..n-1] > cut_val
|
||||||
|
//
|
||||||
|
// We can set n_lo to any value in the range [br1..br2] to satisfy
|
||||||
|
// the exit conditions of the procedure.
|
||||||
|
//
|
||||||
|
// if ideal_cut_val < min (implying br2 >= 1),
|
||||||
|
// then we select n_lo = 1 (so there is one point on left) and
|
||||||
|
// if ideal_cut_val > max (implying br1 <= n-1),
|
||||||
|
// then we select n_lo = n-1 (so there is one point on right).
|
||||||
|
// Otherwise, we select n_lo as close to n/2 as possible within
|
||||||
|
// [br1..br2].
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
if (ideal_cut_val < min) n_lo = 1;
|
||||||
|
else if (ideal_cut_val > max) n_lo = n-1;
|
||||||
|
else if (br1 > n/2) n_lo = br1;
|
||||||
|
else if (br2 < n/2) n_lo = br2;
|
||||||
|
else n_lo = n/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// fair_split - fair-split splitting rule
|
||||||
|
//
|
||||||
|
// This is a compromise between the kd-tree splitting rule (which
|
||||||
|
// always splits data points at their median) and the midpoint
|
||||||
|
// splitting rule (which always splits a box through its center.
|
||||||
|
// The goal of this procedure is to achieve both nicely balanced
|
||||||
|
// splits, and boxes of bounded aspect ratio.
|
||||||
|
//
|
||||||
|
// A constant FS_ASPECT_RATIO is defined. Given a box, those sides
|
||||||
|
// which can be split so that the ratio of the longest to shortest
|
||||||
|
// side does not exceed ASPECT_RATIO are identified. Among these
|
||||||
|
// sides, we select the one in which the points have the largest
|
||||||
|
// spread. We then split the points in a manner which most evenly
|
||||||
|
// distributes the points on either side of the splitting plane,
|
||||||
|
// subject to maintaining the bound on the ratio of long to short
|
||||||
|
// sides. To determine that the aspect ratio will be preserved,
|
||||||
|
// we determine the longest side (other than this side), and
|
||||||
|
// determine how narrowly we can cut this side, without causing the
|
||||||
|
// aspect ratio bound to be exceeded (small_piece).
|
||||||
|
//
|
||||||
|
// This procedure is more robust than either kd_split or midpt_split,
|
||||||
|
// but is more complicated as well. When point distribution is
|
||||||
|
// extremely skewed, this degenerates to midpt_split (actually
|
||||||
|
// 1/3 point split), and when the points are most evenly distributed,
|
||||||
|
// this degenerates to kd-split.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void fair_split(
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo) // num of points on low side (returned)
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
|
||||||
|
cut_dim = 0;
|
||||||
|
for (d = 1; d < dim; d++) { // find length of longest box side
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (length > max_length) {
|
||||||
|
max_length = length;
|
||||||
|
cut_dim = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNcoord max_spread = 0; // find legal cut with max spread
|
||||||
|
cut_dim = 0;
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
// is this side midpoint splitable
|
||||||
|
// without violating aspect ratio?
|
||||||
|
if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
|
||||||
|
// compute spread along this dim
|
||||||
|
ANNcoord spr = annSpread(pa, pidx, n, d);
|
||||||
|
if (spr > max_spread) { // best spread so far
|
||||||
|
max_spread = spr;
|
||||||
|
cut_dim = d; // this is dimension to cut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max_length = 0; // find longest side other than cut_dim
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (d != cut_dim && length > max_length)
|
||||||
|
max_length = length;
|
||||||
|
}
|
||||||
|
// consider most extreme splits
|
||||||
|
ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
|
||||||
|
ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
|
||||||
|
ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
|
||||||
|
|
||||||
|
int br1, br2;
|
||||||
|
// is median below lo_cut ?
|
||||||
|
if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
|
||||||
|
cut_val = lo_cut; // cut at lo_cut
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
n_lo = br1;
|
||||||
|
}
|
||||||
|
// is median above hi_cut?
|
||||||
|
else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
|
||||||
|
cut_val = hi_cut; // cut at hi_cut
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
n_lo = br2;
|
||||||
|
}
|
||||||
|
else { // median cut preserves asp ratio
|
||||||
|
n_lo = n/2; // split about median
|
||||||
|
annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// sl_fair_split - sliding fair split splitting rule
|
||||||
|
//
|
||||||
|
// Sliding fair split is a splitting rule that combines the
|
||||||
|
// strengths of both fair split with sliding midpoint split.
|
||||||
|
// Fair split tends to produce balanced splits when the points
|
||||||
|
// are roughly uniformly distributed, but it can produce many
|
||||||
|
// trivial splits when points are highly clustered. Sliding
|
||||||
|
// midpoint never produces trivial splits, and shrinks boxes
|
||||||
|
// nicely if points are highly clustered, but it may produce
|
||||||
|
// rather unbalanced splits when points are unclustered but not
|
||||||
|
// quite uniform.
|
||||||
|
//
|
||||||
|
// Sliding fair split is based on the theory that there are two
|
||||||
|
// types of splits that are "good": balanced splits that produce
|
||||||
|
// fat boxes, and unbalanced splits provided the cell with fewer
|
||||||
|
// points is fat.
|
||||||
|
//
|
||||||
|
// This splitting rule operates by first computing the longest
|
||||||
|
// side of the current bounding box. Then it asks which sides
|
||||||
|
// could be split (at the midpoint) and still satisfy the aspect
|
||||||
|
// ratio bound with respect to this side. Among these, it selects
|
||||||
|
// the side with the largest spread (as fair split would). It
|
||||||
|
// then considers the most extreme cuts that would be allowed by
|
||||||
|
// the aspect ratio bound. This is done by dividing the longest
|
||||||
|
// side of the box by the aspect ratio bound. If the median cut
|
||||||
|
// lies between these extreme cuts, then we use the median cut.
|
||||||
|
// If not, then consider the extreme cut that is closer to the
|
||||||
|
// median. If all the points lie to one side of this cut, then
|
||||||
|
// we slide the cut until it hits the first point. This may
|
||||||
|
// violate the aspect ratio bound, but will never generate empty
|
||||||
|
// cells. However the sibling of every such skinny cell is fat,
|
||||||
|
// and hence packing arguments still apply.
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void sl_fair_split(
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo) // num of points on low side (returned)
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
ANNcoord min, max; // min/max coordinates
|
||||||
|
int br1, br2; // split break points
|
||||||
|
|
||||||
|
ANNcoord max_length = bnds.hi[0] - bnds.lo[0];
|
||||||
|
cut_dim = 0;
|
||||||
|
for (d = 1; d < dim; d++) { // find length of longest box side
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (length > max_length) {
|
||||||
|
max_length = length;
|
||||||
|
cut_dim = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNcoord max_spread = 0; // find legal cut with max spread
|
||||||
|
cut_dim = 0;
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
// is this side midpoint splitable
|
||||||
|
// without violating aspect ratio?
|
||||||
|
if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) {
|
||||||
|
// compute spread along this dim
|
||||||
|
ANNcoord spr = annSpread(pa, pidx, n, d);
|
||||||
|
if (spr > max_spread) { // best spread so far
|
||||||
|
max_spread = spr;
|
||||||
|
cut_dim = d; // this is dimension to cut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max_length = 0; // find longest side other than cut_dim
|
||||||
|
for (d = 0; d < dim; d++) {
|
||||||
|
ANNcoord length = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (d != cut_dim && length > max_length)
|
||||||
|
max_length = length;
|
||||||
|
}
|
||||||
|
// consider most extreme splits
|
||||||
|
ANNcoord small_piece = max_length / FS_ASPECT_RATIO;
|
||||||
|
ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut
|
||||||
|
ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut
|
||||||
|
// find min and max along cut_dim
|
||||||
|
annMinMax(pa, pidx, n, cut_dim, min, max);
|
||||||
|
// is median below lo_cut?
|
||||||
|
if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) {
|
||||||
|
if (max > lo_cut) { // are any points above lo_cut?
|
||||||
|
cut_val = lo_cut; // cut at lo_cut
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
n_lo = br1; // balance if there are ties
|
||||||
|
}
|
||||||
|
else { // all points below lo_cut
|
||||||
|
cut_val = max; // cut at max value
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
n_lo = n-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// is median above hi_cut?
|
||||||
|
else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) {
|
||||||
|
if (min < hi_cut) { // are any points below hi_cut?
|
||||||
|
cut_val = hi_cut; // cut at hi_cut
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
n_lo = br2; // balance if there are ties
|
||||||
|
}
|
||||||
|
else { // all points above hi_cut
|
||||||
|
cut_val = min; // cut at min value
|
||||||
|
annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2);
|
||||||
|
n_lo = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // median cut is good enough
|
||||||
|
n_lo = n/2; // split about median
|
||||||
|
annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_split.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Methods for splitting kd-trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_KD_SPLIT_H
|
||||||
|
#define ANN_KD_SPLIT_H
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree definitions
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// External entry points
|
||||||
|
// These are all splitting procedures for kd-trees.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void kd_split( // standard (optimized) kd-splitter
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo); // num of points on low side (returned)
|
||||||
|
|
||||||
|
void midpt_split( // midpoint kd-splitter
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo); // num of points on low side (returned)
|
||||||
|
|
||||||
|
void sl_midpt_split( // sliding midpoint kd-splitter
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo); // num of points on low side (returned)
|
||||||
|
|
||||||
|
void fair_split( // fair-split kd-splitter
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo); // num of points on low side (returned)
|
||||||
|
|
||||||
|
void sl_fair_split( // sliding fair-split kd-splitter
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo); // num of points on low side (returned)
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,405 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_tree.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Basic methods for kd-trees.
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Increased aspect ratio bound (ANN_AR_TOOBIG) from 100 to 1000.
|
||||||
|
// Fixed leaf counts to count trivial leaves.
|
||||||
|
// Added optional pa, pi arguments to Skeleton kd_tree constructor
|
||||||
|
// for use in load constructor.
|
||||||
|
// Added annClose() to eliminate KD_TRIVIAL memory leak.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree declarations
|
||||||
|
#include "kd_split.h" // kd-tree splitting rules
|
||||||
|
#include "kd_util.h" // kd-tree utilities
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global data
|
||||||
|
//
|
||||||
|
// For some splitting rules, especially with small bucket sizes,
|
||||||
|
// it is possible to generate a large number of empty leaf nodes.
|
||||||
|
// To save storage we allocate a single trivial leaf node which
|
||||||
|
// contains no points. For messy coding reasons it is convenient
|
||||||
|
// to have it reference a trivial point index.
|
||||||
|
//
|
||||||
|
// KD_TRIVIAL is allocated when the first kd-tree is created. It
|
||||||
|
// must *never* deallocated (since it may be shared by more than
|
||||||
|
// one tree).
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
static int IDX_TRIVIAL[] = {0}; // trivial point index
|
||||||
|
ANNkd_leaf *KD_TRIVIAL = NULL; // trivial leaf node
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Printing the kd-tree
|
||||||
|
// These routines print a kd-tree in reverse inorder (high then
|
||||||
|
// root then low). (This is so that if you look at the output
|
||||||
|
// from the right side it appear from left to right in standard
|
||||||
|
// inorder.) When outputting leaves we output only the point
|
||||||
|
// indices rather than the point coordinates. There is an option
|
||||||
|
// to print the point coordinates separately.
|
||||||
|
//
|
||||||
|
// The tree printing routine calls the printing routines on the
|
||||||
|
// individual nodes of the tree, passing in the level or depth
|
||||||
|
// in the tree. The level in the tree is used to print indentation
|
||||||
|
// for readability.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_split::print( // print splitting node
|
||||||
|
int level, // depth of node in tree
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
child[ANN_HI]->print(level+1, out); // print high child
|
||||||
|
out << " ";
|
||||||
|
for (int i = 0; i < level; i++) // print indentation
|
||||||
|
out << "..";
|
||||||
|
out << "Split cd=" << cut_dim << " cv=" << cut_val;
|
||||||
|
out << " lbnd=" << cd_bnds[ANN_LO];
|
||||||
|
out << " hbnd=" << cd_bnds[ANN_HI];
|
||||||
|
out << "\n";
|
||||||
|
child[ANN_LO]->print(level+1, out); // print low child
|
||||||
|
}
|
||||||
|
|
||||||
|
void ANNkd_leaf::print( // print leaf node
|
||||||
|
int level, // depth of node in tree
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
|
||||||
|
out << " ";
|
||||||
|
for (int i = 0; i < level; i++) // print indentation
|
||||||
|
out << "..";
|
||||||
|
|
||||||
|
if (this == KD_TRIVIAL) { // canonical trivial leaf node
|
||||||
|
out << "Leaf (trivial)\n";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
out << "Leaf n=" << n_pts << " <";
|
||||||
|
for (int j = 0; j < n_pts; j++) {
|
||||||
|
out << bkt[j];
|
||||||
|
if (j < n_pts-1) out << ",";
|
||||||
|
}
|
||||||
|
out << ">\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ANNkd_tree::Print( // print entire tree
|
||||||
|
ANNbool with_pts, // print points as well?
|
||||||
|
ostream &out) // output stream
|
||||||
|
{
|
||||||
|
out << "ANN Version " << ANNversion << "\n";
|
||||||
|
if (with_pts) { // print point coordinates
|
||||||
|
out << " Points:\n";
|
||||||
|
for (int i = 0; i < n_pts; i++) {
|
||||||
|
out << "\t" << i << ": ";
|
||||||
|
annPrintPt(pts[i], dim, out);
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (root == NULL) // empty tree?
|
||||||
|
out << " Null tree.\n";
|
||||||
|
else {
|
||||||
|
root->print(0, out); // invoke printing at root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_tree statistics (for performance evaluation)
|
||||||
|
// This routine compute various statistics information for
|
||||||
|
// a kd-tree. It is used by the implementors for performance
|
||||||
|
// evaluation of the data structure.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
void ANNkdStats::merge(const ANNkdStats &st) // merge stats from child
|
||||||
|
{
|
||||||
|
n_lf += st.n_lf; n_tl += st.n_tl;
|
||||||
|
n_spl += st.n_spl; n_shr += st.n_shr;
|
||||||
|
depth = MAX(depth, st.depth);
|
||||||
|
sum_ar += st.sum_ar;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Update statistics for nodes
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const double ANN_AR_TOOBIG = 1000; // too big an aspect ratio
|
||||||
|
|
||||||
|
void ANNkd_leaf::getStats( // get subtree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // stats (modified)
|
||||||
|
ANNorthRect &bnd_box) // bounding box
|
||||||
|
{
|
||||||
|
st.reset();
|
||||||
|
st.n_lf = 1; // count this leaf
|
||||||
|
if (this == KD_TRIVIAL) st.n_tl = 1; // count trivial leaf
|
||||||
|
double ar = annAspectRatio(dim, bnd_box); // aspect ratio of leaf
|
||||||
|
// incr sum (ignore outliers)
|
||||||
|
st.sum_ar += float(ar < ANN_AR_TOOBIG ? ar : ANN_AR_TOOBIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ANNkd_split::getStats( // get subtree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // stats (modified)
|
||||||
|
ANNorthRect &bnd_box) // bounding box
|
||||||
|
{
|
||||||
|
ANNkdStats ch_stats; // stats for children
|
||||||
|
// get stats for low child
|
||||||
|
ANNcoord hv = bnd_box.hi[cut_dim]; // save box bounds
|
||||||
|
bnd_box.hi[cut_dim] = cut_val; // upper bound for low child
|
||||||
|
ch_stats.reset(); // reset
|
||||||
|
child[ANN_LO]->getStats(dim, ch_stats, bnd_box);
|
||||||
|
st.merge(ch_stats); // merge them
|
||||||
|
bnd_box.hi[cut_dim] = hv; // restore bound
|
||||||
|
// get stats for high child
|
||||||
|
ANNcoord lv = bnd_box.lo[cut_dim]; // save box bounds
|
||||||
|
bnd_box.lo[cut_dim] = cut_val; // lower bound for high child
|
||||||
|
ch_stats.reset(); // reset
|
||||||
|
child[ANN_HI]->getStats(dim, ch_stats, bnd_box);
|
||||||
|
st.merge(ch_stats); // merge them
|
||||||
|
bnd_box.lo[cut_dim] = lv; // restore bound
|
||||||
|
|
||||||
|
st.depth++; // increment depth
|
||||||
|
st.n_spl++; // increment number of splits
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// getStats
|
||||||
|
// Collects a number of statistics related to kd_tree or
|
||||||
|
// bd_tree.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_tree::getStats( // get tree statistics
|
||||||
|
ANNkdStats &st) // stats (modified)
|
||||||
|
{
|
||||||
|
st.reset(dim, n_pts, bkt_size); // reset stats
|
||||||
|
// create bounding box
|
||||||
|
ANNorthRect bnd_box(dim, bnd_box_lo, bnd_box_hi);
|
||||||
|
if (root != NULL) { // if nonempty tree
|
||||||
|
root->getStats(dim, st, bnd_box); // get statistics
|
||||||
|
st.avg_ar = st.sum_ar / st.n_lf; // average leaf asp ratio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_tree destructor
|
||||||
|
// The destructor just frees the various elements that were
|
||||||
|
// allocated in the construction process.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_tree::~ANNkd_tree() // tree destructor
|
||||||
|
{
|
||||||
|
if (root != NULL) delete root;
|
||||||
|
if (pidx != NULL) delete [] pidx;
|
||||||
|
if (bnd_box_lo != NULL) annDeallocPt(bnd_box_lo);
|
||||||
|
if (bnd_box_hi != NULL) annDeallocPt(bnd_box_hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This is called with all use of ANN is finished. It eliminates the
|
||||||
|
// minor memory leak caused by the allocation of KD_TRIVIAL.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
void annClose() // close use of ANN
|
||||||
|
{
|
||||||
|
if (KD_TRIVIAL != NULL) {
|
||||||
|
delete KD_TRIVIAL;
|
||||||
|
KD_TRIVIAL = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd_tree constructors
|
||||||
|
// There is a skeleton kd-tree constructor which sets up a
|
||||||
|
// trivial empty tree. The last optional argument allows
|
||||||
|
// the routine to be passed a point index array which is
|
||||||
|
// assumed to be of the proper size (n). Otherwise, one is
|
||||||
|
// allocated and initialized to the identity. Warning: In
|
||||||
|
// either case the destructor will deallocate this array.
|
||||||
|
//
|
||||||
|
// As a kludge, we need to allocate KD_TRIVIAL if one has not
|
||||||
|
// already been allocated. (This is because I'm too dumb to
|
||||||
|
// figure out how to cause a pointer to be allocated at load
|
||||||
|
// time.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ANNkd_tree::SkeletonTree( // construct skeleton tree
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs, // bucket size
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pi) // point indices
|
||||||
|
{
|
||||||
|
dim = dd; // initialize basic elements
|
||||||
|
n_pts = n;
|
||||||
|
bkt_size = bs;
|
||||||
|
pts = pa; // initialize points array
|
||||||
|
|
||||||
|
root = NULL; // no associated tree yet
|
||||||
|
|
||||||
|
if (pi == NULL) { // point indices provided?
|
||||||
|
pidx = new ANNidx[n]; // no, allocate space for point indices
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
pidx[i] = i; // initially identity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pidx = pi; // yes, use them
|
||||||
|
}
|
||||||
|
|
||||||
|
bnd_box_lo = bnd_box_hi = NULL; // bounding box is nonexistent
|
||||||
|
if (KD_TRIVIAL == NULL) // no trivial leaf node yet?
|
||||||
|
KD_TRIVIAL = new ANNkd_leaf(0, IDX_TRIVIAL); // allocate it
|
||||||
|
}
|
||||||
|
|
||||||
|
ANNkd_tree::ANNkd_tree( // basic constructor
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs) // bucket size
|
||||||
|
{ SkeletonTree(n, dd, bs); } // construct skeleton tree
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// rkd_tree - recursive procedure to build a kd-tree
|
||||||
|
//
|
||||||
|
// Builds a kd-tree for points in pa as indexed through the
|
||||||
|
// array pidx[0..n-1] (typically a subarray of the array used in
|
||||||
|
// the top-level call). This routine permutes the array pidx,
|
||||||
|
// but does not alter pa[].
|
||||||
|
//
|
||||||
|
// The construction is based on a standard algorithm for constructing
|
||||||
|
// the kd-tree (see Friedman, Bentley, and Finkel, ``An algorithm for
|
||||||
|
// finding best matches in logarithmic expected time,'' ACM Transactions
|
||||||
|
// on Mathematical Software, 3(3):209-226, 1977). The procedure
|
||||||
|
// operates by a simple divide-and-conquer strategy, which determines
|
||||||
|
// an appropriate orthogonal cutting plane (see below), and splits
|
||||||
|
// the points. When the number of points falls below the bucket size,
|
||||||
|
// we simply store the points in a leaf node's bucket.
|
||||||
|
//
|
||||||
|
// One of the arguments is a pointer to a splitting routine,
|
||||||
|
// whose prototype is:
|
||||||
|
//
|
||||||
|
// void split(
|
||||||
|
// ANNpointArray pa, // complete point array
|
||||||
|
// ANNidxArray pidx, // point array (permuted on return)
|
||||||
|
// ANNorthRect &bnds, // bounds of current cell
|
||||||
|
// int n, // number of points
|
||||||
|
// int dim, // dimension of space
|
||||||
|
// int &cut_dim, // cutting dimension
|
||||||
|
// ANNcoord &cut_val, // cutting value
|
||||||
|
// int &n_lo) // no. of points on low side of cut
|
||||||
|
//
|
||||||
|
// This procedure selects a cutting dimension and cutting value,
|
||||||
|
// partitions pa about these values, and returns the number of
|
||||||
|
// points on the low side of the cut.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_ptr rkd_tree( // recursive construction of kd-tree
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int bsp, // bucket space
|
||||||
|
ANNorthRect &bnd_box, // bounding box for current node
|
||||||
|
ANNkd_splitter splitter) // splitting routine
|
||||||
|
{
|
||||||
|
if (n <= bsp) { // n small, make a leaf node
|
||||||
|
if (n == 0) // empty leaf node
|
||||||
|
return KD_TRIVIAL; // return (canonical) empty leaf
|
||||||
|
else // construct the node and return
|
||||||
|
return new ANNkd_leaf(n, pidx);
|
||||||
|
}
|
||||||
|
else { // n large, make a splitting node
|
||||||
|
int cd; // cutting dimension
|
||||||
|
ANNcoord cv; // cutting value
|
||||||
|
int n_lo; // number on low side of cut
|
||||||
|
ANNkd_node *lo, *hi; // low and high children
|
||||||
|
|
||||||
|
// invoke splitting procedure
|
||||||
|
(*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo);
|
||||||
|
|
||||||
|
ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension
|
||||||
|
ANNcoord hv = bnd_box.hi[cd];
|
||||||
|
|
||||||
|
bnd_box.hi[cd] = cv; // modify bounds for left subtree
|
||||||
|
lo = rkd_tree( // build left subtree
|
||||||
|
pa, pidx, n_lo, // ...from pidx[0..n_lo-1]
|
||||||
|
dim, bsp, bnd_box, splitter);
|
||||||
|
bnd_box.hi[cd] = hv; // restore bounds
|
||||||
|
|
||||||
|
bnd_box.lo[cd] = cv; // modify bounds for right subtree
|
||||||
|
hi = rkd_tree( // build right subtree
|
||||||
|
pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1]
|
||||||
|
dim, bsp, bnd_box, splitter);
|
||||||
|
bnd_box.lo[cd] = lv; // restore bounds
|
||||||
|
|
||||||
|
// create the splitting node
|
||||||
|
ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi);
|
||||||
|
|
||||||
|
return ptr; // return pointer to this node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd-tree constructor
|
||||||
|
// This is the main constructor for kd-trees given a set of points.
|
||||||
|
// It first builds a skeleton tree, then computes the bounding box
|
||||||
|
// of the data points, and then invokes rkd_tree() to actually
|
||||||
|
// build the tree, passing it the appropriate splitting routine.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_tree::ANNkd_tree( // construct from point array
|
||||||
|
ANNpointArray pa, // point array (with at least n pts)
|
||||||
|
int n, // number of points
|
||||||
|
int dd, // dimension
|
||||||
|
int bs, // bucket size
|
||||||
|
ANNsplitRule split) // splitting method
|
||||||
|
{
|
||||||
|
SkeletonTree(n, dd, bs); // set up the basic stuff
|
||||||
|
pts = pa; // where the points are
|
||||||
|
if (n == 0) return; // no points--no sweat
|
||||||
|
|
||||||
|
ANNorthRect bnd_box(dd); // bounding box for points
|
||||||
|
annEnclRect(pa, pidx, n, dd, bnd_box);// construct bounding rectangle
|
||||||
|
// copy to tree structure
|
||||||
|
bnd_box_lo = annCopyPt(dd, bnd_box.lo);
|
||||||
|
bnd_box_hi = annCopyPt(dd, bnd_box.hi);
|
||||||
|
|
||||||
|
switch (split) { // build by rule
|
||||||
|
case ANN_KD_STD: // standard kd-splitting rule
|
||||||
|
root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split);
|
||||||
|
break;
|
||||||
|
case ANN_KD_MIDPT: // midpoint split
|
||||||
|
root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split);
|
||||||
|
break;
|
||||||
|
case ANN_KD_FAIR: // fair split
|
||||||
|
root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split);
|
||||||
|
break;
|
||||||
|
case ANN_KD_SUGGEST: // best (in our opinion)
|
||||||
|
case ANN_KD_SL_MIDPT: // sliding midpoint split
|
||||||
|
root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split);
|
||||||
|
break;
|
||||||
|
case ANN_KD_SL_FAIR: // sliding fair split
|
||||||
|
root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
annError("Illegal splitting method", ANNabort);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_tree.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Declarations for standard kd-tree routines
|
||||||
|
// Last modified: 05/03/05 (Version 1.1)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.1 05/03/05
|
||||||
|
// Added fixed radius kNN search
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_kd_tree_H
|
||||||
|
#define ANN_kd_tree_H
|
||||||
|
|
||||||
|
#include <ann/ANNx.h> // all ANN includes
|
||||||
|
|
||||||
|
using namespace std; // make std:: available
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Generic kd-tree node
|
||||||
|
//
|
||||||
|
// Nodes in kd-trees are of two types, splitting nodes which contain
|
||||||
|
// splitting information (a splitting hyperplane orthogonal to one
|
||||||
|
// of the coordinate axes) and leaf nodes which contain point
|
||||||
|
// information (an array of points stored in a bucket). This is
|
||||||
|
// handled by making a generic class kd_node, which is essentially an
|
||||||
|
// empty shell, and then deriving the leaf and splitting nodes from
|
||||||
|
// this.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNkd_node{ // generic kd-tree node (empty shell)
|
||||||
|
public:
|
||||||
|
virtual ~ANNkd_node() {} // virtual distroyer
|
||||||
|
|
||||||
|
virtual void ann_search(ANNdist) = 0; // tree search
|
||||||
|
virtual void ann_pri_search(ANNdist) = 0; // priority search
|
||||||
|
virtual void ann_FR_search(ANNdist) = 0; // fixed-radius search
|
||||||
|
|
||||||
|
virtual void getStats( // get tree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // statistics
|
||||||
|
ANNorthRect &bnd_box) = 0; // bounding box
|
||||||
|
// print node
|
||||||
|
virtual void print(int level, ostream &out) = 0;
|
||||||
|
virtual void dump(ostream &out) = 0; // dump node
|
||||||
|
|
||||||
|
friend class ANNkd_tree; // allow kd-tree to access us
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd-splitting function:
|
||||||
|
// kd_splitter is a pointer to a splitting routine for preprocessing.
|
||||||
|
// Different splitting procedures result in different strategies
|
||||||
|
// for building the tree.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef void (*ANNkd_splitter)( // splitting routine for kd-trees
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices (permuted on return)
|
||||||
|
const ANNorthRect &bnds, // bounding rectangle for cell
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &cut_dim, // cutting dimension (returned)
|
||||||
|
ANNcoord &cut_val, // cutting value (returned)
|
||||||
|
int &n_lo); // num of points on low side (returned)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Leaf kd-tree node
|
||||||
|
// Leaf nodes of the kd-tree store the set of points associated
|
||||||
|
// with this bucket, stored as an array of point indices. These
|
||||||
|
// are indices in the array points, which resides with the
|
||||||
|
// root of the kd-tree. We also store the number of points
|
||||||
|
// that reside in this bucket.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNkd_leaf: public ANNkd_node // leaf node for kd-tree
|
||||||
|
{
|
||||||
|
int n_pts; // no. points in bucket
|
||||||
|
ANNidxArray bkt; // bucket of points
|
||||||
|
public:
|
||||||
|
ANNkd_leaf( // constructor
|
||||||
|
int n, // number of points
|
||||||
|
ANNidxArray b) // bucket
|
||||||
|
{
|
||||||
|
n_pts = n; // number of points in bucket
|
||||||
|
bkt = b; // the bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
~ANNkd_leaf() { } // destructor (none)
|
||||||
|
|
||||||
|
virtual void getStats( // get tree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // statistics
|
||||||
|
ANNorthRect &bnd_box); // bounding box
|
||||||
|
virtual void print(int level, ostream &out);// print node
|
||||||
|
virtual void dump(ostream &out); // dump node
|
||||||
|
|
||||||
|
virtual void ann_search(ANNdist); // standard search
|
||||||
|
virtual void ann_pri_search(ANNdist); // priority search
|
||||||
|
virtual void ann_FR_search(ANNdist); // fixed-radius search
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// KD_TRIVIAL is a special pointer to an empty leaf node. Since
|
||||||
|
// some splitting rules generate many (more than 50%) trivial
|
||||||
|
// leaves, we use this one shared node to save space.
|
||||||
|
//
|
||||||
|
// The pointer is initialized to NULL, but whenever a kd-tree is
|
||||||
|
// created, we allocate this node, if it has not already been
|
||||||
|
// allocated. This node is *never* deallocated, so it produces
|
||||||
|
// a small memory leak.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern ANNkd_leaf *KD_TRIVIAL; // trivial (empty) leaf node
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// kd-tree splitting node.
|
||||||
|
// Splitting nodes contain a cutting dimension and a cutting value.
|
||||||
|
// These indicate the axis-parellel plane which subdivide the
|
||||||
|
// box for this node. The extent of the bounding box along the
|
||||||
|
// cutting dimension is maintained (this is used to speed up point
|
||||||
|
// to box distance calculations) [we do not store the entire bounding
|
||||||
|
// box since this may be wasteful of space in high dimensions].
|
||||||
|
// We also store pointers to the 2 children.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNkd_split : public ANNkd_node // splitting node of a kd-tree
|
||||||
|
{
|
||||||
|
int cut_dim; // dim orthogonal to cutting plane
|
||||||
|
ANNcoord cut_val; // location of cutting plane
|
||||||
|
ANNcoord cd_bnds[2]; // lower and upper bounds of
|
||||||
|
// rectangle along cut_dim
|
||||||
|
ANNkd_ptr child[2]; // left and right children
|
||||||
|
public:
|
||||||
|
ANNkd_split( // constructor
|
||||||
|
int cd, // cutting dimension
|
||||||
|
ANNcoord cv, // cutting value
|
||||||
|
ANNcoord lv, ANNcoord hv, // low and high values
|
||||||
|
ANNkd_ptr lc=NULL, ANNkd_ptr hc=NULL) // children
|
||||||
|
{
|
||||||
|
cut_dim = cd; // cutting dimension
|
||||||
|
cut_val = cv; // cutting value
|
||||||
|
cd_bnds[ANN_LO] = lv; // lower bound for rectangle
|
||||||
|
cd_bnds[ANN_HI] = hv; // upper bound for rectangle
|
||||||
|
child[ANN_LO] = lc; // left child
|
||||||
|
child[ANN_HI] = hc; // right child
|
||||||
|
}
|
||||||
|
|
||||||
|
~ANNkd_split() // destructor
|
||||||
|
{
|
||||||
|
if (child[ANN_LO]!= NULL && child[ANN_LO]!= KD_TRIVIAL)
|
||||||
|
delete child[ANN_LO];
|
||||||
|
if (child[ANN_HI]!= NULL && child[ANN_HI]!= KD_TRIVIAL)
|
||||||
|
delete child[ANN_HI];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void getStats( // get tree statistics
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNkdStats &st, // statistics
|
||||||
|
ANNorthRect &bnd_box); // bounding box
|
||||||
|
virtual void print(int level, ostream &out);// print node
|
||||||
|
virtual void dump(ostream &out); // dump node
|
||||||
|
|
||||||
|
virtual void ann_search(ANNdist); // standard search
|
||||||
|
virtual void ann_pri_search(ANNdist); // priority search
|
||||||
|
virtual void ann_FR_search(ANNdist); // fixed-radius search
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// External entry points
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNkd_ptr rkd_tree( // recursive construction of kd-tree
|
||||||
|
ANNpointArray pa, // point array (unaltered)
|
||||||
|
ANNidxArray pidx, // point indices to store in subtree
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
int bsp, // bucket space
|
||||||
|
ANNorthRect &bnd_box, // bounding box for current node
|
||||||
|
ANNkd_splitter splitter); // splitting routine
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,439 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_util.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Common utilities for kd-trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "kd_util.h" // kd-utility declarations
|
||||||
|
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// The following routines are utility functions for manipulating
|
||||||
|
// points sets, used in determining splitting planes for kd-tree
|
||||||
|
// construction.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// NOTE: Virtually all point indexing is done through an index (i.e.
|
||||||
|
// permutation) array pidx. Consequently, a reference to the d-th
|
||||||
|
// coordinate of the i-th point is pa[pidx[i]][d]. The macro PA(i,d)
|
||||||
|
// is a shorthand for this.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// standard 2-d indirect indexing
|
||||||
|
#define PA(i,d) (pa[pidx[(i)]][(d)])
|
||||||
|
// accessing a single point
|
||||||
|
#define PP(i) (pa[pidx[(i)]])
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annAspectRatio
|
||||||
|
// Compute the aspect ratio (ratio of longest to shortest side)
|
||||||
|
// of a rectangle.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
double annAspectRatio(
|
||||||
|
int dim, // dimension
|
||||||
|
const ANNorthRect &bnd_box) // bounding cube
|
||||||
|
{
|
||||||
|
ANNcoord length = bnd_box.hi[0] - bnd_box.lo[0];
|
||||||
|
ANNcoord min_length = length; // min side length
|
||||||
|
ANNcoord max_length = length; // max side length
|
||||||
|
for (int d = 0; d < dim; d++) {
|
||||||
|
length = bnd_box.hi[d] - bnd_box.lo[d];
|
||||||
|
if (length < min_length) min_length = length;
|
||||||
|
if (length > max_length) max_length = length;
|
||||||
|
}
|
||||||
|
return max_length/min_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annEnclRect, annEnclCube
|
||||||
|
// These utilities compute the smallest rectangle and cube enclosing
|
||||||
|
// a set of points, respectively.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annEnclRect(
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension
|
||||||
|
ANNorthRect &bnds) // bounding cube (returned)
|
||||||
|
{
|
||||||
|
for (int d = 0; d < dim; d++) { // find smallest enclosing rectangle
|
||||||
|
ANNcoord lo_bnd = PA(0,d); // lower bound on dimension d
|
||||||
|
ANNcoord hi_bnd = PA(0,d); // upper bound on dimension d
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (PA(i,d) < lo_bnd) lo_bnd = PA(i,d);
|
||||||
|
else if (PA(i,d) > hi_bnd) hi_bnd = PA(i,d);
|
||||||
|
}
|
||||||
|
bnds.lo[d] = lo_bnd;
|
||||||
|
bnds.hi[d] = hi_bnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void annEnclCube( // compute smallest enclosing cube
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension
|
||||||
|
ANNorthRect &bnds) // bounding cube (returned)
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
// compute smallest enclosing rect
|
||||||
|
annEnclRect(pa, pidx, n, dim, bnds);
|
||||||
|
|
||||||
|
ANNcoord max_len = 0; // max length of any side
|
||||||
|
for (d = 0; d < dim; d++) { // determine max side length
|
||||||
|
ANNcoord len = bnds.hi[d] - bnds.lo[d];
|
||||||
|
if (len > max_len) { // update max_len if longest
|
||||||
|
max_len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (d = 0; d < dim; d++) { // grow sides to match max
|
||||||
|
ANNcoord len = bnds.hi[d] - bnds.lo[d];
|
||||||
|
ANNcoord half_diff = (max_len - len) / 2;
|
||||||
|
bnds.lo[d] -= half_diff;
|
||||||
|
bnds.hi[d] += half_diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annBoxDistance - utility routine which computes distance from point to
|
||||||
|
// box (Note: most distances to boxes are computed using incremental
|
||||||
|
// distance updates, not this function.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNdist annBoxDistance( // compute distance from point to box
|
||||||
|
const ANNpoint q, // the point
|
||||||
|
const ANNpoint lo, // low point of box
|
||||||
|
const ANNpoint hi, // high point of box
|
||||||
|
int dim) // dimension of space
|
||||||
|
{
|
||||||
|
register ANNdist dist = 0.0; // sum of squared distances
|
||||||
|
register ANNdist t;
|
||||||
|
|
||||||
|
for (register int d = 0; d < dim; d++) {
|
||||||
|
if (q[d] < lo[d]) { // q is left of box
|
||||||
|
t = ANNdist(lo[d]) - ANNdist(q[d]);
|
||||||
|
dist = ANN_SUM(dist, ANN_POW(t));
|
||||||
|
}
|
||||||
|
else if (q[d] > hi[d]) { // q is right of box
|
||||||
|
t = ANNdist(q[d]) - ANNdist(hi[d]);
|
||||||
|
dist = ANN_SUM(dist, ANN_POW(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ANN_FLOP(4*dim) // increment floating op count
|
||||||
|
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annSpread - find spread along given dimension
|
||||||
|
// annMinMax - find min and max coordinates along given dimension
|
||||||
|
// annMaxSpread - find dimension of max spread
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
ANNcoord annSpread( // compute point spread along dimension
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d) // dimension to check
|
||||||
|
{
|
||||||
|
ANNcoord min = PA(0,d); // compute max and min coords
|
||||||
|
ANNcoord max = PA(0,d);
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
ANNcoord c = PA(i,d);
|
||||||
|
if (c < min) min = c;
|
||||||
|
else if (c > max) max = c;
|
||||||
|
}
|
||||||
|
return (max - min); // total spread is difference
|
||||||
|
}
|
||||||
|
|
||||||
|
void annMinMax( // compute min and max coordinates along dim
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension to check
|
||||||
|
ANNcoord &min, // minimum value (returned)
|
||||||
|
ANNcoord &max) // maximum value (returned)
|
||||||
|
{
|
||||||
|
min = PA(0,d); // compute max and min coords
|
||||||
|
max = PA(0,d);
|
||||||
|
for (int i = 1; i < n; i++) {
|
||||||
|
ANNcoord c = PA(i,d);
|
||||||
|
if (c < min) min = c;
|
||||||
|
else if (c > max) max = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int annMaxSpread( // compute dimension of max spread
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim) // dimension of space
|
||||||
|
{
|
||||||
|
int max_dim = 0; // dimension of max spread
|
||||||
|
ANNcoord max_spr = 0; // amount of max spread
|
||||||
|
|
||||||
|
if (n == 0) return max_dim; // no points, who cares?
|
||||||
|
|
||||||
|
for (int d = 0; d < dim; d++) { // compute spread along each dim
|
||||||
|
ANNcoord spr = annSpread(pa, pidx, n, d);
|
||||||
|
if (spr > max_spr) { // bigger than current max
|
||||||
|
max_spr = spr;
|
||||||
|
max_dim = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annMedianSplit - split point array about its median
|
||||||
|
// Splits a subarray of points pa[0..n] about an element of given
|
||||||
|
// rank (median: n_lo = n/2) with respect to dimension d. It places
|
||||||
|
// the element of rank n_lo-1 correctly (because our splitting rule
|
||||||
|
// takes the mean of these two). On exit, the array is permuted so
|
||||||
|
// that:
|
||||||
|
//
|
||||||
|
// pa[0..n_lo-2][d] <= pa[n_lo-1][d] <= pa[n_lo][d] <= pa[n_lo+1..n-1][d].
|
||||||
|
//
|
||||||
|
// The mean of pa[n_lo-1][d] and pa[n_lo][d] is returned as the
|
||||||
|
// splitting value.
|
||||||
|
//
|
||||||
|
// All indexing is done indirectly through the index array pidx.
|
||||||
|
//
|
||||||
|
// This function uses the well known selection algorithm due to
|
||||||
|
// C.A.R. Hoare.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// swap two points in pa array
|
||||||
|
#define PASWAP(a,b) { int tmp = pidx[a]; pidx[a] = pidx[b]; pidx[b] = tmp; }
|
||||||
|
|
||||||
|
void annMedianSplit(
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension along which to split
|
||||||
|
ANNcoord &cv, // cutting value
|
||||||
|
int n_lo) // split into n_lo and n-n_lo
|
||||||
|
{
|
||||||
|
int l = 0; // left end of current subarray
|
||||||
|
int r = n-1; // right end of current subarray
|
||||||
|
while (l < r) {
|
||||||
|
register int i = (r+l)/2; // select middle as pivot
|
||||||
|
register int k;
|
||||||
|
|
||||||
|
if (PA(i,d) > PA(r,d)) // make sure last > pivot
|
||||||
|
PASWAP(i,r)
|
||||||
|
PASWAP(l,i); // move pivot to first position
|
||||||
|
|
||||||
|
ANNcoord c = PA(l,d); // pivot value
|
||||||
|
i = l;
|
||||||
|
k = r;
|
||||||
|
for(;;) { // pivot about c
|
||||||
|
while (PA(++i,d) < c) ;
|
||||||
|
while (PA(--k,d) > c) ;
|
||||||
|
if (i < k) PASWAP(i,k) else break;
|
||||||
|
}
|
||||||
|
PASWAP(l,k); // pivot winds up in location k
|
||||||
|
|
||||||
|
if (k > n_lo) r = k-1; // recurse on proper subarray
|
||||||
|
else if (k < n_lo) l = k+1;
|
||||||
|
else break; // got the median exactly
|
||||||
|
}
|
||||||
|
if (n_lo > 0) { // search for next smaller item
|
||||||
|
ANNcoord c = PA(0,d); // candidate for max
|
||||||
|
int k = 0; // candidate's index
|
||||||
|
for (int i = 1; i < n_lo; i++) {
|
||||||
|
if (PA(i,d) > c) {
|
||||||
|
c = PA(i,d);
|
||||||
|
k = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PASWAP(n_lo-1, k); // max among pa[0..n_lo-1] to pa[n_lo-1]
|
||||||
|
}
|
||||||
|
// cut value is midpoint value
|
||||||
|
cv = (PA(n_lo-1,d) + PA(n_lo,d))/2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annPlaneSplit - split point array about a cutting plane
|
||||||
|
// Split the points in an array about a given plane along a
|
||||||
|
// given cutting dimension. On exit, br1 and br2 are set so
|
||||||
|
// that:
|
||||||
|
//
|
||||||
|
// pa[ 0 ..br1-1] < cv
|
||||||
|
// pa[br1..br2-1] == cv
|
||||||
|
// pa[br2.. n -1] > cv
|
||||||
|
//
|
||||||
|
// All indexing is done indirectly through the index array pidx.
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annPlaneSplit( // split points by a plane
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension along which to split
|
||||||
|
ANNcoord cv, // cutting value
|
||||||
|
int &br1, // first break (values < cv)
|
||||||
|
int &br2) // second break (values == cv)
|
||||||
|
{
|
||||||
|
int l = 0;
|
||||||
|
int r = n-1;
|
||||||
|
for(;;) { // partition pa[0..n-1] about cv
|
||||||
|
while (l < n && PA(l,d) < cv) l++;
|
||||||
|
while (r >= 0 && PA(r,d) >= cv) r--;
|
||||||
|
if (l > r) break;
|
||||||
|
PASWAP(l,r);
|
||||||
|
l++; r--;
|
||||||
|
}
|
||||||
|
br1 = l; // now: pa[0..br1-1] < cv <= pa[br1..n-1]
|
||||||
|
r = n-1;
|
||||||
|
for(;;) { // partition pa[br1..n-1] about cv
|
||||||
|
while (l < n && PA(l,d) <= cv) l++;
|
||||||
|
while (r >= br1 && PA(r,d) > cv) r--;
|
||||||
|
if (l > r) break;
|
||||||
|
PASWAP(l,r);
|
||||||
|
l++; r--;
|
||||||
|
}
|
||||||
|
br2 = l; // now: pa[br1..br2-1] == cv < pa[br2..n-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annBoxSplit - split point array about a orthogonal rectangle
|
||||||
|
// Split the points in an array about a given orthogonal
|
||||||
|
// rectangle. On exit, n_in is set to the number of points
|
||||||
|
// that are inside (or on the boundary of) the rectangle.
|
||||||
|
//
|
||||||
|
// All indexing is done indirectly through the index array pidx.
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annBoxSplit( // split points by a box
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNorthRect &box, // the box
|
||||||
|
int &n_in) // number of points inside (returned)
|
||||||
|
{
|
||||||
|
int l = 0;
|
||||||
|
int r = n-1;
|
||||||
|
for(;;) { // partition pa[0..n-1] about box
|
||||||
|
while (l < n && box.inside(dim, PP(l))) l++;
|
||||||
|
while (r >= 0 && !box.inside(dim, PP(r))) r--;
|
||||||
|
if (l > r) break;
|
||||||
|
PASWAP(l,r);
|
||||||
|
l++; r--;
|
||||||
|
}
|
||||||
|
n_in = l; // now: pa[0..n_in-1] inside and rest outside
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annSplitBalance - compute balance factor for a given plane split
|
||||||
|
// Balance factor is defined as the number of points lying
|
||||||
|
// below the splitting value minus n/2 (median). Thus, a
|
||||||
|
// median split has balance 0, left of this is negative and
|
||||||
|
// right of this is positive. (The points are unchanged.)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
int annSplitBalance( // determine balance factor of a split
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension along which to split
|
||||||
|
ANNcoord cv) // cutting value
|
||||||
|
{
|
||||||
|
int n_lo = 0;
|
||||||
|
for(int i = 0; i < n; i++) { // count number less than cv
|
||||||
|
if (PA(i,d) < cv) n_lo++;
|
||||||
|
}
|
||||||
|
return n_lo - n/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annBox2Bnds - convert bounding box to list of bounds
|
||||||
|
// Given two boxes, an inner box enclosed within a bounding
|
||||||
|
// box, this routine determines all the sides for which the
|
||||||
|
// inner box is strictly contained with the bounding box,
|
||||||
|
// and adds an appropriate entry to a list of bounds. Then
|
||||||
|
// we allocate storage for the final list of bounds, and return
|
||||||
|
// the resulting list and its size.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annBox2Bnds( // convert inner box to bounds
|
||||||
|
const ANNorthRect &inner_box, // inner box
|
||||||
|
const ANNorthRect &bnd_box, // enclosing box
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &n_bnds, // number of bounds (returned)
|
||||||
|
ANNorthHSArray &bnds) // bounds array (returned)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
n_bnds = 0; // count number of bounds
|
||||||
|
for (i = 0; i < dim; i++) {
|
||||||
|
if (inner_box.lo[i] > bnd_box.lo[i]) // low bound is inside
|
||||||
|
n_bnds++;
|
||||||
|
if (inner_box.hi[i] < bnd_box.hi[i]) // high bound is inside
|
||||||
|
n_bnds++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bnds = new ANNorthHalfSpace[n_bnds]; // allocate appropriate size
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (i = 0; i < dim; i++) { // fill the array
|
||||||
|
if (inner_box.lo[i] > bnd_box.lo[i]) {
|
||||||
|
bnds[j].cd = i;
|
||||||
|
bnds[j].cv = inner_box.lo[i];
|
||||||
|
bnds[j].sd = +1;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (inner_box.hi[i] < bnd_box.hi[i]) {
|
||||||
|
bnds[j].cd = i;
|
||||||
|
bnds[j].cv = inner_box.hi[i];
|
||||||
|
bnds[j].sd = -1;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// annBnds2Box - convert list of bounds to bounding box
|
||||||
|
// Given an enclosing box and a list of bounds, this routine
|
||||||
|
// computes the corresponding inner box. It is assumed that
|
||||||
|
// the box points have been allocated already.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
void annBnds2Box(
|
||||||
|
const ANNorthRect &bnd_box, // enclosing box
|
||||||
|
int dim, // dimension of space
|
||||||
|
int n_bnds, // number of bounds
|
||||||
|
ANNorthHSArray bnds, // bounds array
|
||||||
|
ANNorthRect &inner_box) // inner box (returned)
|
||||||
|
{
|
||||||
|
annAssignRect(dim, inner_box, bnd_box); // copy bounding box to inner
|
||||||
|
|
||||||
|
for (int i = 0; i < n_bnds; i++) {
|
||||||
|
bnds[i].project(inner_box.lo); // project each endpoint
|
||||||
|
bnds[i].project(inner_box.hi);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: kd_util.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Common utilities for kd- trees
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef ANN_kd_util_H
|
||||||
|
#define ANN_kd_util_H
|
||||||
|
|
||||||
|
#include "kd_tree.h" // kd-tree declarations
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// externally accessible functions
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
double annAspectRatio( // compute aspect ratio of box
|
||||||
|
int dim, // dimension
|
||||||
|
const ANNorthRect &bnd_box); // bounding cube
|
||||||
|
|
||||||
|
void annEnclRect( // compute smallest enclosing rectangle
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension
|
||||||
|
ANNorthRect &bnds); // bounding cube (returned)
|
||||||
|
|
||||||
|
void annEnclCube( // compute smallest enclosing cube
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension
|
||||||
|
ANNorthRect &bnds); // bounding cube (returned)
|
||||||
|
|
||||||
|
ANNdist annBoxDistance( // compute distance from point to box
|
||||||
|
const ANNpoint q, // the point
|
||||||
|
const ANNpoint lo, // low point of box
|
||||||
|
const ANNpoint hi, // high point of box
|
||||||
|
int dim); // dimension of space
|
||||||
|
|
||||||
|
ANNcoord annSpread( // compute point spread along dimension
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d); // dimension to check
|
||||||
|
|
||||||
|
void annMinMax( // compute min and max coordinates along dim
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension to check
|
||||||
|
ANNcoord& min, // minimum value (returned)
|
||||||
|
ANNcoord& max); // maximum value (returned)
|
||||||
|
|
||||||
|
int annMaxSpread( // compute dimension of max spread
|
||||||
|
ANNpointArray pa, // point array
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim); // dimension of space
|
||||||
|
|
||||||
|
void annMedianSplit( // split points along median value
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension along which to split
|
||||||
|
ANNcoord &cv, // cutting value
|
||||||
|
int n_lo); // split into n_lo and n-n_lo
|
||||||
|
|
||||||
|
void annPlaneSplit( // split points by a plane
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension along which to split
|
||||||
|
ANNcoord cv, // cutting value
|
||||||
|
int &br1, // first break (values < cv)
|
||||||
|
int &br2); // second break (values == cv)
|
||||||
|
|
||||||
|
void annBoxSplit( // split points by a box
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int dim, // dimension of space
|
||||||
|
ANNorthRect &box, // the box
|
||||||
|
int &n_in); // number of points inside (returned)
|
||||||
|
|
||||||
|
int annSplitBalance( // determine balance factor of a split
|
||||||
|
ANNpointArray pa, // points to split
|
||||||
|
ANNidxArray pidx, // point indices
|
||||||
|
int n, // number of points
|
||||||
|
int d, // dimension along which to split
|
||||||
|
ANNcoord cv); // cutting value
|
||||||
|
|
||||||
|
void annBox2Bnds( // convert inner box to bounds
|
||||||
|
const ANNorthRect &inner_box, // inner box
|
||||||
|
const ANNorthRect &bnd_box, // enclosing box
|
||||||
|
int dim, // dimension of space
|
||||||
|
int &n_bnds, // number of bounds (returned)
|
||||||
|
ANNorthHSArray &bnds); // bounds array (returned)
|
||||||
|
|
||||||
|
void annBnds2Box( // convert bounds to inner box
|
||||||
|
const ANNorthRect &bnd_box, // enclosing box
|
||||||
|
int dim, // dimension of space
|
||||||
|
int n_bnds, // number of bounds
|
||||||
|
ANNorthHSArray bnds, // bounds array
|
||||||
|
ANNorthRect &inner_box); // inner box (returned)
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,136 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: perf.cpp
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Methods for performance stats
|
||||||
|
// Last modified: 01/27/10 (Version 1.1.2)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2010 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
// Revision 1.0 04/01/05
|
||||||
|
// Changed names to avoid namespace conflicts.
|
||||||
|
// Added flush after printing performance stats to fix bug
|
||||||
|
// in Microsoft Windows version.
|
||||||
|
// Revision 1.1.2 01/27/10
|
||||||
|
// Fixed minor compilation bugs for new versions of gcc
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <ann/ANN.h> // basic ANN includes
|
||||||
|
#include <ann/ANNperf.h> // performance includes
|
||||||
|
|
||||||
|
using namespace std; // make std:: available
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Performance statistics
|
||||||
|
// The following data and routines are used for computing
|
||||||
|
// performance statistics for nearest neighbor searching.
|
||||||
|
// Because these routines can slow the code down, they can be
|
||||||
|
// activated and deactiviated by defining the PERF variable,
|
||||||
|
// by compiling with the option: -DPERF
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Global counters for performance measurement
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
int ann_Ndata_pts = 0; // number of data points
|
||||||
|
int ann_Nvisit_lfs = 0; // number of leaf nodes visited
|
||||||
|
int ann_Nvisit_spl = 0; // number of splitting nodes visited
|
||||||
|
int ann_Nvisit_shr = 0; // number of shrinking nodes visited
|
||||||
|
int ann_Nvisit_pts = 0; // visited points for one query
|
||||||
|
int ann_Ncoord_hts = 0; // coordinate hits for one query
|
||||||
|
int ann_Nfloat_ops = 0; // floating ops for one query
|
||||||
|
ANNsampStat ann_visit_lfs; // stats on leaf nodes visits
|
||||||
|
ANNsampStat ann_visit_spl; // stats on splitting nodes visits
|
||||||
|
ANNsampStat ann_visit_shr; // stats on shrinking nodes visits
|
||||||
|
ANNsampStat ann_visit_nds; // stats on total nodes visits
|
||||||
|
ANNsampStat ann_visit_pts; // stats on points visited
|
||||||
|
ANNsampStat ann_coord_hts; // stats on coordinate hits
|
||||||
|
ANNsampStat ann_float_ops; // stats on floating ops
|
||||||
|
//
|
||||||
|
ANNsampStat ann_average_err; // average error
|
||||||
|
ANNsampStat ann_rank_err; // rank error
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Routines for statistics.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
DLL_API void annResetStats(int data_size) // reset stats for a set of queries
|
||||||
|
{
|
||||||
|
ann_Ndata_pts = data_size;
|
||||||
|
ann_visit_lfs.reset();
|
||||||
|
ann_visit_spl.reset();
|
||||||
|
ann_visit_shr.reset();
|
||||||
|
ann_visit_nds.reset();
|
||||||
|
ann_visit_pts.reset();
|
||||||
|
ann_coord_hts.reset();
|
||||||
|
ann_float_ops.reset();
|
||||||
|
ann_average_err.reset();
|
||||||
|
ann_rank_err.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL_API void annResetCounts() // reset counts for one query
|
||||||
|
{
|
||||||
|
ann_Nvisit_lfs = 0;
|
||||||
|
ann_Nvisit_spl = 0;
|
||||||
|
ann_Nvisit_shr = 0;
|
||||||
|
ann_Nvisit_pts = 0;
|
||||||
|
ann_Ncoord_hts = 0;
|
||||||
|
ann_Nfloat_ops = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL_API void annUpdateStats() // update stats with current counts
|
||||||
|
{
|
||||||
|
ann_visit_lfs += ann_Nvisit_lfs;
|
||||||
|
ann_visit_nds += ann_Nvisit_spl + ann_Nvisit_lfs;
|
||||||
|
ann_visit_spl += ann_Nvisit_spl;
|
||||||
|
ann_visit_shr += ann_Nvisit_shr;
|
||||||
|
ann_visit_pts += ann_Nvisit_pts;
|
||||||
|
ann_coord_hts += ann_Ncoord_hts;
|
||||||
|
ann_float_ops += ann_Nfloat_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print a single statistic
|
||||||
|
void print_one_stat(const char* title, ANNsampStat s, double div)
|
||||||
|
{
|
||||||
|
cout << title << "= [ ";
|
||||||
|
cout.width(9); cout << s.mean()/div << " : ";
|
||||||
|
cout.width(9); cout << s.stdDev()/div << " ]<";
|
||||||
|
cout.width(9); cout << s.min()/div << " , ";
|
||||||
|
cout.width(9); cout << s.max()/div << " >\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL_API void annPrintStats( // print statistics for a run
|
||||||
|
ANNbool validate) // true if average errors desired
|
||||||
|
{
|
||||||
|
cout.precision(4); // set floating precision
|
||||||
|
cout << " (Performance stats: "
|
||||||
|
<< " [ mean : stddev ]< min , max >\n";
|
||||||
|
print_one_stat(" leaf_nodes ", ann_visit_lfs, 1);
|
||||||
|
print_one_stat(" splitting_nodes ", ann_visit_spl, 1);
|
||||||
|
print_one_stat(" shrinking_nodes ", ann_visit_shr, 1);
|
||||||
|
print_one_stat(" total_nodes ", ann_visit_nds, 1);
|
||||||
|
print_one_stat(" points_visited ", ann_visit_pts, 1);
|
||||||
|
print_one_stat(" coord_hits/pt ", ann_coord_hts, ann_Ndata_pts);
|
||||||
|
print_one_stat(" floating_ops_(K) ", ann_float_ops, 1000);
|
||||||
|
if (validate) {
|
||||||
|
print_one_stat(" average_error ", ann_average_err, 1);
|
||||||
|
print_one_stat(" rank_error ", ann_rank_err, 1);
|
||||||
|
}
|
||||||
|
cout.precision(0); // restore the default
|
||||||
|
cout << " )\n";
|
||||||
|
cout.flush();
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: pr_queue.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Include file for priority queue and related
|
||||||
|
// structures.
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef PR_QUEUE_H
|
||||||
|
#define PR_QUEUE_H
|
||||||
|
|
||||||
|
#include <ann/ANNx.h> // all ANN includes
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Basic types.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
typedef void *PQinfo; // info field is generic pointer
|
||||||
|
typedef ANNdist PQkey; // key field is distance
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Priority queue
|
||||||
|
// A priority queue is a list of items, along with associated
|
||||||
|
// priorities. The basic operations are insert and extract_minimum.
|
||||||
|
//
|
||||||
|
// The priority queue is maintained using a standard binary heap.
|
||||||
|
// (Implementation note: Indexing is performed from [1..max] rather
|
||||||
|
// than the C standard of [0..max-1]. This simplifies parent/child
|
||||||
|
// computations.) User information consists of a void pointer,
|
||||||
|
// and the user is responsible for casting this quantity into whatever
|
||||||
|
// useful form is desired.
|
||||||
|
//
|
||||||
|
// Because the priority queue is so central to the efficiency of
|
||||||
|
// query processing, all the code is inline.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNpr_queue {
|
||||||
|
|
||||||
|
struct pq_node { // node in priority queue
|
||||||
|
PQkey key; // key value
|
||||||
|
PQinfo info; // info field
|
||||||
|
};
|
||||||
|
int n; // number of items in queue
|
||||||
|
int max_size; // maximum queue size
|
||||||
|
pq_node *pq; // the priority queue (array of nodes)
|
||||||
|
|
||||||
|
public:
|
||||||
|
ANNpr_queue(int max) // constructor (given max size)
|
||||||
|
{
|
||||||
|
n = 0; // initially empty
|
||||||
|
max_size = max; // maximum number of items
|
||||||
|
pq = new pq_node[max+1]; // queue is array [1..max] of nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
~ANNpr_queue() // destructor
|
||||||
|
{ delete [] pq; }
|
||||||
|
|
||||||
|
ANNbool empty() // is queue empty?
|
||||||
|
{ if (n==0) return ANNtrue; else return ANNfalse; }
|
||||||
|
|
||||||
|
ANNbool non_empty() // is queue nonempty?
|
||||||
|
{ if (n==0) return ANNfalse; else return ANNtrue; }
|
||||||
|
|
||||||
|
void reset() // make existing queue empty
|
||||||
|
{ n = 0; }
|
||||||
|
|
||||||
|
inline void insert( // insert item (inlined for speed)
|
||||||
|
PQkey kv, // key value
|
||||||
|
PQinfo inf) // item info
|
||||||
|
{
|
||||||
|
if (++n > max_size) annError("Priority queue overflow.", ANNabort);
|
||||||
|
register int r = n;
|
||||||
|
while (r > 1) { // sift up new item
|
||||||
|
register int p = r/2;
|
||||||
|
ANN_FLOP(1) // increment floating ops
|
||||||
|
if (pq[p].key <= kv) // in proper order
|
||||||
|
break;
|
||||||
|
pq[r] = pq[p]; // else swap with parent
|
||||||
|
r = p;
|
||||||
|
}
|
||||||
|
pq[r].key = kv; // insert new item at final location
|
||||||
|
pq[r].info = inf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void extr_min( // extract minimum (inlined for speed)
|
||||||
|
PQkey &kv, // key (returned)
|
||||||
|
PQinfo &inf) // item info (returned)
|
||||||
|
{
|
||||||
|
kv = pq[1].key; // key of min item
|
||||||
|
inf = pq[1].info; // information of min item
|
||||||
|
register PQkey kn = pq[n--].key;// last item in queue
|
||||||
|
register int p = 1; // p points to item out of position
|
||||||
|
register int r = p<<1; // left child of p
|
||||||
|
while (r <= n) { // while r is still within the heap
|
||||||
|
ANN_FLOP(2) // increment floating ops
|
||||||
|
// set r to smaller child of p
|
||||||
|
if (r < n && pq[r].key > pq[r+1].key) r++;
|
||||||
|
if (kn <= pq[r].key) // in proper order
|
||||||
|
break;
|
||||||
|
pq[p] = pq[r]; // else swap with child
|
||||||
|
p = r; // advance pointers
|
||||||
|
r = p<<1;
|
||||||
|
}
|
||||||
|
pq[p] = pq[n+1]; // insert last item in proper place
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,118 @@
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// File: pr_queue_k.h
|
||||||
|
// Programmer: Sunil Arya and David Mount
|
||||||
|
// Description: Include file for priority queue with k items.
|
||||||
|
// Last modified: 01/04/05 (Version 1.0)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and
|
||||||
|
// David Mount. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// This software and related documentation is part of the Approximate
|
||||||
|
// Nearest Neighbor Library (ANN). This software is provided under
|
||||||
|
// the provisions of the Lesser GNU Public License (LGPL). See the
|
||||||
|
// file ../ReadMe.txt for further information.
|
||||||
|
//
|
||||||
|
// The University of Maryland (U.M.) and the authors make no
|
||||||
|
// representations about the suitability or fitness of this software for
|
||||||
|
// any purpose. It is provided "as is" without express or implied
|
||||||
|
// warranty.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// History:
|
||||||
|
// Revision 0.1 03/04/98
|
||||||
|
// Initial release
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef PR_QUEUE_K_H
|
||||||
|
#define PR_QUEUE_K_H
|
||||||
|
|
||||||
|
#include <ann/ANNx.h> // all ANN includes
|
||||||
|
#include <ann/ANNperf.h> // performance evaluation
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Basic types
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
typedef ANNdist PQKkey; // key field is distance
|
||||||
|
typedef int PQKinfo; // info field is int
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// The NULL key value is used to initialize the priority queue, and
|
||||||
|
// so it should be larger than any valid distance, so that it will
|
||||||
|
// be replaced as legal distance values are inserted. The NULL
|
||||||
|
// info value must be a nonvalid array index, we use ANN_NULL_IDX,
|
||||||
|
// which is guaranteed to be negative.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const PQKkey PQ_NULL_KEY = ANN_DIST_INF; // nonexistent key value
|
||||||
|
const PQKinfo PQ_NULL_INFO = ANN_NULL_IDX; // nonexistent info value
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// ANNmin_k
|
||||||
|
// An ANNmin_k structure is one which maintains the smallest
|
||||||
|
// k values (of type PQKkey) and associated information (of type
|
||||||
|
// PQKinfo). The special info and key values PQ_NULL_INFO and
|
||||||
|
// PQ_NULL_KEY means that thise entry is empty.
|
||||||
|
//
|
||||||
|
// It is currently implemented using an array with k items.
|
||||||
|
// Items are stored in increasing sorted order, and insertions
|
||||||
|
// are made through standard insertion sort. (This is quite
|
||||||
|
// inefficient, but current applications call for small values
|
||||||
|
// of k and relatively few insertions.)
|
||||||
|
//
|
||||||
|
// Note that the list contains k+1 entries, but the last entry
|
||||||
|
// is used as a simple placeholder and is otherwise ignored.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ANNmin_k {
|
||||||
|
struct mk_node { // node in min_k structure
|
||||||
|
PQKkey key; // key value
|
||||||
|
PQKinfo info; // info field (user defined)
|
||||||
|
};
|
||||||
|
|
||||||
|
int k; // max number of keys to store
|
||||||
|
int n; // number of keys currently active
|
||||||
|
mk_node *mk; // the list itself
|
||||||
|
|
||||||
|
public:
|
||||||
|
ANNmin_k(int max) // constructor (given max size)
|
||||||
|
{
|
||||||
|
n = 0; // initially no items
|
||||||
|
k = max; // maximum number of items
|
||||||
|
mk = new mk_node[max+1]; // sorted array of keys
|
||||||
|
}
|
||||||
|
|
||||||
|
~ANNmin_k() // destructor
|
||||||
|
{ delete [] mk; }
|
||||||
|
|
||||||
|
PQKkey ANNmin_key() // return minimum key
|
||||||
|
{ return (n > 0 ? mk[0].key : PQ_NULL_KEY); }
|
||||||
|
|
||||||
|
PQKkey max_key() // return maximum key
|
||||||
|
{ return (n == k ? mk[k-1].key : PQ_NULL_KEY); }
|
||||||
|
|
||||||
|
PQKkey ith_smallest_key(int i) // ith smallest key (i in [0..n-1])
|
||||||
|
{ return (i < n ? mk[i].key : PQ_NULL_KEY); }
|
||||||
|
|
||||||
|
PQKinfo ith_smallest_info(int i) // info for ith smallest (i in [0..n-1])
|
||||||
|
{ return (i < n ? mk[i].info : PQ_NULL_INFO); }
|
||||||
|
|
||||||
|
inline void insert( // insert item (inlined for speed)
|
||||||
|
PQKkey kv, // key value
|
||||||
|
PQKinfo inf) // item info
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
// slide larger values up
|
||||||
|
for (i = n; i > 0; i--) {
|
||||||
|
if (mk[i-1].key > kv)
|
||||||
|
mk[i] = mk[i-1];
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mk[i].key = kv; // store element here
|
||||||
|
mk[i].info = inf;
|
||||||
|
if (n < k) n++; // increment number of items
|
||||||
|
ANN_FLOP(k-i+1) // increment floating ops
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
add_definitions(-DUSE_PQP=0)
|
||||||
|
add_definitions(-DUSE_SVMLIGHT=0)
|
||||||
|
|
||||||
|
set (sources
|
||||||
|
src/AABB.cpp
|
||||||
|
src/OBB.cpp
|
||||||
|
src/RSS.cpp
|
||||||
|
src/vec_3f.cpp
|
||||||
|
src/traversal_node_base.cpp
|
||||||
|
src/traversal_node_bvhs.cpp
|
||||||
|
src/intersect.cpp
|
||||||
|
src/motion.cpp
|
||||||
|
src/BV_fitter.cpp
|
||||||
|
src/BV_splitter.cpp
|
||||||
|
src/BVH_model.cpp
|
||||||
|
src/BVH_utility.cpp
|
||||||
|
src/transform.cpp
|
||||||
|
src/simple_setup.cpp
|
||||||
|
src/geometric_shapes.cpp
|
||||||
|
src/geometric_shapes_utility.cpp
|
||||||
|
src/geometric_shapes_intersect.cpp
|
||||||
|
src/collision_node.cpp
|
||||||
|
src/traversal_recurse.cpp
|
||||||
|
src/broad_phase_collision.cpp
|
||||||
|
src/collision.cpp
|
||||||
|
src/collision_func_matrix.cpp
|
||||||
|
src/interval_tree.cpp
|
||||||
|
src/conservative_advancement.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(SYSTEM
|
||||||
|
${CMAKE_SOURCE_DIR}/deps/fcl/include
|
||||||
|
${CMAKE_SOURCE_DIR}/deps/ann/include
|
||||||
|
${CMAKE_SOURCE_DIR}/deps/libccd/include
|
||||||
|
)
|
||||||
|
|
||||||
|
gz_add_library(gazebo_fcl ${sources})
|
||||||
|
target_link_libraries(gazebo_fcl gazebo_ccd gazebo_ann)
|
||||||
|
gz_install_library(gazebo_fcl)
|
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_AABB_H
|
||||||
|
#define FCL_AABB_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief A class describing the AABB collision structure, which is a box in 3D space determined by two diagonal points */
|
||||||
|
class AABB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief The min point in the AABB */
|
||||||
|
Vec3f min_;
|
||||||
|
/** \brief The max point in the AABB */
|
||||||
|
Vec3f max_;
|
||||||
|
|
||||||
|
/** \brief Constructor creating an AABB with infinite size */
|
||||||
|
AABB();
|
||||||
|
|
||||||
|
/** \brief Constructor creating an AABB at position v with zero size */
|
||||||
|
AABB(const Vec3f& v) : min_(v), max_(v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Constructor creating an AABB with two endpoints a and b */
|
||||||
|
AABB(const Vec3f& a, const Vec3f&b)
|
||||||
|
{
|
||||||
|
min_ = min(a, b);
|
||||||
|
max_ = max(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Check whether two AABB are overlap */
|
||||||
|
inline bool overlap(const AABB& other) const
|
||||||
|
{
|
||||||
|
if(min_[0] > other.max_[0]) return false;
|
||||||
|
if(min_[1] > other.max_[1]) return false;
|
||||||
|
if(min_[2] > other.max_[2]) return false;
|
||||||
|
|
||||||
|
if(max_[0] < other.min_[0]) return false;
|
||||||
|
if(max_[1] < other.min_[1]) return false;
|
||||||
|
if(max_[2] < other.min_[2]) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \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_ = max(min_, other.min_);
|
||||||
|
overlap_part.max_ = min(max_, 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;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Merge the AABB and a point */
|
||||||
|
inline AABB& operator += (const Vec3f& p)
|
||||||
|
{
|
||||||
|
min_ = min(min_, p);
|
||||||
|
max_ = max(max_, p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Merge the AABB and another AABB */
|
||||||
|
inline AABB& operator += (const AABB& other)
|
||||||
|
{
|
||||||
|
min_ = min(min_, other.min_);
|
||||||
|
max_ = max(max_, other.max_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Return the merged AABB of current AABB and the other one */
|
||||||
|
inline AABB operator + (const AABB& other) const
|
||||||
|
{
|
||||||
|
AABB res(*this);
|
||||||
|
return res += other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Width of the AABB */
|
||||||
|
inline BVH_REAL width() const
|
||||||
|
{
|
||||||
|
return max_[0] - min_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Height of the AABB */
|
||||||
|
inline BVH_REAL height() const
|
||||||
|
{
|
||||||
|
return max_[1] - min_[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Depth of the AABB */
|
||||||
|
inline BVH_REAL depth() const
|
||||||
|
{
|
||||||
|
return max_[2] - min_[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Volume of the AABB */
|
||||||
|
inline BVH_REAL volume() const
|
||||||
|
{
|
||||||
|
return width() * height() * depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Size of the AABB, for split order */
|
||||||
|
inline BVH_REAL size() const
|
||||||
|
{
|
||||||
|
return (max_ - min_).sqrLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Center of the AABB */
|
||||||
|
inline Vec3f center() const
|
||||||
|
{
|
||||||
|
return (min_ + max_) * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The distance between two AABB
|
||||||
|
* Not implemented.
|
||||||
|
*/
|
||||||
|
BVH_REAL distance(const AABB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_BV_H
|
||||||
|
#define FCL_BV_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "fcl/kDOP.h"
|
||||||
|
#include "fcl/AABB.h"
|
||||||
|
#include "fcl/OBB.h"
|
||||||
|
#include "fcl/RSS.h"
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_BVH_FRONT_H
|
||||||
|
#define FCL_BVH_FRONT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief A class describing the node for BVH front */
|
||||||
|
struct BVHFrontNode
|
||||||
|
{
|
||||||
|
bool valid; // not valid when collision detected on the front node
|
||||||
|
int left, right;
|
||||||
|
|
||||||
|
BVHFrontNode(int left_, int right_)
|
||||||
|
{
|
||||||
|
left = left_;
|
||||||
|
right = right_;
|
||||||
|
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief A class describing the BVH front list */
|
||||||
|
typedef std::list<BVHFrontNode> BVHFrontList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_BVH_INTERNAL_H
|
||||||
|
#define FCL_BVH_INTERNAL_H
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef double BVH_REAL;
|
||||||
|
|
||||||
|
/** \brief States for BVH construction
|
||||||
|
* empty->begun->processed ->replace_begun->processed -> ......
|
||||||
|
* |
|
||||||
|
* |-> update_begun -> updated -> .....
|
||||||
|
* */
|
||||||
|
enum BVHBuildState
|
||||||
|
{
|
||||||
|
BVH_BUILD_STATE_EMPTY, // empty state, immediately after constructor
|
||||||
|
BVH_BUILD_STATE_BEGUN, // after beginModel(), state for adding geometry primitives
|
||||||
|
BVH_BUILD_STATE_PROCESSED, // after tree has been build, ready for cd use
|
||||||
|
BVH_BUILD_STATE_UPDATE_BEGUN, // after beginUpdateModel(), state for updating geometry primitives
|
||||||
|
BVH_BUILD_STATE_UPDATED, // after tree has been build for updated geometry, ready for ccd use
|
||||||
|
BVH_BUILD_STATE_REPLACE_BEGUN // after beginReplaceModel(), state for replacing geometry primitives
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Error code for BVH */
|
||||||
|
enum BVHReturnCode
|
||||||
|
{
|
||||||
|
BVH_OK = 0,
|
||||||
|
BVH_ERR_MODEL_OUT_OF_MEMORY = -1,
|
||||||
|
BVH_ERR_OUT_OF_MEMORY = -2,
|
||||||
|
BVH_ERR_UNPROCESSED_MODEL = -3,
|
||||||
|
BVH_ERR_BUILD_OUT_OF_SEQUENCE = -4,
|
||||||
|
BVH_ERR_BUILD_EMPTY_MODEL = -5,
|
||||||
|
BVH_ERR_BUILD_EMPTY_PREVIOUS_FRAME = -6,
|
||||||
|
BVH_ERR_UNSUPPORTED_FUNCTION = -7,
|
||||||
|
BVH_ERR_UNUPDATED_MODEL = -8,
|
||||||
|
BVH_ERR_INCORRECT_DATA = -9,
|
||||||
|
BVH_ERR_UNKNOWN = -10
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief BVH model type */
|
||||||
|
enum BVHModelType
|
||||||
|
{
|
||||||
|
BVH_MODEL_UNKNOWN,
|
||||||
|
BVH_MODEL_TRIANGLES,
|
||||||
|
BVH_MODEL_POINTCLOUD
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_BVH_MODEL_H
|
||||||
|
#define FCL_BVH_MODEL_H
|
||||||
|
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/BV.h"
|
||||||
|
#include "fcl/BV_node.h"
|
||||||
|
#include "fcl/primitive.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/BV_splitter.h"
|
||||||
|
#include "fcl/BV_fitter.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief A class describing the bounding hierarchy of a mesh model */
|
||||||
|
template<typename BV>
|
||||||
|
class BVHModel : public CollisionObject
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int num_tris_allocated;
|
||||||
|
int num_vertices_allocated;
|
||||||
|
int num_bvs_allocated;
|
||||||
|
int num_vertex_updated; // for ccd vertex update
|
||||||
|
unsigned int* primitive_indices;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief The state of BVH building process */
|
||||||
|
BVHBuildState build_state;
|
||||||
|
|
||||||
|
/** \brief Split rule to split one BV node into two children */
|
||||||
|
boost::shared_ptr<BVSplitterBase<BV> > bv_splitter;
|
||||||
|
|
||||||
|
/** \brief Fitting rule to fit a BV node to a set of geometry primitives */
|
||||||
|
boost::shared_ptr<BVFitterBase<BV> > bv_fitter;
|
||||||
|
|
||||||
|
/** \brief Model type */
|
||||||
|
BVHModelType getModelType() const
|
||||||
|
{
|
||||||
|
if(num_tris && num_vertices)
|
||||||
|
return BVH_MODEL_TRIANGLES;
|
||||||
|
else if(num_vertices)
|
||||||
|
return BVH_MODEL_POINTCLOUD;
|
||||||
|
else
|
||||||
|
return BVH_MODEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Constructing an empty BVH */
|
||||||
|
BVHModel()
|
||||||
|
{
|
||||||
|
vertices = NULL;
|
||||||
|
tri_indices = NULL;
|
||||||
|
bvs = NULL;
|
||||||
|
|
||||||
|
num_tris = 0;
|
||||||
|
num_tris_allocated = 0;
|
||||||
|
num_vertices = 0;
|
||||||
|
num_vertices_allocated = 0;
|
||||||
|
num_bvs = 0;
|
||||||
|
num_bvs_allocated = 0;
|
||||||
|
|
||||||
|
prev_vertices = NULL;
|
||||||
|
|
||||||
|
primitive_indices = NULL;
|
||||||
|
|
||||||
|
build_state = BVH_BUILD_STATE_EMPTY;
|
||||||
|
|
||||||
|
bv_splitter.reset(new BVSplitter<BV>(SPLIT_METHOD_MEAN));
|
||||||
|
bv_fitter.reset(new BVFitter<BV>());
|
||||||
|
}
|
||||||
|
|
||||||
|
BVHModel(const BVHModel& other);
|
||||||
|
|
||||||
|
|
||||||
|
~BVHModel()
|
||||||
|
{
|
||||||
|
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 Get the BV of index id */
|
||||||
|
const BVNode<BV>& getBV(int id) const
|
||||||
|
{
|
||||||
|
return bvs[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get the BV of index id */
|
||||||
|
BVNode<BV>& getBV(int id)
|
||||||
|
{
|
||||||
|
return bvs[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get the number of BVs */
|
||||||
|
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 */
|
||||||
|
NODE_TYPE getNodeType() const { return BV_UNKNOWN; }
|
||||||
|
|
||||||
|
/** \brief Compute the AABB for the BVH, used for broad-phase collision */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Geometry point data */
|
||||||
|
Vec3f* vertices;
|
||||||
|
|
||||||
|
/** \brief Geometry triangle index data, will be NULL for point clouds */
|
||||||
|
Triangle* tri_indices;
|
||||||
|
|
||||||
|
/** \brief Geometry point data in previous frame */
|
||||||
|
Vec3f* prev_vertices;
|
||||||
|
|
||||||
|
/** \brief Number of triangles */
|
||||||
|
int num_tris;
|
||||||
|
|
||||||
|
/** \brief Number of points */
|
||||||
|
int num_vertices;
|
||||||
|
|
||||||
|
/** \brief Begin a new BVH model */
|
||||||
|
int beginModel(int num_tris = 0, int num_vertices = 0);
|
||||||
|
|
||||||
|
/** \brief Add one point in the new BVH model */
|
||||||
|
int addVertex(const Vec3f& p);
|
||||||
|
|
||||||
|
/** \brief Add one triangle in the new BVH model */
|
||||||
|
int addTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3);
|
||||||
|
|
||||||
|
/** \brief Add a set of triangles in the new BVH model */
|
||||||
|
int addSubModel(const std::vector<Vec3f>& ps, const std::vector<Triangle>& ts);
|
||||||
|
|
||||||
|
/** \brief Add a set of points in the new BVH model */
|
||||||
|
int addSubModel(const std::vector<Vec3f>& ps);
|
||||||
|
|
||||||
|
/** \brief End BVH model construction, will build the bounding volume hierarchy */
|
||||||
|
int endModel();
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Replace the geometry information of current frame (i.e. should have the same mesh topology with the previous frame) */
|
||||||
|
int beginReplaceModel();
|
||||||
|
|
||||||
|
/** \brief Replace one point in the old BVH model */
|
||||||
|
int replaceVertex(const Vec3f& p);
|
||||||
|
|
||||||
|
/** \brief Replace one triangle in the old BVH model */
|
||||||
|
int replaceTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3);
|
||||||
|
|
||||||
|
/** \brief Replace a set of points in the old BVH model */
|
||||||
|
int replaceSubModel(const std::vector<Vec3f>& ps);
|
||||||
|
|
||||||
|
/** \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();
|
||||||
|
|
||||||
|
/** \brief Update one point in the old BVH model */
|
||||||
|
int updateVertex(const Vec3f& p);
|
||||||
|
|
||||||
|
/** \brief Update one triangle in the old BVH model */
|
||||||
|
int updateTriangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3);
|
||||||
|
|
||||||
|
/** \brief Update a set of points in the old BVH model */
|
||||||
|
int updateSubModel(const std::vector<Vec3f>& ps);
|
||||||
|
|
||||||
|
/** \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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Bounding volume hierarchy */
|
||||||
|
BVNode<BV>* bvs;
|
||||||
|
|
||||||
|
/** \brief Number of BV nodes in bounding volume hierarchy */
|
||||||
|
int num_bvs;
|
||||||
|
|
||||||
|
/** \brief Build the bounding volume hierarchy */
|
||||||
|
int buildTree();
|
||||||
|
|
||||||
|
/** \brief Refit the bounding volume hierarchy */
|
||||||
|
int refitTree(bool bottomup);
|
||||||
|
|
||||||
|
/** \brief Refit the bounding volume hierarchy in a top-down way (slow but more compact)*/
|
||||||
|
int refitTree_topdown();
|
||||||
|
|
||||||
|
/** \brief Refit the bounding volume hierarchy in a bottom-up way (fast but less compact) */
|
||||||
|
int refitTree_bottomup();
|
||||||
|
|
||||||
|
/** \brief Recursive kernel for hierarchy construction */
|
||||||
|
int recursiveBuildTree(int bv_id, int first_primitive, int num_primitives);
|
||||||
|
|
||||||
|
/** \brief Recursive kernel for bottomup refitting */
|
||||||
|
int recursiveRefitTree_bottomup(int bv_id);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Specialization of getNodeType() for BVHModel with different BV types */
|
||||||
|
template<>
|
||||||
|
NODE_TYPE BVHModel<AABB>::getNodeType() const;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
NODE_TYPE BVHModel<OBB>::getNodeType() const;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
NODE_TYPE BVHModel<RSS>::getNodeType() const;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
NODE_TYPE BVHModel<KDOP<16> >::getNodeType() const;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
NODE_TYPE BVHModel<KDOP<18> >::getNodeType() const;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
NODE_TYPE BVHModel<KDOP<24> >::getNodeType() const;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_BVH_UTILITY_H
|
||||||
|
#define FCL_BVH_UTILITY_H
|
||||||
|
|
||||||
|
#include "fcl/primitive.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/BVH_model.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Expand the BVH bounding boxes according to uncertainty */
|
||||||
|
template<typename BV>
|
||||||
|
void BVHExpand(BVHModel<BV>& model, const Uncertainty* ucs, BVH_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 Uncertainty& 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 uncertainty, for OBB */
|
||||||
|
void BVHExpand(BVHModel<OBB>& model, const Uncertainty* ucs, BVH_REAL r);
|
||||||
|
|
||||||
|
/** \brief Expand the BVH bounding boxes according to uncertainty, for RSS */
|
||||||
|
void BVHExpand(BVHModel<RSS>& model, const Uncertainty* ucs, BVH_REAL r);
|
||||||
|
|
||||||
|
/** \brief Estimate the uncertainty of point clouds due to sampling procedure */
|
||||||
|
void estimateSamplingUncertainty(Vec3f* vertices, int num_vertices, Uncertainty* ucs);
|
||||||
|
|
||||||
|
/** \brief Compute the covariance matrix for a set or subset of points. */
|
||||||
|
void getCovariance(Vec3f* ps, Vec3f* ps2, unsigned int* indices, int n, Vec3f M[3]);
|
||||||
|
|
||||||
|
/** \brief Compute the covariance matrix for a set or subset of triangles. */
|
||||||
|
void getCovariance(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Vec3f M[3]);
|
||||||
|
|
||||||
|
|
||||||
|
/** \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, unsigned int* indices, int n, Vec3f axis[3], Vec3f& origin, BVH_REAL l[2], BVH_REAL& r);
|
||||||
|
|
||||||
|
|
||||||
|
/** \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, Vec3f axis[3], Vec3f& origin, BVH_REAL l[2], BVH_REAL& r);
|
||||||
|
|
||||||
|
/** \brief Compute the bounding volume extent and center for a set or subset of points.
|
||||||
|
* The bounding volume axes are known.
|
||||||
|
*/
|
||||||
|
void getExtentAndCenter(Vec3f* ps, Vec3f* ps2, unsigned int* indices, int n, Vec3f axis[3], Vec3f& center, Vec3f& extent);
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Compute the bounding volume extent and center for a set or subset of points.
|
||||||
|
* The bounding volume axes are known.
|
||||||
|
*/
|
||||||
|
void getExtentAndCenter(Vec3f* ps, Vec3f* ps2, Triangle* ts, unsigned int* indices, int n, Vec3f axis[3], Vec3f& center, Vec3f& extent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,256 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_BV_FITTER_H
|
||||||
|
#define FCL_BV_FITTER_H
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/primitive.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/OBB.h"
|
||||||
|
#include "fcl/RSS.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Compute a bounding volume that fits a set of n points. */
|
||||||
|
template<typename BV>
|
||||||
|
void fit(Vec3f* ps, int n, BV& bv)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
bv += ps[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void fit<OBB>(Vec3f* ps, int n, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void fit<RSS>(Vec3f* ps, int n, RSS& bv);
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
class BVFitterBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_) = 0;
|
||||||
|
|
||||||
|
virtual void set(Vec3f* vertices_, Vec3f* prev_vertices_, Triangle* tri_indices_, BVHModelType type_) = 0;
|
||||||
|
|
||||||
|
virtual BV fit(unsigned int* primitive_indices, int num_primitives) = 0;
|
||||||
|
|
||||||
|
virtual void clear() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief A class for fitting a bounding volume to a set of points */
|
||||||
|
template<typename BV>
|
||||||
|
class BVFitter : public BVFitterBase<BV>
|
||||||
|
{
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
BV fit(unsigned int* primitive_indices, int num_primitives)
|
||||||
|
{
|
||||||
|
BV bv;
|
||||||
|
|
||||||
|
if(type == BVH_MODEL_TRIANGLES) /* The primitive is triangle */
|
||||||
|
{
|
||||||
|
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) /* When fitting both current and previous frame */
|
||||||
|
{
|
||||||
|
bv += prev_vertices[t[0]];
|
||||||
|
bv += prev_vertices[t[1]];
|
||||||
|
bv += prev_vertices[t[2]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type == BVH_MODEL_POINTCLOUD) /* The primitive is point */
|
||||||
|
{
|
||||||
|
for(int i = 0; i < num_primitives; ++i)
|
||||||
|
{
|
||||||
|
bv += vertices[primitive_indices[i]];
|
||||||
|
|
||||||
|
if(prev_vertices) /* When fitting both current and previous frame */
|
||||||
|
{
|
||||||
|
bv += prev_vertices[primitive_indices[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Specification of BVFitter for OBB bounding volume */
|
||||||
|
template<>
|
||||||
|
class BVFitter<OBB> : public BVFitterBase<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 */
|
||||||
|
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>
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_BV_NODE_H
|
||||||
|
#define FCL_BV_NODE_H
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief A class describing a bounding volume node */
|
||||||
|
template<typename BV>
|
||||||
|
struct BVNode
|
||||||
|
{
|
||||||
|
/** \brief A bounding volume */
|
||||||
|
BV bv;
|
||||||
|
|
||||||
|
/** \brief An index for first child node or primitive
|
||||||
|
* If the value is positive, it is the index of the first child bv node
|
||||||
|
* If the value is negative, it is -(primitive index + 1)
|
||||||
|
* Zero is not used.
|
||||||
|
*/
|
||||||
|
int first_child;
|
||||||
|
|
||||||
|
/** \brief The start id the primitive belonging to the current node. The index is referred to the primitive_indices in BVHModel and from that
|
||||||
|
* we can obtain the primitive's index in original data indirectly.
|
||||||
|
*/
|
||||||
|
int first_primitive;
|
||||||
|
|
||||||
|
/** \brief The number of primitives belonging to the current node */
|
||||||
|
int num_primitives;
|
||||||
|
|
||||||
|
/** \brief Whether current node is a leaf node (i.e. contains a primitive index */
|
||||||
|
bool isLeaf() const { return first_child < 0; }
|
||||||
|
|
||||||
|
/** \brief Return the primitive index. The index is referred to the original data (i.e. vertices or tri_indices) in BVHModel */
|
||||||
|
int primitiveId() const { return -(first_child + 1); }
|
||||||
|
|
||||||
|
/** \brief Return the index of the first child. The index is referred to the bounding volume array (i.e. bvs) in BVHModel */
|
||||||
|
int leftChild() const { return first_child; }
|
||||||
|
|
||||||
|
/** \brief Return the index of the second child. The index is referred to the bounding volume array (i.e. bvs) in BVHModel */
|
||||||
|
int rightChild() const { return first_child + 1; }
|
||||||
|
|
||||||
|
/** \brief Check whether two BVNode collide */
|
||||||
|
bool overlap(const BVNode& other) const
|
||||||
|
{
|
||||||
|
return bv.overlap(other.bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL distance(const BVNode& other, Vec3f* P1 = NULL, Vec3f* P2 = NULL) const
|
||||||
|
{
|
||||||
|
return bv.distance(other.bv, P1, P2);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_BV_SPLITTER_H
|
||||||
|
#define FCL_BV_SPLITTER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/primitive.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/OBB.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Base class for BV splitting operation */
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
BVSplitter(SplitMethodType method)
|
||||||
|
{
|
||||||
|
split_method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set the geometry data needed by the split rule */
|
||||||
|
void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
|
||||||
|
{
|
||||||
|
vertices = vertices_;
|
||||||
|
tri_indices = tri_indices_;
|
||||||
|
type = type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */
|
||||||
|
void computeRule(const BV& bv, unsigned int* primitive_indices, int num_primitives)
|
||||||
|
{
|
||||||
|
switch(split_method)
|
||||||
|
{
|
||||||
|
case SPLIT_METHOD_MEAN:
|
||||||
|
computeRule_mean(bv, primitive_indices, num_primitives);
|
||||||
|
break;
|
||||||
|
case SPLIT_METHOD_MEDIAN:
|
||||||
|
computeRule_median(bv, primitive_indices, num_primitives);
|
||||||
|
break;
|
||||||
|
case SPLIT_METHOD_BV_CENTER:
|
||||||
|
computeRule_bvcenter(bv, primitive_indices, num_primitives);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << "Split method not supported" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Apply the split rule on a given point */
|
||||||
|
bool apply(const Vec3f& q) const
|
||||||
|
{
|
||||||
|
return q[split_axis] > split_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Clear the geometry data set before */
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
vertices = NULL;
|
||||||
|
tri_indices = NULL;
|
||||||
|
type = BVH_MODEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief The split axis */
|
||||||
|
int split_axis;
|
||||||
|
|
||||||
|
/** \brief The split threshold */
|
||||||
|
BVH_REAL split_value;
|
||||||
|
|
||||||
|
Vec3f* vertices;
|
||||||
|
Triangle* tri_indices;
|
||||||
|
BVHModelType type;
|
||||||
|
SplitMethodType split_method;
|
||||||
|
|
||||||
|
/** \brief Split the node from center */
|
||||||
|
void computeRule_bvcenter(const BV& bv, unsigned int* /*primitive_indices*/, int /*num_primitives*/)
|
||||||
|
{
|
||||||
|
Vec3f center = bv.center();
|
||||||
|
int axis = 2;
|
||||||
|
|
||||||
|
if(bv.width() >= bv.height() && bv.width() >= bv.depth())
|
||||||
|
axis = 0;
|
||||||
|
else if(bv.height() >= bv.width() && bv.height() >= bv.depth())
|
||||||
|
axis = 1;
|
||||||
|
|
||||||
|
split_axis = axis;
|
||||||
|
split_value = center[axis];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Split the node according to the mean of the data contained */
|
||||||
|
void computeRule_mean(const BV& bv, unsigned int* primitive_indices, int num_primitives)
|
||||||
|
{
|
||||||
|
int axis = 2;
|
||||||
|
|
||||||
|
if(bv.width() >= bv.height() && bv.width() >= bv.depth())
|
||||||
|
axis = 0;
|
||||||
|
else if(bv.height() >= bv.width() && bv.height() >= bv.depth())
|
||||||
|
axis = 1;
|
||||||
|
|
||||||
|
split_axis = axis;
|
||||||
|
BVH_REAL sum = 0;
|
||||||
|
|
||||||
|
if(type == BVH_MODEL_TRIANGLES)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < num_primitives; ++i)
|
||||||
|
{
|
||||||
|
const Triangle& t = tri_indices[primitive_indices[i]];
|
||||||
|
sum += ((vertices[t[0]][split_axis] + vertices[t[1]][split_axis] + vertices[t[2]][split_axis]) / 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type == BVH_MODEL_POINTCLOUD)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < num_primitives; ++i)
|
||||||
|
{
|
||||||
|
sum += vertices[primitive_indices[i]][split_axis];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
split_value = sum / num_primitives;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Split the node according to the median of the data contained */
|
||||||
|
void computeRule_median(const BV& bv, unsigned int* primitive_indices, int num_primitives)
|
||||||
|
{
|
||||||
|
int axis = 2;
|
||||||
|
|
||||||
|
if(bv.width() >= bv.height() && bv.width() >= bv.depth())
|
||||||
|
axis = 0;
|
||||||
|
else if(bv.height() >= bv.width() && bv.height() >= bv.depth())
|
||||||
|
axis = 1;
|
||||||
|
|
||||||
|
split_axis = axis;
|
||||||
|
std::vector<BVH_REAL> proj(num_primitives);
|
||||||
|
|
||||||
|
if(type == BVH_MODEL_TRIANGLES)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < num_primitives; ++i)
|
||||||
|
{
|
||||||
|
const Triangle& t = tri_indices[primitive_indices[i]];
|
||||||
|
proj[i] = (vertices[t[0]][split_axis] + vertices[t[1]][split_axis] + vertices[t[2]][split_axis]) / 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type == BVH_MODEL_POINTCLOUD)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < num_primitives; ++i)
|
||||||
|
proj[i] = vertices[primitive_indices[i]][split_axis];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(proj.begin(), proj.end());
|
||||||
|
|
||||||
|
if(num_primitives % 2 == 1)
|
||||||
|
{
|
||||||
|
split_value = proj[(num_primitives - 1) / 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
split_value = (proj[num_primitives / 2] + proj[num_primitives / 2 - 1]) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief BVHSplitRule specialization for OBB */
|
||||||
|
template<>
|
||||||
|
class BVSplitter<OBB> : public BVSplitterBase<OBB>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
BVSplitter(SplitMethodType method)
|
||||||
|
{
|
||||||
|
split_method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set the geometry data needed by the split rule */
|
||||||
|
void set(Vec3f* vertices_, Triangle* tri_indices_, BVHModelType type_)
|
||||||
|
{
|
||||||
|
vertices = vertices_;
|
||||||
|
tri_indices = tri_indices_;
|
||||||
|
type = type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Compute the split rule according to a subset of geometry and the corresponding BV node */
|
||||||
|
void computeRule(const OBB& bv, unsigned int* /*primitive_indices*/, int /*num_primitives*/)
|
||||||
|
{
|
||||||
|
Vec3f center = bv.center();
|
||||||
|
split_vector = bv.axis[0];
|
||||||
|
split_value = center[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Apply the split rule on a given point */
|
||||||
|
bool apply(const Vec3f& q) const
|
||||||
|
{
|
||||||
|
return split_vector.dot(Vec3f(q[0], q[1], q[2])) > split_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Clear the geometry data set before */
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
vertices = NULL;
|
||||||
|
tri_indices = NULL;
|
||||||
|
type = BVH_MODEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Split the node from center */
|
||||||
|
void computeRule_bvcenter(const OBB& bv, unsigned int* primitive_indices, int num_primitives);
|
||||||
|
|
||||||
|
/** \brief Split the node according to the mean of the data contained */
|
||||||
|
void computeRule_mean(const OBB& bv, unsigned int* primitive_indices, int num_primitives);
|
||||||
|
|
||||||
|
/** \brief Split the node according to the median of the data contained */
|
||||||
|
void computeRule_median(const OBB& bv, unsigned int* primitive_indices, int num_primitives);
|
||||||
|
|
||||||
|
BVH_REAL split_value;
|
||||||
|
Vec3f split_vector;
|
||||||
|
|
||||||
|
Vec3f* vertices;
|
||||||
|
Triangle* tri_indices;
|
||||||
|
BVHModelType type;
|
||||||
|
SplitMethodType split_method;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_PQP_H
|
||||||
|
#define FCL_PQP_H
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief OBB class */
|
||||||
|
class OBB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Orientation of OBB */
|
||||||
|
Vec3f axis[3]; // R[i] is the ith column of the orientation matrix, or the axis of the OBB
|
||||||
|
|
||||||
|
/** \brief center of OBB */
|
||||||
|
Vec3f To;
|
||||||
|
|
||||||
|
/** \brief Half dimensions of OBB */
|
||||||
|
Vec3f extent;
|
||||||
|
|
||||||
|
OBB() {}
|
||||||
|
|
||||||
|
/** \brief Check collision between two OBB */
|
||||||
|
bool overlap(const OBB& other) const;
|
||||||
|
|
||||||
|
/** \brief Check collision between two OBB and return the overlap part.
|
||||||
|
* For OBB, we return nothing, 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 */
|
||||||
|
inline bool contain(const Vec3f& p) const;
|
||||||
|
|
||||||
|
/** \brief A simple way to merge the OBB and a point, not compact. */
|
||||||
|
OBB& operator += (const Vec3f& p);
|
||||||
|
|
||||||
|
/** \brief Merge the OBB and another OBB */
|
||||||
|
OBB& operator += (const OBB& other)
|
||||||
|
{
|
||||||
|
*this = *this + other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Return the merged OBB of current OBB and the other one */
|
||||||
|
OBB operator + (const OBB& other) const;
|
||||||
|
|
||||||
|
/** \brief Width of the OBB */
|
||||||
|
inline BVH_REAL width() const
|
||||||
|
{
|
||||||
|
return 2 * extent[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Height of the OBB */
|
||||||
|
inline BVH_REAL height() const
|
||||||
|
{
|
||||||
|
return 2 * extent[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Depth of the OBB */
|
||||||
|
inline BVH_REAL depth() const
|
||||||
|
{
|
||||||
|
return 2 * extent[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Volume of the OBB */
|
||||||
|
inline BVH_REAL volume() const
|
||||||
|
{
|
||||||
|
return width() * height() * depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Size of the OBB, for split order */
|
||||||
|
inline BVH_REAL size() const
|
||||||
|
{
|
||||||
|
return extent.sqrLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Center of the OBB */
|
||||||
|
inline Vec3f center() const
|
||||||
|
{
|
||||||
|
return To;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The distance between two OBB
|
||||||
|
* Not implemented
|
||||||
|
*/
|
||||||
|
BVH_REAL distance(const OBB& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Compute the 8 vertices of a OBB */
|
||||||
|
void computeVertices(Vec3f vertex[8]) const;
|
||||||
|
|
||||||
|
/** \brief OBB merge method when the centers of two smaller OBB are far away */
|
||||||
|
static OBB merge_largedist(const OBB& b1, const OBB& b2);
|
||||||
|
|
||||||
|
/** \brief OBB merge method when the centers of two smaller OBB are close */
|
||||||
|
static OBB merge_smalldist(const OBB& b1, const OBB& b2);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Kernel check whether two OBB are disjoint */
|
||||||
|
static bool obbDisjoint(const Vec3f B[3], const Vec3f& T, const Vec3f& a, const Vec3f& b);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool overlap(const Vec3f R0[3], const Vec3f& T0, const OBB& b1, const OBB& b2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_RSS_H
|
||||||
|
#define FCL_RSS_H
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
class RSS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Orientation of RSS */
|
||||||
|
Vec3f axis[3];
|
||||||
|
|
||||||
|
/** \brief position of rectangle (origin of the rectangle) */
|
||||||
|
Vec3f Tr;
|
||||||
|
|
||||||
|
/** \brief side lengths of rectangle */
|
||||||
|
BVH_REAL l[2];
|
||||||
|
|
||||||
|
/** \brief radius of sphere summed with rectangle to form RSS */
|
||||||
|
BVH_REAL r;
|
||||||
|
|
||||||
|
RSS() {}
|
||||||
|
|
||||||
|
/** \brief Check collision between two RSS */
|
||||||
|
bool overlap(const RSS& other) 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 overlap(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Check whether the RSS contains a point */
|
||||||
|
inline bool contain(const Vec3f& p) const;
|
||||||
|
|
||||||
|
/** \brief A simple way to merge the RSS and a point, not compact.
|
||||||
|
* THIS FUNCTION STILL HAS PROBLEM!!
|
||||||
|
*/
|
||||||
|
RSS& operator += (const Vec3f& p);
|
||||||
|
|
||||||
|
/** \brief Merge the RSS and another RSS */
|
||||||
|
inline RSS& operator += (const RSS& other)
|
||||||
|
{
|
||||||
|
*this = *this + other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Return the merged RSS of current RSS and the other one */
|
||||||
|
RSS operator + (const RSS& other) const;
|
||||||
|
|
||||||
|
/** \brief Width of the RSS */
|
||||||
|
inline BVH_REAL width() const
|
||||||
|
{
|
||||||
|
return l[0] + 2 * r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Height of the RSS */
|
||||||
|
inline BVH_REAL height() const
|
||||||
|
{
|
||||||
|
return l[1] + 2 * r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Depth of the RSS */
|
||||||
|
inline BVH_REAL depth() const
|
||||||
|
{
|
||||||
|
return 2 * r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Volume of the RSS */
|
||||||
|
inline BVH_REAL volume() const
|
||||||
|
{
|
||||||
|
return (l[0] * l[1] * 2 * r + 4 * 3.1415926 * r * r * r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Size of the RSS, for split order */
|
||||||
|
inline BVH_REAL size() const
|
||||||
|
{
|
||||||
|
return (sqrt(l[0] * l[0] + l[1] * l[1]) + 2 * r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The RSS center */
|
||||||
|
inline Vec3f center() const
|
||||||
|
{
|
||||||
|
return Tr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief the distance between two RSS */
|
||||||
|
BVH_REAL distance(const RSS& other, Vec3f* P = NULL, Vec3f* Q = NULL) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** \brief Clip val between a and b */
|
||||||
|
static void clipToRange(BVH_REAL& val, BVH_REAL a, BVH_REAL b);
|
||||||
|
|
||||||
|
/** \brief Finds the parameters t & u corresponding to the two closest points on a pair of line segments.
|
||||||
|
* The first segment is defined as Pa + A*t, 0 <= t <= a, where "Pa" is one endpoint of the segment, "A" is a unit vector
|
||||||
|
* pointing to the other endpoint, and t is a scalar that produces all the points between the two endpoints. Since "A" is a unit
|
||||||
|
* vector, "a" is the segment's length.
|
||||||
|
* The second segment is defined as Pb + B*u, 0 <= u <= b.
|
||||||
|
* Many of the terms needed by the algorithm are already computed for other purposes,so we just pass these terms into the function
|
||||||
|
* instead of complete specifications of each segment. "T" in the dot products is the vector betweeen Pa and Pb.
|
||||||
|
* Reference: "On fast computation of distance between line segments." Vladimir J. Lumelsky, in Information Processing Letters, no. 21, pages 55-61, 1985.
|
||||||
|
*/
|
||||||
|
static void segCoords(BVH_REAL& t, BVH_REAL& u, BVH_REAL a, BVH_REAL b, BVH_REAL A_dot_B, BVH_REAL A_dot_T, BVH_REAL B_dot_T);
|
||||||
|
|
||||||
|
/** \brief Returns whether the nearest point on rectangle edge
|
||||||
|
* Pb + B*u, 0 <= u <= b, to the rectangle edge,
|
||||||
|
* Pa + A*t, 0 <= t <= a, is within the half space
|
||||||
|
* determined by the point Pa and the direction Anorm.
|
||||||
|
*
|
||||||
|
* A,B, and Anorm are unit vectors.
|
||||||
|
* T is the vector between Pa and Pb.
|
||||||
|
*/
|
||||||
|
static bool inVoronoi(BVH_REAL a, BVH_REAL b, BVH_REAL Anorm_dot_B, BVH_REAL Anorm_dot_T, BVH_REAL A_dot_B, BVH_REAL A_dot_T, BVH_REAL B_dot_T);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief distance between two oriented rectangles
|
||||||
|
* P and Q (optional return values) are the closest points in the rectangles, both are in the local frame of the first rectangle
|
||||||
|
*/
|
||||||
|
static BVH_REAL rectDistance(const Vec3f Rab[3], Vec3f const& Tab, const BVH_REAL a[2], const BVH_REAL b[2], Vec3f* P = NULL, Vec3f* Q = NULL);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \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)
|
||||||
|
*/
|
||||||
|
BVH_REAL distance(const Vec3f R0[3], const Vec3f& T0, const RSS& b1, const RSS& b2, Vec3f* P = NULL, Vec3f* Q = NULL);
|
||||||
|
|
||||||
|
bool overlap(const Vec3f R0[3], const Vec3f& T0, const RSS& b1, const RSS& b2);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,493 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_BROAD_PHASE_COLLISION_H
|
||||||
|
#define FCL_BROAD_PHASE_COLLISION_H
|
||||||
|
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/collision_data.h"
|
||||||
|
#include "fcl/AABB.h"
|
||||||
|
#include "fcl/interval_tree.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool defaultCollisionFunction(CollisionObject* o1, CollisionObject* o2, void* cdata);
|
||||||
|
|
||||||
|
/** \brief return value is whether can stop now */
|
||||||
|
typedef bool (*CollisionCallBack)(CollisionObject* o1, CollisionObject* o2, void* cdata);
|
||||||
|
|
||||||
|
/** \brief Base class for broad phase collision */
|
||||||
|
class BroadPhaseCollisionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief add one object to the manager */
|
||||||
|
virtual void registerObject(CollisionObject* obj) = 0;
|
||||||
|
|
||||||
|
/** \brief remove one object from the manager */
|
||||||
|
virtual void unregisterObject(CollisionObject* obj) = 0;
|
||||||
|
|
||||||
|
/** \brief initialize the manager, related with the specific type of manager */
|
||||||
|
virtual void setup() = 0;
|
||||||
|
|
||||||
|
/** \brief update the condition of manager */
|
||||||
|
virtual void update() = 0;
|
||||||
|
|
||||||
|
/** \brief clear the manager */
|
||||||
|
virtual void clear() = 0;
|
||||||
|
|
||||||
|
/** \brief return the objects managed by the manager */
|
||||||
|
virtual void getObjects(std::vector<CollisionObject*>& objs) const = 0;
|
||||||
|
|
||||||
|
/** \brief perform collision test between one object and all the objects belonging to the manager */
|
||||||
|
virtual void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const = 0;
|
||||||
|
|
||||||
|
/** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
|
||||||
|
virtual void collide(void* cdata, CollisionCallBack callback) const = 0;
|
||||||
|
|
||||||
|
/** \brief whether the manager is empty */
|
||||||
|
virtual bool empty() const = 0;
|
||||||
|
|
||||||
|
/** \brief the number of objects managed by the manager */
|
||||||
|
virtual size_t size() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Brute force N-body collision manager */
|
||||||
|
class NaiveCollisionManager : public BroadPhaseCollisionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NaiveCollisionManager() {}
|
||||||
|
|
||||||
|
/** \brief remove one object from the manager */
|
||||||
|
void registerObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief add one object to the manager */
|
||||||
|
void unregisterObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief initialize the manager, related with the specific type of manager */
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
/** \brief update the condition of manager */
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/** \brief clear the manager */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** \brief return the objects managed by the manager */
|
||||||
|
void getObjects(std::vector<CollisionObject*>& objs) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test between one object and all the objects belonging to the manager */
|
||||||
|
void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
|
||||||
|
void collide(void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief whether the manager is empty */
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
/** \brief the number of objects managed by the manager */
|
||||||
|
inline size_t size() const { return objs.size(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** \brief objects belonging to the manager are stored in a list structure */
|
||||||
|
std::list<CollisionObject*> objs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Rigorous SAP collision manager */
|
||||||
|
class SaPCollisionManager : public BroadPhaseCollisionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
SaPCollisionManager()
|
||||||
|
{
|
||||||
|
elist[0] = NULL;
|
||||||
|
elist[1] = NULL;
|
||||||
|
elist[2] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SaPCollisionManager()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief remove one object from the manager */
|
||||||
|
void registerObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief add one object to the manager */
|
||||||
|
void unregisterObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief initialize the manager, related with the specific type of manager */
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
/** \brief update the condition of manager */
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/** \brief clear the manager */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** \brief return the objects managed by the manager */
|
||||||
|
void getObjects(std::vector<CollisionObject*>& objs) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test between one object and all the objects belonging to the manager */
|
||||||
|
void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
|
||||||
|
void collide(void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief whether the manager is empty */
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
/** \brief the number of objects managed by the manager */
|
||||||
|
inline size_t size() const { return AABB_arr.size(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct EndPoint;
|
||||||
|
|
||||||
|
/** \brief SAP interval for one object */
|
||||||
|
struct SaPAABB
|
||||||
|
{
|
||||||
|
/** \brief object */
|
||||||
|
CollisionObject* obj;
|
||||||
|
|
||||||
|
/** \brief lower bound end point of the interval */
|
||||||
|
EndPoint* lo;
|
||||||
|
|
||||||
|
/** \brief higher bound end point of the interval */
|
||||||
|
EndPoint* hi;
|
||||||
|
|
||||||
|
/** \brief cached AABB value */
|
||||||
|
AABB cached;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief End point for an interval */
|
||||||
|
struct EndPoint
|
||||||
|
{
|
||||||
|
/** \brief tag for whether it is a lower bound or higher bound of an interval, 0 for lo, and 1 for hi */
|
||||||
|
char minmax;
|
||||||
|
|
||||||
|
/** \brief back pointer to SAP interval */
|
||||||
|
SaPAABB* aabb;
|
||||||
|
|
||||||
|
/** \brief the previous end point in the end point list */
|
||||||
|
EndPoint* prev[3];
|
||||||
|
/** \brief the next end point in the end point list */
|
||||||
|
EndPoint* next[3];
|
||||||
|
|
||||||
|
/** \brief get the value of the end point */
|
||||||
|
const Vec3f& getVal() const
|
||||||
|
{
|
||||||
|
if(minmax == 0) return aabb->cached.min_;
|
||||||
|
else return aabb->cached.max_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief set the value of the end point */
|
||||||
|
Vec3f& getVal()
|
||||||
|
{
|
||||||
|
if(minmax == 0) return aabb->cached.min_;
|
||||||
|
else return aabb->cached.max_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief A pair of objects that are not culling away and should further check collision */
|
||||||
|
struct SaPPair
|
||||||
|
{
|
||||||
|
SaPPair(CollisionObject* a, CollisionObject* b)
|
||||||
|
{
|
||||||
|
obj1 = a;
|
||||||
|
obj2 = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollisionObject* obj1;
|
||||||
|
CollisionObject* obj2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Functor to help unregister one object */
|
||||||
|
class isUnregistered
|
||||||
|
{
|
||||||
|
CollisionObject* obj;
|
||||||
|
|
||||||
|
public:
|
||||||
|
isUnregistered(CollisionObject* obj_)
|
||||||
|
{
|
||||||
|
obj = obj_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator() (const SaPPair& pair)
|
||||||
|
{
|
||||||
|
return (pair.obj1 == obj) || (pair.obj2 == obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Functor to help remove collision pairs no longer valid (i.e., should be culled away) */
|
||||||
|
class isNotValidPair
|
||||||
|
{
|
||||||
|
CollisionObject* obj1;
|
||||||
|
CollisionObject* obj2;
|
||||||
|
|
||||||
|
public:
|
||||||
|
isNotValidPair(CollisionObject* obj1_, CollisionObject* obj2_)
|
||||||
|
{
|
||||||
|
obj1 = obj1_;
|
||||||
|
obj2 = obj2_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator() (const SaPPair& pair)
|
||||||
|
{
|
||||||
|
return (pair.obj1 == obj1 && pair.obj2 == obj2) || (pair.obj1 == obj2 && pair.obj2 == obj1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief End point list for x, y, z coordinates */
|
||||||
|
EndPoint* elist[3];
|
||||||
|
|
||||||
|
/** \brief SAP interval list */
|
||||||
|
std::list<SaPAABB*> AABB_arr;
|
||||||
|
|
||||||
|
/** \brief The pair of objects that should further check for collision */
|
||||||
|
std::list<SaPPair> overlap_pairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Simple SAP collision manager */
|
||||||
|
class SSaPCollisionManager : public BroadPhaseCollisionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SSaPCollisionManager()
|
||||||
|
{
|
||||||
|
setup_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief remove one object from the manager */
|
||||||
|
void registerObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief add one object to the manager */
|
||||||
|
void unregisterObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief initialize the manager, related with the specific type of manager */
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
/** \brief update the condition of manager */
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/** \brief clear the manager */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** \brief return the objects managed by the manager */
|
||||||
|
void getObjects(std::vector<CollisionObject*>& objs) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test between one object and all the objects belonging to the manager */
|
||||||
|
void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
|
||||||
|
void collide(void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief whether the manager is empty */
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
/** \brief the number of objects managed by the manager */
|
||||||
|
inline size_t size() const { return objs_x.size(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** \brief Functor sorting objects according to the AABB lower x bound */
|
||||||
|
struct SortByXLow
|
||||||
|
{
|
||||||
|
bool operator()(const CollisionObject* a, const CollisionObject* b) const
|
||||||
|
{
|
||||||
|
if(a->getAABB().min_[0] < b->getAABB().min_[0])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Functor sorting objects according to the AABB lower y bound */
|
||||||
|
struct SortByYLow
|
||||||
|
{
|
||||||
|
bool operator()(const CollisionObject* a, const CollisionObject* b) const
|
||||||
|
{
|
||||||
|
if(a->getAABB().min_[1] < b->getAABB().min_[1])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Functor sorting objects according to the AABB lower z bound */
|
||||||
|
struct SortByZLow
|
||||||
|
{
|
||||||
|
bool operator()(const CollisionObject* a, const CollisionObject* b) const
|
||||||
|
{
|
||||||
|
if(a->getAABB().min_[2] < b->getAABB().min_[2])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Dummy collision object with a point AABB */
|
||||||
|
class DummyCollisionObject : public CollisionObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DummyCollisionObject(const AABB& aabb_)
|
||||||
|
{
|
||||||
|
aabb = aabb_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeLocalAABB() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief check collision between one object and a list of objects */
|
||||||
|
void checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end,
|
||||||
|
CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Objects sorted according to lower x value */
|
||||||
|
std::vector<CollisionObject*> objs_x;
|
||||||
|
|
||||||
|
/** \brief Objects sorted according to lower y value */
|
||||||
|
std::vector<CollisionObject*> objs_y;
|
||||||
|
|
||||||
|
/** \brief Objects sorted according to lower z value */
|
||||||
|
std::vector<CollisionObject*> objs_z;
|
||||||
|
|
||||||
|
/** \brief tag about whether the environment is maintained suitably (i.e., the objs_x, objs_y, objs_z are sorted correctly */
|
||||||
|
bool setup_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Collision manager based on interval tree */
|
||||||
|
class IntervalTreeCollisionManager : public BroadPhaseCollisionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IntervalTreeCollisionManager()
|
||||||
|
{
|
||||||
|
setup_ = false;
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
interval_trees[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief remove one object from the manager */
|
||||||
|
void registerObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief add one object to the manager */
|
||||||
|
void unregisterObject(CollisionObject* obj);
|
||||||
|
|
||||||
|
/** \brief initialize the manager, related with the specific type of manager */
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
/** \brief update the condition of manager */
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/** \brief clear the manager */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** \brief return the objects managed by the manager */
|
||||||
|
void getObjects(std::vector<CollisionObject*>& objs) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test between one object and all the objects belonging to the manager */
|
||||||
|
void collide(CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief perform collision test for the objects belonging to the manager (i.e., N^2 self collision) */
|
||||||
|
void collide(void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
/** \brief whether the manager is empty */
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
/** \brief the number of objects managed by the manager */
|
||||||
|
inline size_t size() const { return endpoints[0].size() / 2; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** \brief check collision between one object and a list of objects */
|
||||||
|
void checkColl(std::vector<CollisionObject*>::const_iterator pos_start, std::vector<CollisionObject*>::const_iterator pos_end,
|
||||||
|
CollisionObject* obj, void* cdata, CollisionCallBack callback) const;
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief SAP end point */
|
||||||
|
struct EndPoint
|
||||||
|
{
|
||||||
|
/** \brief object related with the end point */
|
||||||
|
CollisionObject* obj;
|
||||||
|
|
||||||
|
/** \brief end point value */
|
||||||
|
BVH_REAL value;
|
||||||
|
|
||||||
|
/** \brief tag for whether it is a lower bound or higher bound of an interval, 0 for lo, and 1 for hi */
|
||||||
|
char minmax;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Functor for sorting end points */
|
||||||
|
struct SortByValue
|
||||||
|
{
|
||||||
|
bool operator()(const EndPoint& a, const EndPoint& b) const
|
||||||
|
{
|
||||||
|
if(a.value < b.value)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Extention interval tree's interval to SAP interval, adding more information */
|
||||||
|
struct SAPInterval : public Interval
|
||||||
|
{
|
||||||
|
CollisionObject* obj;
|
||||||
|
SAPInterval(double low_, double high_, CollisionObject* obj_)
|
||||||
|
{
|
||||||
|
low = low_;
|
||||||
|
high = high_;
|
||||||
|
obj = obj_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief vector stores all the end points */
|
||||||
|
std::vector<EndPoint> endpoints[3];
|
||||||
|
|
||||||
|
/** \brief interval tree manages the intervals */
|
||||||
|
IntervalTree* interval_trees[3];
|
||||||
|
|
||||||
|
/** \brief tag for whether the interval tree is maintained suitably */
|
||||||
|
bool setup_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_COLLISION_H
|
||||||
|
#define FCL_COLLISION_H
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/collision_data.h"
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Main collision interface: given two collision objects, and the requirements for contacts, including num of max contacts, whether perform exhaustive collision (i.e., returning
|
||||||
|
* returning all the contact points), whether return detailed contact information (i.e., normal, contact point, depth; otherwise only contact primitive id is returned), this function
|
||||||
|
* performs the collision between them.
|
||||||
|
* Return value is the number of contacts returned
|
||||||
|
*/
|
||||||
|
int collide(const CollisionObject* o1, const CollisionObject* o2,
|
||||||
|
int num_max_contacts, bool exhaustive, bool enable_contact,
|
||||||
|
std::vector<Contact>& contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,75 @@
|
||||||
|
#ifndef FCL_COLLISION_DATA_H
|
||||||
|
#define FCL_COLLISION_DATA_H
|
||||||
|
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Contact
|
||||||
|
{
|
||||||
|
BVH_REAL penetration_depth;
|
||||||
|
Vec3f normal;
|
||||||
|
Vec3f pos;
|
||||||
|
const CollisionObject* o1;
|
||||||
|
const CollisionObject* o2;
|
||||||
|
int b1;
|
||||||
|
int b2;
|
||||||
|
|
||||||
|
Contact()
|
||||||
|
{
|
||||||
|
o1 = NULL;
|
||||||
|
o2 = NULL;
|
||||||
|
b1 = -1;
|
||||||
|
b2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Contact(const CollisionObject* o1_, const CollisionObject* o2_, int b1_, int b2_)
|
||||||
|
{
|
||||||
|
o1 = o1_;
|
||||||
|
o2 = o2_;
|
||||||
|
b1 = b1_;
|
||||||
|
b2 = b2_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Contact(const CollisionObject* o1_, const CollisionObject* o2_, int b1_, int b2_,
|
||||||
|
const Vec3f& pos_, const Vec3f& normal_, BVH_REAL depth_)
|
||||||
|
{
|
||||||
|
o1 = o1_;
|
||||||
|
o2 = o2_;
|
||||||
|
b1 = b1_;
|
||||||
|
b2 = b2_;
|
||||||
|
normal = normal_;
|
||||||
|
pos = pos_;
|
||||||
|
penetration_depth = depth_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CollisionData
|
||||||
|
{
|
||||||
|
CollisionData()
|
||||||
|
{
|
||||||
|
done = false;
|
||||||
|
is_collision = false;
|
||||||
|
num_max_contacts = 1;
|
||||||
|
enable_contact = false;
|
||||||
|
exhaustive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done;
|
||||||
|
bool is_collision;
|
||||||
|
bool exhaustive;
|
||||||
|
unsigned int num_max_contacts;
|
||||||
|
bool enable_contact;
|
||||||
|
|
||||||
|
std::vector<Contact> contacts;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_COLLISION_FUNC_MATRIX_H
|
||||||
|
#define FCL_COLLISION_FUNC_MATRIX_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/collision_data.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
typedef int (*CollisionFunc)(const CollisionObject* o1, const CollisionObject* o2, int num_max_contacts, bool exhaustive, bool enable_contact, std::vector<Contact>& contacts);
|
||||||
|
|
||||||
|
|
||||||
|
struct CollisionFunctionMatrix
|
||||||
|
{
|
||||||
|
CollisionFunc collision_matrix[14][14];
|
||||||
|
|
||||||
|
CollisionFunctionMatrix();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_COLLISION_NODE_H
|
||||||
|
#define FCL_COLLISION_NODE_H
|
||||||
|
|
||||||
|
#include "fcl/traversal_node_base.h"
|
||||||
|
#include "fcl/traversal_node_bvhs.h"
|
||||||
|
#include "fcl/BVH_front.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
void collide(CollisionTraversalNodeBase* node, BVHFrontList* front_list = NULL);
|
||||||
|
|
||||||
|
void selfCollide(CollisionTraversalNodeBase* node, BVHFrontList* front_list = NULL);
|
||||||
|
|
||||||
|
void distance(DistanceTraversalNodeBase* node, BVHFrontList* front_list = NULL, int qsize = 2);
|
||||||
|
|
||||||
|
void distance(MeshDistanceTraversalNodeRSS* node, BVHFrontList* front_list = NULL, int qsize = 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_COLLISION_OBJECT_BASE_H
|
||||||
|
#define FCL_COLLISION_OBJECT_BASE_H
|
||||||
|
|
||||||
|
#include "fcl/AABB.h"
|
||||||
|
#include "fcl/transform.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
enum OBJECT_TYPE {OT_UNKNOWN, OT_BVH, OT_GEOM};
|
||||||
|
|
||||||
|
enum NODE_TYPE {BV_UNKNOWN, BV_AABB, BV_OBB, BV_RSS, BV_KDOP16, BV_KDOP18, BV_KDOP24,
|
||||||
|
GEOM_BOX, GEOM_SPHERE, GEOM_CAPSULE, GEOM_CONE, GEOM_CYLINDER, GEOM_CONVEX, GEOM_PLANE};
|
||||||
|
|
||||||
|
/** \brief Base class for all objects participating in collision */
|
||||||
|
class CollisionObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~CollisionObject() {}
|
||||||
|
|
||||||
|
virtual OBJECT_TYPE getObjectType() const { return OT_UNKNOWN; }
|
||||||
|
|
||||||
|
virtual NODE_TYPE getNodeType() const { return BV_UNKNOWN; }
|
||||||
|
|
||||||
|
virtual void computeLocalAABB() = 0;
|
||||||
|
|
||||||
|
inline const AABB& getAABB() const
|
||||||
|
{
|
||||||
|
return aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void computeAABB()
|
||||||
|
{
|
||||||
|
Vec3f center = t.transform(aabb_center);
|
||||||
|
Vec3f delta(aabb_radius, aabb_radius, aabb_radius);
|
||||||
|
aabb.min_ = center - delta;
|
||||||
|
aabb.max_ = center + delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Vec3f& getTranslation() const
|
||||||
|
{
|
||||||
|
return t.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Vec3f* getRotation() const
|
||||||
|
{
|
||||||
|
return t.getRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const SimpleQuaternion& getQuatRotation() const
|
||||||
|
{
|
||||||
|
return t.getQuatRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRotation(const Vec3f R[3])
|
||||||
|
{
|
||||||
|
t.setRotation(R);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTranslation(const Vec3f& T)
|
||||||
|
{
|
||||||
|
t.setTranslation(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setQuatRotation(const SimpleQuaternion& q)
|
||||||
|
{
|
||||||
|
t.setQuatRotation(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTransform(const Vec3f R[3], const Vec3f& T)
|
||||||
|
{
|
||||||
|
t.setTransform(R, T);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTransform(const SimpleQuaternion& q, const Vec3f& T)
|
||||||
|
{
|
||||||
|
t.setTransform(q, T);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIdentityTransform() const
|
||||||
|
{
|
||||||
|
return t.isIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIdentityTransform()
|
||||||
|
{
|
||||||
|
t.setIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** AABB in global coordinate */
|
||||||
|
mutable AABB aabb;
|
||||||
|
|
||||||
|
/** AABB in local coordinate */
|
||||||
|
AABB aabb_local;
|
||||||
|
|
||||||
|
/** AABB center in local coordinate */
|
||||||
|
Vec3f aabb_center;
|
||||||
|
|
||||||
|
/** AABB radius */
|
||||||
|
BVH_REAL aabb_radius;
|
||||||
|
|
||||||
|
SimpleTransform t;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_CONSERVATIVE_ADVANCEMENT_H
|
||||||
|
#define FCL_CONSERVATIVE_ADVANCEMENT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/collision_data.h"
|
||||||
|
#include "fcl/motion_base.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
int conservativeAdvancement(const CollisionObject* o1,
|
||||||
|
MotionBase<BV>* motion1,
|
||||||
|
const CollisionObject* o2,
|
||||||
|
MotionBase<BV>* motion2,
|
||||||
|
int num_max_contacts, bool exhaustive, bool enable_contact,
|
||||||
|
std::vector<Contact>& contacts,
|
||||||
|
BVH_REAL& toc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GEOMETRIC_SHAPE_TO_BVH_MODEL_H
|
||||||
|
#define GEOMETRIC_SHAPE_TO_BVH_MODEL_H
|
||||||
|
|
||||||
|
#include "fcl/geometric_shapes.h"
|
||||||
|
#include "fcl/BVH_model.h"
|
||||||
|
#include <boost/math/constants/constants.hpp>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Generate BVH model from box */
|
||||||
|
template<typename BV>
|
||||||
|
void generateBVHModel(BVHModel<BV>& model, const Box& shape)
|
||||||
|
{
|
||||||
|
double a = shape.side[0];
|
||||||
|
double b = shape.side[1];
|
||||||
|
double c = shape.side[2];
|
||||||
|
std::vector<Vec3f> points(8);
|
||||||
|
std::vector<Triangle> tri_indices(12);
|
||||||
|
points[0] = Vec3f(0.5 * a, -0.5 * b, 0.5 * c);
|
||||||
|
points[1] = Vec3f(0.5 * a, 0.5 * b, 0.5 * c);
|
||||||
|
points[2] = Vec3f(-0.5 * a, 0.5 * b, 0.5 * c);
|
||||||
|
points[3] = Vec3f(-0.5 * a, -0.5 * b, 0.5 * c);
|
||||||
|
points[4] = Vec3f(0.5 * a, -0.5 * b, -0.5 * c);
|
||||||
|
points[5] = Vec3f(0.5 * a, 0.5 * b, -0.5 * c);
|
||||||
|
points[6] = Vec3f(-0.5 * a, 0.5 * b, -0.5 * c);
|
||||||
|
points[7] = Vec3f(-0.5 * a, -0.5 * b, -0.5 * c);
|
||||||
|
|
||||||
|
tri_indices[0] = Triangle(0, 4, 1);
|
||||||
|
tri_indices[1] = Triangle(1, 4, 5);
|
||||||
|
tri_indices[2] = Triangle(2, 6, 3);
|
||||||
|
tri_indices[3] = Triangle(3, 6, 7);
|
||||||
|
tri_indices[4] = Triangle(3, 0, 2);
|
||||||
|
tri_indices[5] = Triangle(2, 0, 1);
|
||||||
|
tri_indices[6] = Triangle(6, 5, 7);
|
||||||
|
tri_indices[7] = Triangle(7, 5, 4);
|
||||||
|
tri_indices[8] = Triangle(1, 5, 2);
|
||||||
|
tri_indices[9] = Triangle(2, 5, 6);
|
||||||
|
tri_indices[10] = Triangle(3, 7, 0);
|
||||||
|
tri_indices[11] = Triangle(0, 7, 4);
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < points.size(); ++i)
|
||||||
|
{
|
||||||
|
Vec3f v = matMulVec(shape.getLocalRotation(), points[i]) + shape.getLocalTranslation();
|
||||||
|
v = matMulVec(shape.getRotation(), v) + shape.getTranslation();
|
||||||
|
points[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.beginModel();
|
||||||
|
model.addSubModel(points, tri_indices);
|
||||||
|
model.endModel();
|
||||||
|
model.computeLocalAABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generate BVH model from sphere */
|
||||||
|
template<typename BV>
|
||||||
|
void generateBVHModel(BVHModel<BV>& model, const Sphere& shape, unsigned int seg = 16, unsigned int ring = 16)
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> points;
|
||||||
|
std::vector<Triangle> tri_indices;
|
||||||
|
|
||||||
|
double r = shape.radius;
|
||||||
|
double phi, phid;
|
||||||
|
const double pi = boost::math::constants::pi<double>();
|
||||||
|
phid = pi * 2 / seg;
|
||||||
|
phi = 0;
|
||||||
|
|
||||||
|
double theta, thetad;
|
||||||
|
thetad = pi / (ring + 1);
|
||||||
|
theta = 0;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < ring; ++i)
|
||||||
|
{
|
||||||
|
double theta_ = theta + thetad * (i + 1);
|
||||||
|
for(unsigned int j = 0; j < seg; ++j)
|
||||||
|
{
|
||||||
|
points.push_back(Vec3f(r * sin(theta_) * cos(phi + j * phid), r * sin(theta_) * sin(phi + j * phid), r * cos(theta_)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points.push_back(Vec3f(0, 0, r));
|
||||||
|
points.push_back(Vec3f(0, 0, -r));
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < ring - 1; ++i)
|
||||||
|
{
|
||||||
|
for(unsigned int j = 0; j < seg; ++j)
|
||||||
|
{
|
||||||
|
unsigned int a, b, c, d;
|
||||||
|
a = i * seg + j;
|
||||||
|
b = (j == seg - 1) ? (i * seg) : (i * seg + j + 1);
|
||||||
|
c = (i + 1) * seg + j;
|
||||||
|
d = (j == seg - 1) ? ((i + 1) * seg) : ((i + 1) * seg + j + 1);
|
||||||
|
tri_indices.push_back(Triangle(a, c, b));
|
||||||
|
tri_indices.push_back(Triangle(b, c, d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int j = 0; j < seg; ++j)
|
||||||
|
{
|
||||||
|
unsigned int a, b;
|
||||||
|
a = j;
|
||||||
|
b = (j == seg - 1) ? 0 : (j + 1);
|
||||||
|
tri_indices.push_back(Triangle(ring * seg, a, b));
|
||||||
|
|
||||||
|
a = (ring - 1) * seg + j;
|
||||||
|
b = (j == seg - 1) ? (ring - 1) * seg : ((ring - 1) * seg + j + 1);
|
||||||
|
tri_indices.push_back(Triangle(a, ring * seg + 1, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < points.size(); ++i)
|
||||||
|
{
|
||||||
|
Vec3f v = matMulVec(shape.getLocalRotation(), points[i]) + shape.getLocalTranslation();
|
||||||
|
v = matMulVec(shape.getRotation(), v) + shape.getTranslation();
|
||||||
|
points[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.beginModel();
|
||||||
|
model.addSubModel(points, tri_indices);
|
||||||
|
model.endModel();
|
||||||
|
model.computeLocalAABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Generate BVH model from cylinder */
|
||||||
|
template<typename BV>
|
||||||
|
void generateBVHModel(BVHModel<BV>& model, const Cylinder& shape, unsigned int tot = 16)
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> points;
|
||||||
|
std::vector<Triangle> tri_indices;
|
||||||
|
|
||||||
|
double r = shape.radius;
|
||||||
|
double h = shape.lz;
|
||||||
|
double phi, phid;
|
||||||
|
const double pi = boost::math::constants::pi<double>();
|
||||||
|
phid = pi * 2 / tot;
|
||||||
|
phi = 0;
|
||||||
|
|
||||||
|
double circle_edge = phid * r;
|
||||||
|
unsigned int h_num = ceil(h / circle_edge);
|
||||||
|
double hd = h / h_num;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
points.push_back(Vec3f(r * cos(phi + phid * i), r * sin(phi + phid * i), h / 2));
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < h_num - 1; ++i)
|
||||||
|
{
|
||||||
|
for(unsigned int j = 0; j < tot; ++j)
|
||||||
|
{
|
||||||
|
points.push_back(Vec3f(r * cos(phi + phid * j), r * sin(phi + phid * j), h / 2 - (i + 1) * hd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
points.push_back(Vec3f(r * cos(phi + phid * i), r * sin(phi + phid * i), - h / 2));
|
||||||
|
|
||||||
|
points.push_back(Vec3f(0, 0, h / 2));
|
||||||
|
points.push_back(Vec3f(0, 0, -h / 2));
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
{
|
||||||
|
Triangle tmp((h_num + 1) * tot, i, ((i == tot - 1) ? 0 : (i + 1)));
|
||||||
|
tri_indices.push_back(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
{
|
||||||
|
Triangle tmp((h_num + 1) * tot + 1, h_num * tot + ((i == tot - 1) ? 0 : (i + 1)), h_num * tot + i);
|
||||||
|
tri_indices.push_back(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < h_num; ++i)
|
||||||
|
{
|
||||||
|
for(unsigned int j = 0; j < tot; ++j)
|
||||||
|
{
|
||||||
|
int a, b, c, d;
|
||||||
|
a = j;
|
||||||
|
b = (j == tot - 1) ? 0 : (j + 1);
|
||||||
|
c = j + tot;
|
||||||
|
d = (j == tot - 1) ? tot : (j + 1 + tot);
|
||||||
|
|
||||||
|
int start = i * tot;
|
||||||
|
tri_indices.push_back(Triangle(start + b, start + a, start + c));
|
||||||
|
tri_indices.push_back(Triangle(start + b, start + c, start + d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < points.size(); ++i)
|
||||||
|
{
|
||||||
|
Vec3f v = matMulVec(shape.getLocalRotation(), points[i]) + shape.getLocalTranslation();
|
||||||
|
v = matMulVec(shape.getRotation(), v) + shape.getTranslation();
|
||||||
|
points[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.beginModel();
|
||||||
|
model.addSubModel(points, tri_indices);
|
||||||
|
model.endModel();
|
||||||
|
model.computeLocalAABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Generate BVH model from cone */
|
||||||
|
template<typename BV>
|
||||||
|
void generateBVHModel(BVHModel<BV>& model, const Cone& shape, unsigned int tot = 16)
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> points;
|
||||||
|
std::vector<Triangle> tri_indices;
|
||||||
|
|
||||||
|
double r = shape.radius;
|
||||||
|
double h = shape.lz;
|
||||||
|
|
||||||
|
double phi, phid;
|
||||||
|
const double pi = boost::math::constants::pi<double>();
|
||||||
|
phid = pi * 2 / tot;
|
||||||
|
phi = 0;
|
||||||
|
|
||||||
|
double circle_edge = phid * r;
|
||||||
|
unsigned int h_num = ceil(h / circle_edge);
|
||||||
|
double hd = h / h_num;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < h_num - 1; ++i)
|
||||||
|
{
|
||||||
|
for(unsigned int j = 0; j < tot; ++j)
|
||||||
|
{
|
||||||
|
points.push_back(Vec3f(r * cos(phi + phid * j), r * sin(phi + phid * j), h / 2 - (i + 1) * hd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
points.push_back(Vec3f(r * cos(phi + phid * i), r * sin(phi + phid * i), - h / 2));
|
||||||
|
|
||||||
|
points.push_back(Vec3f(0, 0, h / 2));
|
||||||
|
points.push_back(Vec3f(0, 0, -h / 2));
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
{
|
||||||
|
Triangle tmp(h_num * tot, i, (i == tot - 1) ? 0 : (i + 1));
|
||||||
|
tri_indices.push_back(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < tot; ++i)
|
||||||
|
{
|
||||||
|
Triangle tmp(h_num * tot + 1, (h_num - 1) * tot + (i == tot - 1) ? 0 : (i + 1), (h_num - 1) * tot + i);
|
||||||
|
tri_indices.push_back(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < h_num - 1; ++i)
|
||||||
|
{
|
||||||
|
for(unsigned int j = 0; j < tot; ++j)
|
||||||
|
{
|
||||||
|
int a, b, c, d;
|
||||||
|
a = j;
|
||||||
|
b = (j == tot - 1) ? 0 : (j + 1);
|
||||||
|
c = j + tot;
|
||||||
|
d = (j == tot - 1) ? tot : (j + 1 + tot);
|
||||||
|
|
||||||
|
int start = i * tot;
|
||||||
|
tri_indices.push_back(Triangle(start + b, start + a, start + c));
|
||||||
|
tri_indices.push_back(Triangle(start + b, start + c, start + d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < points.size(); ++i)
|
||||||
|
{
|
||||||
|
Vec3f v = matMulVec(shape.getLocalRotation(), points[i]) + shape.getLocalTranslation();
|
||||||
|
v = matMulVec(shape.getRotation(), v) + shape.getTranslation();
|
||||||
|
points[i] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.beginModel();
|
||||||
|
model.addSubModel(points, tri_indices);
|
||||||
|
model.endModel();
|
||||||
|
model.computeLocalAABB();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,332 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_GEOMETRIC_SHAPES_H
|
||||||
|
#define FCL_GEOMETRIC_SHAPES_H
|
||||||
|
|
||||||
|
#include "fcl/collision_object.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Base class for all basic geometric shapes */
|
||||||
|
class ShapeBase : public CollisionObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Default Constructor */
|
||||||
|
ShapeBase()
|
||||||
|
{
|
||||||
|
Rloc[0][0] = 1;
|
||||||
|
Rloc[1][1] = 1;
|
||||||
|
Rloc[2][2] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set the local frame of the shape */
|
||||||
|
void setLocalTransform(const Vec3f R_[3], const Vec3f& T_)
|
||||||
|
{
|
||||||
|
Rloc[0] = R_[0];
|
||||||
|
Rloc[1] = R_[1];
|
||||||
|
Rloc[2] = R_[2];
|
||||||
|
Tloc = T_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set the local orientation of the shape */
|
||||||
|
void setLocalRotation(const Vec3f R[3])
|
||||||
|
{
|
||||||
|
Rloc[0] = R[0];
|
||||||
|
Rloc[1] = R[1];
|
||||||
|
Rloc[2] = R[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set the local position of the shape */
|
||||||
|
void setLocalTranslation(const Vec3f& T)
|
||||||
|
{
|
||||||
|
Tloc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Append additional transform to the local transform */
|
||||||
|
void appendLocalTransform(const Vec3f R[3], const Vec3f& T)
|
||||||
|
{
|
||||||
|
Vec3f R0[3];
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R0[i] = Rloc[i];
|
||||||
|
matMulMat(R, R0, Rloc);
|
||||||
|
Tloc = matMulVec(R, Tloc) + T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get local transform */
|
||||||
|
void getLocalTransform(Vec3f R[3], Vec3f& T) const
|
||||||
|
{
|
||||||
|
T = Tloc;
|
||||||
|
R[0] = Rloc[0];
|
||||||
|
R[1] = Rloc[1];
|
||||||
|
R[2] = Rloc[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get local position */
|
||||||
|
inline const Vec3f& getLocalTranslation() const
|
||||||
|
{
|
||||||
|
return Tloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get local orientation */
|
||||||
|
inline const Vec3f* getLocalRotation() const
|
||||||
|
{
|
||||||
|
return Rloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get object type: a geometric shape */
|
||||||
|
OBJECT_TYPE getObjectType() const { return OT_GEOM; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Vec3f Rloc[3];
|
||||||
|
Vec3f Tloc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Center at zero point, axis aligned box */
|
||||||
|
class Box : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Box(BVH_REAL x, BVH_REAL y, BVH_REAL z) : ShapeBase(), side(x, y, z) {}
|
||||||
|
|
||||||
|
/** box side length */
|
||||||
|
Vec3f side;
|
||||||
|
|
||||||
|
/** \brief Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Get node type: a box */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_BOX; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Center at zero point sphere */
|
||||||
|
class Sphere : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sphere(BVH_REAL radius_) : ShapeBase(), radius(radius_) {}
|
||||||
|
|
||||||
|
/** \brief Radius of the sphere */
|
||||||
|
BVH_REAL radius;
|
||||||
|
|
||||||
|
/** \brief Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Get node type: a sphere */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_SPHERE; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Center at zero point capsule */
|
||||||
|
class Capsule : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Capsule(BVH_REAL radius_, BVH_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_) {}
|
||||||
|
|
||||||
|
/** \brief Radius of capsule */
|
||||||
|
BVH_REAL radius;
|
||||||
|
|
||||||
|
/** \brief Length along z axis */
|
||||||
|
BVH_REAL lz;
|
||||||
|
|
||||||
|
/** \brief Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Get node type: a capsule */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_CAPSULE; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Center at zero cone */
|
||||||
|
class Cone : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Cone(BVH_REAL radius_, BVH_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_) {}
|
||||||
|
|
||||||
|
/** \brief Radius of the cone */
|
||||||
|
BVH_REAL radius;
|
||||||
|
|
||||||
|
/** \brief Length along z axis */
|
||||||
|
BVH_REAL lz;
|
||||||
|
|
||||||
|
/** \brief Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Get node type: a cone */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_CONE; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Center at zero cylinder */
|
||||||
|
class Cylinder : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Cylinder(BVH_REAL radius_, BVH_REAL lz_) : ShapeBase(), radius(radius_), lz(lz_) {}
|
||||||
|
|
||||||
|
/** \brief Radius of the cylinder */
|
||||||
|
BVH_REAL radius;
|
||||||
|
|
||||||
|
/** \brief Length along z axis */
|
||||||
|
BVH_REAL lz;
|
||||||
|
|
||||||
|
/** \brief Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Get node type: a cylinder */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_CYLINDER; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Convex polytope */
|
||||||
|
class Convex : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructing a convex, providing normal and offset of each polytype surface, and the points and shape topology information */
|
||||||
|
Convex(Vec3f* plane_normals_,
|
||||||
|
BVH_REAL* plane_dis_,
|
||||||
|
int num_planes_,
|
||||||
|
Vec3f* points_,
|
||||||
|
int /*num_points_*/,
|
||||||
|
int* polygons_) : ShapeBase()
|
||||||
|
{
|
||||||
|
plane_normals = plane_normals_;
|
||||||
|
plane_dis = plane_dis_;
|
||||||
|
num_planes = num_planes_;
|
||||||
|
points = points_;
|
||||||
|
polygons = polygons_;
|
||||||
|
edges = NULL;
|
||||||
|
|
||||||
|
Vec3f sum;
|
||||||
|
for(int i = 0; i < num_points; ++i)
|
||||||
|
{
|
||||||
|
sum += points[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
center = sum * (BVH_REAL)(1.0 / num_points);
|
||||||
|
|
||||||
|
fillEdges();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor */
|
||||||
|
Convex(const Convex& other) : ShapeBase(other)
|
||||||
|
{
|
||||||
|
plane_normals = other.plane_normals;
|
||||||
|
plane_dis = other.plane_dis;
|
||||||
|
num_planes = other.num_planes;
|
||||||
|
points = other.points;
|
||||||
|
polygons = other.polygons;
|
||||||
|
edges = new Edge[other.num_edges];
|
||||||
|
memcpy(edges, other.edges, sizeof(Edge) * num_edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Convex()
|
||||||
|
{
|
||||||
|
delete [] edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** Get node type: a conex polytope */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_CONVEX; }
|
||||||
|
|
||||||
|
|
||||||
|
Vec3f* plane_normals;
|
||||||
|
BVH_REAL* plane_dis;
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
|
||||||
|
Vec3f* points;
|
||||||
|
int num_points;
|
||||||
|
int num_edges;
|
||||||
|
int num_planes;
|
||||||
|
|
||||||
|
struct Edge
|
||||||
|
{
|
||||||
|
int first, second;
|
||||||
|
};
|
||||||
|
|
||||||
|
Edge* edges;
|
||||||
|
|
||||||
|
/** \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;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** \brief Get edge information */
|
||||||
|
void fillEdges();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Infinite plane */
|
||||||
|
class Plane : public ShapeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Construct a plane with normal direction and offset */
|
||||||
|
Plane(const Vec3f& n_, BVH_REAL d_) : ShapeBase(), n(n_), d(d_) { unitNormalTest(); }
|
||||||
|
|
||||||
|
/** \brief Construct a plane with normal direction and offset */
|
||||||
|
Plane(BVH_REAL a, BVH_REAL b, BVH_REAL c, BVH_REAL d_)
|
||||||
|
{
|
||||||
|
n = Vec3f(a, b, c);
|
||||||
|
d = d_;
|
||||||
|
unitNormalTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Compute AABB */
|
||||||
|
void computeLocalAABB();
|
||||||
|
|
||||||
|
/** \brief Get node type: a plane */
|
||||||
|
NODE_TYPE getNodeType() const { return GEOM_PLANE; }
|
||||||
|
|
||||||
|
/** \brief Plane normal */
|
||||||
|
Vec3f n;
|
||||||
|
|
||||||
|
/** \brief Plane offset */
|
||||||
|
BVH_REAL d;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** \brief Turn non-unit normal into unit */
|
||||||
|
void unitNormalTest();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_GEOMETRIC_SHAPES_INTERSECT_H
|
||||||
|
#define FCL_GEOMETRIC_SHAPES_INTERSECT_H
|
||||||
|
|
||||||
|
#include "fcl/geometric_shapes.h"
|
||||||
|
#include "fcl/transform.h"
|
||||||
|
|
||||||
|
#include <ccd/ccd.h>
|
||||||
|
#include <ccd/quat.h>
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief recall function used by GJK algorithm */
|
||||||
|
typedef void (*GJKSupportFunction)(const void* obj, const ccd_vec3_t* dir_, ccd_vec3_t* v);
|
||||||
|
typedef void (*GJKCenterFunction)(const void* obj, ccd_vec3_t* c);
|
||||||
|
|
||||||
|
/** \brief initialize GJK stuffs */
|
||||||
|
template<typename T>
|
||||||
|
class GJKInitializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Get GJK support function */
|
||||||
|
static GJKSupportFunction getSupportFunction() { return NULL; }
|
||||||
|
|
||||||
|
/** \brief Get GJK center function */
|
||||||
|
static GJKCenterFunction getCenterFunction() { return NULL; }
|
||||||
|
|
||||||
|
/** \brief Get GJK object from a shape
|
||||||
|
* Notice that only local transformation is applied.
|
||||||
|
* Gloal transformation are considered later
|
||||||
|
*/
|
||||||
|
static void* createGJKObject(const T& /*s*/) { return NULL; }
|
||||||
|
|
||||||
|
/** \brief Delete GJK object */
|
||||||
|
static void deleteGJKObject(void* /*o*/) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Cylinder */
|
||||||
|
template<>
|
||||||
|
class GJKInitializer<Cylinder>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GJKSupportFunction getSupportFunction();
|
||||||
|
static GJKCenterFunction getCenterFunction();
|
||||||
|
static void* createGJKObject(const Cylinder& s);
|
||||||
|
static void deleteGJKObject(void* o);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Sphere */
|
||||||
|
template<>
|
||||||
|
class GJKInitializer<Sphere>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GJKSupportFunction getSupportFunction();
|
||||||
|
static GJKCenterFunction getCenterFunction();
|
||||||
|
static void* createGJKObject(const Sphere& s);
|
||||||
|
static void deleteGJKObject(void* o);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Box */
|
||||||
|
template<>
|
||||||
|
class GJKInitializer<Box>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GJKSupportFunction getSupportFunction();
|
||||||
|
static GJKCenterFunction getCenterFunction();
|
||||||
|
static void* createGJKObject(const Box& s);
|
||||||
|
static void deleteGJKObject(void* o);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Capsule */
|
||||||
|
template<>
|
||||||
|
class GJKInitializer<Capsule>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GJKSupportFunction getSupportFunction();
|
||||||
|
static GJKCenterFunction getCenterFunction();
|
||||||
|
static void* createGJKObject(const Capsule& s);
|
||||||
|
static void deleteGJKObject(void* o);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Cone */
|
||||||
|
template<>
|
||||||
|
class GJKInitializer<Cone>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GJKSupportFunction getSupportFunction();
|
||||||
|
static GJKCenterFunction getCenterFunction();
|
||||||
|
static void* createGJKObject(const Cone& s);
|
||||||
|
static void deleteGJKObject(void* o);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Convex */
|
||||||
|
template<>
|
||||||
|
class GJKInitializer<Convex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static GJKSupportFunction getSupportFunction();
|
||||||
|
static GJKCenterFunction getCenterFunction();
|
||||||
|
static void* createGJKObject(const Convex& s);
|
||||||
|
static void deleteGJKObject(void* o);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief initialize GJK Triangle */
|
||||||
|
GJKSupportFunction triGetSupportFunction();
|
||||||
|
|
||||||
|
GJKCenterFunction triGetCenterFunction();
|
||||||
|
|
||||||
|
void* triCreateGJKObject(const Vec3f& P1, const Vec3f& P2, const Vec3f& P3);
|
||||||
|
|
||||||
|
void* triCreateGJKObject(const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Vec3f R[3], const Vec3f& T);
|
||||||
|
|
||||||
|
void triDeleteGJKObject(void* o);
|
||||||
|
|
||||||
|
/** \brief GJK collision algorithm */
|
||||||
|
bool GJKCollide(void* obj1, ccd_support_fn supp1, ccd_center_fn cen1,
|
||||||
|
void* obj2, ccd_support_fn supp2, ccd_center_fn cen2,
|
||||||
|
Vec3f* contact_points, BVH_REAL* penetration_depth, Vec3f* normal);
|
||||||
|
|
||||||
|
|
||||||
|
/** intersection checking between two shapes */
|
||||||
|
template<typename S1, typename S2>
|
||||||
|
bool shapeIntersect(const S1& s1, const S2& s2, Vec3f* contact_points = NULL, BVH_REAL* penetration_depth = NULL, Vec3f* normal = NULL)
|
||||||
|
{
|
||||||
|
void* o1 = GJKInitializer<S1>::createGJKObject(s1);
|
||||||
|
void* o2 = GJKInitializer<S2>::createGJKObject(s2);
|
||||||
|
|
||||||
|
return GJKCollide(o1, GJKInitializer<S1>::getSupportFunction(), GJKInitializer<S1>::getCenterFunction(),
|
||||||
|
o2, GJKInitializer<S2>::getSupportFunction(), GJKInitializer<S2>::getCenterFunction(),
|
||||||
|
contact_points, penetration_depth, normal);
|
||||||
|
|
||||||
|
GJKInitializer<S1>::deleteGJKObject(o1);
|
||||||
|
GJKInitializer<S2>::deleteGJKObject(o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief intersection checking between one shape and a triangle */
|
||||||
|
template<typename S>
|
||||||
|
bool shapeTriangleIntersect(const S& s, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, Vec3f* contact_points = NULL, BVH_REAL* penetration_depth = NULL, Vec3f* normal = NULL)
|
||||||
|
{
|
||||||
|
void* o1 = GJKInitializer<S>::createGJKObject(s);
|
||||||
|
void* o2 = triCreateGJKObject(P1, P2, P3);
|
||||||
|
|
||||||
|
return GJKCollide(o1, GJKInitializer<S>::getSupportFunction(), GJKInitializer<S>::getCenterFunction(),
|
||||||
|
o2, triGetSupportFunction(), triGetCenterFunction(),
|
||||||
|
contact_points, penetration_depth, normal);
|
||||||
|
|
||||||
|
GJKInitializer<S>::deleteGJKObject(o1);
|
||||||
|
triDeleteGJKObject(o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief intersection checking between one shape and a triangle with transformation */
|
||||||
|
template<typename S>
|
||||||
|
bool shapeTriangleIntersect(const S& s, const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Vec3f R[3], const Vec3f& T,
|
||||||
|
Vec3f* contact_points = NULL, BVH_REAL* penetration_depth = NULL, Vec3f* normal = NULL)
|
||||||
|
{
|
||||||
|
void* o1 = GJKInitializer<S>::createGJKObject(s);
|
||||||
|
void* o2 = triCreateGJKObject(P1, P2, P3, R, T);
|
||||||
|
|
||||||
|
return GJKCollide(o1, GJKInitializer<S>::getSupportFunction(), GJKInitializer<S>::getCenterFunction(),
|
||||||
|
o2, triGetSupportFunction(), triGetCenterFunction(),
|
||||||
|
contact_points, penetration_depth, normal);
|
||||||
|
|
||||||
|
GJKInitializer<S>::deleteGJKObject(o1);
|
||||||
|
triDeleteGJKObject(o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_GEOMETRIC_SHAPES_UTILITY_H
|
||||||
|
#define FCL_GEOMETRIC_SHAPES_UTILITY_H
|
||||||
|
|
||||||
|
#include "fcl/geometric_shapes.h"
|
||||||
|
#include "fcl/BV.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Box& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Sphere& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Capsule& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Cone& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Cylinder& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Convex& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
/** the bounding volume for half space back of plane
|
||||||
|
* for OBB, it is the plane itself
|
||||||
|
*/
|
||||||
|
template<typename BV>
|
||||||
|
void computeBV(const Plane& /*s*/, BV& /*bv*/) {}
|
||||||
|
|
||||||
|
/** For AABB */
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Box& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Sphere& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Capsule& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Cone& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Cylinder& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Convex& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<AABB>(const Plane& s, AABB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Box& s, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Sphere& s, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Capsule& s, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Cone& s, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Cylinder& s, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Convex& s, OBB& bv);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void computeBV<OBB>(const Plane& s, OBB& bv);
|
||||||
|
|
||||||
|
// TODO: implement computeBV for RSS and KDOP
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_INTERSECT_H
|
||||||
|
#define FCL_INTERSECT_H
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/primitive.h"
|
||||||
|
|
||||||
|
#if USE_SVMLIGHT
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
# include <svm_light/svm_common.h>
|
||||||
|
# include <svm_light/svm_learn.h>
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief A class solves polynomial degree (1,2,3) equations */
|
||||||
|
class PolySolver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Solve a linear equation with coefficients c, return roots s and number of roots */
|
||||||
|
static int solveLinear(BVH_REAL c[2], BVH_REAL s[1]);
|
||||||
|
|
||||||
|
/** \brief Solve a quadratic function with coefficients c, return roots s and number of roots */
|
||||||
|
static int solveQuadric(BVH_REAL c[3], BVH_REAL s[2]);
|
||||||
|
|
||||||
|
/** \brief Solve a cubic function with coefficients c, return roots s and number of roots */
|
||||||
|
static int solveCubic(BVH_REAL c[4], BVH_REAL s[3]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** \brief Check whether v is zero */
|
||||||
|
static inline bool isZero(BVH_REAL v);
|
||||||
|
|
||||||
|
/** \brief Compute v^{1/3} */
|
||||||
|
static inline bool cbrt(BVH_REAL v);
|
||||||
|
|
||||||
|
static const BVH_REAL NEAR_ZERO_THRESHOLD;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if USE_SVMLIGHT
|
||||||
|
class CloudClassifierParam
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LEARN_PARM learn_parm;
|
||||||
|
KERNEL_PARM kernel_parm;
|
||||||
|
|
||||||
|
CloudClassifierParam();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief CCD intersect kernel among primitives */
|
||||||
|
class Intersect
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief CCD intersect between one vertex and one face
|
||||||
|
* [a0, b0, c0] and [a1, b1, c1] are points for the triangle face in time t0 and t1
|
||||||
|
* p0 and p1 are points for vertex in time t0 and t1
|
||||||
|
* p_i returns the coordinate of the collision point
|
||||||
|
*/
|
||||||
|
static bool intersect_VF(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& p0,
|
||||||
|
const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& p1,
|
||||||
|
BVH_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
|
||||||
|
|
||||||
|
/** \brief CCD intersect between two edges
|
||||||
|
* [a0, b0] and [a1, b1] are points for one edge in time t0 and t1
|
||||||
|
* [c0, d0] and [c1, d1] are points for the other edge in time t0 and t1
|
||||||
|
* p_i returns the coordinate of the collision point
|
||||||
|
*/
|
||||||
|
static bool intersect_EE(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1,
|
||||||
|
BVH_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
|
||||||
|
|
||||||
|
/** \brief CCD intersect between one vertex and one face, using additional filter */
|
||||||
|
static bool intersect_VF_filtered(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& p0,
|
||||||
|
const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& p1,
|
||||||
|
BVH_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
|
||||||
|
|
||||||
|
/** \brief CCD intersect between two edges, using additional filter */
|
||||||
|
static bool intersect_EE_filtered(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1,
|
||||||
|
BVH_REAL* collision_time, Vec3f* p_i, bool useNewton = true);
|
||||||
|
|
||||||
|
/** \brief CCD intersect between one vertex and and one edge */
|
||||||
|
static bool intersect_VE(const Vec3f& a0, const Vec3f& b0, const Vec3f& p0,
|
||||||
|
const Vec3f& a1, const Vec3f& b1, const Vec3f& p1,
|
||||||
|
const Vec3f& L);
|
||||||
|
|
||||||
|
/** \brief CD intersect between two triangles [P1, P2, P3] and [Q1, Q2, Q3] */
|
||||||
|
static bool intersect_Triangle(const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
|
||||||
|
const Vec3f& Q1, const Vec3f& Q2, const Vec3f& Q3,
|
||||||
|
Vec3f* contact_points = NULL,
|
||||||
|
unsigned int* num_contact_points = NULL,
|
||||||
|
BVH_REAL* penetration_depth = NULL,
|
||||||
|
Vec3f* normal = NULL);
|
||||||
|
|
||||||
|
static bool intersect_Triangle(const Vec3f& P1, const Vec3f& P2, const Vec3f& P3,
|
||||||
|
const Vec3f& Q1, const Vec3f& Q2, const Vec3f& Q3,
|
||||||
|
const Vec3f R[3], const Vec3f& T,
|
||||||
|
Vec3f* contact_points = NULL,
|
||||||
|
unsigned int* num_contact_points = NULL,
|
||||||
|
BVH_REAL* penetration_depth = NULL,
|
||||||
|
Vec3f* normal = NULL);
|
||||||
|
|
||||||
|
#if USE_SVMLIGHT
|
||||||
|
|
||||||
|
static BVH_REAL intersect_PointClouds(Vec3f* cloud1, Uncertainty* uc1, int size_cloud1,
|
||||||
|
Vec3f* cloud2, Uncertainty* uc2, int size_cloud2,
|
||||||
|
const CloudClassifierParam& solver, bool scaling = true);
|
||||||
|
|
||||||
|
static BVH_REAL intersect_PointClouds(Vec3f* cloud1, Uncertainty* uc1, int size_cloud1,
|
||||||
|
Vec3f* cloud2, Uncertainty* uc2, int size_cloud2,
|
||||||
|
const Vec3f R[3], const Vec3f& T, const CloudClassifierParam& solver, bool scaling = true);
|
||||||
|
|
||||||
|
static BVH_REAL intersect_PointCloudsTriangle(Vec3f* cloud1, Uncertainty* uc1, int size_cloud1,
|
||||||
|
const Vec3f& Q1, const Vec3f& Q2, const Vec3f& Q3);
|
||||||
|
|
||||||
|
static BVH_REAL intersect_PointCloudsTriangle(Vec3f* cloud1, Uncertainty* uc1, int size_cloud1,
|
||||||
|
const Vec3f& Q1, const Vec3f& Q2, const Vec3f& Q3,
|
||||||
|
const Vec3f R[3], const Vec3f& T);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** \brief Project function used in intersect_Triangle() */
|
||||||
|
static int project6(const Vec3f& ax,
|
||||||
|
const Vec3f& p1, const Vec3f& p2, const Vec3f& p3,
|
||||||
|
const Vec3f& q1, const Vec3f& q2, const Vec3f& q3);
|
||||||
|
|
||||||
|
/** \brief Check whether one value is zero */
|
||||||
|
static inline bool isZero(BVH_REAL v);
|
||||||
|
|
||||||
|
/** \brief Solve the cubic function using Newton method, also satisfies the interval restriction */
|
||||||
|
static bool solveCubicWithIntervalNewton(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vc, const Vec3f& vd,
|
||||||
|
BVH_REAL& l, BVH_REAL& r, bool bVF, BVH_REAL coeffs[], Vec3f* data = NULL);
|
||||||
|
|
||||||
|
/** \brief Check whether one point p is within triangle [a, b, c] */
|
||||||
|
static bool insideTriangle(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f&p);
|
||||||
|
|
||||||
|
/** \brief Check whether one point p is within a line segment [a, b] */
|
||||||
|
static bool insideLineSegment(const Vec3f& a, const Vec3f& b, const Vec3f& p);
|
||||||
|
|
||||||
|
/** \brief Calculate the line segment papb that is the shortest route between
|
||||||
|
* two lines p1p2 and p3p4. Calculate also the values of mua and mub where
|
||||||
|
* pa = p1 + mua (p2 - p1)
|
||||||
|
* pb = p3 + mub (p4 - p3)
|
||||||
|
* return FALSE if no solution exists.
|
||||||
|
*/
|
||||||
|
static bool linelineIntersect(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3, const Vec3f& p4,
|
||||||
|
Vec3f* pa, Vec3f* pb, BVH_REAL* mua, BVH_REAL* mub);
|
||||||
|
|
||||||
|
/** \brief Check whether a root for VF intersection is valid (i.e. within the triangle at intersection t */
|
||||||
|
static bool checkRootValidity_VF(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& p0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vc, const Vec3f& vp,
|
||||||
|
BVH_REAL t);
|
||||||
|
|
||||||
|
/** \brief Check whether a root for EE intersection is valid (i.e. within the two edges intersected at the given time */
|
||||||
|
static bool checkRootValidity_EE(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vc, const Vec3f& vd,
|
||||||
|
BVH_REAL t, Vec3f* q_i = NULL);
|
||||||
|
|
||||||
|
/** \brief Check whether a root for VE intersection is valid */
|
||||||
|
static bool checkRootValidity_VE(const Vec3f& a0, const Vec3f& b0, const Vec3f& p0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vp,
|
||||||
|
BVH_REAL t);
|
||||||
|
|
||||||
|
/** \brief Solve a square function for EE intersection (with interval restriction) */
|
||||||
|
static bool solveSquare(BVH_REAL a, BVH_REAL b, BVH_REAL c,
|
||||||
|
const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vc, const Vec3f& vd,
|
||||||
|
bool bVF,
|
||||||
|
BVH_REAL* ret);
|
||||||
|
|
||||||
|
/** \brief Solve a square function for VE intersection (with interval restriction) */
|
||||||
|
static bool solveSquare(BVH_REAL a, BVH_REAL b, BVH_REAL c,
|
||||||
|
const Vec3f& a0, const Vec3f& b0, const Vec3f& p0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vp);
|
||||||
|
|
||||||
|
/** \brief Compute the cubic coefficients for VF intersection
|
||||||
|
* See Paper "Interactive Continuous Collision Detection between Deformable Models using Connectivity-Based Culling", Equation 1.
|
||||||
|
*/
|
||||||
|
static void computeCubicCoeff_VF(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& p0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vc, const Vec3f& vp,
|
||||||
|
BVH_REAL* a, BVH_REAL* b, BVH_REAL* c, BVH_REAL* d);
|
||||||
|
|
||||||
|
/** \brief Compute the cubic coefficients for EE intersection */
|
||||||
|
static void computeCubicCoeff_EE(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vc, const Vec3f& vd,
|
||||||
|
BVH_REAL* a, BVH_REAL* b, BVH_REAL* c, BVH_REAL* d);
|
||||||
|
|
||||||
|
/** \brief Compute the cubic coefficients for VE intersection */
|
||||||
|
static void computeCubicCoeff_VE(const Vec3f& a0, const Vec3f& b0, const Vec3f& p0,
|
||||||
|
const Vec3f& va, const Vec3f& vb, const Vec3f& vp,
|
||||||
|
const Vec3f& L,
|
||||||
|
BVH_REAL* a, BVH_REAL* b, BVH_REAL* c);
|
||||||
|
|
||||||
|
/** \brief filter for intersection, works for both VF and EE */
|
||||||
|
static bool intersectPreFiltering(const Vec3f& a0, const Vec3f& b0, const Vec3f& c0, const Vec3f& d0,
|
||||||
|
const Vec3f& a1, const Vec3f& b1, const Vec3f& c1, const Vec3f& d1);
|
||||||
|
|
||||||
|
/** \brief distance of point v to a plane n * x - t = 0 */
|
||||||
|
static BVH_REAL distanceToPlane(const Vec3f& n, BVH_REAL t, const Vec3f& v);
|
||||||
|
|
||||||
|
/** \brief check wether points v1, v2, v2 are on the same side of plane n * x - t = 0 */
|
||||||
|
static bool sameSideOfPlane(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, const Vec3f& n, BVH_REAL t);
|
||||||
|
|
||||||
|
/** \brief clip triangle v1, v2, v3 by the prism made by t1, t2 and t3. The normal of the prism is tn and is cutted up by to */
|
||||||
|
static void clipTriangleByTriangleAndEdgePlanes(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3,
|
||||||
|
const Vec3f& t1, const Vec3f& t2, const Vec3f& t3,
|
||||||
|
const Vec3f& tn, BVH_REAL to,
|
||||||
|
Vec3f clipped_points[], unsigned int* num_clipped_points, bool clip_triangle = false);
|
||||||
|
|
||||||
|
/** \brief build a plane passed through triangle v1 v2 v3 */
|
||||||
|
static bool buildTrianglePlane(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3, Vec3f* n, BVH_REAL* t);
|
||||||
|
|
||||||
|
/** \brief build a plane pass through edge v1 and v2, normal is tn */
|
||||||
|
static bool buildEdgePlane(const Vec3f& v1, const Vec3f& v2, const Vec3f& tn, Vec3f* n, BVH_REAL* t);
|
||||||
|
|
||||||
|
/** \brief compute the points which has deepest penetration depth */
|
||||||
|
static void computeDeepestPoints(Vec3f* clipped_points, unsigned int num_clipped_points, const Vec3f& n, BVH_REAL t, BVH_REAL* penetration_depth, Vec3f* deepest_points, unsigned int* num_deepest_points);
|
||||||
|
|
||||||
|
/** \brief clip polygon by plane */
|
||||||
|
static void clipPolygonByPlane(Vec3f* polygon_points, unsigned int num_polygon_points, const Vec3f& n, BVH_REAL t, Vec3f clipped_points[], unsigned int* num_clipped_points);
|
||||||
|
|
||||||
|
/** \brief clip a line segment by plane */
|
||||||
|
static void clipSegmentByPlane(const Vec3f& v1, const Vec3f& v2, const Vec3f& n, BVH_REAL t, Vec3f* clipped_point);
|
||||||
|
|
||||||
|
/** \brief compute the cdf(x) */
|
||||||
|
static BVH_REAL gaussianCDF(BVH_REAL x)
|
||||||
|
{
|
||||||
|
return 0.5 * erfc(-x / sqrt(2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_SVMLIGHT
|
||||||
|
/** \brief compute the d K(x0, x) / dx, where x is one 3d point on or near the classification surface, and K is a composite kernel */
|
||||||
|
static void kernelGradient(KERNEL_PARM *kernel_parm, DOC *a, DOC *b, Vec3f& g);
|
||||||
|
|
||||||
|
/** \brief compute the d K(x0, x) / dx, where x is one 3d point on or near the classification surface, and K is a single kernel */
|
||||||
|
static void singleKernelGradient(KERNEL_PARM *kernel_parm, SVECTOR *a, SVECTOR *b, Vec3f& g);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const BVH_REAL EPSILON;
|
||||||
|
static const BVH_REAL NEAR_ZERO_THRESHOLD;
|
||||||
|
static const BVH_REAL CCD_RESOLUTION;
|
||||||
|
static const unsigned int MAX_TRIANGLE_CLIPS = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TriangleDistance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief Returns closest points between an segment pair.
|
||||||
|
* The first segment is P + t * A
|
||||||
|
* The second segment is Q + t * B
|
||||||
|
* X, Y are the closest points on the two segments
|
||||||
|
* VEC is the vector between X and Y
|
||||||
|
*/
|
||||||
|
static void segPoints(const Vec3f& P, const Vec3f& A, const Vec3f& Q, const Vec3f& B,
|
||||||
|
Vec3f& VEC, Vec3f& X, Vec3f& Y);
|
||||||
|
|
||||||
|
/** \brief Compute the closest points on two triangles given their absolute coordinate, and returns the distance between them
|
||||||
|
* S and T are two triangles
|
||||||
|
* 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 from the triangles, not
|
||||||
|
* coincident points on the intersection of the triangles, as might be expected.
|
||||||
|
*/
|
||||||
|
static BVH_REAL triDistance(const Vec3f S[3], const Vec3f T[3], Vec3f& P, Vec3f& Q);
|
||||||
|
|
||||||
|
static BVH_REAL triDistance(const Vec3f& S1, const Vec3f& S2, const Vec3f& S3,
|
||||||
|
const Vec3f& T1, const Vec3f& T2, const Vec3f& T3,
|
||||||
|
Vec3f& P, Vec3f& Q);
|
||||||
|
|
||||||
|
/** \brief Compute the closest points on two triangles given the relative transform between them, and returns the distance between them
|
||||||
|
* S and T are two triangles
|
||||||
|
* 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 from the triangles, not
|
||||||
|
* coincident points on the intersection of the triangles, as might be expected.
|
||||||
|
* The returned P and Q are both in the coordinate of the first triangle's coordinate
|
||||||
|
*/
|
||||||
|
static BVH_REAL triDistance(const Vec3f S[3], const Vec3f T[3],
|
||||||
|
const Vec3f R[3], const Vec3f& Tl,
|
||||||
|
Vec3f& P, Vec3f& Q);
|
||||||
|
|
||||||
|
static BVH_REAL triDistance(const Vec3f& S1, const Vec3f& S2, const Vec3f& S3,
|
||||||
|
const Vec3f& T1, const Vec3f& T2, const Vec3f& T3,
|
||||||
|
const Vec3f R[3], const Vec3f& Tl,
|
||||||
|
Vec3f& P, Vec3f& Q);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_INTERVAL_TREE_H
|
||||||
|
#define FCL_INTERVAL_TREE_H
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Interval trees implemented using red-black-trees as described in
|
||||||
|
* the book Introduction_To_Algorithms_ by Cormen, Leisserson, and Rivest.
|
||||||
|
* Can be replaced in part by boost::icl::interval_set, which is only supported after boost 1.46 and does not support delete node routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Interval
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Interval() {}
|
||||||
|
virtual ~Interval() {}
|
||||||
|
virtual void print() {}
|
||||||
|
|
||||||
|
double low, high;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IntervalTreeNode
|
||||||
|
{
|
||||||
|
friend class IntervalTree;
|
||||||
|
public:
|
||||||
|
/** \brief Print the interval node information: set left = nil and right = root */
|
||||||
|
void print(IntervalTreeNode* left, IntervalTreeNode* right) const;
|
||||||
|
|
||||||
|
IntervalTreeNode();
|
||||||
|
|
||||||
|
IntervalTreeNode(Interval* new_interval);
|
||||||
|
|
||||||
|
~IntervalTreeNode();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Interval* stored_interval;
|
||||||
|
|
||||||
|
double key;
|
||||||
|
|
||||||
|
double high;
|
||||||
|
|
||||||
|
double max_high;
|
||||||
|
|
||||||
|
bool red; /* if red = false then the node is black */
|
||||||
|
|
||||||
|
IntervalTreeNode* left;
|
||||||
|
|
||||||
|
IntervalTreeNode* right;
|
||||||
|
|
||||||
|
IntervalTreeNode* parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Class describes the information needed when we take the
|
||||||
|
* right branch in searching for intervals but possibly come back
|
||||||
|
* and check the left branch as well.
|
||||||
|
*/
|
||||||
|
struct it_recursion_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IntervalTreeNode* start_node;
|
||||||
|
|
||||||
|
unsigned int parent_index;
|
||||||
|
|
||||||
|
bool try_right_branch;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Interval tree */
|
||||||
|
class IntervalTree
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
IntervalTree();
|
||||||
|
|
||||||
|
~IntervalTree();
|
||||||
|
|
||||||
|
/** \brief Print the whole interval tree */
|
||||||
|
void print() const;
|
||||||
|
|
||||||
|
/** \brief Delete one node of the interval tree */
|
||||||
|
Interval* deleteNode(IntervalTreeNode* node);
|
||||||
|
|
||||||
|
/** \brief Insert one node of the interval tree */
|
||||||
|
IntervalTreeNode* insert(Interval* new_interval);
|
||||||
|
|
||||||
|
/** \brief get the predecessor of a given node */
|
||||||
|
IntervalTreeNode* getPredecessor(IntervalTreeNode* node) const;
|
||||||
|
|
||||||
|
/** \brief Get the successor of a given node */
|
||||||
|
IntervalTreeNode* getSuccessor(IntervalTreeNode* node) const;
|
||||||
|
|
||||||
|
/** \brief Return result for a given query */
|
||||||
|
std::deque<Interval*> query(double low, double high);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
IntervalTreeNode* root;
|
||||||
|
|
||||||
|
IntervalTreeNode* nil;
|
||||||
|
|
||||||
|
/** \brief left rotation of tree node */
|
||||||
|
void leftRotate(IntervalTreeNode* node);
|
||||||
|
|
||||||
|
/** \brief right rotation of tree node */
|
||||||
|
void rightRotate(IntervalTreeNode* node);
|
||||||
|
|
||||||
|
/** \brief recursively insert a node */
|
||||||
|
void recursiveInsert(IntervalTreeNode* node);
|
||||||
|
|
||||||
|
/** \brief recursively print a subtree */
|
||||||
|
void recursivePrint(IntervalTreeNode* node) const;
|
||||||
|
|
||||||
|
/** \brief Travels up to the root fixing the max_high fields after an insertion or deletion */
|
||||||
|
void fixupMaxHigh(IntervalTreeNode* node);
|
||||||
|
|
||||||
|
void deleteFixup(IntervalTreeNode* node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int recursion_node_stack_size;
|
||||||
|
it_recursion_node* recursion_node_stack;
|
||||||
|
unsigned int current_parent;
|
||||||
|
unsigned int recursion_node_stack_top;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,294 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_KDOP_H
|
||||||
|
#define FCL_KDOP_H
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <limits>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Find the smaller and larger one of two values */
|
||||||
|
inline void minmax(BVH_REAL a, BVH_REAL b, BVH_REAL& minv, BVH_REAL& maxv)
|
||||||
|
{
|
||||||
|
if(a > b)
|
||||||
|
{
|
||||||
|
minv = b;
|
||||||
|
maxv = a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minv = a;
|
||||||
|
maxv = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** \brief Merge the interval [minv, maxv] and value p */
|
||||||
|
inline void minmax(BVH_REAL p, BVH_REAL& minv, BVH_REAL& maxv)
|
||||||
|
{
|
||||||
|
if(p > maxv) maxv = p;
|
||||||
|
if(p < minv) minv = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Compute the distances to planes with normals from KDOP vectors except those of AABB face planes */
|
||||||
|
template<size_t N>
|
||||||
|
void getDistances(const Vec3f& p, BVH_REAL d[]) {}
|
||||||
|
|
||||||
|
/** \brief Specification of getDistances */
|
||||||
|
template<>
|
||||||
|
inline void getDistances<5>(const Vec3f& p, BVH_REAL d[])
|
||||||
|
{
|
||||||
|
d[0] = p[0] + p[1];
|
||||||
|
d[1] = p[0] + p[2];
|
||||||
|
d[2] = p[1] + p[2];
|
||||||
|
d[3] = p[0] - p[1];
|
||||||
|
d[4] = p[0] - p[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void getDistances<6>(const Vec3f& p, BVH_REAL d[])
|
||||||
|
{
|
||||||
|
d[0] = p[0] + p[1];
|
||||||
|
d[1] = p[0] + p[2];
|
||||||
|
d[2] = p[1] + p[2];
|
||||||
|
d[3] = p[0] - p[1];
|
||||||
|
d[4] = p[0] - p[2];
|
||||||
|
d[5] = p[1] - p[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void getDistances<9>(const Vec3f& p, BVH_REAL d[])
|
||||||
|
{
|
||||||
|
d[0] = p[0] + p[1];
|
||||||
|
d[1] = p[0] + p[2];
|
||||||
|
d[2] = p[1] + p[2];
|
||||||
|
d[3] = p[0] - p[1];
|
||||||
|
d[4] = p[0] - p[2];
|
||||||
|
d[5] = p[1] - p[2];
|
||||||
|
d[6] = p[0] + p[1] - p[2];
|
||||||
|
d[7] = p[0] + p[2] - p[1];
|
||||||
|
d[8] = p[1] + p[2] - p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \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 = 18, the planes are 6 AABB planes and 12 diagonal planes that cut off some space of the edges:
|
||||||
|
(-1,0,0) and (1,0,0) -> indices 0 and 9
|
||||||
|
(0,-1,0) and (0,1,0) -> indices 1 and 10
|
||||||
|
(0,0,-1) and (0,0,1) -> indices 2 and 11
|
||||||
|
(-1,-1,0) and (1,1,0) -> indices 3 and 12
|
||||||
|
(-1,0,-1) and (1,0,1) -> indices 4 and 13
|
||||||
|
(0,-1,-1) and (0,1,1) -> indices 5 and 14
|
||||||
|
(-1,1,0) and (1,-1,0) -> indices 6 and 15
|
||||||
|
(-1,0,1) and (1,0,-1) -> indices 7 and 16
|
||||||
|
(0,-1,1) and (0,1,-1) -> indices 8 and 17
|
||||||
|
*/
|
||||||
|
template<size_t N>
|
||||||
|
class KDOP
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KDOP()
|
||||||
|
{
|
||||||
|
BVH_REAL real_max = std::numeric_limits<BVH_REAL>::max();
|
||||||
|
for(size_t i = 0; i < N / 2; ++i)
|
||||||
|
{
|
||||||
|
dist_[i] = real_max;
|
||||||
|
dist_[i + N / 2] = -real_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KDOP(const Vec3f& v)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
dist_[i] = dist_[N / 2 + i] = v[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL d[(N - 6) / 2];
|
||||||
|
getDistances<(N - 6) / 2>(v, d);
|
||||||
|
for(size_t i = 0; i < (N - 6) / 2; ++i)
|
||||||
|
{
|
||||||
|
dist_[3 + i] = dist_[3 + i + N / 2] = d[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KDOP(const Vec3f& a, const Vec3f& b)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
minmax(a[i], b[i], dist_[i], dist_[i + N / 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL ad[(N - 6) / 2], bd[(N - 6) / 2];
|
||||||
|
getDistances<(N - 6) / 2>(a, ad);
|
||||||
|
getDistances<(N - 6) / 2>(b, bd);
|
||||||
|
for(size_t i = 0; i < (N - 6) / 2; ++i)
|
||||||
|
{
|
||||||
|
minmax(ad[i], bd[i], dist_[3 + i], dist_[3 + i + N / 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Check whether two KDOPs are overlapped */
|
||||||
|
inline bool overlap(const KDOP<N>& other) const
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < N / 2; ++i)
|
||||||
|
{
|
||||||
|
if(dist_[i] > other.dist_[i + N / 2]) return false;
|
||||||
|
if(dist_[i + N / 2] < other.dist_[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Check whether one point is inside the KDOP */
|
||||||
|
inline bool inside(const Vec3f& p) const
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if(p[i] < dist_[i] || p[i] > dist_[i + N / 2])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL d[(N - 6) / 2];
|
||||||
|
getDistances(p, d);
|
||||||
|
for(size_t i = 0; i < (N - 6) / 2; ++i)
|
||||||
|
{
|
||||||
|
if(d[i] < dist_[3 + i] || d[i] > dist_[i + 3 + N / 2])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Merge the point and the KDOP */
|
||||||
|
inline KDOP<N>& operator += (const Vec3f& p)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
minmax(p[i], dist_[i], dist_[N / 2 + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL pd[(N - 6) / 2];
|
||||||
|
getDistances<(N - 6) / 2>(p, pd);
|
||||||
|
for(size_t i = 0; i < (N - 6) / 2; ++i)
|
||||||
|
{
|
||||||
|
minmax(pd[i], dist_[3 + i], dist_[3 + N / 2 + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Merge two KDOPs */
|
||||||
|
inline KDOP<N>& operator += (const KDOP<N>& other)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < N / 2; ++i)
|
||||||
|
{
|
||||||
|
dist_[i] = std::min(other.dist_[i], dist_[i]);
|
||||||
|
dist_[i + N / 2] = std::max(other.dist_[i + N / 2], dist_[i + N / 2]);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Create a KDOP by mergin two KDOPs */
|
||||||
|
inline KDOP<N> operator + (const KDOP<N>& other) const
|
||||||
|
{
|
||||||
|
KDOP<N> res(*this);
|
||||||
|
return res += other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The (AABB) width */
|
||||||
|
inline BVH_REAL width() const
|
||||||
|
{
|
||||||
|
return dist_[N / 2] - dist_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The (AABB) height */
|
||||||
|
inline BVH_REAL height() const
|
||||||
|
{
|
||||||
|
return dist_[N / 2 + 1] - dist_[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The (AABB) depth */
|
||||||
|
inline BVH_REAL depth() const
|
||||||
|
{
|
||||||
|
return dist_[N / 2 + 2] - dist_[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The (AABB) volume */
|
||||||
|
inline BVH_REAL volume() const
|
||||||
|
{
|
||||||
|
return width() * height() * depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline BVH_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.
|
||||||
|
*/
|
||||||
|
BVH_REAL distance(const KDOP<N>& other, Vec3f* P = NULL, Vec3f* Q = NULL) const
|
||||||
|
{
|
||||||
|
std::cerr << "KDOP distance not implemented!" << std::endl;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** \brief distances to N KDOP planes */
|
||||||
|
BVH_REAL dist_[N];
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,660 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_MOTION_H
|
||||||
|
#define FCL_MOTION_H
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/RSS.h"
|
||||||
|
#include "fcl/transform.h"
|
||||||
|
#include "fcl/motion_base.h"
|
||||||
|
#include "fcl/intersect.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
class SplineMotion : public MotionBase<BV>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Construct motion from 4 deBoor points */
|
||||||
|
SplineMotion(const Vec3f& Td0, const Vec3f& Td1, const Vec3f& Td2, const Vec3f& Td3,
|
||||||
|
const Vec3f& Rd0, const Vec3f& Rd1, const Vec3f& Rd2, const Vec3f& Rd3)
|
||||||
|
{
|
||||||
|
Td[0] = Td0;
|
||||||
|
Td[1] = Td1;
|
||||||
|
Td[2] = Td2;
|
||||||
|
Td[3] = Td3;
|
||||||
|
|
||||||
|
Rd[0] = Rd0;
|
||||||
|
Rd[1] = Rd1;
|
||||||
|
Rd[2] = Rd2;
|
||||||
|
Rd[3] = Rd3;
|
||||||
|
|
||||||
|
Rd0Rd0 = Rd[0].dot(Rd[0]);
|
||||||
|
Rd0Rd1 = Rd[0].dot(Rd[1]);
|
||||||
|
Rd0Rd2 = Rd[0].dot(Rd[2]);
|
||||||
|
Rd0Rd3 = Rd[0].dot(Rd[3]);
|
||||||
|
Rd1Rd1 = Rd[1].dot(Rd[1]);
|
||||||
|
Rd1Rd2 = Rd[1].dot(Rd[2]);
|
||||||
|
Rd1Rd3 = Rd[1].dot(Rd[3]);
|
||||||
|
Rd2Rd2 = Rd[2].dot(Rd[2]);
|
||||||
|
Rd2Rd3 = Rd[2].dot(Rd[3]);
|
||||||
|
Rd3Rd3 = Rd[3].dot(Rd[3]);
|
||||||
|
|
||||||
|
TA = Td[1] * 3 - Td[2] * 3 + Td[3] - Td[0];
|
||||||
|
TB = (Td[0] - Td[1] * 2 + Td[2]) * 3;
|
||||||
|
TC = (Td[2] - Td[0]) * 3;
|
||||||
|
|
||||||
|
RA = Rd[1] * 3 - Rd[2] * 3 + Rd[3] - Rd[0];
|
||||||
|
RB = (Rd[0] - Rd[1] * 2 + Rd[2]) * 3;
|
||||||
|
RC = (Rd[2] - Rd[0]) * 3;
|
||||||
|
|
||||||
|
integrate(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Integrate the motion from 0 to dt
|
||||||
|
* We compute the current transformation from zero point instead of from last integrate time, for precision.
|
||||||
|
*/
|
||||||
|
bool integrate(double dt)
|
||||||
|
{
|
||||||
|
if(dt > 1) dt = 1;
|
||||||
|
|
||||||
|
Vec3f cur_T = Td[0] * getWeight0(dt) + Td[1] * getWeight1(dt) + Td[2] * getWeight2(dt) + Td[3] * getWeight3(dt);
|
||||||
|
Vec3f cur_w = Rd[0] * getWeight0(dt) + Rd[1] * getWeight1(dt) + Rd[2] * getWeight2(dt) + Rd[3] * getWeight3(dt);
|
||||||
|
BVH_REAL cur_angle = cur_w.length();
|
||||||
|
cur_w.normalize();
|
||||||
|
|
||||||
|
SimpleQuaternion cur_q;
|
||||||
|
cur_q.fromAxisAngle(cur_w, cur_angle);
|
||||||
|
|
||||||
|
tf.setTransform(cur_q, cur_T);
|
||||||
|
|
||||||
|
tf_t = dt;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a bounding volume along a given direction n
|
||||||
|
* For general BV, not implemented so return trivial 0
|
||||||
|
*/
|
||||||
|
BVH_REAL computeMotionBound(const BV& bv, const Vec3f& n) const { return 0.0; }
|
||||||
|
|
||||||
|
BVH_REAL computeMotionBound(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& n) const
|
||||||
|
{
|
||||||
|
BVH_REAL T_bound = computeTBound(n);
|
||||||
|
|
||||||
|
BVH_REAL R_bound = fabs(a.dot(n)) + a.length() + (a.cross(n)).length();
|
||||||
|
BVH_REAL R_bound_tmp = fabs(b.dot(n)) + b.length() + (b.cross(n)).length();
|
||||||
|
if(R_bound_tmp > R_bound) R_bound = R_bound_tmp;
|
||||||
|
R_bound_tmp = fabs(c.dot(n)) + c.length() + (c.cross(n)).length();
|
||||||
|
if(R_bound_tmp > R_bound) R_bound = R_bound_tmp;
|
||||||
|
|
||||||
|
BVH_REAL dWdW_max = computeDWMax();
|
||||||
|
BVH_REAL ratio = std::min(1 - tf_t, dWdW_max);
|
||||||
|
|
||||||
|
R_bound *= 2 * ratio;
|
||||||
|
|
||||||
|
// std::cout << R_bound << " " << T_bound << std::endl;
|
||||||
|
|
||||||
|
return R_bound + T_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get the rotation and translation in current step */
|
||||||
|
void getCurrentTransform(Vec3f R[3], Vec3f& T) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
R[i] = tf.getRotation()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
T = tf.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentRotation(Vec3f R[3]) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R[i] = tf.getRotation()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentTranslation(Vec3f& T) const
|
||||||
|
{
|
||||||
|
T = tf.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void computeSplineParameter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL getWeight0(BVH_REAL t) const
|
||||||
|
{
|
||||||
|
return (1 - 3 * t + 3 * t * t - t * t * t) / 6.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL getWeight1(BVH_REAL t) const
|
||||||
|
{
|
||||||
|
return (4 - 6 * t * t + 3 * t * t * t) / 6.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL getWeight2(BVH_REAL t) const
|
||||||
|
{
|
||||||
|
return (1 + 3 * t + 3 * t * t - 3 * t * t * t) / 6.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL getWeight3(BVH_REAL t) const
|
||||||
|
{
|
||||||
|
return t * t * t / 6.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL computeTBound(const Vec3f& n) const
|
||||||
|
{
|
||||||
|
BVH_REAL Ta = TA.dot(n);
|
||||||
|
BVH_REAL Tb = TB.dot(n);
|
||||||
|
BVH_REAL Tc = TC.dot(n);
|
||||||
|
|
||||||
|
std::vector<BVH_REAL> T_potential;
|
||||||
|
T_potential.push_back(tf_t);
|
||||||
|
T_potential.push_back(1);
|
||||||
|
if(Tb * Tb - 3 * Ta * Tc >= 0)
|
||||||
|
{
|
||||||
|
if(Ta == 0)
|
||||||
|
{
|
||||||
|
if(Tb != 0)
|
||||||
|
{
|
||||||
|
BVH_REAL tmp = -Tc / (2 * Tb);
|
||||||
|
if(tmp < 1 && tmp > tf_t)
|
||||||
|
T_potential.push_back(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BVH_REAL tmp_delta = sqrt(Tb * Tb - 3 * Ta * Tc);
|
||||||
|
BVH_REAL tmp1 = (-Tb + tmp_delta) / (3 * Ta);
|
||||||
|
BVH_REAL tmp2 = (-Tb - tmp_delta) / (3 * Ta);
|
||||||
|
if(tmp1 < 1 && tmp1 > tf_t)
|
||||||
|
T_potential.push_back(tmp1);
|
||||||
|
if(tmp2 < 1 && tmp2 > tf_t)
|
||||||
|
T_potential.push_back(tmp2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL T_bound = Ta * T_potential[0] * T_potential[0] * T_potential[0] + Tb * T_potential[0] * T_potential[0] + Tc * T_potential[0];
|
||||||
|
for(unsigned int i = 1; i < T_potential.size(); ++i)
|
||||||
|
{
|
||||||
|
BVH_REAL T_bound_tmp = Ta * T_potential[i] * T_potential[i] * T_potential[i] + Tb * T_potential[i] * T_potential[i] + Tc * T_potential[i];
|
||||||
|
if(T_bound_tmp > T_bound) T_bound = T_bound_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BVH_REAL cur_delta = Ta * tf_t * tf_t * tf_t + Tb * tf_t * tf_t + Tc * tf_t;
|
||||||
|
|
||||||
|
T_bound -= cur_delta;
|
||||||
|
T_bound /= 6.0;
|
||||||
|
|
||||||
|
return T_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL computeDWMax() const
|
||||||
|
{
|
||||||
|
// first compute ||w'||
|
||||||
|
int a00[5] = {1,-4,6,-4,1};
|
||||||
|
int a01[5] = {-3,10,-11,4,0};
|
||||||
|
int a02[5] = {3,-8,6,0,-1};
|
||||||
|
int a03[5] = {-1,2,-1,0,0};
|
||||||
|
int a11[5] = {9,-24,16,0,0};
|
||||||
|
int a12[5] = {-9,18,-5,-4,0};
|
||||||
|
int a13[5] = {3,-4,0,0,0};
|
||||||
|
int a22[5] = {9,-12,-2,4,1};
|
||||||
|
int a23[5] = {-3,2,1,0,0};
|
||||||
|
int a33[5] = {1,0,0,0,0};
|
||||||
|
|
||||||
|
BVH_REAL a[5];
|
||||||
|
|
||||||
|
for(int i = 0; i < 5; ++i)
|
||||||
|
{
|
||||||
|
a[i] = Rd0Rd0 * a00[i] + Rd0Rd1 * a01[i] + Rd0Rd2 * a02[i] + Rd0Rd3 * a03[i]
|
||||||
|
+ Rd0Rd1 * a01[i] + Rd1Rd1 * a11[i] + Rd1Rd2 * a12[i] + Rd1Rd3 * a13[i]
|
||||||
|
+ Rd0Rd2 * a02[i] + Rd1Rd2 * a12[i] + Rd2Rd2 * a22[i] + Rd2Rd3 * a23[i]
|
||||||
|
+ Rd0Rd3 * a03[i] + Rd1Rd3 * a13[i] + Rd2Rd3 * a23[i] + Rd3Rd3 * a33[i];
|
||||||
|
a[i] /= 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute polynomial for ||w'||'
|
||||||
|
int da00[4] = {4,-12,12,-4};
|
||||||
|
int da01[4] = {-12,30,-22,4};
|
||||||
|
int da02[4] = {12,-24,12,0};
|
||||||
|
int da03[4] = {-4,6,-2,0};
|
||||||
|
int da11[4] = {36,-72,32,0};
|
||||||
|
int da12[4] = {-36,54,-10,-4};
|
||||||
|
int da13[4] = {12,-12,0,0};
|
||||||
|
int da22[4] = {36,-36,-4,4};
|
||||||
|
int da23[4] = {-12,6,2,0};
|
||||||
|
int da33[4] = {4,0,0,0};
|
||||||
|
|
||||||
|
BVH_REAL da[4];
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
da[i] = Rd0Rd0 * da00[i] + Rd0Rd1 * da01[i] + Rd0Rd2 * da02[i] + Rd0Rd3 * da03[i]
|
||||||
|
+ Rd0Rd1 * da01[i] + Rd1Rd1 * da11[i] + Rd1Rd2 * da12[i] + Rd1Rd3 * da13[i]
|
||||||
|
+ Rd0Rd2 * da02[i] + Rd1Rd2 * da12[i] + Rd2Rd2 * da22[i] + Rd2Rd3 * da23[i]
|
||||||
|
+ Rd0Rd3 * da03[i] + Rd1Rd3 * da13[i] + Rd2Rd3 * da23[i] + Rd3Rd3 * da33[i];
|
||||||
|
da[i] /= 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BVH_REAL roots[3];
|
||||||
|
|
||||||
|
int root_num = PolySolver::solveCubic(da, roots);
|
||||||
|
|
||||||
|
BVH_REAL dWdW_max = a[0] * tf_t * tf_t * tf_t + a[1] * tf_t * tf_t * tf_t + a[2] * tf_t * tf_t + a[3] * tf_t + a[4];
|
||||||
|
BVH_REAL dWdW_1 = a[0] + a[1] + a[2] + a[3] + a[4];
|
||||||
|
if(dWdW_max < dWdW_1) dWdW_max = dWdW_1;
|
||||||
|
for(int i = 0; i < root_num; ++i)
|
||||||
|
{
|
||||||
|
BVH_REAL v = roots[i];
|
||||||
|
|
||||||
|
if(v >= tf_t && v <= 1)
|
||||||
|
{
|
||||||
|
BVH_REAL value = a[0] * v * v * v * v + a[1] * v * v * v + a[2] * v * v + a[3] * v + a[4];
|
||||||
|
if(value > dWdW_max) dWdW_max = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqrt(dWdW_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3f Td[4];
|
||||||
|
Vec3f Rd[4];
|
||||||
|
|
||||||
|
Vec3f TA, TB, TC;
|
||||||
|
Vec3f RA, RB, RC;
|
||||||
|
|
||||||
|
BVH_REAL Rd0Rd0, Rd0Rd1, Rd0Rd2, Rd0Rd3, Rd1Rd1, Rd1Rd2, Rd1Rd3, Rd2Rd2, Rd2Rd3, Rd3Rd3;
|
||||||
|
/** \brief The transformation at current time t */
|
||||||
|
SimpleTransform tf;
|
||||||
|
|
||||||
|
/** \brief The time related with tf */
|
||||||
|
BVH_REAL tf_t;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
class ScrewMotion : public MotionBase<BV>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Default transformations are all identities */
|
||||||
|
ScrewMotion()
|
||||||
|
{
|
||||||
|
/** Default angular velocity is zero */
|
||||||
|
axis = Vec3f(1, 0, 0);
|
||||||
|
angular_vel = 0;
|
||||||
|
|
||||||
|
/** Default reference point is local zero point */
|
||||||
|
|
||||||
|
/** Default linear velocity is zero */
|
||||||
|
linear_vel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Construct motion from the initial rotation/translation and goal rotation/translation */
|
||||||
|
ScrewMotion(const Vec3f R1[3], const Vec3f& T1,
|
||||||
|
const Vec3f R2[3], const Vec3f& T2)
|
||||||
|
{
|
||||||
|
tf1 = SimpleTransform(R1, T1);
|
||||||
|
tf2 = SimpleTransform(R2, T2);
|
||||||
|
|
||||||
|
/** Current time is zero, so the transformation is t1 */
|
||||||
|
tf = tf1;
|
||||||
|
|
||||||
|
computeScrewParameter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Integrate the motion from 0 to dt
|
||||||
|
* We compute the current transformation from zero point instead of from last integrate time, for precision.
|
||||||
|
*/
|
||||||
|
bool integrate(double dt)
|
||||||
|
{
|
||||||
|
if(dt > 1) dt = 1;
|
||||||
|
|
||||||
|
tf.setQuatRotation(absoluteRotation(dt));
|
||||||
|
|
||||||
|
SimpleQuaternion delta_rot = deltaRotation(dt);
|
||||||
|
tf.setTranslation(p + axis * (dt * linear_vel) + delta_rot.transform(tf1.getTranslation() - p));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a bounding volume along a given direction n
|
||||||
|
* For general BV, not implemented so return trivial 0
|
||||||
|
*/
|
||||||
|
BVH_REAL computeMotionBound(const BV& bv, const Vec3f& n) const { return 0.0; }
|
||||||
|
|
||||||
|
BVH_REAL computeMotionBound(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& n) const
|
||||||
|
{
|
||||||
|
BVH_REAL proj_max = ((tf.getQuatRotation().transform(a) + tf.getTranslation() - p).cross(axis)).sqrLength();
|
||||||
|
BVH_REAL tmp;
|
||||||
|
tmp = ((tf.getQuatRotation().transform(b) + tf.getTranslation() - p).cross(axis)).sqrLength();
|
||||||
|
if(tmp > proj_max) proj_max = tmp;
|
||||||
|
tmp = ((tf.getQuatRotation().transform(c) + tf.getTranslation() - p).cross(axis)).sqrLength();
|
||||||
|
if(tmp > proj_max) proj_max = tmp;
|
||||||
|
|
||||||
|
proj_max = sqrt(proj_max);
|
||||||
|
|
||||||
|
BVH_REAL v_dot_n = axis.dot(n) * linear_vel;
|
||||||
|
BVH_REAL w_cross_n = (axis.cross(n)).length() * angular_vel;
|
||||||
|
BVH_REAL mu = v_dot_n + w_cross_n * proj_max;
|
||||||
|
|
||||||
|
return mu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get the rotation and translation in current step */
|
||||||
|
void getCurrentTransform(Vec3f R[3], Vec3f& T) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
R[i] = tf.getRotation()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
T = tf.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentRotation(Vec3f R[3]) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R[i] = tf.getRotation()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentTranslation(Vec3f& T) const
|
||||||
|
{
|
||||||
|
T = tf.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void computeScrewParameter()
|
||||||
|
{
|
||||||
|
SimpleQuaternion deltaq = tf2.getQuatRotation() * tf1.getQuatRotation().inverse();
|
||||||
|
deltaq.toAxisAngle(axis, angular_vel);
|
||||||
|
if(angular_vel < 0)
|
||||||
|
{
|
||||||
|
angular_vel = -angular_vel;
|
||||||
|
axis = -axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(angular_vel < 1e-10)
|
||||||
|
{
|
||||||
|
angular_vel = 0;
|
||||||
|
axis = tf2.getTranslation() - tf1.getTranslation();
|
||||||
|
linear_vel = axis.length();
|
||||||
|
p = tf1.getTranslation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vec3f o = tf2.getTranslation() - tf1.getTranslation();
|
||||||
|
p = (tf1.getTranslation() + tf2.getTranslation() + axis.cross(o) * (1.0 / tan(angular_vel / 2.0))) * 0.5;
|
||||||
|
linear_vel = o.dot(axis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleQuaternion deltaRotation(BVH_REAL dt) const
|
||||||
|
{
|
||||||
|
SimpleQuaternion res;
|
||||||
|
res.fromAxisAngle(axis, (BVH_REAL)(dt * angular_vel));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleQuaternion absoluteRotation(BVH_REAL dt) const
|
||||||
|
{
|
||||||
|
SimpleQuaternion delta_t = deltaRotation(dt);
|
||||||
|
return delta_t * tf1.getQuatRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The transformation at time 0 */
|
||||||
|
SimpleTransform tf1;
|
||||||
|
|
||||||
|
/** \brief The transformation at time 1 */
|
||||||
|
SimpleTransform tf2;
|
||||||
|
|
||||||
|
/** \brief The transformation at current time t */
|
||||||
|
SimpleTransform tf;
|
||||||
|
|
||||||
|
/** \brief screw axis */
|
||||||
|
Vec3f axis;
|
||||||
|
|
||||||
|
/** \brief A point on the axis S */
|
||||||
|
Vec3f p;
|
||||||
|
|
||||||
|
/** \brief linear velocity along the axis */
|
||||||
|
BVH_REAL linear_vel;
|
||||||
|
|
||||||
|
/** \brief angular velocity */
|
||||||
|
BVH_REAL angular_vel;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a bounding volume along a given direction n
|
||||||
|
* according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||R0(ci) x w||. w is the angular axis (normalized)
|
||||||
|
* and ci are the endpoints of the generator primitives of RSS.
|
||||||
|
* Notice that all bv parameters are in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
BVH_REAL ScrewMotion<RSS>::computeMotionBound(const RSS& bv, const Vec3f& n) const;
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Linear interpolation motion
|
||||||
|
* Each Motion is assumed to have constant linear velocity and angular velocity
|
||||||
|
* The motion is R(t)(p - p_ref) + p_ref + T(t)
|
||||||
|
* Therefore, R(0) = R0, R(1) = R1
|
||||||
|
* T(0) = T0 + R0 p_ref - p_ref
|
||||||
|
* T(1) = T1 + R1 p_ref - p_ref
|
||||||
|
*/
|
||||||
|
template<typename BV>
|
||||||
|
class InterpMotion : public MotionBase<BV>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Default transformations are all identities */
|
||||||
|
InterpMotion()
|
||||||
|
{
|
||||||
|
/** Default angular velocity is zero */
|
||||||
|
angular_axis = Vec3f(1, 0, 0);
|
||||||
|
angular_vel = 0;
|
||||||
|
|
||||||
|
/** Default reference point is local zero point */
|
||||||
|
|
||||||
|
/** Default linear velocity is zero */
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Construct motion from the initial rotation/translation and goal rotation/translation */
|
||||||
|
InterpMotion(const Vec3f R1[3], const Vec3f& T1,
|
||||||
|
const Vec3f R2[3], const Vec3f& T2)
|
||||||
|
{
|
||||||
|
tf1 = SimpleTransform(R1, T1);
|
||||||
|
tf2 = SimpleTransform(R2, T2);
|
||||||
|
|
||||||
|
/** Current time is zero, so the transformation is t1 */
|
||||||
|
tf = tf1;
|
||||||
|
|
||||||
|
/** Default reference point is local zero point */
|
||||||
|
|
||||||
|
/** Compute the velocities for the motion */
|
||||||
|
computeVelocity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Construct motion from the initial rotation/translation and goal rotation/translation related to some rotation center
|
||||||
|
*/
|
||||||
|
InterpMotion(const Vec3f R1[3], const Vec3f& T1,
|
||||||
|
const Vec3f R2[3], const Vec3f& T2,
|
||||||
|
const Vec3f& O)
|
||||||
|
{
|
||||||
|
tf1 = SimpleTransform(R1, T1);
|
||||||
|
tf2 = SimpleTransform(R2, T2);
|
||||||
|
tf = tf1;
|
||||||
|
|
||||||
|
reference_p = O;
|
||||||
|
|
||||||
|
/** Compute the velocities for the motion */
|
||||||
|
computeVelocity();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Integrate the motion from 0 to dt
|
||||||
|
* We compute the current transformation from zero point instead of from last integrate time, for precision.
|
||||||
|
*/
|
||||||
|
bool integrate(double dt)
|
||||||
|
{
|
||||||
|
if(dt > 1) dt = 1;
|
||||||
|
|
||||||
|
tf.setQuatRotation(absoluteRotation(dt));
|
||||||
|
tf.setTranslation(linear_vel * dt + tf1.transform(reference_p) - tf.getQuatRotation().transform(reference_p));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a bounding volume along a given direction n
|
||||||
|
* For general BV, not implemented so return trivial 0
|
||||||
|
*/
|
||||||
|
BVH_REAL computeMotionBound(const BV& bv, const Vec3f& n) const { return 0.0; }
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a triangle along a given direction n
|
||||||
|
* according to mu < |v * n| + ||w x n||(max||ci*||) where ||ci*|| = ||R0(ci) x w|| / \|w\|. w is the angular velocity
|
||||||
|
* and ci are the triangle vertex coordinates.
|
||||||
|
* Notice that the triangle is in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
|
||||||
|
*/
|
||||||
|
BVH_REAL computeMotionBound(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& n) const
|
||||||
|
{
|
||||||
|
BVH_REAL proj_max = ((tf.getQuatRotation().transform(a - reference_p)).cross(angular_axis)).sqrLength();
|
||||||
|
BVH_REAL tmp;
|
||||||
|
tmp = ((tf.getQuatRotation().transform(b - reference_p)).cross(angular_axis)).sqrLength();
|
||||||
|
if(tmp > proj_max) proj_max = tmp;
|
||||||
|
tmp = ((tf.getQuatRotation().transform(c - reference_p)).cross(angular_axis)).sqrLength();
|
||||||
|
if(tmp > proj_max) proj_max = tmp;
|
||||||
|
|
||||||
|
proj_max = sqrt(proj_max);
|
||||||
|
|
||||||
|
BVH_REAL v_dot_n = linear_vel.dot(n);
|
||||||
|
BVH_REAL w_cross_n = (angular_axis.cross(n)).length() * angular_vel;
|
||||||
|
BVH_REAL mu = v_dot_n + w_cross_n * proj_max;
|
||||||
|
|
||||||
|
return mu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get the rotation and translation in current step */
|
||||||
|
void getCurrentTransform(Vec3f R[3], Vec3f& T) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
R[i] = tf.getRotation()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
T = tf.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentRotation(Vec3f R[3]) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R[i] = tf.getRotation()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCurrentTranslation(Vec3f& T) const
|
||||||
|
{
|
||||||
|
T = tf.getTranslation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void computeVelocity()
|
||||||
|
{
|
||||||
|
linear_vel = tf2.transform(reference_p) - tf1.transform(reference_p);
|
||||||
|
SimpleQuaternion deltaq = tf2.getQuatRotation() * tf1.getQuatRotation().inverse();
|
||||||
|
deltaq.toAxisAngle(angular_axis, angular_vel);
|
||||||
|
if(angular_vel < 0)
|
||||||
|
{
|
||||||
|
angular_vel = -angular_vel;
|
||||||
|
angular_axis = -angular_axis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SimpleQuaternion deltaRotation(BVH_REAL dt) const
|
||||||
|
{
|
||||||
|
SimpleQuaternion res;
|
||||||
|
res.fromAxisAngle(angular_axis, (BVH_REAL)(dt * angular_vel));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleQuaternion absoluteRotation(BVH_REAL dt) const
|
||||||
|
{
|
||||||
|
SimpleQuaternion delta_t = deltaRotation(dt);
|
||||||
|
return delta_t * tf1.getQuatRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief The transformation at time 0 */
|
||||||
|
SimpleTransform tf1;
|
||||||
|
|
||||||
|
/** \brief The transformation at time 1 */
|
||||||
|
SimpleTransform tf2;
|
||||||
|
|
||||||
|
/** \brief The transformation at current time t */
|
||||||
|
SimpleTransform tf;
|
||||||
|
|
||||||
|
/** \brief Linear velocity */
|
||||||
|
Vec3f linear_vel;
|
||||||
|
|
||||||
|
/** \brief Angular speed */
|
||||||
|
BVH_REAL angular_vel;
|
||||||
|
|
||||||
|
/** \brief Angular velocity axis */
|
||||||
|
Vec3f angular_axis;
|
||||||
|
|
||||||
|
/** \brief Reference point for the motion (in the object's local frame) */
|
||||||
|
Vec3f reference_p;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a bounding volume along a given direction n
|
||||||
|
* according to mu < |v * n| + ||w x n||(r + max(||ci*||)) where ||ci*|| = ||R0(ci) x w||. w is the angular axis (normalized)
|
||||||
|
* and ci are the endpoints of the generator primitives of RSS.
|
||||||
|
* Notice that all bv parameters are in the local frame of the object, but n should be in the global frame (the reason is that the motion (t1, t2 and t) is in global frame)
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
BVH_REAL InterpMotion<RSS>::computeMotionBound(const RSS& bv, const Vec3f& n) const;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_MOTION_BASE_H
|
||||||
|
#define FCL_MOTION_BASE_H
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/RSS.h"
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename BV>
|
||||||
|
class MotionBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MotionBase() {}
|
||||||
|
|
||||||
|
/** \brief Integrate the motion from 0 to dt */
|
||||||
|
virtual bool integrate(double dt) = 0;
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a bounding volume, given the closest direction n between two query objects */
|
||||||
|
virtual BVH_REAL computeMotionBound(const BV& bv, const Vec3f& n) const = 0;
|
||||||
|
|
||||||
|
/** \brief Compute the motion bound for a triangle, given the closest direction n between two query objects */
|
||||||
|
virtual BVH_REAL computeMotionBound(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& n) const = 0;
|
||||||
|
|
||||||
|
/** \brief Get the rotation and translation in current step */
|
||||||
|
virtual void getCurrentTransform(Vec3f R[3], Vec3f& T) const = 0;
|
||||||
|
|
||||||
|
virtual void getCurrentRotation(Vec3f R[3]) const = 0;
|
||||||
|
|
||||||
|
virtual void getCurrentTranslation(Vec3f& T) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef COLLISION_CHECKING_PRIMITIVE_H
|
||||||
|
#define COLLISION_CHECKING_PRIMITIVE_H
|
||||||
|
|
||||||
|
#include "fcl/BVH_internal.h"
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Uncertainty information */
|
||||||
|
struct Uncertainty
|
||||||
|
{
|
||||||
|
Uncertainty() {}
|
||||||
|
|
||||||
|
Uncertainty(Vec3f Sigma_[3])
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
Sigma[i] = Sigma_[i];
|
||||||
|
preprocess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** preprocess performs the eigen decomposition on the Sigma matrix */
|
||||||
|
void preprocess()
|
||||||
|
{
|
||||||
|
matEigen(Sigma, sigma, axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** sqrt performs 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
|
||||||
|
*/
|
||||||
|
void sqrt()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if(sigma[i] < 0) sigma[i] = 0;
|
||||||
|
sigma[i] = std::sqrt(sigma[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
Sigma[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
for(int 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Variation matrix for uncertainty */
|
||||||
|
Vec3f Sigma[3];
|
||||||
|
|
||||||
|
/** \brief Variations along the eigen axes */
|
||||||
|
BVH_REAL sigma[3];
|
||||||
|
|
||||||
|
/** \brief eigen axes of uncertainty matrix */
|
||||||
|
Vec3f axis[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Simple triangle with 3 indices for points */
|
||||||
|
struct Triangle
|
||||||
|
{
|
||||||
|
unsigned int vids[3];
|
||||||
|
|
||||||
|
Triangle() {}
|
||||||
|
|
||||||
|
Triangle(unsigned int p1, unsigned int p2, unsigned int p3)
|
||||||
|
{
|
||||||
|
set(p1, p2, p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set(unsigned int p1, unsigned int p2, unsigned int p3)
|
||||||
|
{
|
||||||
|
vids[0] = p1; vids[1] = p2; vids[2] = p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int operator[](int i) const { return vids[i]; }
|
||||||
|
|
||||||
|
inline unsigned int& operator[](int i) { return vids[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Simple edge with two indices for its endpoints */
|
||||||
|
struct Edge
|
||||||
|
{
|
||||||
|
unsigned int vids[2];
|
||||||
|
unsigned int fids[2];
|
||||||
|
|
||||||
|
Edge()
|
||||||
|
{
|
||||||
|
vids[0] = -1; vids[1] = -1;
|
||||||
|
fids[0] = -1; fids[1] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge(unsigned int vid0, unsigned int vid1, unsigned int fid)
|
||||||
|
{
|
||||||
|
vids[0] = vid0;
|
||||||
|
vids[1] = vid1;
|
||||||
|
fids[0] = fid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Whether two edges are the same, assuming belongs to the same object */
|
||||||
|
bool operator == (const Edge& other) const
|
||||||
|
{
|
||||||
|
return (vids[0] == other.vids[0]) && (vids[1] == other.vids[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator < (const Edge& other) const
|
||||||
|
{
|
||||||
|
if(vids[0] == other.vids[0])
|
||||||
|
return vids[1] < other.vids[1];
|
||||||
|
|
||||||
|
return vids[0] < other.vids[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,648 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_SIMPLE_SETUP_H
|
||||||
|
#define FCL_SIMPLE_SETUP_H
|
||||||
|
|
||||||
|
#include "fcl/traversal_node_bvhs.h"
|
||||||
|
#include "fcl/traversal_node_shapes.h"
|
||||||
|
#include "fcl/traversal_node_bvh_shape.h"
|
||||||
|
#include "fcl/BVH_utility.h"
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between two geometric shapes */
|
||||||
|
template<typename S1, typename S2>
|
||||||
|
bool initialize(ShapeCollisionTraversalNode<S1, S2>& node, const S1& shape1, const S2& shape2, bool enable_contact = false)
|
||||||
|
{
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
node.model1 = &shape1;
|
||||||
|
node.model2 = &shape2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between one mesh and one shape, given current object transform */
|
||||||
|
template<typename BV, typename S>
|
||||||
|
bool initialize(MeshShapeCollisionTraversalNode<BV, S>& node, BVHModel<BV>& model1, const S& model2,
|
||||||
|
int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false,
|
||||||
|
bool use_refit = false, bool refit_bottomup = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
if(!model1.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed(model1.num_vertices);
|
||||||
|
for(int i = 0; i < model1.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model1.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model1.getRotation(), p) + model1.getTranslation();
|
||||||
|
vertices_transformed[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model1.beginReplaceModel();
|
||||||
|
model1.replaceSubModel(vertices_transformed);
|
||||||
|
model1.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model1.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.vertices = model1.vertices;
|
||||||
|
node.tri_indices = model1.tri_indices;
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between one mesh and one shape, given current object transform */
|
||||||
|
template<typename S, typename BV>
|
||||||
|
bool initialize(ShapeMeshCollisionTraversalNode<S, BV>& node, const S& model1, BVHModel<BV>& model2,
|
||||||
|
int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false,
|
||||||
|
bool use_refit = false, bool refit_bottomup = false)
|
||||||
|
{
|
||||||
|
if(model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
if(!model2.isIdentityTransform())
|
||||||
|
{
|
||||||
|
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 = matMulVec(model2.getRotation(), p) + model2.getTranslation();
|
||||||
|
vertices_transformed[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model2.beginReplaceModel();
|
||||||
|
model2.replaceSubModel(vertices_transformed);
|
||||||
|
model2.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model2.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.vertices = model2.vertices;
|
||||||
|
node.tri_indices = model2.tri_indices;
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBB type */
|
||||||
|
template<typename S>
|
||||||
|
bool initialize(MeshShapeCollisionTraversalNodeOBB<S>& node, const BVHModel<OBB>& model1, const S& model2, int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices = model1.vertices;
|
||||||
|
node.tri_indices = model1.tri_indices;
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
node.R[i] = model1.getRotation()[i];
|
||||||
|
node.T = model1.getTranslation();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize the traversal node for collision between one mesh and one shape, specialized for OBB type */
|
||||||
|
template<typename S>
|
||||||
|
bool initialize(ShapeMeshCollisionTraversalNodeOBB<S>& node, const S& model1, const BVHModel<OBB>& model2, int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false)
|
||||||
|
{
|
||||||
|
if(model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices = model2.vertices;
|
||||||
|
node.tri_indices = model2.tri_indices;
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
node.R[i] = model2.getRotation()[i];
|
||||||
|
node.T = model2.getTranslation();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between two meshes, given the current transforms */
|
||||||
|
template<typename BV>
|
||||||
|
bool initialize(MeshCollisionTraversalNode<BV>& node, BVHModel<BV>& model1, BVHModel<BV>& model2,
|
||||||
|
int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false,
|
||||||
|
bool use_refit = false, bool refit_bottomup = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!model1.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed1(model1.num_vertices);
|
||||||
|
for(int i = 0; i < model1.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model1.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model1.getRotation(), p) + model1.getTranslation();
|
||||||
|
vertices_transformed1[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model1.beginReplaceModel();
|
||||||
|
model1.replaceSubModel(vertices_transformed1);
|
||||||
|
model1.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model1.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!model2.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed2(model2.num_vertices);
|
||||||
|
for(int i = 0; i < model2.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model2.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model2.getRotation(), p) + model2.getTranslation();
|
||||||
|
vertices_transformed2[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model2.beginReplaceModel();
|
||||||
|
model2.replaceSubModel(vertices_transformed2);
|
||||||
|
model2.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model2.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices1 = model1.tri_indices;
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between two meshes, specialized for OBB type */
|
||||||
|
bool initialize(MeshCollisionTraversalNodeOBB& node, const BVHModel<OBB>& model1, const BVHModel<OBB>& model2,
|
||||||
|
int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false);
|
||||||
|
|
||||||
|
bool initialize(MeshCollisionTraversalNodeRSS& node, const BVHModel<RSS>& model1, const BVHModel<RSS>& model2,
|
||||||
|
int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false);
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_SVMLIGHT
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between two point clouds, given current transforms */
|
||||||
|
template<typename BV, bool use_refit, bool refit_bottomup>
|
||||||
|
bool initialize(PointCloudCollisionTraversalNode<BV>& node, BVHModel<BV>& model1, BVHModel<BV>& model2,
|
||||||
|
BVH_REAL collision_prob_threshold = 0.5,
|
||||||
|
int leaf_size_threshold = 1,
|
||||||
|
int num_max_contacts = 1,
|
||||||
|
bool exhaustive = false,
|
||||||
|
bool enable_contact = false,
|
||||||
|
BVH_REAL expand_r = 1)
|
||||||
|
{
|
||||||
|
if(!(model1.getModelType() == BVH_MODEL_TRIANGLES || model1.getModelType() == BVH_MODEL_POINTCLOUD)
|
||||||
|
|| !(model2.getModelType() == BVH_MODEL_TRIANGLES || model2.getModelType() == BVH_MODEL_POINTCLOUD))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!model1.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed1(model1.num_vertices);
|
||||||
|
for(int i = 0; i < model1.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model1.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model1.getRotation(), p) + model1.getTranslation();
|
||||||
|
vertices_transformed1[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model1.beginReplaceModel();
|
||||||
|
model1.replaceSubModel(vertices_transformed1);
|
||||||
|
model1.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model1.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!model2.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed2(model2.num_vertices);
|
||||||
|
for(int i = 0; i < model2.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model2.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model2.getRotation(), p) + model2.getTranslation();
|
||||||
|
vertices_transformed2[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model2.beginReplaceModel();
|
||||||
|
model2.replaceSubModel(vertices_transformed2);
|
||||||
|
model2.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model2.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.uc1.reset(new Uncertainty[model1.num_vertices]);
|
||||||
|
node.uc2.reset(new Uncertainty[model2.num_vertices]);
|
||||||
|
|
||||||
|
estimateSamplingUncertainty(model1.vertices, model1.num_vertices, node.uc1.get());
|
||||||
|
estimateSamplingUncertainty(model2.vertices, model2.num_vertices, node.uc2.get());
|
||||||
|
|
||||||
|
BVHExpand(model1, node.uc1.get(), expand_r);
|
||||||
|
BVHExpand(model2, node.uc2.get(), expand_r);
|
||||||
|
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
node.collision_prob_threshold = collision_prob_threshold;
|
||||||
|
node.leaf_size_threshold = leaf_size_threshold;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between two point clouds, given current transforms, specialized for OBB type */
|
||||||
|
bool initialize(PointCloudCollisionTraversalNodeOBB& node, BVHModel<OBB>& model1, BVHModel<OBB>& model2,
|
||||||
|
BVH_REAL collision_prob_threshold = 0.5,
|
||||||
|
int leaf_size_threshold = 1,
|
||||||
|
int num_max_contacts = 1,
|
||||||
|
bool exhaustive = false,
|
||||||
|
bool enable_contact = false,
|
||||||
|
BVH_REAL expand_r = 1);
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between two point clouds, given current transforms, specialized for RSS type */
|
||||||
|
bool initialize(PointCloudCollisionTraversalNodeRSS& node, BVHModel<RSS>& model1, BVHModel<RSS>& model2,
|
||||||
|
BVH_REAL collision_prob_threshold = 0.5,
|
||||||
|
int leaf_size_threshold = 1,
|
||||||
|
int num_max_contacts = 1,
|
||||||
|
bool exhaustive = false,
|
||||||
|
bool enable_contact = false,
|
||||||
|
BVH_REAL expand_r = 1);
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between one point cloud and one mesh, given current transforms */
|
||||||
|
template<typename BV, bool use_refit, bool refit_bottomup>
|
||||||
|
bool initialize(PointCloudMeshCollisionTraversalNode<BV>& node, BVHModel<BV>& model1, BVHModel<BV>& model2,
|
||||||
|
BVH_REAL collision_prob_threshold = 0.5,
|
||||||
|
int leaf_size_threshold = 1,
|
||||||
|
int num_max_contacts = 1,
|
||||||
|
bool exhaustive = false,
|
||||||
|
bool enable_contact = false,
|
||||||
|
BVH_REAL expand_r = 1)
|
||||||
|
{
|
||||||
|
if(!(model1.getModelType() == BVH_MODEL_TRIANGLES || model1.getModelType() == BVH_MODEL_POINTCLOUD) || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!model1.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed1(model1.num_vertices);
|
||||||
|
for(int i = 0; i < model1.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model1.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model1.getRotation(), p) + model1.getTranslation();
|
||||||
|
vertices_transformed1[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model1.beginReplaceModel();
|
||||||
|
model1.replaceSubModel(vertices_transformed1);
|
||||||
|
model1.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model1.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!model2.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed2(model2.num_vertices);
|
||||||
|
for(int i = 0; i < model2.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model2.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model2.getRotation(), p) + model2.getTranslation();
|
||||||
|
vertices_transformed2[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model2.beginReplaceModel();
|
||||||
|
model2.replaceSubModel(vertices_transformed2);
|
||||||
|
model2.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model2.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
node.uc1.reset(new Uncertainty[model1.num_vertices]);
|
||||||
|
|
||||||
|
estimateSamplingUncertainty(model1.vertices, model1.num_vertices, node.uc1.get());
|
||||||
|
|
||||||
|
BVHExpand(model1, node.uc1.get(), expand_r);
|
||||||
|
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
node.collision_prob_threshold = collision_prob_threshold;
|
||||||
|
node.leaf_size_threshold = leaf_size_threshold;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between one point cloud and one mesh, given current transforms, specialized for OBB type */
|
||||||
|
bool initialize(PointCloudMeshCollisionTraversalNodeOBB& node, BVHModel<OBB>& model1, const BVHModel<OBB>& model2,
|
||||||
|
BVH_REAL collision_prob_threshold = 0.5,
|
||||||
|
int leaf_size_threshold = 1,
|
||||||
|
int num_max_contacts = 1,
|
||||||
|
bool exhaustive = false,
|
||||||
|
bool enable_contact = false,
|
||||||
|
BVH_REAL expand_r = 1);
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for collision between one point cloud and one mesh, given current transforms, specialized for RSS type */
|
||||||
|
bool initialize(PointCloudMeshCollisionTraversalNodeRSS& node, BVHModel<RSS>& model1, const BVHModel<RSS>& model2,
|
||||||
|
BVH_REAL collision_prob_threshold = 0.5,
|
||||||
|
int leaf_size_threshold = 1,
|
||||||
|
int num_max_contacts = 1,
|
||||||
|
bool exhaustive = false,
|
||||||
|
bool enable_contact = false,
|
||||||
|
BVH_REAL expand_r = 1);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for distance computation between two meshes, given the current transforms */
|
||||||
|
template<typename BV>
|
||||||
|
bool initialize(MeshDistanceTraversalNode<BV>& node, BVHModel<BV>& model1, BVHModel<BV>& model2,
|
||||||
|
bool use_refit = false, bool refit_bottomup = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!model1.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed1(model1.num_vertices);
|
||||||
|
for(int i = 0; i < model1.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model1.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model1.getRotation(), p) + model1.getTranslation();
|
||||||
|
vertices_transformed1[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model1.beginReplaceModel();
|
||||||
|
model1.replaceSubModel(vertices_transformed1);
|
||||||
|
model1.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model1.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!model2.isIdentityTransform())
|
||||||
|
{
|
||||||
|
std::vector<Vec3f> vertices_transformed2(model2.num_vertices);
|
||||||
|
for(int i = 0; i < model2.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model2.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(model2.getRotation(), p) + model2.getTranslation();
|
||||||
|
vertices_transformed2[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model2.beginReplaceModel();
|
||||||
|
model2.replaceSubModel(vertices_transformed2);
|
||||||
|
model2.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model2.setIdentityTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices1 = model1.tri_indices;
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for distance computation between two meshes, given the current transforms */
|
||||||
|
bool initialize(MeshDistanceTraversalNodeRSS& node, const BVHModel<RSS>& model1, const BVHModel<RSS>& model2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for continuous collision detection between two meshes */
|
||||||
|
template<typename BV>
|
||||||
|
bool initialize(MeshContinuousCollisionTraversalNode<BV>& node, const BVHModel<BV>& model1, const BVHModel<BV>& model2, int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices1 = model1.tri_indices;
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
|
||||||
|
node.prev_vertices1 = model1.prev_vertices;
|
||||||
|
node.prev_vertices2 = model2.prev_vertices;
|
||||||
|
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for continuous collision detection between one mesh and one point cloud */
|
||||||
|
template<typename BV>
|
||||||
|
bool initialize(MeshPointCloudContinuousCollisionTraversalNode<BV>& node, const BVHModel<BV>& model1, const BVHModel<BV>& model2, int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES || !(model2.getModelType() == BVH_MODEL_TRIANGLES || model2.getModelType() == BVH_MODEL_POINTCLOUD))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices1 = model1.tri_indices;
|
||||||
|
node.prev_vertices1 = model1.prev_vertices;
|
||||||
|
node.prev_vertices2 = model2.prev_vertices;
|
||||||
|
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for continuous collision detection between one point cloud and one mesh */
|
||||||
|
template<typename BV>
|
||||||
|
bool initialize(PointCloudMeshContinuousCollisionTraversalNode<BV>& node, const BVHModel<BV>& model1, const BVHModel<BV>& model2, int num_max_contacts = 1, bool exhaustive = false, bool enable_contact = false)
|
||||||
|
{
|
||||||
|
if(!(model1.getModelType() == BVH_MODEL_TRIANGLES || model1.getModelType() == BVH_MODEL_POINTCLOUD) || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
node.prev_vertices1 = model1.prev_vertices;
|
||||||
|
node.prev_vertices2 = model2.prev_vertices;
|
||||||
|
|
||||||
|
node.num_max_contacts = num_max_contacts;
|
||||||
|
node.exhaustive = exhaustive;
|
||||||
|
node.enable_contact = enable_contact;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for conservative advancement computation between two meshes, given the current transforms */
|
||||||
|
template<typename BV>
|
||||||
|
bool initialize(MeshConservativeAdvancementTraversalNode<BV>& node, BVHModel<BV>& model1, BVHModel<BV>& model2,
|
||||||
|
const Vec3f R1[3], const Vec3f& T1, const Vec3f R2[3], const Vec3f& T2, BVH_REAL w = 1,
|
||||||
|
bool use_refit = false, bool refit_bottomup = false)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::vector<Vec3f> vertices_transformed1(model1.num_vertices);
|
||||||
|
for(int i = 0; i < model1.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model1.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(R1, p) + T1;
|
||||||
|
vertices_transformed1[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Vec3f> vertices_transformed2(model2.num_vertices);
|
||||||
|
for(int i = 0; i < model2.num_vertices; ++i)
|
||||||
|
{
|
||||||
|
Vec3f& p = model2.vertices[i];
|
||||||
|
Vec3f new_v = matMulVec(R2, p) + T2;
|
||||||
|
vertices_transformed2[i] = new_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
model1.beginReplaceModel();
|
||||||
|
model1.replaceSubModel(vertices_transformed1);
|
||||||
|
model1.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
model2.beginReplaceModel();
|
||||||
|
model2.replaceSubModel(vertices_transformed2);
|
||||||
|
model2.endReplaceModel(use_refit, refit_bottomup);
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices1 = model1.tri_indices;
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
|
||||||
|
node.w = w;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Initialize traversal node for conservative advancement computation between two meshes, given the current transforms, specialized for RSS */
|
||||||
|
inline bool initialize(MeshConservativeAdvancementTraversalNodeRSS& node, const BVHModel<RSS>& model1, const BVHModel<RSS>& model2,
|
||||||
|
const Vec3f R1[3], const Vec3f& T1, const Vec3f R2[3], const Vec3f& T2, BVH_REAL w = 1)
|
||||||
|
{
|
||||||
|
if(model1.getModelType() != BVH_MODEL_TRIANGLES || model2.getModelType() != BVH_MODEL_TRIANGLES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
node.model1 = &model1;
|
||||||
|
node.model2 = &model2;
|
||||||
|
|
||||||
|
node.vertices1 = model1.vertices;
|
||||||
|
node.vertices2 = model2.vertices;
|
||||||
|
|
||||||
|
node.tri_indices1 = model1.tri_indices;
|
||||||
|
node.tri_indices2 = model2.tri_indices;
|
||||||
|
|
||||||
|
node.w = w;
|
||||||
|
|
||||||
|
relativeTransform(R1, T1, R2, T2, node.R, node.T);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,228 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_TRANSFORM_H
|
||||||
|
#define FCL_TRANSFORM_H
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
/** \brief Quaternion used locally by InterpMotion */
|
||||||
|
class SimpleQuaternion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief Default quaternion is identity rotation */
|
||||||
|
SimpleQuaternion()
|
||||||
|
{
|
||||||
|
data[0] = 1;
|
||||||
|
data[1] = 0;
|
||||||
|
data[2] = 0;
|
||||||
|
data[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleQuaternion(BVH_REAL a, BVH_REAL b, BVH_REAL c, BVH_REAL d)
|
||||||
|
{
|
||||||
|
data[0] = a; // w
|
||||||
|
data[1] = b; // x
|
||||||
|
data[2] = c; // y
|
||||||
|
data[3] = d; // z
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Matrix to quaternion */
|
||||||
|
void fromRotation(const Vec3f R[3]);
|
||||||
|
|
||||||
|
/** \brief Quaternion to matrix */
|
||||||
|
void toRotation(Vec3f R[3]) const;
|
||||||
|
|
||||||
|
/** \brief Axes to quaternion */
|
||||||
|
void fromAxes(const Vec3f axis[3]);
|
||||||
|
|
||||||
|
/** \brief Axes to matrix */
|
||||||
|
void toAxes(Vec3f axis[3]) const;
|
||||||
|
|
||||||
|
/** \brief Axis and angle to quaternion */
|
||||||
|
void fromAxisAngle(const Vec3f& axis, BVH_REAL angle);
|
||||||
|
|
||||||
|
/** \brief Quaternion to axis and angle */
|
||||||
|
void toAxisAngle(Vec3f& axis, BVH_REAL& angle) const;
|
||||||
|
|
||||||
|
/** \brief Dot product between quaternions */
|
||||||
|
BVH_REAL dot(const SimpleQuaternion& other) const;
|
||||||
|
|
||||||
|
/** \brief addition */
|
||||||
|
SimpleQuaternion operator + (const SimpleQuaternion& other) const;
|
||||||
|
|
||||||
|
/** \brief minus */
|
||||||
|
SimpleQuaternion operator - (const SimpleQuaternion& other) const;
|
||||||
|
|
||||||
|
/** \brief multiplication */
|
||||||
|
SimpleQuaternion operator * (const SimpleQuaternion& other) const;
|
||||||
|
|
||||||
|
/** \brief division */
|
||||||
|
SimpleQuaternion operator - () const;
|
||||||
|
|
||||||
|
/** \brief scalar multiplication */
|
||||||
|
SimpleQuaternion operator * (BVH_REAL t) const;
|
||||||
|
|
||||||
|
/** \brief conjugate */
|
||||||
|
SimpleQuaternion conj() const;
|
||||||
|
|
||||||
|
/** \brief inverse */
|
||||||
|
SimpleQuaternion inverse() const;
|
||||||
|
|
||||||
|
/** \brief rotate a vector */
|
||||||
|
Vec3f transform(const Vec3f& v) const;
|
||||||
|
|
||||||
|
inline const BVH_REAL& getW() const { return data[0]; }
|
||||||
|
inline const BVH_REAL& getX() const { return data[1]; }
|
||||||
|
inline const BVH_REAL& getY() const { return data[2]; }
|
||||||
|
inline const BVH_REAL& getZ() const { return data[3]; }
|
||||||
|
|
||||||
|
inline BVH_REAL& getW() { return data[0]; }
|
||||||
|
inline BVH_REAL& getX() { return data[1]; }
|
||||||
|
inline BVH_REAL& getY() { return data[2]; }
|
||||||
|
inline BVH_REAL& getZ() { return data[3]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
BVH_REAL data[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Simple transform class used locally by InterpMotion */
|
||||||
|
class SimpleTransform
|
||||||
|
{
|
||||||
|
/** \brief Rotation matrix and translation vector */
|
||||||
|
Vec3f R[3];
|
||||||
|
Vec3f T;
|
||||||
|
|
||||||
|
/** \brief Quaternion representation for R */
|
||||||
|
SimpleQuaternion q;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** \brief Default transform is no movement */
|
||||||
|
SimpleTransform()
|
||||||
|
{
|
||||||
|
R[0][0] = 1; R[1][1] = 1; R[2][2] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTransform(const Vec3f R_[3], const Vec3f& T_)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R[i] = R_[i];
|
||||||
|
T = T_;
|
||||||
|
|
||||||
|
q.fromRotation(R_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Vec3f& getTranslation() const
|
||||||
|
{
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Vec3f* getRotation() const
|
||||||
|
{
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const SimpleQuaternion& getQuatRotation() const
|
||||||
|
{
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setTransform(const Vec3f R_[3], const Vec3f& T_)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R[i] = R_[i];
|
||||||
|
T = T_;
|
||||||
|
|
||||||
|
q.fromRotation(R_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setTransform(const SimpleQuaternion& q_, const Vec3f& T_)
|
||||||
|
{
|
||||||
|
q = q_;
|
||||||
|
T = T_;
|
||||||
|
q.toRotation(R);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setRotation(const Vec3f R_[3])
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 3; ++i)
|
||||||
|
R[i] = R_[i];
|
||||||
|
q.fromRotation(R_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setTranslation(const Vec3f& T_)
|
||||||
|
{
|
||||||
|
T = T_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setQuatRotation(const SimpleQuaternion& q_)
|
||||||
|
{
|
||||||
|
q = q_;
|
||||||
|
q.toRotation(R);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3f transform(const Vec3f& v) const
|
||||||
|
{
|
||||||
|
return q.transform(v) + T;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIdentity() const
|
||||||
|
{
|
||||||
|
return (R[0][0] == 1) && (R[0][1] == 0) && (R[0][2] == 0) && (R[1][0] == 0) && (R[1][1] == 1) && (R[1][2] == 0) && (R[2][0] == 0) && (R[2][1] == 0) && (R[2][2] == 1)
|
||||||
|
&& (T[0] == 0) && (T[1] == 0) && (T[2] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIdentity()
|
||||||
|
{
|
||||||
|
R[0] = Vec3f(1, 0, 0);
|
||||||
|
R[1] = Vec3f(0, 1, 0);
|
||||||
|
R[2] = Vec3f(0, 0, 1);
|
||||||
|
T = Vec3f();
|
||||||
|
q = SimpleQuaternion();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
#ifndef FCL_TRAVERSAL_NODE_BASE_H
|
||||||
|
#define FCL_TRAVERSAL_NODE_BASE_H
|
||||||
|
|
||||||
|
#include "fcl/vec_3f.h"
|
||||||
|
#include "fcl/primitive.h"
|
||||||
|
#include "fcl/BVH_front.h"
|
||||||
|
#include "fcl/BVH_model.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Main namespace */
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
class TraversalNodeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TraversalNodeBase() : enable_statistics(false) {}
|
||||||
|
|
||||||
|
virtual ~TraversalNodeBase();
|
||||||
|
|
||||||
|
/** \brief Whether b is a leaf node in the first BVH tree */
|
||||||
|
virtual bool isFirstNodeLeaf(int b) const;
|
||||||
|
|
||||||
|
/** \brief Whether b is a leaf node in the second BVH tree */
|
||||||
|
virtual bool isSecondNodeLeaf(int b) const;
|
||||||
|
|
||||||
|
/** \brief Traverse the subtree of the node in the first tree first */
|
||||||
|
virtual bool firstOverSecond(int b1, int b2) const;
|
||||||
|
|
||||||
|
/** \brief Get the left child of the node b in the first tree */
|
||||||
|
virtual int getFirstLeftChild(int b) const;
|
||||||
|
|
||||||
|
/** \brief Get the right child of the node b in the first tree */
|
||||||
|
virtual int getFirstRightChild(int b) const;
|
||||||
|
|
||||||
|
/** \brief Get the left child of the node b in the second tree */
|
||||||
|
virtual int getSecondLeftChild(int b) const;
|
||||||
|
|
||||||
|
/** \brief Get the right child of the node b in the second tree */
|
||||||
|
virtual int getSecondRightChild(int b) const;
|
||||||
|
|
||||||
|
void enableStatistics(bool enable) { enable_statistics = enable; }
|
||||||
|
|
||||||
|
bool enable_statistics;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CollisionTraversalNodeBase : public TraversalNodeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CollisionTraversalNodeBase() : TraversalNodeBase() {}
|
||||||
|
|
||||||
|
virtual ~CollisionTraversalNodeBase();
|
||||||
|
|
||||||
|
/** \brief BV test between b1 and b2 */
|
||||||
|
virtual bool BVTesting(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;
|
||||||
|
|
||||||
|
/** \brief Check whether the traversal can stop */
|
||||||
|
virtual bool canStop() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DistanceTraversalNodeBase : public TraversalNodeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DistanceTraversalNodeBase() : TraversalNodeBase() {}
|
||||||
|
|
||||||
|
virtual ~DistanceTraversalNodeBase();
|
||||||
|
|
||||||
|
virtual BVH_REAL BVTesting(int b1, int b2) const;
|
||||||
|
|
||||||
|
virtual void leafTesting(int b1, int b2) const;
|
||||||
|
|
||||||
|
virtual bool canStop(BVH_REAL c) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,423 @@
|
||||||
|
/*
|
||||||
|
* Software License Agreement (BSD License)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011, Willow Garage, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
* * Neither the name of Willow Garage, Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \author Jia Pan */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FCL_TRAVERSAL_NODE_MESH_SHAPE_H
|
||||||
|
#define FCL_TRAVERSAL_NODE_MESH_SHAPE_H
|
||||||
|
|
||||||
|
#include "fcl/geometric_shapes.h"
|
||||||
|
#include "fcl/traversal_node_base.h"
|
||||||
|
#include "fcl/BVH_model.h"
|
||||||
|
#include "fcl/geometric_shapes_utility.h"
|
||||||
|
|
||||||
|
namespace fcl
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename BV, typename S>
|
||||||
|
class BVHShapeCollisionTraversalNode : public CollisionTraversalNodeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BVHShapeCollisionTraversalNode()
|
||||||
|
{
|
||||||
|
model1 = NULL;
|
||||||
|
model2 = NULL;
|
||||||
|
|
||||||
|
num_bv_tests = 0;
|
||||||
|
num_leaf_tests = 0;
|
||||||
|
query_time_seconds = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFirstNodeLeaf(int b) const
|
||||||
|
{
|
||||||
|
return model1->getBV(b).isLeaf();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getFirstLeftChild(int b) const
|
||||||
|
{
|
||||||
|
return model1->getBV(b).leftChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getFirstRightChild(int b) const
|
||||||
|
{
|
||||||
|
return model1->getBV(b).rightChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BVTesting(int b1, int /*b2*/) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) num_bv_tests++;
|
||||||
|
BV bv_shape;
|
||||||
|
computeBV(*model2, bv_shape);
|
||||||
|
return !model1->getBV(b1).bv.overlap(bv_shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BVHModel<BV>* model1;
|
||||||
|
const S* model2;
|
||||||
|
|
||||||
|
mutable int num_bv_tests;
|
||||||
|
mutable int num_leaf_tests;
|
||||||
|
mutable BVH_REAL query_time_seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename S, typename BV>
|
||||||
|
class ShapeBVHCollisionTraversalNode : public CollisionTraversalNodeBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShapeBVHCollisionTraversalNode()
|
||||||
|
{
|
||||||
|
model1 = NULL;
|
||||||
|
model2 = NULL;
|
||||||
|
|
||||||
|
num_bv_tests = 0;
|
||||||
|
num_leaf_tests = 0;
|
||||||
|
query_time_seconds = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool firstOverSecond(int, int) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSecondNodeLeaf(int b) const
|
||||||
|
{
|
||||||
|
return model2->getBV(b).isLeaf();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSecondLeftChild(int b) const
|
||||||
|
{
|
||||||
|
return model2->getBV(b).leftChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSecondRightChild(int b) const
|
||||||
|
{
|
||||||
|
return model2->getBV(b).rightChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BVTesting(int b1, int b2) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) num_bv_tests++;
|
||||||
|
BV bv_shape;
|
||||||
|
computeBV(*model1, bv_shape);
|
||||||
|
return !model2->getBV(b2).bv.overlap(bv_shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
const S* model1;
|
||||||
|
const BVHModel<BV>* model2;
|
||||||
|
|
||||||
|
mutable int num_bv_tests;
|
||||||
|
mutable int num_leaf_tests;
|
||||||
|
mutable BVH_REAL query_time_seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief The indices of in-collision primitives of objects */
|
||||||
|
struct BVHShapeCollisionPair
|
||||||
|
{
|
||||||
|
BVHShapeCollisionPair() {}
|
||||||
|
|
||||||
|
BVHShapeCollisionPair(int id_) : id(id_) {}
|
||||||
|
|
||||||
|
BVHShapeCollisionPair(int id_, const Vec3f& n, const Vec3f& contactp, BVH_REAL depth) : id(id_),
|
||||||
|
normal(n), contact_point(contactp), penetration_depth(depth) {}
|
||||||
|
|
||||||
|
/** \brief The index of BVH's in-collision primitive */
|
||||||
|
int id;
|
||||||
|
|
||||||
|
/** \brief Contact normal */
|
||||||
|
Vec3f normal;
|
||||||
|
|
||||||
|
/** \brief Contact points */
|
||||||
|
Vec3f contact_point;
|
||||||
|
|
||||||
|
/** \brief Penetration depth for two triangles */
|
||||||
|
BVH_REAL penetration_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BVHShapeCollisionPairComp
|
||||||
|
{
|
||||||
|
bool operator()(const BVHShapeCollisionPair& a, const BVHShapeCollisionPair& b)
|
||||||
|
{
|
||||||
|
return a.id < b.id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BV, typename S>
|
||||||
|
class MeshShapeCollisionTraversalNode : public BVHShapeCollisionTraversalNode<BV, S>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MeshShapeCollisionTraversalNode() : BVHShapeCollisionTraversalNode<BV, S>()
|
||||||
|
{
|
||||||
|
vertices = NULL;
|
||||||
|
tri_indices = NULL;
|
||||||
|
|
||||||
|
num_max_contacts = 1;
|
||||||
|
exhaustive = false;
|
||||||
|
enable_contact = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void leafTesting(int b1, int /*b2*/) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) this->num_leaf_tests++;
|
||||||
|
const BVNode<BV>& node = this->model1->getBV(b1);
|
||||||
|
|
||||||
|
int primitive_id = node.primitiveId();
|
||||||
|
|
||||||
|
const Triangle& tri_id = tri_indices[primitive_id];
|
||||||
|
|
||||||
|
const Vec3f& p1 = vertices[tri_id[0]];
|
||||||
|
const Vec3f& p2 = vertices[tri_id[1]];
|
||||||
|
const Vec3f& p3 = vertices[tri_id[2]];
|
||||||
|
|
||||||
|
BVH_REAL penetration;
|
||||||
|
Vec3f normal;
|
||||||
|
Vec3f contactp;
|
||||||
|
|
||||||
|
if(!enable_contact) // only interested in collision or not
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model2), p1, p2, p3))
|
||||||
|
{
|
||||||
|
pairs.push_back(BVHShapeCollisionPair(primitive_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model2), p1, p2, p3, &contactp, &penetration, &normal))
|
||||||
|
{
|
||||||
|
pairs.push_back(BVHShapeCollisionPair(primitive_id, normal, contactp, penetration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canStop() const
|
||||||
|
{
|
||||||
|
return (pairs.size() > 0) && (!exhaustive) && (num_max_contacts <= (int)pairs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3f* vertices;
|
||||||
|
Triangle* tri_indices;
|
||||||
|
|
||||||
|
int num_max_contacts;
|
||||||
|
bool exhaustive;
|
||||||
|
bool enable_contact;
|
||||||
|
|
||||||
|
mutable std::vector<BVHShapeCollisionPair> pairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
class MeshShapeCollisionTraversalNodeOBB : public MeshShapeCollisionTraversalNode<OBB, S>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MeshShapeCollisionTraversalNodeOBB() : MeshShapeCollisionTraversalNode<OBB, S>()
|
||||||
|
{
|
||||||
|
R[0] = Vec3f(1, 0, 0);
|
||||||
|
R[1] = Vec3f(0, 1, 0);
|
||||||
|
R[2] = Vec3f(0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BVTesting(int b1, int /*b2*/) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) this->num_bv_tests++;
|
||||||
|
OBB bv_shape;
|
||||||
|
computeBV(*this->model2, bv_shape);
|
||||||
|
return !overlap(R, T, bv_shape, this->model1->getBV(b1).bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void leafTesting(int b1, int /*b2*/) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) this->num_leaf_tests++;
|
||||||
|
const BVNode<OBB>& node = this->model1->getBV(b1);
|
||||||
|
|
||||||
|
int primitive_id = node.primitiveId();
|
||||||
|
|
||||||
|
const Triangle& tri_id = this->tri_indices[primitive_id];
|
||||||
|
|
||||||
|
const Vec3f& p1 = this->vertices[tri_id[0]];
|
||||||
|
const Vec3f& p2 = this->vertices[tri_id[1]];
|
||||||
|
const Vec3f& p3 = this->vertices[tri_id[2]];
|
||||||
|
|
||||||
|
BVH_REAL penetration;
|
||||||
|
Vec3f normal;
|
||||||
|
Vec3f contactp;
|
||||||
|
|
||||||
|
if(!this->enable_contact) // only interested in collision or not
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model2), p1, p2, p3, R, T))
|
||||||
|
{
|
||||||
|
this->pairs.push_back(BVHShapeCollisionPair(primitive_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model2), p1, p2, p3, R, T, &contactp, &penetration, &normal))
|
||||||
|
{
|
||||||
|
this->pairs.push_back(BVHShapeCollisionPair(primitive_id, normal, contactp, penetration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// R, T is the transformation of bvh model
|
||||||
|
Vec3f R[3];
|
||||||
|
Vec3f T;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename S, typename BV>
|
||||||
|
class ShapeMeshCollisionTraversalNode : public ShapeBVHCollisionTraversalNode<S, BV>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShapeMeshCollisionTraversalNode() : ShapeBVHCollisionTraversalNode<S, BV>()
|
||||||
|
{
|
||||||
|
vertices = NULL;
|
||||||
|
tri_indices = NULL;
|
||||||
|
|
||||||
|
num_max_contacts = 1;
|
||||||
|
exhaustive = false;
|
||||||
|
enable_contact = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void leafTesting(int b1, int b2) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) this->num_leaf_tests++;
|
||||||
|
const BVNode<BV>& node = this->model2->getBV(b2);
|
||||||
|
|
||||||
|
int primitive_id = node.primitiveId();
|
||||||
|
|
||||||
|
const Triangle& tri_id = tri_indices[primitive_id];
|
||||||
|
|
||||||
|
const Vec3f& p1 = vertices[tri_id[0]];
|
||||||
|
const Vec3f& p2 = vertices[tri_id[1]];
|
||||||
|
const Vec3f& p3 = vertices[tri_id[2]];
|
||||||
|
|
||||||
|
BVH_REAL penetration;
|
||||||
|
Vec3f normal;
|
||||||
|
Vec3f contactp;
|
||||||
|
|
||||||
|
if(!enable_contact) // only interested in collision or not
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model1), p1, p2, p3))
|
||||||
|
{
|
||||||
|
pairs.push_back(BVHShapeCollisionPair(primitive_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model1), p1, p2, p3, &contactp, &penetration, &normal))
|
||||||
|
{
|
||||||
|
pairs.push_back(BVHShapeCollisionPair(primitive_id, normal, contactp, penetration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canStop() const
|
||||||
|
{
|
||||||
|
return (pairs.size() > 0) && (!exhaustive) && (num_max_contacts <= (int)pairs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3f* vertices;
|
||||||
|
Triangle* tri_indices;
|
||||||
|
|
||||||
|
int num_max_contacts;
|
||||||
|
bool exhaustive;
|
||||||
|
bool enable_contact;
|
||||||
|
|
||||||
|
mutable std::vector<BVHShapeCollisionPair> pairs;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
class ShapeMeshCollisionTraversalNodeOBB : public ShapeMeshCollisionTraversalNode<S, OBB>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShapeMeshCollisionTraversalNodeOBB() : ShapeMeshCollisionTraversalNode<S, OBB>()
|
||||||
|
{
|
||||||
|
R[0] = Vec3f(1, 0, 0);
|
||||||
|
R[1] = Vec3f(0, 1, 0);
|
||||||
|
R[2] = Vec3f(0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BVTesting(int b1, int b2) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) this->num_bv_tests++;
|
||||||
|
OBB bv_shape;
|
||||||
|
computeBV(*this->model1, bv_shape);
|
||||||
|
return !overlap(R, T, bv_shape, this->model2->getBV(b2).bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void leafTesting(int b1, int b2) const
|
||||||
|
{
|
||||||
|
if(this->enable_statistics) this->num_leaf_tests++;
|
||||||
|
const BVNode<OBB>& node = this->model2->getBV(b2);
|
||||||
|
|
||||||
|
int primitive_id = node.primitiveId();
|
||||||
|
|
||||||
|
const Triangle& tri_id = this->tri_indices[primitive_id];
|
||||||
|
|
||||||
|
const Vec3f& p1 = this->vertices[tri_id[0]];
|
||||||
|
const Vec3f& p2 = this->vertices[tri_id[1]];
|
||||||
|
const Vec3f& p3 = this->vertices[tri_id[2]];
|
||||||
|
|
||||||
|
BVH_REAL penetration;
|
||||||
|
Vec3f normal;
|
||||||
|
Vec3f contactp;
|
||||||
|
|
||||||
|
if(!this->enable_contact) // only interested in collision or not
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model1), p1, p2, p3, R, T))
|
||||||
|
{
|
||||||
|
this->pairs.push_back(BVHShapeCollisionPair(primitive_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(shapeTriangleIntersect(*(this->model1), p1, p2, p3, R, T, &contactp, &penetration, &normal))
|
||||||
|
{
|
||||||
|
this->pairs.push_back(BVHShapeCollisionPair(primitive_id, normal, contactp, penetration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// R, T is the transformation of bvh model
|
||||||
|
Vec3f R[3];
|
||||||
|
Vec3f T;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue