From f68bf52a801c8bebf220e05ae40c5e90c3304cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20V=2E=20G=C3=B3mez?= Date: Mon, 2 May 2016 22:20:21 +0200 Subject: [PATCH 01/27] Improve the generation of config.cmake and version.cmake files Improve the generation of config.cmake and version.cmake files, relocatable via CONFIGURE_PACKAGE_CONFIG_FILE. Upgrades the Travis build farm requirements to Ubuntu Trusty. --- .travis.yml | 4 +- CMakeLists.txt | 2 +- dynamicEDT3D/CMakeLists.txt | 34 +++++++++++---- .../dynamicEDT3DConfig-version.cmake.in | 11 ----- dynamicEDT3D/dynamicEDT3DConfig.cmake.in | 15 +++---- octomap/CMakeLists.txt | 32 +++++++++++---- octomap/octomap-config-version.cmake.in | 11 ----- octomap/octomap-config.cmake.in | 14 +++---- octovis/CMakeLists.txt | 41 +++++++++++++------ octovis/octovis-config-version.cmake.in | 11 ----- octovis/octovis-config.cmake.in | 10 ++--- 11 files changed, 100 insertions(+), 85 deletions(-) delete mode 100644 dynamicEDT3D/dynamicEDT3DConfig-version.cmake.in delete mode 100644 octomap/octomap-config-version.cmake.in delete mode 100644 octovis/octovis-config-version.cmake.in diff --git a/.travis.yml b/.travis.yml index 2e692af2..2fa49387 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,12 @@ language: cpp +sudo: required +dist: trusty compiler: - gcc - clang before_install: - sudo apt-get update -qq - - sudo apt-get install -qq libqt4-dev libqt4-opengl-dev libqglviewer-qt4-dev + - sudo apt-get install -qq libqt4-dev libqt4-opengl-dev libqglviewer-dev before_script: - mkdir build - cd build diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c56033d..d7fc92e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT( octomap-distribution ) ENABLE_TESTING() # enable CTest environment of subprojects diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 195a8704..5ff8e478 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT(dynamicEDT3D) ENABLE_TESTING() @@ -96,10 +96,18 @@ ELSE() ENDIF() # not used right now (export depends?) #set(DYNEDT3D_CMAKE_DIR "${PROJECT_BINARY_DIR}") -configure_file(dynamicEDT3DConfig.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DConfig.cmake" @ONLY) -configure_file(dynamicEDT3DConfig-version.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DConfig-version.cmake" @ONLY) +include(CMakePackageConfigHelpers) + +CONFIGURE_PACKAGE_CONFIG_FILE( + dynamicEDT3DConfig.cmake.in + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DConfig.cmake" + PATH_VARS DYNAMICEDT3D_INCLUDE_DIRS DYNAMICEDT3D_LIB_DIR + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dynamicEDT3D) + +WRITE_BASIC_PACKAGE_VERSION_FILE( + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DConfig-version.cmake" + VERSION ${DYNAMICEDT3D_VERSION} + COMPATIBILITY AnyNewerVersion) # Install the export set for use with the install-tree #install(EXPORT FooBarLibraryDepends DESTINATION @@ -111,10 +119,18 @@ configure_file(dynamicEDT3DConfig-version.cmake.in set(DYNAMICEDT3D_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") set(DYNAMICEDT3D_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") #set(DYNAMICEDT3D_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") -configure_file(dynamicEDT3DConfig.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig.cmake" @ONLY) -configure_file(dynamicEDT3DConfig-version.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig-version.cmake" @ONLY) + +CONFIGURE_PACKAGE_CONFIG_FILE( + dynamicEDT3DConfig.cmake.in + "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig.cmake" + PATH_VARS DYNAMICEDT3D_INCLUDE_DIRS DYNAMICEDT3D_LIB_DIR + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dynamicEDT3D) + +WRITE_BASIC_PACKAGE_VERSION_FILE( + "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig-version.cmake" + VERSION ${DYNAMICEDT3D_VERSION} + COMPATIBILITY AnyNewerVersion) + install(FILES "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig.cmake" "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig-version.cmake" diff --git a/dynamicEDT3D/dynamicEDT3DConfig-version.cmake.in b/dynamicEDT3D/dynamicEDT3DConfig-version.cmake.in deleted file mode 100644 index 722ebb3d..00000000 --- a/dynamicEDT3D/dynamicEDT3DConfig-version.cmake.in +++ /dev/null @@ -1,11 +0,0 @@ -set(PACKAGE_VERSION "@DYNAMICEDT3D_VERSION@") - -# Check whether the requested PACKAGE_FIND_VERSION is compatible -if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_COMPATIBLE FALSE) -else() - set(PACKAGE_VERSION_COMPATIBLE TRUE) - if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_EXACT TRUE) - endif() -endif() \ No newline at end of file diff --git a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in index 9cd3df84..5055b589 100644 --- a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in +++ b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in @@ -1,5 +1,4 @@ # - Config file for the dynamicEDT3D package -# (example from http://www.vtk.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file) # # Usage from an external project: # In your CMakeLists.txt, add these lines: @@ -12,12 +11,14 @@ # DYNAMICEDT3D_INCLUDE_DIRS - include directories for dynamicEDT3D # DYNAMICEDT3D_LIBRARY_DIRS - library directories for dynamicEDT3D (normally not used!) # DYNAMICEDT3D_LIBRARIES - libraries to link against - + +@PACKAGE_INIT@ + # Tell the user project where to find our headers and libraries -set(DYNAMICEDT3D_INCLUDE_DIRS "@DYNAMICEDT3D_INCLUDE_DIRS@") -set(DYNAMICEDT3D_LIBRARY_DIRS "@DYNAMICEDT3D_LIB_DIR@") - +set(DYNAMICEDT3D_INCLUDE_DIRS "@PACKAGE_DYNAMICEDT3D_INCLUDE_DIRS@") +set(DYNAMICEDT3D_LIBRARY_DIRS "@PACKAGE_DYNAMICEDT3D_LIB_DIR@") + # Our library dependencies (contains definitions for IMPORTED targets) # include("@FOOBAR_CMAKE_DIR@/FooBarLibraryDepends.cmake") - -set(DYNAMICEDT3D_LIBRARIES "@DYNAMICEDT3D_LIB_DIR@/@DYNAMICEDT3D_LIBRARY@") + +set(DYNAMICEDT3D_LIBRARIES "@PACKAGE_DYNAMICEDT3D_LIB_DIR@/@DYNAMICEDT3D_LIBRARY@") diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index fcafca18..1ba3417f 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT( octomap ) ENABLE_TESTING() @@ -103,11 +103,18 @@ ENDIF() # not used right now (export depends?) #set(OCTOMAP_CMAKE_DIR "${PROJECT_BINARY_DIR}") -configure_file(octomap-config.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-config.cmake" @ONLY) -configure_file(octomap-config-version.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-config-version.cmake" @ONLY) +include(CMakePackageConfigHelpers) +CONFIGURE_PACKAGE_CONFIG_FILE( + octomap-config.cmake.in + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-config.cmake" + PATH_VARS OCTOMAP_INCLUDE_DIRS OCTOMAP_LIB_DIR + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/octomap) + +WRITE_BASIC_PACKAGE_VERSION_FILE( + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-config-version.cmake" + VERSION ${OCTOMAP_VERSION} + COMPATIBILITY AnyNewerVersion) # Create a octomap-config.cmake file for the use from the install tree # and install it @@ -115,10 +122,17 @@ set(OCTOMAP_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") set(OCTOMAP_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") #set(OCTOMAP_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") -configure_file(octomap-config.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config.cmake" @ONLY) -configure_file(octomap-config-version.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake" @ONLY) +CONFIGURE_PACKAGE_CONFIG_FILE( + octomap-config.cmake.in + "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config.cmake" + PATH_VARS OCTOMAP_INCLUDE_DIRS OCTOMAP_LIB_DIR + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/octomap) + +WRITE_BASIC_PACKAGE_VERSION_FILE( + ${PROJECT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake + VERSION ${OCTOMAP_VERSION} + COMPATIBILITY AnyNewerVersion) + install(FILES "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config.cmake" "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config-version.cmake" diff --git a/octomap/octomap-config-version.cmake.in b/octomap/octomap-config-version.cmake.in deleted file mode 100644 index c1a11734..00000000 --- a/octomap/octomap-config-version.cmake.in +++ /dev/null @@ -1,11 +0,0 @@ -set(PACKAGE_VERSION "@OCTOMAP_VERSION@") - -# Check whether the requested PACKAGE_FIND_VERSION is compatible -if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_COMPATIBLE FALSE) -else() - set(PACKAGE_VERSION_COMPATIBLE TRUE) - if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_EXACT TRUE) - endif() -endif() \ No newline at end of file diff --git a/octomap/octomap-config.cmake.in b/octomap/octomap-config.cmake.in index 2f5ba8c5..5ab5dee4 100644 --- a/octomap/octomap-config.cmake.in +++ b/octomap/octomap-config.cmake.in @@ -17,18 +17,16 @@ # LINK_DIRECTORIES with this path is NOT needed. # - OCTOMAP_INCLUDE_DIRS : The OctoMap include directories. # -# Based on the example CMake Tutorial -# http://www.vtk.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file -# and OpenCVConfig.cmake.in from OpenCV # =================================================================================== - -set(OCTOMAP_INCLUDE_DIRS "@OCTOMAP_INCLUDE_DIRS@") -set(OCTOMAP_LIBRARY_DIRS "@OCTOMAP_LIB_DIR@") +@PACKAGE_INIT@ + +set(OCTOMAP_INCLUDE_DIRS "@PACKAGE_OCTOMAP_INCLUDE_DIRS@") +set(OCTOMAP_LIBRARY_DIRS "@PACKAGE_OCTOMAP_LIB_DIR@") # Set library names set(OCTOMAP_LIBRARIES - "@OCTOMAP_LIB_DIR@/@OCTOMAP_LIBRARY@" - "@OCTOMAP_LIB_DIR@/@OCTOMATH_LIBRARY@" + "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMAP_LIBRARY@" + "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMATH_LIBRARY@" ) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index 87fb9a51..8d1a0636 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT( octovis ) # # version (e.g. for packaging) @@ -61,6 +61,7 @@ SET( BUILD_VIEWER 0) # Look for required libraries: FIND_PACKAGE(OpenGL) FIND_PACKAGE(Qt4) + IF (OpenGL-NOTFOUND OR Qt4-NOTFOUND) MESSAGE ( "OpenGL and QT4 are required for octovis but could not be found.") ELSE() @@ -84,7 +85,7 @@ IF(BUILD_VIEWER) INCLUDE( CMakeLists_src.txt ) # Create an octovis-config.cmake file for the use from the build tree - set(OCTOVIS_INCLUDE_DIR "${INCLUDE_DIRS}") + set(OCTOVIS_INCLUDE_DIRS "${INCLUDE_DIRS}") set(OCTOVIS_LIB_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") # Set library names as absolute paths # Windows, spec. MSVC requires the .lib suffix for imported libs @@ -98,28 +99,44 @@ IF(BUILD_VIEWER) ) ENDIF() + include(CMakePackageConfigHelpers) + + CONFIGURE_PACKAGE_CONFIG_FILE( + octovis-config.cmake.in + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-config.cmake" + PATH_VARS OCTOVIS_INCLUDE_DIRS OCTOVIS_LIB_DIR + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/octovis) + + WRITE_BASIC_PACKAGE_VERSION_FILE( + "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-config-version.cmake" + VERSION ${OCTOVIS_VERSION} + COMPATIBILITY AnyNewerVersion) + # not used right now (export depends?) #set(OCTOMAP_CMAKE_DIR "${PROJECT_BINARY_DIR}") - configure_file(octovis-config.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-config.cmake" @ONLY) - configure_file(octovis-config-version.cmake.in - "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-config-version.cmake" @ONLY) # Create a octovis-config.cmake file for the use from the install tree # and install it set(OCTOVIS_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") set(OCTOVIS_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") #set(OCTOMAP_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") - configure_file(octovis-config.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config.cmake" @ONLY) - configure_file(octovis-config-version.cmake.in - "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" @ONLY) + + CONFIGURE_PACKAGE_CONFIG_FILE( + octovis-config.cmake.in + "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config.cmake" + PATH_VARS OCTOVIS_INCLUDE_DIRS OCTOVIS_LIB_DIR + INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/octovis) + + WRITE_BASIC_PACKAGE_VERSION_FILE( + "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" + VERSION ${OCTOVIS_VERSION} + COMPATIBILITY AnyNewerVersion) + install(FILES "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config.cmake" "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config-version.cmake" DESTINATION share/octovis/) - - + # #installation: # # store all header files to install: file(GLOB octovis_HDRS *.h *.hxx *.hpp) diff --git a/octovis/octovis-config-version.cmake.in b/octovis/octovis-config-version.cmake.in deleted file mode 100644 index c8263826..00000000 --- a/octovis/octovis-config-version.cmake.in +++ /dev/null @@ -1,11 +0,0 @@ -set(PACKAGE_VERSION "@OCTOVIS_VERSION@") - -# Check whether the requested PACKAGE_FIND_VERSION is compatible -if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_COMPATIBLE FALSE) -else() - set(PACKAGE_VERSION_COMPATIBLE TRUE) - if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_EXACT TRUE) - endif() -endif() \ No newline at end of file diff --git a/octovis/octovis-config.cmake.in b/octovis/octovis-config.cmake.in index 89425d5d..7969b521 100644 --- a/octovis/octovis-config.cmake.in +++ b/octovis/octovis-config.cmake.in @@ -1,17 +1,17 @@ -# - Config file for the OctoMap package -# (example from http://www.vtk.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file) # It defines the following variables # OCTOVIS_INCLUDE_DIRS - include directories for OctoMap viewer # OCTOVIS_LIBRARY_DIRS - library directories for OctoMap viewer # OCTOVIS_LIBRARIES - libraries to link against -set(OCTOVIS_INCLUDE_DIRS "@QGLViewer_INCLUDE_DIR@" "@OCTOVIS_INCLUDE_DIR@") -set(OCTOVIS_LIBRARY_DIRS "@QGLViewer_LIBRARY_DIR@" "@OCTOVIS_LIB_DIR@") +@PACKAGE_INIT@ + +set(OCTOVIS_INCLUDE_DIRS "@QGLViewer_INCLUDE_DIR@" "@PACKAGE_OCTOVIS_INCLUDE_DIRS@") +set(OCTOVIS_LIBRARY_DIRS "@QGLViewer_LIBRARY_DIR@" "@PACKAGE_OCTOVIS_LIB_DIR@") # Set library names as absolute paths: set(OCTOVIS_LIBRARIES "@QGLViewer_LIBRARIES@" "@QT_LIBRARIES@" - "@OCTOVIS_LIB_DIR@/@OCTOVIS_LIBRARY@" + "@PACKAGE_OCTOVIS_LIB_DIR@/@OCTOVIS_LIBRARY@" ) From 76a6b3cc0175751f484159091902610024f0fcce Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Tue, 3 May 2016 20:49:57 +0200 Subject: [PATCH 02/27] Make relocatable CMake configs more robust using set_and_check() --- dynamicEDT3D/dynamicEDT3DConfig.cmake.in | 7 ++----- octomap/octomap-config.cmake.in | 4 ++-- octovis/octovis-config.cmake.in | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in index 5055b589..53fe264c 100644 --- a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in +++ b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in @@ -15,10 +15,7 @@ @PACKAGE_INIT@ # Tell the user project where to find our headers and libraries -set(DYNAMICEDT3D_INCLUDE_DIRS "@PACKAGE_DYNAMICEDT3D_INCLUDE_DIRS@") -set(DYNAMICEDT3D_LIBRARY_DIRS "@PACKAGE_DYNAMICEDT3D_LIB_DIR@") - -# Our library dependencies (contains definitions for IMPORTED targets) -# include("@FOOBAR_CMAKE_DIR@/FooBarLibraryDepends.cmake") +set_and_check(DYNAMICEDT3D_INCLUDE_DIRS "@PACKAGE_DYNAMICEDT3D_INCLUDE_DIRS@") +set_and_check(DYNAMICEDT3D_LIBRARY_DIRS "@PACKAGE_DYNAMICEDT3D_LIB_DIR@") set(DYNAMICEDT3D_LIBRARIES "@PACKAGE_DYNAMICEDT3D_LIB_DIR@/@DYNAMICEDT3D_LIBRARY@") diff --git a/octomap/octomap-config.cmake.in b/octomap/octomap-config.cmake.in index 5ab5dee4..6c6dd747 100644 --- a/octomap/octomap-config.cmake.in +++ b/octomap/octomap-config.cmake.in @@ -21,8 +21,8 @@ @PACKAGE_INIT@ -set(OCTOMAP_INCLUDE_DIRS "@PACKAGE_OCTOMAP_INCLUDE_DIRS@") -set(OCTOMAP_LIBRARY_DIRS "@PACKAGE_OCTOMAP_LIB_DIR@") +set_and_check(OCTOMAP_INCLUDE_DIRS "@PACKAGE_OCTOMAP_INCLUDE_DIRS@") +set_and_check(OCTOMAP_LIBRARY_DIRS "@PACKAGE_OCTOMAP_LIB_DIR@") # Set library names diff --git a/octovis/octovis-config.cmake.in b/octovis/octovis-config.cmake.in index 7969b521..1212a645 100644 --- a/octovis/octovis-config.cmake.in +++ b/octovis/octovis-config.cmake.in @@ -5,8 +5,8 @@ @PACKAGE_INIT@ -set(OCTOVIS_INCLUDE_DIRS "@QGLViewer_INCLUDE_DIR@" "@PACKAGE_OCTOVIS_INCLUDE_DIRS@") -set(OCTOVIS_LIBRARY_DIRS "@QGLViewer_LIBRARY_DIR@" "@PACKAGE_OCTOVIS_LIB_DIR@") +set_and_check(OCTOVIS_INCLUDE_DIRS "@QGLViewer_INCLUDE_DIR@" "@PACKAGE_OCTOVIS_INCLUDE_DIRS@") +set_and_check(OCTOVIS_LIBRARY_DIRS "@QGLViewer_LIBRARY_DIR@" "@PACKAGE_OCTOVIS_LIB_DIR@") # Set library names as absolute paths: From e378f067a9166c1cf4e5b3bc1c16d03cfbb37c36 Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Fri, 6 May 2016 14:22:15 +0200 Subject: [PATCH 03/27] More travis build jobs in matrix, move scripts into own dir --- .travis.yml | 13 +++++-- .../increase_version.py | 0 scripts/travis_build_jobs.sh | 39 +++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) rename increase_version.py => scripts/increase_version.py (100%) create mode 100755 scripts/travis_build_jobs.sh diff --git a/.travis.yml b/.travis.yml index 2fa49387..cb4cda90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,12 @@ before_install: - sudo apt-get update -qq - sudo apt-get install -qq libqt4-dev libqt4-opengl-dev libqglviewer-dev before_script: - - mkdir build - - cd build - - cmake .. -script: make && make test +script: ./scripts/travis_build_jobs.sh $VARIANT +env: + - VARIANT=dist + - VARIANT=components +matrix: + exclude: + - compiler: clang + env: VARIANT=components + diff --git a/increase_version.py b/scripts/increase_version.py similarity index 100% rename from increase_version.py rename to scripts/increase_version.py diff --git a/scripts/travis_build_jobs.sh b/scripts/travis_build_jobs.sh new file mode 100755 index 00000000..64a2e88c --- /dev/null +++ b/scripts/travis_build_jobs.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# travis build script for test compilations + +set -e + +function build { + cd $1 + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/tmp/octomap/$1 + make -j4 + cd .. +} + +case "$1" in +"dist") + build . + cd build && make test + make install + ;; +"components") + build octomap + cd build && make test + make install + cd ../.. + build dynamicEDT3D + cd .. + build octovis + cd .. + ;; +*) + echo "Invalid build variant" + exit 1 +esac + + + + From 595cb83bfe862524ebb571c628486710794c7b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20V=2E=20G=C3=B3mez?= Date: Mon, 13 Jun 2016 20:29:00 +0200 Subject: [PATCH 04/27] Templated dynamicEDT3D (#120) * dynamicEDT3D converted to template form, for now only OctomapStamped has been tested * compatible to the previous API --- .../include/dynamicEDT3D/dynamicEDTOctomap.h | 27 +++-- .../dynamicEDT3D/dynamicEDTOctomap.hxx} | 81 +++++++------- dynamicEDT3D/src/CMakeLists.txt | 1 - dynamicEDT3D/src/examples/CMakeLists.txt | 3 + .../src/examples/exampleEDTOctomapStamped.cpp | 102 ++++++++++++++++++ 5 files changed, 167 insertions(+), 47 deletions(-) rename dynamicEDT3D/{src/dynamicEDTOctomap.cpp => include/dynamicEDT3D/dynamicEDTOctomap.hxx} (75%) create mode 100644 dynamicEDT3D/src/examples/exampleEDTOctomapStamped.cpp diff --git a/dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.h b/dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.h index 6da5ed26..b071853a 100644 --- a/dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.h +++ b/dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.h @@ -40,36 +40,38 @@ #include "dynamicEDT3D.h" #include +#include -/// A DynamicEDTOctomap object connects a DynamicEDT3D object to an octomap. -class DynamicEDTOctomap: private DynamicEDT3D { +/// A DynamicEDTOctomapBase object connects a DynamicEDT3D object to an octomap. +template +class DynamicEDTOctomapBase: private DynamicEDT3D { public: - /** Create a DynamicEDTOctomap object that maintains a distance transform in the bounding box given by bbxMin, bbxMax and clamps distances at maxdist. + /** Create a DynamicEDTOctomapBase object that maintains a distance transform in the bounding box given by bbxMin, bbxMax and clamps distances at maxdist. * treatUnknownAsOccupied configures the treatment of unknown cells in the distance computation. * * The constructor copies occupancy data but does not yet compute the distance map. You need to call udpate to do this. * * The distance map is maintained in a full three-dimensional array, i.e., there exists a float field in memory for every voxel inside the bounding box given by bbxMin and bbxMax. Consider this when computing distance maps for large octomaps, they will use much more memory than the octomap itself! */ - DynamicEDTOctomap(float maxdist, octomap::OcTree* _octree, octomap::point3d bbxMin, octomap::point3d bbxMax, bool treatUnknownAsOccupied); + DynamicEDTOctomapBase(float maxdist, TREE* _octree, octomap::point3d bbxMin, octomap::point3d bbxMax, bool treatUnknownAsOccupied); - virtual ~DynamicEDTOctomap(); + virtual ~DynamicEDTOctomapBase(); ///trigger updating of the distance map. This will query the octomap for the set of changes since the last update. ///If you set updateRealDist to false, computations will be faster (square root will be omitted), but you can only retrieve squared distances virtual void update(bool updateRealDist=true); ///retrieves distance and closestObstacle (closestObstacle is to be discarded if distance is maximum distance, the method does not write closestObstacle in this case). - ///Returns DynamicEDTOctomap::distanceValue_Error if point is outside the map. + ///Returns DynamicEDTOctomapBase::distanceValue_Error if point is outside the map. void getDistanceAndClosestObstacle(const octomap::point3d& p, float &distance, octomap::point3d& closestObstacle) const; - ///retrieves distance at point. Returns DynamicEDTOctomap::distanceValue_Error if point is outside the map. + ///retrieves distance at point. Returns DynamicEDTOctomapBase::distanceValue_Error if point is outside the map. float getDistance(const octomap::point3d& p) const; - ///retrieves distance at key. Returns DynamicEDTOctomap::distanceValue_Error if key is outside the map. + ///retrieves distance at key. Returns DynamicEDTOctomapBase::distanceValue_Error if key is outside the map. float getDistance(const octomap::OcTreeKey& k) const; - ///retrieves squared distance in cells at point. Returns DynamicEDTOctomap::distanceInCellsValue_Error if point is outside the map. + ///retrieves squared distance in cells at point. Returns DynamicEDTOctomapBase::distanceInCellsValue_Error if point is outside the map. int getSquaredDistanceInCells(const octomap::point3d& p) const; //variant of getDistanceAndClosestObstacle that ommits the check whether p is inside the area of the distance map. Use only if you are certain that p is covered by the distance map and if you need to save the time of the check. @@ -111,7 +113,7 @@ class DynamicEDTOctomap: private DynamicEDT3D { void mapToWorld(int x, int y, int z, octomap::point3d &p) const; void mapToWorld(int x, int y, int z, octomap::OcTreeKey &key) const; - octomap::OcTree* octree; + TREE* octree; bool unknownOccupied; int treeDepth; double treeResolution; @@ -120,4 +122,9 @@ class DynamicEDTOctomap: private DynamicEDT3D { int offsetX, offsetY, offsetZ; }; +typedef DynamicEDTOctomapBase DynamicEDTOctomap; +typedef DynamicEDTOctomapBase DynamicEDTOctomapStamped; + +#include "dynamicEDTOctomap.hxx" + #endif /* DYNAMICEDTOCTOMAP_H_ */ diff --git a/dynamicEDT3D/src/dynamicEDTOctomap.cpp b/dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.hxx similarity index 75% rename from dynamicEDT3D/src/dynamicEDTOctomap.cpp rename to dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.hxx index b66c8c3a..a329865c 100644 --- a/dynamicEDT3D/src/dynamicEDTOctomap.cpp +++ b/dynamicEDT3D/include/dynamicEDT3D/dynamicEDTOctomap.hxx @@ -35,12 +35,14 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +template +float DynamicEDTOctomapBase::distanceValue_Error = -1.0; -float DynamicEDTOctomap::distanceValue_Error = -1.0; -int DynamicEDTOctomap::distanceInCellsValue_Error = -1; +template +int DynamicEDTOctomapBase::distanceInCellsValue_Error = -1; -DynamicEDTOctomap::DynamicEDTOctomap(float maxdist, octomap::OcTree* _octree, octomap::point3d bbxMin, octomap::point3d bbxMax, bool treatUnknownAsOccupied) +template +DynamicEDTOctomapBase::DynamicEDTOctomapBase(float maxdist, TREE* _octree, octomap::point3d bbxMin, octomap::point3d bbxMax, bool treatUnknownAsOccupied) : DynamicEDT3D(((int) (maxdist/_octree->getResolution()+1)*((int) (maxdist/_octree->getResolution()+1)))), octree(_octree), unknownOccupied(treatUnknownAsOccupied) { treeDepth = octree->getTreeDepth(); @@ -49,12 +51,14 @@ DynamicEDTOctomap::DynamicEDTOctomap(float maxdist, octomap::OcTree* _octree, oc octree->enableChangeDetection(true); } -DynamicEDTOctomap::~DynamicEDTOctomap() { +template +DynamicEDTOctomapBase::~DynamicEDTOctomapBase() { } -void DynamicEDTOctomap::update(bool updateRealDist){ +template +void DynamicEDTOctomapBase::update(bool updateRealDist){ for(octomap::KeyBoolMap::const_iterator it = octree->changedKeysBegin(), end=octree->changedKeysEnd(); it!=end; ++it){ //the keys in this list all go down to the lowest level! @@ -67,7 +71,7 @@ void DynamicEDTOctomap::update(bool updateRealDist){ if(key[0] > boundingBoxMaxKey[0] || key[1] > boundingBoxMaxKey[1] || key[2] > boundingBoxMaxKey[2]) continue; - octomap::OcTreeNode* node = octree->search(key); + typename TREE::NodeType* node = octree->search(key); assert(node); //"node" is not necessarily at lowest level, BUT: the occupancy value of this node //has to be the same as of the node indexed by the key *it @@ -79,7 +83,8 @@ void DynamicEDTOctomap::update(bool updateRealDist){ DynamicEDT3D::update(updateRealDist); } -void DynamicEDTOctomap::initializeOcTree(octomap::point3d bbxMin, octomap::point3d bbxMax){ +template +void DynamicEDTOctomapBase::initializeOcTree(octomap::point3d bbxMin, octomap::point3d bbxMax){ boundingBoxMinKey = octree->coordToKey(bbxMin); boundingBoxMaxKey = octree->coordToKey(bbxMax); @@ -96,7 +101,7 @@ void DynamicEDTOctomap::initializeOcTree(octomap::point3d bbxMin, octomap::point if(unknownOccupied == false){ - for(octomap::OcTree::leaf_bbx_iterator it = octree->begin_leafs_bbx(bbxMin,bbxMax), end=octree->end_leafs_bbx(); it!= end; ++it){ + for(typename TREE::leaf_bbx_iterator it = octree->begin_leafs_bbx(bbxMin,bbxMax), end=octree->end_leafs_bbx(); it!= end; ++it){ if(octree->isNodeOccupied(*it)){ int nodeDepth = it.getDepth(); if( nodeDepth == treeDepth){ @@ -130,7 +135,7 @@ void DynamicEDTOctomap::initializeOcTree(octomap::point3d bbxMin, octomap::point for(int dz=0; dzsearch(key); + typename TREE::NodeType* node = octree->search(key); if(!node || octree->isNodeOccupied(node)){ insertMaxDepthLeafAtInitialize(key); } @@ -140,7 +145,8 @@ void DynamicEDTOctomap::initializeOcTree(octomap::point3d bbxMin, octomap::point } } -void DynamicEDTOctomap::insertMaxDepthLeafAtInitialize(octomap::OcTreeKey key){ +template +void DynamicEDTOctomapBase::insertMaxDepthLeafAtInitialize(octomap::OcTreeKey key){ bool isSurrounded = true; @@ -149,7 +155,7 @@ void DynamicEDTOctomap::insertMaxDepthLeafAtInitialize(octomap::OcTreeKey key){ for(int dz=-1; dz<=1; dz++){ if(dx==0 && dy==0 && dz==0) continue; - octomap::OcTreeNode* node = octree->search(octomap::OcTreeKey(key[0]+dx, key[1]+dy, key[2]+dz)); + typename TREE::NodeType* node = octree->search(octomap::OcTreeKey(key[0]+dx, key[1]+dy, key[2]+dz)); if((!unknownOccupied && node==NULL) || ((node!=NULL) && (octree->isNodeOccupied(node)==false))){ isSurrounded = false; break; @@ -176,30 +182,34 @@ void DynamicEDTOctomap::insertMaxDepthLeafAtInitialize(octomap::OcTreeKey key){ } } -void DynamicEDTOctomap::updateMaxDepthLeaf(octomap::OcTreeKey& key, bool occupied){ +template +void DynamicEDTOctomapBase::updateMaxDepthLeaf(octomap::OcTreeKey& key, bool occupied){ if(occupied) setObstacle(key[0]+offsetX, key[1]+offsetY, key[2]+offsetZ); else removeObstacle(key[0]+offsetX, key[1]+offsetY, key[2]+offsetZ); } -void DynamicEDTOctomap::worldToMap(const octomap::point3d &p, int &x, int &y, int &z) const { +template +void DynamicEDTOctomapBase::worldToMap(const octomap::point3d &p, int &x, int &y, int &z) const { octomap::OcTreeKey key = octree->coordToKey(p); x = key[0] + offsetX; y = key[1] + offsetY; z = key[2] + offsetZ; } -void DynamicEDTOctomap::mapToWorld(int x, int y, int z, octomap::point3d &p) const { +template +void DynamicEDTOctomapBase::mapToWorld(int x, int y, int z, octomap::point3d &p) const { p = octree->keyToCoord(octomap::OcTreeKey(x-offsetX, y-offsetY, z-offsetZ)); } -void DynamicEDTOctomap::mapToWorld(int x, int y, int z, octomap::OcTreeKey &key) const { +template +void DynamicEDTOctomapBase::mapToWorld(int x, int y, int z, octomap::OcTreeKey &key) const { key = octomap::OcTreeKey(x-offsetX, y-offsetY, z-offsetZ); } - -void DynamicEDTOctomap::getDistanceAndClosestObstacle(const octomap::point3d& p, float &distance, octomap::point3d& closestObstacle) const { +template +void DynamicEDTOctomapBase::getDistanceAndClosestObstacle(const octomap::point3d& p, float &distance, octomap::point3d& closestObstacle) const { int x,y,z; worldToMap(p, x, y, z); if(x>=0 && x=0 && y=0 && z +void DynamicEDTOctomapBase::getDistanceAndClosestObstacle_unsafe(const octomap::point3d& p, float &distance, octomap::point3d& closestObstacle) const { int x,y,z; worldToMap(p, x, y, z); @@ -231,8 +241,8 @@ void DynamicEDTOctomap::getDistanceAndClosestObstacle_unsafe(const octomap::poin } } - -float DynamicEDTOctomap::getDistance(const octomap::point3d& p) const { +template +float DynamicEDTOctomapBase::getDistance(const octomap::point3d& p) const { int x,y,z; worldToMap(p, x, y, z); if(x>=0 && x=0 && y=0 && z +float DynamicEDTOctomapBase::getDistance_unsafe(const octomap::point3d& p) const { int x,y,z; worldToMap(p, x, y, z); return data[x][y][z].dist*treeResolution; } - -float DynamicEDTOctomap::getDistance(const octomap::OcTreeKey& k) const { +template +float DynamicEDTOctomapBase::getDistance(const octomap::OcTreeKey& k) const { int x = k[0] + offsetX; int y = k[1] + offsetY; int z = k[2] + offsetZ; @@ -261,8 +272,8 @@ float DynamicEDTOctomap::getDistance(const octomap::OcTreeKey& k) const { } } - -float DynamicEDTOctomap::getDistance_unsafe(const octomap::OcTreeKey& k) const { +template +float DynamicEDTOctomapBase::getDistance_unsafe(const octomap::OcTreeKey& k) const { int x = k[0] + offsetX; int y = k[1] + offsetY; int z = k[2] + offsetZ; @@ -270,8 +281,8 @@ float DynamicEDTOctomap::getDistance_unsafe(const octomap::OcTreeKey& k) const { return data[x][y][z].dist*treeResolution; } - -int DynamicEDTOctomap::getSquaredDistanceInCells(const octomap::point3d& p) const { +template +int DynamicEDTOctomapBase::getSquaredDistanceInCells(const octomap::point3d& p) const { int x,y,z; worldToMap(p, x, y, z); if(x>=0 && x=0 && y=0 && z +int DynamicEDTOctomapBase::getSquaredDistanceInCells_unsafe(const octomap::point3d& p) const { int x,y,z; worldToMap(p, x, y, z); return data[x][y][z].sqdist; } - -bool DynamicEDTOctomap::checkConsistency() const { +template +bool DynamicEDTOctomapBase::checkConsistency() const { for(octomap::KeyBoolMap::const_iterator it = octree->changedKeysBegin(), end=octree->changedKeysEnd(); it!=end; ++it){ //std::cerr<<"Cannot check consistency, you must execute the update() method first."<search(point); + typename TREE::NodeType* node = octree->search(point); bool mapOccupied = isOccupied(x,y,z); bool treeOccupied = false; @@ -324,6 +336,3 @@ bool DynamicEDTOctomap::checkConsistency() const { return true; } - - - diff --git a/dynamicEDT3D/src/CMakeLists.txt b/dynamicEDT3D/src/CMakeLists.txt index e0ade01f..7ce3fd50 100644 --- a/dynamicEDT3D/src/CMakeLists.txt +++ b/dynamicEDT3D/src/CMakeLists.txt @@ -1,6 +1,5 @@ SET( dynamicEDT3D_SRCS dynamicEDT3D.cpp - dynamicEDTOctomap.cpp ) add_library(dynamicedt3d SHARED ${dynamicEDT3D_SRCS}) diff --git a/dynamicEDT3D/src/examples/CMakeLists.txt b/dynamicEDT3D/src/examples/CMakeLists.txt index 5a7fd4d2..01473157 100644 --- a/dynamicEDT3D/src/examples/CMakeLists.txt +++ b/dynamicEDT3D/src/examples/CMakeLists.txt @@ -3,3 +3,6 @@ target_link_libraries(exampleEDT3D dynamicedt3d) add_executable(exampleEDTOctomap exampleEDTOctomap.cpp) target_link_libraries(exampleEDTOctomap dynamicedt3d) + +add_executable(exampleEDTOctomapStamped exampleEDTOctomapStamped.cpp) +target_link_libraries(exampleEDTOctomapStamped dynamicedt3d) \ No newline at end of file diff --git a/dynamicEDT3D/src/examples/exampleEDTOctomapStamped.cpp b/dynamicEDT3D/src/examples/exampleEDTOctomapStamped.cpp new file mode 100644 index 00000000..d93f3fe8 --- /dev/null +++ b/dynamicEDT3D/src/examples/exampleEDTOctomapStamped.cpp @@ -0,0 +1,102 @@ +/** +* dynamicEDT3D: +* A library for incrementally updatable Euclidean distance transforms in 3D. +* @author C. Sprunk, B. Lau, W. Burgard, University of Freiburg, Copyright (C) 2011. +* @see http://octomap.sourceforge.net/ +* License: New BSD License +*/ + +/* + * Copyright (c) 2011-2012, C. Sprunk, B. Lau, W. Burgard, University of Freiburg + * 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 the University of Freiburg nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + + + +int main( int argc, char *argv[] ) { + if(argc<=1){ + std::cout<<"usage: "<"<readBinary(argv[1]); + + std::cout<<"read in tree, "<getNumLeafNodes()<<" leaves "<getMetricMin(x,y,z); + octomap::point3d min(x,y,z); + //std::cout<<"Metric min: "<getMetricMax(x,y,z); + octomap::point3d max(x,y,z); + //std::cout<<"Metric max: "<insertScan() or tree->updateNode() + //just call distmap.update() again to adapt the distance map to the changes made + + delete tree; + + return 0; +} From 928ba9bb6bda0146e70851c23d79dea70dec59b4 Mon Sep 17 00:00:00 2001 From: Thomas Roehr Date: Tue, 12 Jul 2016 19:26:58 +0200 Subject: [PATCH 05/27] Disambiguate isnan (#125) Allow octomap to build with c++11 --- octomap/src/compare_octrees.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/octomap/src/compare_octrees.cpp b/octomap/src/compare_octrees.cpp index d2bee77f..78e03b8c 100644 --- a/octomap/src/compare_octrees.cpp +++ b/octomap/src/compare_octrees.cpp @@ -132,7 +132,11 @@ int main(int argc, char** argv) { else kld +=log(p1/p2)*p1 + log((1-p1)/(1-p2))*(1-p1); +#if __cplusplus >= 201103L + if (std::isnan(kld)){ +#else if (isnan(kld)){ +#endif OCTOMAP_ERROR("KLD is nan! KLD(%f,%f)=%f; sum = %f", p1, p2, kld, kld_sum); exit(-1); } From 6e3a7ac54c10e2c7070e6a1879189d90bba17c1a Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Thu, 14 Jul 2016 20:47:20 +0200 Subject: [PATCH 06/27] Set root=NULL in clear(), fixes #123. Add unit test for clear() in test_pruning.cpp --- octomap/include/octomap/OcTreeBaseImpl.h | 3 ++- octomap/include/octomap/OcTreeBaseImpl.hxx | 7 ++++--- octomap/src/testing/test_pruning.cpp | 23 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/octomap/include/octomap/OcTreeBaseImpl.h b/octomap/include/octomap/OcTreeBaseImpl.h index 43517317..fe71aeee 100644 --- a/octomap/include/octomap/OcTreeBaseImpl.h +++ b/octomap/include/octomap/OcTreeBaseImpl.h @@ -516,7 +516,8 @@ namespace octomap { /// recursive call of writeData() std::ostream& writeNodesRecurs(const NODE*, std::ostream &s) const; - /// recursive delete of node and all children (deallocates memory) + /// Recursively delete a node and all children. Deallocates memory + /// but does NOT set the node ptr to NULL nor updates tree size. void deleteNodeRecurs(NODE* node); /// recursive call of deleteNode() diff --git a/octomap/include/octomap/OcTreeBaseImpl.hxx b/octomap/include/octomap/OcTreeBaseImpl.hxx index e1614bca..af02183c 100644 --- a/octomap/include/octomap/OcTreeBaseImpl.hxx +++ b/octomap/include/octomap/OcTreeBaseImpl.hxx @@ -513,6 +513,7 @@ namespace octomap { if (this->root){ deleteNodeRecurs(root); this->tree_size = 0; + this->root = NULL; // max extent of tree changed: this->size_changed = true; } @@ -664,15 +665,15 @@ namespace octomap { if (node->children != NULL) { for (unsigned int i=0; i<8; i++) { - if (node->children[i] != NULL) - this->deleteNodeRecurs(static_cast(node->children[i])); + if (node->children[i] != NULL){ + this->deleteNodeRecurs(static_cast(node->children[i])); + } } delete[] node->children; node->children = NULL; } // else: node has no children delete node; - node = NULL; } diff --git a/octomap/src/testing/test_pruning.cpp b/octomap/src/testing/test_pruning.cpp index 00ff44ca..4c3a15ae 100644 --- a/octomap/src/testing/test_pruning.cpp +++ b/octomap/src/testing/test_pruning.cpp @@ -9,6 +9,10 @@ using namespace octomath; int main(int argc, char** argv) { float res = 0.01f; OcTree tree(res); + + EXPECT_EQ(tree.size(), 0); + tree.prune(); + EXPECT_EQ(tree.size(), 0); point3d singlePt(-0.05f, -0.02f, 1.0f); OcTreeKey singleKey; @@ -233,6 +237,25 @@ int main(int argc, char** argv) { } + + tree.write("pruning_test_out.ot"); + + { + std::cout << "\nClearing tree / recursive delete\n===============================\n"; + + OcTree emptyTree(0.1234); + EXPECT_EQ(emptyTree.size(), 0); + emptyTree.clear(); + EXPECT_EQ(emptyTree.size(), emptyTree.calcNumNodes()); + EXPECT_EQ(emptyTree.size(), 0); + + tree.clear(); + EXPECT_EQ(tree.size(), 0); + EXPECT_EQ(tree.size(), tree.calcNumNodes()); + + tree.prune(); + EXPECT_EQ(tree.size(), 0); + } tree.write("pruning_test_out.ot"); std::cerr << "Test successful.\n"; From e19c1f33f92495e546175d64eb88fc40f16b62da Mon Sep 17 00:00:00 2001 From: Jackie Kay Date: Sun, 28 Aug 2016 05:21:32 -0700 Subject: [PATCH 07/27] use static_cast in KeyHash (#128) --- octomap/include/octomap/OcTreeKey.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/octomap/include/octomap/OcTreeKey.h b/octomap/include/octomap/OcTreeKey.h index 26ebc980..fca29a77 100644 --- a/octomap/include/octomap/OcTreeKey.h +++ b/octomap/include/octomap/OcTreeKey.h @@ -113,7 +113,9 @@ namespace octomap { // a simple hashing function // explicit casts to size_t to operate on the complete range // constanst will be promoted according to C++ standard - return size_t(key.k[0]) + 1447*size_t(key.k[1]) + 345637*size_t(key.k[2]); + return static_cast(key.k[0]) + + 1447*static_cast(key.k[1]) + + 345637*static_cast(key.k[2]); } }; From cb9768a30f34e432ec4c32ab84b5d36570258248 Mon Sep 17 00:00:00 2001 From: Jamie Snape Date: Thu, 15 Sep 2016 11:30:45 -0400 Subject: [PATCH 08/27] Enable rpath on OS X when the CMake version supports it --- dynamicEDT3D/CMakeLists.txt | 4 ++++ octomap/CMakeLists.txt | 4 ++++ octovis/CMakeLists.txt | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 5ff8e478..0fa448a2 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -12,6 +12,10 @@ set(DYNAMICEDT3D_SOVERSION ${DYNAMICEDT3D_MAJOR_VERSION}.${DYNAMICEDT3D_MINOR_VE if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) + if(POLICY CMP0042) + # Enable MACOSX_RPATH by default. + cmake_policy(SET CMP0042 NEW) + endif(POLICY CMP0042) endif(COMMAND cmake_policy) SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 1ba3417f..223fec90 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -11,6 +11,10 @@ set(OCTOMAP_VERSION ${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}.${OCTOMAP_ set(OCTOMAP_SOVERSION ${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) + if(POLICY CMP0042) + # Enable MACOSX_RPATH by default. + cmake_policy(SET CMP0042 NEW) + endif(POLICY CMP0042) endif(COMMAND cmake_policy) SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index 8d1a0636..d0fbec86 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -10,6 +10,10 @@ set(OCTOVIS_SOVERSION ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION}) # get rid of a useless warning: if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) + if(POLICY CMP0042) + # Enable MACOSX_RPATH by default. + cmake_policy(SET CMP0042 NEW) + endif(POLICY CMP0042) endif(COMMAND cmake_policy) SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") From 689a09f1e0c2732b60c1ef7c85d4f6fc9ea63a2c Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Sat, 17 Sep 2016 20:13:16 +0200 Subject: [PATCH 09/27] Switch OCTOVIS_LIBRARY_DIRS order in octovis-config.cmake (Workaround for #129) --- octovis/octovis-config.cmake.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octovis/octovis-config.cmake.in b/octovis/octovis-config.cmake.in index 1212a645..3d28447c 100644 --- a/octovis/octovis-config.cmake.in +++ b/octovis/octovis-config.cmake.in @@ -5,8 +5,8 @@ @PACKAGE_INIT@ -set_and_check(OCTOVIS_INCLUDE_DIRS "@QGLViewer_INCLUDE_DIR@" "@PACKAGE_OCTOVIS_INCLUDE_DIRS@") -set_and_check(OCTOVIS_LIBRARY_DIRS "@QGLViewer_LIBRARY_DIR@" "@PACKAGE_OCTOVIS_LIB_DIR@") +set_and_check(OCTOVIS_INCLUDE_DIRS "@PACKAGE_OCTOVIS_INCLUDE_DIRS@" "@QGLViewer_INCLUDE_DIR@") +set_and_check(OCTOVIS_LIBRARY_DIRS "@PACKAGE_OCTOVIS_LIB_DIR@" "@QGLViewer_LIBRARY_DIR@") # Set library names as absolute paths: From 4b3541d9edb686a9a909e529e9d01fab0a0adbf3 Mon Sep 17 00:00:00 2001 From: Jamie Snape Date: Tue, 27 Sep 2016 16:24:09 -0400 Subject: [PATCH 10/27] Add version information to *-config.cmake files --- dynamicEDT3D/dynamicEDT3DConfig.cmake.in | 15 ++++++++++++--- octomap/octomap-config.cmake.in | 12 ++++++++++-- octovis/octovis-config.cmake.in | 18 +++++++++++++----- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in index 53fe264c..0628f082 100644 --- a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in +++ b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in @@ -8,12 +8,21 @@ # TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${DYNAMICEDT3D_LIBRARIES}) # # It defines the following variables -# DYNAMICEDT3D_INCLUDE_DIRS - include directories for dynamicEDT3D -# DYNAMICEDT3D_LIBRARY_DIRS - library directories for dynamicEDT3D (normally not used!) -# DYNAMICEDT3D_LIBRARIES - libraries to link against +# DYNAMICEDT3D_INCLUDE_DIRS - include directories for dynamicEDT3D +# DYNAMICEDT3D_LIBRARY_DIRS - library directories for dynamicEDT3D (normally not used!) +# DYNAMICEDT3D_LIBRARIES - libraries to link against +# DYNAMICEDT3D_MAJOR_VERSION - major version +# DYNAMICEDT3D_MINOR_VERSION - minor version +# DYNAMICEDT3D_PATCH_VERSION - patch version +# DYNAMICEDT3D_VERSION - major.minor.patch version @PACKAGE_INIT@ +set(DYNAMICEDT3D_MAJOR_VERSION "@DYNAMICEDT3D_MAJOR_VERSION@") +set(DYNAMICEDT3D_MINOR_VERSION "@DYNAMICEDT3D_MINOR_VERSION@") +set(DYNAMICEDT3D_PATCH_VERSION "@DYNAMICEDT3D_PATCH_VERSION@") +set(DYNAMICEDT3D_VERSION "@DYNAMICEDT3D_VERSION@") + # Tell the user project where to find our headers and libraries set_and_check(DYNAMICEDT3D_INCLUDE_DIRS "@PACKAGE_DYNAMICEDT3D_INCLUDE_DIRS@") set_and_check(DYNAMICEDT3D_LIBRARY_DIRS "@PACKAGE_DYNAMICEDT3D_LIB_DIR@") diff --git a/octomap/octomap-config.cmake.in b/octomap/octomap-config.cmake.in index 6c6dd747..eebc2ecf 100644 --- a/octomap/octomap-config.cmake.in +++ b/octomap/octomap-config.cmake.in @@ -16,17 +16,25 @@ # - OCTOMAP_LIBRARY_DIRS : The directory where lib files are. Calling # LINK_DIRECTORIES with this path is NOT needed. # - OCTOMAP_INCLUDE_DIRS : The OctoMap include directories. +# - OCTOMAP_MAJOR_VERSION : Major version. +# - OCTOMAP_MINOR_VERSION : Minor version. +# - OCTOMAP_PATCH_VERSION : Patch version. +# - OCTOMAP_VERSION : Major.Minor.Patch version. # # =================================================================================== @PACKAGE_INIT@ +set(OCTOMAP_MAJOR_VERSION "@OCTOMAP_MAJOR_VERSION@") +set(OCTOMAP_MINOR_VERSION "@OCTOMAP_MINOR_VERSION@") +set(OCTOMAP_PATCH_VERSION "@OCTOMAP_PATCH_VERSION@") +set(OCTOMAP_VERSION "@OCTOMAP_VERSION@") + set_and_check(OCTOMAP_INCLUDE_DIRS "@PACKAGE_OCTOMAP_INCLUDE_DIRS@") set_and_check(OCTOMAP_LIBRARY_DIRS "@PACKAGE_OCTOMAP_LIB_DIR@") - # Set library names -set(OCTOMAP_LIBRARIES +set(OCTOMAP_LIBRARIES "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMAP_LIBRARY@" "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMATH_LIBRARY@" ) diff --git a/octovis/octovis-config.cmake.in b/octovis/octovis-config.cmake.in index 3d28447c..b31eed1f 100644 --- a/octovis/octovis-config.cmake.in +++ b/octovis/octovis-config.cmake.in @@ -1,14 +1,22 @@ # It defines the following variables -# OCTOVIS_INCLUDE_DIRS - include directories for OctoMap viewer -# OCTOVIS_LIBRARY_DIRS - library directories for OctoMap viewer -# OCTOVIS_LIBRARIES - libraries to link against - +# OCTOVIS_INCLUDE_DIRS - include directories for OctoMap viewer +# OCTOVIS_LIBRARY_DIRS - library directories for OctoMap viewer +# OCTOVIS_LIBRARIES - libraries to link against +# OCTOVIS_MAJOR_VERSION - major version +# OCTOVIS_MINOR_VERSION - minor version +# OCTOVIS_PATCH_VERSION - patch version +# OCTOVIS_VERSION - major.minor.patch version + @PACKAGE_INIT@ +set(OCTOVIS_MAJOR_VERSION "@OCTOVIS_MAJOR_VERSION@") +set(OCTOVIS_MINOR_VERSION "@OCTOVIS_MINOR_VERSION@") +set(OCTOVIS_PATCH_VERSION "@OCTOVIS_PATCH_VERSION@") +set(OCTOVIS_VERSION "@OCTOVIS_VERSION@") + set_and_check(OCTOVIS_INCLUDE_DIRS "@PACKAGE_OCTOVIS_INCLUDE_DIRS@" "@QGLViewer_INCLUDE_DIR@") set_and_check(OCTOVIS_LIBRARY_DIRS "@PACKAGE_OCTOVIS_LIB_DIR@" "@QGLViewer_LIBRARY_DIR@") - # Set library names as absolute paths: set(OCTOVIS_LIBRARIES "@QGLViewer_LIBRARIES@" From 1cbb35df5e525f1327449568b795e0413799fd6f Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Wed, 5 Oct 2016 21:47:37 +0200 Subject: [PATCH 11/27] Fix #131: Portable binary read/write of Pointcloud and ScanGraph - uint32_t for size, move inttypes.h include into octomap_types.h --- octomap/include/octomap/OcTreeKey.h | 1 - octomap/include/octomap/octomap_types.h | 1 + octomap/src/Pointcloud.cpp | 19 +++++++++++++++---- octomap/src/ScanGraph.cpp | 8 ++++++-- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/octomap/include/octomap/OcTreeKey.h b/octomap/include/octomap/OcTreeKey.h index fca29a77..fabb965c 100644 --- a/octomap/include/octomap/OcTreeKey.h +++ b/octomap/include/octomap/OcTreeKey.h @@ -40,7 +40,6 @@ #include #include -#include /* Libc++ does not implement the TR1 namespace, all c++11 related functionality * is instead implemented in the std namespace. diff --git a/octomap/include/octomap/octomap_types.h b/octomap/include/octomap/octomap_types.h index 328a0b7c..2ae7fedc 100644 --- a/octomap/include/octomap/octomap_types.h +++ b/octomap/include/octomap/octomap_types.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/octomap/src/Pointcloud.cpp b/octomap/src/Pointcloud.cpp index b78ca554..09349db0 100644 --- a/octomap/src/Pointcloud.cpp +++ b/octomap/src/Pointcloud.cpp @@ -43,6 +43,8 @@ #endif #include #include +#include +#include #include @@ -284,14 +286,14 @@ namespace octomap { std::istream& Pointcloud::readBinary(std::istream &s) { - unsigned int pc_size = 0; + uint32_t pc_size = 0; s.read((char*)&pc_size, sizeof(pc_size)); OCTOMAP_DEBUG("Reading %d points from binary file...", pc_size); if (pc_size > 0) { this->points.reserve(pc_size); point3d p; - for (unsigned int i=0; ipush_back(p); @@ -302,6 +304,8 @@ namespace octomap { } } } + assert(pc_size == this->size()); + OCTOMAP_DEBUG("done.\n"); return s; @@ -310,8 +314,15 @@ namespace octomap { std::ostream& Pointcloud::writeBinary(std::ostream &s) const { - size_t pc_size = this->size(); - OCTOMAP_DEBUG("Writing %lu points to binary file...", (unsigned long)pc_size); + // check if written unsigned int can hold size + size_t orig_size = this->size(); + if (orig_size > std::numeric_limits::max()){ + OCTOMAP_ERROR("Pointcloud::writeBinary ERROR: Point cloud too large to be written"); + return s; + } + + uint32_t pc_size = static_cast(this->size()); + OCTOMAP_DEBUG("Writing %u points to binary file...", pc_size); s.write((char*)&pc_size, sizeof(pc_size)); for (Pointcloud::const_iterator it = this->begin(); it != this->end(); it++) { diff --git a/octomap/src/ScanGraph.cpp b/octomap/src/ScanGraph.cpp index 922fd142..f3a0aeb0 100644 --- a/octomap/src/ScanGraph.cpp +++ b/octomap/src/ScanGraph.cpp @@ -55,7 +55,9 @@ namespace octomap { scan->writeBinary(s); pose.writeBinary(s); - s.write((char*)&id, sizeof(id)); + + uint32_t uintId = static_cast(id); + s.write((char*)&uintId, sizeof(uintId)); return s; } @@ -67,7 +69,9 @@ namespace octomap { this->pose.readBinary(s); - s.read((char*)&this->id, sizeof(this->id)); + uint32_t uintId; + s.read((char*)&uintId, sizeof(uintId)); + this->id = uintId; return s; } From cc7cddc6e5e01c2fdb1b142124a9890b949a0360 Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Wed, 5 Oct 2016 21:49:13 +0200 Subject: [PATCH 12/27] Add unit test for Pointcloud and ScanGraph IO (#131) --- octomap/share/data/spherical_scan.graph | Bin 0 -> 285708 bytes octomap/src/testing/CMakeLists.txt | 1 + octomap/src/testing/test_scans.cpp | 96 +++++++++++++++++++----- octomap/src/testing/unit_tests.cpp | 1 + 4 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 octomap/share/data/spherical_scan.graph diff --git a/octomap/share/data/spherical_scan.graph b/octomap/share/data/spherical_scan.graph new file mode 100644 index 0000000000000000000000000000000000000000..111a13f0b2272b0c117b32d300316d50b644adb3 GIT binary patch literal 285708 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
*& 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 #include #include +#include "testing.h" using namespace std; using namespace octomap; +void printUsage(char* self){ + std::cerr << "\nUSAGE: " << self << " spherical_scan.graph (reference file to compare, required)\n\n"; + exit(1); +} int main(int argc, char** argv) { + if (argc != 2){ + printUsage(argv[0]); + } + std::string filename = std::string(argv[1]); + + ScanGraph referenceGraph; + EXPECT_TRUE(referenceGraph.readBinary(filename)); + + // TODO: read in reference graph file - //############################################################## - OcTree tree (0.05); + //############################################################## - point3d origin (0.01f, 0.01f, 0.02f); point3d point_on_surface (4.01f, 0.01f, 0.01f); - cout << "generating spherical scan at " << origin << " ..." << endl; - Pointcloud cloud; + Pointcloud* cloud = new Pointcloud(); - for (int i=-100; i<101; i++) { - for (int j=-100; j<101; j++) { + for (int i=-50; i<51; i++) { + for (int j=-50; j<51; j++) { point3d rotated = point_on_surface; rotated.rotate_IP(0, DEG2RAD(i*0.5), DEG2RAD(j*0.5)); - cloud.push_back(rotated); + cloud->push_back(rotated); } - } - - // insert in global coordinates: - tree.insertPointCloud(cloud, origin); - - cout << "done." << endl; - cout << "writing to spherical_scan.bt..." << endl; - tree.writeBinary("spherical_scan.bt"); - - + } + + pose6d origin(1.0, 0, -0.5, 0, 0, 0); + + ScanGraph graph; + graph.addNode(cloud, origin); // graph assumes ownership of cloud! + + { + std::cout << "Comparing ScanGraph with reference file at " << filename << std::endl; + EXPECT_TRUE(graph.size() == referenceGraph.size()); + ScanNode* scanNode = *graph.begin(); + ScanNode* refScanNode = *referenceGraph.begin(); + + EXPECT_EQ(scanNode->id, refScanNode->id); + EXPECT_EQ(scanNode->pose, refScanNode->pose); + EXPECT_EQ(scanNode->scan->size(), refScanNode->scan->size()); + + for (size_t i = 0; i < scanNode->scan->size(); ++i){ + EXPECT_EQ((*scanNode->scan)[i], (*refScanNode->scan)[i]); + } + + } + // test reading and writing to file + { + std::cout << "Testing ScanGraph I/O" << std::endl; + + EXPECT_TRUE(graph.writeBinary("spherical_scan_out.graph")); + + ScanGraph reReadGraph; + EXPECT_TRUE(reReadGraph.readBinary("spherical_scan_out.graph")); + + EXPECT_TRUE(graph.size() == reReadGraph.size()); + EXPECT_EQ(reReadGraph.size(), 1); + + ScanNode* scanNode = *graph.begin(); + ScanNode* readScanNode = *reReadGraph.begin(); + + EXPECT_EQ(scanNode->id, readScanNode->id); + EXPECT_EQ(scanNode->pose, readScanNode->pose); + EXPECT_EQ(scanNode->scan->size(), readScanNode->scan->size()); + + for (size_t i = 0; i < scanNode->scan->size(); ++i){ + EXPECT_EQ((*scanNode->scan)[i], (*readScanNode->scan)[i]); + } + } + + + // insert into OcTree + { + OcTree tree (0.05); + + // insert in global coordinates: + tree.insertPointCloud(*cloud, origin.trans()); + + tree.writeBinary("spherical_scan.bt"); + } + + cout << "Test done." << endl; + exit(0); } diff --git a/octomap/src/testing/unit_tests.cpp b/octomap/src/testing/unit_tests.cpp index 15ae99fb..a3bf2c60 100644 --- a/octomap/src/testing/unit_tests.cpp +++ b/octomap/src/testing/unit_tests.cpp @@ -149,6 +149,7 @@ int main(int argc, char** argv) { // ------------------------------------------------------------ // graph read file test } else if (test_name == "ReadGraph") { + // not really meaningful, see better test in "test_scans.cpp" ScanGraph graph; EXPECT_TRUE (graph.readBinary("test.graph")); // ------------------------------------------------------------ From 545302a3e17d8f085de6bc31dc8e93afc58bf154 Mon Sep 17 00:00:00 2001 From: Felix Endres Date: Thu, 6 Oct 2016 21:49:32 +0200 Subject: [PATCH 13/27] Command line param for the initial tree depth cutoff (#122) Add octovis cmd line param for the initial tree depth cutoff (renders faster right after startup) --- octovis/include/octovis/ViewerGui.h | 2 +- octovis/include/octovis/ViewerSettingsPanel.h | 2 +- octovis/src/ViewerGui.cpp | 7 +++++-- octovis/src/ViewerSettingsPanel.cpp | 2 ++ octovis/src/main.cpp | 11 ++++++++--- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/octovis/include/octovis/ViewerGui.h b/octovis/include/octovis/ViewerGui.h index 86d8aa75..06645154 100644 --- a/octovis/include/octovis/ViewerGui.h +++ b/octovis/include/octovis/ViewerGui.h @@ -51,7 +51,7 @@ namespace octomap { Q_OBJECT public: - ViewerGui(const std::string& filename="", QWidget *parent = 0); + ViewerGui(const std::string& filename="", QWidget *parent = 0, unsigned int initTreeDepth = 16); ~ViewerGui(); static const unsigned int LASERTYPE_URG = 0; diff --git a/octovis/include/octovis/ViewerSettingsPanel.h b/octovis/include/octovis/ViewerSettingsPanel.h index dd694be7..371ced2f 100644 --- a/octovis/include/octovis/ViewerSettingsPanel.h +++ b/octovis/include/octovis/ViewerSettingsPanel.h @@ -43,13 +43,13 @@ public slots: void setNumberOfScans(unsigned scans); void setCurrentScan(unsigned scan); void setResolution(double resolution); + void setTreeDepth(int depth); private slots: void on_firstScanButton_clicked(); void on_lastScanButton_clicked(); void on_nextScanButton_clicked(); void on_fastFwdScanButton_clicked(); - void setTreeDepth(int depth); signals: void treeDepthChanged(int depth); diff --git a/octovis/src/ViewerGui.cpp b/octovis/src/ViewerGui.cpp index 2da221da..10e3cb95 100644 --- a/octovis/src/ViewerGui.cpp +++ b/octovis/src/ViewerGui.cpp @@ -36,12 +36,13 @@ namespace octomap{ -ViewerGui::ViewerGui(const std::string& filename, QWidget *parent) +ViewerGui::ViewerGui(const std::string& filename, QWidget *parent, unsigned int initDepth) : QMainWindow(parent), m_scanGraph(NULL), m_trajectoryDrawer(NULL), m_pointcloudDrawer(NULL), m_cameraFollowMode(NULL), m_octreeResolution(0.1), m_laserMaxRange(-1.), m_occupancyThresh(0.5), - m_max_tree_depth(16), m_laserType(LASERTYPE_SICK), + m_max_tree_depth(initDepth > 0 && initDepth <= 16 ? initDepth : 16), + m_laserType(LASERTYPE_SICK), m_cameraStored(false), m_filename("") { ui.setupUi(this); @@ -50,6 +51,7 @@ ViewerGui::ViewerGui(const std::string& filename, QWidget *parent) // Settings panel at the right side ViewerSettingsPanel* settingsPanel = new ViewerSettingsPanel(this); + settingsPanel->setTreeDepth(initDepth); QDockWidget* settingsDock = new QDockWidget("Octree / Scan graph settings", this); settingsDock->setWidget(settingsPanel); this->addDockWidget(Qt::RightDockWidgetArea, settingsDock); @@ -393,6 +395,7 @@ void ViewerGui::openFile(){ QString temp = QString(m_filename.c_str()); QFileInfo fileinfo(temp); + this->setWindowTitle(fileinfo.fileName()); if (fileinfo.suffix() == "graph"){ openGraph(); }else if (fileinfo.suffix() == "bt"){ diff --git a/octovis/src/ViewerSettingsPanel.cpp b/octovis/src/ViewerSettingsPanel.cpp index aba9028f..d99a7b60 100644 --- a/octovis/src/ViewerSettingsPanel.cpp +++ b/octovis/src/ViewerSettingsPanel.cpp @@ -114,6 +114,8 @@ void ViewerSettingsPanel::setResolution(double resolution){ void ViewerSettingsPanel::setTreeDepth(int depth){ emit treeDepthChanged(depth); m_treeDepth = depth; + ui.treeDepth->setValue(depth); + ui.treeDepthSlider->setValue(depth); leafSizeChanged(); } diff --git a/octovis/src/main.cpp b/octovis/src/main.cpp index 2113a6b7..bdf93f06 100644 --- a/octovis/src/main.cpp +++ b/octovis/src/main.cpp @@ -25,17 +25,22 @@ #include #include #include +#include //strtol int main(int argc, char *argv[]) { std::string filename = ""; - if (argc == 2) { - filename = std::string(argv[1]); + int depth = 0; + if (argc == 1) { + std::cout << "Usage: " << argv[0] << " [mapfile] [tree depth cutoff]\n"; + std::cout << "Where the optional [tree depth cutoff] is an integer from 1 to 16\n"; } + if (argc >= 2) { filename = std::string(argv[1]); } + if (argc >= 3) { depth = std::strtol(argv[2], NULL, 10); }//zero on parse error QApplication app(argc, argv); - octomap::ViewerGui gui(filename); + octomap::ViewerGui gui(filename, NULL, depth); gui.show(); return app.exec(); } From d10aabd96ee91f414e9bc3e95c71f9cb4fbc2782 Mon Sep 17 00:00:00 2001 From: Felix Endres Date: Thu, 6 Oct 2016 23:21:35 +0200 Subject: [PATCH 14/27] Add alternative rendering method By using opengl compiled display lists for rendering the cubes, CPU and RAM usage and CPU-GPU communication can be strongly reduced, leading to 3-4x higher frame rates at half the CPU and RAM usage. The drawbacks are long "compilation" times before the first rendering and upon all changes in the octree display, like selecting a new colormap or depth cutoff (but not on changing the perspective of course). Further, for displaying too detailed maps octovis may crash, supposably due to exhaustion of the RAM on the graphics card. Therefore the feature is off by default, but can be enabled by checking View->"Alternate Rendering" --- octovis/include/octovis/OcTreeDrawer.h | 13 ++-- octovis/include/octovis/ViewerGui.h | 1 + octovis/include/octovis/ViewerGui.ui | 21 ++++++ octovis/src/OcTreeDrawer.cpp | 98 +++++++++++++++++--------- octovis/src/ViewerGui.cpp | 11 ++- 5 files changed, 105 insertions(+), 39 deletions(-) diff --git a/octovis/include/octovis/OcTreeDrawer.h b/octovis/include/octovis/OcTreeDrawer.h index a9712c90..34d719a3 100644 --- a/octovis/include/octovis/OcTreeDrawer.h +++ b/octovis/include/octovis/OcTreeDrawer.h @@ -59,16 +59,17 @@ namespace octomap { /// sets alpha level for occupied cells void setAlphaOccupied(double alpha); + void setAlternativeDrawing(bool flag){m_alternativeDrawing = flag;} void enableOcTree(bool enabled = true); - void enableOcTreeCells(bool enabled = true) {m_drawOccupied = enabled; }; - void enableFreespace(bool enabled = true) {m_drawFree = enabled; }; - void enableSelection(bool enabled = true) {m_drawSelection = enabled; }; - void setMax_tree_depth(unsigned int max_tree_depth) {m_max_tree_depth = max_tree_depth;}; + void enableOcTreeCells(bool enabled = true) { m_update = true; m_drawOccupied = enabled; }; + void enableFreespace(bool enabled = true) { m_update = true; m_drawFree = enabled; }; + void enableSelection(bool enabled = true) { m_update = true; m_drawSelection = enabled; }; + void setMax_tree_depth(unsigned int max_tree_depth) { m_update = true; m_max_tree_depth = max_tree_depth;}; // set new origin (move object) void setOrigin(octomap::pose6d t); - void enableAxes(bool enabled = true) { m_displayAxes = enabled; }; + void enableAxes(bool enabled = true) { m_update = true; m_displayAxes = enabled; }; protected: //void clearOcTree(); @@ -146,6 +147,8 @@ namespace octomap { bool m_drawSelection; bool m_octree_grid_vis_initialized; bool m_displayAxes; + bool m_alternativeDrawing; + mutable bool m_update; unsigned int m_max_tree_depth; double m_alphaOccupied; diff --git a/octovis/include/octovis/ViewerGui.h b/octovis/include/octovis/ViewerGui.h index 06645154..41a5dee7 100644 --- a/octovis/include/octovis/ViewerGui.h +++ b/octovis/include/octovis/ViewerGui.h @@ -106,6 +106,7 @@ namespace octomap { void on_actionSelected_toggled(bool enabled); void on_actionAxes_toggled(bool checked); void on_actionHideBackground_toggled(bool checked); + void on_actionAlternateRendering_toggled(bool checked); void on_actionClear_triggered(); void on_action_bg_black_triggered(); diff --git a/octovis/include/octovis/ViewerGui.ui b/octovis/include/octovis/ViewerGui.ui index 8016b742..f83d88d2 100644 --- a/octovis/include/octovis/ViewerGui.ui +++ b/octovis/include/octovis/ViewerGui.ui @@ -76,6 +76,8 @@ + + @@ -247,6 +249,14 @@ 0 + + + false + + + Alternative rendering + + Remove all octrees @@ -541,6 +551,17 @@ With "occupied" (only unknown) + + + true + + + Alternate Rendering + + + Uses precompiled rendering of the octomap. Faster and requires less CPU but more memory on your graphics card. The first rendering takes longer. + + diff --git a/octovis/src/OcTreeDrawer.cpp b/octovis/src/OcTreeDrawer.cpp index 77d4d8ea..6868a7dd 100644 --- a/octovis/src/OcTreeDrawer.cpp +++ b/octovis/src/OcTreeDrawer.cpp @@ -40,6 +40,8 @@ namespace octomap { m_drawFree = false; m_drawSelection = true; m_displayAxes = false; + m_update = true; + m_alternativeDrawing = false; m_occupiedArray = NULL; m_freeArray = NULL; @@ -59,50 +61,77 @@ namespace octomap { } void OcTreeDrawer::draw() const { + static int gl_list_index = -1; + if(m_alternativeDrawing && gl_list_index < 0){ + gl_list_index = glGenLists(1); + m_update = true; + } + if(!m_alternativeDrawing && gl_list_index != -1){//Free video card memory + //std::cerr << "Freeing VRAM\n"; + glDeleteLists(gl_list_index,1); + gl_list_index = -1; + } + if(m_update || !m_alternativeDrawing) + { + if(m_alternativeDrawing) { + std::cout << "Preparing batch rendering, please wait ...\n"; + glNewList(gl_list_index, GL_COMPILE_AND_EXECUTE); + } - // push current status - glPushMatrix(); - // octomap::pose6d relative_transform = origin * initial_origin.inv(); - - octomap::pose6d relative_transform = origin;// * initial_origin; + // push current status + glPushMatrix(); + // octomap::pose6d relative_transform = origin * initial_origin.inv(); - // apply relative transform - const octomath::Quaternion& q = relative_transform.rot(); - glTranslatef(relative_transform.x(), relative_transform.y(), relative_transform.z()); - - // convert quaternion to angle/axis notation - float scale = sqrt(q.x() * q.x() + q.y() * q.y() + q.z() * q.z()); - if (scale) { - float axis_x = q.x() / scale; - float axis_y = q.y() / scale; - float axis_z = q.z() / scale; - float angle = acos(q.u()) * 2.0f * OTD_RAD2DEG; // opengl expects DEG - glRotatef(angle, axis_x, axis_y, axis_z); - } + octomap::pose6d relative_transform = origin;// * initial_origin; - glEnableClientState(GL_VERTEX_ARRAY); + // apply relative transform + const octomath::Quaternion& q = relative_transform.rot(); + glTranslatef(relative_transform.x(), relative_transform.y(), relative_transform.z()); + + // convert quaternion to angle/axis notation + float scale = sqrt(q.x() * q.x() + q.y() * q.y() + q.z() * q.z()); + if (scale) { + float axis_x = q.x() / scale; + float axis_y = q.y() / scale; + float axis_z = q.z() / scale; + float angle = acos(q.u()) * 2.0f * OTD_RAD2DEG; // opengl expects DEG + glRotatef(angle, axis_x, axis_y, axis_z); + } - if (m_drawOccupied) - drawOccupiedVoxels(); - if (m_drawFree) - drawFreeVoxels(); - if (m_drawOcTreeGrid) - drawOctreeGrid(); - if (m_drawSelection) - drawSelection(); + glEnableClientState(GL_VERTEX_ARRAY); - if (m_displayAxes) { - drawAxes(); - } + if (m_drawOccupied) + drawOccupiedVoxels(); + if (m_drawFree) + drawFreeVoxels(); + if (m_drawOcTreeGrid) + drawOctreeGrid(); + if (m_drawSelection) + drawSelection(); - glDisableClientState(GL_VERTEX_ARRAY); + if (m_displayAxes) { + drawAxes(); + } - // reset previous status - glPopMatrix(); + glDisableClientState(GL_VERTEX_ARRAY); + // reset previous status + glPopMatrix(); + if(m_alternativeDrawing) { + glEndList(); + std::cout << "Finished preparation of batch rendering.\n"; + } + m_update = false; + } + else + { + glCallList(gl_list_index); + } + } void OcTreeDrawer::setAlphaOccupied(double alpha){ + m_update = true; m_alphaOccupied = alpha; } @@ -209,10 +238,12 @@ namespace octomap { } void OcTreeDrawer::setOcTreeSelection(const std::list& selectedVoxels){ + m_update = true; generateCubes(selectedVoxels, &m_selectionArray, m_selectionSize, this->origin); } void OcTreeDrawer::clearOcTreeSelection(){ + m_update = true; clearCubes(&m_selectionArray, m_selectionSize); } @@ -818,6 +849,7 @@ namespace octomap { } void OcTreeDrawer::enableOcTree(bool enabled) { + m_update = true; m_drawOcTreeGrid = enabled; if(m_drawOcTreeGrid && !m_octree_grid_vis_initialized) { initOctreeGridVis(); diff --git a/octovis/src/ViewerGui.cpp b/octovis/src/ViewerGui.cpp index 10e3cb95..a748ff4f 100644 --- a/octovis/src/ViewerGui.cpp +++ b/octovis/src/ViewerGui.cpp @@ -43,7 +43,9 @@ ViewerGui::ViewerGui(const std::string& filename, QWidget *parent, unsigned int m_octreeResolution(0.1), m_laserMaxRange(-1.), m_occupancyThresh(0.5), m_max_tree_depth(initDepth > 0 && initDepth <= 16 ? initDepth : 16), m_laserType(LASERTYPE_SICK), - m_cameraStored(false), m_filename("") { + m_cameraStored(false), + m_filename("") +{ ui.setupUi(this); m_glwidget = new ViewerWidget(this); @@ -1048,6 +1050,13 @@ void ViewerGui::on_actionHideBackground_toggled(bool checked) { } } +void ViewerGui::on_actionAlternateRendering_toggled(bool checked) { + for (std::map::iterator it = m_octrees.begin(); it != m_octrees.end(); ++it) { + //std::cout << "Setting Octree " << it->first << " to " << (checked ? "alternate" : "regular") << " rendering."; + it->second.octree_drawer->setAlternativeDrawing(checked); + } +} + void ViewerGui::on_actionClear_triggered() { for (std::map::iterator it = m_octrees.begin(); it != m_octrees.end(); ++it) { From 21d159f3c0bbdc3d2a3283ae4c0fd719f38bdc57 Mon Sep 17 00:00:00 2001 From: Jamie Snape Date: Fri, 7 Oct 2016 20:10:09 -0400 Subject: [PATCH 15/27] Add CMake exported targets --- dynamicEDT3D/CMakeLists.txt | 3 +++ dynamicEDT3D/dynamicEDT3DConfig.cmake.in | 2 ++ dynamicEDT3D/src/CMakeLists.txt | 13 +++++++++---- octomap/CMakeLists.txt | 3 +++ octomap/octomap-config.cmake.in | 2 ++ octomap/src/CMakeLists.txt | 14 +++++++++++--- octomap/src/math/CMakeLists.txt | 10 ++++++++-- octovis/CMakeLists.txt | 3 +++ octovis/CMakeLists_src.txt | 10 +++++++--- octovis/octovis-config.cmake.in | 2 ++ 10 files changed, 50 insertions(+), 12 deletions(-) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 0fa448a2..49ad0447 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -124,6 +124,9 @@ set(DYNAMICEDT3D_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") set(DYNAMICEDT3D_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") #set(DYNAMICEDT3D_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") +set(DYNAMICEDT3D_INCLUDE_TARGETS + "include(\${CMAKE_CURRENT_LIST_DIR}/dynamicEDT3DTargets.cmake)") + CONFIGURE_PACKAGE_CONFIG_FILE( dynamicEDT3DConfig.cmake.in "${PROJECT_BINARY_DIR}/InstallFiles/dynamicEDT3DConfig.cmake" diff --git a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in index 0628f082..c8ffd885 100644 --- a/dynamicEDT3D/dynamicEDT3DConfig.cmake.in +++ b/dynamicEDT3D/dynamicEDT3DConfig.cmake.in @@ -28,3 +28,5 @@ set_and_check(DYNAMICEDT3D_INCLUDE_DIRS "@PACKAGE_DYNAMICEDT3D_INCLUDE_DIRS@") set_and_check(DYNAMICEDT3D_LIBRARY_DIRS "@PACKAGE_DYNAMICEDT3D_LIB_DIR@") set(DYNAMICEDT3D_LIBRARIES "@PACKAGE_DYNAMICEDT3D_LIB_DIR@/@DYNAMICEDT3D_LIBRARY@") + +@DYNAMICEDT3D_INCLUDE_TARGETS@ diff --git a/dynamicEDT3D/src/CMakeLists.txt b/dynamicEDT3D/src/CMakeLists.txt index 7ce3fd50..4a720fa3 100644 --- a/dynamicEDT3D/src/CMakeLists.txt +++ b/dynamicEDT3D/src/CMakeLists.txt @@ -14,6 +14,9 @@ target_link_libraries(dynamicedt3d-static ${OCTOMAP_LIBRARIES}) SET_TARGET_PROPERTIES(dynamicedt3d-static PROPERTIES OUTPUT_NAME "dynamicedt3d") +export(TARGETS dynamicedt3d dynamicedt3d-static + FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DTargets.cmake") + # directly depend on the octomap library target when building the # complete distribution, so it it recompiled as needed if (CMAKE_PROJECT_NAME STREQUAL "octomap-distribution") @@ -23,7 +26,9 @@ endif() ADD_SUBDIRECTORY(examples) -install(TARGETS - dynamicedt3d - dynamicedt3d-static - ${INSTALL_TARGETS_DEFAULT_ARGS}) \ No newline at end of file +install(TARGETS dynamicedt3d dynamicedt3d-static + EXPORT dynamicEDT3DTargets + INCLUDES DESTINATION include + ${INSTALL_TARGETS_DEFAULT_ARGS} +) +install(EXPORT dynamicEDT3DTargets DESTINATION share/dynamicEDT3D/) diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 223fec90..ffa609c8 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -126,6 +126,9 @@ set(OCTOMAP_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include") set(OCTOMAP_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") #set(OCTOMAP_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") +set(OCTOMAP_INCLUDE_TARGETS + "include(\${CMAKE_CURRENT_LIST_DIR}/octomap-targets.cmake)") + CONFIGURE_PACKAGE_CONFIG_FILE( octomap-config.cmake.in "${PROJECT_BINARY_DIR}/InstallFiles/octomap-config.cmake" diff --git a/octomap/octomap-config.cmake.in b/octomap/octomap-config.cmake.in index eebc2ecf..e0ffc5d6 100644 --- a/octomap/octomap-config.cmake.in +++ b/octomap/octomap-config.cmake.in @@ -38,3 +38,5 @@ set(OCTOMAP_LIBRARIES "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMAP_LIBRARY@" "@PACKAGE_OCTOMAP_LIB_DIR@/@OCTOMATH_LIBRARY@" ) + +@OCTOMAP_INCLUDE_TARGETS@ diff --git a/octomap/src/CMakeLists.txt b/octomap/src/CMakeLists.txt index 71360504..6d5cae09 100644 --- a/octomap/src/CMakeLists.txt +++ b/octomap/src/CMakeLists.txt @@ -21,6 +21,9 @@ SET_TARGET_PROPERTIES(octomap-static PROPERTIES OUTPUT_NAME "octomap") TARGET_LINK_LIBRARIES(octomap octomath) +export(TARGETS octomap octomap-static + APPEND FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-targets.cmake") + ADD_SUBDIRECTORY( testing ) ADD_EXECUTABLE(graph2tree graph2tree.cpp) @@ -59,9 +62,14 @@ TARGET_LINK_LIBRARIES(intersection_example octomap) ADD_EXECUTABLE(octree2pointcloud octree2pointcloud.cpp) TARGET_LINK_LIBRARIES(octree2pointcloud octomap) -install(TARGETS - octomap - octomap-static +install(TARGETS octomap octomap-static + EXPORT octomap-targets + INCLUDES DESTINATION include + ${INSTALL_TARGETS_DEFAULT_ARGS} +) +install(EXPORT octomap-targets DESTINATION share/octomap/) + +install(TARGETS graph2tree log2graph binvox2bt diff --git a/octomap/src/math/CMakeLists.txt b/octomap/src/math/CMakeLists.txt index e464190c..f6ae8b17 100644 --- a/octomap/src/math/CMakeLists.txt +++ b/octomap/src/math/CMakeLists.txt @@ -17,5 +17,11 @@ SET_TARGET_PROPERTIES( octomath PROPERTIES ADD_LIBRARY( octomath-static STATIC ${octomath_SRCS}) SET_TARGET_PROPERTIES(octomath-static PROPERTIES OUTPUT_NAME "octomath") -install(TARGETS octomath octomath-static ${INSTALL_TARGETS_DEFAULT_ARGS}) - \ No newline at end of file +export(TARGETS octomath octomath-static + APPEND FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-targets.cmake") + +install(TARGETS octomath octomath-static + EXPORT octomap-targets + INCLUDES DESTINATION include + ${INSTALL_TARGETS_DEFAULT_ARGS} +) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index d0fbec86..c326d7fd 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -125,6 +125,9 @@ IF(BUILD_VIEWER) set(OCTOVIS_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") #set(OCTOMAP_CMAKE_DIR "${INSTALL_DATA_DIR}/FooBar/CMake") + set(OCTOVIS_INCLUDE_TARGETS + "include(\${CMAKE_CURRENT_LIST_DIR}/octovis-targets.cmake)") + CONFIGURE_PACKAGE_CONFIG_FILE( octovis-config.cmake.in "${PROJECT_BINARY_DIR}/InstallFiles/octovis-config.cmake" diff --git a/octovis/CMakeLists_src.txt b/octovis/CMakeLists_src.txt index f9cf9ebe..736a5a38 100644 --- a/octovis/CMakeLists_src.txt +++ b/octovis/CMakeLists_src.txt @@ -113,11 +113,15 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") ) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") -install(TARGETS octovis - octovis-static - octovis-shared +export(TARGETS octovis octovis-static octovis-shared + FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-targets.cmake") + +install(TARGETS octovis octovis-static octovis-shared + EXPORT octovis-targets + INCLUDES DESTINATION include ${INSTALL_TARGETS_DEFAULT_ARGS} ) +install(EXPORT octovis-targets DESTINATION share/octovis/) file(GLOB octovis_HDRS ${PROJECT_SOURCE_DIR}/include/octovis/*.h) # filter generated headers for GUI: diff --git a/octovis/octovis-config.cmake.in b/octovis/octovis-config.cmake.in index b31eed1f..3add82ee 100644 --- a/octovis/octovis-config.cmake.in +++ b/octovis/octovis-config.cmake.in @@ -23,3 +23,5 @@ set(OCTOVIS_LIBRARIES "@QT_LIBRARIES@" "@PACKAGE_OCTOVIS_LIB_DIR@/@OCTOVIS_LIBRARY@" ) + +@OCTOVIS_INCLUDE_TARGETS@ From 4f64f0e6c8144079b0d576c7543205284bcc1bbb Mon Sep 17 00:00:00 2001 From: Jamie Snape Date: Fri, 7 Oct 2016 20:26:20 -0400 Subject: [PATCH 16/27] Use CTest module and its BUILD_TESTING option Note that BUILD_TESTING defaults to ON --- dynamicEDT3D/CMakeLists.txt | 2 +- octomap/CMakeLists.txt | 2 +- octomap/src/testing/CMakeLists.txt | 73 +++++++++++++++--------------- octovis/CMakeLists.txt | 2 + 4 files changed, 41 insertions(+), 38 deletions(-) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 0fa448a2..c90d2e48 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT(dynamicEDT3D) -ENABLE_TESTING() +include(CTest) # version (e.g. for packaging) set(DYNAMICEDT3D_MAJOR_VERSION 1) diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 223fec90..8c675f07 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT( octomap ) -ENABLE_TESTING() +include(CTest) # version (e.g. for packaging) set(OCTOMAP_MAJOR_VERSION 1) diff --git a/octomap/src/testing/CMakeLists.txt b/octomap/src/testing/CMakeLists.txt index cb90a6e8..b85ae3b5 100644 --- a/octomap/src/testing/CMakeLists.txt +++ b/octomap/src/testing/CMakeLists.txt @@ -1,48 +1,49 @@ +if(BUILD_TESTING) + ADD_EXECUTABLE(test_raycasting test_raycasting.cpp) + TARGET_LINK_LIBRARIES(test_raycasting octomap) -ADD_EXECUTABLE(test_raycasting test_raycasting.cpp) -TARGET_LINK_LIBRARIES(test_raycasting octomap) + ADD_EXECUTABLE(test_iterators test_iterators.cpp) + TARGET_LINK_LIBRARIES(test_iterators octomap) -ADD_EXECUTABLE(test_iterators test_iterators.cpp) -TARGET_LINK_LIBRARIES(test_iterators octomap) + ADD_EXECUTABLE(test_io test_io.cpp) + TARGET_LINK_LIBRARIES(test_io octomap) -ADD_EXECUTABLE(test_io test_io.cpp) -TARGET_LINK_LIBRARIES(test_io octomap) + ADD_EXECUTABLE(test_changedkeys test_changedkeys.cpp) + TARGET_LINK_LIBRARIES(test_changedkeys octomap) -ADD_EXECUTABLE(test_changedkeys test_changedkeys.cpp) -TARGET_LINK_LIBRARIES(test_changedkeys octomap) + ADD_EXECUTABLE(test_scans test_scans.cpp) + TARGET_LINK_LIBRARIES(test_scans octomap) -ADD_EXECUTABLE(test_scans test_scans.cpp) -TARGET_LINK_LIBRARIES(test_scans octomap) + ADD_EXECUTABLE(test_color_tree test_color_tree.cpp) + TARGET_LINK_LIBRARIES(test_color_tree octomap) -ADD_EXECUTABLE(test_color_tree test_color_tree.cpp) -TARGET_LINK_LIBRARIES(test_color_tree octomap) + ADD_EXECUTABLE(color_tree_histogram color_tree_histogram.cpp) + TARGET_LINK_LIBRARIES(color_tree_histogram octomap) -ADD_EXECUTABLE(color_tree_histogram color_tree_histogram.cpp) -TARGET_LINK_LIBRARIES(color_tree_histogram octomap) + ADD_EXECUTABLE(test_mapcollection test_mapcollection.cpp) + TARGET_LINK_LIBRARIES(test_mapcollection octomap octomath) -ADD_EXECUTABLE(test_mapcollection test_mapcollection.cpp) -TARGET_LINK_LIBRARIES(test_mapcollection octomap octomath) + ADD_EXECUTABLE(test_pruning test_pruning.cpp) + TARGET_LINK_LIBRARIES(test_pruning octomap octomath) -ADD_EXECUTABLE(test_pruning test_pruning.cpp) -TARGET_LINK_LIBRARIES(test_pruning octomap octomath) + # CTest tests below -# CTest tests below + ADD_EXECUTABLE(unit_tests unit_tests.cpp) + TARGET_LINK_LIBRARIES(unit_tests octomap) -ADD_EXECUTABLE(unit_tests unit_tests.cpp) -TARGET_LINK_LIBRARIES(unit_tests octomap) - -ADD_TEST (NAME MathVector COMMAND unit_tests MathVector ) -ADD_TEST (NAME MathPose COMMAND unit_tests MathPose ) -ADD_TEST (NAME InsertRay COMMAND unit_tests InsertRay ) -ADD_TEST (NAME InsertScan COMMAND unit_tests InsertScan ) -ADD_TEST (NAME ReadGraph COMMAND unit_tests ReadGraph ) -ADD_TEST (NAME StampedTree COMMAND unit_tests StampedTree ) -ADD_TEST (NAME OcTreeKey COMMAND unit_tests OcTreeKey ) -ADD_TEST (NAME test_scans COMMAND test_scans ${PROJECT_SOURCE_DIR}/share/data/spherical_scan.graph) -ADD_TEST (NAME test_raycasting COMMAND test_raycasting) -ADD_TEST (NAME test_io COMMAND test_io ${PROJECT_SOURCE_DIR}/share/data/geb079.bt) -ADD_TEST (NAME test_pruning COMMAND test_pruning ) -ADD_TEST (NAME test_iterators COMMAND test_iterators ${PROJECT_SOURCE_DIR}/share/data/geb079.bt) -ADD_TEST (NAME test_mapcollection COMMAND test_mapcollection ${PROJECT_SOURCE_DIR}/share/data/mapcoll.txt) -ADD_TEST (NAME test_color_tree COMMAND test_color_tree) + ADD_TEST (NAME MathVector COMMAND unit_tests MathVector ) + ADD_TEST (NAME MathPose COMMAND unit_tests MathPose ) + ADD_TEST (NAME InsertRay COMMAND unit_tests InsertRay ) + ADD_TEST (NAME InsertScan COMMAND unit_tests InsertScan ) + ADD_TEST (NAME ReadGraph COMMAND unit_tests ReadGraph ) + ADD_TEST (NAME StampedTree COMMAND unit_tests StampedTree ) + ADD_TEST (NAME OcTreeKey COMMAND unit_tests OcTreeKey ) + ADD_TEST (NAME test_scans COMMAND test_scans ${PROJECT_SOURCE_DIR}/share/data/spherical_scan.graph) + ADD_TEST (NAME test_raycasting COMMAND test_raycasting) + ADD_TEST (NAME test_io COMMAND test_io ${PROJECT_SOURCE_DIR}/share/data/geb079.bt) + ADD_TEST (NAME test_pruning COMMAND test_pruning ) + ADD_TEST (NAME test_iterators COMMAND test_iterators ${PROJECT_SOURCE_DIR}/share/data/geb079.bt) + ADD_TEST (NAME test_mapcollection COMMAND test_mapcollection ${PROJECT_SOURCE_DIR}/share/data/mapcoll.txt) + ADD_TEST (NAME test_color_tree COMMAND test_color_tree) +endif() diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index d0fbec86..e50f6800 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -1,6 +1,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.8) PROJECT( octovis ) +include(CTest) + # # version (e.g. for packaging) set(OCTOVIS_MAJOR_VERSION 1) set(OCTOVIS_MINOR_VERSION 8) From fc851bb8fc259febe8b4698ae11289c2ceb0f618 Mon Sep 17 00:00:00 2001 From: Jamie Snape Date: Mon, 24 Oct 2016 09:48:45 -0400 Subject: [PATCH 17/27] Ensure directory for exported targets exists --- dynamicEDT3D/src/CMakeLists.txt | 4 ++++ octomap/src/CMakeLists.txt | 4 ++++ octomap/src/math/CMakeLists.txt | 4 ++++ octovis/CMakeLists_src.txt | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/dynamicEDT3D/src/CMakeLists.txt b/dynamicEDT3D/src/CMakeLists.txt index 4a720fa3..44645d88 100644 --- a/dynamicEDT3D/src/CMakeLists.txt +++ b/dynamicEDT3D/src/CMakeLists.txt @@ -14,6 +14,10 @@ target_link_libraries(dynamicedt3d-static ${OCTOMAP_LIBRARIES}) SET_TARGET_PROPERTIES(dynamicedt3d-static PROPERTIES OUTPUT_NAME "dynamicedt3d") +if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D") + file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D") +endif() + export(TARGETS dynamicedt3d dynamicedt3d-static FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/dynamicEDT3D/dynamicEDT3DTargets.cmake") diff --git a/octomap/src/CMakeLists.txt b/octomap/src/CMakeLists.txt index 6d5cae09..9ac6dcbf 100644 --- a/octomap/src/CMakeLists.txt +++ b/octomap/src/CMakeLists.txt @@ -21,6 +21,10 @@ SET_TARGET_PROPERTIES(octomap-static PROPERTIES OUTPUT_NAME "octomap") TARGET_LINK_LIBRARIES(octomap octomath) +if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") + file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") +endif() + export(TARGETS octomap octomap-static APPEND FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-targets.cmake") diff --git a/octomap/src/math/CMakeLists.txt b/octomap/src/math/CMakeLists.txt index f6ae8b17..22127adb 100644 --- a/octomap/src/math/CMakeLists.txt +++ b/octomap/src/math/CMakeLists.txt @@ -17,6 +17,10 @@ SET_TARGET_PROPERTIES( octomath PROPERTIES ADD_LIBRARY( octomath-static STATIC ${octomath_SRCS}) SET_TARGET_PROPERTIES(octomath-static PROPERTIES OUTPUT_NAME "octomath") +if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") + file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap") +endif() + export(TARGETS octomath octomath-static APPEND FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octomap/octomap-targets.cmake") diff --git a/octovis/CMakeLists_src.txt b/octovis/CMakeLists_src.txt index 736a5a38..8227d984 100644 --- a/octovis/CMakeLists_src.txt +++ b/octovis/CMakeLists_src.txt @@ -113,6 +113,10 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") ) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +if(NOT EXISTS "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis") + file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis") +endif() + export(TARGETS octovis octovis-static octovis-shared FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/octovis/octovis-targets.cmake") From 4ddbd1ba79874e4bf5ba8320fbf49f6772575f77 Mon Sep 17 00:00:00 2001 From: Aleksandrs Ecins Date: Fri, 13 Jan 2017 18:55:50 -0500 Subject: [PATCH 18/27] Fix getUnknownLeafCenters to return true leaf centers --- octomap/include/octomap/OcTreeBaseImpl.hxx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/octomap/include/octomap/OcTreeBaseImpl.hxx b/octomap/include/octomap/OcTreeBaseImpl.hxx index af02183c..ac66507c 100644 --- a/octomap/include/octomap/OcTreeBaseImpl.hxx +++ b/octomap/include/octomap/OcTreeBaseImpl.hxx @@ -1049,16 +1049,19 @@ namespace octomap { if (depth == 0) depth = tree_depth; + point3d pmin_clamped = this->keyToCoord(this->coordToKey(pmin, depth), depth); + point3d pmax_clamped = this->keyToCoord(this->coordToKey(pmax, depth), depth); + float diff[3]; unsigned int steps[3]; float step_size = this->resolution * pow(2, tree_depth-depth); for (int i=0;i<3;++i) { - diff[i] = pmax(i) - pmin(i); + diff[i] = pmax_clamped(i) - pmin_clamped(i); steps[i] = floor(diff[i] / step_size); // std::cout << "bbx " << i << " size: " << diff[i] << " " << steps[i] << " steps\n"; } - point3d p = pmin; + point3d p = pmin_clamped; NODE* res; for (unsigned int x=0; x Date: Tue, 17 Jan 2017 22:22:58 +0100 Subject: [PATCH 19/27] Update changelog --- octomap/CHANGELOG.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/octomap/CHANGELOG.txt b/octomap/CHANGELOG.txt index 8775f7a5..4d0da7a0 100644 --- a/octomap/CHANGELOG.txt +++ b/octomap/CHANGELOG.txt @@ -1,3 +1,9 @@ +v1.8.1: 2017-01-13 +================== +- Disambiguated isnan (C++11) +- Fixed #123: Set root=NULL in clear() +- Fixed #131: Portable binary read/write of Pointcloud and ScanGraph (uint32_t) + v1.8.0: 2016-04-20 ================== - Fixed #98: The tree structure in memory is now maintained in OcTreeBaseImpl to From 84bd2268b10bbf14ad7231fefeb8180eb2698104 Mon Sep 17 00:00:00 2001 From: Christopher-Eyk Hrabia Date: Wed, 8 Feb 2017 21:14:07 +0100 Subject: [PATCH 20/27] Improve build by specifically targeting local includes in case of available system includes (#155) --- octovis/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index 23f01deb..ecee0673 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -48,7 +48,7 @@ ${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap ) MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) -INCLUDE_DIRECTORIES(${OCTOMAP_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(BEFORE SYSTEM ${OCTOMAP_INCLUDE_DIRS}) # Export the package for use from the build-tree # (this registers the build-tree with a global CMake-registry) From 6ac4c9cfa12e2ce59eaf1c0bc7ef5ac69f90e951 Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Wed, 8 Feb 2017 21:16:47 +0100 Subject: [PATCH 21/27] Improve dynamicEDT3D build by specifically targeting local includes before system includes --- dynamicEDT3D/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 865daaf7..38e2bd12 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -57,7 +57,7 @@ find_package(octomap REQUIRED MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) MESSAGE(STATUS "octomap libraries: ${OCTOMAP_LIBRARIES}") -INCLUDE_DIRECTORIES(${OCTOMAP_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(BEFORE SYSTEM ${OCTOMAP_INCLUDE_DIRS}) ADD_SUBDIRECTORY(src) From 817af600a2aa0a5074141a052ffeb7dc0870f2d1 Mon Sep 17 00:00:00 2001 From: Christopher-Eyk Hrabia Date: Fri, 24 Feb 2017 20:35:09 +0100 Subject: [PATCH 22/27] Replace ${CMAKE_SOURCE_DIR} with ${PROJECT_SOURCE_DIR} Enables embedding octomap into other source structures, for instance through add_subdirectory() (#157) --- dynamicEDT3D/CMakeLists.txt | 6 +++--- octomap/CMakeLists.txt | 2 +- octovis/CMakeLists.txt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 38e2bd12..40fd2ae9 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -25,7 +25,7 @@ INCLUDE(CompilerSettings) # Set output directories for libraries and executables -SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) +SET( BASE_DIR ${PROJECT_SOURCE_DIR} ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) @@ -51,8 +51,8 @@ set(INSTALL_TARGETS_DEFAULT_ARGS ) find_package(octomap REQUIRED - HINTS ${CMAKE_SOURCE_DIR}/lib/cmake/octomap - ${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap + PATHS ${PROJECT_SOURCE_DIR}/../octomap/lib/cmake/octomap + NO_DEFAULT_PATH ) MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) MESSAGE(STATUS "octomap libraries: ${OCTOMAP_LIBRARIES}") diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 0f8887df..290b89bf 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -35,7 +35,7 @@ IF(OCTOMAP_OMP) ENDIF(OCTOMAP_OMP) # Set output directories for libraries and executables -SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) +SET( BASE_DIR ${PROJECT_SOURCE_DIR} ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index ecee0673..d9072c6d 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -24,7 +24,7 @@ SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") INCLUDE(CompilerSettings) # Set output directories for libraries and executables -SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) +SET( BASE_DIR ${PROJECT_SOURCE_DIR} ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) @@ -43,8 +43,8 @@ endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) # Otherwise you need to export octomap_DIR to the directory containing # the file octomap-config.cmake find_package(octomap ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION} REQUIRED -HINTS ${CMAKE_SOURCE_DIR}/lib/cmake/octomap -${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap +PATHS ${PROJECT_SOURCE_DIR}/../octomap/lib/cmake/octomap +NO_DEFAULT_PATH ) MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) From cefed0c1d79afafa5aeb05273cf1246b093b771c Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Sat, 11 Mar 2017 22:19:30 +0100 Subject: [PATCH 23/27] Qt5 support (CMake option) for octovis (#152) Set CMake option OCTOVIS_QT5 to true in order to use it. Contributed by K. Stepanas. --- CMakeLists.txt | 6 +++ octovis/CMakeLists.txt | 4 +- octovis/CMakeLists_src.txt | 51 +++++++++++++++---- octovis/include/octovis/SceneObject.h | 4 +- octovis/include/octovis/ViewerGui.h | 5 ++ octovis/include/octovis/ViewerSettings.h | 5 ++ .../octovis/ViewerSettingsPanelCamera.h | 5 ++ octovis/src/ViewerGui.cpp | 8 +++ 8 files changed, 74 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7fc92e8..4b3d8d75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,12 @@ ENABLE_TESTING() # enable CTest environment of subprojects option(BUILD_OCTOVIS_SUBPROJECT "Build targets from subproject octovis" ON) option(BUILD_DYNAMICETD3D_SUBPROJECT "Build targets from subproject dynamicEDT3D" ON) +option(OCTOVIS_QT5 "Link Octovis against Qt5?" NO) + +if(OCTOVIS_QT5) + # Compiling against QT5 requires C++11. + set(CMAKE_CXX_STANDARD 11) +endif(OCTOVIS_QT5) ADD_SUBDIRECTORY( octomap ) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index d9072c6d..8dced443 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -66,7 +66,9 @@ SET( BUILD_VIEWER 0) # Look for required libraries: FIND_PACKAGE(OpenGL) -FIND_PACKAGE(Qt4) +if(NOT OCTOVIS_QT5) + FIND_PACKAGE(Qt4) +endif(NOT OCTOVIS_QT5) IF (OpenGL-NOTFOUND OR Qt4-NOTFOUND) MESSAGE ( "OpenGL and QT4 are required for octovis but could not be found.") diff --git a/octovis/CMakeLists_src.txt b/octovis/CMakeLists_src.txt index 8227d984..1f800c2d 100644 --- a/octovis/CMakeLists_src.txt +++ b/octovis/CMakeLists_src.txt @@ -1,9 +1,26 @@ -# Qt4-support (more info: http://qtnode.net/wiki?title=Qt_with_cmake) -find_package(Qt4 REQUIRED) -set(QT_USE_QTOPENGL TRUE) -set(QT_USE_QTXML TRUE) -# include the files enabled above -include(${QT_USE_FILE}) + +if(OCTOVIS_QT5) + find_package(Qt5Core REQUIRED) + find_package(Qt5Gui REQUIRED) + find_package(Qt5OpenGL REQUIRED) + find_package(Qt5Widgets REQUIRED) + find_package(Qt5Xml REQUIRED) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets Qt5::Xml "${OPENGL_gl_LIBRARY}" "${OPENGL_glu_LIBRARY}") + include_directories( + "${Qt5Core_INCLUDE_DIRS}" + "${Qt5Gui_INCLUDE_DIRS}" + "${Qt5OpenGL_INCLUDE_DIRS}" + "${Qt5Widgets_INCLUDE_DIRS}" + "${Qt5Xml_INCLUDE_DIRS}" + ) +else(OCTOVIS_QT5) + # Qt4-support (more info: http://qtnode.net/wiki?title=Qt_with_cmake) + find_package(Qt4 REQUIRED) + set(QT_USE_QTOPENGL TRUE) + set(QT_USE_QTXML TRUE) + # include the files enabled above + include(${QT_USE_FILE}) +endif(OCTOVIS_QT5) # Mac OS X seems to require special linker flags: IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -34,7 +51,11 @@ set(viewer_SRCS ) # Resource files (icons, ...) -QT4_ADD_RESOURCES(viewer_RES src/icons.qrc) +if(OCTOVIS_QT5) + QT5_ADD_RESOURCES(viewer_RES src/icons.qrc) +else(OCTOVIS_QT5) + QT4_ADD_RESOURCES(viewer_RES src/icons.qrc) +endif(OCTOVIS_QT5) #found QGLViewer lib dir link_directories(${QGLViewer_LIBRARY_DIR}) @@ -53,7 +74,11 @@ SET(viewer_MOC_HDRS ) # generate list of MOC srcs: -QT4_WRAP_CPP(viewer_MOC_SRCS ${viewer_MOC_HDRS}) +if(OCTOVIS_QT5) + QT5_WRAP_CPP(viewer_MOC_SRCS ${viewer_MOC_HDRS}) +else(OCTOVIS_QT5) + QT4_WRAP_CPP(viewer_MOC_SRCS ${viewer_MOC_HDRS}) +endif(OCTOVIS_QT5) # let cmake generate ui*.h files from .ui files (Qt Designer): SET(viewer_UIS @@ -62,7 +87,11 @@ SET(viewer_UIS ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettingsPanel.ui ${PROJECT_SOURCE_DIR}/include/octovis/ViewerSettingsPanelCamera.ui ) -QT4_WRAP_UI(viewer_UIS_H ${viewer_UIS}) +if(OCTOVIS_QT5) + QT5_WRAP_UI(viewer_UIS_H ${viewer_UIS}) +else(OCTOVIS_QT5) + QT4_WRAP_UI(viewer_UIS_H ${viewer_UIS}) +endif(OCTOVIS_QT5) # Don't forget to include output directory, otherwise # the UI file won't be wrapped! @@ -108,8 +137,8 @@ target_link_libraries(octovis # special handling of MacOS X: IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_custom_command(TARGET octovis POST_BUILD - COMMAND install_name_tool -change libQGLViewer.2.dylib /opt/local/lib/libQGLViewer.2.dylib ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/octovis + add_custom_command(TARGET octovis POST_BUILD + COMMAND install_name_tool -change libQGLViewer.2.dylib /opt/local/lib/libQGLViewer.2.dylib ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/octovis ) ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/octovis/include/octovis/SceneObject.h b/octovis/include/octovis/SceneObject.h index 7005d969..240c4650 100644 --- a/octovis/include/octovis/SceneObject.h +++ b/octovis/include/octovis/SceneObject.h @@ -27,11 +27,11 @@ // fix Windows includes #include -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(Q_OS_WIN) #include #endif -#ifdef Q_WS_MAC +#if defined(Q_WS_MAC) || defined(Q_OS_MAC) #include #else #include diff --git a/octovis/include/octovis/ViewerGui.h b/octovis/include/octovis/ViewerGui.h index 41a5dee7..829d851e 100644 --- a/octovis/include/octovis/ViewerGui.h +++ b/octovis/include/octovis/ViewerGui.h @@ -25,7 +25,12 @@ #ifndef VIEWERGUI_H #define VIEWERGUI_H +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#else // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include +#endif // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #include #include diff --git a/octovis/include/octovis/ViewerSettings.h b/octovis/include/octovis/ViewerSettings.h index 80a6be11..2d9e94e3 100644 --- a/octovis/include/octovis/ViewerSettings.h +++ b/octovis/include/octovis/ViewerSettings.h @@ -25,7 +25,12 @@ #ifndef VIEWERSETTINGS_H #define VIEWERSETTINGS_H +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#else // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include +#endif // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include "ui_ViewerSettings.h" class ViewerSettings : public QDialog diff --git a/octovis/include/octovis/ViewerSettingsPanelCamera.h b/octovis/include/octovis/ViewerSettingsPanelCamera.h index 5c666972..57051d12 100644 --- a/octovis/include/octovis/ViewerSettingsPanelCamera.h +++ b/octovis/include/octovis/ViewerSettingsPanelCamera.h @@ -25,7 +25,12 @@ #ifndef VIEWERSETTINGSPANELFLYMODE_H #define VIEWERSETTINGSPANELFLYMODE_H +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#else #include +#endif #include "ui_ViewerSettingsPanelCamera.h" class ViewerSettingsPanelCamera : public QWidget diff --git a/octovis/src/ViewerGui.cpp b/octovis/src/ViewerGui.cpp index a748ff4f..b4442c41 100644 --- a/octovis/src/ViewerGui.cpp +++ b/octovis/src/ViewerGui.cpp @@ -1197,14 +1197,22 @@ void ViewerGui::on_action_bg_gray_triggered() { void ViewerGui::on_savecampose_triggered() { QString filename = QFileDialog::getSaveFileName(this, "Save Viewer State", "camera.xml", "Camera/State file (*.xml)"); if (!filename.isEmpty()) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + saveCameraPosition(filename.toLatin1().constData()); +#else // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) saveCameraPosition(filename.toAscii().constData()); +#endif // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) } } void ViewerGui::on_loadcampose_triggered() { QString filename = QFileDialog::getOpenFileName(this, "Load Viewer State", "camera.xml", "Camera/State file (*.xml)"); if (!filename.isEmpty()) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + loadCameraPosition(filename.toLatin1().constData()); +#else // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) loadCameraPosition(filename.toAscii().constData()); +#endif // QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) } } From 6f981e9c4b7d834dd81fb44db25918ef459dc364 Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Wed, 26 Apr 2017 21:22:24 +0200 Subject: [PATCH 24/27] Revert "Replace ${CMAKE_SOURCE_DIR} with ${PROJECT_SOURCE_DIR} " (#157) This reverts commit 817af600a2aa0a5074141a052ffeb7dc0870f2d1. --- dynamicEDT3D/CMakeLists.txt | 6 +++--- octomap/CMakeLists.txt | 2 +- octovis/CMakeLists.txt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 40fd2ae9..38e2bd12 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -25,7 +25,7 @@ INCLUDE(CompilerSettings) # Set output directories for libraries and executables -SET( BASE_DIR ${PROJECT_SOURCE_DIR} ) +SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) @@ -51,8 +51,8 @@ set(INSTALL_TARGETS_DEFAULT_ARGS ) find_package(octomap REQUIRED - PATHS ${PROJECT_SOURCE_DIR}/../octomap/lib/cmake/octomap - NO_DEFAULT_PATH + HINTS ${CMAKE_SOURCE_DIR}/lib/cmake/octomap + ${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap ) MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) MESSAGE(STATUS "octomap libraries: ${OCTOMAP_LIBRARIES}") diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 290b89bf..0f8887df 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -35,7 +35,7 @@ IF(OCTOMAP_OMP) ENDIF(OCTOMAP_OMP) # Set output directories for libraries and executables -SET( BASE_DIR ${PROJECT_SOURCE_DIR} ) +SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index 8dced443..7bf6c5c7 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -24,7 +24,7 @@ SET (CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") INCLUDE(CompilerSettings) # Set output directories for libraries and executables -SET( BASE_DIR ${PROJECT_SOURCE_DIR} ) +SET( BASE_DIR ${CMAKE_SOURCE_DIR} ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BASE_DIR}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BASE_DIR}/bin ) @@ -43,8 +43,8 @@ endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) # Otherwise you need to export octomap_DIR to the directory containing # the file octomap-config.cmake find_package(octomap ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION} REQUIRED -PATHS ${PROJECT_SOURCE_DIR}/../octomap/lib/cmake/octomap -NO_DEFAULT_PATH +HINTS ${CMAKE_SOURCE_DIR}/lib/cmake/octomap +${CMAKE_SOURCE_DIR}/../octomap/lib/cmake/octomap ) MESSAGE(STATUS "Found octomap version: " ${octomap_VERSION}) From 5355bbc46af6f0da874cd12f81a323a2de0b0235 Mon Sep 17 00:00:00 2001 From: zzh Date: Sat, 29 Apr 2017 04:24:28 +0900 Subject: [PATCH 25/27] Minimal workaround for ColorOcTree in octovis with VS2012 (#167) a minimal workaround for the ColorOcTree type register issue on the visual studio 2012 platform of windows 8 a redundant object definition to ensure VS2012 not to drop the the constructor of the member static class called StaticMemberInitializer, causing the ColorOcTree failing to register. --- octovis/src/ViewerGui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/octovis/src/ViewerGui.cpp b/octovis/src/ViewerGui.cpp index b4442c41..dfa65c3c 100644 --- a/octovis/src/ViewerGui.cpp +++ b/octovis/src/ViewerGui.cpp @@ -29,6 +29,8 @@ #include #include #include +//Dummy object definition to ensure VS2012 does not drop the StaticMemberInitializer, causing this tree failing to register. +octomap::ColorOcTree colortreeTmp(0); #define _MAXRANGE_URG 5.1 From 14581c443dfb13e86e77c500937855d14bad7dd3 Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Fri, 28 Apr 2017 21:35:53 +0200 Subject: [PATCH 26/27] Recommend uppercase OCTOMAP for FIND_PACKAGE in octomap-config.cmake.in (Fixes #138) --- octomap/octomap-config.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octomap/octomap-config.cmake.in b/octomap/octomap-config.cmake.in index e0ffc5d6..2f686bef 100644 --- a/octomap/octomap-config.cmake.in +++ b/octomap/octomap-config.cmake.in @@ -6,7 +6,7 @@ # Usage from an external project: # In your CMakeLists.txt, add these lines: # -# FIND_PACKAGE(octomap REQUIRED ) +# FIND_PACKAGE(OCTOMAP REQUIRED ) # INCLUDE_DIRECTORIES(${OCTOMAP_INCLUDE_DIRS}) # TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${OCTOMAP_LIBRARIES}) # From 4f0127598d50cfb289bdeec1706ac987eae78591 Mon Sep 17 00:00:00 2001 From: Armin Hornung Date: Fri, 28 Apr 2017 21:48:42 +0200 Subject: [PATCH 27/27] Version 1.9.0 release --- dynamicEDT3D/CMakeLists.txt | 2 +- dynamicEDT3D/package.xml | 2 +- octomap/CHANGELOG.txt | 15 +++++++++++++++ octomap/CMakeLists.txt | 2 +- octomap/package.xml | 2 +- octovis/CMakeLists.txt | 2 +- octovis/package.xml | 2 +- 7 files changed, 21 insertions(+), 6 deletions(-) diff --git a/dynamicEDT3D/CMakeLists.txt b/dynamicEDT3D/CMakeLists.txt index 38e2bd12..ed8d2f55 100644 --- a/dynamicEDT3D/CMakeLists.txt +++ b/dynamicEDT3D/CMakeLists.txt @@ -5,7 +5,7 @@ include(CTest) # version (e.g. for packaging) set(DYNAMICEDT3D_MAJOR_VERSION 1) -set(DYNAMICEDT3D_MINOR_VERSION 8) +set(DYNAMICEDT3D_MINOR_VERSION 9) set(DYNAMICEDT3D_PATCH_VERSION 0) set(DYNAMICEDT3D_VERSION ${DYNAMICEDT3D_MAJOR_VERSION}.${DYNAMICEDT3D_MINOR_VERSION}.${DYNAMICEDT3D_PATCH_VERSION}) set(DYNAMICEDT3D_SOVERSION ${DYNAMICEDT3D_MAJOR_VERSION}.${DYNAMICEDT3D_MINOR_VERSION}) diff --git a/dynamicEDT3D/package.xml b/dynamicEDT3D/package.xml index a25cd01f..bb2a636e 100644 --- a/dynamicEDT3D/package.xml +++ b/dynamicEDT3D/package.xml @@ -1,6 +1,6 @@ dynamic_edt_3d - 1.8.0 + 1.9.0 The dynamicEDT3D library implements an inrementally updatable Euclidean distance transform (EDT) in 3D. It comes with a wrapper to use the OctoMap 3D representation and hooks into the change detection of the OctoMap library to propagate changes to the EDT. Christoph Sprunk diff --git a/octomap/CHANGELOG.txt b/octomap/CHANGELOG.txt index 4d0da7a0..f86868ac 100644 --- a/octomap/CHANGELOG.txt +++ b/octomap/CHANGELOG.txt @@ -1,3 +1,18 @@ +v1.9.0: 2017-04-28 +================== +- Fixed getUnknownLeafCenters to return true leaf centers (thx to A. Ecins) +- dynamicEDT3D templated over OctoMap type (thx to J.V. Gomez) +- Added optimized rendering option and command line option for tree cutoff + in octovis (thx to F. Endres) +- Added optional Qt5 support in octovis (thx to K. Stepanas) +- Improved the generation of config.cmake and version.cmake files, make them + relocatable via CONFIGURE_PACKAGE_CONFIG_FILE (thx to J.V. Gomez) +- Enable rpath on OS X when the CMake version supports it (thx to J. Snape) +- Added version information to *-config.cmake files and exported targets to + CMakeLists.txt (thx to J. Snape) +- Improved CMake build by specifically targeting local includes (thx to + C.-E. Hrabia) + v1.8.1: 2017-01-13 ================== - Disambiguated isnan (C++11) diff --git a/octomap/CMakeLists.txt b/octomap/CMakeLists.txt index 0f8887df..50e6323f 100644 --- a/octomap/CMakeLists.txt +++ b/octomap/CMakeLists.txt @@ -5,7 +5,7 @@ include(CTest) # version (e.g. for packaging) set(OCTOMAP_MAJOR_VERSION 1) -set(OCTOMAP_MINOR_VERSION 8) +set(OCTOMAP_MINOR_VERSION 9) set(OCTOMAP_PATCH_VERSION 0) set(OCTOMAP_VERSION ${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}.${OCTOMAP_PATCH_VERSION}) set(OCTOMAP_SOVERSION ${OCTOMAP_MAJOR_VERSION}.${OCTOMAP_MINOR_VERSION}) diff --git a/octomap/package.xml b/octomap/package.xml index ed2282c6..28ffe778 100644 --- a/octomap/package.xml +++ b/octomap/package.xml @@ -1,6 +1,6 @@ octomap - 1.8.0 + 1.9.0 The OctoMap library implements a 3D occupancy grid mapping approach, providing data structures and mapping algorithms in C++. The map implementation is based on an octree. See http://octomap.github.io for details. diff --git a/octovis/CMakeLists.txt b/octovis/CMakeLists.txt index 7bf6c5c7..61490d9a 100644 --- a/octovis/CMakeLists.txt +++ b/octovis/CMakeLists.txt @@ -5,7 +5,7 @@ include(CTest) # # version (e.g. for packaging) set(OCTOVIS_MAJOR_VERSION 1) -set(OCTOVIS_MINOR_VERSION 8) +set(OCTOVIS_MINOR_VERSION 9) set(OCTOVIS_PATCH_VERSION 0) set(OCTOVIS_VERSION ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION}.${OCTOVIS_PATCH_VERSION}) set(OCTOVIS_SOVERSION ${OCTOVIS_MAJOR_VERSION}.${OCTOVIS_MINOR_VERSION}) diff --git a/octovis/package.xml b/octovis/package.xml index 57567556..c95b9e80 100644 --- a/octovis/package.xml +++ b/octovis/package.xml @@ -1,6 +1,6 @@ octovis - 1.8.0 + 1.9.0 octovis is visualization tool for the OctoMap library based on Qt and libQGLViewer. See http://octomap.github.io for details.