diff --git a/.ci/azure-pipelines/azure-pipelines.yaml b/.ci/azure-pipelines/azure-pipelines.yaml index a6b03419323..079655b21ae 100644 --- a/.ci/azure-pipelines/azure-pipelines.yaml +++ b/.ci/azure-pipelines/azure-pipelines.yaml @@ -1,15 +1,33 @@ +trigger: + paths: + exclude: + - doc + - README.md + - CHANGES.md + - CONTRIBUTING.md + +pr: + paths: + exclude: + - doc + - README.md + - CHANGES.md + - CONTRIBUTING.md + resources: containers: + - container: winx86 + image: pointcloudlibrary/env:winx86 + - container: winx64 + image: pointcloudlibrary/env:winx64 - container: fmt image: pointcloudlibrary/fmt - container: env1804 image: pointcloudlibrary/env:18.04 - container: env2004 image: pointcloudlibrary/env:20.04 - - container: env2010 - image: pointcloudlibrary/env:20.10 - - container: doc - image: pointcloudlibrary/doc + - container: env2204 + image: pointcloudlibrary/env:22.04 stages: - stage: formatting @@ -33,18 +51,17 @@ stages: CXX: g++ BUILD_GPU: ON CMAKE_ARGS: '-DPCL_WARNINGS_ARE_ERRORS=ON' - 20.10 GCC: # latest Ubuntu - CONTAINER: env2010 + 22.04 GCC: # latest Ubuntu + CONTAINER: env2204 CC: gcc CXX: g++ - BUILD_GPU: OFF - # surface is not ready for re-entrant QHull - CMAKE_ARGS: '-DBUILD_tests_surface=OFF' + BUILD_GPU: OFF # There are currently incompatibilities between GCC 11.2 and CUDA 11.5 container: $[ variables['CONTAINER'] ] timeoutInMinutes: 0 variables: BUILD_DIR: '$(Agent.BuildDirectory)/build' CMAKE_CXX_FLAGS: '-Wall -Wextra -Wnoexcept-type' + DISPLAY: :99.0 # Checked for in CMake steps: - template: build/ubuntu.yaml @@ -61,9 +78,9 @@ stages: Catalina 10.15: VMIMAGE: 'macOS-10.15' OSX_VERSION: '10.15' - Mojave 10.14: - VMIMAGE: 'macOS-10.14' - OSX_VERSION: '10.14' + Big Sur 11: + VMIMAGE: 'macOS-11' + OSX_VERSION: '11' timeoutInMinutes: 0 variables: BUILD_DIR: '$(Agent.WorkFolder)/build' @@ -94,6 +111,7 @@ stages: variables: BUILD_DIR: '$(Agent.BuildDirectory)/build' CMAKE_CXX_FLAGS: '-Wall -Wextra' + DISPLAY: :99.0 # Checked for in CMake steps: - template: build/ubuntu.yaml - job: ubuntu_indices @@ -124,37 +142,27 @@ stages: displayName: Build MSVC dependsOn: formatting jobs: - - job: vs2017 - displayName: Windows VS2017 Build + - job: Windows + displayName: Windows Build pool: - vmImage: 'vs2017-win2016' + vmImage: 'windows-2019' strategy: matrix: x86: + CONTAINER: winx86 PLATFORM: 'x86' ARCHITECTURE: 'x86' - GENERATOR: 'Visual Studio 15 2017' + GENERATOR: '"Visual Studio 16 2019" -A Win32' x64: + CONTAINER: winx64 PLATFORM: 'x64' ARCHITECTURE: 'x86_amd64' - GENERATOR: 'Visual Studio 15 2017 Win64' + GENERATOR: '"Visual Studio 16 2019" -A x64' + container: $[ variables['CONTAINER'] ] timeoutInMinutes: 0 variables: BUILD_DIR: 'c:\build' CONFIGURATION: 'Release' - VCPKG_ROOT: 'C:\vcpkg' + VCPKG_ROOT: 'c:\vcpkg' steps: - template: build/windows.yaml - - - stage: documentation - displayName: Documentation - dependsOn: [] - jobs: - - template: documentation.yaml - - - stage: tutorials - displayName: Tutorials - dependsOn: build_gcc - jobs: - - template: tutorials.yaml - diff --git a/.ci/azure-pipelines/build/macos.yaml b/.ci/azure-pipelines/build/macos.yaml index 4eddf4fb09e..3663116698c 100644 --- a/.ci/azure-pipelines/build/macos.yaml +++ b/.ci/azure-pipelines/build/macos.yaml @@ -3,7 +3,7 @@ steps: # find the commit hash on a quick non-forced update too fetchDepth: 10 - script: | - brew install cmake pkg-config boost eigen flann glew libusb qhull vtk glew qt5 libpcap libomp + brew install cmake pkg-config boost eigen flann glew libusb qhull vtk glew qt5 libpcap libomp google-benchmark brew install brewsci/science/openni git clone https://github.com/abseil/googletest.git $GOOGLE_TEST_DIR # the official endpoint changed to abseil/googletest cd $GOOGLE_TEST_DIR && git checkout release-1.8.1 @@ -20,6 +20,7 @@ steps: -DPCL_ONLY_CORE_POINT_TYPES=ON \ -DBUILD_simulation=ON \ -DBUILD_global_tests=ON \ + -DBUILD_benchmarks=ON \ -DBUILD_examples=ON \ -DBUILD_tools=ON \ -DBUILD_apps=ON \ diff --git a/.ci/azure-pipelines/build/ubuntu.yaml b/.ci/azure-pipelines/build/ubuntu.yaml index 559dfddd70e..961e34ea128 100644 --- a/.ci/azure-pipelines/build/ubuntu.yaml +++ b/.ci/azure-pipelines/build/ubuntu.yaml @@ -1,4 +1,6 @@ steps: + - script: (nohup Xvfb :99 -screen 0 1280x1024x24 -nolisten tcp -nolisten unix &) + displayName: "Start Xvfb for DISPLAY=$(DISPLAY)" - checkout: self # find the commit hash on a quick non-forced update too fetchDepth: 10 @@ -12,6 +14,7 @@ steps: -DBUILD_simulation=ON \ -DBUILD_surface_on_nurbs=ON \ -DBUILD_global_tests=ON \ + -DBUILD_benchmarks=ON \ -DBUILD_examples=ON \ -DBUILD_tools=ON \ -DBUILD_apps=ON \ diff --git a/.ci/azure-pipelines/build/ubuntu_indices.yaml b/.ci/azure-pipelines/build/ubuntu_indices.yaml index 28f8340db43..fd2e836662a 100644 --- a/.ci/azure-pipelines/build/ubuntu_indices.yaml +++ b/.ci/azure-pipelines/build/ubuntu_indices.yaml @@ -10,11 +10,6 @@ steps: -DPCL_ONLY_CORE_POINT_TYPES=ON \ -DPCL_INDEX_SIGNED=$INDEX_SIGNED \ -DPCL_INDEX_SIZE=$INDEX_SIZE \ - -DBUILD_geometry=OFF \ - -DBUILD_tools=OFF \ - -DBUILD_kdtree=OFF \ - -DBUILD_ml=OFF \ - -DBUILD_octree=OFF \ -DBUILD_global_tests=ON # Temporary fix to ensure no tests are skipped cmake $(Build.SourcesDirectory) diff --git a/.ci/azure-pipelines/build/windows.yaml b/.ci/azure-pipelines/build/windows.yaml index 6ffce220103..c98398475b6 100644 --- a/.ci/azure-pipelines/build/windows.yaml +++ b/.ci/azure-pipelines/build/windows.yaml @@ -3,43 +3,32 @@ steps: # find the commit hash on a quick non-forced update too fetchDepth: 10 - script: | - echo ##vso[task.setvariable variable=BOOST_ROOT]%BOOST_ROOT_1_72_0% - displayName: 'Set BOOST_ROOT Environment Variable' - - script: | - echo ##vso[task.prependpath]%BOOST_ROOT_1_72_0%\lib - displayName: 'Include Boost Libraries In System PATH' - - pwsh: Get-PSDrive - displayName: "Check free space" - - script: | - vcpkg.exe install eigen3 flann gtest qhull --triplet %PLATFORM%-windows && vcpkg.exe list - displayName: 'Install C++ Dependencies Via Vcpkg' - - script: | - mkdir %BUILD_DIR% && cd %BUILD_DIR% + mkdir %BUILD_DIR% && cd %BUILD_DIR% && dir cmake $(Build.SourcesDirectory) ^ - -G"%GENERATOR%" ^ + -G%GENERATOR% ^ + -DVCPKG_TARGET_TRIPLET=%PLATFORM%-windows-rel ^ -DCMAKE_BUILD_TYPE="MinSizeRel" ^ - -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake ^ + -DCMAKE_TOOLCHAIN_FILE="%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake" ^ -DVCPKG_APPLOCAL_DEPS=ON ^ -DPCL_BUILD_WITH_BOOST_DYNAMIC_LINKING_WIN32=ON ^ -DPCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32=ON ^ -DPCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32=ON ^ -DBUILD_global_tests=ON ^ + -DBUILD_benchmarks=ON ^ -DBUILD_tools=OFF ^ - -DBUILD_surface_on_nurbs=ON + -DBUILD_surface_on_nurbs=ON ^ + -DPCL_DISABLE_VISUALIZATION_TESTS=ON displayName: 'CMake Configuration' - workingDirectory: 'c:' - script: | cd %BUILD_DIR% && cmake --build . --config %CONFIGURATION% displayName: 'Build Library' - workingDirectory: 'c:' - script: | cd %BUILD_DIR% && cmake --build . --target tests --config %CONFIGURATION% displayName: 'Run Unit Tests' - workingDirectory: 'c:' - task: PublishTestResults@2 inputs: testResultsFormat: 'CTest' testResultsFiles: '**/Test*.xml' - searchFolder: '%BUILD_DIR%' + searchFolder: '$(BUILD_DIR)' condition: succeededOrFailed() diff --git a/.ci/azure-pipelines/docs-pipeline.yaml b/.ci/azure-pipelines/docs-pipeline.yaml new file mode 100644 index 00000000000..e9c787cb0af --- /dev/null +++ b/.ci/azure-pipelines/docs-pipeline.yaml @@ -0,0 +1,46 @@ +trigger: + paths: + include: + - doc + +pr: + paths: + include: + - doc + +resources: + pipelines: + - pipeline: Build-CI + source: Build + trigger: + stages: + - build_gcc + containers: + - container: fmt # for formatting.yaml + image: pointcloudlibrary/fmt + - container: doc # for documentation.yaml + image: pointcloudlibrary/doc + - container: env1804 # for tutorials.yaml + image: pointcloudlibrary/env:18.04 + +stages: + - stage: formatting + displayName: Formatting + # if docs pipeline triggered by build_gcc stage, + # the formatting stage has already run, thus it + # won't run for a second time here. + condition: ne(variables['Build.Reason'], 'ResourceTrigger') + jobs: + - template: formatting.yaml + + - stage: documentation + displayName: Documentation + condition: in(dependencies.formatting.result, 'Succeeded', 'SucceededWithIssues', 'Skipped') + jobs: + - template: documentation.yaml + + - stage: tutorials + displayName: Tutorials + condition: in(dependencies.documentation.result, 'Succeeded', 'SucceededWithIssues') + jobs: + - template: tutorials.yaml diff --git a/.ci/azure-pipelines/env.yml b/.ci/azure-pipelines/env.yml index 264efa3d904..3dfb5176a43 100644 --- a/.ci/azure-pipelines/env.yml +++ b/.ci/azure-pipelines/env.yml @@ -9,12 +9,14 @@ trigger: paths: include: - .dev/docker/env/Dockerfile + - .dev/docker/windows - .ci/azure-pipelines/env.yml pr: paths: include: - .dev/docker/env/Dockerfile + - .dev/docker/windows - .ci/azure-pipelines/env.yml schedules: @@ -32,7 +34,7 @@ variables: dockerHubID: "pointcloudlibrary" jobs: -- job: BuildAndPush +- job: BuildAndPushUbuntu timeoutInMinutes: 360 displayName: "Env" pool: @@ -40,41 +42,55 @@ jobs: strategy: matrix: Ubuntu 18.04: - CUDA_VERSION: 10.2 - UBUNTU_DISTRO: 18.04 - USE_CUDA: true + # Test the oldest supported version of Ubuntu + UBUNTU_VERSION: 18.04 VTK_VERSION: 6 - tag: 18.04 + ENSENSOSDK_VERSION: 2.3.1570 + TAG: 18.04 Ubuntu 20.04: - CUDA_VERSION: 11.1 - UBUNTU_DISTRO: 20.04 + UBUNTU_VERSION: 20.04 VTK_VERSION: 7 - USE_CUDA: true - tag: 20.04 - Ubuntu 20.10: - CUDA_VERSION: 11.1 - UBUNTU_DISTRO: 20.10 - VTK_VERSION: 7 - # nvidia-cuda docker image has not been released for 20.10 yet - USE_CUDA: "" - tag: 20.10 + TAG: 20.04 + Ubuntu 21.10: + UBUNTU_VERSION: 21.10 + USE_LATEST_CMAKE: true + VTK_VERSION: 9 + TAG: 21.10 + # Test the latest LTS version of Ubuntu + Ubuntu 22.04: + UBUNTU_VERSION: 22.04 + VTK_VERSION: 9 + TAG: 22.04 steps: + - script: | + dockerBuildArgs="" ; \ + if [ -n "$UBUNTU_VERSION" ]; then \ + dockerBuildArgs="$dockerBuildArgs --build-arg UBUNTU_VERSION=$UBUNTU_VERSION" ; \ + fi ; \ + if [ -n "$ENSENSOSDK_VERSION" ]; then \ + dockerBuildArgs="$dockerBuildArgs --build-arg ENSENSOSDK_VERSION=$ENSENSOSDK_VERSION" ; \ + fi ; \ + if [ -n "$VTK_VERSION" ]; then \ + dockerBuildArgs="$dockerBuildArgs --build-arg VTK_VERSION=$VTK_VERSION" ; \ + fi ; \ + if [ -n "$USE_LATEST_CMAKE" ]; then \ + dockerBuildArgs="$dockerBuildArgs --build-arg USE_LATEST_CMAKE=$USE_LATEST_CMAKE" ; \ + fi + echo "##vso[task.setvariable variable=dockerBuildArgs]$dockerBuildArgs" + displayName: "Prepare docker build arguments" - task: Docker@2 displayName: "Build docker image" inputs: command: build arguments: | --no-cache - --build-arg CUDA_VERSION=$(CUDA_VERSION) - --build-arg UBUNTU_DISTRO=$(UBUNTU_DISTRO) - --build-arg USE_CUDA=$(USE_CUDA) - --build-arg VTK_VERSION=$(VTK_VERSION) - -t $(dockerHubID)/env:$(tag) + $(dockerBuildArgs) + -t $(dockerHubID)/env:$(TAG) dockerfile: '$(Build.SourcesDirectory)/.dev/docker/env/Dockerfile' - tags: "$(tag)" + tags: "$(TAG)" - script: | set -x - docker run --rm -v "$(Build.SourcesDirectory)":/pcl $(dockerHubID)/env:$(tag) bash -c ' \ + docker run --rm -v "$(Build.SourcesDirectory)":/pcl $(dockerHubID)/env:$(TAG) bash -c ' \ mkdir /pcl/build && cd /pcl/build && \ cmake /pcl \ -DCMAKE_BUILD_TYPE="Release" \ @@ -89,6 +105,57 @@ jobs: command: push containerRegistry: $(dockerHub) repository: $(dockerHubID)/env - tags: "$(tag)" + tags: "$(TAG)" + condition: and(eq(variables['Build.Repository.Name'], 'PointCloudLibrary/pcl'), + eq(variables['Build.SourceBranch'], 'refs/heads/master')) +- job: BuildAndPushWindows + timeoutInMinutes: 360 + displayName: "Env" + pool: + vmImage: 'windows-2019' + strategy: + matrix: + Winx86: + PLATFORM: x86 + TAG: winx86 + GENERATOR: "'Visual Studio 16 2019' -A Win32" + VCPKGCOMMIT: b86c0c35b88e2bf3557ff49dc831689c2f085090 + Winx64: + PLATFORM: x64 + TAG: winx64 + GENERATOR: "'Visual Studio 16 2019' -A x64" + VCPKGCOMMIT: master + steps: + - task: Docker@2 + displayName: "Build docker image" + inputs: + command: build + arguments: | + --no-cache + --build-arg PLATFORM=$(PLATFORM) + --build-arg VCPKGCOMMIT=$(VCPKGCOMMIT) + -t $(dockerHubID)/env:$(TAG) + dockerfile: '$(Build.SourcesDirectory)/.dev/docker/windows/Dockerfile' + tags: "$(TAG)" + + - script: > + docker run --rm -v "$(Build.SourcesDirectory)":c:\pcl $(dockerHubID)/env:$(TAG) + powershell -command "mkdir c:\pcl\build; cd c:\pcl\build; + cmake c:\pcl -G$(GENERATOR) + -DVCPKG_TARGET_TRIPLET=$(PLATFORM)-windows-rel + -DCMAKE_BUILD_TYPE='Release' + -DCMAKE_TOOLCHAIN_FILE=c:\vcpkg\scripts\buildsystems\vcpkg.cmake + -DPCL_ONLY_CORE_POINT_TYPES=ON + -DBUILD_io:BOOL=OFF + -DBUILD_kdtree:BOOL=OFF; + cmake --build . " + displayName: 'Verify Dockerimage' + - task: Docker@2 + displayName: "Push docker image" + inputs: + command: push + containerRegistry: $(dockerHub) + repository: $(dockerHubID)/env + tags: "$(TAG)" condition: and(eq(variables['Build.Repository.Name'], 'PointCloudLibrary/pcl'), eq(variables['Build.SourceBranch'], 'refs/heads/master')) diff --git a/.ci/azure-pipelines/ubuntu-variety.yaml b/.ci/azure-pipelines/ubuntu-variety.yaml new file mode 100644 index 00000000000..09fdcbf5459 --- /dev/null +++ b/.ci/azure-pipelines/ubuntu-variety.yaml @@ -0,0 +1,49 @@ +trigger: + branches: + include: + - master + paths: + include: + - .dev/docker/ubuntu-variety + - .ci/azure-pipelines/ubuntu-variety.yaml + +pr: + paths: + include: + - .dev/docker/ubuntu-variety + - .ci/azure-pipelines/ubuntu-variety.yaml + +schedules: +- cron: "0 0 * * 6" + displayName: "Saturday midnight build" + branches: + include: + - master + +resources: +- repo: self + +jobs: +- job: BuildUbuntuVariety + timeoutInMinutes: 360 + displayName: "BuildUbuntuVariety" + steps: + - script: | + POSSIBLE_VTK_VERSION=("7" "9") \ + POSSIBLE_CMAKE_CXX_STANDARD=("14" "17" "20") \ + POSSIBLE_CMAKE_BUILD_TYPE=("None" "Debug" "Release" "RelWithDebInfo" "MinSizeRel") \ + POSSIBLE_COMPILER_PACKAGE=("g++" "g++-10" "g++-11" "g++-12" "clang" "clang-9" "clang-11" "clang-12" "clang-13" "clang-14") \ + POSSIBLE_CMAKE_C_COMPILER=("gcc" "gcc-10" "gcc-11" "gcc-12" "clang" "clang-9" "clang-11" "clang-12" "clang-13" "clang-14") \ + POSSIBLE_CMAKE_CXX_COMPILER=("g++" "g++-10" "g++-11" "g++-12" "clang++" "clang++-9" "clang++-11" "clang++-12" "clang++-13" "clang++-14") \ + CHOSEN_COMPILER=$[RANDOM%${#POSSIBLE_COMPILER_PACKAGE[@]}] \ + dockerBuildArgs="--build-arg VTK_VERSION=${POSSIBLE_VTK_VERSION[$[RANDOM%${#POSSIBLE_VTK_VERSION[@]}]]} --build-arg CMAKE_CXX_STANDARD=${POSSIBLE_CMAKE_CXX_STANDARD[$[RANDOM%${#POSSIBLE_CMAKE_CXX_STANDARD[@]}]]} --build-arg CMAKE_BUILD_TYPE=${POSSIBLE_CMAKE_BUILD_TYPE[$[RANDOM%${#POSSIBLE_CMAKE_BUILD_TYPE[@]}]]} --build-arg COMPILER_PACKAGE=${POSSIBLE_COMPILER_PACKAGE[$CHOSEN_COMPILER]} --build-arg CMAKE_C_COMPILER=${POSSIBLE_CMAKE_C_COMPILER[$CHOSEN_COMPILER]} --build-arg CMAKE_CXX_COMPILER=${POSSIBLE_CMAKE_CXX_COMPILER[$CHOSEN_COMPILER]}" ; \ + echo "##vso[task.setvariable variable=dockerBuildArgs]$dockerBuildArgs" + displayName: "Prepare docker build arguments" + - task: Docker@2 + displayName: "Build docker image" + inputs: + command: build + arguments: | + --no-cache + $(dockerBuildArgs) + dockerfile: '$(Build.SourcesDirectory)/.dev/docker/ubuntu-variety/Dockerfile' diff --git a/.ci/scripts/build_tutorials.sh b/.ci/scripts/build_tutorials.sh index 169128ec943..c26d02d974e 100755 --- a/.ci/scripts/build_tutorials.sh +++ b/.ci/scripts/build_tutorials.sh @@ -73,7 +73,7 @@ for DIRECTORY in "$SOURCE_DIR"/*/ ; do TUTORIAL_BUILD_DIR="$BUILD_DIR/$NAME" mkdir -p "$TUTORIAL_BUILD_DIR" && cd "$TUTORIAL_BUILD_DIR" || exit echo "Configuring tutorial: $NAME" - if ! cmake "$TUTORIAL_SOURCE_DIR" -DPCL_DIR="$INSTALL_DIR" -DCMAKE_CXX_FLAGS="-Werror"; then + if ! cmake "$TUTORIAL_SOURCE_DIR" -DPCL_DIR="$INSTALL_DIR" -DCMAKE_CXX_FLAGS="-Wall -Wextra -Wpedantic -Werror"; then STATUS="cmake error" else echo "Building tutorial: $NAME" diff --git a/.clang-format b/.clang-format index 3e0ebf2ffec..3578d7f1cad 100644 --- a/.clang-format +++ b/.clang-format @@ -62,7 +62,7 @@ IncludeCategories: - Regex: '^<(OpenGL|(GL(UT)?/))' Priority: 450 # Matches all std includes. Match them before any unknown include, so we can order them behind. - - Regex: '^<[a-z]+>$' + - Regex: '^<[a-z_]+>$' Priority: 900 # Any unknown include - Regex: '.*' diff --git a/.dev/docker/env/Dockerfile b/.dev/docker/env/Dockerfile index e2dcb662b65..eb8d414d2ef 100644 --- a/.dev/docker/env/Dockerfile +++ b/.dev/docker/env/Dockerfile @@ -1,33 +1,40 @@ -# For valid combinations, check the following repo: -# https://gitlab.com/nvidia/container-images/cuda/tree/master/dist -# To enable cuda, use "--build-arg USE_CUDA=true" during image build process -ARG USE_CUDA -ARG CUDA_VERSION="9.2" -ARG UBUNTU_DISTRO="16.04" -ARG BASE_CUDA_IMAGE=${USE_CUDA:+"nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_DISTRO}"} -ARG BASE_IMAGE=${BASE_CUDA_IMAGE:-"ubuntu:${UBUNTU_DISTRO}"} +ARG UBUNTU_VERSION=20.04 -FROM ${BASE_IMAGE} +FROM "ubuntu:${UBUNTU_VERSION}" +# Eigen patch (https://eigen.tuxfamily.org/bz/show_bug.cgi?id=1462) to fix issue metioned +# in https://github.com/PointCloudLibrary/pcl/issues/3729 is available in Eigen 3.3.7. +# Not needed from 20.04 since it is the default version from apt +ARG EIGEN_MINIMUM_VERSION=3.3.7 + +# See https://www.optonic.com/support/download/ensenso-sdk/archiv/ for available versions +ARG ENSENSOSDK_VERSION=3.2.489 + +# See https://github.com/IntelRealSense/librealsense/tags for available tags of releases +ARG REALSENSE_VERSION=2.50.0 + +# Check https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=libvtk%20qt-dev +# for available packes for choosen UBUNTU_VERSION ARG VTK_VERSION=6 + +# Use the latest version of CMake by adding the Kitware repository if true, +# otherwise use the default version of CMake of the system. +ARG USE_LATEST_CMAKE=false + ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update \ - && apt-get install -y \ - xvfb \ - cmake \ - g++ \ + && apt-get -V install -y \ + build-essential \ clang \ - wget \ + clang-tidy \ + libblas-dev \ libboost-date-time-dev \ libboost-filesystem-dev \ libboost-iostreams-dev \ - libeigen3-dev \ - libblas-dev \ libflann-dev \ libglew-dev \ libgtest-dev \ - libbenchmark-dev \ libopenni-dev \ libopenni2-dev \ libproj-dev \ @@ -36,44 +43,64 @@ RUN apt-get update \ libusb-1.0-0-dev \ libvtk${VTK_VERSION}-dev \ libvtk${VTK_VERSION}-qt-dev \ + lsb-release \ qtbase5-dev \ software-properties-common \ + wget \ + xvfb \ + && if [ "$USE_LATEST_CMAKE" = true ] ; then \ + cmake_ubuntu_version=$(lsb_release -cs) ; \ + if ! wget -q --method=HEAD "https://apt.kitware.com/ubuntu/dists/$cmake_ubuntu_version/Release"; then \ + cmake_ubuntu_version="focal" ; \ + fi ; \ + wget -qO - https://apt.kitware.com/kitware-archive.sh | bash -s -- --release $cmake_ubuntu_version ; \ + apt-get update ; \ + fi \ + && apt-get -V install -y cmake \ + && if [ "$(lsb_release -sr)" = "18.04" ]; then \ + apt-get -V install -y nvidia-cuda-toolkit g++-6 ; \ + else \ + apt-get -V install -y nvidia-cuda-toolkit-gcc ; \ + fi \ + && if [ "$(lsb_release -sr)" = "21.10" ]; then \ + wget -qO- https://github.com/google/benchmark/archive/refs/tags/v1.6.1.tar.gz | tar xz \ + && cd benchmark-1.6.1 \ + && mkdir build \ + && cd build \ + && cmake .. -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_GTEST_TESTS=OFF -DBENCHMARK_ENABLE_TESTING=OFF \ + && make -j$(nproc) install \ + && cd ../.. \ + && rm -rf benchmark-1.6.1 ; \ + else \ + apt-get -V install -y libbenchmark-dev ; \ + fi \ && rm -rf /var/lib/apt/lists/* -# Eigen patch (https://eigen.tuxfamily.org/bz/show_bug.cgi?id=1462) to fix issue metioned -# in https://github.com/PointCloudLibrary/pcl/issues/3729 is available in Eigen 3.3.7 -# Not needed from 20.04 since it is the default version from apt -RUN if [ `pkg-config --modversion eigen3 | cut -d. -f3` -lt 7 ]; then \ - wget -qO- https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz | tar xz \ - && apt install -y libblas-dev \ - && cd eigen-3.3.7 \ - && mkdir build \ - && cd build \ - && cmake .. \ - && make install \ - && cd ../.. \ - && rm -rf eigen-3.3.7/ \ - && rm -f eigen-3.3.7.tar.gz ; \ - fi - -# To avoid CUDA build errors on CUDA 9.2+ GCC 7 is required -RUN if [ `gcc -dumpversion | cut -d. -f1` -lt 7 ]; then add-apt-repository ppa:ubuntu-toolchain-r/test \ - && apt update \ - && apt install g++-7 -y \ - && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7 \ - && update-alternatives --config gcc ; \ +# Use libeigen3-dev if it meets the minimal version. +# In most cases libeigen3-dev is already installed as a dependency of libvtk6-dev & libvtk7-dev, but not in every case (libvtk9 doesn't seem to have this dependency), +# so install it from apt if the version is sufficient. +RUN if dpkg --compare-versions $(apt-cache show --no-all-versions libeigen3-dev | grep -P -o 'Version:\s*\K.*') ge ${EIGEN_MINIMUM_VERSION}; then \ + apt-get -V install -y libeigen3-dev ; \ + else \ + wget -qO- https://gitlab.com/libeigen/eigen/-/archive/${EIGEN_MINIMUM_VERSION}/eigen-${EIGEN_MINIMUM_VERSION}.tar.gz | tar xz \ + && cd eigen-${EIGEN_MINIMUM_VERSION} \ + && mkdir build \ + && cd build \ + && cmake .. \ + && make -j$(nproc) install \ + && cd ../.. \ + && rm -rf eigen-${EIGEN_MINIMUM_VERSION}/ ; \ fi -RUN wget -qO- https://github.com/IntelRealSense/librealsense/archive/v2.23.0.tar.gz | tar xz \ - && cd librealsense-2.23.0 \ +RUN wget -qO- https://github.com/IntelRealSense/librealsense/archive/v${REALSENSE_VERSION}.tar.gz | tar xz \ + && cd librealsense-${REALSENSE_VERSION} \ && mkdir build \ && cd build \ && cmake .. -DBUILD_EXAMPLES=OFF -DBUILD_GRAPHICAL_EXAMPLES=OFF \ - && make -j2 \ - && make install \ + && make -j$(nproc) install \ && cd ../.. \ - && rm -rf librealsense-2.23.0 + && rm -rf librealsense-${REALSENSE_VERSION} -RUN wget -qO ensenso.deb https://download.ensenso.com/s/ensensosdk/download?files=ensenso-sdk-2.2.160-x64.deb \ +RUN wget -qO ensenso.deb https://download.ensenso.com/s/ensensosdk/download?files=ensenso-sdk-${ENSENSOSDK_VERSION}-x64.deb \ && dpkg -i ensenso.deb \ && rm ensenso.deb diff --git a/.dev/docker/perception_pcl_ros/Dockerfile b/.dev/docker/perception_pcl_ros/Dockerfile index 670bdc47459..6d189fcbb21 100644 --- a/.dev/docker/perception_pcl_ros/Dockerfile +++ b/.dev/docker/perception_pcl_ros/Dockerfile @@ -35,6 +35,6 @@ COPY package.xml ${workspace}/src/pcl/ RUN cd ${workspace} \ && . "/opt/ros/${flavor}/setup.sh" \ && catkin config --install --link-devel \ - && catkin build -j2 libpcl-all-dev --cmake-args -DWITH_OPENGL:BOOL=OFF \ + && catkin build --no-status --verbose --summary -j2 libpcl-all-dev --cmake-args -DWITH_OPENGL:BOOL=OFF \ && rm -fr build/libpcl-all-dev \ - && catkin build --start-with pcl_msgs + && catkin build --no-status --verbose --summary --start-with pcl_msgs diff --git a/.dev/docker/ubuntu-variety/Dockerfile b/.dev/docker/ubuntu-variety/Dockerfile new file mode 100644 index 00000000000..6eb149f903a --- /dev/null +++ b/.dev/docker/ubuntu-variety/Dockerfile @@ -0,0 +1,29 @@ +# TODO maybe also rolling and latest? +FROM "ubuntu:devel" + +# TODO PCL_INDEX_SIZE and PCL_INDEX_SIGNED +# TODO test more versions of cmake, boost, vtk, eigen, qt, maybe flann, maybe other compilers? +ARG VTK_VERSION +ARG CMAKE_CXX_STANDARD +ARG CMAKE_BUILD_TYPE +ARG COMPILER_PACKAGE +ARG CMAKE_C_COMPILER +ARG CMAKE_CXX_COMPILER +RUN echo VTK_VERSION=${VTK_VERSION} CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} COMPILER_PACKAGE=${COMPILER_PACKAGE} CMAKE_C_COMPILER=${CMAKE_C_COMPILER} CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt update +RUN apt install -y git cmake ${COMPILER_PACKAGE} +RUN apt install -y libeigen3-dev libflann-dev +RUN apt install -y libboost-filesystem-dev libboost-date-time-dev libboost-iostreams-dev +RUN apt install -y libgtest-dev libbenchmark-dev +RUN apt install -y qtbase5-dev libvtk${VTK_VERSION}-dev libvtk${VTK_VERSION}-qt-dev + +RUN cd \ + && git clone --depth=1 https://github.com/PointCloudLibrary/pcl \ + && mkdir pcl/build \ + && cd pcl/build \ + && cmake .. -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DBUILD_simulation=ON -DBUILD_surface_on_nurbs=ON -DBUILD_global_tests=ON -DBUILD_benchmarks=ON -DBUILD_examples=ON -DBUILD_tools=ON -DBUILD_apps=ON -DBUILD_apps_3d_rec_framework=ON -DBUILD_apps_cloud_composer=ON -DBUILD_apps_in_hand_scanner=ON -DBUILD_apps_modeler=ON -DBUILD_apps_point_cloud_editor=ON \ + && cmake --build . -- -j2 -k \ + && cmake --build . -- tests +# TODO maybe also build tutorials? diff --git a/.dev/docker/windows/Dockerfile b/.dev/docker/windows/Dockerfile new file mode 100644 index 00000000000..610587b0283 --- /dev/null +++ b/.dev/docker/windows/Dockerfile @@ -0,0 +1,49 @@ +# escape=` + +FROM mcr.microsoft.com/windows/servercore:ltsc2019 + +# Use "--build-arg platform=x64" for 64 bit or x86 for 32 bit. +ARG PLATFORM + +# Use to set specific commit to checkout +ARG VCPKGCOMMIT + +# Download channel for fixed install. +ARG CHANNEL_BASE_URL=https://aka.ms/vs/16/release + +ADD $CHANNEL_BASE_URL/channel C:\TEMP\VisualStudio.chman + +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] + +# Download and install Build Tools for Visual Studio 2019 for native desktop +RUN wget $Env:CHANNEL_BASE_URL/vs_buildtools.exe -OutFile 'C:\TEMP\vs_buildtools.exe'; ` + Start-Process -FilePath C:\TEMP\vs_buildtools.exe -ArgumentList ` + "--quiet", ` + "--norestart", ` + "--nocache", ` + "--installPath", ` + "C:\BuildTools", ` + "--wait", ` + "--channelUri", ` + "C:\TEMP\VisualStudio.chman", ` + "--installChannelUri", ` + "C:\TEMP\VisualStudio.chman", ` + "--add", ` + "Microsoft.VisualStudio.Workload.VCTools", ` + "--includeRecommended" ` + -Wait -PassThru; ` + del c:\temp\vs_buildtools.exe; + +# VCPKG requires update if Cmake version is > 3.20.5 see: https://github.com/microsoft/vcpkg-tool/pull/107 +RUN iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')); ` + choco install cmake --version=3.20.5 --installargs 'ADD_CMAKE_TO_PATH=System' -y --no-progress; ` + choco install git -y --no-progress + +RUN git clone https://github.com/microsoft/vcpkg.git; cd vcpkg; git checkout $Env:VCPKGCOMMIT; + +# To explicit set VCPKG to only build Release version of the libraries. +COPY $PLATFORM'-windows-rel.cmake' 'c:\vcpkg\triplets\'$PLATFORM'-windows-rel.cmake' + +RUN cd .\vcpkg; ` + .\bootstrap-vcpkg.bat; ` + .\vcpkg install boost flann eigen3 qhull vtk[qt,opengl] gtest benchmark --triplet $Env:PLATFORM-windows-rel --clean-after-build; diff --git a/.dev/docker/windows/x64-windows-rel.cmake b/.dev/docker/windows/x64-windows-rel.cmake new file mode 100644 index 00000000000..f6c40253a08 --- /dev/null +++ b/.dev/docker/windows/x64-windows-rel.cmake @@ -0,0 +1,4 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) +set(VCPKG_BUILD_TYPE release) diff --git a/.dev/docker/windows/x86-windows-rel.cmake b/.dev/docker/windows/x86-windows-rel.cmake new file mode 100644 index 00000000000..0a277bdb77b --- /dev/null +++ b/.dev/docker/windows/x86-windows-rel.cmake @@ -0,0 +1,4 @@ +set(VCPKG_TARGET_ARCHITECTURE x86) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) +set(VCPKG_BUILD_TYPE release) diff --git a/.dev/format.sh b/.dev/format.sh index 0fba50bb1e4..e9bf4f3359e 100755 --- a/.dev/format.sh +++ b/.dev/format.sh @@ -8,7 +8,7 @@ format() { # don't use a directory with whitespace - local whitelist="apps/3d_rec_framework apps/modeler 2d geometry ml octree simulation stereo tracking registration" + local whitelist="apps/3d_rec_framework apps/in_hand_scanner apps/include apps/modeler apps/src benchmarks 2d geometry ml octree simulation stereo tracking registration gpu/containers gpu/segmentation" local PCL_DIR="${2}" local formatter="${1}" diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..c1f7a5669a8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# EditorConfig file, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +tab_width = 2 +trim_trailing_whitespace = true + +# Visual C++ Code Style settings +cpp_generate_documentation_comments = doxygen_slash_star diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..30ac450562c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Reolace with a single Ko Fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: PointCloudLibrary +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 8bad30c50ae..d14e85b779f 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -26,7 +26,7 @@ What happens instead of the expected behavior? **To Reproduce** -Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. A reproducible example helps to provide faster answers. +Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. A reproducible example helps to provide faster answers. If you load data e.g. from a PCD or PLY file, please provide the file. **Screenshots/Code snippets** diff --git a/.github/ISSUE_TEMPLATE/compilation-failure.md b/.github/ISSUE_TEMPLATE/compilation-failure.md index 17d0046683c..77771e2865b 100644 --- a/.github/ISSUE_TEMPLATE/compilation-failure.md +++ b/.github/ISSUE_TEMPLATE/compilation-failure.md @@ -36,7 +36,7 @@ In order to help explain your problem, please consider adding - OS: [e.g. Ubuntu 16.04] - Compiler: [:eg GCC 8.1] - PCL Version [e.g. 1.10, HEAD] (NB: please ensure you don't have multiple versions available) - - PCL Type: [Installed/Compiled from source] + - PCL Type: [e.g. Installed with VCPKG/Installed with apt/Compiled from source] If PCL was compiled from source or failure in compiling PCL itself: - GPU, Kinfu, CUDA enabled? Yes/No diff --git a/CHANGES.md b/CHANGES.md index 533d35f46fe..375412caf8d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,328 @@ # ChangeList +## = 1.12.1 (2021.12.21) = + +This minor release brings in a lot of enhancements in CMake thanks to @larshg and @SunBlack. +Enjoy a lot of bug-fixes and improvements in IO and Filters. + +### Notable changes + +**New features** *added to PCL* + +* **[io]** Add a grabber for SICK 2D LiDAR: TiM [[#4429](https://github.com/PointCloudLibrary/pcl/pull/4429)] + +**Deprecation** *of public APIs, scheduled to be removed after two minor releases* + +* **[cuda][filters]** Add deprecation for filter getters with bool reference [[#4861](https://github.com/PointCloudLibrary/pcl/pull/4861)] +* **[filters]** Fix keep_organized behavior in CropHull filter [[#4855](https://github.com/PointCloudLibrary/pcl/pull/4855)] + +**Behavior changes** *in classes, apps, or tools* + +* **[registration]** Fix typo in the hessian representation of NDT [[#4889](https://github.com/PointCloudLibrary/pcl/pull/4889)] +* **[cmake]** Update PCLConfig.cmake.in to 3.10 for default policy. [[#4996](https://github.com/PointCloudLibrary/pcl/pull/4996)] + +**ABI changes** *that are still API compatible* + +* **[ml]** Wrap QMatrix in namespace pcl to resolve linker conflict with Qt6 [[#4858](https://github.com/PointCloudLibrary/pcl/pull/4858)] + +### Changes grouped by module + +#### CMake: + +* Add AVX for Linux & macos [[#4698](https://github.com/PointCloudLibrary/pcl/pull/4698)] +* Update cmake to 3.10 and add CUDA language support [[#4619](https://github.com/PointCloudLibrary/pcl/pull/4619)] +* Fix CUDA Compute Capability version detection [[#4900](https://github.com/PointCloudLibrary/pcl/pull/4900)] +* Update pcl_find_boost to allow compilation with Boost 1.77 and 1.78 [[#4972](https://github.com/PointCloudLibrary/pcl/pull/4972)] [[#5067](https://github.com/PointCloudLibrary/pcl/pull/5067)] +* Allow boost to be found by config files. [[#4952](https://github.com/PointCloudLibrary/pcl/pull/4952)] +* **[behavior change]** Update PCLConfig.cmake.in to 3.10 for default policy. [[#4996](https://github.com/PointCloudLibrary/pcl/pull/4996)] +* Allow PCL to have non-static dependencies for static builds and vice-versa [[#4390](https://github.com/PointCloudLibrary/pcl/pull/4390)] +* Enhance finding of qhull [[#4923](https://github.com/PointCloudLibrary/pcl/pull/4923)] + +#### libpcl_common: + +* Fix: max_id size should be equal to histogram.size() - 1 [[#4934](https://github.com/PointCloudLibrary/pcl/pull/4934)] +* Remove casts, use more auto and uindex_t in conversions.h [[#4935](https://github.com/PointCloudLibrary/pcl/pull/4935)] +* Fix inaccurate covariance matrix computation [[#4983](https://github.com/PointCloudLibrary/pcl/pull/4983)] + +#### libpcl_cuda: + +* **[deprecation]** Add deprecation for filter getters with bool reference [[#4861](https://github.com/PointCloudLibrary/pcl/pull/4861)] + +#### libpcl_features: + +* Add `isNormalFinite` check in `ShapeContext3DEstimation` [[#4883](https://github.com/PointCloudLibrary/pcl/pull/4883)] + +#### libpcl_filters: + +* Clear the output indices in function `CropHull::applyFilters` [[#4851](https://github.com/PointCloudLibrary/pcl/pull/4851)] +* Fix unresolved linking to Convolution [[#4845](https://github.com/PointCloudLibrary/pcl/pull/4845)] +* **[deprecation]** Add deprecation for filter getters with bool reference [[#4861](https://github.com/PointCloudLibrary/pcl/pull/4861)] +* NormalSpaceSampling filter: add constructor to specify `extract_removed_indices` [[#4846](https://github.com/PointCloudLibrary/pcl/pull/4846)] +* **[deprecation]** Fix keep_organized behavior in CropHull filter [[#4855](https://github.com/PointCloudLibrary/pcl/pull/4855)] +* Added reserve function before storing points in PointCloud in VoxelGr… [[#4938](https://github.com/PointCloudLibrary/pcl/pull/4938)] + +#### libpcl_io: + +* Higher flexibility regarding which PLY files can be read [[#4963](https://github.com/PointCloudLibrary/pcl/pull/4963)] +* **[new feature]** Add a grabber for SICK 2D LiDAR: TiM [[#4429](https://github.com/PointCloudLibrary/pcl/pull/4429)] + +#### libpcl_keypoints: + +* Bugfix: Number of OpenMP threads was not validated, ... [[#4863](https://github.com/PointCloudLibrary/pcl/pull/4863)] + +#### libpcl_ml: + +* **[ABI break]** Wrap QMatrix in namespace pcl to resolve linker conflict with Qt6 [[#4858](https://github.com/PointCloudLibrary/pcl/pull/4858)] + +#### libpcl_registration: + +* **[behavior change]** Fix typo in the hessian representation of NDT [[#4889](https://github.com/PointCloudLibrary/pcl/pull/4889)] +* Fix discretization bug in PPFRegistration [[#4975](https://github.com/PointCloudLibrary/pcl/pull/4975)] + +#### libpcl_sample_consensus: + +* Fix SampleConsensusModelCylinder.projectPoints and verify with test [[#4881](https://github.com/PointCloudLibrary/pcl/pull/4881)] + +#### libpcl_search: + +* Add missing include of hpp file in flann_search.h [[#4848](https://github.com/PointCloudLibrary/pcl/pull/4848)] + +#### libpcl_surface: + +* Improve logging in `multi_grid_octree_data.hpp` [[#4844](https://github.com/PointCloudLibrary/pcl/pull/4844)] +* Fix duplicate definition error in mls [[#5049](https://github.com/PointCloudLibrary/pcl/pull/5049)] + +#### libpcl_visualization: + +* Use pixel ratio to scale mouse events on HiDpi monitors [[#4411](https://github.com/PointCloudLibrary/pcl/pull/4411)] +* Remove declaration of updateCamera [[#4921](https://github.com/PointCloudLibrary/pcl/pull/4921)] + +#### PCL Docs: + +* Require sphinx>=3 to fix errors on readthedocs [[#5037](https://github.com/PointCloudLibrary/pcl/pull/5037)] + +## = 1.12.0 (2021.07.07) = + +PCL 1.12.0 enables custom index size and type, from `int16_t` to `uint64_t`, allowing +users to have as small or large clouds as they wish. 1.12 also comes with improved +support for VTK and CUDA, along with making existing functionality more user friendly. + +This is all on top of the usual bug-fixes and performance improvements across the board + +### Notable changes + +**New features** *added to PCL* + +* **[sample_consensus]** Add SIMD implementations to some countWithinDistance functions [[#3519](https://github.com/PointCloudLibrary/pcl/pull/3519)] +* **[io]** Enable Real Sense 2 grabber for all platforms [[#4471](https://github.com/PointCloudLibrary/pcl/pull/4471)] +* **[visualization]** add ellipsoid shape to pcl_visualizer [[#4531](https://github.com/PointCloudLibrary/pcl/pull/4531)] +* **[common]** Add `constexpr` to static member functions for point types, add macro for `if constexpr` [[#4735](https://github.com/PointCloudLibrary/pcl/pull/4735)] +* **[ci]** Use windows docker image in CI. [[#4426](https://github.com/PointCloudLibrary/pcl/pull/4426)] +* **[common]** Add pcl log stream macros [[#4595](https://github.com/PointCloudLibrary/pcl/pull/4595)] + +**Deprecation** *of public APIs, scheduled to be removed after two minor releases* + +* **[common]** Modify index type for vertices [[#4256](https://github.com/PointCloudLibrary/pcl/pull/4256)] +* **[gpu]** Add square distances to GPU knnSearch API [[#4322](https://github.com/PointCloudLibrary/pcl/pull/4322)] +* **[gpu]** Add square distances to ApproxNearestSearch [[#4340](https://github.com/PointCloudLibrary/pcl/pull/4340)] +* Deprecate unused ease-of-internal-use headers [[#4367](https://github.com/PointCloudLibrary/pcl/pull/4367)] +* **[registration]** Deprecate `TransformationEstimationDQ` in favor of `TransformationEstimationDualQuaternion` [[#4425](https://github.com/PointCloudLibrary/pcl/pull/4425)] +* **[segmentation]** Deprecate unused `max_label` in `extractLabeledEuclideanClusters` [[#4105](https://github.com/PointCloudLibrary/pcl/pull/4105)] +* **[surface]** MLS: correct typo in `principle` by using `principal` instead [[#4505](https://github.com/PointCloudLibrary/pcl/pull/4505)] +* Deprecate unneeded meta-headers [[#4628](https://github.com/PointCloudLibrary/pcl/pull/4628)] +* **[apps][tracking]** pyramidal klt: switch keypoints_status_ to int vector [[#4681](https://github.com/PointCloudLibrary/pcl/pull/4681)] +* Properly remove remaining items deprecated for version 1.12, deprecate `uniform_sampling.h` [[#4688](https://github.com/PointCloudLibrary/pcl/pull/4688)] +* **[recognition]** Add deprecation for incorrectly installed headers [[#4650](https://github.com/PointCloudLibrary/pcl/pull/4650)] + +**Removal** *of the public APIs deprecated in previous releases* + +* Remove deprecated items as scheduled in preparation of v1.12 (except `concatenatePointCloud`) [[#4341](https://github.com/PointCloudLibrary/pcl/pull/4341)] +* **[apps]** Remove unused code in persistence_utils.h [[#4500](https://github.com/PointCloudLibrary/pcl/pull/4500)] +* Properly remove remaining items deprecated for version 1.12, deprecate `uniform_sampling.h` [[#4688](https://github.com/PointCloudLibrary/pcl/pull/4688)] + +**Behavior changes** *in classes, apps, or tools* + +* **[registration]** Don't move, or copy ICP [[#4167](https://github.com/PointCloudLibrary/pcl/pull/4167)] +* **[common]** Fix PointXYZRGBA ctor, set A as 255 by default [[#4799](https://github.com/PointCloudLibrary/pcl/pull/4799)] + +**API changes** *that did not go through the proper deprecation and removal cycle* + +* **[common]** modify index type for PCLImage [[#4257](https://github.com/PointCloudLibrary/pcl/pull/4257)] +* **[registration]** Don't move, or copy ICP [[#4167](https://github.com/PointCloudLibrary/pcl/pull/4167)] +* **[kdtree]** KdTree: handle 0 or negative k for nearestKSearch [[#4430](https://github.com/PointCloudLibrary/pcl/pull/4430)] +* **[common]** Use `std::array` instead of C-array for ColorLUT [[#4489](https://github.com/PointCloudLibrary/pcl/pull/4489)] +* **[tracking]** Use SFINAE instead of relying on macro `PCL_TRACKING_NORMAL_SUPPORTED` [[#4643](https://github.com/PointCloudLibrary/pcl/pull/4643)] +* **[gpu]** Export and template extract clusters [[#4196](https://github.com/PointCloudLibrary/pcl/pull/4196)] +* **[common]** Added `namespace pcl` to free functions: `aligned_{malloc/free}` [[#4742](https://github.com/PointCloudLibrary/pcl/pull/4742)] + +**ABI changes** *that are still API compatible* + +* **[registration]** Refactoring and Bugfix of NDT [[#4180](https://github.com/PointCloudLibrary/pcl/pull/4180)] +* **[common]** modify index types for PCLPointCloud2 [[#4199](https://github.com/PointCloudLibrary/pcl/pull/4199)] +* **[common]** Modify index type for vertices [[#4256](https://github.com/PointCloudLibrary/pcl/pull/4256)] +* **[common]** Modify index type for PCLPointField [[#4228](https://github.com/PointCloudLibrary/pcl/pull/4228)] +* **[surface]** Enabled multithreading in Poisson surface reconstruction [[#4332](https://github.com/PointCloudLibrary/pcl/pull/4332)] +* **[io]** Allow file_io to read large point clouds depending on PCL config [[#4331](https://github.com/PointCloudLibrary/pcl/pull/4331)] +* **[sample_consensus]** Allow user to apply arbitrary constraint on models in sample consensus [[#4260](https://github.com/PointCloudLibrary/pcl/pull/4260)] +* **[tracking]** Use SFINAE instead of relying on macro `PCL_TRACKING_NORMAL_SUPPORTED` [[#4643](https://github.com/PointCloudLibrary/pcl/pull/4643)] +* **[features]** Move the init of static variables to library load time [[#4640](https://github.com/PointCloudLibrary/pcl/pull/4640)] +* **[octree]** Octree2BufBase: Fix bug that contents from previous buffer appear in current buffer [[#4642](https://github.com/PointCloudLibrary/pcl/pull/4642)] + +### Changes grouped by module + +#### CMake: + +* Update `pcl_find_boost` to allow compilation with Boost 1.74 [[#4330](https://github.com/PointCloudLibrary/pcl/pull/4330)] +* Variable needs to be expanded when checking for `EXT_DEPS` [[#4353](https://github.com/PointCloudLibrary/pcl/pull/4353)] +* Update pcl_find_cuda.cmake to contain all supported architectures [[#4400](https://github.com/PointCloudLibrary/pcl/pull/4400)] +* Add support for VTK 9 [[#4262](https://github.com/PointCloudLibrary/pcl/pull/4262)] +* Refactor cmake find script of libusb [[#4483](https://github.com/PointCloudLibrary/pcl/pull/4483)] +* Add AVX for windows [[#4598](https://github.com/PointCloudLibrary/pcl/pull/4598)] +* Add SSE definitions for SSE 4.1 and 4.2 [[#4596](https://github.com/PointCloudLibrary/pcl/pull/4596)] + +#### libpcl_common: + +* **[ABI break]** modify index types for PCLPointCloud2 [[#4199](https://github.com/PointCloudLibrary/pcl/pull/4199)] +* **[API break]** modify index type for PCLImage [[#4257](https://github.com/PointCloudLibrary/pcl/pull/4257)] +* **[ABI break][deprecation]** Modify index type for vertices [[#4256](https://github.com/PointCloudLibrary/pcl/pull/4256)] +* **[ABI break]** Modify index type for PCLPointField [[#4228](https://github.com/PointCloudLibrary/pcl/pull/4228)] +* Allow PCL_DEPRECATED to detect and help remove deprecations before release [[#4336](https://github.com/PointCloudLibrary/pcl/pull/4336)] +* Allow conversion of PointCloud with more than 32-bit size rows/columns [[#4343](https://github.com/PointCloudLibrary/pcl/pull/4343)] +* Improve routing for `transformPointCloud` [[#4398](https://github.com/PointCloudLibrary/pcl/pull/4398)] +* Correct typo in `transformPlane` [[#4396](https://github.com/PointCloudLibrary/pcl/pull/4396)] +* **[API break]** Use `std::array` instead of C-array for ColorLUT [[#4489](https://github.com/PointCloudLibrary/pcl/pull/4489)] +* Set header in two toPCLPointCloud2 functions [[#4538](https://github.com/PointCloudLibrary/pcl/pull/4538)] +* Add more operators to `PointCloud` to prevent perf regression in refactoring [[#4397](https://github.com/PointCloudLibrary/pcl/pull/4397)] +* Make sure that organized point clouds are still organized after transformPointCloud [[#4488](https://github.com/PointCloudLibrary/pcl/pull/4488)] +* **[API break]** Added `namespace pcl` to free functions: `aligned_{malloc/free}` [[#4742](https://github.com/PointCloudLibrary/pcl/pull/4742)] +* **[new feature]** Add `constexpr` to static member functions for point types, add macro for `if constexpr` [[#4735](https://github.com/PointCloudLibrary/pcl/pull/4735)] +* Fix `PolygonMesh::concatenate` and its unit test [[#4745](https://github.com/PointCloudLibrary/pcl/pull/4745)] +* **[behavior change]** Fix PointXYZRGBA ctor, set A as 255 by default [[#4799](https://github.com/PointCloudLibrary/pcl/pull/4799)] +* Remove pseudo-template-instantiations in eigen.h to reduce compilation time [[#4788](https://github.com/PointCloudLibrary/pcl/pull/4788)] +* **[new feature]** Add pcl log stream macros [[#4595](https://github.com/PointCloudLibrary/pcl/pull/4595)] + +#### libpcl_features: + +* **[ABI break]** Move the init of static variables to library load time [[#4640](https://github.com/PointCloudLibrary/pcl/pull/4640)] +* Use correct cloud for checking finite-ness in fpfh [[#4720](https://github.com/PointCloudLibrary/pcl/pull/4720)] + +#### libpcl_filters: + +* Improve performance of median filter by using `nth_element` [[#4360](https://github.com/PointCloudLibrary/pcl/pull/4360)] +* Fix the covariance calculation as suggested by @zxd123 [[#4466](https://github.com/PointCloudLibrary/pcl/pull/4466)] +* Filters: fix wrong initialization of covariance in VoxelGridCovariance [[#4556](https://github.com/PointCloudLibrary/pcl/pull/4556)] +* Fix application of setMinimumPointsNumberPerVoxel for PCLPointCloud2 implementation of VoxelGrid [[#4389](https://github.com/PointCloudLibrary/pcl/pull/4389)] +* Adding tests for CropHull and using hull_cloud instead of input in getHullCloudRange [[#3976](https://github.com/PointCloudLibrary/pcl/pull/3976)] + +#### libpcl_gpu: + +* **[deprecation]** Add square distances to GPU knnSearch API [[#4322](https://github.com/PointCloudLibrary/pcl/pull/4322)] +* **[deprecation]** Add square distances to ApproxNearestSearch [[#4340](https://github.com/PointCloudLibrary/pcl/pull/4340)] +* **[API break]** Export and template extract clusters [[#4196](https://github.com/PointCloudLibrary/pcl/pull/4196)] +* Update support for CUDA arch in CMake and `convertSMVer2Cores` [[#4748](https://github.com/PointCloudLibrary/pcl/pull/4748)] +* Add ability to download contiguous chunk of memory to host using `Device{Array,Memory}` [[#4741](https://github.com/PointCloudLibrary/pcl/pull/4741)] +* Speeding up GPU clustering using smarter download strategy and memory allocations [[#4677](https://github.com/PointCloudLibrary/pcl/pull/4677)] + +#### libpcl_io: + +* **[ABI break]** Allow file_io to read large point clouds depending on PCL config [[#4331](https://github.com/PointCloudLibrary/pcl/pull/4331)] +* Improve PCD read performance (more than 50%) by reusing `istringstream` [[#4339](https://github.com/PointCloudLibrary/pcl/pull/4339)] +* **[new feature]** Enable Real Sense 2 grabber for all platforms [[#4471](https://github.com/PointCloudLibrary/pcl/pull/4471)] +* Throw error if the device bluffs about its capability [[#4141](https://github.com/PointCloudLibrary/pcl/pull/4141)] +* Fix crash in Dinast Grabber due to bad initialization of device handle [[#4484](https://github.com/PointCloudLibrary/pcl/pull/4484)] +* PLY face definition accepts uint fields as well [[#4492](https://github.com/PointCloudLibrary/pcl/pull/4492)] +* Prevent segfault in vtk2mesh [[#4581](https://github.com/PointCloudLibrary/pcl/pull/4581)] +* Prevent exception in PCDReader for misformed PCD files [[#4566](https://github.com/PointCloudLibrary/pcl/pull/4566)] +* Enable arbitary size Indices for Octree module [[#4350](https://github.com/PointCloudLibrary/pcl/pull/4350)] +* Fix addition of Carriage Return to PCD files. [[#4727](https://github.com/PointCloudLibrary/pcl/pull/4727)] +* Support Ensenso SDK 3.0 for ensenso_grabber [[#4751](https://github.com/PointCloudLibrary/pcl/pull/4751)] +* Specify no face elements in PLY files (from point cloud) to make them interoperable with VTK [[#4774](https://github.com/PointCloudLibrary/pcl/pull/4774)] + +#### libpcl_kdtree: + +* **[API break]** KdTree: handle 0 or negative k for nearestKSearch [[#4430](https://github.com/PointCloudLibrary/pcl/pull/4430)] + +#### libpcl_ml: + +* Fix un-initialized centroids bug (k-means) [[#4570](https://github.com/PointCloudLibrary/pcl/pull/4570)] + +#### libpcl_octree: + +* Enable arbitary size Indices for Octree module [[#4350](https://github.com/PointCloudLibrary/pcl/pull/4350)] +* Fix problems in octree search functions when using dynamic depth [[#4657](https://github.com/PointCloudLibrary/pcl/pull/4657)] +* **[ABI break]** Octree2BufBase: Fix bug that contents from previous buffer appear in current buffer [[#4642](https://github.com/PointCloudLibrary/pcl/pull/4642)] + +#### libpcl_outofcore: + +* Fix compile issue due to missing include under MSVC 2019 [[#4755](https://github.com/PointCloudLibrary/pcl/pull/4755)] + +#### libpcl_recognition: + +* **[deprecation]** Add deprecation for incorrectly installed headers [[#4650](https://github.com/PointCloudLibrary/pcl/pull/4650)] + +#### libpcl_registration: + +* **[ABI break]** Refactoring and Bugfix of NDT [[#4180](https://github.com/PointCloudLibrary/pcl/pull/4180)] +* **[API break][behavior change]** Don't move, or copy ICP [[#4167](https://github.com/PointCloudLibrary/pcl/pull/4167)] +* **[deprecation]** Deprecate `TransformationEstimationDQ` in favor of `TransformationEstimationDualQuaternion` [[#4425](https://github.com/PointCloudLibrary/pcl/pull/4425)] +* Fix force no recompute [[#4535](https://github.com/PointCloudLibrary/pcl/pull/4535)] +* Skip non-finite points for Pyramid Feature Matching [[#4711](https://github.com/PointCloudLibrary/pcl/pull/4711)] + +#### libpcl_sample_consensus: + +* **[ABI break]** Allow user to apply arbitrary constraint on models in sample consensus [[#4260](https://github.com/PointCloudLibrary/pcl/pull/4260)] +* Improve logging errors during sample consensus model registration [[#4381](https://github.com/PointCloudLibrary/pcl/pull/4381)] +* **[new feature]** Add SIMD implementations to some countWithinDistance functions [[#3519](https://github.com/PointCloudLibrary/pcl/pull/3519)] +* Faster sample consensus functions [[#4424](https://github.com/PointCloudLibrary/pcl/pull/4424)] +* Fix and improve MLESAC [[#4575](https://github.com/PointCloudLibrary/pcl/pull/4575)] +* Improve logging in module `sample_consensus` [[#4261](https://github.com/PointCloudLibrary/pcl/pull/4261)] + +#### libpcl_search: + +* Faster organized search [[#4496](https://github.com/PointCloudLibrary/pcl/pull/4496)] +* Add access to boxSearch [[#4282](https://github.com/PointCloudLibrary/pcl/pull/4282)] + +#### libpcl_segmentation: + +* **[deprecation]** Deprecate unused `max_label` in `extractLabeledEuclideanClusters` [[#4105](https://github.com/PointCloudLibrary/pcl/pull/4105)] +* Fix the dotproduct calculation in `extractEuclideanClusters` for smooth surfaces [[#4162](https://github.com/PointCloudLibrary/pcl/pull/4162)] +* Make euclidean clustering with normals faster [[#4551](https://github.com/PointCloudLibrary/pcl/pull/4551)] + +#### libpcl_surface: + +* **[ABI break]** Enabled multithreading in Poisson surface reconstruction [[#4332](https://github.com/PointCloudLibrary/pcl/pull/4332)] +* Add stdlib header for malloc in poisson (bugfix for gcc-5) [[#4376](https://github.com/PointCloudLibrary/pcl/pull/4376)] +* Always update counter and prevent overflow access in poisson4 octree [[#4316](https://github.com/PointCloudLibrary/pcl/pull/4316)] +* Add missing include to nurbs_solve_umfpack.cpp [[#4571](https://github.com/PointCloudLibrary/pcl/pull/4571)] +* **[deprecation]** MLS: correct typo in `principle` by using `principal` instead [[#4505](https://github.com/PointCloudLibrary/pcl/pull/4505)] + +#### libpcl_visualization: + +* Add support for VTK 9 [[#4262](https://github.com/PointCloudLibrary/pcl/pull/4262)] +* **[new feature]** add ellipsoid shape to pcl_visualizer [[#4531](https://github.com/PointCloudLibrary/pcl/pull/4531)] + +#### PCL Apps: + +* **[removal]** Remove unused code in persistence_utils.h [[#4500](https://github.com/PointCloudLibrary/pcl/pull/4500)] +* **[deprecation]** pyramidal klt: switch keypoints_status_ to int vector [[#4681](https://github.com/PointCloudLibrary/pcl/pull/4681)] + +#### PCL Docs: + +* Update documentation to be coherent with the style guide [[#4771](https://github.com/PointCloudLibrary/pcl/pull/4771)] + +#### PCL Tutorials: + +* Replace PassThrough with removeNaNFromPointCloud in 3 tutorials [[#4760](https://github.com/PointCloudLibrary/pcl/pull/4760)] + +#### PCL Tools: + +* Fix virtual scanner [[#4730](https://github.com/PointCloudLibrary/pcl/pull/4730)] + +#### CI: + +* Make windows build on c:\ drive to fix out-of-disk-space errors [[#4382](https://github.com/PointCloudLibrary/pcl/pull/4382)] +* **[new feature]** Use windows docker image in CI. [[#4426](https://github.com/PointCloudLibrary/pcl/pull/4426)] + ## = 1.11.1 (13.08.2020) = Apart from the usual serving of bug-fixes and speed improvements, PCL 1.11.1 brings in diff --git a/CMakeLists.txt b/CMakeLists.txt index ceec26b0be8..ada78ba05cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ ### ---[ PCL global CMake -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) if(POLICY CMP0074) # 1. Remove with 3.12.4. @@ -12,13 +12,10 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD 14 CACHE STRING "The target C++ standard. PCL requires C++14 or higher.") set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -if(CMAKE_VERSION VERSION_LESS 3.8) - # CMake did not have cxx_std_14 compile feature prior to 3.8 - # We use cxx_attribute_deprecated as a proxy because this feature is a part of c++14 standard - set(PCL_CXX_COMPILE_FEATURES cxx_attribute_deprecated) -else() - set(PCL_CXX_COMPILE_FEATURES cxx_std_14) -endif() +set(PCL_CXX_COMPILE_FEATURES cxx_std_14) + +set(CMAKE_CUDA_STANDARD 14 CACHE STRING "The target CUDA/C++ standard. PCL requires CUDA/C++ 14 or higher.") +set(CMAKE_CUDA_STANDARD_REQUIRED ON) set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "possible configurations" FORCE) @@ -27,7 +24,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "") set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "build type default to RelWithDebInfo, set to Release to improve performance" FORCE) endif() -project(PCL VERSION 1.11.1.99) +project(PCL VERSION 1.12.1.99) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) ### ---[ Find universal dependencies @@ -51,7 +48,7 @@ set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING # Compiler identification # Define a variable CMAKE_COMPILER_IS_X where X is the compiler short name. # Note: CMake automatically defines one for GNUCXX, nothing to do in this case. -if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_COMPILER_IS_CLANG 1) elseif(__COMPILER_PATHSCALE) set(CMAKE_COMPILER_IS_PATHSCALE 1) @@ -61,6 +58,20 @@ elseif(MINGW) set(CMAKE_COMPILER_IS_MINGW 1) endif() +# https://github.com/fish-shell/fish-shell/issues/5865 +include(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES(" +#include +struct big { int foo[64]; }; +std::atomic x; +int main() { + return x.load().foo[13]; +}" +LIBATOMIC_NOT_NEEDED) +IF (NOT LIBATOMIC_NOT_NEEDED) + SET(ATOMIC_LIBRARY "atomic") +ENDIF() + # Create a variable with expected default CXX flags # This will be used further down the road to check if the user explicitly provided CXX flags if(CMAKE_COMPILER_IS_MSVC) @@ -91,6 +102,12 @@ if(PCL_ENABLE_SSE AND "${CMAKE_CXX_FLAGS}" STREQUAL "${CMAKE_CXX_FLAGS_DEFAULT}" PCL_CHECK_FOR_SSE() endif() +# check for AVX flags +if(PCL_ENABLE_AVX AND "${CMAKE_CXX_FLAGS}" STREQUAL "${CMAKE_CXX_FLAGS_DEFAULT}") + include("${PCL_SOURCE_DIR}/cmake/pcl_find_avx.cmake") + PCL_CHECK_FOR_AVX() +endif() + # ---[ Unix/Darwin/Windows specific flags if(CMAKE_COMPILER_IS_GNUCXX) if("${CMAKE_CXX_FLAGS}" STREQUAL "${CMAKE_CXX_FLAGS_DEFAULT}") @@ -99,10 +116,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) else() string(APPEND CMAKE_CXX_FLAGS " -Wabi") endif() - string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wno-unknown-pragmas -fno-strict-aliasing -Wno-format-extra-args -Wno-sign-compare -Wno-invalid-offsetof -Wno-conversion ${SSE_FLAGS_STR}") - if(PCL_WARNINGS_ARE_ERRORS) - string(APPEND CMAKE_CXX_FLAGS " -Werror") - endif() + string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wno-unknown-pragmas -fno-strict-aliasing -Wno-format-extra-args -Wno-sign-compare -Wno-invalid-offsetof -Wno-conversion ${SSE_FLAGS} ${AVX_FLAGS}") + endif() + + if(PCL_WARNINGS_ARE_ERRORS) + string(APPEND CMAKE_CXX_FLAGS " -Werror -fno-strict-aliasing") endif() if("${CMAKE_SHARED_LINKER_FLAGS}" STREQUAL "" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") @@ -125,10 +143,8 @@ endif() if(CMAKE_COMPILER_IS_MSVC) add_definitions("-DBOOST_ALL_NO_LIB -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -DNOMINMAX -DPCL_ONLY_CORE_POINT_TYPES ${SSE_DEFINITIONS}") - add_compile_options(/bigobj) - if("${CMAKE_CXX_FLAGS}" STREQUAL "${CMAKE_CXX_FLAGS_DEFAULT}") - string(APPEND CMAKE_CXX_FLAGS " /fp:precise /wd4800 /wd4521 /wd4251 /wd4275 /wd4305 /wd4355 ${SSE_FLAGS_STR}") + string(APPEND CMAKE_CXX_FLAGS " /fp:precise /wd4800 /wd4521 /wd4251 /wd4275 /wd4305 /wd4355 ${SSE_FLAGS} ${AVX_FLAGS} /bigobj") # Add extra code generation/link optimizations if(CMAKE_MSVC_CODE_LINK_OPTIMIZATION AND (NOT BUILD_CUDA) AND (NOT BUILD_GPU)) @@ -136,6 +152,8 @@ if(CMAKE_COMPILER_IS_MSVC) string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " /LTCG /OPT:REF") string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " /LTCG") else() + set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=/bigobj") + message("Global optimizations /GL has been turned off, as it doesn't work with nvcc/thrust") endif() # /MANIFEST:NO") # please, don't disable manifest generation, otherwise crash at start for vs2008 @@ -148,7 +166,7 @@ if(CMAKE_COMPILER_IS_MSVC) ProcessorCount(CPUCores) set(MSVC_MP ${CPUCores} CACHE STRING "Number of simultaneously running compilers (0 = automatic detection by MSVC). See documentation of /MP flag.") if (CMAKE_VERSION VERSION_LESS 3.11.0) - # Usage of COMPILE_LANGUAGE generator expression for MSVC in add_compile_options requires at least CMake 3.11, see https://gitlab.kitware.com/cmake/cmake/issues/17435 + # Usage of COMPILE_LANGUAGE generator expression for MSVC in add_compile_options requires at least CMake 3.11, see https://gitlab.kitware.com/cmake/cmake/issues/17435 if(MSVC_MP EQUAL 0) # MSVC_MP is 0 in case the information cannot be determined by ProcessorCount => fallback string(APPEND CMAKE_C_FLAGS " /MP") @@ -188,7 +206,7 @@ if(CMAKE_COMPILER_IS_CLANG) set(CMAKE_C_FLAGS "-Qunused-arguments") endif() if("${CMAKE_CXX_FLAGS}" STREQUAL "") - set(CMAKE_CXX_FLAGS "-ftemplate-depth=1024 -Qunused-arguments -Wno-invalid-offsetof ${SSE_FLAGS_STR}") # Unfortunately older Clang versions do not have this: -Wno-unnamed-type-template-args + set(CMAKE_CXX_FLAGS "-ftemplate-depth=1024 -Qunused-arguments -Wno-invalid-offsetof ${SSE_FLAGS} ${AVX_FLAGS}") # Unfortunately older Clang versions do not have this: -Wno-unnamed-type-template-args if(APPLE AND WITH_CUDA AND CUDA_FOUND) string(APPEND CMAKE_CXX_FLAGS " -stdlib=libstdc++") endif() @@ -280,6 +298,8 @@ if(OpenMP_FOUND) set(OPENMP_DLL VCOMP140) elseif(MSVC_VERSION MATCHES "^192[0-9]$") set(OPENMP_DLL VCOMP140) + elseif(MSVC_VERSION MATCHES "^193[0-9]$") + set(OPENMP_DLL VCOMP140) endif() if(OPENMP_DLL) string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /DELAYLOAD:${OPENMP_DLL}D.dll") @@ -300,18 +320,15 @@ find_package(Eigen 3.1 REQUIRED) include_directories(SYSTEM ${EIGEN_INCLUDE_DIRS}) # FLANN (required) -if(NOT PCL_SHARED_LIBS OR ((WIN32 AND NOT MINGW) AND NOT PCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32)) - set(FLANN_USE_STATIC ON) +find_package(FLANN 1.9.1 REQUIRED) +if(NOT (${FLANN_LIBRARY_TYPE} MATCHES ${PCL_FLANN_REQUIRED_TYPE}) AND NOT (${PCL_FLANN_REQUIRED_TYPE} MATCHES "DONTCARE")) + message(FATAL_ERROR "Flann was selected with ${PCL_FLANN_REQUIRED_TYPE} but found as ${FLANN_LIBRARY_TYPE}") endif() -find_package(FLANN 1.7.0 REQUIRED) -# libusb-1.0 +# libusb option(WITH_LIBUSB "Build USB RGBD-Camera drivers" TRUE) if(WITH_LIBUSB) - find_package(libusb-1.0) - if(LIBUSB_1_FOUND) - include_directories(SYSTEM "${LIBUSB_1_INCLUDE_DIR}") - endif() + include("${PCL_SOURCE_DIR}/cmake/pcl_find_libusb.cmake") endif() # Dependencies for different grabbers @@ -349,12 +366,9 @@ endif() # Qhull option(WITH_QHULL "Include convex-hull operations" TRUE) if(WITH_QHULL) - if(NOT PCL_SHARED_LIBS OR ((WIN32 AND NOT MINGW) AND NOT PCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32)) - set(QHULL_USE_STATIC ON) - endif() find_package(Qhull) - if(QHULL_FOUND) - include_directories(SYSTEM ${QHULL_INCLUDE_DIRS}) + if(NOT (${QHULL_LIBRARY_TYPE} MATCHES ${PCL_QHULL_REQUIRED_TYPE}) AND NOT (${PCL_QHULL_REQUIRED_TYPE} MATCHES "DONTCARE")) + message(FATAL_ERROR "Qhull was selected with ${PCL_QHULL_REQUIRED_TYPE} but found as ${QHULL_LIBRARY_TYPE}") endif() endif() @@ -364,22 +378,25 @@ if(WITH_CUDA) include("${PCL_SOURCE_DIR}/cmake/pcl_find_cuda.cmake") endif() -option(WITH_QT "Build QT Front-End" TRUE) -if(WITH_QT) - find_package(Qt5 COMPONENTS Concurrent OpenGL Widgets QUIET) - if(Qt5_FOUND) - message(STATUS "Found Qt5 version: ${Qt5_VERSION}") - endif() -endif() -# Find VTK +# Reset VTK_FOUND to off +set(VTK_FOUND OFF) +# Find VTK - VTK has to be found before Qt, otherwise it can overwrite Qt variables option(WITH_VTK "Build VTK-Visualizations" TRUE) -if(WITH_VTK AND NOT ANDROID) - include("${PCL_SOURCE_DIR}/cmake/pcl_find_vtk.cmake") -else() - set(VTK_FOUND OFF) +if(WITH_VTK) + if(ANDROID) + message(WARNING "VTK is not supported on Android.") + else() + include("${PCL_SOURCE_DIR}/cmake/pcl_find_vtk.cmake") + endif() endif() +# VTK can depend on Qt and search for its required version, so search after so we can overwrite Qt5_FOUND/Qt6_FOUND if the version we require is not found. +set(WITH_QT "AUTO" CACHE STRING "Build QT Front-End (AUTO|YES|QT6|QT5|NO)") +set_property(CACHE WITH_QT PROPERTY STRINGS "AUTO" "YES" "QT6" "QT5" "NO") +if(WITH_QT) + include("${PCL_SOURCE_DIR}/cmake/pcl_find_qt.cmake") +endif() #Find PCAP option(WITH_PCAP "pcap file capabilities in Velodyne HDL driver" TRUE) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 71aa4672da6..c940ed3bcdf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,40 +114,12 @@ of each `.h` and `.cpp` file: ```cpp /* - * Software License Agreement (BSD License) + * SPDX-License-Identifier: BSD-3-Clause * * Point Cloud Library (PCL) - www.pointclouds.org - * Copyright (c) 2014-, Open Perception, Inc. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the copyright holder(s) 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. + * Copyright (c) 2014-, Open Perception Inc. * + * All rights reserved */ ``` diff --git a/PCLConfig.cmake.in b/PCLConfig.cmake.in index c725067bb85..aa7a03809ce 100644 --- a/PCLConfig.cmake.in +++ b/PCLConfig.cmake.in @@ -13,7 +13,7 @@ #------------------------------------------------------------------------------------ # Set default policy behavior similar to minimum requirement version -cmake_policy(VERSION 3.5) +cmake_policy(VERSION 3.10) # explicitly set policies we already support in newer cmake versions if(POLICY CMP0074) @@ -93,22 +93,14 @@ macro(find_boost) elseif(NOT BOOST_INCLUDEDIR) set(BOOST_INCLUDEDIR "@Boost_INCLUDE_DIR@") endif() - # use static Boost in Windows - if(WIN32) - set(Boost_USE_STATIC_LIBS @Boost_USE_STATIC_LIBS@) - set(Boost_USE_STATIC @Boost_USE_STATIC@) - set(Boost_USE_MULTITHREAD @Boost_USE_MULTITHREAD@) - endif() + set(Boost_ADDITIONAL_VERSIONS "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@.@Boost_SUBMINOR_VERSION@" "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@" - "1.75.0" "1.75" + "1.79.0" "1.79" "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74" "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" - "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" - "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" - "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55") - # Disable the config mode of find_package(Boost) - set(Boost_NO_BOOST_CMAKE ON) - find_package(Boost 1.55.0 ${QUIET_} COMPONENTS @PCLCONFIG_AVAILABLE_BOOST_MODULES@) + "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65") + + find_package(Boost 1.65.0 ${QUIET_} COMPONENTS @PCLCONFIG_AVAILABLE_BOOST_MODULES@) set(BOOST_FOUND ${Boost_FOUND}) set(BOOST_INCLUDE_DIRS "${Boost_INCLUDE_DIR}") @@ -137,7 +129,7 @@ macro(find_qhull) get_filename_component(QHULL_ROOT "@QHULL_INCLUDE_DIRS@" PATH) endif() - set(QHULL_USE_STATIC @QHULL_USE_STATIC@) + set(PCL_QHULL_REQUIRED_TYPE @PCL_QHULL_REQUIRED_TYPE@) find_package(Qhull) endmacro() @@ -235,7 +227,7 @@ macro(find_flann) set(FLANN_ROOT "@FLANN_ROOT@") endif() - set(FLANN_USE_STATIC @FLANN_USE_STATIC@) + set(PCL_FLANN_REQUIRED_TYPE @PCL_FLANN_REQUIRED_TYPE@) find_package(FLANN) endmacro() @@ -255,17 +247,7 @@ macro(find_VTK) endmacro() macro(find_libusb) - if(NOT WIN32) - find_path(LIBUSB_1_INCLUDE_DIR - NAMES libusb-1.0/libusb.h - PATHS /usr/include /usr/local/include /opt/local/include /sw/include - PATH_SUFFIXES libusb-1.0) - - find_library(LIBUSB_1_LIBRARY - NAMES usb-1.0 - PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib) - find_package_handle_standard_args(libusb-1.0 LIBUSB_1_LIBRARY LIBUSB_1_INCLUDE_DIR) - endif() + find_package(libusb) endmacro() macro(find_glew) @@ -310,7 +292,7 @@ macro(find_external_library _component _lib _is_optional) find_rssdk2() elseif("${_lib}" STREQUAL "vtk") find_VTK() - elseif("${_lib}" STREQUAL "libusb-1.0") + elseif("${_lib}" STREQUAL "libusb") find_libusb() elseif("${_lib}" STREQUAL "glew") find_glew() @@ -323,13 +305,20 @@ macro(find_external_library _component _lib _is_optional) string(REGEX REPLACE "[.-]" "_" LIB ${LIB}) if(${LIB}_FOUND) list(APPEND PCL_${COMPONENT}_INCLUDE_DIRS ${${LIB}_INCLUDE_DIRS}) - if(${LIB}_USE_FILE) + + if(${LIB} MATCHES "VTK") + if(${${LIB}_VERSION_MAJOR} GREATER_EQUAL 9) + set(ISVTK9ORGREATER TRUE) + endif() + endif() + + if(${LIB}_USE_FILE AND NOT ISVTK9ORGREATER ) include(${${LIB}_USE_FILE}) else() list(APPEND PCL_${COMPONENT}_LIBRARY_DIRS "${${LIB}_LIBRARY_DIRS}") endif() if(${LIB}_LIBRARIES) - list(APPEND PCL_${COMPONENT}_LIBRARIES "${${LIB}_LIBRARIES}") + list(APPEND PCL_${COMPONENT}_LINK_LIBRARIES "${${LIB}_LIBRARIES}") endif() if(${LIB}_DEFINITIONS AND NOT ${LIB} STREQUAL "VTK") list(APPEND PCL_${COMPONENT}_DEFINITIONS ${${LIB}_DEFINITIONS}) @@ -396,6 +385,9 @@ file(TO_CMAKE_PATH "${PCL_DIR}" PCL_DIR) if(WIN32 AND NOT MINGW) # PCLConfig.cmake is installed to PCL_ROOT/cmake get_filename_component(PCL_ROOT "${PCL_DIR}" PATH) + if(EXISTS "${PCL_ROOT}/3rdParty") + set(PCL_ALL_IN_ONE_INSTALLER ON) + endif() else() # PCLConfig.cmake is installed to PCL_ROOT/share/pcl-x.y get_filename_component(PCL_ROOT "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE) @@ -407,23 +399,16 @@ if(EXISTS "${PCL_ROOT}/include/pcl-${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR}/pcl # pcl_message("Found a PCL installation") set(PCL_CONF_INCLUDE_DIR "${PCL_ROOT}/include/pcl-${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR}") set(PCL_LIBRARY_DIRS "${PCL_ROOT}/@LIB_INSTALL_DIR@") - if(EXISTS "${PCL_ROOT}/3rdParty") - set(PCL_ALL_IN_ONE_INSTALLER ON) - endif() elseif(EXISTS "${PCL_ROOT}/include/pcl/pcl_config.h") # Found a non-standard (likely ANDROID) PCL installation # pcl_message("Found a PCL installation") set(PCL_CONF_INCLUDE_DIR "${PCL_ROOT}/include") set(PCL_LIBRARY_DIRS "${PCL_ROOT}/lib") - if(EXISTS "${PCL_ROOT}/3rdParty") - set(PCL_ALL_IN_ONE_INSTALLER ON) - endif() elseif(EXISTS "${PCL_DIR}/include/pcl/pcl_config.h") # Found PCLConfig.cmake in a build tree of PCL # pcl_message("PCL found into a build tree.") set(PCL_CONF_INCLUDE_DIR "${PCL_DIR}/include") # for pcl_config.h set(PCL_LIBRARY_DIRS "${PCL_DIR}/@LIB_INSTALL_DIR@") - set(PCL_SOURCES_TREE "@CMAKE_SOURCE_DIR@") else() pcl_report_not_found("PCL can not be found on this machine") endif() @@ -434,10 +419,15 @@ set(PCL_INCLUDE_DIRS "${PCL_CONF_INCLUDE_DIR}") set(PCL_DEBUG_SUFFIX "@CMAKE_DEBUG_POSTFIX@") set(PCL_RELEASE_SUFFIX "@CMAKE_RELEASE_POSTFIX@") +set(PCL_SHARED_LIBS "@PCL_SHARED_LIBS@") + #set SSE flags used compiling PCL list(APPEND PCL_DEFINITIONS @PCLCONFIG_SSE_DEFINITIONS@) list(APPEND PCL_COMPILE_OPTIONS @PCLCONFIG_SSE_COMPILE_OPTIONS@) +#set AVX flags used compiling PCL +list(APPEND PCL_COMPILE_OPTIONS @PCLCONFIG_AVX_COMPILE_OPTIONS@) + set(pcl_all_components @PCLCONFIG_AVAILABLE_COMPONENTS@) list(LENGTH pcl_all_components PCL_NB_COMPONENTS) @@ -513,7 +503,6 @@ foreach(component ${PCL_TO_FIND_COMPONENTS}) pcl/cuda/${cuda_component} pcl/cuda/${component} pcl/gpu/${gpu_component} pcl/gpu/${component} HINTS ${PCL_INCLUDE_DIRS} - "${PCL_SOURCES_TREE}" PATH_SUFFIXES ${component}/include apps/${component}/include @@ -529,6 +518,7 @@ foreach(component ${PCL_TO_FIND_COMPONENTS}) #pcl_message("No include directory found for pcl_${component}.") endif() + set(FPHSA_NAME_MISMATCHED 1) # Suppress warnings, see https://cmake.org/cmake/help/v3.17/module/FindPackageHandleStandardArgs.html # Skip find_library for header only modules list(FIND pcl_header_only_components ${component} _is_header_only) if(_is_header_only EQUAL -1) @@ -565,6 +555,7 @@ foreach(component ${PCL_TO_FIND_COMPONENTS}) find_package_handle_standard_args(PCL_${COMPONENT} DEFAULT_MSG PCL_${COMPONENT}_INCLUDE_DIR) endif() + unset(FPHSA_NAME_MISMATCHED) if(PCL_${COMPONENT}_FOUND) if(NOT "${PCL_${COMPONENT}_INCLUDE_DIRS}" STREQUAL "") @@ -675,10 +666,14 @@ endif() pcl_remove_duplicate_libraries(PCL_COMPONENTS PCL_LIBRARIES) # Add 3rd party libraries, as user code might include our .HPP implementations -list(APPEND PCL_LIBRARIES ${BOOST_LIBRARIES} ${QHULL_LIBRARIES} ${OPENNI_LIBRARIES} ${OPENNI2_LIBRARIES} ${ENSENSO_LIBRARIES} ${davidSDK_LIBRARIES} ${DSSDK_LIBRARIES} ${RSSDK_LIBRARIES} ${RSSDK2_LIBRARIES} ${VTK_LIBRARIES}) +list(APPEND PCL_LIBRARIES ${BOOST_LIBRARIES} ${OPENNI_LIBRARIES} ${OPENNI2_LIBRARIES} ${ENSENSO_LIBRARIES} ${davidSDK_LIBRARIES} ${DSSDK_LIBRARIES} ${RSSDK_LIBRARIES} ${RSSDK2_LIBRARIES} ${VTK_LIBRARIES}) if (TARGET FLANN::FLANN) list(APPEND PCL_LIBRARIES FLANN::FLANN) endif() +if(TARGET QHULL::QHULL) + list(APPEND PCL_LIBRARIES QHULL::QHULL) +endif() + find_package_handle_standard_args(PCL DEFAULT_MSG PCL_LIBRARIES PCL_INCLUDE_DIRS) mark_as_advanced(PCL_LIBRARIES PCL_INCLUDE_DIRS PCL_LIBRARY_DIRS) diff --git a/README.md b/README.md index eb0109ab4c6..7301bcca1aa 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Release][release-image]][releases] [![License][license-image]][license] -[release-image]: https://img.shields.io/badge/release-1.11.1-green.svg?style=flat +[release-image]: https://img.shields.io/badge/release-1.12.1-green.svg?style=flat [releases]: https://github.com/PointCloudLibrary/pcl/releases [license-image]: https://img.shields.io/badge/license-BSD-green.svg?style=flat @@ -23,17 +23,20 @@ Continuous integration [ci-latest-build]: https://dev.azure.com/PointCloudLibrary/pcl/_build/latest?definitionId=9&branchName=master [ci-ubuntu-18.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20GCC&jobName=Ubuntu&configuration=Ubuntu%2018.04%20GCC&label=Ubuntu%2018.04%20GCC [ci-ubuntu-20.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=Ubuntu&configuration=Ubuntu%2020.04%20Clang&label=Ubuntu%2020.04%20Clang -[ci-ubuntu-20.10]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20GCC&jobName=Ubuntu&configuration=Ubuntu%2020.10%20GCC&label=Ubuntu%2020.10%20GCC -[ci-windows-x86]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20MSVC&jobName=Windows%20VS2017%20Build&configuration=Windows%20VS2017%20Build%20x86&label=Windows%20VS2017%20x86 -[ci-windows-x64]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20MSVC&jobName=Windows%20VS2017%20Build&configuration=Windows%20VS2017%20Build%20x64&label=Windows%20VS2017%20x64 -[ci-macos-10.14]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=macOS&configuration=macOS%20Mojave%2010.14&label=macOS%20Mojave%2010.14 +[ci-ubuntu-22.04]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20GCC&jobName=Ubuntu&configuration=Ubuntu%2022.04%20GCC&label=Ubuntu%2022.04%20GCC +[ci-windows-x86]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20MSVC&jobName=Windows%20Build&configuration=Windows%20Build%20x86&label=Windows%20VS2019%20x86 +[ci-windows-x64]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20MSVC&jobName=Windows%20Build&configuration=Windows%20Build%20x64&label=Windows%20VS2019%20x64 +[ci-macos-11]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=macOS&configuration=macOS%20Big%20Sur%2011&label=macOS%20Big%20Sur%2011 [ci-macos-10.15]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/9?branchName=master&stageName=Build%20Clang&jobName=macOS&configuration=macOS%20Catalina%2010.15&label=macOS%20Catalina%2010.15 +[ci-docs]: https://dev.azure.com/PointCloudLibrary/pcl/_apis/build/status/Documentation?branchName=master +[ci-latest-docs]: https://dev.azure.com/PointCloudLibrary/pcl/_build/latest?definitionId=14&branchName=master Build Platform | Status ------------------------ | ------------------------------------------------------------------------------------------------- | -Ubuntu | [![Status][ci-ubuntu-18.04]][ci-latest-build]
[![Status][ci-ubuntu-20.04]][ci-latest-build]
[![Status][ci-ubuntu-20.10]][ci-latest-build] | +Ubuntu | [![Status][ci-ubuntu-18.04]][ci-latest-build]
[![Status][ci-ubuntu-20.04]][ci-latest-build]
[![Status][ci-ubuntu-22.04]][ci-latest-build] | Windows | [![Status][ci-windows-x86]][ci-latest-build]
[![Status][ci-windows-x64]][ci-latest-build] | -macOS | [![Status][ci-macos-10.14]][ci-latest-build]
[![Status][ci-macos-10.15]][ci-latest-build] | +macOS | [![Status][ci-macos-10.15]][ci-latest-build]
[![Status][ci-macos-11]][ci-latest-build] | +Documentation | [![Status][ci-docs]][ci-latest-docs] | Community --------- @@ -97,3 +100,18 @@ for Q&A as well as support for troubleshooting, installation and debugging. Do remember to tag your questions with the tag `point-cloud-library`. * [Discord Server](https://discord.gg/JFFMAXS) for live chat with other members of the PCL community and casual discussions + +Citation +-------- +We encourage other researchers to cite PCL if they use PCL or its components for their work or baselines. The bibtex entry for the same is +``` +@InProceedings{Rusu_ICRA2011_PCL, + author = {Radu Bogdan Rusu and Steve Cousins}, + title = {{3D is here: Point Cloud Library (PCL)}}, + booktitle = {{IEEE International Conference on Robotics and Automation (ICRA)}}, + month = {May 9-13}, + year = {2011}, + address = {Shanghai, China}, + publisher = {IEEE} +} +``` diff --git a/apps/3d_rec_framework/CMakeLists.txt b/apps/3d_rec_framework/CMakeLists.txt index 6b64e28c9c4..219c4deff89 100644 --- a/apps/3d_rec_framework/CMakeLists.txt +++ b/apps/3d_rec_framework/CMakeLists.txt @@ -1,24 +1,7 @@ set(SUBSUBSYS_NAME 3d_rec_framework) set(SUBSUBSYS_DESC "3D recognition framework") set(SUBSUBSYS_DEPS common geometry io filters sample_consensus segmentation visualization kdtree features surface octree registration keypoints tracking search recognition ml) - -# Find VTK -if(NOT VTK_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "VTK was not found.") -else() - set(DEFAULT TRUE) - set(REASON) -endif() - -# OpenNI found? -if(NOT WITH_OPENNI) - set(DEFAULT AUTO_OFF) - set(REASON "OpenNI was not found or was disabled by the user.") -elseif(NOT ${DEFAULT} STREQUAL "AUTO_OFF") - set(DEFAULT TRUE) - set(REASON) -endif() +set(SUBSUBSYS_EXT_DEPS vtk openni) # Default to not building for now if(${DEFAULT} STREQUAL "TRUE") @@ -26,7 +9,7 @@ if(${DEFAULT} STREQUAL "TRUE") endif() PCL_SUBSUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" "${SUBSUBSYS_DESC}" ${DEFAULT} "${REASON}") -PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" DEPS ${SUBSUBSYS_DEPS} EXT_DEPS vtk openni) +PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" DEPS ${SUBSUBSYS_DEPS} EXT_DEPS ${SUBSUBSYS_EXT_DEPS}) if(NOT build) return() @@ -111,10 +94,6 @@ target_link_libraries("${LIB_NAME}" pcl_apps pcl_common pcl_io pcl_filters pcl_v if(WITH_OPENNI) target_link_libraries("${LIB_NAME}" ${OPENNI_LIBRARIES}) - if(NOT WIN32) - find_package(libusb-1.0 REQUIRED) - target_link_libraries("${LIB_NAME}" ${LIBUSB_1_LIBRARIES}) - endif() endif() PCL_MAKE_PKGCONFIG(${LIB_NAME} COMPONENT ${SUBSUBSYS_NAME} DESC ${SUBSUBSYS_DESC}) diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h index 328aee83853..c37229b958a 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/local/local_estimator.h @@ -77,7 +77,7 @@ class UniformSamplingExtractor : public KeypointExtractor { using KeypointExtractor::input_; using KeypointExtractor::radius_; float sampling_density_; - std::shared_ptr>> neighborhood_indices_; + std::shared_ptr> neighborhood_indices_; std::shared_ptr>> neighborhood_dist_; void @@ -92,7 +92,7 @@ class UniformSamplingExtractor : public KeypointExtractor { tree.reset(new pcl::search::KdTree(false)); tree->setInputCloud(input); - neighborhood_indices_.reset(new std::vector>); + neighborhood_indices_.reset(new std::vector); neighborhood_indices_->resize(keypoints_cloud->size()); neighborhood_dist_.reset(new std::vector>); neighborhood_dist_->resize(keypoints_cloud->size()); diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h index e1e7a132970..64ec3e95abe 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/feature_wrapper/normal_estimator.h @@ -30,11 +30,9 @@ class PreProcessorAndNormalEstimator { KdTreeInPtr tree = pcl::make_shared>(false); tree->setInputCloud(input); - std::vector nn_indices(9); + pcl::Indices nn_indices(9); std::vector nn_distances(9); - std::vector src_indices; - float sum_distances = 0.0; std::vector avg_distances(input->size()); // Iterate through the source data set for (std::size_t i = 0; i < input->size(); ++i) { @@ -47,10 +45,12 @@ class PreProcessorAndNormalEstimator { avg_dist_neighbours /= static_cast(nn_indices.size()); avg_distances[i] = avg_dist_neighbours; - sum_distances += avg_dist_neighbours; } - std::sort(avg_distances.begin(), avg_distances.end()); + // median: nth_element is faster than sorting everything + std::nth_element(avg_distances.begin(), + avg_distances.begin() + (avg_distances.size() / 2 + 1), + avg_distances.end()); float avg = avg_distances[static_cast(avg_distances.size()) / 2 + 1]; return avg; } diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h index 690c6c59815..1699f85d96a 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pc_source/registered_views_source.h @@ -8,7 +8,7 @@ #pragma once #include -#include +#include #include #include diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h index 7b96958227e..d6554df8260 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_classifier.h @@ -33,7 +33,7 @@ class PCL_EXPORTS GlobalClassifier { classify() = 0; virtual void - setIndices(std::vector& indices) = 0; + setIndices(pcl::Indices& indices) = 0; virtual void setInputCloud(const PointInTPtr& cloud) = 0; @@ -91,7 +91,7 @@ class PCL_EXPORTS GlobalNNPipeline flann::Index* flann_index_; std::vector flann_models_; - std::vector indices_; + pcl::Indices indices_; // load features from disk and create flann structure void @@ -185,7 +185,7 @@ class PCL_EXPORTS GlobalNNPipeline } void - setIndices(std::vector& indices) override + setIndices(pcl::Indices& indices) override { indices_ = indices; } diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_crh.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_crh.h index fb597bb1bcd..ff3bde4e537 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_crh.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_crh.h @@ -95,7 +95,7 @@ class PCL_EXPORTS GlobalNNCRHRecognizer { poses_cache_; std::map, Eigen::Vector3f> centroids_cache_; - std::vector indices_; + pcl::Indices indices_; // load features from disk and create flann structure void @@ -216,7 +216,7 @@ class PCL_EXPORTS GlobalNNCRHRecognizer { } void - setIndices(std::vector& indices) + setIndices(pcl::Indices& indices) { indices_ = indices; } diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_cvfh.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_cvfh.h index 82e9cc3442f..54c5076c2d8 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_cvfh.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/global_nn_recognizer_cvfh.h @@ -130,7 +130,7 @@ class PCL_EXPORTS GlobalNNCVFHRecognizer { poses_cache_; std::map, Eigen::Vector3f> centroids_cache_; - std::vector indices_; + pcl::Indices indices_; bool compute_scale_; @@ -295,7 +295,7 @@ class PCL_EXPORTS GlobalNNCVFHRecognizer { } void - setIndices(std::vector& indices) + setIndices(pcl::Indices& indices) { indices_ = indices; } diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/impl/global_nn_recognizer_cvfh.hpp b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/impl/global_nn_recognizer_cvfh.hpp index b891d95ec3b..b3ea5716e9d 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/impl/global_nn_recognizer_cvfh.hpp +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/impl/global_nn_recognizer_cvfh.hpp @@ -270,14 +270,12 @@ pcl::rec_3d_framework::GlobalNNCVFHRecognizer::rec indices, distances); // gather NN-search results - double score = 0; for (std::size_t i = 0; i < (std::size_t)NN_; ++i) { - score = distances[0][i]; index_score is; is.idx_models_ = single_categories_pointers_to_models_[it->second]->at(indices[0][i]); is.idx_input_ = static_cast(idx); - is.score_ = score; + is.score_ = distances[0][i]; indices_scores.push_back(is); } } diff --git a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/local_recognizer.h b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/local_recognizer.h index 8ef60a94427..99fa9f7c11c 100644 --- a/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/local_recognizer.h +++ b/apps/3d_rec_framework/include/pcl/apps/3d_rec_framework/pipeline/local_recognizer.h @@ -80,7 +80,7 @@ class PCL_EXPORTS LocalRecognitionPipeline { flann::Index* flann_index_; std::vector flann_models_; - std::vector indices_; + pcl::Indices indices_; bool use_cache_; std::map, @@ -242,7 +242,7 @@ class PCL_EXPORTS LocalRecognitionPipeline { } void - setIndices(std::vector& indices) + setIndices(pcl::Indices& indices) { indices_ = indices; } diff --git a/apps/3d_rec_framework/src/tools/global_classification.cpp b/apps/3d_rec_framework/src/tools/global_classification.cpp index 500bb59f7e8..45b1b77be29 100644 --- a/apps/3d_rec_framework/src/tools/global_classification.cpp +++ b/apps/3d_rec_framework/src/tools/global_classification.cpp @@ -62,9 +62,9 @@ segmentAndClassify( dps.compute_fast(clusters); dps.getIndicesClusters(indices); Eigen::Vector4f table_plane_; + dps.getTableCoefficients(table_plane_); Eigen::Vector3f normal_plane_ = Eigen::Vector3f(table_plane_[0], table_plane_[1], table_plane_[2]); - dps.getTableCoefficients(table_plane_); vis.removePointCloud("frame"); vis.addPointCloud(frame, "frame"); diff --git a/apps/3d_rec_framework/src/tools/local_recognition_mian_dataset.cpp b/apps/3d_rec_framework/src/tools/local_recognition_mian_dataset.cpp index b742768072d..53891821d11 100644 --- a/apps/3d_rec_framework/src/tools/local_recognition_mian_dataset.cpp +++ b/apps/3d_rec_framework/src/tools/local_recognition_mian_dataset.cpp @@ -283,7 +283,7 @@ main(int argc, char** argv) int detect_clutter = 1; int hv_method = 0; int use_hv = 1; - float thres_hyp_ = 0.2f; + float thres_hyp = 0.2f; float desc_radius = 0.04f; pcl::console::parse_argument(argc, argv, "-models_dir", path); @@ -300,7 +300,8 @@ main(int argc, char** argv) pcl::console::parse_argument(argc, argv, "-detect_clutter", detect_clutter); pcl::console::parse_argument(argc, argv, "-hv_method", hv_method); pcl::console::parse_argument(argc, argv, "-use_hv", use_hv); - pcl::console::parse_argument(argc, argv, "-thres_hyp", thres_hyp_); + pcl::console::parse_argument(argc, argv, "-thres_hyp", thres_hyp); + pcl::console::parse_argument(argc, argv, "-desc_radius", desc_radius); if (mians_scenes.empty()) { PCL_ERROR("Set the directory containing mians scenes using the -mians_scenes_dir " @@ -493,7 +494,7 @@ main(int argc, char** argv) local.setUseCache(static_cast(use_cache)); local.initialize(static_cast(force_retrain)); - local.setThresholdAcceptHyp(thres_hyp_); + local.setThresholdAcceptHyp(thres_hyp); uniform_keypoint_extractor->setSamplingDensity(0.005f); local.setICPIterations(icp_iterations); diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index bd252740ae1..d352ab49beb 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,16 +1,22 @@ set(SUBSYS_NAME apps) set(SUBSYS_DESC "Application examples/samples that show how PCL works") set(SUBSYS_DEPS common geometry io filters sample_consensus segmentation visualization kdtree features surface octree registration keypoints tracking search recognition ml stereo 2d) +set(SUBSYS_OPT_DEPS openni vtk ${QTX}) set(DEFAULT FALSE) set(REASON "Disabled by default") PCL_SUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSYS_DESC}" ${DEFAULT} "${REASON}") -PCL_SUBSYS_DEPEND(build "${SUBSYS_NAME}" DEPS ${SUBSYS_DEPS} OPT_DEPS openni vtk) +PCL_SUBSYS_DEPEND(build "${SUBSYS_NAME}" DEPS ${SUBSYS_DEPS} OPT_DEPS ${SUBSYS_OPT_DEPS}) if(NOT build) return() endif() +#Enable cmakes QT auto features. +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + # to be filled with all targets the apps subsystem set(PCL_APPS_ALL_TARGETS) @@ -28,7 +34,7 @@ target_link_libraries(pcl_pyramid_surface_matching pcl_common pcl_io pcl_feature PCL_ADD_EXECUTABLE(pcl_statistical_multiscale_interest_region_extraction_example COMPONENT ${SUBSYS_NAME} SOURCES src/statistical_multiscale_interest_region_extraction_example.cpp) target_link_libraries(pcl_statistical_multiscale_interest_region_extraction_example pcl_common pcl_io pcl_features pcl_filters) -if(LIBUSB_1_FOUND) +if(LIBUSB_FOUND) PCL_ADD_EXECUTABLE(pcl_dinast_grabber COMPONENT ${SUBSYS_NAME} SOURCES src/dinast_grabber_example.cpp) target_link_libraries(pcl_dinast_grabber pcl_common pcl_visualization pcl_io) endif() @@ -58,43 +64,43 @@ if(VTK_FOUND) if(QHULL_FOUND) PCL_ADD_EXECUTABLE(pcl_pcd_select_object_plane COMPONENT ${SUBSYS_NAME} SOURCES src/pcd_select_object_plane.cpp) target_link_libraries(pcl_pcd_select_object_plane pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_features pcl_surface) - #TODO: Update when CMAKE 3.10 is available - if(NOT (${VTK_VERSION} VERSION_LESS 9.0)) - target_link_libraries(pcl_pcd_select_object_plane VTK::FiltersGeometry) - endif() endif() PCL_ADD_EXECUTABLE(pcl_pcd_organized_edge_detection COMPONENT ${SUBSYS_NAME} SOURCES src/pcd_organized_edge_detection.cpp) target_link_libraries(pcl_pcd_organized_edge_detection pcl_common pcl_io pcl_features pcl_visualization) PCL_ADD_EXECUTABLE(pcl_face_trainer COMPONENT ${SUBSYS_NAME} SOURCES src/face_detection/face_trainer.cpp) - target_link_libraries(pcl_face_trainer pcl_features pcl_recognition pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_sample_consensus pcl_surface pcl_keypoints pcl_ml pcl_search pcl_kdtree ${VTK_LIBRARIES}) + target_link_libraries(pcl_face_trainer pcl_features pcl_recognition pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_sample_consensus pcl_surface pcl_keypoints pcl_ml pcl_search pcl_kdtree) PCL_ADD_EXECUTABLE(pcl_fs_face_detector COMPONENT ${SUBSYS_NAME} SOURCES src/face_detection//filesystem_face_detection.cpp BUNDLE) - target_link_libraries(pcl_fs_face_detector pcl_features pcl_recognition pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_sample_consensus pcl_surface pcl_keypoints pcl_ml pcl_search pcl_kdtree ${VTK_LIBRARIES}) + target_link_libraries(pcl_fs_face_detector pcl_features pcl_recognition pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_sample_consensus pcl_surface pcl_keypoints pcl_ml pcl_search pcl_kdtree) PCL_ADD_EXECUTABLE(pcl_stereo_ground_segmentation COMPONENT ${SUBSYS_NAME} SOURCES src/stereo_ground_segmentation.cpp) target_link_libraries(pcl_stereo_ground_segmentation pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_features pcl_stereo) - if(Qt5_FOUND AND HAVE_QVTK) + if(QT_FOUND AND HAVE_QVTK) # Manual registration demo - QT5_WRAP_UI(manual_registration_ui src/manual_registration/manual_registration.ui) - QT5_WRAP_CPP(manual_registration_moc include/pcl/apps/manual_registration.h OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - PCL_ADD_EXECUTABLE(pcl_manual_registration COMPONENT ${SUBSYS_NAME} SOURCES ${manual_registration_ui} ${manual_registration_moc} src/manual_registration/manual_registration.cpp BUNDLE) - target_link_libraries(pcl_manual_registration pcl_common pcl_io pcl_visualization pcl_segmentation pcl_features pcl_surface Qt5::Widgets) - #TODO: Update when CMAKE 3.10 is available - if(NOT (${VTK_VERSION} VERSION_LESS 9.0)) - target_link_libraries(pcl_manual_registration VTK::GUISupportQt) - endif() - - QT5_WRAP_UI(pcd_video_player_ui src/pcd_video_player/pcd_video_player.ui) - QT5_WRAP_CPP(pcd_video_player_moc include/pcl/apps/pcd_video_player.h OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - PCL_ADD_EXECUTABLE(pcl_pcd_video_player COMPONENT ${SUBSYS_NAME} SOURCES ${pcd_video_player_ui} ${pcd_video_player_moc} src/pcd_video_player/pcd_video_player.cpp BUNDLE) - target_link_libraries(pcl_pcd_video_player pcl_common pcl_io pcl_visualization pcl_segmentation pcl_features pcl_surface Qt5::Widgets) - #TODO: Update when CMAKE 3.10 is available - if(NOT (${VTK_VERSION} VERSION_LESS 9.0)) - target_link_libraries(pcl_pcd_video_player VTK::GUISupportQt) - endif() + PCL_ADD_EXECUTABLE(pcl_manual_registration + COMPONENT + ${SUBSYS_NAME} + SOURCES + include/pcl/apps/manual_registration.h + src/manual_registration/manual_registration.cpp + src/manual_registration/manual_registration.ui + BUNDLE) + + target_link_libraries(pcl_manual_registration pcl_common pcl_io pcl_visualization pcl_segmentation pcl_features pcl_surface ${QTX}::Widgets) + + PCL_ADD_EXECUTABLE(pcl_pcd_video_player + COMPONENT + ${SUBSYS_NAME} + SOURCES + include/pcl/apps/pcd_video_player.h + src/pcd_video_player/pcd_video_player.cpp + src/pcd_video_player/pcd_video_player.ui + BUNDLE) + + target_link_libraries(pcl_pcd_video_player pcl_common pcl_io pcl_visualization pcl_segmentation pcl_features pcl_surface ${QTX}::Widgets) endif() if(WITH_OPENNI) @@ -146,28 +152,34 @@ if(VTK_FOUND) target_link_libraries(pcl_openni_organized_edge_detection pcl_common pcl_io pcl_features pcl_visualization) PCL_ADD_EXECUTABLE(pcl_openni_face_detector COMPONENT ${SUBSYS_NAME} SOURCES src/face_detection//openni_face_detection.cpp src/face_detection//openni_frame_source.cpp BUNDLE) - target_link_libraries(pcl_openni_face_detector pcl_features pcl_recognition pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_sample_consensus pcl_surface pcl_keypoints pcl_ml pcl_search pcl_kdtree ${VTK_LIBRARIES}) + target_link_libraries(pcl_openni_face_detector pcl_features pcl_recognition pcl_common pcl_io pcl_filters pcl_visualization pcl_segmentation pcl_sample_consensus pcl_surface pcl_keypoints pcl_ml pcl_search pcl_kdtree) - if(Qt5_FOUND AND HAVE_QVTK) + if(QT_FOUND AND HAVE_QVTK) # OpenNI Passthrough application demo - QT5_WRAP_UI(openni_passthrough_ui src/openni_passthrough.ui) - QT5_WRAP_CPP(openni_passthrough_moc include/pcl/apps/openni_passthrough.h OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - PCL_ADD_EXECUTABLE(pcl_openni_passthrough COMPONENT ${SUBSYS_NAME} SOURCES ${openni_passthrough_ui} ${openni_passthrough_moc} src/openni_passthrough.cpp) - target_link_libraries(pcl_openni_passthrough pcl_common pcl_io pcl_filters pcl_visualization Qt5::Widgets) - #TODO: Update when CMAKE 3.10 is available - if(NOT (${VTK_VERSION} VERSION_LESS 9.0)) - target_link_libraries(pcl_openni_passthrough VTK::GUISupportQt) - endif() + PCL_ADD_EXECUTABLE(pcl_openni_passthrough + COMPONENT + ${SUBSYS_NAME} + SOURCES + include/pcl/apps/openni_passthrough.h + src/openni_passthrough.cpp + src/openni_passthrough.ui) + + target_link_libraries(pcl_openni_passthrough pcl_common pcl_io pcl_filters pcl_visualization ${QTX}::Widgets) + + list(APPEND CMAKE_AUTOUIC_SEARCH_PATHS "src") # OpenNI Organized Connected Component application demo - QT5_WRAP_UI(organized_segmentation_demo_ui src/organized_segmentation_demo.ui) - QT5_WRAP_CPP(organized_segmentation_demo_moc include/pcl/apps/organized_segmentation_demo.h OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - PCL_ADD_EXECUTABLE(pcl_organized_segmentation_demo COMPONENT ${SUBSYS_NAME} SOURCES ${organized_segmentation_demo_ui} ${organized_segmentation_demo_moc} src/organized_segmentation_demo.cpp BUNDLE) - target_link_libraries(pcl_organized_segmentation_demo pcl_common pcl_io pcl_visualization pcl_segmentation pcl_features pcl_surface Qt5::Widgets) - #TODO: Update when CMAKE 3.10 is available - if(NOT (${VTK_VERSION} VERSION_LESS 9.0)) - target_link_libraries(pcl_organized_segmentation_demo VTK::GUISupportQt) - endif() + PCL_ADD_EXECUTABLE(pcl_organized_segmentation_demo + COMPONENT + ${SUBSYS_NAME} + SOURCES + include/pcl/apps/organized_segmentation_demo_qt.h + include/pcl/apps/organized_segmentation_demo.h + src/organized_segmentation_demo.cpp + src/organized_segmentation_demo.ui + BUNDLE) + target_link_libraries(pcl_organized_segmentation_demo pcl_common pcl_io pcl_visualization pcl_segmentation pcl_features pcl_surface ${QTX}::Widgets) + endif() if(QHULL_FOUND) diff --git a/apps/cloud_composer/CMakeLists.txt b/apps/cloud_composer/CMakeLists.txt index 80a9a27a3d0..c9223a9efbb 100644 --- a/apps/cloud_composer/CMakeLists.txt +++ b/apps/cloud_composer/CMakeLists.txt @@ -6,24 +6,7 @@ set(SUBSUBSYS_NAME cloud_composer) set(SUBSUBSYS_DESC "Cloud Composer - Application for Manipulating Point Clouds") set(SUBSUBSYS_DEPS common io visualization filters apps) - -# Find VTK -if(NOT VTK_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "VTK was not found.") -else() - set(DEFAULT TRUE) - set(REASON) -endif() - -# QT5 Found? -if(NOT Qt5_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "Qt5 was not found.") -elseif(NOT ${DEFAULT} STREQUAL "AUTO_OFF") - set(DEFAULT TRUE) - set(REASON) -endif() +set(SUBSUBSYS_EXT_DEPS vtk ${QTX}) # QVTK? if(NOT HAVE_QVTK) @@ -40,7 +23,7 @@ if("${DEFAULT}" STREQUAL "TRUE") endif() PCL_SUBSUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" "${SUBSUBSYS_DESC}" ${DEFAULT} "${REASON}") -PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" DEPS ${SUBSUBSYS_DEPS} EXT_DEPS vtk) +PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" DEPS ${SUBSUBSYS_DEPS} EXT_DEPS ${SUBSUBSYS_EXT_DEPS}) PCL_ADD_DOC(${SUBSUBSYS_NAME}) @@ -89,15 +72,11 @@ set(INTERFACE_SOURCES # Build pcl_cc_tool_interface as static library, to fix issue mentioned in #2708 set(PCL_LIB_TYPE_ORIGIN ${PCL_LIB_TYPE}) set(PCL_LIB_TYPE STATIC) -QT5_WRAP_CPP(INTERFACE_HEADERS_MOC ${INTERFACE_HEADERS} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -PCL_ADD_LIBRARY(pcl_cc_tool_interface COMPONENT ${SUBSUBSYS_NAME} SOURCES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES} ${INTERFACE_HEADERS_MOC}) -set(vtk_libs ${VTK_LIBRARIES}) -#TODO: Update when CMAKE 3.10 is available -if (NOT (${VTK_VERSION} VERSION_LESS 9.0)) - set(vtk_libs VTK::GUISupportQt) -endif() -target_link_libraries(pcl_cc_tool_interface pcl_common pcl_filters pcl_search pcl_visualization Qt5::Widgets ${vtk_libs}) +PCL_ADD_LIBRARY(pcl_cc_tool_interface COMPONENT ${SUBSUBSYS_NAME} SOURCES ${INTERFACE_HEADERS} ${INTERFACE_SOURCES}) + + +target_link_libraries(pcl_cc_tool_interface pcl_common pcl_filters pcl_search pcl_visualization ${QTX}::Widgets) set(PCL_LIB_TYPE ${PCL_LIB_TYPE_ORIGIN}) @@ -114,7 +93,6 @@ set(incs "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/item_inspector.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/merge_selection.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/project_model.h" - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/properties_model.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/signal_multiplexer.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/toolbox_model.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/transform_clouds.h" @@ -147,13 +125,13 @@ set(impl_incs set(uis src/cloud_composer_main_window.ui) set(resources resources/resources.qrc) -QT5_WRAP_UI(cloud_composer_ui ${uis}) -QT5_WRAP_CPP(cloud_composer_moc ${incs} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) -QT5_ADD_RESOURCES(resource_srcs ${resources}) +list(APPEND CMAKE_AUTOUIC_SEARCH_PATHS "src") set(EXE_NAME "pcl_${SUBSUBSYS_NAME}") -PCL_ADD_EXECUTABLE(${EXE_NAME} COMPONENT ${SUBSUBSYS_NAME} SOURCES ${cloud_composer_ui} ${cloud_composer_moc} ${srcs} ${resource_srcs} ${impl_incs}) -target_link_libraries("${EXE_NAME}" pcl_cc_tool_interface pcl_common pcl_io pcl_visualization pcl_filters Qt5::Widgets) +PCL_ADD_EXECUTABLE(${EXE_NAME} COMPONENT ${SUBSUBSYS_NAME} SOURCES ${uis} ${incs} ${srcs} ${resources} ${impl_incs}) +target_link_libraries("${EXE_NAME}" pcl_cc_tool_interface pcl_common pcl_io pcl_visualization pcl_filters ${QTX}::Widgets) + + # Install include files PCL_ADD_INCLUDES("${SUBSUBSYS_NAME}" "${SUBSUBSYS_NAME}" ${incs} ${item_incs} ${selector_incs}) diff --git a/apps/cloud_composer/ComposerTool.cmake b/apps/cloud_composer/ComposerTool.cmake index 6ba49c8d7db..bf6d80b64da 100644 --- a/apps/cloud_composer/ComposerTool.cmake +++ b/apps/cloud_composer/ComposerTool.cmake @@ -3,23 +3,21 @@ function(define_composer_tool TOOL_NAME TOOL_SOURCES TOOL_HEADERS DEPS) project(pcl_cc_tool_${TOOL_NAME}) - #message("Making plugin " pcl_cc_tool_${TOOL_NAME}) - QT5_WRAP_CPP(TOOL_HEADERS_MOC ${TOOL_HEADERS} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) set(TOOL_TARGET pcl_cc_tool_${TOOL_NAME}) - # message("Files:" ${TOOL_SOURCES} ${TOOL_HEADERS_MOC}) - PCL_ADD_LIBRARY(${TOOL_TARGET} COMPONENT ${SUBSYS_NAME} SOURCES ${TOOL_SOURCES} ${TOOL_HEADERS} ${TOOL_HEADERS_MOC}) + PCL_ADD_LIBRARY(${TOOL_TARGET} COMPONENT ${SUBSYS_NAME} SOURCES ${TOOL_SOURCES} ${TOOL_HEADERS}) + if(WIN32) set_target_properties (${TOOL_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CLOUD_COMPOSER_PLUGIN_DIR} RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CLOUD_COMPOSER_PLUGIN_DIR}) else() set_target_properties (${TOOL_TARGET} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CLOUD_COMPOSER_PLUGIN_DIR}) endif() + add_definitions(${QT_DEFINITIONS}) add_definitions(-DQT_PLUGIN) - add_definitions(-DQT_NO_DEBUG) add_definitions(-DQT_SHARED) - target_link_libraries(${TOOL_TARGET} pcl_cc_tool_interface pcl_common pcl_io ${DEPS} Qt5::Widgets) + target_link_libraries(${TOOL_TARGET} pcl_cc_tool_interface pcl_common pcl_io ${DEPS} ${QTX}::Widgets) if(APPLE) set_target_properties(${TOOL_TARGET} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") diff --git a/apps/cloud_composer/include/pcl/apps/cloud_composer/cloud_composer.h b/apps/cloud_composer/include/pcl/apps/cloud_composer/cloud_composer.h index ec7e0be11ee..9fbfdcc5b17 100644 --- a/apps/cloud_composer/include/pcl/apps/cloud_composer/cloud_composer.h +++ b/apps/cloud_composer/include/pcl/apps/cloud_composer/cloud_composer.h @@ -42,6 +42,7 @@ #include #include + class QTreeView; namespace pcl diff --git a/apps/cloud_composer/include/pcl/apps/cloud_composer/tools/impl/organized_segmentation.hpp b/apps/cloud_composer/include/pcl/apps/cloud_composer/tools/impl/organized_segmentation.hpp index 1b32f201fe0..708ea1f34b1 100644 --- a/apps/cloud_composer/include/pcl/apps/cloud_composer/tools/impl/organized_segmentation.hpp +++ b/apps/cloud_composer/include/pcl/apps/cloud_composer/tools/impl/organized_segmentation.hpp @@ -122,7 +122,7 @@ pcl::cloud_composer::OrganizedSegmentationTool::performTemplatedAction (const QL euclidean_segmentation.setInputCloud (input_cloud); euclidean_segmentation.segment (euclidean_labels, euclidean_label_indices); - pcl::IndicesPtr extracted_indices (new std::vector ()); + pcl::IndicesPtr extracted_indices (new pcl::Indices ()); for (std::size_t i = 0; i < euclidean_label_indices.size (); i++) { if (euclidean_label_indices[i].indices.size () >= (std::size_t) min_cluster_size) diff --git a/apps/cloud_composer/tools/euclidean_clustering.cpp b/apps/cloud_composer/tools/euclidean_clustering.cpp index 4a52dd75c1e..13f5d914dbb 100644 --- a/apps/cloud_composer/tools/euclidean_clustering.cpp +++ b/apps/cloud_composer/tools/euclidean_clustering.cpp @@ -69,7 +69,7 @@ pcl::cloud_composer::EuclideanClusteringTool::performAction (ConstItemList input Eigen::Vector4f source_origin = input_item->data (ItemDataRole::ORIGIN).value (); Eigen::Quaternionf source_orientation = input_item->data (ItemDataRole::ORIENTATION).value (); //Vector to accumulate the extracted indices - pcl::IndicesPtr extracted_indices (new std::vector ()); + pcl::IndicesPtr extracted_indices (new pcl::Indices ()); //Put found clusters into new cloud_items! qDebug () << "Found "< #include diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/common_types.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/common_types.h index f963aa9afda..d5c32ceaa90 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/common_types.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/common_types.h @@ -40,55 +40,52 @@ #pragma once -#include - +#include #include #include -#include -namespace pcl -{ - namespace ihs - { - struct PointIHS; - using CloudIHS = pcl::PointCloud; - using CloudIHSPtr = CloudIHS::Ptr; - using CloudIHSConstPtr = CloudIHS::ConstPtr; - } // End namespace ihs +#include + +namespace pcl { +namespace ihs { +struct PointIHS; +using CloudIHS = pcl::PointCloud; +using CloudIHSPtr = CloudIHS::Ptr; +using CloudIHSConstPtr = CloudIHS::ConstPtr; +} // End namespace ihs } // End namespace pcl #include -POINT_CLOUD_REGISTER_POINT_STRUCT (pcl::ihs::_PointIHS, - (float, x, x) - (float, y, y) - (float, z, z) - (float, normal_x, normal_x) - (float, normal_y, normal_y) - (float, normal_z, normal_z) - (float, rgb, rgb) - (float, weight, weight) - (unsigned int, age, age) - (std::uint32_t, directions, directions) - ) -POINT_CLOUD_REGISTER_POINT_WRAPPER (pcl::ihs::PointIHS, pcl::ihs::_PointIHS) +// clang-format off +POINT_CLOUD_REGISTER_POINT_STRUCT(pcl::ihs::_PointIHS, + (float, x, x) + (float, y, y) + (float, z, z) + (float, normal_x, normal_x) + (float, normal_y, normal_y) + (float, normal_z, normal_z) + (float, rgb, rgb) + (float, weight, weight) + (unsigned int, age, age) + (std::uint32_t, directions, directions) + ) +POINT_CLOUD_REGISTER_POINT_WRAPPER(pcl::ihs::PointIHS, pcl::ihs::_PointIHS) +// clang-format on -namespace pcl -{ - namespace ihs - { - struct MeshTraits - { - using VertexData = PointIHS; - using HalfEdgeData = pcl::geometry::NoData; - using EdgeData = pcl::geometry::NoData; - using FaceData = pcl::geometry::NoData; - using IsManifold = std::true_type; - }; +namespace pcl { +namespace ihs { +struct MeshTraits { + using VertexData = PointIHS; + using HalfEdgeData = pcl::geometry::NoData; + using EdgeData = pcl::geometry::NoData; + using FaceData = pcl::geometry::NoData; + using IsManifold = std::true_type; +}; - // NOTE: The drawMesh method in pcl::ihs::InHandScanner only supports triangles! - using Mesh = pcl::geometry::TriangleMesh; - using MeshPtr = Mesh::Ptr; - using MeshConstPtr = Mesh::ConstPtr; - } // End namespace ihs +// NOTE: The drawMesh method in pcl::ihs::InHandScanner only supports triangles! +using Mesh = pcl::geometry::TriangleMesh; +using MeshPtr = Mesh::Ptr; +using MeshConstPtr = Mesh::ConstPtr; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/eigen.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/eigen.h index 7c1208e399b..a4380316268 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/eigen.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/eigen.h @@ -41,9 +41,9 @@ #pragma once #ifdef __GNUC__ -# pragma GCC system_header +#pragma GCC system_header #endif - +PCL_DEPRECATED_HEADER(1, 15, "Please include the needed eigen headers directly.") +#include #include #include -#include diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/help_window.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/help_window.h index abfdbd89297..dd88d34f261 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/help_window.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/help_window.h @@ -42,25 +42,21 @@ #include -namespace Ui -{ - class HelpWindow; +namespace Ui { +class HelpWindow; } -namespace pcl -{ - namespace ihs - { - class HelpWindow : public QDialog - { - Q_OBJECT +namespace pcl { +namespace ihs { +class HelpWindow : public QDialog { + Q_OBJECT - public: - explicit HelpWindow (QWidget* parent = nullptr); - ~HelpWindow (); +public: + explicit HelpWindow(QWidget* parent = nullptr); + ~HelpWindow(); - private: - Ui::HelpWindow* ui; - }; - } // End namespace ihs +private: + Ui::HelpWindow* ui; +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/icp.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/icp.h index 46991846e50..7496c578f0a 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/icp.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/icp.h @@ -40,174 +40,200 @@ #pragma once -#include -#include -#include #include #include +#include //////////////////////////////////////////////////////////////////////////////// // ICP //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - /** \brief Iterative Closest Point registration. - * \author Martin Saelzle - * \ingroup apps - */ - class PCL_EXPORTS ICP - { - public: - - using PointXYZRGBNormal = pcl::PointXYZRGBNormal; - using CloudXYZRGBNormal = pcl::PointCloud; - using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; - using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - - using Mesh = pcl::ihs::Mesh; - using MeshPtr = pcl::ihs::MeshPtr; - using MeshConstPtr = pcl::ihs::MeshConstPtr; - - /** \brief Constructor */ - ICP (); - - /** @{ */ - /** \brief Convergence is detected when the change of the fitness between the current and previous iteration becomes smaller than the given epsilon (set in cm^2). The fitness is the mean squared euclidean distance between corresponding points. - * \note Only accepted if it is greater than 0. - */ - void - setEpsilon (const float epsilon); - - float - getEpsilon () const; - /** @} */ - - /** @{ */ - /** \brief The registration fails if the number of iterations exceeds the maximum number of iterations. - * \note Must be greater than 0. Smaller values are set to 1. - */ - void - setMaxIterations (const unsigned int max_iter); - - unsigned int - getMaxIterations () const; - /** @} */ - - /** @{ */ - /** \brief The registration fails at the state of convergence if the overlap between the model and data shape is smaller than a minimum overlap. The overlap is the fraction of correspondences (after rejection) to the initial number of data points. - * \note Must be between zero and one. Values outside this range are clamped to the nearest valid value. - */ - void - setMinOverlap (const float overlap); - - float - getMinOverlap () const; - /** @} */ - - /** @{ */ - /** \brief The registration fails at the state of convergence if the fitness is bigger than this threshold (set in cm^2) - * \note Must be greater than zero. - */ - void - setMaxFitness (const float fitness); - - float - getMaxFitness () const; - /** @} */ - - /** @{ */ - /** \brief Correspondences are rejected if the squared distance is above a threshold. This threshold is initialized with infinity (all correspondences are accepted in the first iteration). The threshold of the next iterations is set to the fitness of the current iteration multiplied by the factor set by this method. - * \note Must be greater or equal one. Smaller values are set to one. - */ - void - setCorrespondenceRejectionFactor (const float factor); - - float - getCorrespondenceRejectionFactor () const; - /** @} */ - - /** @{ */ - /** \brief Correspondences are rejected if the angle between the normals is bigger than this threshold. Set in degrees. - * \note Must be between 180 degrees and 0. Values outside this range are clamped to the nearest valid value. - */ - void - setMaxAngle (const float angle); - - float - getMaxAngle () const; - /** @} */ - - /** \brief Find the transformation that aligns the data cloud (source) to the model mesh (target). - * \param[in] mesh_model Model mesh (target). - * \param[in] cloud_data Data cloud (source). - * \param[in] T_init Initial guess for the transformation. - * \paran[out] T_final The computed transformation. - * \return true if success. - */ - bool - findTransformation (const MeshConstPtr& mesh_model, - const CloudXYZRGBNormalConstPtr& cloud_data, - const Eigen::Matrix4f& T_init, - Eigen::Matrix4f& T_final); - - private: - - using PointNormal = pcl::PointNormal; - using CloudNormal = pcl::PointCloud; - using CloudNormalPtr = CloudNormal::Ptr; - using CloudNormalConstPtr = CloudNormal::ConstPtr; - - using KdTree = pcl::KdTree; - using KdTreePtr = KdTree::Ptr; - using KdTreeConstPtr = KdTree::ConstPtr; - - /** \brief Selects the model points that are pointing towards to the camera (data coordinate system = camera coordinate system). - * \param[in] mesh_model Input mesh. - * \param[in] T_inv Transformation that brings the model mesh into the camera coordinate system. - * \return Cloud containing the selected points (the connectivity information of the mesh is currently not used during the registration). - */ - CloudNormalConstPtr - selectModelPoints (const MeshConstPtr& mesh_model, - const Eigen::Matrix4f& T_inv) const; - - /** \brief Selects the valid data points. The input cloud is organized -> contains nans which are removed - * \param[in] cloud_data Input cloud. - * \return Cloud containing the selected points. - */ - CloudNormalConstPtr - selectDataPoints (const CloudXYZRGBNormalConstPtr& cloud_data) const; - - /** \brief Finds the transformation that minimizes the point to plane distance from the source to the target cloud. The input clouds must be arranged to have one to one correspondences (point 0 in source corresponds to point 0 in target, point 1 in source to point 1 in target and so on). - * \param[in] cloud_source Source cloud (data). - * \param[in] cloud_target Target cloud (model). - * \param[out] T The computed transformation. - * \return true if success - */ - bool - minimizePointPlane (const CloudNormal& cloud_source, - const CloudNormal& cloud_target, - Eigen::Matrix4f& T) const; - - //////////////////////////////////////////////////////////////////////// - // Members - //////////////////////////////////////////////////////////////////////// - - KdTreePtr kd_tree_; - - // Convergence - float epsilon_; // in cm^2 - - // Registration failure - unsigned int max_iterations_; - float min_overlap_; // [0 1] - float max_fitness_; // in cm^2 - - // Correspondence rejection - float factor_; - float max_angle_; // in degrees - }; - } // End namespace ihs +namespace pcl { +namespace ihs { +/** \brief Iterative Closest Point registration. + * \author Martin Saelzle + * \ingroup apps + */ +class PCL_EXPORTS ICP { +public: + using PointXYZRGBNormal = pcl::PointXYZRGBNormal; + using CloudXYZRGBNormal = pcl::PointCloud; + using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; + using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; + + using Mesh = pcl::ihs::Mesh; + using MeshPtr = pcl::ihs::MeshPtr; + using MeshConstPtr = pcl::ihs::MeshConstPtr; + + /** \brief Constructor */ + ICP(); + + /** @{ */ + /** \brief Convergence is detected when the change of the fitness between the current + * and previous iteration becomes smaller than the given epsilon (set in cm^2). The + * fitness is the mean squared euclidean distance between corresponding points. + * + * \note Only accepted if it is greater than 0. + */ + void + setEpsilon(const float epsilon); + + float + getEpsilon() const; + /** @} */ + + /** @{ */ + /** \brief The registration fails if the number of iterations exceeds the maximum + * number of iterations. + * + * \note Must be greater than 0. Smaller values are set to 1. + */ + void + setMaxIterations(const unsigned int max_iter); + + unsigned int + getMaxIterations() const; + /** @} */ + + /** @{ */ + /** \brief The registration fails at the state of convergence if the overlap between + * the model and data shape is smaller than a minimum overlap. The overlap is the + * fraction of correspondences (after rejection) to the initial number of data points. + * + * \note Must be between zero and one. Values outside this range are clamped to the + * nearest valid value. + */ + void + setMinOverlap(const float overlap); + + float + getMinOverlap() const; + /** @} */ + + /** @{ */ + /** \brief The registration fails at the state of convergence if the fitness is bigger + * than this threshold (set in cm^2) + * + * \note Must be greater than zero. + */ + void + setMaxFitness(const float fitness); + + float + getMaxFitness() const; + /** @} */ + + /** @{ */ + /** \brief Correspondences are rejected if the squared distance is above a threshold. + * This threshold is initialized with infinity (all correspondences are accepted in + * the first iteration). The threshold of the next iterations is set to the fitness of + * the current iteration multiplied by the factor set by this method. + * + * \note Must be greater or equal one. Smaller values are set to one. + */ + void + setCorrespondenceRejectionFactor(const float factor); + + float + getCorrespondenceRejectionFactor() const; + /** @} */ + + /** @{ */ + /** \brief Correspondences are rejected if the angle between the normals is bigger + * than this threshold. Set in degrees. + * + * \note Must be between 180 degrees and 0. Values outside this range are clamped to + * the nearest valid value. + */ + void + setMaxAngle(const float angle); + + float + getMaxAngle() const; + /** @} */ + + /** \brief Find the transformation that aligns the data cloud (source) to the model + * mesh (target). + * + * \param[in] mesh_model Model mesh (target). + * \param[in] cloud_data Data cloud (source). + * \param[in] T_init Initial guess for the transformation. + * \param[out] T_final The computed transformation. + * + * \return true if success. + */ + bool + findTransformation(const MeshConstPtr& mesh_model, + const CloudXYZRGBNormalConstPtr& cloud_data, + const Eigen::Matrix4f& T_init, + Eigen::Matrix4f& T_final); + +private: + using PointNormal = pcl::PointNormal; + using CloudNormal = pcl::PointCloud; + using CloudNormalPtr = CloudNormal::Ptr; + using CloudNormalConstPtr = CloudNormal::ConstPtr; + + using KdTree = pcl::KdTree; + using KdTreePtr = KdTree::Ptr; + using KdTreeConstPtr = KdTree::ConstPtr; + + /** \brief Selects the model points that are pointing towards to the camera (data + * coordinate system = camera coordinate system). + * + * \param[in] mesh_model Input mesh. + * \param[in] T_inv Transformation that brings the model mesh into the camera + * coordinate system. + * + * \return Cloud containing the selected points (the connectivity + * information of the mesh is currently not used during the registration). + */ + CloudNormalConstPtr + selectModelPoints(const MeshConstPtr& mesh_model, const Eigen::Matrix4f& T_inv) const; + + /** \brief Selects the valid data points. The input cloud is organized -> contains + * nans which are removed + * + * \param[in] cloud_data Input cloud. + * + * \return Cloud containing the selected points. + */ + CloudNormalConstPtr + selectDataPoints(const CloudXYZRGBNormalConstPtr& cloud_data) const; + + /** \brief Finds the transformation that minimizes the point to plane distance from + * the source to the target cloud. The input clouds must be arranged to have one to + * one correspondences (point 0 in source corresponds to point 0 in target, point 1 in + * source to point 1 in target and so on). + * + * \param[in] cloud_source Source cloud (data). + * \param[in] cloud_target Target cloud (model). + * \param[out] T The computed transformation. + * + * \return true if success + */ + bool + minimizePointPlane(const CloudNormal& cloud_source, + const CloudNormal& cloud_target, + Eigen::Matrix4f& T) const; + + //////////////////////////////////////////////////////////////////////// + // Members + //////////////////////////////////////////////////////////////////////// + + KdTreePtr kd_tree_; + + // Convergence + float epsilon_; // in cm^2 + + // Registration failure + unsigned int max_iterations_; + float min_overlap_; // [0 1] + float max_fitness_; // in cm^2 + + // Correspondence rejection + float factor_; + float max_angle_; // in degrees +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/impl/common_types.hpp b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/impl/common_types.hpp index 76f82bc3036..17900bf5347 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/impl/common_types.hpp +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/impl/common_types.hpp @@ -41,90 +41,98 @@ #ifndef PCL_APPS_IN_HAND_SCANNER_IMPL_COMMON_TYPES_HPP #define PCL_APPS_IN_HAND_SCANNER_IMPL_COMMON_TYPES_HPP -#include - #include #include -namespace pcl -{ - namespace ihs +#include + +namespace pcl { +namespace ihs { +struct EIGEN_ALIGN16 _PointIHS { + PCL_ADD_POINT4D + PCL_ADD_NORMAL4D + PCL_ADD_RGB + float weight; + unsigned int age; + std::uint32_t directions; + + PCL_MAKE_ALIGNED_OPERATOR_NEW +}; + +struct PointIHS : public pcl::ihs::_PointIHS { + // NOTE: I rely on NaN in the default constructor! + inline PointIHS() + { + this->x = this->y = this->z = std::numeric_limits::quiet_NaN(); + this->data[3] = 1.f; + + this->normal_x = this->normal_y = this->normal_z = + std::numeric_limits::quiet_NaN(); + this->data_n[3] = 0.f; + + this->b = this->g = this->r = 0; + this->a = 255; + + this->weight = 0.f; + this->age = 0; + this->directions = 0; + } + + inline PointIHS(const PointIHS& other) { - struct EIGEN_ALIGN16 _PointIHS - { - PCL_ADD_POINT4D - PCL_ADD_NORMAL4D - PCL_ADD_RGB - float weight; - unsigned int age; - std::uint32_t directions; - - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; - - struct PointIHS : public pcl::ihs::_PointIHS - { - // NOTE: I rely on NaN in the default constructor! - inline PointIHS () - { - this->x = this->y = this->z = std::numeric_limits::quiet_NaN (); - this->data[3] = 1.f; - - this->normal_x = this->normal_y = this->normal_z = std::numeric_limits::quiet_NaN (); - this->data_n[3] = 0.f; - - this->b = this->g = this->r = 0; this->a = 255; - - this->weight = 0.f; - this->age = 0; - this->directions = 0; - } - - inline PointIHS (const PointIHS& other) - { - this->x = other.x; - this->y = other.y; - this->z = other.z; - this->data[3] = other.data[3]; - - this->normal_x = other.normal_x; - this->normal_y = other.normal_y; - this->normal_z = other.normal_z; - this->data_n[3] = other.data_n[3]; - - this->rgba = other.rgba; - - this->weight = other.weight; - this->age = other.age; - this->directions = other.directions; - } - - inline PointIHS (const pcl::PointXYZRGBNormal& other, const float weight) - { - this->x = other.x; - this->y = other.y; - this->z = other.z; - this->data[3] = other.data[3]; - - this->normal_x = other.normal_x; - this->normal_y = other.normal_y; - this->normal_z = other.normal_z; - this->data_n[3] = other.data_n[3]; - - this->rgba = other.rgba; - - this->weight = weight; - this->age = 0; - this->directions = 0; - } - - // inline Eigen::Vector3i getRGBVector3i () {return (Eigen::Vector3i (r, g, b));} - inline const Eigen::Vector3i getRGBVector3i () const {return (Eigen::Vector3i (r, g, b));} - // inline Eigen::Vector4i getRGBVector4i () {return (Eigen::Vector4i (r, g, b, a));} - inline const Eigen::Vector4i getRGBVector4i () const {return (Eigen::Vector4i (r, g, b, a));} - }; - - } // End namespace ihs + this->x = other.x; + this->y = other.y; + this->z = other.z; + this->data[3] = other.data[3]; + + this->normal_x = other.normal_x; + this->normal_y = other.normal_y; + this->normal_z = other.normal_z; + this->data_n[3] = other.data_n[3]; + + this->rgba = other.rgba; + + this->weight = other.weight; + this->age = other.age; + this->directions = other.directions; + } + + inline PointIHS& + operator=(const PointIHS& other) = default; + + inline PointIHS(const pcl::PointXYZRGBNormal& other, const float weight) + { + this->x = other.x; + this->y = other.y; + this->z = other.z; + this->data[3] = other.data[3]; + + this->normal_x = other.normal_x; + this->normal_y = other.normal_y; + this->normal_z = other.normal_z; + this->data_n[3] = other.data_n[3]; + + this->rgba = other.rgba; + + this->weight = weight; + this->age = 0; + this->directions = 0; + } + + inline const Eigen::Vector3i + getRGBVector3i() const + { + return (Eigen::Vector3i(r, g, b)); + } + + inline const Eigen::Vector4i + getRGBVector4i() const + { + return (Eigen::Vector4i(r, g, b, a)); + } +}; + +} // End namespace ihs } // End namespace pcl #endif // PCL_APPS_IN_HAND_SCANNER_IMPL_COMMON_TYPES_HPP diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/in_hand_scanner.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/in_hand_scanner.h index b972e66893e..80ab152167a 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/in_hand_scanner.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/in_hand_scanner.h @@ -40,271 +40,278 @@ #pragma once +#include +#include #include #include #include -#include -#include -#include +#include // for connection + +#include #include -#include #include -#include +#include //////////////////////////////////////////////////////////////////////////////// // Forward declarations //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - class OpenNIGrabber; +namespace pcl { +class OpenNIGrabber; - namespace ihs - { - class ICP; - class InputDataProcessing; - class Integration; - class MeshProcessing; - } // End namespace ihs +namespace ihs { +class ICP; +class InputDataProcessing; +class Integration; +class MeshProcessing; +} // End namespace ihs } // End namespace pcl //////////////////////////////////////////////////////////////////////////////// // InHandScanner //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs +namespace pcl { +namespace ihs { +/** \brief + * \todo Add Documentation + */ +class PCL_EXPORTS InHandScanner : public pcl::ihs::OpenGLViewer { + Q_OBJECT + +public: + using Base = pcl::ihs::OpenGLViewer; + using Self = pcl::ihs::InHandScanner; + + using InputDataProcessing = pcl::ihs::InputDataProcessing; + using InputDataProcessingPtr = std::shared_ptr; + using InputDataProcessingConstPtr = std::shared_ptr; + + using ICP = pcl::ihs::ICP; + using ICPPtr = std::shared_ptr; + using ICPConstPtr = std::shared_ptr; + + using Integration = pcl::ihs::Integration; + using IntegrationPtr = std::shared_ptr; + using IntegrationConstPtr = std::shared_ptr; + + using MeshProcessing = pcl::ihs::MeshProcessing; + using MeshProcessingPtr = std::shared_ptr; + using MeshProcessingConstPtr = std::shared_ptr; + + /** \brief Switch between different branches of the scanning pipeline. */ + enum RunningMode { + RM_SHOW_MODEL = 0, /**< Shows the model shape (if it is available). */ + RM_UNPROCESSED = 1, /**< Shows the unprocessed input data. */ + RM_PROCESSED = 2, /**< Shows the processed input data. */ + RM_REGISTRATION_CONT = + 3, /**< Registers new data to the first acquired data continuously. */ + RM_REGISTRATION_SINGLE = + 4 /**< Registers new data once and returns to showing the processed data. */ + }; + + /** \brief File type for saving and loading files. */ + enum FileType { + FT_PLY = 0, /**< Polygon File Format. */ + FT_VTK = 1 /**< VTK File Format. */ + }; + + /** \brief Constructor. */ + explicit InHandScanner(Base* parent = nullptr); + + /** \brief Destructor. */ + ~InHandScanner(); + + /** \brief Get the input data processing. */ + inline InputDataProcessing& + getInputDataProcessing() { - /** \brief - * \todo Add Documentation - */ - class PCL_EXPORTS InHandScanner : public pcl::ihs::OpenGLViewer - { - Q_OBJECT - - public: - - using Base = pcl::ihs::OpenGLViewer; - using Self = pcl::ihs::InHandScanner; - - using InputDataProcessing = pcl::ihs::InputDataProcessing; - using InputDataProcessingPtr = std::shared_ptr; - using InputDataProcessingConstPtr = std::shared_ptr; - - using ICP = pcl::ihs::ICP; - using ICPPtr = std::shared_ptr; - using ICPConstPtr = std::shared_ptr; - - using Integration = pcl::ihs::Integration; - using IntegrationPtr = std::shared_ptr; - using IntegrationConstPtr = std::shared_ptr; - - using MeshProcessing = pcl::ihs::MeshProcessing; - using MeshProcessingPtr = std::shared_ptr; - using MeshProcessingConstPtr = std::shared_ptr; - - /** \brief Switch between different branches of the scanning pipeline. */ - enum RunningMode - { - RM_SHOW_MODEL = 0, /**< Shows the model shape (if it is available). */ - RM_UNPROCESSED = 1, /**< Shows the unprocessed input data. */ - RM_PROCESSED = 2, /**< Shows the processed input data. */ - RM_REGISTRATION_CONT = 3, /**< Registers new data to the first acquired data continuously. */ - RM_REGISTRATION_SINGLE = 4 /**< Registers new data once and returns to showing the processed data. */ - }; - - /** \brief File type for saving and loading files. */ - enum FileType - { - FT_PLY = 0, /**< Polygon File Format. */ - FT_VTK = 1 /**< VTK File Format. */ - }; - - /** \brief Constructor. */ - explicit InHandScanner (Base* parent=nullptr); - - /** \brief Destructor. */ - ~InHandScanner (); - - /** \brief Get the input data processing. */ - inline InputDataProcessing& - getInputDataProcessing () {return (*input_data_processing_);} - - /** \brief Get the registration. */ - inline ICP& - getICP () {return (*icp_);} - - /** \brief Get the integration. */ - inline Integration& - getIntegration () {return (*integration_);} - - Q_SIGNALS: - - /** \brief Emitted when the running mode changes. */ - void - runningModeChanged (RunningMode new_running_mode) const; - - public Q_SLOTS: - - /** \brief Start the grabber (enables the scanning pipeline). */ - void - startGrabber (); - - /** \brief Shows the unprocessed input data. */ - void - showUnprocessedData (); - - /** \brief Shows the processed input data. */ - void - showProcessedData (); - - /** \brief Registers new data to the first acquired data continuously. */ - void - registerContinuously (); - - /** \brief Registers new data once and returns to showing the processed data. */ - void - registerOnce (); - - /** \brief Show the model shape (if one is available). */ - void - showModel (); - - /** \brief Removes unfit vertices regardless of their age. Unfit vertices are those that have not been observed from enough directions. */ - void - removeUnfitVertices (); - - /** \brief Reset the scanning pipeline. */ - void - reset (); - - /** \brief Saves the model mesh in a file with the given filename and filetype. - * \note The extension of the filename is ignored! - */ - void - saveAs (const std::string& filename, const FileType& filetype); - - /** \see http://doc.qt.digia.com/qt/qwidget.html#keyPressEvent */ - void - keyPressEvent (QKeyEvent* event) override; - - private: - - using PointXYZRGBA = pcl::PointXYZRGBA; - using CloudXYZRGBA = pcl::PointCloud; - using CloudXYZRGBAPtr = CloudXYZRGBA::Ptr; - using CloudXYZRGBAConstPtr = CloudXYZRGBA::ConstPtr; - - using PointXYZRGBNormal = pcl::PointXYZRGBNormal; - using CloudXYZRGBNormal = pcl::PointCloud; - using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; - using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - - using PointIHS = pcl::ihs::PointIHS; - using CloudIHS = pcl::ihs::CloudIHS; - using CloudIHSPtr = pcl::ihs::CloudIHSPtr; - using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; - - using Mesh = pcl::ihs::Mesh; - using MeshPtr = pcl::ihs::MeshPtr; - using MeshConstPtr = pcl::ihs::MeshConstPtr; - - using Grabber = pcl::OpenNIGrabber; - using GrabberPtr = std::shared_ptr; - using GrabberConstPtr = std::shared_ptr; - - /** \brief Helper object for the computation thread. Please have a look at the documentation of calcFPS. */ - class ComputationFPS : public Base::FPS - { - public: - ComputationFPS () {} - ~ComputationFPS () {} - }; - - /** \brief Helper object for the visualization thread. Please have a look at the documentation of calcFPS. */ - class VisualizationFPS : public Base::FPS - { - public: - VisualizationFPS () {} - ~VisualizationFPS () {} - }; - - /** \brief Called when new data arries from the grabber. The grabbing - registration - integration pipeline is implemented here. */ - void - newDataCallback (const CloudXYZRGBAConstPtr& cloud_in); + return (*input_data_processing_); + } - /** \see http://doc.qt.digia.com/qt/qwidget.html#paintEvent - * \see http://doc.qt.digia.com/qt/opengl-overpainting.html - */ - void - paintEvent (QPaintEvent* event) override; - - /** \brief Draw text over the opengl scene. - * \see http://doc.qt.digia.com/qt/opengl-overpainting.html - */ - void - drawText (); - - /** \brief Actual implementeation of startGrabber (needed so it can be run in a different thread and doesn't block the application when starting up). */ - void - startGrabberImpl (); - - //////////////////////////////////////////////////////////////////////// - // Members - //////////////////////////////////////////////////////////////////////// - - /** \brief Synchronization. */ - std::mutex mutex_; - - /** \brief Please have a look at the documentation of ComputationFPS. */ - ComputationFPS computation_fps_; - - /** \brief Please have a look at the documentation of VisualizationFPS. */ - VisualizationFPS visualization_fps_; - - /** \brief Switch between different branches of the scanning pipeline. */ - RunningMode running_mode_; - - /** \brief The iteration of the scanning pipeline (grab - register - integrate). */ - unsigned int iteration_; - - /** \brief Used to get new data from the sensor. */ - GrabberPtr grabber_; - - /** \brief This variable is true if the grabber is starting. */ - bool starting_grabber_; - - /** \brief Connection of the grabber signal with the data processing thread. */ - boost::signals2::connection new_data_connection_; - - /** \brief Processes the data from the sensor. Output is input to the registration. */ - InputDataProcessingPtr input_data_processing_; - - /** \brief Registration (Iterative Closest Point). */ - ICPPtr icp_; - - /** \brief Transformation that brings the data cloud into model coordinates. */ - Eigen::Matrix4f transformation_; - - /** \brief Integrate the data cloud into a common model. */ - IntegrationPtr integration_; + /** \brief Get the registration. */ + inline ICP& + getICP() + { + return (*icp_); + } - /** \brief Methods called after the integration. */ - MeshProcessingPtr mesh_processing_; + /** \brief Get the integration. */ + inline Integration& + getIntegration() + { + return (*integration_); + } + +Q_SIGNALS: + + /** \brief Emitted when the running mode changes. */ + void + runningModeChanged(RunningMode new_running_mode) const; + +public Q_SLOTS: + + /** \brief Start the grabber (enables the scanning pipeline). */ + void + startGrabber(); + + /** \brief Shows the unprocessed input data. */ + void + showUnprocessedData(); + + /** \brief Shows the processed input data. */ + void + showProcessedData(); + + /** \brief Registers new data to the first acquired data continuously. */ + void + registerContinuously(); + + /** \brief Registers new data once and returns to showing the processed data. */ + void + registerOnce(); + + /** \brief Show the model shape (if one is available). */ + void + showModel(); + + /** \brief Removes unfit vertices regardless of their age. Unfit vertices are those + * that have not been observed from enough directions. */ + void + removeUnfitVertices(); + + /** \brief Reset the scanning pipeline. */ + void + reset(); + + /** \brief Saves the model mesh in a file with the given filename and filetype. + * + * \note The extension of the filename is ignored! + */ + void + saveAs(const std::string& filename, const FileType& filetype); + + /** \see http://doc.qt.digia.com/qt/qwidget.html#keyPressEvent */ + void + keyPressEvent(QKeyEvent* event) override; + +private: + using PointXYZRGBA = pcl::PointXYZRGBA; + using CloudXYZRGBA = pcl::PointCloud; + using CloudXYZRGBAPtr = CloudXYZRGBA::Ptr; + using CloudXYZRGBAConstPtr = CloudXYZRGBA::ConstPtr; + + using PointXYZRGBNormal = pcl::PointXYZRGBNormal; + using CloudXYZRGBNormal = pcl::PointCloud; + using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; + using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - /** \brief Model to which new data is registered to (stored as a mesh). */ - MeshPtr mesh_model_; + using PointIHS = pcl::ihs::PointIHS; + using CloudIHS = pcl::ihs::CloudIHS; + using CloudIHSPtr = pcl::ihs::CloudIHSPtr; + using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; + + using Mesh = pcl::ihs::Mesh; + using MeshPtr = pcl::ihs::MeshPtr; + using MeshConstPtr = pcl::ihs::MeshConstPtr; + + using Grabber = pcl::OpenNIGrabber; + using GrabberPtr = std::shared_ptr; + using GrabberConstPtr = std::shared_ptr; + + /** \brief Helper object for the computation thread. Please have a look at the + * documentation of calcFPS. */ + class ComputationFPS : public Base::FPS { + public: + ComputationFPS() {} + ~ComputationFPS() {} + }; + + /** \brief Helper object for the visualization thread. Please have a look at the + * documentation of calcFPS. */ + class VisualizationFPS : public Base::FPS { + public: + VisualizationFPS() {} + ~VisualizationFPS() {} + }; + + /** \brief Called when new data arries from the grabber. The grabbing - registration - + * integration pipeline is implemented here. */ + void + newDataCallback(const CloudXYZRGBAConstPtr& cloud_in); + + /** \see http://doc.qt.digia.com/qt/qwidget.html#paintEvent + * \see http://doc.qt.digia.com/qt/opengl-overpainting.html + */ + void + paintEvent(QPaintEvent* event) override; + + /** \brief Draw text over the opengl scene. + * \see http://doc.qt.digia.com/qt/opengl-overpainting.html + */ + void + drawText(); + + /** \brief Actual implementeation of startGrabber (needed so it can be run in a + * different thread and doesn't block the application when starting up). */ + void + startGrabberImpl(); + + //////////////////////////////////////////////////////////////////////// + // Members + //////////////////////////////////////////////////////////////////////// + + /** \brief Synchronization. */ + std::mutex mutex_; + + /** \brief Please have a look at the documentation of ComputationFPS. */ + ComputationFPS computation_fps_; + + /** \brief Please have a look at the documentation of VisualizationFPS. */ + VisualizationFPS visualization_fps_; + + /** \brief Switch between different branches of the scanning pipeline. */ + RunningMode running_mode_; + + /** \brief The iteration of the scanning pipeline (grab - register - integrate). */ + unsigned int iteration_; + + /** \brief Used to get new data from the sensor. */ + GrabberPtr grabber_; + + /** \brief This variable is true if the grabber is starting. */ + bool starting_grabber_; + + /** \brief Connection of the grabber signal with the data processing thread. */ + boost::signals2::connection new_data_connection_; + + /** \brief Processes the data from the sensor. Output is input to the registration. */ + InputDataProcessingPtr input_data_processing_; + + /** \brief Registration (Iterative Closest Point). */ + ICPPtr icp_; + + /** \brief Transformation that brings the data cloud into model coordinates. */ + Eigen::Matrix4f transformation_; + + /** \brief Integrate the data cloud into a common model. */ + IntegrationPtr integration_; + + /** \brief Methods called after the integration. */ + MeshProcessingPtr mesh_processing_; - /** \brief Prevent the application to crash while closing. */ - bool destructor_called_; + /** \brief Model to which new data is registered to (stored as a mesh). */ + MeshPtr mesh_model_; + + /** \brief Prevent the application to crash while closing. */ + bool destructor_called_; - public: - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; - } // End namespace ihs +public: + PCL_MAKE_ALIGNED_OPERATOR_NEW +}; +} // End namespace ihs } // End namespace pcl // http://doc.qt.digia.com/qt/qmetatype.html#Q_DECLARE_METATYPE -Q_DECLARE_METATYPE (pcl::ihs::InHandScanner::RunningMode) +Q_DECLARE_METATYPE(pcl::ihs::InHandScanner::RunningMode) diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/input_data_processing.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/input_data_processing.h index 63b9cc153e9..6c238fde75b 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/input_data_processing.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/input_data_processing.h @@ -40,192 +40,335 @@ #pragma once -#include -#include #include #include #include +#include //////////////////////////////////////////////////////////////////////////////// // InputDataProcessing //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - /** \brief Bundles methods that are applied to the input data from the sensor. - * \author Martin Saelzle - * \ingroup apps - */ - class PCL_EXPORTS InputDataProcessing - { - public: - - using PointXYZRGBA = pcl::PointXYZRGBA; - using CloudXYZRGBA = pcl::PointCloud; - using CloudXYZRGBAPtr = CloudXYZRGBA::Ptr; - using CloudXYZRGBAConstPtr = CloudXYZRGBA::ConstPtr; - - using PointXYZRGBNormal = pcl::PointXYZRGBNormal; - using CloudXYZRGBNormal = pcl::PointCloud; - using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; - using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - - /** \brief Constructor */ - InputDataProcessing (); - - /** \brief Apply the segmentation on the input cloud (XYZ and HSV). - * \param[in] cloud_in The input cloud. - * \param[out] cloud_out The segmented cloud. - * \param[out] cloud_discarded Cloud containing all points that were removed during the HSV segmentation. The points in the XYZ segmentation are NOT used! - * \return true if success. - * \note Converts from m to cm. - */ - bool - segment (const CloudXYZRGBAConstPtr& cloud_in, - CloudXYZRGBNormalPtr& cloud_out, - CloudXYZRGBNormalPtr& cloud_discarded) const; - - /** \brief Calculate the normals of the input cloud. - * \param[in] cloud_in The input cloud. - * \param[out] cloud_out Input cloud with normals appended. - * \return true if success. - * \note Converts from m to cm. - */ - bool - calculateNormals (const CloudXYZRGBAConstPtr& cloud_in, - CloudXYZRGBNormalPtr& cloud_out) const; - - /** @{ */ - /** \brief Points outside of X - Y - Z - min / max are discarded. The unit is cm. The min values must be smaller than the max values. */ - inline void setXMin (const float x_min) {if (x_min < x_max_) x_min_ = x_min;} - inline void setXMax (const float x_max) {if (x_max > x_min_) x_max_ = x_max;} - inline void setYMin (const float y_min) {if (y_min < y_max_) y_min_ = y_min;} - inline void setYMax (const float y_max) {if (y_max > y_min_) y_max_ = y_max;} - inline void setZMin (const float z_min) {if (z_min < z_max_) z_min_ = z_min;} - inline void setZMax (const float z_max) {if (z_max > z_min_) z_max_ = z_max;} - - inline float getXMin () const {return (x_min_);} - inline float getXMax () const {return (x_max_);} - inline float getYMin () const {return (y_min_);} - inline float getYMax () const {return (y_max_);} - inline float getZMin () const {return (z_min_);} - inline float getZMax () const {return (z_max_);} - /** @} */ - - /** @{ */ - /** \brief Simple color segmentation in the HSV color space. Points inside of H - S - V min / max are discarded. H must be in the range 0 and 360, S and V in the range 0 and 1. - * \note If you set values outside of the allowed range the member variables are clamped to the next best value. E.g. H is set to 0 if you pass -1. - */ - inline void setHMin (const float h_min) {h_min_ = pcl::ihs::clamp (h_min, 0.f, 360.f);} - inline void setHMax (const float h_max) {h_max_ = pcl::ihs::clamp (h_max, 0.f, 360.f);} - inline void setSMin (const float s_min) {s_min_ = pcl::ihs::clamp (s_min, 0.f, 1.f);} - inline void setSMax (const float s_max) {s_max_ = pcl::ihs::clamp (s_max, 0.f, 1.f);} - inline void setVMin (const float v_min) {v_min_ = pcl::ihs::clamp (v_min, 0.f, 1.f);} - inline void setVMax (const float v_max) {v_max_ = pcl::ihs::clamp (v_max, 0.f, 1.f);} - - inline float getHMin () const {return (h_min_);} - inline float getHMax () const {return (h_max_);} - inline float getSMin () const {return (s_min_);} - inline float getSMax () const {return (s_max_);} - inline float getVMin () const {return (v_min_);} - inline float getVMax () const {return (v_max_);} - /** @} */ - - /** @{ */ - /** \brief If true the color values inside of H - S - V min / max are accepted instead of discarded. */ - inline void setColorSegmentationInverted (const bool hsv_inverted) {hsv_inverted_ = hsv_inverted;} - inline bool getColorSegmentationInverted () const {return (hsv_inverted_);} - /** @} */ - - /** @{ */ - /** \brief Enable / disable the color segmentation. */ - inline void setColorSegmentationEnabled (const bool hsv_enabled) {hsv_enabled_ = hsv_enabled;} - inline bool getColorSegmentationEnabled () const {return (hsv_enabled_);} - /** @} */ - - /** @{ */ - /** \brief The XYZ mask is eroded with a kernel of this size. */ - inline void setXYZErodeSize (const unsigned int size) {size_erode_ = size;} - inline unsigned int getXYZErodeSize () const {return (size_erode_);} - /** @} */ - - /** @{ */ - /** \brief The HSV mask is dilated with a kernel of this size. */ - inline void setHSVDilateSize (const unsigned int size) {size_dilate_ = size;} - inline unsigned int getHSVDilateSize () const {return (size_dilate_);} - /** @} */ - - private: - - using Normal = pcl::Normal; - using CloudNormals = pcl::PointCloud; - using CloudNormalsPtr = CloudNormals::Ptr; - using CloudNormalsConstPtr = CloudNormals::ConstPtr; - - using NormalEstimation = pcl::IntegralImageNormalEstimation ; - using NormalEstimationPtr = NormalEstimation::Ptr; - using NormalEstimationConstPtr = NormalEstimation::ConstPtr; - - using MatrixXb = Eigen::Matrix ; - using MatrixXi = Eigen::MatrixXi; - - /** \brief Erodes the input mask k times with a diamond shaped structuring element. - * \see http://ostermiller.org/dilate_and_erode.html - */ - void - erode (MatrixXb& mask, const int k) const; - - /** \brief Dilates the input mask k times with a diamond shaped structuring element. - * \see http://ostermiller.org/dilate_and_erode.html - */ - void - dilate (MatrixXb& mask, const int k) const; - - /** \brief Calculates the manhattan distance map for the input matrix. - * \param[in] mat Input matrix. - * \param[in] comp Compared value. mat==comp will have zero distance. - * \return Matrix containing the distances to mat==comp - * \see http://ostermiller.org/dilate_and_erode.html - */ - MatrixXi - manhattan (const MatrixXb& mat, const bool comp) const; - - /** \brief Conversion from the RGB to HSV color space. */ - void - RGBToHSV (const unsigned char r, - const unsigned char g, - const unsigned char b, - float& h, - float& s, - float& v) const; - - //////////////////////////////////////////////////////////////////////// - // Members - //////////////////////////////////////////////////////////////////////// - - NormalEstimationPtr normal_estimation_; - - float x_min_; - float x_max_; - float y_min_; - float y_max_; - float z_min_; - float z_max_; - - float h_min_; - float h_max_; - float s_min_; - float s_max_; - float v_min_; - float v_max_; - - bool hsv_inverted_; - bool hsv_enabled_; - - unsigned int size_dilate_; - unsigned int size_erode_; - }; - } // End namespace ihs +namespace pcl { +namespace ihs { +/** \brief Bundles methods that are applied to the input data from the sensor. + * \author Martin Saelzle + * \ingroup apps + */ +class PCL_EXPORTS InputDataProcessing { +public: + using PointXYZRGBA = pcl::PointXYZRGBA; + using CloudXYZRGBA = pcl::PointCloud; + using CloudXYZRGBAPtr = CloudXYZRGBA::Ptr; + using CloudXYZRGBAConstPtr = CloudXYZRGBA::ConstPtr; + + using PointXYZRGBNormal = pcl::PointXYZRGBNormal; + using CloudXYZRGBNormal = pcl::PointCloud; + using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; + using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; + + /** \brief Constructor */ + InputDataProcessing(); + + /** \brief Apply the segmentation on the input cloud (XYZ and HSV). + * + * \param[in] cloud_in The input cloud. + * \param[out] cloud_out The segmented cloud. + * \param[out] cloud_discarded Cloud containing all points that were removed during + * the HSV segmentation. The points in the XYZ segmentation are NOT used! + * + * \return true if success. + * + * \note Converts from m to cm. + */ + bool + segment(const CloudXYZRGBAConstPtr& cloud_in, + CloudXYZRGBNormalPtr& cloud_out, + CloudXYZRGBNormalPtr& cloud_discarded) const; + + /** \brief Calculate the normals of the input cloud. + * + * \param[in] cloud_in The input cloud. + * \param[out] cloud_out Input cloud with normals appended. + * + * \return true if success. + * + * \note Converts from m to cm. + */ + bool + calculateNormals(const CloudXYZRGBAConstPtr& cloud_in, + CloudXYZRGBNormalPtr& cloud_out) const; + + /** @{ */ + /** \brief Points outside of X - Y - Z - min / max are discarded. The unit is cm. The + * min values must be smaller than the max values. */ + inline void + setXMin(const float x_min) + { + if (x_min < x_max_) + x_min_ = x_min; + } + inline void + setXMax(const float x_max) + { + if (x_max > x_min_) + x_max_ = x_max; + } + inline void + setYMin(const float y_min) + { + if (y_min < y_max_) + y_min_ = y_min; + } + inline void + setYMax(const float y_max) + { + if (y_max > y_min_) + y_max_ = y_max; + } + inline void + setZMin(const float z_min) + { + if (z_min < z_max_) + z_min_ = z_min; + } + inline void + setZMax(const float z_max) + { + if (z_max > z_min_) + z_max_ = z_max; + } + + inline float + getXMin() const + { + return (x_min_); + } + inline float + getXMax() const + { + return (x_max_); + } + inline float + getYMin() const + { + return (y_min_); + } + inline float + getYMax() const + { + return (y_max_); + } + inline float + getZMin() const + { + return (z_min_); + } + inline float + getZMax() const + { + return (z_max_); + } + /** @} */ + + /** @{ */ + /** \brief Simple color segmentation in the HSV color space. Points inside of H - S - + * V min / max are discarded. H must be in the range 0 and 360, S and V in the range 0 + * and 1. + * + * \note If you set values outside of the allowed range the member variables + * are clamped to the next best value. E.g. H is set to 0 if you pass -1. + */ + inline void + setHMin(const float h_min) + { + h_min_ = pcl::ihs::clamp(h_min, 0.f, 360.f); + } + inline void + setHMax(const float h_max) + { + h_max_ = pcl::ihs::clamp(h_max, 0.f, 360.f); + } + inline void + setSMin(const float s_min) + { + s_min_ = pcl::ihs::clamp(s_min, 0.f, 1.f); + } + inline void + setSMax(const float s_max) + { + s_max_ = pcl::ihs::clamp(s_max, 0.f, 1.f); + } + inline void + setVMin(const float v_min) + { + v_min_ = pcl::ihs::clamp(v_min, 0.f, 1.f); + } + inline void + setVMax(const float v_max) + { + v_max_ = pcl::ihs::clamp(v_max, 0.f, 1.f); + } + + inline float + getHMin() const + { + return (h_min_); + } + inline float + getHMax() const + { + return (h_max_); + } + inline float + getSMin() const + { + return (s_min_); + } + inline float + getSMax() const + { + return (s_max_); + } + inline float + getVMin() const + { + return (v_min_); + } + inline float + getVMax() const + { + return (v_max_); + } + /** @} */ + + /** @{ */ + /** \brief If true the color values inside of H - S - V min / max are accepted instead + * of discarded. */ + inline void + setColorSegmentationInverted(const bool hsv_inverted) + { + hsv_inverted_ = hsv_inverted; + } + inline bool + getColorSegmentationInverted() const + { + return (hsv_inverted_); + } + /** @} */ + + /** @{ */ + /** \brief Enable / disable the color segmentation. */ + inline void + setColorSegmentationEnabled(const bool hsv_enabled) + { + hsv_enabled_ = hsv_enabled; + } + inline bool + getColorSegmentationEnabled() const + { + return (hsv_enabled_); + } + /** @} */ + + /** @{ */ + /** \brief The XYZ mask is eroded with a kernel of this size. */ + inline void + setXYZErodeSize(const unsigned int size) + { + size_erode_ = size; + } + inline unsigned int + getXYZErodeSize() const + { + return (size_erode_); + } + /** @} */ + + /** @{ */ + /** \brief The HSV mask is dilated with a kernel of this size. */ + inline void + setHSVDilateSize(const unsigned int size) + { + size_dilate_ = size; + } + inline unsigned int + getHSVDilateSize() const + { + return (size_dilate_); + } + /** @} */ + +private: + using Normal = pcl::Normal; + using CloudNormals = pcl::PointCloud; + using CloudNormalsPtr = CloudNormals::Ptr; + using CloudNormalsConstPtr = CloudNormals::ConstPtr; + + using NormalEstimation = pcl::IntegralImageNormalEstimation; + using NormalEstimationPtr = NormalEstimation::Ptr; + using NormalEstimationConstPtr = NormalEstimation::ConstPtr; + + using MatrixXb = Eigen::Matrix; + using MatrixXi = Eigen::MatrixXi; + + /** \brief Erodes the input mask k times with a diamond shaped structuring element. + * \see http://ostermiller.org/dilate_and_erode.html + */ + void + erode(MatrixXb& mask, const int k) const; + + /** \brief Dilates the input mask k times with a diamond shaped structuring element. + * \see http://ostermiller.org/dilate_and_erode.html + */ + void + dilate(MatrixXb& mask, const int k) const; + + /** \brief Calculates the manhattan distance map for the input matrix. + * + * \param[in] mat Input matrix. + * \param[in] comp Compared value. mat==comp will have zero distance. + * + * \return Matrix containing the distances to mat==comp + * \see http://ostermiller.org/dilate_and_erode.html + */ + MatrixXi + manhattan(const MatrixXb& mat, const bool comp) const; + + /** \brief Conversion from the RGB to HSV color space. */ + void + RGBToHSV(const unsigned char r, + const unsigned char g, + const unsigned char b, + float& h, + float& s, + float& v) const; + + //////////////////////////////////////////////////////////////////////// + // Members + //////////////////////////////////////////////////////////////////////// + + NormalEstimationPtr normal_estimation_; + + float x_min_; + float x_max_; + float y_min_; + float y_max_; + float z_min_; + float z_max_; + + float h_min_; + float h_max_; + float s_min_; + float s_max_; + float v_min_; + float v_max_; + + bool hsv_inverted_; + bool hsv_enabled_; + + unsigned int size_dilate_; + unsigned int size_erode_; +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/integration.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/integration.h index 2617e12c16d..4c7b37e6dbb 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/integration.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/integration.h @@ -40,183 +40,214 @@ #pragma once -#include - #include -#include #include +#include + +#include //////////////////////////////////////////////////////////////////////////////// // Integration //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - /** \brief Integrate several clouds into a common mesh. - * \author Martin Saelzle - * \ingroup apps - */ - class PCL_EXPORTS Integration - { - public: - - using PointXYZRGBNormal = pcl::PointXYZRGBNormal; - using CloudXYZRGBNormal = pcl::PointCloud; - using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; - using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - - using Mesh = pcl::ihs::Mesh; - using MeshPtr = pcl::ihs::MeshPtr; - using MeshConstPtr = pcl::ihs::MeshConstPtr; - using VertexIndex = Mesh::VertexIndex; - using VertexIndices = Mesh::VertexIndices; - - /** \brief Constructor. */ - Integration (); - - /** \brief Reconstructs a mesh from an organized cloud. - * \param[in] cloud_data Input cloud. Must be organized. - * \param[in] mesh_model Reconstructed mesh. - * \return true if success. - */ - bool - reconstructMesh (const CloudXYZRGBNormalConstPtr& cloud_data, - MeshPtr& mesh_model) const; - - /** \brief Merge the organized cloud into the mesh. - * \param[in] cloud_data Input cloud. Must be organized. - * \param[in,out] mesh_model Mesh with new points integrated. - * \param[in] T Transformation that aligns the data cloud with the model mesh. - * \return true if success. - */ - bool - merge (const CloudXYZRGBNormalConstPtr& cloud_data, - MeshPtr& mesh_model, - const Eigen::Matrix4f& T) const; - - /** \brief Outlier rejection. In each merge step points that have not been observed again age by one iteration. Points that are observed again get an age of 0. Once a point reaches the maximum age it is decided if the point is removed or kept in the mesh. A point is removed if it has not been observed from a minimum number of directions. - * \param[in,out] mesh The mesh which should be processed. - * \param[in] cleanup Calls mesh.cleanup () if true. - */ - void - age (const MeshPtr& mesh, const bool cleanup=true) const; - - /** \brief Removes unfit vertices regardless of their age. Unfit vertices are those that have not been observed from enough directions. - * \param[in,out] mesh The which should be processed. - * \param[in] cleanup Calls mesh.cleanup () if true. - */ - void - removeUnfitVertices (const MeshPtr& mesh, const bool cleanup=true) const; - - /** @{ */ - /** \brief Corresponding points are averaged out if their distance is below a distance threshold. Else the points are added to the mesh as new vertices (Set in cm^2). - * \note Must be greater than zero. - */ - void setMaxSquaredDistance (const float squared_distance); - float getMaxSquaredDistance () const; - /** @} */ - - /** @{ */ - /** \brief Corresponding points are only averaged out if the angle between the normals is smaller than an angle threshold. - * \note Must be between 0 and 180. Values outside this range are clamped to the nearest valid value. - */ - void setMaxAngle (const float angle); - float getMaxAngle () const; - /** @} */ - - /** @{ */ - /** \brief Once a point reaches the maximum age it is decided if the point is removed or kept in the mesh. - * \note Must be greater than zero. - */ - void setMaxAge (const unsigned int age); - unsigned int getMaxAge () const; - /** @} */ - - /** @{ */ - /** \brief A point is removed if it has not been observed from a minimum number of directions. - * \note Must be greater than zero. - */ - void setMinDirections (const unsigned int directions); - unsigned int getMinDirections () const; - /** @} */ - - private: - - using PointXYZ = pcl::PointXYZ; - using CloudXYZ = pcl::PointCloud; - using CloudXYZPtr = CloudXYZ::Ptr; - using CloudXYZConstPtr = CloudXYZ::ConstPtr; - - using PointIHS = pcl::ihs::PointIHS; - using CloudIHS = pcl::ihs::CloudIHS; - using CloudIHSPtr = pcl::ihs::CloudIHSPtr; - using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; - - using KdTree = pcl::KdTree; - using KdTreePtr = KdTree::Ptr; - using KdTreeConstPtr = KdTree::ConstPtr; - - std::uint8_t - trimRGB (const float val) const; - - /** \brief Adds two triangles between points 0-1-3 and 1-2-3 to the mesh. */ - void - addToMesh (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2, - const PointIHS& pt_3, - VertexIndex& vi_0, - VertexIndex& vi_1, - VertexIndex& vi_2, - VertexIndex& vi_3, - const MeshPtr& mesh) const; - - /** \brief Adds a triangle between the points 0-1-2 to the mesh. */ - void - addToMesh (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2, - VertexIndex& vi_0, - VertexIndex& vi_1, - VertexIndex& vi_2, - const MeshPtr& mesh) const; - - /** \brief Returns true if the distance between the three points is below a threshold. */ - bool - distanceThreshold (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2) const; - - /** \brief Returns true if the distance between the four points is below a threshold. */ - bool - distanceThreshold (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2, - const PointIHS& pt_3) const; - - //////////////////////////////////////////////////////////////////////// - // Members - //////////////////////////////////////////////////////////////////////// - - /** \brief Nearest neighbor search. */ - KdTreePtr kd_tree_; - - /** \brief Maximum squared distance below which points are averaged out. */ - float max_squared_distance_; - - /** \brief Maximum angle between normals below which points are averaged out. In degrees. */ - float max_angle_; - - /** \brief Minimum weight above which points are added. */ - float min_weight_; - - /** \brief Once a point reaches the maximum age it is decided if the point is removed or kept in the mesh. */ - unsigned int max_age_; - - /** \brief A point is removed if it has not been observed from a minimum number of directions. */ - unsigned int min_directions_; - }; - } // End namespace ihs +namespace pcl { +namespace ihs { +/** \brief Integrate several clouds into a common mesh. + * \author Martin Saelzle + * \ingroup apps + */ +class PCL_EXPORTS Integration { +public: + using PointXYZRGBNormal = pcl::PointXYZRGBNormal; + using CloudXYZRGBNormal = pcl::PointCloud; + using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; + using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; + + using Mesh = pcl::ihs::Mesh; + using MeshPtr = pcl::ihs::MeshPtr; + using MeshConstPtr = pcl::ihs::MeshConstPtr; + using VertexIndex = Mesh::VertexIndex; + using VertexIndices = Mesh::VertexIndices; + + /** \brief Constructor. */ + Integration(); + + /** \brief Reconstructs a mesh from an organized cloud. + * + * \param[in] cloud_data Input cloud. Must be organized. + * \param[in] mesh_model Reconstructed mesh. + * + * \return true if success. + */ + bool + reconstructMesh(const CloudXYZRGBNormalConstPtr& cloud_data, + MeshPtr& mesh_model) const; + + /** \brief Merge the organized cloud into the mesh.# + * + * \param[in] cloud_data Input cloud. Must be organized. + * \param[in,out] mesh_model Mesh with new points integrated. + * \param[in] T Transformation that aligns the data cloud with the model mesh. + * + * \return true if success. + */ + bool + merge(const CloudXYZRGBNormalConstPtr& cloud_data, + MeshPtr& mesh_model, + const Eigen::Matrix4f& T) const; + + /** \brief Outlier rejection. In each merge step points that have not been observed + * again age by one iteration. Points that are observed again get an age of 0. Once a + * point reaches the maximum age it is decided if the point is removed or kept in the + * mesh. A point is removed if it has not been observed from a minimum number of + * directions. + * + * \param[in,out] mesh The mesh which should be processed. + * \param[in] cleanup Calls mesh.cleanup() if true. + */ + void + age(const MeshPtr& mesh, const bool cleanup = true) const; + + /** \brief Removes unfit vertices regardless of their age. Unfit vertices are those + * that have not been observed from enough directions. + * + * \param[in,out] mesh The which should be processed. + * \param[in] cleanup Calls mesh.cleanup() if true. + */ + void + removeUnfitVertices(const MeshPtr& mesh, const bool cleanup = true) const; + + /** @{ */ + /** \brief Corresponding points are averaged out if their distance is below a distance + * threshold. Else the points are added to the mesh as new vertices (Set in cm^2). + * + * \note Must be greater than zero. + */ + void + setMaxSquaredDistance(const float squared_distance); + float + getMaxSquaredDistance() const; + /** @} */ + + /** @{ */ + /** \brief Corresponding points are only averaged out if the angle between the normals + * is smaller than an angle threshold. + * + * \note Must be between 0 and 180. Values outside this range are clamped to the + * nearest valid value. + */ + void + setMaxAngle(const float angle); + float + getMaxAngle() const; + /** @} */ + + /** @{ */ + /** \brief Once a point reaches the maximum age it is decided if the point is removed + * or kept in the mesh. + * + * \note Must be greater than zero. + */ + void + setMaxAge(const unsigned int age); + unsigned int + getMaxAge() const; + /** @} */ + + /** @{ */ + /** \brief A point is removed if it has not been observed from a minimum number of + * directions. + * + * \note Must be greater than zero. + */ + void + setMinDirections(const unsigned int directions); + unsigned int + getMinDirections() const; + /** @} */ + +private: + using PointXYZ = pcl::PointXYZ; + using CloudXYZ = pcl::PointCloud; + using CloudXYZPtr = CloudXYZ::Ptr; + using CloudXYZConstPtr = CloudXYZ::ConstPtr; + + using PointIHS = pcl::ihs::PointIHS; + using CloudIHS = pcl::ihs::CloudIHS; + using CloudIHSPtr = pcl::ihs::CloudIHSPtr; + using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; + + using KdTree = pcl::KdTree; + using KdTreePtr = KdTree::Ptr; + using KdTreeConstPtr = KdTree::ConstPtr; + + std::uint8_t + trimRGB(const float val) const; + + /** \brief Adds two triangles between points 0-1-3 and 1-2-3 to the mesh. */ + void + addToMesh(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2, + const PointIHS& pt_3, + VertexIndex& vi_0, + VertexIndex& vi_1, + VertexIndex& vi_2, + VertexIndex& vi_3, + const MeshPtr& mesh) const; + + /** \brief Adds a triangle between the points 0-1-2 to the mesh. */ + void + addToMesh(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2, + VertexIndex& vi_0, + VertexIndex& vi_1, + VertexIndex& vi_2, + const MeshPtr& mesh) const; + + /** \brief Returns true if the distance between the three points is below a threshold. + */ + bool + distanceThreshold(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2) const; + + /** \brief Returns true if the distance between the four points is below a threshold. + */ + bool + distanceThreshold(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2, + const PointIHS& pt_3) const; + + //////////////////////////////////////////////////////////////////////// + // Members + //////////////////////////////////////////////////////////////////////// + + /** \brief Nearest neighbor search. */ + KdTreePtr kd_tree_; + + /** \brief Maximum squared distance below which points are averaged out. */ + float max_squared_distance_; + + /** \brief Maximum angle between normals below which points are averaged out. In + * degrees. + */ + float max_angle_; + + /** \brief Minimum weight above which points are added. */ + float min_weight_; + + /** \brief Once a point reaches the maximum age it is decided if the point is removed + * or kept in the mesh. + */ + unsigned int max_age_; + + /** \brief A point is removed if it has not been observed from a minimum number of + * directions. + */ + unsigned int min_directions_; +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/main_window.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/main_window.h index 62e496e2f5b..7d02686a1cc 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/main_window.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/main_window.h @@ -40,98 +40,120 @@ #pragma once -#include - #include +#include + //////////////////////////////////////////////////////////////////////////////// // Forward declarations //////////////////////////////////////////////////////////////////////////////// -namespace Ui -{ - class MainWindow; +namespace Ui { +class MainWindow; } -namespace pcl -{ - namespace ihs - { - class HelpWindow; - } // End namespace ihs +namespace pcl { +namespace ihs { +class HelpWindow; +} // End namespace ihs } // End namespace pcl //////////////////////////////////////////////////////////////////////////////// // MainWindow //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - class MainWindow : public QMainWindow - { - Q_OBJECT - - public: - - using InHandScanner = pcl::ihs::InHandScanner; - using HelpWindow = pcl::ihs::HelpWindow; - using RunningMode = InHandScanner::RunningMode; - - explicit MainWindow (QWidget* parent = nullptr); - ~MainWindow (); - - public Q_SLOTS: - - void showHelp (); - void saveAs (); - - // In hand scanner - void runningModeChanged (const RunningMode mode); - void keyPressEvent (QKeyEvent* event) override; - - // Input data processing. - void setXMin (const int x_min); - void setXMax (const int x_max); - void setYMin (const int y_min); - void setYMax (const int y_max); - void setZMin (const int z_min); - void setZMax (const int z_max); - - void setHMin (const int h_min); - void setHMax (const int h_max); - void setSMin (const int s_min); - void setSMax (const int s_max); - void setVMin (const int v_min); - void setVMax (const int v_max); - - void setColorSegmentationInverted (const bool is_inverted); - void setColorSegmentationEnabled (const bool is_enabled); - - void setXYZErodeSize (const int size); - void setHSVDilateSize (const int size); - - // Registration - void setEpsilon (); - void setMaxIterations (const int iterations); - void setMinOverlap (const int overlap); - void setMaxFitness (); - - void setCorrespondenceRejectionFactor (const double factor); - void setCorrespondenceRejectionMaxAngle (const int angle); - - // Integration - void setMaxSquaredDistance (); - void setAveragingMaxAngle (const int angle); - void setMaxAge (const int age); - void setMinDirections (const int directions); - - private: - - Ui::MainWindow* ui_; - HelpWindow* help_window_; - InHandScanner* ihs_; - }; - } // End namespace ihs +namespace pcl { +namespace ihs { +class MainWindow : public QMainWindow { + Q_OBJECT + +public: + using InHandScanner = pcl::ihs::InHandScanner; + using HelpWindow = pcl::ihs::HelpWindow; + using RunningMode = InHandScanner::RunningMode; + + explicit MainWindow(QWidget* parent = nullptr); + ~MainWindow(); + +public Q_SLOTS: + + void + showHelp(); + void + saveAs(); + + // In hand scanner + void + runningModeChanged(const RunningMode mode); + void + keyPressEvent(QKeyEvent* event) override; + + // Input data processing. + void + setXMin(const int x_min); + void + setXMax(const int x_max); + void + setYMin(const int y_min); + void + setYMax(const int y_max); + void + setZMin(const int z_min); + void + setZMax(const int z_max); + + void + setHMin(const int h_min); + void + setHMax(const int h_max); + void + setSMin(const int s_min); + void + setSMax(const int s_max); + void + setVMin(const int v_min); + void + setVMax(const int v_max); + + void + setColorSegmentationInverted(const bool is_inverted); + void + setColorSegmentationEnabled(const bool is_enabled); + + void + setXYZErodeSize(const int size); + void + setHSVDilateSize(const int size); + + // Registration + void + setEpsilon(); + void + setMaxIterations(const int iterations); + void + setMinOverlap(const int overlap); + void + setMaxFitness(); + + void + setCorrespondenceRejectionFactor(const double factor); + void + setCorrespondenceRejectionMaxAngle(const int angle); + + // Integration + void + setMaxSquaredDistance(); + void + setAveragingMaxAngle(const int angle); + void + setMaxAge(const int age); + void + setMinDirections(const int directions); + +private: + Ui::MainWindow* ui_; + HelpWindow* help_window_; + InHandScanner* ihs_; +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/mesh_processing.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/mesh_processing.h index 69d785b329f..fecea6f2bd0 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/mesh_processing.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/mesh_processing.h @@ -42,33 +42,36 @@ #include -namespace pcl -{ - namespace ihs - { - /** \brief Contains methods that take advantage of the connectivity information in the mesh. - * \author Martin Saelzle - * \ingroup apps - */ - class MeshProcessing - { - public: - - using Mesh = pcl::ihs::Mesh; - using HalfEdgeIndices = Mesh::HalfEdgeIndices; +namespace pcl { +namespace ihs { +/** \brief Contains methods that take advantage of the connectivity information in the + * mesh. + * + * \author Martin Saelzle + * \ingroup apps + */ +class MeshProcessing { +public: + using Mesh = pcl::ihs::Mesh; + using HalfEdgeIndices = Mesh::HalfEdgeIndices; - static_assert (Mesh::IsManifold::value, "MeshProcessing currently works only on the manifold mesh."); + static_assert(Mesh::IsManifold::value, + "MeshProcessing currently works only on the manifold mesh."); - /** \brief Constructor. */ - MeshProcessing (); + /** \brief Constructor. */ + MeshProcessing(); - /** \brief Inserts triangles into jagged boundaries, removes isolated triangles and closes triangular holes. - * \param[in,out] mesh The mesh which should be processed. - * \param[in] boundary_collection Collection of boundary half-edges. - * \param[in] cleanup Calls mesh.cleanup () if true. - */ - void - processBoundary (Mesh& mesh, const std::vector & boundary_collection, const bool cleanup=true) const; - }; - } // End namespace ihs + /** \brief Inserts triangles into jagged boundaries, removes isolated triangles and + * closes triangular holes. + * + * \param[in,out] mesh The mesh which should be processed. + * \param[in] boundary_collection Collection of boundary half-edges. + * \param[in] cleanup Calls mesh.cleanup() if true. + */ + void + processBoundary(Mesh& mesh, + const std::vector& boundary_collection, + const bool cleanup = true) const; +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/offline_integration.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/offline_integration.h index cff11995d4b..02bfae3e0ec 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/offline_integration.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/offline_integration.h @@ -40,185 +40,183 @@ #pragma once +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include #include -#include #include +#include //////////////////////////////////////////////////////////////////////////////// // Forward declarations //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - class Integration; - } // End namespace ihs +namespace pcl { +namespace ihs { +class Integration; +} // End namespace ihs } // End namespace pcl //////////////////////////////////////////////////////////////////////////////// // OfflineIntegration //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - /** \brief Read the clouds and transformations from files and integrate them into one common model. - * \todo Add Documentation - */ - class PCL_EXPORTS OfflineIntegration : public pcl::ihs::OpenGLViewer - { - Q_OBJECT - - public: - - using Base = pcl::ihs::OpenGLViewer; - using Self = pcl::ihs::OfflineIntegration; - - /** \brief Constructor. */ - explicit OfflineIntegration (Base* parent=nullptr); - - /** \brief Destructor. */ - ~OfflineIntegration (); - - public Q_SLOTS: - - /** \brief Start the procedure from a path. */ - void - start (); - - private Q_SLOTS: - - /** \brief Loads in new data. */ - void - computationThread (); - - private: - - using PointXYZRGBA = pcl::PointXYZRGBA; - using CloudXYZRGBA = pcl::PointCloud; - using CloudXYZRGBAPtr = CloudXYZRGBA::Ptr; - using CloudXYZRGBAConstPtr = CloudXYZRGBA::ConstPtr; - - using PointXYZRGBNormal = pcl::PointXYZRGBNormal; - using CloudXYZRGBNormal = pcl::PointCloud; - using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; - using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - - using Mesh = pcl::ihs::Mesh; - using MeshPtr = pcl::ihs::MeshPtr; - using MeshConstPtr = pcl::ihs::MeshConstPtr; - - using Integration = pcl::ihs::Integration; - using IntegrationPtr = std::shared_ptr; - using IntegrationConstPtr = std::shared_ptr; - - using NormalEstimation = pcl::IntegralImageNormalEstimation ; - using NormalEstimationPtr = NormalEstimation::Ptr; - using NormalEstimationConstPtr = NormalEstimation::ConstPtr; - - /** \brief Helper object for the computation thread. Please have a look at the documentation of calcFPS. */ - class ComputationFPS : public Base::FPS - { - public: - ComputationFPS () {} - ~ComputationFPS () {} - }; - - - /** \brief Helper object for the visualization thread. Please have a look at the documentation of calcFPS. */ - class VisualizationFPS : public Base::FPS - { - public: - VisualizationFPS () {} - ~VisualizationFPS () {} - }; - - /** \brief Get a list of files with from a given directory. - * \param[in] path_dir Path to search for the files. - * \param[in] extension File extension (must start with a dot). E.g. '.pcd'. - * \param[out] files Paths to the files. - * \return True if success. - */ - bool - getFilesFromDirectory (const std::string& path_dir, - const std::string& extension, - std::vector & files) const; - - /** \brief Load the transformation matrix from the given file. - * \param[in] filename Path to the file. - * \param[out] transform The loaded transform. - * \return True if success. - */ - bool - loadTransform (const std::string& filename, - Eigen::Matrix4f& transform) const; - - /** \brief Load the cloud and transformation from the files and compute the normals. - * \param[in] filename Path to the pcd file. - * \param[out] cloud Cloud with computed normals. - * \param[out] T Loaded transformation. - * \return True if success. - */ - bool - load (const std::string& filename, - CloudXYZRGBNormalPtr& cloud, - Eigen::Matrix4f& T) const; - - /** \see http://doc.qt.digia.com/qt/qwidget.html#paintEvent - * \see http://doc.qt.digia.com/qt/opengl-overpainting.html - */ - void - paintEvent (QPaintEvent* event) override; - - /** \see http://doc.qt.digia.com/qt/qwidget.html#keyPressEvent */ - void - keyPressEvent (QKeyEvent* event) override; - - ////////////////////////////////////////////////////////////////////////// - // Members - ////////////////////////////////////////////////////////////////////////// - - /** \brief Synchronization. */ - std::mutex mutex_; - - /** \brief Wait until the data finished processing. */ - std::mutex mutex_quit_; - - /** \brief Please have a look at the documentation of ComputationFPS. */ - ComputationFPS computation_fps_; - - /** \brief Please have a look at the documentation of VisualizationFPS. */ - VisualizationFPS visualization_fps_; - - /** \brief Path to the pcd and transformation files. */ - std::string path_dir_; - - /** \brief Model to which new data is registered to (stored as a mesh). */ - MeshPtr mesh_model_; - - /** \brief Compute the normals for the input clouds. */ - NormalEstimationPtr normal_estimation_; - - /** \brief Integrate the data cloud into a common model. */ - IntegrationPtr integration_; - - /** \brief Prevent the application to crash while closing. */ - bool destructor_called_; - - public: - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; - } // End namespace ihs +namespace pcl { +namespace ihs { +/** \brief Read the clouds and transformations from files and integrate them into one + * common model. + * + * \todo Add Documentation + */ +class PCL_EXPORTS OfflineIntegration : public pcl::ihs::OpenGLViewer { + Q_OBJECT + +public: + using Base = pcl::ihs::OpenGLViewer; + using Self = pcl::ihs::OfflineIntegration; + + /** \brief Constructor. */ + explicit OfflineIntegration(Base* parent = nullptr); + + /** \brief Destructor. */ + ~OfflineIntegration(); + +public Q_SLOTS: + + /** \brief Start the procedure from a path. */ + void + start(); + +private Q_SLOTS: + + /** \brief Loads in new data. */ + void + computationThread(); + +private: + using PointXYZRGBA = pcl::PointXYZRGBA; + using CloudXYZRGBA = pcl::PointCloud; + using CloudXYZRGBAPtr = CloudXYZRGBA::Ptr; + using CloudXYZRGBAConstPtr = CloudXYZRGBA::ConstPtr; + + using PointXYZRGBNormal = pcl::PointXYZRGBNormal; + using CloudXYZRGBNormal = pcl::PointCloud; + using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; + using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; + + using Mesh = pcl::ihs::Mesh; + using MeshPtr = pcl::ihs::MeshPtr; + using MeshConstPtr = pcl::ihs::MeshConstPtr; + + using Integration = pcl::ihs::Integration; + using IntegrationPtr = std::shared_ptr; + using IntegrationConstPtr = std::shared_ptr; + + using NormalEstimation = + pcl::IntegralImageNormalEstimation; + using NormalEstimationPtr = NormalEstimation::Ptr; + using NormalEstimationConstPtr = NormalEstimation::ConstPtr; + + /** \brief Helper object for the computation thread. Please have a look at the + * documentation of calcFPS. */ + class ComputationFPS : public Base::FPS { + public: + ComputationFPS() {} + ~ComputationFPS() {} + }; + + /** \brief Helper object for the visualization thread. Please have a look at the + * documentation of calcFPS. */ + class VisualizationFPS : public Base::FPS { + public: + VisualizationFPS() {} + ~VisualizationFPS() {} + }; + + /** \brief Get a list of files with from a given directory. + * + * \param[in] path_dir Path to search for the files. + * \param[in] extension File extension (must start with a dot). E.g. '.pcd'. + * \param[out] files Paths to the files. + * + * \return True if success. + */ + bool + getFilesFromDirectory(const std::string& path_dir, + const std::string& extension, + std::vector& files) const; + + /** \brief Load the transformation matrix from the given file. + * + * \param[in] filename Path to the file. + * \param[out] transform The loaded transform. + * + * \return True if success. + */ + bool + loadTransform(const std::string& filename, Eigen::Matrix4f& transform) const; + + /** \brief Load the cloud and transformation from the files and compute the normals. + * + * \param[in] filename Path to the pcd file. + * \param[out] cloud Cloud with computed normals. + * \param[out] T Loaded transformation. + * + * \return True if success. + */ + bool + load(const std::string& filename, + CloudXYZRGBNormalPtr& cloud, + Eigen::Matrix4f& T) const; + + /** \see http://doc.qt.digia.com/qt/qwidget.html#paintEvent + * \see http://doc.qt.digia.com/qt/opengl-overpainting.html + */ + void + paintEvent(QPaintEvent* event) override; + + /** \see http://doc.qt.digia.com/qt/qwidget.html#keyPressEvent */ + void + keyPressEvent(QKeyEvent* event) override; + + ////////////////////////////////////////////////////////////////////////// + // Members + ////////////////////////////////////////////////////////////////////////// + + /** \brief Synchronization. */ + std::mutex mutex_; + + /** \brief Wait until the data finished processing. */ + std::mutex mutex_quit_; + + /** \brief Please have a look at the documentation of ComputationFPS. */ + ComputationFPS computation_fps_; + + /** \brief Please have a look at the documentation of VisualizationFPS. */ + VisualizationFPS visualization_fps_; + + /** \brief Path to the pcd and transformation files. */ + std::string path_dir_; + + /** \brief Model to which new data is registered to (stored as a mesh). */ + MeshPtr mesh_model_; + + /** \brief Compute the normals for the input clouds. */ + NormalEstimationPtr normal_estimation_; + + /** \brief Integrate the data cloud into a common model. */ + IntegrationPtr integration_; + + /** \brief Prevent the application to crash while closing. */ + bool destructor_called_; + +public: + PCL_MAKE_ALIGNED_OPERATOR_NEW +}; +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/opengl_viewer.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/opengl_viewer.h index a684650c55a..fc4fe03331a 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/opengl_viewer.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/opengl_viewer.h @@ -40,416 +40,445 @@ #pragma once +#include +#include #include #include #include -#include -#include -#include -#include #include -#include #include +#include #include #include -namespace pcl -{ - namespace ihs - { - namespace detail +namespace pcl { +namespace ihs { +namespace detail { +/** \brief Mesh format more efficient for visualization than the half-edge data + * structure. \see http://en.wikipedia.org/wiki/Polygon_mesh#Face-vertex_meshes + * + * \note Only triangles are currently supported. + */ +class FaceVertexMesh { +public: + class Triangle { + public: + Triangle() : first(0), second(0), third(0) {} + Triangle(const unsigned int first, + const unsigned int second, + const unsigned int third) + : first(first), second(second), third(third) + {} + + unsigned int first; + unsigned int second; + unsigned int third; + }; + + /** \brief Constructor */ + FaceVertexMesh(); + + /** \brief Constructor. Converts the input mesh into a face vertex mesh. */ + FaceVertexMesh(const Mesh& mesh, const Eigen::Isometry3d& T); + + using PointIHS = pcl::ihs::PointIHS; + using CloudIHS = pcl::ihs::CloudIHS; + using CloudIHSPtr = pcl::ihs::CloudIHSPtr; + using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; + + CloudIHS vertices; + std::vector triangles; + Eigen::Isometry3d transformation; + +public: + PCL_MAKE_ALIGNED_OPERATOR_NEW +}; +} // End namespace detail + +/** \brief Viewer for the in-hand scanner based on Qt and OpenGL. + * + * \note Currently you have to derive from this class to use it. Implement the + * paintEvent: Call the paint event of this class and declare a QPainter. + */ +class PCL_EXPORTS OpenGLViewer : public QGLWidget { + Q_OBJECT + +public: + using PointXYZRGBNormal = pcl::PointXYZRGBNormal; + using CloudXYZRGBNormal = pcl::PointCloud; + using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; + using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; + + using Mesh = pcl::ihs::Mesh; + using MeshPtr = pcl::ihs::MeshPtr; + using MeshConstPtr = pcl::ihs::MeshConstPtr; + + /** \brief How to draw the mesh. */ + enum MeshRepresentation { + MR_POINTS, /**< Draw the points. */ + MR_EDGES, /**< Wireframe represen of the mesh. */ + MR_FACES /**< Draw the faces of the mesh without edges. */ + }; + + /** \brief How to color the shapes. */ + enum Coloring { + COL_RGB, /**< Coloring according to the rgb values. */ + COL_ONE_COLOR, /**< Use one color for all points. */ + COL_VISCONF /**< Coloring according to the visibility confidence. */ + }; + + /** \brief Coefficients for the wireframe box. */ + class BoxCoefficients { + public: + BoxCoefficients() + : x_min(0) + , x_max(0) + , y_min(0) + , y_max(0) + , z_min(0) + , z_max(0) + , transformation(Eigen::Isometry3d::Identity()) + {} + + BoxCoefficients(const float x_min, + const float x_max, + const float y_min, + const float y_max, + const float z_min, + const float z_max, + const Eigen::Isometry3d& T) + : x_min(x_min) + , x_max(x_max) + , y_min(y_min) + , y_max(y_max) + , z_min(z_min) + , z_max(z_max) + , transformation(T) + {} + + float x_min; + float x_max; + float y_min; + float y_max; + float z_min; + float z_max; + Eigen::Isometry3d transformation; + + public: + PCL_MAKE_ALIGNED_OPERATOR_NEW + }; + + /** \brief Constructor. */ + explicit OpenGLViewer(QWidget* parent = nullptr); + + /** \brief Destructor. */ + ~OpenGLViewer(); + + /** \brief Add a mesh to be drawn. + * + * \param[in] mesh The input mesh. + * \param[in] id Unique identifier for the mesh. The internal mesh is replaced by the + * input mesh if the id already exists. + * \param[in] T Transformation applied to the mesh. Defaults to an identity + * transformation. + * + * \return true if success. + * + * \note Converts the mesh to the internal representation better suited for + * visualization. Therefore this method takes some time. + */ + bool + addMesh(const MeshConstPtr& mesh, + const std::string& id, + const Eigen::Isometry3d& T = Eigen::Isometry3d::Identity()); + + /** \brief Convert an organized cloud to a mesh and draw it. + * + * \param[in] cloud Organized input cloud. + * \param[in] id Unique identifier for the mesh. The internal mesh is replaced by the + * converted input mesh if the id already exists. + * \param[in] T Transformation applied to the mesh. Defaults to an identity + * transformation. + * + * \return true if success. + * + * \note This method takes some time for the conversion). + */ + bool + addMesh(const CloudXYZRGBNormalConstPtr& cloud, + const std::string& id, + const Eigen::Isometry3d& T = Eigen::Isometry3d::Identity()); + + /** \brief Remove the mesh with the given id. + * + * \param[in] id Identifier of the mesh (results in a failure if the id does not + * exist). + * + * \return true if success. + */ + bool + removeMesh(const std::string& id); + + /** \brief Remove all meshes that are currently drawn. */ + void + removeAllMeshes(); + + /** \brief Set the coefficients for the box. */ + void + setBoxCoefficients(const BoxCoefficients& coeffs); + + /** \brief Enable / disable drawing the box. */ + void + setDrawBox(const bool enabled); + + /** \brief Check if the box is drawn. */ + bool + getDrawBox() const; + + /** \brief Set the point around which the camera rotates during mouse navigation. */ + void + setPivot(const Eigen::Vector3d& pivot); + + /** \brief Searches the given id in the drawn meshes and calculates the pivot as the + * centroid of the found geometry. + * + * \note Returns immediately and computes the pivot in + * another thread. + */ + void + setPivot(const std::string& id); + + /** \brief Stop the visualization timer. */ + void + stopTimer(); + + /** \brief The visibility confidence is normalized with this value (must be greater + * than 1). */ + void + setVisibilityConfidenceNormalization(const float vis_conf_norm); + + /** \see http://doc.qt.digia.com/qt/qwidget.html#minimumSizeHint-prop */ + QSize + minimumSizeHint() const override; + + /** \see http://doc.qt.digia.com/qt/qwidget.html#sizeHint-prop */ + QSize + sizeHint() const override; + + /** \brief Set the scaling factor to convert from meters to the unit of the drawn + * files. */ + void + setScalingFactor(const double scale); + +public Q_SLOTS: + + /** \brief Requests the scene to be re-drawn (called periodically from a timer). */ + void + timerCallback(); + + /** \brief Reset the virtual camera position and orientation. */ + void + resetCamera(); + + /** \brief Toggle the mesh representation. */ + void + toggleMeshRepresentation(); + + /** \brief Set the mesh representation. */ + void + setMeshRepresentation(const MeshRepresentation& representation); + + /** \brief Toggle the coloring mode. */ + void + toggleColoring(); + + /** \brief Set the coloring mode. */ + void + setColoring(const Coloring& coloring); + +protected: + /** \brief Please have a look at the documentation of calcFPS. */ + class FPS { + public: + FPS() : fps_(0.) {} + + inline double& + value() { - /** \brief Mesh format more efficient for visualization than the half-edge data structure. - * \see http://en.wikipedia.org/wiki/Polygon_mesh#Face-vertex_meshes - * \note Only triangles are currently supported. - */ - class FaceVertexMesh - { - public: - - class Triangle - { - public: - - Triangle () : first (0), second (0), third (0) {} - Triangle (const unsigned int first, const unsigned int second, const unsigned int third) - : first (first), second (second), third (third) - { - } - - unsigned int first; - unsigned int second; - unsigned int third; - }; - - /** \brief Constructor */ - FaceVertexMesh (); - - /** \brief Constructor. Converts the input mesh into a face vertex mesh. */ - FaceVertexMesh (const Mesh& mesh, const Eigen::Isometry3d& T); - - using PointIHS = pcl::ihs::PointIHS; - using CloudIHS = pcl::ihs::CloudIHS; - using CloudIHSPtr = pcl::ihs::CloudIHSPtr; - using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; - - CloudIHS vertices; - std::vector triangles; - Eigen::Isometry3d transformation; - - public: - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; - } // End namespace detail - - /** \brief Viewer for the in-hand scanner based on Qt and OpenGL. - * \note Currently you have to derive from this class to use it. Implement the paintEvent: Call the paint event of this class and declare a QPainter. - */ - class PCL_EXPORTS OpenGLViewer : public QGLWidget + return (fps_); + } + inline double + value() const { - Q_OBJECT - - public: - - using PointXYZRGBNormal = pcl::PointXYZRGBNormal; - using CloudXYZRGBNormal = pcl::PointCloud; - using CloudXYZRGBNormalPtr = CloudXYZRGBNormal::Ptr; - using CloudXYZRGBNormalConstPtr = CloudXYZRGBNormal::ConstPtr; - - using Mesh = pcl::ihs::Mesh; - using MeshPtr = pcl::ihs::MeshPtr; - using MeshConstPtr = pcl::ihs::MeshConstPtr; - - /** \brief How to draw the mesh. */ - enum MeshRepresentation - { - MR_POINTS, /**< Draw the points. */ - MR_EDGES, /**< Wireframe represen of the mesh. */ - MR_FACES /**< Draw the faces of the mesh without edges. */ - }; - - /** \brief How to color the shapes. */ - enum Coloring - { - COL_RGB, /**< Coloring according to the rgb values. */ - COL_ONE_COLOR, /**< Use one color for all points. */ - COL_VISCONF /**< Coloring according to the visibility confidence. */ - }; - - /** \brief Coefficients for the wireframe box. */ - class BoxCoefficients - { - public: - - BoxCoefficients () - : x_min (0), x_max (0), - y_min (0), y_max (0), - z_min (0), z_max (0), - transformation (Eigen::Isometry3d::Identity ()) - { - } - - BoxCoefficients (const float x_min, const float x_max, - const float y_min, const float y_max, - const float z_min, const float z_max, - const Eigen::Isometry3d& T) - : x_min (x_min), x_max (x_max), - y_min (y_min), y_max (y_max), - z_min (z_min), z_max (z_max), - transformation (T) - { - } - - float x_min; float x_max; - float y_min; float y_max; - float z_min; float z_max; - Eigen::Isometry3d transformation; - - public: - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; - - /** \brief Constructor. */ - explicit OpenGLViewer (QWidget* parent=nullptr); - - /** \brief Destructor. */ - ~OpenGLViewer (); - - /** \brief Add a mesh to be drawn. - * \param[in] mesh The input mesh. - * \param[in] id Unique identifier for the mesh. The internal mesh is replaced by the input mesh if the id already exists. - * \param[in] T Transformation applied to the mesh. Defaults to an identity transformation. - * \return true if success. - * \note Converts the mesh to the internal representation better suited for visualization. Therefore this method takes some time. - */ - bool - addMesh (const MeshConstPtr& mesh, const std::string& id, const Eigen::Isometry3d& T = Eigen::Isometry3d::Identity ()); - - /** \brief Convert an organized cloud to a mesh and draw it. - * \param[in] cloud Organized input cloud. - * \param[in] id Unique identifier for the mesh. The internal mesh is replaced by the converted input mesh if the id already exists. - * \param[in] T Transformation applied to the mesh. Defaults to an identity transformation. - * \return true if success. - * \note This method takes some time for the conversion). - */ - bool - addMesh (const CloudXYZRGBNormalConstPtr& cloud, const std::string& id, const Eigen::Isometry3d& T = Eigen::Isometry3d::Identity ()); - - /** \brief Remove the mesh with the given id. - * \param[in] id Identifier of the mesh (results in a failure if the id does not exist). - * \return true if success. - */ - bool - removeMesh (const std::string& id); - - /** \brief Remove all meshes that are currently drawn. */ - void - removeAllMeshes (); - - /** \brief Set the coefficients for the box. */ - void - setBoxCoefficients (const BoxCoefficients& coeffs); - - /** \brief Enable / disable drawing the box. */ - void - setDrawBox (const bool enabled); - - /** \brief Check if the box is drawn. */ - bool - getDrawBox () const; - - /** \brief Set the point around which the camera rotates during mouse navigation. */ - void - setPivot (const Eigen::Vector3d& pivot); - - /** \brief Searches the given id in the drawn meshes and calculates the pivot as the centroid of the found geometry. - * \note Returns immediately and computes the pivot in another thread. - */ - void - setPivot (const std::string& id); - - /** \brief Stop the visualization timer. */ - void - stopTimer (); - - /** \brief The visibility confidence is normalized with this value (must be greater than 1). */ - void - setVisibilityConfidenceNormalization (const float vis_conf_norm); - - /** \see http://doc.qt.digia.com/qt/qwidget.html#minimumSizeHint-prop */ - QSize - minimumSizeHint () const override; - - /** \see http://doc.qt.digia.com/qt/qwidget.html#sizeHint-prop */ - QSize - sizeHint () const override; - - /** \brief Set the scaling factor to convert from meters to the unit of the drawn files. */ - void - setScalingFactor (const double scale); - - public Q_SLOTS: - - /** \brief Requests the scene to be re-drawn (called periodically from a timer). */ - void - timerCallback (); - - /** \brief Reset the virtual camera position and orientation. */ - void - resetCamera (); - - /** \brief Toggle the mesh representation. */ - void - toggleMeshRepresentation (); - - /** \brief Set the mesh representation. */ - void - setMeshRepresentation (const MeshRepresentation& representation); - - /** \brief Toggle the coloring mode. */ - void - toggleColoring (); - - /** \brief Set the coloring mode. */ - void - setColoring (const Coloring& coloring); - - protected: - - /** \brief Please have a look at the documentation of calcFPS. */ - class FPS - { - public: - - FPS () : fps_ (0.) {} - - inline double& value () {return (fps_);} - inline double value () const {return (fps_);} - - inline std::string - str () const - { - std::stringstream ss; - ss << std::setprecision (1) << std::fixed << fps_; - return (ss.str ()); - } - - protected: - - ~FPS () {} - - private: - - double fps_; - }; + return (fps_); + } - /** Measures the performance of the current thread (selected by passing the corresponding 'fps' helper object). The resulting value is stored in the fps object. */ - template void - calcFPS (FPS& fps) const - { - static pcl::StopWatch sw; - static unsigned int count = 0; - - ++count; - if (sw.getTimeSeconds () >= .2) - { - fps.value () = static_cast (count) / sw.getTimeSeconds (); - count = 0; - sw.reset (); - } - } - - /** \see http://doc.qt.digia.com/qt/qwidget.html#paintEvent - * \see http://doc.qt.digia.com/qt/opengl-overpainting.html - */ - void - paintEvent (QPaintEvent* event) override; + inline std::string + str() const + { + std::stringstream ss; + ss << std::setprecision(1) << std::fixed << fps_; + return (ss.str()); + } + + protected: + ~FPS() {} + + private: + double fps_; + }; + + /** Measures the performance of the current thread (selected by passing the + * corresponding 'fps' helper object). The resulting value is stored in the fps + * object. */ + template + void + calcFPS(FPS& fps) const + { + static pcl::StopWatch sw; + static unsigned int count = 0; + + ++count; + if (sw.getTimeSeconds() >= .2) { + fps.value() = static_cast(count) / sw.getTimeSeconds(); + count = 0; + sw.reset(); + } + } - private: + /** \see http://doc.qt.digia.com/qt/qwidget.html#paintEvent + * \see http://doc.qt.digia.com/qt/opengl-overpainting.html + */ + void + paintEvent(QPaintEvent* event) override; - using Color = Eigen::Matrix ; - using Colors = Eigen::Matrix ; - using Colormap = Eigen::Matrix ; +private: + using Color = Eigen::Matrix; + using Colors = Eigen::Matrix; + using Colormap = Eigen::Matrix; - using CloudXYZRGBNormalMap = std::unordered_map ; + using CloudXYZRGBNormalMap = std::unordered_map; - using PointIHS = pcl::ihs::PointIHS; - using CloudIHS = pcl::ihs::CloudIHS; - using CloudIHSPtr = pcl::ihs::CloudIHSPtr; - using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; + using PointIHS = pcl::ihs::PointIHS; + using CloudIHS = pcl::ihs::CloudIHS; + using CloudIHSPtr = pcl::ihs::CloudIHSPtr; + using CloudIHSConstPtr = pcl::ihs::CloudIHSConstPtr; - using FaceVertexMesh = pcl::ihs::detail::FaceVertexMesh; - using FaceVertexMeshPtr = std::shared_ptr; - using FaceVertexMeshConstPtr = std::shared_ptr; - using FaceVertexMeshMap = std::unordered_map ; + using FaceVertexMesh = pcl::ihs::detail::FaceVertexMesh; + using FaceVertexMeshPtr = std::shared_ptr; + using FaceVertexMeshConstPtr = std::shared_ptr; + using FaceVertexMeshMap = std::unordered_map; - /** \brief Check if the mesh with the given id is added. - * \note Must lock the mutex before calling this method. - */ - bool - getMeshIsAdded (const std::string& id); + /** \brief Check if the mesh with the given id is added. + * + * \note Must lock the mutex before calling this method. + */ + bool + getMeshIsAdded(const std::string& id); - /** \brief Calculate the pivot for the stored id. */ - void - calcPivot (); + /** \brief Calculate the pivot for the stored id. */ + void + calcPivot(); - /** \brief Draw all meshes. - * \note Only triangle meshes are currently supported. - */ - void - drawMeshes (); + /** \brief Draw all meshes. + * + * \note Only triangle meshes are currently supported. + */ + void + drawMeshes(); - /** \brief Draw a wireframe box. */ - void - drawBox (); + /** \brief Draw a wireframe box. */ + void + drawBox(); - /** \see http://doc.qt.digia.com/qt/qglwidget.html#initializeGL */ - void - initializeGL () override; + /** \see http://doc.qt.digia.com/qt/qglwidget.html#initializeGL */ + void + initializeGL() override; - /** \see http://www.opengl.org/sdk/docs/man/xhtml/glViewport.xml */ - void - setupViewport (const int w, const int h); + /** \see http://www.opengl.org/sdk/docs/man/xhtml/glViewport.xml */ + void + setupViewport(const int w, const int h); - /** \see http://doc.qt.digia.com/qt/qglwidget.html#resizeGL */ - void - resizeGL (int w, int h) override; + /** \see http://doc.qt.digia.com/qt/qglwidget.html#resizeGL */ + void + resizeGL(int w, int h) override; - /** \see http://doc.qt.digia.com/qt/qwidget.html#mousePressEvent */ - void - mousePressEvent (QMouseEvent* event) override; + /** \see http://doc.qt.digia.com/qt/qwidget.html#mousePressEvent */ + void + mousePressEvent(QMouseEvent* event) override; - /** \see http://doc.qt.digia.com/qt/qwidget.html#mouseMoveEvent */ - void - mouseMoveEvent (QMouseEvent* event) override; + /** \see http://doc.qt.digia.com/qt/qwidget.html#mouseMoveEvent */ + void + mouseMoveEvent(QMouseEvent* event) override; - /** \see http://doc.qt.digia.com/qt/qwidget.html#wheelEvent */ - void - wheelEvent (QWheelEvent* event) override; + /** \see http://doc.qt.digia.com/qt/qwidget.html#wheelEvent */ + void + wheelEvent(QWheelEvent* event) override; - //////////////////////////////////////////////////////////////////////// - // Members - //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + // Members + //////////////////////////////////////////////////////////////////////// - /** \brief Synchronization. */ - std::mutex mutex_vis_; + /** \brief Synchronization. */ + std::mutex mutex_vis_; - /** \brief Visualization timer. */ - std::shared_ptr timer_vis_; + /** \brief Visualization timer. */ + std::shared_ptr timer_vis_; - /** \brief Colormap. */ - Colormap colormap_; + /** \brief Colormap. */ + Colormap colormap_; - /** \brief The visibility confidence is normalized with this value. */ - float vis_conf_norm_; + /** \brief The visibility confidence is normalized with this value. */ + float vis_conf_norm_; - /** \brief Meshes stored for visualization. */ - FaceVertexMeshMap drawn_meshes_; + /** \brief Meshes stored for visualization. */ + FaceVertexMeshMap drawn_meshes_; - /** \brief How to draw the mesh. */ - MeshRepresentation mesh_representation_; + /** \brief How to draw the mesh. */ + MeshRepresentation mesh_representation_; - /** \brief How to color the shapes. */ - Coloring coloring_; + /** \brief How to color the shapes. */ + Coloring coloring_; - /** \brief A box is drawn if this value is true. */ - bool draw_box_; + /** \brief A box is drawn if this value is true. */ + bool draw_box_; - /** \brief Coefficients of the drawn box. */ - BoxCoefficients box_coefficients_; + /** \brief Coefficients of the drawn box. */ + BoxCoefficients box_coefficients_; - /** \brief Scaling factor to convert from meters to the unit of the drawn files. */ - double scaling_factor_; + /** \brief Scaling factor to convert from meters to the unit of the drawn files. */ + double scaling_factor_; - /** \brief Rotation of the camera. */ - Eigen::Quaterniond R_cam_; + /** \brief Rotation of the camera. */ + Eigen::Quaterniond R_cam_; - /** \brief Translation of the camera. */ - Eigen::Vector3d t_cam_; + /** \brief Translation of the camera. */ + Eigen::Vector3d t_cam_; - /** \brief Center of rotation during mouse navigation. */ - Eigen::Vector3d cam_pivot_; + /** \brief Center of rotation during mouse navigation. */ + Eigen::Vector3d cam_pivot_; - /** \brief Compute the pivot for the mesh with the given id. */ - std::string cam_pivot_id_; + /** \brief Compute the pivot for the mesh with the given id. */ + std::string cam_pivot_id_; - /** \brief Set to true right after the mouse got pressed and false if the mouse got moved. */ - bool mouse_pressed_begin_; + /** \brief Set to true right after the mouse got pressed and false if the mouse got + * moved. */ + bool mouse_pressed_begin_; - /** \brief Mouse x-position of the previous mouse move event. */ - int x_prev_; + /** \brief Mouse x-position of the previous mouse move event. */ + int x_prev_; - /** \brief Mouse y-position of the previous mouse move event. */ - int y_prev_; + /** \brief Mouse y-position of the previous mouse move event. */ + int y_prev_; - public: - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; - } // End namespace ihs +public: + PCL_MAKE_ALIGNED_OPERATOR_NEW +}; +} // End namespace ihs } // End namespace pcl // http://doc.qt.digia.com/qt/qmetatype.html#Q_DECLARE_METATYPE -Q_DECLARE_METATYPE (pcl::ihs::OpenGLViewer::MeshRepresentation) -Q_DECLARE_METATYPE (pcl::ihs::OpenGLViewer::Coloring) +Q_DECLARE_METATYPE(pcl::ihs::OpenGLViewer::MeshRepresentation) +Q_DECLARE_METATYPE(pcl::ihs::OpenGLViewer::Coloring) diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/utils.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/utils.h index 937734a6223..7687a794d13 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/utils.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/utils.h @@ -40,15 +40,16 @@ #pragma once -namespace pcl +namespace pcl { +namespace ihs { +/** \brief Clamp the value to the given range. All values smaller than min are set to + * min and all values bigger than max are set to max. + */ +template +inline T +clamp(const T value, const T min, const T max) { - namespace ihs - { - /** \brief Clamp the value to the given range. All values smaller than min are set to min and all values bigger than max are set to max. */ - template inline T - clamp (const T value, const T min, const T max) - { - return (value < min ? min : value > max ? max : value); - } - } // End namespace ihs + return (value < min ? min : value > max ? max : value); +} +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/visibility_confidence.h b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/visibility_confidence.h index 086baacbf86..16d97412e50 100644 --- a/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/visibility_confidence.h +++ b/apps/in_hand_scanner/include/pcl/apps/in_hand_scanner/visibility_confidence.h @@ -40,49 +40,43 @@ #pragma once -#include - #include #include #include -#include -namespace pcl -{ - namespace ihs - { - // - Frequency 3 Icosahedron where each vertex corresponds to a viewing direction - // - First vertex aligned to z-axis - // - Removed vertices with z < 0.3 - // -> 31 directions, fitting nicely into a 32 bit integer - // -> Very oblique angles are not considered - class PCL_EXPORTS Dome - { - public: - - static const int num_directions = 31; - using Vertices = Eigen::Matrix ; +#include - Dome (); +namespace pcl { +namespace ihs { +// - Frequency 3 Icosahedron where each vertex corresponds to a viewing direction +// - First vertex aligned to z-axis +// - Removed vertices with z < 0.3 +// -> 31 directions, fitting nicely into a 32 bit integer +// -> Very oblique angles are not considered +class PCL_EXPORTS Dome { +public: + static const int num_directions = 31; + using Vertices = Eigen::Matrix; - Vertices - getVertices () const; + Dome(); - private: + Vertices + getVertices() const; - Vertices vertices_; +private: + Vertices vertices_; - public: - PCL_MAKE_ALIGNED_OPERATOR_NEW - }; +public: + PCL_MAKE_ALIGNED_OPERATOR_NEW +}; - PCL_EXPORTS void - addDirection (const Eigen::Vector4f& normal, - const Eigen::Vector4f& direction, - std::uint32_t& directions); +PCL_EXPORTS void +addDirection(const Eigen::Vector4f& normal, + const Eigen::Vector4f& direction, + std::uint32_t& directions); - PCL_EXPORTS unsigned int - countDirections (const std::uint32_t directions); +PCL_EXPORTS unsigned int +countDirections(const std::uint32_t directions); - } // End namespace ihs +} // End namespace ihs } // End namespace pcl diff --git a/apps/in_hand_scanner/src/help_window.cpp b/apps/in_hand_scanner/src/help_window.cpp index 63a24bd8fcb..95b73bca9fe 100644 --- a/apps/in_hand_scanner/src/help_window.cpp +++ b/apps/in_hand_scanner/src/help_window.cpp @@ -38,24 +38,20 @@ * */ - #include + #include "ui_help_window.h" //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::HelpWindow::HelpWindow (QWidget *parent) - : QDialog (parent), - ui (new Ui::HelpWindow) +pcl::ihs::HelpWindow::HelpWindow(QWidget* parent) +: QDialog(parent), ui(new Ui::HelpWindow) { ui->setupUi(this); } //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::HelpWindow::~HelpWindow() -{ - delete ui; -} +pcl::ihs::HelpWindow::~HelpWindow() { delete ui; } //////////////////////////////////////////////////////////////////////////////// diff --git a/apps/in_hand_scanner/src/icp.cpp b/apps/in_hand_scanner/src/icp.cpp index 0688595ed46..b3ae1372f41 100644 --- a/apps/in_hand_scanner/src/icp.cpp +++ b/apps/in_hand_scanner/src/icp.cpp @@ -39,43 +39,43 @@ */ #include - -#include -#include -#include -#include - -#include +#include #include #include +#include -#include +#include +#include +#include +#include //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::ICP::ICP () - : kd_tree_ (new pcl::KdTreeFLANN ()), +pcl::ihs::ICP::ICP() +: kd_tree_(new pcl::KdTreeFLANN()) +, - epsilon_ (10e-6f), - max_iterations_ (50), - min_overlap_ (.75f), - max_fitness_ (.1f), +epsilon_(10e-6f) +, max_iterations_(50) +, min_overlap_(.75f) +, max_fitness_(.1f) +, - factor_ (9.f), - max_angle_ (45.f) -{ -} +factor_(9.f) +, max_angle_(45.f) +{} //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::ICP::setEpsilon (const float epsilon) +pcl::ihs::ICP::setEpsilon(const float epsilon) { - if (epsilon > 0) epsilon_ = epsilon; + if (epsilon > 0) + epsilon_ = epsilon; } float -pcl::ihs::ICP::getEpsilon () const +pcl::ihs::ICP::getEpsilon() const { return (epsilon_); } @@ -83,13 +83,13 @@ pcl::ihs::ICP::getEpsilon () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::ICP::setMaxIterations (const unsigned int max_iter) +pcl::ihs::ICP::setMaxIterations(const unsigned int max_iter) { max_iterations_ = max_iter < 1 ? 1 : max_iter; } unsigned int -pcl::ihs::ICP::getMaxIterations () const +pcl::ihs::ICP::getMaxIterations() const { return (max_iterations_); } @@ -97,13 +97,13 @@ pcl::ihs::ICP::getMaxIterations () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::ICP::setMinOverlap (const float overlap) +pcl::ihs::ICP::setMinOverlap(const float overlap) { - min_overlap_ = pcl::ihs::clamp (overlap, 0.f, 1.f); + min_overlap_ = pcl::ihs::clamp(overlap, 0.f, 1.f); } float -pcl::ihs::ICP::getMinOverlap () const +pcl::ihs::ICP::getMinOverlap() const { return (min_overlap_); } @@ -111,13 +111,14 @@ pcl::ihs::ICP::getMinOverlap () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::ICP::setMaxFitness (const float fitness) +pcl::ihs::ICP::setMaxFitness(const float fitness) { - if (fitness > 0) max_fitness_ = fitness; + if (fitness > 0) + max_fitness_ = fitness; } float -pcl::ihs::ICP::getMaxFitness () const +pcl::ihs::ICP::getMaxFitness() const { return (max_fitness_); } @@ -125,13 +126,13 @@ pcl::ihs::ICP::getMaxFitness () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::ICP::setCorrespondenceRejectionFactor (const float factor) +pcl::ihs::ICP::setCorrespondenceRejectionFactor(const float factor) { factor_ = factor < 1.f ? 1.f : factor; } float -pcl::ihs::ICP::getCorrespondenceRejectionFactor () const +pcl::ihs::ICP::getCorrespondenceRejectionFactor() const { return (factor_); } @@ -139,13 +140,13 @@ pcl::ihs::ICP::getCorrespondenceRejectionFactor () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::ICP::setMaxAngle (const float angle) +pcl::ihs::ICP::setMaxAngle(const float angle) { - max_angle_ = pcl::ihs::clamp (angle, 0.f, 180.f); + max_angle_ = pcl::ihs::clamp(angle, 0.f, 180.f); } float -pcl::ihs::ICP::getMaxAngle () const +pcl::ihs::ICP::getMaxAngle() const { return (max_angle_); } @@ -153,17 +154,16 @@ pcl::ihs::ICP::getMaxAngle () const //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::ICP::findTransformation (const MeshConstPtr& mesh_model, - const CloudXYZRGBNormalConstPtr& cloud_data, - const Eigen::Matrix4f& T_init, - Eigen::Matrix4f& T_final) +pcl::ihs::ICP::findTransformation(const MeshConstPtr& mesh_model, + const CloudXYZRGBNormalConstPtr& cloud_data, + const Eigen::Matrix4f& T_init, + Eigen::Matrix4f& T_final) { // Check the input // TODO: Double check the minimum number of points necessary for icp const std::size_t n_min = 4; - if(mesh_model->sizeVertices () < n_min || cloud_data->size () < n_min) - { + if (mesh_model->sizeVertices() < n_min || cloud_data->size() < n_min) { std::cerr << "ERROR in icp.cpp: Not enough input points!\n"; return (false); } @@ -171,15 +171,15 @@ pcl::ihs::ICP::findTransformation (const MeshConstPtr& mesh_model, // Time measurements pcl::StopWatch sw; pcl::StopWatch sw_total; - double t_select = 0.; - double t_build = 0.; - double t_nn_search = 0.; + double t_select = 0.; + double t_build = 0.; + double t_nn_search = 0.; double t_calc_trafo = 0.; // Convergence and registration failure - float current_fitness = 0.f; - float delta_fitness = std::numeric_limits ::max (); - float overlap = std::numeric_limits ::quiet_NaN (); + float current_fitness = 0.f; + float delta_fitness = std::numeric_limits::max(); + float overlap = std::numeric_limits::quiet_NaN(); // Outlier rejection float squared_distance_threshold = std::numeric_limits::max(); @@ -188,204 +188,207 @@ pcl::ihs::ICP::findTransformation (const MeshConstPtr& mesh_model, Eigen::Matrix4f T_cur = T_init; // Point selection - sw.reset (); - const CloudNormalConstPtr cloud_model_selected = this->selectModelPoints (mesh_model, T_init.inverse ()); - const CloudNormalConstPtr cloud_data_selected = this->selectDataPoints (cloud_data); - t_select = sw.getTime (); - - const std::size_t n_model = cloud_model_selected->size (); - const std::size_t n_data = cloud_data_selected->size (); - if(n_model < n_min) {std::cerr << "ERROR in icp.cpp: Not enough model points after selection!\n"; return (false);} - if(n_data < n_min) {std::cerr << "ERROR in icp.cpp: Not enough data points after selection!\n"; return (false);} + sw.reset(); + const CloudNormalConstPtr cloud_model_selected = + this->selectModelPoints(mesh_model, T_init.inverse()); + const CloudNormalConstPtr cloud_data_selected = this->selectDataPoints(cloud_data); + t_select = sw.getTime(); + + const std::size_t n_model = cloud_model_selected->size(); + const std::size_t n_data = cloud_data_selected->size(); + if (n_model < n_min) { + std::cerr << "ERROR in icp.cpp: Not enough model points after selection!\n"; + return (false); + } + if (n_data < n_min) { + std::cerr << "ERROR in icp.cpp: Not enough data points after selection!\n"; + return (false); + } // Build a kd-tree - sw.reset (); - kd_tree_->setInputCloud (cloud_model_selected); - t_build = sw.getTime (); + sw.reset(); + kd_tree_->setInputCloud(cloud_model_selected); + t_build = sw.getTime(); - std::vector index (1); - std::vector squared_distance (1); + pcl::Indices index(1); + std::vector squared_distance(1); // Clouds with one to one correspondences CloudNormal cloud_model_corr; CloudNormal cloud_data_corr; - cloud_model_corr.reserve (n_data); - cloud_data_corr.reserve (n_data); + cloud_model_corr.reserve(n_data); + cloud_data_corr.reserve(n_data); // ICP main loop unsigned int iter = 1; PointNormal pt_d; - const float dot_min = std::cos (max_angle_ * 17.45329252e-3); // deg to rad - while (true) - { + const float dot_min = std::cos(max_angle_ * 17.45329252e-3); // deg to rad + while (true) { // Accumulated error float squared_distance_sum = 0.f; // NN search - cloud_model_corr.clear (); - cloud_data_corr.clear (); - sw.reset (); - for (CloudNormal::const_iterator it_d = cloud_data_selected->begin (); it_d!=cloud_data_selected->end (); ++it_d) - { + cloud_model_corr.clear(); + cloud_data_corr.clear(); + sw.reset(); + for (CloudNormal::const_iterator it_d = cloud_data_selected->begin(); + it_d != cloud_data_selected->end(); + ++it_d) { // Transform the data point pt_d = *it_d; - pt_d.getVector4fMap () = T_cur * pt_d.getVector4fMap (); - pt_d.getNormalVector4fMap () = T_cur * pt_d.getNormalVector4fMap (); + pt_d.getVector4fMap() = T_cur * pt_d.getVector4fMap(); + pt_d.getNormalVector4fMap() = T_cur * pt_d.getNormalVector4fMap(); // Find the correspondence to the model points - if (!kd_tree_->nearestKSearch (pt_d, 1, index, squared_distance)) - { + if (!kd_tree_->nearestKSearch(pt_d, 1, index, squared_distance)) { std::cerr << "ERROR in icp.cpp: nearestKSearch failed!\n"; return (false); } // Check the distance threshold - if (squared_distance [0] < squared_distance_threshold) - { - if ((std::size_t) index [0] >= cloud_model_selected->size ()) - { + if (squared_distance[0] < squared_distance_threshold) { + if ((std::size_t)index[0] >= cloud_model_selected->size()) { std::cerr << "ERROR in icp.cpp: Segfault!\n"; - std::cerr << " Trying to access index " << index [0] << " >= " << cloud_model_selected->size () << std::endl; - exit (EXIT_FAILURE); + std::cerr << " Trying to access index " << index[0] + << " >= " << cloud_model_selected->size() << std::endl; + exit(EXIT_FAILURE); } - const PointNormal& pt_m = cloud_model_selected->operator [] (index [0]); + const PointNormal& pt_m = cloud_model_selected->operator[](index[0]); // Check the normals threshold - if (pt_m.getNormalVector4fMap ().dot (pt_d.getNormalVector4fMap ()) > dot_min) - { - squared_distance_sum += squared_distance [0]; + if (pt_m.getNormalVector4fMap().dot(pt_d.getNormalVector4fMap()) > dot_min) { + squared_distance_sum += squared_distance[0]; - cloud_model_corr.push_back (pt_m); - cloud_data_corr.push_back (pt_d); + cloud_model_corr.push_back(pt_m); + cloud_data_corr.push_back(pt_d); } } } - t_nn_search += sw.getTime (); + t_nn_search += sw.getTime(); - const std::size_t n_corr = cloud_data_corr.size (); - if (n_corr < n_min) - { - std::cerr << "ERROR in icp.cpp: Not enough correspondences: " << n_corr << " < " << n_min << std::endl; + const std::size_t n_corr = cloud_data_corr.size(); + if (n_corr < n_min) { + std::cerr << "ERROR in icp.cpp: Not enough correspondences: " << n_corr << " < " + << n_min << std::endl; return (false); } - // NOTE: The fitness is calculated with the transformation from the previous iteration (I don't re-calculate it after the transformation estimation). This means that the actual fitness will be one iteration "better" than the calculated fitness suggests. This should be no problem because the difference is small at the state of convergence. + // NOTE: The fitness is calculated with the transformation from the previous + // iteration (I don't re-calculate it after the transformation estimation). This + // means that the actual fitness will be one iteration "better" than the calculated + // fitness suggests. This should be no problem because the difference is small at + // the state of convergence. float previous_fitness = current_fitness; - current_fitness = squared_distance_sum / static_cast (n_corr); - delta_fitness = std::abs (previous_fitness - current_fitness); + current_fitness = squared_distance_sum / static_cast(n_corr); + delta_fitness = std::abs(previous_fitness - current_fitness); squared_distance_threshold = factor_ * current_fitness; - overlap = static_cast (n_corr) / static_cast (n_data); + overlap = static_cast(n_corr) / static_cast(n_data); // std::cerr << "Iter: " << std::left << std::setw(3) << iter // << " | Overlap: " << std::setprecision(2) << std::setw(4) << overlap - // << " | current fitness: " << std::setprecision(5) << std::setw(10) << current_fitness - // << " | delta fitness: " << std::setprecision(5) << std::setw(10) << delta_fitness << std::endl; + // << " | current fitness: " << std::setprecision(5) << std::setw(10) + // << current_fitness + // << " | delta fitness: " << std::setprecision(5) << std::setw(10) << + // delta_fitness << std::endl; // Minimize the point to plane distance - sw.reset (); - Eigen::Matrix4f T_delta = Eigen::Matrix4f::Identity (); - if (!this->minimizePointPlane (cloud_data_corr, cloud_model_corr, T_delta)) - { + sw.reset(); + Eigen::Matrix4f T_delta = Eigen::Matrix4f::Identity(); + if (!this->minimizePointPlane(cloud_data_corr, cloud_model_corr, T_delta)) { std::cerr << "ERROR in icp.cpp: minimizePointPlane failed!\n"; return (false); } - t_calc_trafo += sw.getTime (); + t_calc_trafo += sw.getTime(); T_cur = T_delta * T_cur; // Convergence - if (delta_fitness < epsilon_) break; + if (delta_fitness < epsilon_) + break; ++iter; - if (iter > max_iterations_) break; + if (iter > max_iterations_) + break; } // End ICP main loop // Some output std::cerr << "Registration:\n" - << " - num model / num data : " - << std::setw (8) << std::right << n_model << " / " - << std::setw (8) << std::left << n_data << "\n" + << " - num model / num data : " << std::setw(8) << std::right + << n_model << " / " << std::setw(8) << std::left << n_data << "\n" - << std::scientific << std::setprecision (1) + << std::scientific << std::setprecision(1) - << " - delta fitness / epsilon : " - << std::setw (8) << std::right << delta_fitness << " / " - << std::setw (8) << std::left << epsilon_ + << " - delta fitness / epsilon : " << std::setw(8) << std::right + << delta_fitness << " / " << std::setw(8) << std::left << epsilon_ << (delta_fitness < epsilon_ ? " <-- :-)\n" : "\n") - << " - fitness / max fitness : " - << std::setw (8) << std::right << current_fitness << " / " - << std::setw (8) << std::left << max_fitness_ + << " - fitness / max fitness : " << std::setw(8) << std::right + << current_fitness << " / " << std::setw(8) << std::left << max_fitness_ << (current_fitness > max_fitness_ ? " <-- :-(\n" : "\n") - << std::fixed << std::setprecision (2) + << std::fixed << std::setprecision(2) - << " - iter / max iter : " - << std::setw (8) << std::right << iter << " / " - << std::setw (8) << std::left << max_iterations_ + << " - iter / max iter : " << std::setw(8) << std::right + << iter << " / " << std::setw(8) << std::left << max_iterations_ << (iter > max_iterations_ ? " <-- :-(\n" : "\n") - << " - overlap / min overlap : " - << std::setw (8) << std::right << overlap << " / " - << std::setw (8) << std::left << min_overlap_ + << " - overlap / min overlap : " << std::setw(8) << std::right + << overlap << " / " << std::setw(8) << std::left << min_overlap_ << (overlap < min_overlap_ ? " <-- :-(\n" : "\n") - << std::fixed << std::setprecision (0) + << std::fixed << std::setprecision(0) - << " - time select : " - << std::setw (8) << std::right << t_select << " ms\n" + << " - time select : " << std::setw(8) << std::right + << t_select << " ms\n" - << " - time build kd-tree : " - << std::setw (8) << std::right << t_build << " ms\n" + << " - time build kd-tree : " << std::setw(8) << std::right + << t_build << " ms\n" - << " - time nn-search / trafo / reject: " - << std::setw (8) << std::right << t_nn_search << " ms\n" + << " - time nn-search / trafo / reject: " << std::setw(8) << std::right + << t_nn_search << " ms\n" - << " - time minimize : " - << std::setw (8) << std::right << t_calc_trafo << " ms\n" + << " - time minimize : " << std::setw(8) << std::right + << t_calc_trafo << " ms\n" - << " - total time : " - << std::setw (8) << std::right << sw_total.getTime () << " ms\n"; + << " - total time : " << std::setw(8) << std::right + << sw_total.getTime() << " ms\n"; - if (iter > max_iterations_ || overlap < min_overlap_ || current_fitness > max_fitness_) - { + if (iter > max_iterations_ || overlap < min_overlap_ || + current_fitness > max_fitness_) { return (false); } - if (delta_fitness <= epsilon_) - { + if (delta_fitness <= epsilon_) { T_final = T_cur; return (true); } std::cerr << "ERROR in icp.cpp: Congratulations! you found a bug.\n"; - exit (EXIT_FAILURE); + exit(EXIT_FAILURE); } //////////////////////////////////////////////////////////////////////////////// pcl::ihs::ICP::CloudNormalConstPtr -pcl::ihs::ICP::selectModelPoints (const MeshConstPtr& mesh_model, - const Eigen::Matrix4f& T_inv) const +pcl::ihs::ICP::selectModelPoints(const MeshConstPtr& mesh_model, + const Eigen::Matrix4f& T_inv) const { - const CloudNormalPtr cloud_model_out (new CloudNormal ()); - cloud_model_out->reserve (mesh_model->sizeVertices ()); + const CloudNormalPtr cloud_model_out(new CloudNormal()); + cloud_model_out->reserve(mesh_model->sizeVertices()); - const Mesh::VertexDataCloud& cloud = mesh_model->getVertexDataCloud (); + const Mesh::VertexDataCloud& cloud = mesh_model->getVertexDataCloud(); - for (const auto &vertex_data : cloud) - { + for (const auto& vertex_data : cloud) { // Don't consider points that are facing away from the camera. - if ((T_inv.lazyProduct (vertex_data.getNormalVector4fMap ())).z () < 0.f) - { + if ((T_inv.lazyProduct(vertex_data.getNormalVector4fMap())).z() < 0.f) { PointNormal pt; - pt.getVector4fMap () = vertex_data.getVector4fMap (); - pt.getNormalVector4fMap () = vertex_data.getNormalVector4fMap (); + pt.getVector4fMap() = vertex_data.getVector4fMap(); + pt.getNormalVector4fMap() = vertex_data.getNormalVector4fMap(); // NOTE: Not the transformed points!! - cloud_model_out->push_back (pt); + cloud_model_out->push_back(pt); } } @@ -395,20 +398,18 @@ pcl::ihs::ICP::selectModelPoints (const MeshConstPtr& mesh_model, //////////////////////////////////////////////////////////////////////////////// pcl::ihs::ICP::CloudNormalConstPtr -pcl::ihs::ICP::selectDataPoints (const CloudXYZRGBNormalConstPtr& cloud_data) const +pcl::ihs::ICP::selectDataPoints(const CloudXYZRGBNormalConstPtr& cloud_data) const { - const CloudNormalPtr cloud_data_out (new CloudNormal ()); - cloud_data_out->reserve (cloud_data->size ()); + const CloudNormalPtr cloud_data_out(new CloudNormal()); + cloud_data_out->reserve(cloud_data->size()); - for (const auto &vertex_data : *cloud_data) - { - if (!std::isnan (vertex_data.x)) - { + for (const auto& vertex_data : *cloud_data) { + if (!std::isnan(vertex_data.x)) { PointNormal pt; - pt.getVector4fMap () = vertex_data.getVector4fMap (); - pt.getNormalVector4fMap () = vertex_data.getNormalVector4fMap (); + pt.getVector4fMap() = vertex_data.getVector4fMap(); + pt.getNormalVector4fMap() = vertex_data.getNormalVector4fMap(); - cloud_data_out->push_back (pt); + cloud_data_out->push_back(pt); } } @@ -418,144 +419,141 @@ pcl::ihs::ICP::selectDataPoints (const CloudXYZRGBNormalConstPtr& cloud_data) co //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::ICP::minimizePointPlane (const CloudNormal& cloud_source, - const CloudNormal& cloud_target, - Eigen::Matrix4f& T) const +pcl::ihs::ICP::minimizePointPlane(const CloudNormal& cloud_source, + const CloudNormal& cloud_target, + Eigen::Matrix4f& T) const { // Check the input // n < n_min already checked in the icp main loop - const std::size_t n = cloud_source.size (); - if (cloud_target.size () != n) - { + const std::size_t n = cloud_source.size(); + if (cloud_target.size() != n) { std::cerr << "ERROR in icp.cpp: Input must have the same size!\n"; return (false); } // For numerical stability - // - Low: Linear Least-Squares Optimization for Point-to-Plane ICP Surface Registration (2004), in the discussion: "To improve the numerical stability of the computation, it is important to use a unit of distance that is comparable in magnitude with the rotation angles. The simplest way is to rescale and move the two input surfaces so that they are bounded within a unit sphere or cube centered at the origin." - // - Gelfand et al.: Geometrically Stable Sampling for the ICP Algorithm (2003), in sec 3.1: "As is common with PCA methods, we will shift the center of mass of the points to the origin." ... "Therefore, af- ter shifting the center of mass, we will scale the point set so that the average distance of points from the origin is 1." - // - Hartley, Zisserman: - Multiple View Geometry (2004), page 109: They normalize to sqrt(2) + // - Low: Linear Least-Squares Optimization for Point-to-Plane ICP Surface + // Registration (2004), in the discussion: "To improve the numerical stability of the + // computation, it is important to use a unit of distance that is comparable in + // magnitude with the rotation angles. The simplest way is to rescale and move the two + // input surfaces so that they are bounded within a unit sphere or cube centered at + // the origin." + // - Gelfand et al.: Geometrically Stable Sampling for the ICP Algorithm (2003), in + // sec 3.1: "As is common with PCA methods, we will shift the center of mass of the + // points to the origin." ... "Therefore, af- ter shifting the center of mass, we will + // scale the point set so that the average distance of points from the origin is 1." + // - Hartley, Zisserman: - Multiple View Geometry (2004), page 109: They normalize to + // sqrt(2) // TODO: Check the resulting C matrix for the conditioning. // Subtract the centroid and calculate the scaling factor - Eigen::Vector4f c_s (0.f, 0.f, 0.f, 1.f); - Eigen::Vector4f c_t (0.f, 0.f, 0.f, 1.f); - pcl::compute3DCentroid (cloud_source, c_s); c_s.w () = 1.f; - pcl::compute3DCentroid (cloud_target, c_t); c_t.w () = 1.f; + Eigen::Vector4f c_s(0.f, 0.f, 0.f, 1.f); + Eigen::Vector4f c_t(0.f, 0.f, 0.f, 1.f); + pcl::compute3DCentroid(cloud_source, c_s); + c_s.w() = 1.f; + pcl::compute3DCentroid(cloud_target, c_t); + c_t.w() = 1.f; // The normals are only needed for the target - using Vec4Xf = std::vector >; + using Vec4Xf = + std::vector>; Vec4Xf xyz_s, xyz_t, nor_t; - xyz_s.reserve (n); - xyz_t.reserve (n); - nor_t.reserve (n); + xyz_s.reserve(n); + xyz_t.reserve(n); + nor_t.reserve(n); - CloudNormal::const_iterator it_s = cloud_source.begin (); - CloudNormal::const_iterator it_t = cloud_target.begin (); + CloudNormal::const_iterator it_s = cloud_source.begin(); + CloudNormal::const_iterator it_t = cloud_target.begin(); float accum = 0.f; Eigen::Vector4f pt_s, pt_t; - for (; it_s!=cloud_source.end (); ++it_s, ++it_t) - { + for (; it_s != cloud_source.end(); ++it_s, ++it_t) { // Subtract the centroid - pt_s = it_s->getVector4fMap () - c_s; - pt_t = it_t->getVector4fMap () - c_t; + pt_s = it_s->getVector4fMap() - c_s; + pt_t = it_t->getVector4fMap() - c_t; - xyz_s.push_back (pt_s); - xyz_t.push_back (pt_t); - nor_t.push_back (it_t->getNormalVector4fMap ()); + xyz_s.push_back(pt_s); + xyz_t.push_back(pt_t); + nor_t.push_back(it_t->getNormalVector4fMap()); - // Calculate the radius (L2 norm) of the bounding sphere through both shapes and accumulate the average + // Calculate the radius (L2 norm) of the bounding sphere through both shapes and + // accumulate the average // TODO: Change to squared norm and adapt the rest accordingly - accum += pt_s.head <3> ().norm () + pt_t.head <3> ().norm (); + accum += pt_s.head<3>().norm() + pt_t.head<3>().norm(); } // Inverse factor (do a multiplication instead of division later) - const float factor = 2.f * static_cast (n) / accum; - const float factor_squared = factor*factor; + const float factor = 2.f * static_cast(n) / accum; + const float factor_squared = factor * factor; // Covariance matrix C - Eigen::Matrix C; + Eigen::Matrix C; // Right hand side vector b - Eigen::Matrix b; + Eigen::Matrix b; // For Eigen vectorization: use 4x4 submatrixes instead of 3x3 submatrixes // -> top left 3x3 matrix will form the final C // Same for b - Eigen::Matrix4f C_tl = Eigen::Matrix4f::Zero(); // top left corner + Eigen::Matrix4f C_tl = Eigen::Matrix4f::Zero(); // top left corner Eigen::Matrix4f C_tr_bl = Eigen::Matrix4f::Zero(); // top right / bottom left - Eigen::Matrix4f C_br = Eigen::Matrix4f::Zero(); // bottom right + Eigen::Matrix4f C_br = Eigen::Matrix4f::Zero(); // bottom right - Eigen::Vector4f b_t = Eigen::Vector4f::Zero(); // top - Eigen::Vector4f b_b = Eigen::Vector4f::Zero(); // bottom + Eigen::Vector4f b_t = Eigen::Vector4f::Zero(); // top + Eigen::Vector4f b_b = Eigen::Vector4f::Zero(); // bottom - Vec4Xf::const_iterator it_xyz_s = xyz_s.begin (); - Vec4Xf::const_iterator it_xyz_t = xyz_t.begin (); - Vec4Xf::const_iterator it_nor_t = nor_t.begin (); + Vec4Xf::const_iterator it_xyz_s = xyz_s.begin(); + Vec4Xf::const_iterator it_xyz_t = xyz_t.begin(); + Vec4Xf::const_iterator it_nor_t = nor_t.begin(); Eigen::Vector4f cross; - for (; it_xyz_s!=xyz_s.end (); ++it_xyz_s, ++it_xyz_t, ++it_nor_t) - { - cross = it_xyz_s->cross3 (*it_nor_t); + for (; it_xyz_s != xyz_s.end(); ++it_xyz_s, ++it_xyz_t, ++it_nor_t) { + cross = it_xyz_s->cross3(*it_nor_t); - C_tl += cross * cross. transpose (); - C_tr_bl += cross * it_nor_t->transpose (); - C_br += *it_nor_t * it_nor_t->transpose (); + C_tl += cross * cross.transpose(); + C_tr_bl += cross * it_nor_t->transpose(); + C_br += *it_nor_t * it_nor_t->transpose(); - float dot = (*it_xyz_t-*it_xyz_s).dot (*it_nor_t); + float dot = (*it_xyz_t - *it_xyz_s).dot(*it_nor_t); - b_t += cross * dot; - b_b += *it_nor_t * dot; + b_t += cross * dot; + b_b += *it_nor_t * dot; } // Scale with the factor and copy the 3x3 submatrixes into C and b - C_tl *= factor_squared; + C_tl *= factor_squared; C_tr_bl *= factor; - C << C_tl. topLeftCorner <3, 3> () , C_tr_bl.topLeftCorner <3, 3> (), - C_tr_bl.topLeftCorner <3, 3> ().transpose(), C_br. topLeftCorner <3, 3> (); + C << C_tl.topLeftCorner<3, 3>(), C_tr_bl.topLeftCorner<3, 3>(), + C_tr_bl.topLeftCorner<3, 3>().transpose(), C_br.topLeftCorner<3, 3>(); - b << b_t.head <3> () * factor_squared, - b_b. head <3> () * factor; + b << b_t.head<3>() * factor_squared, b_b.head<3>() * factor; // Solve C * x = b with a Cholesky factorization with pivoting // x = [alpha; beta; gamma; trans_x; trans_y; trans_z] - Eigen::Matrix x = C.selfadjointView ().ldlt ().solve (b); + Eigen::Matrix x = C.selfadjointView().ldlt().solve(b); // The calculated transformation in the scaled coordinate system - const float - sa = std::sin (x (0)), - ca = std::cos (x (0)), - sb = std::sin (x (1)), - cb = std::cos (x (1)), - sg = std::sin (x (2)), - cg = std::cos (x (2)), - tx = x (3), - ty = x (4), - tz = x (5); + const float sa = std::sin(x(0)), ca = std::cos(x(0)), sb = std::sin(x(1)), + cb = std::cos(x(1)), sg = std::sin(x(2)), cg = std::cos(x(2)), tx = x(3), + ty = x(4), tz = x(5); Eigen::Matrix4f TT; - TT << cg*cb, -sg*ca+cg*sb*sa, sg*sa+cg*sb*ca, tx, - sg*cb , cg*ca+sg*sb*sa, -cg*sa+sg*sb*ca, ty, - -sb , cb*sa , cb*ca , tz, - 0.f , 0.f , 0.f , 1.f; + TT << cg * cb, -sg * ca + cg * sb * sa, sg * sa + cg * sb * ca, tx, sg * cb, + cg * ca + sg * sb * sa, -cg * sa + sg * sb * ca, ty, -sb, cb * sa, cb * ca, tz, + 0.f, 0.f, 0.f, 1.f; // Transformation matrixes into the local coordinate systems of model/data Eigen::Matrix4f T_s, T_t; - T_s << factor, 0.f , 0.f , -c_s.x () * factor, - 0.f , factor, 0.f , -c_s.y () * factor, - 0.f , 0.f , factor, -c_s.z () * factor, - 0.f , 0.f , 0.f , 1.f; + T_s << factor, 0.f, 0.f, -c_s.x() * factor, 0.f, factor, 0.f, -c_s.y() * factor, 0.f, + 0.f, factor, -c_s.z() * factor, 0.f, 0.f, 0.f, 1.f; - T_t << factor, 0.f , 0.f , -c_t.x () * factor, - 0.f , factor, 0.f , -c_t.y () * factor, - 0.f , 0.f , factor, -c_t.z () * factor, - 0.f , 0.f , 0.f , 1.f; + T_t << factor, 0.f, 0.f, -c_t.x() * factor, 0.f, factor, 0.f, -c_t.y() * factor, 0.f, + 0.f, factor, -c_t.z() * factor, 0.f, 0.f, 0.f, 1.f; // Output transformation T - T = T_t.inverse () * TT * T_s; + T = T_t.inverse() * TT * T_s; return (true); } diff --git a/apps/in_hand_scanner/src/in_hand_scanner.cpp b/apps/in_hand_scanner/src/in_hand_scanner.cpp index c385c0635e3..95d2744c610 100644 --- a/apps/in_hand_scanner/src/in_hand_scanner.cpp +++ b/apps/in_hand_scanner/src/in_hand_scanner.cpp @@ -38,326 +38,355 @@ * */ +#include #include - -#include -#include -#include -#include -#include - -#include +#include +#include +#include #include #include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::InHandScanner::InHandScanner (Base* parent) - : Base (parent), - running_mode_ (RM_UNPROCESSED), - iteration_ (0), - starting_grabber_ (false), - input_data_processing_ (new InputDataProcessing ()), - icp_ (new ICP ()), - transformation_ (Eigen::Matrix4f::Identity ()), - integration_ (new Integration ()), - mesh_processing_ (new MeshProcessing ()), - mesh_model_ (new Mesh ()), - destructor_called_ (false) +pcl::ihs::InHandScanner::InHandScanner(Base* parent) +: Base(parent) +, running_mode_(RM_UNPROCESSED) +, iteration_(0) +, starting_grabber_(false) +, input_data_processing_(new InputDataProcessing()) +, icp_(new ICP()) +, transformation_(Eigen::Matrix4f::Identity()) +, integration_(new Integration()) +, mesh_processing_(new MeshProcessing()) +, mesh_model_(new Mesh()) +, destructor_called_(false) { // http://doc.qt.digia.com/qt/qmetatype.html#qRegisterMetaType - qRegisterMetaType ("RunningMode"); + qRegisterMetaType("RunningMode"); - Base::setScalingFactor (0.01); + Base::setScalingFactor(0.01); // Initialize the pivot - const float x_min = input_data_processing_->getXMin (); - const float x_max = input_data_processing_->getXMax (); - const float y_min = input_data_processing_->getYMin (); - const float y_max = input_data_processing_->getYMax (); - const float z_min = input_data_processing_->getZMin (); - const float z_max = input_data_processing_->getZMax (); - - Base::setPivot (Eigen::Vector3d ((x_min + x_max) / 2., (y_min + y_max) / 2., (z_min + z_max) / 2.)); + const float x_min = input_data_processing_->getXMin(); + const float x_max = input_data_processing_->getXMax(); + const float y_min = input_data_processing_->getYMin(); + const float y_max = input_data_processing_->getYMax(); + const float z_min = input_data_processing_->getZMin(); + const float z_max = input_data_processing_->getZMax(); + + Base::setPivot(Eigen::Vector3d( + (x_min + x_max) / 2., (y_min + y_max) / 2., (z_min + z_max) / 2.)); } //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::InHandScanner::~InHandScanner () +pcl::ihs::InHandScanner::~InHandScanner() { - std::lock_guard lock (mutex_); + std::lock_guard lock(mutex_); destructor_called_ = true; - if (grabber_ && grabber_->isRunning ()) grabber_->stop (); - if (new_data_connection_.connected ()) new_data_connection_.disconnect (); + if (grabber_ && grabber_->isRunning()) + grabber_->stop(); + if (new_data_connection_.connected()) + new_data_connection_.disconnect(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::startGrabber () +pcl::ihs::InHandScanner::startGrabber() { - QtConcurrent::run ([this] { startGrabberImpl (); }); + QtConcurrent::run([this] { startGrabberImpl(); }); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::showUnprocessedData () +pcl::ihs::InHandScanner::showUnprocessedData() { - std::lock_guard lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; std::cerr << "Showing the unprocessed input data.\n"; - Base::setDrawBox (false); - Base::setColoring (Base::COL_RGB); + Base::setDrawBox(false); + Base::setColoring(Base::COL_RGB); running_mode_ = RM_UNPROCESSED; - emit runningModeChanged (running_mode_); + emit runningModeChanged(running_mode_); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::showProcessedData () +pcl::ihs::InHandScanner::showProcessedData() { - std::lock_guard lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; std::cerr << "Showing the processed input data.\n"; - Base::setDrawBox (true); - Base::setColoring (Base::COL_RGB); + Base::setDrawBox(true); + Base::setColoring(Base::COL_RGB); running_mode_ = RM_PROCESSED; - emit runningModeChanged (running_mode_); + emit runningModeChanged(running_mode_); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::registerContinuously () +pcl::ihs::InHandScanner::registerContinuously() { - std::lock_guard lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; std::cerr << "Continuous registration.\n"; - Base::setDrawBox (true); - Base::setColoring (Base::COL_VISCONF); + Base::setDrawBox(true); + Base::setColoring(Base::COL_VISCONF); running_mode_ = RM_REGISTRATION_CONT; - emit runningModeChanged (running_mode_); + emit runningModeChanged(running_mode_); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::registerOnce () +pcl::ihs::InHandScanner::registerOnce() { - std::lock_guard lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; std::cerr << "Single registration.\n"; - Base::setDrawBox (true); + Base::setDrawBox(true); running_mode_ = RM_REGISTRATION_SINGLE; - emit runningModeChanged (running_mode_); + emit runningModeChanged(running_mode_); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::showModel () +pcl::ihs::InHandScanner::showModel() { - std::lock_guard lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; std::cerr << "Show the model\n"; - Base::setDrawBox (false); + Base::setDrawBox(false); running_mode_ = RM_SHOW_MODEL; - emit runningModeChanged (running_mode_); + emit runningModeChanged(running_mode_); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::removeUnfitVertices () +pcl::ihs::InHandScanner::removeUnfitVertices() { - std::unique_lock lock (mutex_); - if (destructor_called_) return; + std::unique_lock lock(mutex_); + if (destructor_called_) + return; std::cerr << "Removing unfit vertices ...\n"; - integration_->removeUnfitVertices (mesh_model_); - if (mesh_model_->emptyVertices ()) - { + integration_->removeUnfitVertices(mesh_model_); + if (mesh_model_->emptyVertices()) { std::cerr << "Mesh got empty -> Reset\n"; - lock.unlock (); - this->reset (); + lock.unlock(); + this->reset(); } - else - { - lock.unlock (); - this->showModel (); + else { + lock.unlock(); + this->showModel(); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::reset () +pcl::ihs::InHandScanner::reset() { - std::unique_lock lock (mutex_); - if (destructor_called_) return; + std::unique_lock lock(mutex_); + if (destructor_called_) + return; std::cerr << "Reset the scanning pipeline.\n"; - mesh_model_->clear (); - Base::removeAllMeshes (); + mesh_model_->clear(); + Base::removeAllMeshes(); - iteration_ = 0; - transformation_ = Eigen::Matrix4f::Identity (); + iteration_ = 0; + transformation_ = Eigen::Matrix4f::Identity(); - lock.unlock (); - this->showUnprocessedData (); + lock.unlock(); + this->showUnprocessedData(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::saveAs (const std::string& filename, const FileType& filetype) +pcl::ihs::InHandScanner::saveAs(const std::string& filename, const FileType& filetype) { - std::lock_guard lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; pcl::PolygonMesh pm; - pcl::geometry::toFaceVertexMesh (*mesh_model_, pm); - - switch (filetype) - { - case FT_PLY: pcl::io::savePLYFile (filename, pm); break; - case FT_VTK: pcl::io::saveVTKFile (filename, pm); break; - default: break; + pcl::geometry::toFaceVertexMesh(*mesh_model_, pm); + + switch (filetype) { + case FT_PLY: + pcl::io::savePLYFile(filename, pm); + break; + case FT_VTK: + pcl::io::saveVTKFile(filename, pm); + break; + default: + break; } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::keyPressEvent (QKeyEvent* event) +pcl::ihs::InHandScanner::keyPressEvent(QKeyEvent* event) { // Don't allow keyboard callbacks while the grabber is starting up. - if (starting_grabber_) return; - if (destructor_called_) return; - - switch (event->key ()) - { - case Qt::Key_1: this->showUnprocessedData (); break; - case Qt::Key_2: this->showProcessedData (); break; - case Qt::Key_3: this->registerContinuously (); break; - case Qt::Key_4: this->registerOnce (); break; - case Qt::Key_5: this->showModel (); break; - case Qt::Key_6: this->removeUnfitVertices (); break; - case Qt::Key_0: this->reset (); break; - case Qt::Key_C: Base::resetCamera (); break; - case Qt::Key_K: Base::toggleColoring (); break; - case Qt::Key_S: Base::toggleMeshRepresentation (); break; - default: break; + if (starting_grabber_) + return; + if (destructor_called_) + return; + + switch (event->key()) { + case Qt::Key_1: + this->showUnprocessedData(); + break; + case Qt::Key_2: + this->showProcessedData(); + break; + case Qt::Key_3: + this->registerContinuously(); + break; + case Qt::Key_4: + this->registerOnce(); + break; + case Qt::Key_5: + this->showModel(); + break; + case Qt::Key_6: + this->removeUnfitVertices(); + break; + case Qt::Key_0: + this->reset(); + break; + case Qt::Key_C: + Base::resetCamera(); + break; + case Qt::Key_K: + Base::toggleColoring(); + break; + case Qt::Key_S: + Base::toggleMeshRepresentation(); + break; + default: + break; } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::newDataCallback (const CloudXYZRGBAConstPtr& cloud_in) +pcl::ihs::InHandScanner::newDataCallback(const CloudXYZRGBAConstPtr& cloud_in) { - Base::calcFPS (computation_fps_); // Must come before the lock! + Base::calcFPS(computation_fps_); // Must come before the lock! - std::unique_lock lock (mutex_); - if (destructor_called_) return; + std::unique_lock lock(mutex_); + if (destructor_called_) + return; pcl::StopWatch sw; // Input data processing CloudXYZRGBNormalPtr cloud_data; CloudXYZRGBNormalPtr cloud_discarded; - if (running_mode_ == RM_SHOW_MODEL) - { - cloud_data = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); + if (running_mode_ == RM_SHOW_MODEL) { + cloud_data = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); } - else if (running_mode_ == RM_UNPROCESSED) - { - if (!input_data_processing_->calculateNormals (cloud_in, cloud_data)) + else if (running_mode_ == RM_UNPROCESSED) { + if (!input_data_processing_->calculateNormals(cloud_in, cloud_data)) return; } - else if (running_mode_ >= RM_PROCESSED) - { - if (!input_data_processing_->segment (cloud_in, cloud_data, cloud_discarded)) + else if (running_mode_ >= RM_PROCESSED) { + if (!input_data_processing_->segment(cloud_in, cloud_data, cloud_discarded)) return; } - double time_input_data_processing = sw.getTime (); + double time_input_data_processing = sw.getTime(); // Registration & integration - if (running_mode_ >= RM_REGISTRATION_CONT) - { + if (running_mode_ >= RM_REGISTRATION_CONT) { std::cerr << "\nGlobal iteration " << iteration_ << "\n"; std::cerr << "Input data processing:\n" - << " - time : " - << std::setw (8) << std::right << time_input_data_processing << " ms\n"; + << " - time : " << std::setw(8) << std::right + << time_input_data_processing << " ms\n"; - if (iteration_ == 0) - { - transformation_ = Eigen::Matrix4f::Identity (); + if (iteration_ == 0) { + transformation_ = Eigen::Matrix4f::Identity(); - sw.reset (); - integration_->reconstructMesh (cloud_data, mesh_model_); + sw.reset(); + integration_->reconstructMesh(cloud_data, mesh_model_); std::cerr << "Integration:\n" - << " - time reconstruct mesh : " - << std::setw (8) << std::right << sw.getTime () << " ms\n"; + << " - time reconstruct mesh : " << std::setw(8) << std::right + << sw.getTime() << " ms\n"; - cloud_data = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); + cloud_data = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); ++iteration_; } - else - { - Eigen::Matrix4f T_final = Eigen::Matrix4f::Identity (); - if (icp_->findTransformation (mesh_model_, cloud_data, transformation_, T_final)) - { + else { + Eigen::Matrix4f T_final = Eigen::Matrix4f::Identity(); + if (icp_->findTransformation(mesh_model_, cloud_data, transformation_, T_final)) { transformation_ = T_final; - sw.reset (); - integration_->merge (cloud_data, mesh_model_, transformation_); + sw.reset(); + integration_->merge(cloud_data, mesh_model_, transformation_); std::cerr << "Integration:\n" - << " - time merge : " - << std::setw (8) << std::right << sw.getTime () << " ms\n"; - - sw.reset (); - integration_->age (mesh_model_); - std::cerr << " - time age : " - << std::setw (8) << std::right << sw.getTime () << " ms\n"; - - sw.reset (); - std::vector boundary_collection; - pcl::geometry::getBoundBoundaryHalfEdges (*mesh_model_, boundary_collection, 1000); - std::cerr << " - time compute boundary : " - << std::setw (8) << std::right << sw.getTime () << " ms\n"; - - sw.reset (); - mesh_processing_->processBoundary (*mesh_model_, boundary_collection); - std::cerr << " - time mesh processing : " - << std::setw (8) << std::right << sw.getTime () << " ms\n"; - - cloud_data = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); + << " - time merge : " << std::setw(8) + << std::right << sw.getTime() << " ms\n"; + + sw.reset(); + integration_->age(mesh_model_); + std::cerr << " - time age : " << std::setw(8) + << std::right << sw.getTime() << " ms\n"; + + sw.reset(); + std::vector boundary_collection; + pcl::geometry::getBoundBoundaryHalfEdges( + *mesh_model_, boundary_collection, 1000); + std::cerr << " - time compute boundary : " << std::setw(8) + << std::right << sw.getTime() << " ms\n"; + + sw.reset(); + mesh_processing_->processBoundary(*mesh_model_, boundary_collection); + std::cerr << " - time mesh processing : " << std::setw(8) + << std::right << sw.getTime() << " ms\n"; + + cloud_data = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); ++iteration_; } } @@ -365,125 +394,132 @@ pcl::ihs::InHandScanner::newDataCallback (const CloudXYZRGBAConstPtr& cloud_in) // Visualization & copy back some variables double time_model = 0; - double time_data = 0; + double time_data = 0; - if (mesh_model_->empty ()) Base::setPivot ("data"); - else Base::setPivot ("model"); + if (mesh_model_->empty()) + Base::setPivot("data"); + else + Base::setPivot("model"); - sw.reset (); - Base::addMesh (mesh_model_, "model", Eigen::Isometry3d (transformation_.inverse ().cast ())); - time_model = sw.getTime (); + sw.reset(); + Base::addMesh(mesh_model_, + "model", + Eigen::Isometry3d(transformation_.inverse().cast())); + time_model = sw.getTime(); - sw.reset (); - Base::addMesh (cloud_data , "data"); // Converts to a mesh for visualization + sw.reset(); + Base::addMesh(cloud_data, "data"); // Converts to a mesh for visualization - if (running_mode_ < RM_REGISTRATION_CONT && cloud_discarded) - { - Base::addMesh (cloud_discarded, "cloud_discarded"); + if (running_mode_ < RM_REGISTRATION_CONT && cloud_discarded) { + Base::addMesh(cloud_discarded, "cloud_discarded"); } - else - { - Base::removeMesh ("cloud_discarded"); + else { + Base::removeMesh("cloud_discarded"); } - time_data = sw.getTime (); + time_data = sw.getTime(); - if (running_mode_ >= RM_REGISTRATION_CONT) - { + if (running_mode_ >= RM_REGISTRATION_CONT) { std::cerr << "Copy to visualization thread:\n" - << " - time model : " - << std::setw (8) << std::right << time_model << " ms\n" - << " - time data : " - << std::setw (8) << std::right << time_data << " ms\n"; + << " - time model : " << std::setw(8) << std::right + << time_model << " ms\n" + << " - time data : " << std::setw(8) << std::right + << time_data << " ms\n"; } - if (running_mode_ == RM_REGISTRATION_SINGLE) - { - lock.unlock (); - this->showProcessedData (); + if (running_mode_ == RM_REGISTRATION_SINGLE) { + lock.unlock(); + this->showProcessedData(); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::paintEvent (QPaintEvent* event) +pcl::ihs::InHandScanner::paintEvent(QPaintEvent* event) { - // std::lock_guard lock (mutex_); - if (destructor_called_) return; - - Base::calcFPS (visualization_fps_); - Base::BoxCoefficients coeffs (input_data_processing_->getXMin (), - input_data_processing_->getXMax (), - input_data_processing_->getYMin (), - input_data_processing_->getYMax (), - input_data_processing_->getZMin (), - input_data_processing_->getZMax (), - Eigen::Isometry3d::Identity ()); - Base::setBoxCoefficients (coeffs); - - Base::setVisibilityConfidenceNormalization (static_cast (integration_->getMinDirections ())); - // lock.unlock (); - - Base::paintEvent (event); - this->drawText (); // NOTE: Must come AFTER the opengl calls + if (destructor_called_) + return; + + Base::calcFPS(visualization_fps_); + Base::BoxCoefficients coeffs(input_data_processing_->getXMin(), + input_data_processing_->getXMax(), + input_data_processing_->getYMin(), + input_data_processing_->getYMax(), + input_data_processing_->getZMin(), + input_data_processing_->getZMax(), + Eigen::Isometry3d::Identity()); + Base::setBoxCoefficients(coeffs); + + Base::setVisibilityConfidenceNormalization( + static_cast(integration_->getMinDirections())); + + Base::paintEvent(event); + this->drawText(); // NOTE: Must come AFTER the opengl calls } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::drawText () +pcl::ihs::InHandScanner::drawText() { - QPainter painter (this); - painter.setPen (Qt::white); + QPainter painter(this); + painter.setPen(Qt::white); QFont font; - if (starting_grabber_) - { - font.setPointSize (this->width () / 20); - painter.setFont (font); - painter.drawText (0, 0, this->width (), this->height (), Qt::AlignHCenter | Qt::AlignVCenter, "Starting the grabber.\n Please wait."); + if (starting_grabber_) { + font.setPointSize(this->width() / 20); + painter.setFont(font); + painter.drawText(0, + 0, + this->width(), + this->height(), + Qt::AlignHCenter | Qt::AlignVCenter, + "Starting the grabber.\n Please wait."); } - else - { - std::string vis_fps ("Visualization: "), comp_fps ("Computation: "); + else { + std::string vis_fps("Visualization: "), comp_fps("Computation: "); - vis_fps.append (visualization_fps_.str ()).append (" fps"); - comp_fps.append (computation_fps_.str ()).append (" fps"); + vis_fps.append(visualization_fps_.str()).append(" fps"); + comp_fps.append(computation_fps_.str()).append(" fps"); - const std::string str = std::string (comp_fps).append ("\n").append (vis_fps); + const std::string str = std::string(comp_fps).append("\n").append(vis_fps); - font.setPointSize (this->width () / 50); + font.setPointSize(this->width() / 50); - painter.setFont (font); - painter.drawText (0, 0, this->width (), this->height (), Qt::AlignBottom | Qt::AlignLeft, str.c_str ()); + painter.setFont(font); + painter.drawText(0, + 0, + this->width(), + this->height(), + Qt::AlignBottom | Qt::AlignLeft, + str.c_str()); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InHandScanner::startGrabberImpl () +pcl::ihs::InHandScanner::startGrabberImpl() { - std::unique_lock lock (mutex_); + std::unique_lock lock(mutex_); starting_grabber_ = true; - lock.unlock (); + lock.unlock(); - try - { - grabber_ = GrabberPtr (new Grabber ()); - } - catch (const pcl::PCLException& e) - { - std::cerr << "ERROR in in_hand_scanner.cpp: " << e.what () << std::endl; - exit (EXIT_FAILURE); + try { + grabber_ = GrabberPtr(new Grabber()); + } catch (const pcl::PCLException& e) { + std::cerr << "ERROR in in_hand_scanner.cpp: " << e.what() << std::endl; + exit(EXIT_FAILURE); } - lock.lock (); - if (destructor_called_) return; + lock.lock(); + if (destructor_called_) + return; - std::function new_data_cb = [this] (const CloudXYZRGBAConstPtr& cloud) { newDataCallback (cloud); }; - new_data_connection_ = grabber_->registerCallback (new_data_cb); - grabber_->start (); + std::function new_data_cb = + [this](const CloudXYZRGBAConstPtr& cloud) { newDataCallback(cloud); }; + new_data_connection_ = grabber_->registerCallback(new_data_cb); + grabber_->start(); starting_grabber_ = false; } diff --git a/apps/in_hand_scanner/src/input_data_processing.cpp b/apps/in_hand_scanner/src/input_data_processing.cpp index 1afbb53dff0..748d7da5955 100644 --- a/apps/in_hand_scanner/src/input_data_processing.cpp +++ b/apps/in_hand_scanner/src/input_data_processing.cpp @@ -39,74 +39,68 @@ */ #include - #include #include -#include //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::InputDataProcessing::InputDataProcessing () - : normal_estimation_ (new NormalEstimation ()), - - x_min_ (-15.f), - x_max_ ( 15.f), - y_min_ (-15.f), - y_max_ ( 15.f), - z_min_ ( 48.f), - z_max_ ( 70.f), - - h_min_ (210.f), - h_max_ (270.f), - s_min_ ( 0.2f), - s_max_ ( 1.f), - v_min_ ( 0.2f), - v_max_ ( 1.f), - - hsv_inverted_ (false), - hsv_enabled_ (true), - - size_dilate_ (3), - size_erode_ (3) +pcl::ihs::InputDataProcessing::InputDataProcessing() +: normal_estimation_(new NormalEstimation()) +, x_min_(-15.f) +, x_max_(15.f) +, y_min_(-15.f) +, y_max_(15.f) +, z_min_(48.f) +, z_max_(70.f) +, h_min_(210.f) +, h_max_(270.f) +, s_min_(0.2f) +, s_max_(1.f) +, v_min_(0.2f) +, v_max_(1.f) +, hsv_inverted_(false) +, hsv_enabled_(true) +, size_dilate_(3) +, size_erode_(3) { // Normal estimation - normal_estimation_->setNormalEstimationMethod (NormalEstimation::AVERAGE_3D_GRADIENT); - normal_estimation_->setMaxDepthChangeFactor (0.02f); // in meters - normal_estimation_->setNormalSmoothingSize (10.0f); + normal_estimation_->setNormalEstimationMethod(NormalEstimation::AVERAGE_3D_GRADIENT); + normal_estimation_->setMaxDepthChangeFactor(0.02f); // in meters + normal_estimation_->setNormalSmoothingSize(10.0f); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::InputDataProcessing::segment (const CloudXYZRGBAConstPtr& cloud_in, - CloudXYZRGBNormalPtr& cloud_out, - CloudXYZRGBNormalPtr& cloud_discarded) const +pcl::ihs::InputDataProcessing::segment(const CloudXYZRGBAConstPtr& cloud_in, + CloudXYZRGBNormalPtr& cloud_out, + CloudXYZRGBNormalPtr& cloud_discarded) const { - if (!cloud_in) - { + if (!cloud_in) { std::cerr << "ERROR in input_data_processing.cpp: Input cloud is invalid.\n"; return (false); } - if (!cloud_in->isOrganized ()) - { + if (!cloud_in->isOrganized()) { std::cerr << "ERROR in input_data_processing.cpp: Input cloud must be organized.\n"; return (false); } - if (!cloud_out) cloud_out = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); - if (!cloud_discarded) cloud_discarded = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); + if (!cloud_out) + cloud_out = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); + if (!cloud_discarded) + cloud_discarded = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); - const unsigned int width = cloud_in->width; + const unsigned int width = cloud_in->width; const unsigned int height = cloud_in->height; // Calculate the normals - CloudNormalsPtr cloud_normals (new CloudNormals ()); - normal_estimation_->setInputCloud (cloud_in); - normal_estimation_->compute (*cloud_normals); + CloudNormalsPtr cloud_normals(new CloudNormals()); + normal_estimation_->setInputCloud(cloud_in); + normal_estimation_->compute(*cloud_normals); // Get the XYZ and HSV masks. - MatrixXb xyz_mask (height, width); - MatrixXb hsv_mask (height, width); + MatrixXb xyz_mask(height, width); + MatrixXb hsv_mask(height, width); // cm -> m for the comparison const float x_min = .01f * x_min_; @@ -117,42 +111,41 @@ pcl::ihs::InputDataProcessing::segment (const CloudXYZRGBAConstPtr& cloud_in, const float z_max = .01f * z_max_; float h, s, v; - for (MatrixXb::Index r=0; r= x_min && xyzrgb.x <= x_max && - xyzrgb.y >= y_min && xyzrgb.y <= y_max && - xyzrgb.z >= z_min && xyzrgb.z <= z_max) - { - xyz_mask (r, c) = true; - - this->RGBToHSV (xyzrgb.r, xyzrgb.g, xyzrgb.b, h, s, v); - if (h >= h_min_ && h <= h_max_ && s >= s_min_ && s <= s_max_ && v >= v_min_ && v <= v_max_) - { - if (!hsv_inverted_) hsv_mask (r, c) = true; + for (MatrixXb::Index r = 0; r < xyz_mask.rows(); ++r) { + for (MatrixXb::Index c = 0; c < xyz_mask.cols(); ++c) { + const PointXYZRGBA& xyzrgb = (*cloud_in)[r * width + c]; + const Normal& normal = (*cloud_normals)[r * width + c]; + + xyz_mask(r, c) = hsv_mask(r, c) = false; + + if (!std::isnan(xyzrgb.x) && !std::isnan(normal.normal_x) && xyzrgb.x >= x_min && + xyzrgb.x <= x_max && xyzrgb.y >= y_min && xyzrgb.y <= y_max && + xyzrgb.z >= z_min && xyzrgb.z <= z_max) { + xyz_mask(r, c) = true; + + this->RGBToHSV(xyzrgb.r, xyzrgb.g, xyzrgb.b, h, s, v); + if (h >= h_min_ && h <= h_max_ && s >= s_min_ && s <= s_max_ && v >= v_min_ && + v <= v_max_) { + if (!hsv_inverted_) + hsv_mask(r, c) = true; } - else - { - if (hsv_inverted_) hsv_mask (r, c) = true; + else { + if (hsv_inverted_) + hsv_mask(r, c) = true; } } } } - this->erode (xyz_mask, size_erode_); - if (hsv_enabled_) this->dilate (hsv_mask, size_dilate_); - else hsv_mask.setZero (); + this->erode(xyz_mask, size_erode_); + if (hsv_enabled_) + this->dilate(hsv_mask, size_dilate_); + else + hsv_mask.setZero(); // Copy the normals into the clouds. - cloud_out->reserve (cloud_in->size ()); - cloud_discarded->reserve (cloud_in->size ()); + cloud_out->reserve(cloud_in->size()); + cloud_discarded->reserve(cloud_in->size()); pcl::PointXYZRGBNormal pt_out, pt_discarded; pt_discarded.r = 50; @@ -160,49 +153,43 @@ pcl::ihs::InputDataProcessing::segment (const CloudXYZRGBAConstPtr& cloud_in, pt_discarded.b = 230; PointXYZRGBA xyzrgb; - Normal normal; + Normal normal; - for (MatrixXb::Index r=0; r cm - xyzrgb.getVector3fMap () = 100.f * xyzrgb.getVector3fMap (); + xyzrgb.getVector3fMap() = 100.f * xyzrgb.getVector3fMap(); - if (hsv_mask (r, c)) - { - pt_discarded.getVector4fMap () = xyzrgb.getVector4fMap (); - pt_discarded.getNormalVector4fMap () = normal.getNormalVector4fMap (); + if (hsv_mask(r, c)) { + pt_discarded.getVector4fMap() = xyzrgb.getVector4fMap(); + pt_discarded.getNormalVector4fMap() = normal.getNormalVector4fMap(); - pt_out.x = std::numeric_limits ::quiet_NaN (); + pt_out.x = std::numeric_limits::quiet_NaN(); } - else - { - pt_out.getVector4fMap () = xyzrgb.getVector4fMap (); - pt_out.getNormalVector4fMap () = normal.getNormalVector4fMap (); - pt_out.rgba = xyzrgb.rgba; + else { + pt_out.getVector4fMap() = xyzrgb.getVector4fMap(); + pt_out.getNormalVector4fMap() = normal.getNormalVector4fMap(); + pt_out.rgba = xyzrgb.rgba; - pt_discarded.x = std::numeric_limits ::quiet_NaN (); + pt_discarded.x = std::numeric_limits::quiet_NaN(); } } - else - { - pt_out.x = std::numeric_limits ::quiet_NaN (); - pt_discarded.x = std::numeric_limits ::quiet_NaN (); + else { + pt_out.x = std::numeric_limits::quiet_NaN(); + pt_discarded.x = std::numeric_limits::quiet_NaN(); } - cloud_out->push_back (pt_out); - cloud_discarded->push_back (pt_discarded); + cloud_out->push_back(pt_out); + cloud_discarded->push_back(pt_discarded); } } - cloud_out->width = cloud_discarded->width = width; - cloud_out->height = cloud_discarded->height = height; + cloud_out->width = cloud_discarded->width = width; + cloud_out->height = cloud_discarded->height = height; cloud_out->is_dense = cloud_discarded->is_dense = false; return (true); @@ -211,50 +198,48 @@ pcl::ihs::InputDataProcessing::segment (const CloudXYZRGBAConstPtr& cloud_in, //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::InputDataProcessing::calculateNormals (const CloudXYZRGBAConstPtr& cloud_in, - CloudXYZRGBNormalPtr& cloud_out) const +pcl::ihs::InputDataProcessing::calculateNormals(const CloudXYZRGBAConstPtr& cloud_in, + CloudXYZRGBNormalPtr& cloud_out) const { - if (!cloud_in) - { + if (!cloud_in) { std::cerr << "ERROR in input_data_processing.cpp: Input cloud is invalid.\n"; return (false); } if (!cloud_out) - cloud_out = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); + cloud_out = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); // Calculate the normals - CloudNormalsPtr cloud_normals (new CloudNormals ()); - normal_estimation_->setInputCloud (cloud_in); - normal_estimation_->compute (*cloud_normals); + CloudNormalsPtr cloud_normals(new CloudNormals()); + normal_estimation_->setInputCloud(cloud_in); + normal_estimation_->compute(*cloud_normals); // Copy the input cloud and normals into the output cloud. - cloud_out->resize (cloud_in->size ()); - cloud_out->width = cloud_in->width; - cloud_out->height = cloud_in->height; + cloud_out->resize(cloud_in->size()); + cloud_out->width = cloud_in->width; + cloud_out->height = cloud_in->height; cloud_out->is_dense = false; - CloudNormals::const_iterator it_n = cloud_normals->begin (); - CloudXYZRGBNormal::iterator it_out = cloud_out->begin (); + CloudNormals::const_iterator it_n = cloud_normals->begin(); + CloudXYZRGBNormal::iterator it_out = cloud_out->begin(); PointXYZRGBNormal invalid_pt; - invalid_pt.x = invalid_pt.y = invalid_pt.z = std::numeric_limits ::quiet_NaN (); - invalid_pt.normal_x = invalid_pt.normal_y = invalid_pt.normal_z = std::numeric_limits ::quiet_NaN (); - invalid_pt.data [3] = 1.f; - invalid_pt.data_n [3] = 0.f; - - for (auto it_in = cloud_in->begin (); it_in!=cloud_in->end (); ++it_in, ++it_n, ++it_out) - { - if (!it_n->getNormalVector4fMap (). hasNaN ()) - { + invalid_pt.x = invalid_pt.y = invalid_pt.z = std::numeric_limits::quiet_NaN(); + invalid_pt.normal_x = invalid_pt.normal_y = invalid_pt.normal_z = + std::numeric_limits::quiet_NaN(); + invalid_pt.data[3] = 1.f; + invalid_pt.data_n[3] = 0.f; + + for (auto it_in = cloud_in->begin(); it_in != cloud_in->end(); + ++it_in, ++it_n, ++it_out) { + if (!it_n->getNormalVector4fMap().hasNaN()) { // m -> cm - it_out->getVector4fMap () = 100.f * it_in->getVector4fMap (); - it_out->data [3] = 1.f; - it_out->rgba = it_in->rgba; - it_out->getNormalVector4fMap () = it_n->getNormalVector4fMap (); + it_out->getVector4fMap() = 100.f * it_in->getVector4fMap(); + it_out->data[3] = 1.f; + it_out->rgba = it_in->rgba; + it_out->getNormalVector4fMap() = it_n->getNormalVector4fMap(); } - else - { + else { *it_out = invalid_pt; } } @@ -265,52 +250,50 @@ pcl::ihs::InputDataProcessing::calculateNormals (const CloudXYZRGBAConstPtr& clo //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InputDataProcessing::erode (MatrixXb& mask, const int k) const +pcl::ihs::InputDataProcessing::erode(MatrixXb& mask, const int k) const { - mask = manhattan (mask, false).array () > k; + mask = manhattan(mask, false).array() > k; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InputDataProcessing::dilate (MatrixXb& mask, const int k) const +pcl::ihs::InputDataProcessing::dilate(MatrixXb& mask, const int k) const { - mask = manhattan (mask, true).array () <= k; + mask = manhattan(mask, true).array() <= k; } //////////////////////////////////////////////////////////////////////////////// pcl::ihs::InputDataProcessing::MatrixXi -pcl::ihs::InputDataProcessing::manhattan (const MatrixXb& mat, const bool comp) const +pcl::ihs::InputDataProcessing::manhattan(const MatrixXb& mat, const bool comp) const { - MatrixXi dist (mat.rows (), mat.cols ()); - const int d_max = dist.rows () + dist.cols (); + MatrixXi dist(mat.rows(), mat.cols()); + const int d_max = dist.rows() + dist.cols(); // Forward - for (MatrixXi::Index r = 0; r < dist.rows (); ++r) - { - for (MatrixXi::Index c = 0; c < dist.cols (); ++c) - { - if (mat (r, c) == comp) - { - dist (r, c) = 0; + for (MatrixXi::Index r = 0; r < dist.rows(); ++r) { + for (MatrixXi::Index c = 0; c < dist.cols(); ++c) { + if (mat(r, c) == comp) { + dist(r, c) = 0; } - else - { - dist (r, c) = d_max; - if (r > 0) dist (r, c) = std::min (dist (r, c), dist (r-1, c ) + 1); - if (c > 0) dist (r, c) = std::min (dist (r, c), dist (r , c-1) + 1); + else { + dist(r, c) = d_max; + if (r > 0) + dist(r, c) = std::min(dist(r, c), dist(r - 1, c) + 1); + if (c > 0) + dist(r, c) = std::min(dist(r, c), dist(r, c - 1) + 1); } } } // Backward - for (int r = dist.rows () - 1; r >= 0; --r) - { - for (int c = dist.cols () - 1; c >= 0; --c) - { - if (r < dist.rows ()-1) dist (r, c) = std::min (dist (r, c), dist (r+1, c ) + 1); - if (c < dist.cols ()-1) dist (r, c) = std::min (dist (r, c), dist (r , c+1) + 1); + for (int r = dist.rows() - 1; r >= 0; --r) { + for (int c = dist.cols() - 1; c >= 0; --c) { + if (r < dist.rows() - 1) + dist(r, c) = std::min(dist(r, c), dist(r + 1, c) + 1); + if (c < dist.cols() - 1) + dist(r, c) = std::min(dist(r, c), dist(r, c + 1) + 1); } } @@ -320,17 +303,17 @@ pcl::ihs::InputDataProcessing::manhattan (const MatrixXb& mat, const bool comp) //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::InputDataProcessing::RGBToHSV (const unsigned char r, - const unsigned char g, - const unsigned char b, - float& h, - float& s, - float& v) const +pcl::ihs::InputDataProcessing::RGBToHSV(const unsigned char r, + const unsigned char g, + const unsigned char b, + float& h, + float& s, + float& v) const { - const unsigned char max = std::max (r, std::max (g, b)); - const unsigned char min = std::min (r, std::min (g, b)); + const unsigned char max = std::max(r, std::max(g, b)); + const unsigned char min = std::min(r, std::min(g, b)); - v = static_cast (max) / 255.f; + v = static_cast(max) / 255.f; if (max == 0) // division by zero { @@ -339,8 +322,8 @@ pcl::ihs::InputDataProcessing::RGBToHSV (const unsigned char r, return; } - const float diff = static_cast (max - min); - s = diff / static_cast (max); + const float diff = static_cast(max - min); + s = diff / static_cast(max); if (min == max) // diff == 0 -> division by zero { @@ -348,11 +331,15 @@ pcl::ihs::InputDataProcessing::RGBToHSV (const unsigned char r, return; } - if (max == r) h = 60.f * ( static_cast (g - b) / diff); - else if (max == g) h = 60.f * (2.f + static_cast (b - r) / diff); - else h = 60.f * (4.f + static_cast (r - g) / diff); // max == b + if (max == r) + h = 60.f * (static_cast(g - b) / diff); + else if (max == g) + h = 60.f * (2.f + static_cast(b - r) / diff); + else + h = 60.f * (4.f + static_cast(r - g) / diff); // max == b - if (h < 0.f) h += 360.f; + if (h < 0.f) + h += 360.f; } //////////////////////////////////////////////////////////////////////////////// diff --git a/apps/in_hand_scanner/src/integration.cpp b/apps/in_hand_scanner/src/integration.cpp index 565a8ecb610..f29a2701893 100644 --- a/apps/in_hand_scanner/src/integration.cpp +++ b/apps/in_hand_scanner/src/integration.cpp @@ -39,83 +39,78 @@ */ #include +#include +#include +#include #include -#include #include - -#include -#include -#include -#include +#include //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::Integration::Integration () - : kd_tree_ (new pcl::KdTreeFLANN ()), - max_squared_distance_ (0.04f), // 0.2cm - max_angle_ (45.f), - min_weight_ (.3f), - max_age_ (30), - min_directions_ (5) -{ -} +pcl::ihs::Integration::Integration() +: kd_tree_(new pcl::KdTreeFLANN()) +, max_squared_distance_(0.04f) +, // 0.2cm +max_angle_(45.f) +, min_weight_(.3f) +, max_age_(30) +, min_directions_(5) +{} //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::Integration::reconstructMesh (const CloudXYZRGBNormalConstPtr& cloud_data, - MeshPtr& mesh_model) const +pcl::ihs::Integration::reconstructMesh(const CloudXYZRGBNormalConstPtr& cloud_data, + MeshPtr& mesh_model) const { - if (!cloud_data) - { + if (!cloud_data) { std::cerr << "ERROR in integration.cpp: Cloud pointer is invalid\n"; return (false); } - if (!cloud_data->isOrganized ()) - { + if (!cloud_data->isOrganized()) { std::cerr << "ERROR in integration.cpp: Cloud is not organized\n"; return (false); } - const int width = static_cast (cloud_data->width); - const int height = static_cast (cloud_data->height); + const int width = static_cast(cloud_data->width); + const int height = static_cast(cloud_data->height); - if (!mesh_model) mesh_model = MeshPtr (new Mesh ()); + if (!mesh_model) + mesh_model = MeshPtr(new Mesh()); - mesh_model->clear (); - mesh_model->reserveVertices (cloud_data->size ()); - mesh_model->reserveEdges ((width-1) * height + width * (height-1) + (width-1) * (height-1)); - mesh_model->reserveFaces (2 * (width-1) * (height-1)); + mesh_model->clear(); + mesh_model->reserveVertices(cloud_data->size()); + mesh_model->reserveEdges((width - 1) * height + width * (height - 1) + + (width - 1) * (height - 1)); + mesh_model->reserveFaces(2 * (width - 1) * (height - 1)); // Store which vertex is set at which position (initialized with invalid indices) - VertexIndices vertex_indices (cloud_data->size (), VertexIndex ()); + VertexIndices vertex_indices(cloud_data->size(), VertexIndex()); - // Convert to the model cloud type. This is actually not needed but avoids code duplication (see merge). And reconstructMesh is called only the first reconstruction step anyway. - // NOTE: The default constructor of PointIHS has to initialize with NaNs! - CloudIHSPtr cloud_model (new CloudIHS ()); - cloud_model->resize (cloud_data->size ()); + // Convert to the model cloud type. This is actually not needed but avoids code + // duplication (see merge). And reconstructMesh is called only the first + // reconstruction step anyway. NOTE: The default constructor of PointIHS has to + // initialize with NaNs! + CloudIHSPtr cloud_model(new CloudIHS()); + cloud_model->resize(cloud_data->size()); // Set the model points not reached by the main loop - for (int c=0; coperator [] (c); + for (int c = 0; c < width; ++c) { + const PointXYZRGBNormal& pt_d = cloud_data->operator[](c); const float weight = -pt_d.normal_z; // weight = -dot (normal, [0; 0; 1]) - if (!std::isnan (pt_d.x) && weight > min_weight_) - { - cloud_model->operator [] (c) = PointIHS (pt_d, weight); + if (!std::isnan(pt_d.x) && weight > min_weight_) { + cloud_model->operator[](c) = PointIHS(pt_d, weight); } } - for (int r=1; roperator [] (r*width + c); + for (int r = 1; r < height; ++r) { + for (int c = 0; c < 2; ++c) { + const PointXYZRGBNormal& pt_d = cloud_data->operator[](r* width + c); const float weight = -pt_d.normal_z; // weight = -dot (normal, [0; 0; 1]) - if (!std::isnan (pt_d.x) && weight > min_weight_) - { - cloud_model->operator [] (r*width + c) = PointIHS (pt_d, weight); + if (!std::isnan(pt_d.x) && weight > min_weight_) { + cloud_model->operator[](r* width + c) = PointIHS(pt_d, weight); } } } @@ -129,49 +124,48 @@ pcl::ihs::Integration::reconstructMesh (const CloudXYZRGBNormalConstPtr& cloud_d // * 3 - 0 // const int offset_1 = -width; const int offset_2 = -width - 1; - const int offset_3 = - 1; + const int offset_3 = -1; const int offset_4 = -width - 2; - for (int r=1; r= 0 && ind_0 < static_cast (cloud_data->size ())); - assert (ind_1 >= 0 && ind_1 < static_cast (cloud_data->size ())); - assert (ind_2 >= 0 && ind_2 < static_cast (cloud_data->size ())); - assert (ind_3 >= 0 && ind_3 < static_cast (cloud_data->size ())); - assert (ind_4 >= 0 && ind_4 < static_cast (cloud_data->size ())); - - const PointXYZRGBNormal& pt_d_0 = cloud_data->operator [] (ind_0); - PointIHS& pt_m_0 = cloud_model->operator [] (ind_0); - const PointIHS& pt_m_1 = cloud_model->operator [] (ind_1); - const PointIHS& pt_m_2 = cloud_model->operator [] (ind_2); - const PointIHS& pt_m_3 = cloud_model->operator [] (ind_3); - const PointIHS& pt_m_4 = cloud_model->operator [] (ind_4); - - VertexIndex& vi_0 = vertex_indices [ind_0]; - VertexIndex& vi_1 = vertex_indices [ind_1]; - VertexIndex& vi_2 = vertex_indices [ind_2]; - VertexIndex& vi_3 = vertex_indices [ind_3]; - VertexIndex& vi_4 = vertex_indices [ind_4]; + assert(ind_0 >= 0 && ind_0 < static_cast(cloud_data->size())); + assert(ind_1 >= 0 && ind_1 < static_cast(cloud_data->size())); + assert(ind_2 >= 0 && ind_2 < static_cast(cloud_data->size())); + assert(ind_3 >= 0 && ind_3 < static_cast(cloud_data->size())); + assert(ind_4 >= 0 && ind_4 < static_cast(cloud_data->size())); + + const PointXYZRGBNormal& pt_d_0 = cloud_data->operator[](ind_0); + PointIHS& pt_m_0 = cloud_model->operator[](ind_0); + const PointIHS& pt_m_1 = cloud_model->operator[](ind_1); + const PointIHS& pt_m_2 = cloud_model->operator[](ind_2); + const PointIHS& pt_m_3 = cloud_model->operator[](ind_3); + const PointIHS& pt_m_4 = cloud_model->operator[](ind_4); + + VertexIndex& vi_0 = vertex_indices[ind_0]; + VertexIndex& vi_1 = vertex_indices[ind_1]; + VertexIndex& vi_2 = vertex_indices[ind_2]; + VertexIndex& vi_3 = vertex_indices[ind_3]; + VertexIndex& vi_4 = vertex_indices[ind_4]; const float weight = -pt_d_0.normal_z; // weight = -dot (normal, [0; 0; 1]) - if (!std::isnan (pt_d_0.x) && weight > min_weight_) - { - pt_m_0 = PointIHS (pt_d_0, weight); + if (!std::isnan(pt_d_0.x) && weight > min_weight_) { + pt_m_0 = PointIHS(pt_d_0, weight); } - this->addToMesh (pt_m_0,pt_m_1,pt_m_2,pt_m_3, vi_0,vi_1,vi_2,vi_3, mesh_model); + this->addToMesh( + pt_m_0, pt_m_1, pt_m_2, pt_m_3, vi_0, vi_1, vi_2, vi_3, mesh_model); if (Mesh::IsManifold::value) // Only needed for the manifold mesh { - this->addToMesh (pt_m_0,pt_m_2,pt_m_4,pt_m_3, vi_0,vi_2,vi_4,vi_3, mesh_model); + this->addToMesh( + pt_m_0, pt_m_2, pt_m_4, pt_m_3, vi_0, vi_2, vi_4, vi_3, mesh_model); } } } @@ -182,87 +176,79 @@ pcl::ihs::Integration::reconstructMesh (const CloudXYZRGBNormalConstPtr& cloud_d //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::Integration::merge (const CloudXYZRGBNormalConstPtr& cloud_data, - MeshPtr& mesh_model, - const Eigen::Matrix4f& T) const +pcl::ihs::Integration::merge(const CloudXYZRGBNormalConstPtr& cloud_data, + MeshPtr& mesh_model, + const Eigen::Matrix4f& T) const { - if (!cloud_data) - { + if (!cloud_data) { std::cerr << "ERROR in integration.cpp: Cloud pointer is invalid\n"; return (false); } - if (!cloud_data->isOrganized ()) - { + if (!cloud_data->isOrganized()) { std::cerr << "ERROR in integration.cpp: Data cloud is not organized\n"; return (false); } - if (!mesh_model) - { + if (!mesh_model) { std::cerr << "ERROR in integration.cpp: Mesh pointer is invalid\n"; return (false); } - if (!mesh_model->sizeVertices ()) - { + if (!mesh_model->sizeVertices()) { std::cerr << "ERROR in integration.cpp: Model mesh is empty\n"; return (false); } - const int width = static_cast (cloud_data->width); - const int height = static_cast (cloud_data->height); + const int width = static_cast(cloud_data->width); + const int height = static_cast(cloud_data->height); // Nearest neighbor search - CloudXYZPtr xyz_model (new CloudXYZ ()); - xyz_model->reserve (mesh_model->sizeVertices ()); - for (std::size_t i=0; isizeVertices (); ++i) - { - const PointIHS& pt = mesh_model->getVertexDataCloud () [i]; - xyz_model->push_back (PointXYZ (pt.x, pt.y, pt.z)); + CloudXYZPtr xyz_model(new CloudXYZ()); + xyz_model->reserve(mesh_model->sizeVertices()); + for (std::size_t i = 0; i < mesh_model->sizeVertices(); ++i) { + const PointIHS& pt = mesh_model->getVertexDataCloud()[i]; + xyz_model->push_back(PointXYZ(pt.x, pt.y, pt.z)); } - kd_tree_->setInputCloud (xyz_model); - std::vector index (1); - std::vector squared_distance (1); + kd_tree_->setInputCloud(xyz_model); + pcl::Indices index(1); + std::vector squared_distance(1); - mesh_model->reserveVertices (mesh_model->sizeVertices () + cloud_data->size ()); - mesh_model->reserveEdges (mesh_model->sizeEdges () + (width-1) * height + width * (height-1) + (width-1) * (height-1)); - mesh_model->reserveFaces (mesh_model->sizeFaces () + 2 * (width-1) * (height-1)); + mesh_model->reserveVertices(mesh_model->sizeVertices() + cloud_data->size()); + mesh_model->reserveEdges(mesh_model->sizeEdges() + (width - 1) * height + + width * (height - 1) + (width - 1) * (height - 1)); + mesh_model->reserveFaces(mesh_model->sizeFaces() + 2 * (width - 1) * (height - 1)); - // Data cloud in model coordinates (this does not change the connectivity information) and weights - CloudIHSPtr cloud_data_transformed (new CloudIHS ()); - cloud_data_transformed->resize (cloud_data->size ()); + // Data cloud in model coordinates (this does not change the connectivity information) + // and weights + CloudIHSPtr cloud_data_transformed(new CloudIHS()); + cloud_data_transformed->resize(cloud_data->size()); // Sensor position in model coordinates - const Eigen::Vector4f& sensor_eye = T * Eigen::Vector4f (0.f, 0.f, 0.f, 1.f); + const Eigen::Vector4f& sensor_eye = T * Eigen::Vector4f(0.f, 0.f, 0.f, 1.f); // Store which vertex is set at which position (initialized with invalid indices) - VertexIndices vertex_indices (cloud_data->size (), VertexIndex ()); + VertexIndices vertex_indices(cloud_data->size(), VertexIndex()); // Set the transformed points not reached by the main loop - for (int c=0; coperator [] (c); + for (int c = 0; c < width; ++c) { + const PointXYZRGBNormal& pt_d = cloud_data->operator[](c); const float weight = -pt_d.normal_z; // weight = -dot (normal, [0; 0; 1]) - if (!std::isnan (pt_d.x) && weight > min_weight_) - { - PointIHS& pt_d_t = cloud_data_transformed->operator [] (c); - pt_d_t = PointIHS (pt_d, weight); - pt_d_t.getVector4fMap () = T * pt_d_t.getVector4fMap (); - pt_d_t.getNormalVector4fMap () = T * pt_d_t.getNormalVector4fMap (); + if (!std::isnan(pt_d.x) && weight > min_weight_) { + PointIHS& pt_d_t = cloud_data_transformed->operator[](c); + pt_d_t = PointIHS(pt_d, weight); + pt_d_t.getVector4fMap() = T * pt_d_t.getVector4fMap(); + pt_d_t.getNormalVector4fMap() = T * pt_d_t.getNormalVector4fMap(); } } - for (int r=1; roperator [] (r*width + c); + for (int r = 1; r < height; ++r) { + for (int c = 0; c < 2; ++c) { + const PointXYZRGBNormal& pt_d = cloud_data->operator[](r* width + c); const float weight = -pt_d.normal_z; // weight = -dot (normal, [0; 0; 1]) - if (!std::isnan (pt_d.x) && weight > min_weight_) - { - PointIHS& pt_d_t = cloud_data_transformed->operator [] (r*width + c); - pt_d_t = PointIHS (pt_d, weight); - pt_d_t.getVector4fMap () = T * pt_d_t.getVector4fMap (); - pt_d_t.getNormalVector4fMap () = T * pt_d_t.getNormalVector4fMap (); + if (!std::isnan(pt_d.x) && weight > min_weight_) { + PointIHS& pt_d_t = cloud_data_transformed->operator[](r* width + c); + pt_d_t = PointIHS(pt_d, weight); + pt_d_t.getVector4fMap() = T * pt_d_t.getVector4fMap(); + pt_d_t.getNormalVector4fMap() = T * pt_d_t.getNormalVector4fMap(); } } } @@ -276,89 +262,92 @@ pcl::ihs::Integration::merge (const CloudXYZRGBNormalConstPtr& cloud_data, // * 3 - 0 // const int offset_1 = -width; const int offset_2 = -width - 1; - const int offset_3 = - 1; + const int offset_3 = -1; const int offset_4 = -width - 2; - const float dot_min = std::cos (max_angle_ * 17.45329252e-3); // deg to rad + const float dot_min = std::cos(max_angle_ * 17.45329252e-3); // deg to rad - for (int r=1; r= 0 && ind_0 < static_cast (cloud_data->size ())); - assert (ind_1 >= 0 && ind_1 < static_cast (cloud_data->size ())); - assert (ind_2 >= 0 && ind_2 < static_cast (cloud_data->size ())); - assert (ind_3 >= 0 && ind_3 < static_cast (cloud_data->size ())); - assert (ind_4 >= 0 && ind_4 < static_cast (cloud_data->size ())); + assert(ind_0 >= 0 && ind_0 < static_cast(cloud_data->size())); + assert(ind_1 >= 0 && ind_1 < static_cast(cloud_data->size())); + assert(ind_2 >= 0 && ind_2 < static_cast(cloud_data->size())); + assert(ind_3 >= 0 && ind_3 < static_cast(cloud_data->size())); + assert(ind_4 >= 0 && ind_4 < static_cast(cloud_data->size())); - const PointXYZRGBNormal& pt_d_0 = cloud_data->operator [] (ind_0); - PointIHS& pt_d_t_0 = cloud_data_transformed->operator [] (ind_0); - const PointIHS& pt_d_t_1 = cloud_data_transformed->operator [] (ind_1); - const PointIHS& pt_d_t_2 = cloud_data_transformed->operator [] (ind_2); - const PointIHS& pt_d_t_3 = cloud_data_transformed->operator [] (ind_3); - const PointIHS& pt_d_t_4 = cloud_data_transformed->operator [] (ind_4); + const PointXYZRGBNormal& pt_d_0 = cloud_data->operator[](ind_0); + PointIHS& pt_d_t_0 = cloud_data_transformed->operator[](ind_0); + const PointIHS& pt_d_t_1 = cloud_data_transformed->operator[](ind_1); + const PointIHS& pt_d_t_2 = cloud_data_transformed->operator[](ind_2); + const PointIHS& pt_d_t_3 = cloud_data_transformed->operator[](ind_3); + const PointIHS& pt_d_t_4 = cloud_data_transformed->operator[](ind_4); - VertexIndex& vi_0 = vertex_indices [ind_0]; + VertexIndex& vi_0 = vertex_indices[ind_0]; const float weight = -pt_d_0.normal_z; // weight = -dot (normal, [0; 0; 1]) - if (!std::isnan (pt_d_0.x) && weight > min_weight_) - { - pt_d_t_0 = PointIHS (pt_d_0, weight); - pt_d_t_0.getVector4fMap () = T * pt_d_t_0.getVector4fMap (); - pt_d_t_0.getNormalVector4fMap () = T * pt_d_t_0.getNormalVector4fMap (); + if (!std::isnan(pt_d_0.x) && weight > min_weight_) { + pt_d_t_0 = PointIHS(pt_d_0, weight); + pt_d_t_0.getVector4fMap() = T * pt_d_t_0.getVector4fMap(); + pt_d_t_0.getNormalVector4fMap() = T * pt_d_t_0.getNormalVector4fMap(); - pcl::PointXYZ tmp; tmp.getVector4fMap () = pt_d_t_0.getVector4fMap (); + pcl::PointXYZ tmp; + tmp.getVector4fMap() = pt_d_t_0.getVector4fMap(); // NN search - if (!kd_tree_->nearestKSearch (tmp, 1, index, squared_distance)) - { + if (!kd_tree_->nearestKSearch(tmp, 1, index, squared_distance)) { std::cerr << "ERROR in integration.cpp: nearestKSearch failed!\n"; return (false); } // Average out corresponding points - if (squared_distance [0] <= max_squared_distance_) - { - PointIHS& pt_m = mesh_model->getVertexDataCloud () [index [0]]; // Non-const reference! - - if (pt_m.getNormalVector4fMap ().dot (pt_d_t_0.getNormalVector4fMap ()) >= dot_min) - { - vi_0 = VertexIndex (index [0]); - - const float W = pt_m.weight; // Old accumulated weight - const float w = pt_d_t_0.weight; // Weight of new point - const float WW = pt_m.weight = W + w; // New accumulated weight - - const float r_m = static_cast (pt_m.r); - const float g_m = static_cast (pt_m.g); - const float b_m = static_cast (pt_m.b); - - const float r_d = static_cast (pt_d_t_0.r); - const float g_d = static_cast (pt_d_t_0.g); - const float b_d = static_cast (pt_d_t_0.b); - - pt_m.getVector4fMap () = ( W*pt_m.getVector4fMap () + w*pt_d_t_0.getVector4fMap ()) / WW; - pt_m.getNormalVector4fMap () = ((W*pt_m.getNormalVector4fMap () + w*pt_d_t_0.getNormalVector4fMap ()) / WW).normalized (); - pt_m.r = this->trimRGB ((W*r_m + w*r_d) / WW); - pt_m.g = this->trimRGB ((W*g_m + w*g_d) / WW); - pt_m.b = this->trimRGB ((W*b_m + w*b_d) / WW); + if (squared_distance[0] <= max_squared_distance_) { + PointIHS& pt_m = + mesh_model->getVertexDataCloud()[index[0]]; // Non-const reference! + + if (pt_m.getNormalVector4fMap().dot(pt_d_t_0.getNormalVector4fMap()) >= + dot_min) { + vi_0 = VertexIndex(index[0]); + + const float W = pt_m.weight; // Old accumulated weight + const float w = pt_d_t_0.weight; // Weight of new point + const float WW = pt_m.weight = W + w; // New accumulated weight + + const float r_m = static_cast(pt_m.r); + const float g_m = static_cast(pt_m.g); + const float b_m = static_cast(pt_m.b); + + const float r_d = static_cast(pt_d_t_0.r); + const float g_d = static_cast(pt_d_t_0.g); + const float b_d = static_cast(pt_d_t_0.b); + + pt_m.getVector4fMap() = + (W * pt_m.getVector4fMap() + w * pt_d_t_0.getVector4fMap()) / WW; + pt_m.getNormalVector4fMap() = ((W * pt_m.getNormalVector4fMap() + + w * pt_d_t_0.getNormalVector4fMap()) / + WW) + .normalized(); + pt_m.r = this->trimRGB((W * r_m + w * r_d) / WW); + pt_m.g = this->trimRGB((W * g_m + w * g_d) / WW); + pt_m.b = this->trimRGB((W * b_m + w * b_d) / WW); // Point has been observed again -> give it some extra time to live pt_m.age = 0; // Add a direction - pcl::ihs::addDirection (pt_m.getNormalVector4fMap (), sensor_eye-pt_m.getVector4fMap (), pt_m.directions); + pcl::ihs::addDirection(pt_m.getNormalVector4fMap(), + sensor_eye - pt_m.getVector4fMap(), + pt_m.directions); } // dot normals - } // squared distance - } // !isnan && min weight + } // squared distance + } // !isnan && min weight // Connect // 4 2 - 1 // @@ -369,15 +358,17 @@ pcl::ihs::Integration::merge (const CloudXYZRGBNormalConstPtr& cloud_data, // \ \ // // * 3 - 0 // - VertexIndex& vi_1 = vertex_indices [ind_1]; - VertexIndex& vi_2 = vertex_indices [ind_2]; - VertexIndex& vi_3 = vertex_indices [ind_3]; - VertexIndex& vi_4 = vertex_indices [ind_4]; + VertexIndex& vi_1 = vertex_indices[ind_1]; + VertexIndex& vi_2 = vertex_indices[ind_2]; + VertexIndex& vi_3 = vertex_indices[ind_3]; + VertexIndex& vi_4 = vertex_indices[ind_4]; - this->addToMesh (pt_d_t_0,pt_d_t_1,pt_d_t_2,pt_d_t_3, vi_0,vi_1,vi_2,vi_3, mesh_model); + this->addToMesh( + pt_d_t_0, pt_d_t_1, pt_d_t_2, pt_d_t_3, vi_0, vi_1, vi_2, vi_3, mesh_model); if (Mesh::IsManifold::value) // Only needed for the manifold mesh { - this->addToMesh (pt_d_t_0,pt_d_t_2,pt_d_t_4,pt_d_t_3, vi_0,vi_2,vi_4,vi_3, mesh_model); + this->addToMesh( + pt_d_t_0, pt_d_t_2, pt_d_t_4, pt_d_t_3, vi_0, vi_2, vi_4, vi_3, mesh_model); } } } @@ -388,67 +379,62 @@ pcl::ihs::Integration::merge (const CloudXYZRGBNormalConstPtr& cloud_data, //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::age (const MeshPtr& mesh, const bool cleanup) const +pcl::ihs::Integration::age(const MeshPtr& mesh, const bool cleanup) const { - for (std::size_t i=0; isizeVertices (); ++i) - { - PointIHS& pt = mesh->getVertexDataCloud () [i]; - if (pt.age < max_age_) - { + for (std::size_t i = 0; i < mesh->sizeVertices(); ++i) { + PointIHS& pt = mesh->getVertexDataCloud()[i]; + if (pt.age < max_age_) { // Point survives ++(pt.age); } else if (pt.age == max_age_) // Judgement Day { - if (pcl::ihs::countDirections (pt.directions) < min_directions_) - { + if (pcl::ihs::countDirections(pt.directions) < min_directions_) { // Point dies (no need to transform it) - mesh->deleteVertex (VertexIndex (i)); + mesh->deleteVertex(VertexIndex(i)); } - else - { + else { // Point becomes immortal - pt.age = std::numeric_limits ::max (); + pt.age = std::numeric_limits::max(); } } } - if (cleanup) - { - mesh->cleanUp (); + if (cleanup) { + mesh->cleanUp(); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::removeUnfitVertices (const MeshPtr& mesh, const bool cleanup) const +pcl::ihs::Integration::removeUnfitVertices(const MeshPtr& mesh, + const bool cleanup) const { - for (std::size_t i=0; isizeVertices (); ++i) - { - if (pcl::ihs::countDirections (mesh->getVertexDataCloud () [i].directions) < min_directions_) - { + for (std::size_t i = 0; i < mesh->sizeVertices(); ++i) { + if (pcl::ihs::countDirections(mesh->getVertexDataCloud()[i].directions) < + min_directions_) { // Point dies (no need to transform it) - mesh->deleteVertex (VertexIndex (i)); + mesh->deleteVertex(VertexIndex(i)); } } - if (cleanup) - { - mesh->cleanUp (); + if (cleanup) { + mesh->cleanUp(); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::setMaxSquaredDistance (const float squared_distance) +pcl::ihs::Integration::setMaxSquaredDistance(const float squared_distance) { - if (squared_distance > 0) max_squared_distance_ = squared_distance; + if (squared_distance > 0) + max_squared_distance_ = squared_distance; } float -pcl::ihs::Integration::getMaxSquaredDistance () const +pcl::ihs::Integration::getMaxSquaredDistance() const { return (max_squared_distance_); } @@ -456,13 +442,13 @@ pcl::ihs::Integration::getMaxSquaredDistance () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::setMaxAngle (const float angle) +pcl::ihs::Integration::setMaxAngle(const float angle) { - max_angle_ = pcl::ihs::clamp (angle, 0.f, 180.f); + max_angle_ = pcl::ihs::clamp(angle, 0.f, 180.f); } float -pcl::ihs::Integration::getMaxAngle () const +pcl::ihs::Integration::getMaxAngle() const { return (max_angle_); } @@ -470,13 +456,13 @@ pcl::ihs::Integration::getMaxAngle () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::setMaxAge (const unsigned int age) +pcl::ihs::Integration::setMaxAge(const unsigned int age) { max_age_ = age < 1 ? 1 : age; } unsigned int -pcl::ihs::Integration::getMaxAge () const +pcl::ihs::Integration::getMaxAge() const { return (max_age_); } @@ -484,13 +470,13 @@ pcl::ihs::Integration::getMaxAge () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::setMinDirections (const unsigned int directions) +pcl::ihs::Integration::setMinDirections(const unsigned int directions) { min_directions_ = directions < 1 ? 1 : directions; } unsigned int -pcl::ihs::Integration::getMinDirections () const +pcl::ihs::Integration::getMinDirections() const { return (min_directions_); } @@ -498,106 +484,133 @@ pcl::ihs::Integration::getMinDirections () const //////////////////////////////////////////////////////////////////////////////// std::uint8_t -pcl::ihs::Integration::trimRGB (const float val) const +pcl::ihs::Integration::trimRGB(const float val) const { - return (static_cast (val > 255.f ? 255 : val)); + return (static_cast(val > 255.f ? 255 : val)); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::addToMesh (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2, - const PointIHS& pt_3, - VertexIndex& vi_0, - VertexIndex& vi_1, - VertexIndex& vi_2, - VertexIndex& vi_3, - const MeshPtr& mesh) const +pcl::ihs::Integration::addToMesh(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2, + const PointIHS& pt_3, + VertexIndex& vi_0, + VertexIndex& vi_1, + VertexIndex& vi_2, + VertexIndex& vi_3, + const MeshPtr& mesh) const { // Treated bitwise // 2 - 1 // | | // 3 - 0 - const unsigned char is_finite = static_cast ( - (1 * !std::isnan (pt_0.x)) | - (2 * !std::isnan (pt_1.x)) | - (4 * !std::isnan (pt_2.x)) | - (8 * !std::isnan (pt_3.x))); - - switch (is_finite) + const unsigned char is_finite = + static_cast((1 * !std::isnan(pt_0.x)) | (2 * !std::isnan(pt_1.x)) | + (4 * !std::isnan(pt_2.x)) | (8 * !std::isnan(pt_3.x))); + + switch (is_finite) { + case 7: + this->addToMesh(pt_0, pt_1, pt_2, vi_0, vi_1, vi_2, mesh); + break; // 0-1-2 + case 11: + this->addToMesh(pt_0, pt_1, pt_3, vi_0, vi_1, vi_3, mesh); + break; // 0-1-3 + case 13: + this->addToMesh(pt_0, pt_2, pt_3, vi_0, vi_2, vi_3, mesh); + break; // 0-2-3 + case 14: + this->addToMesh(pt_1, pt_2, pt_3, vi_1, vi_2, vi_3, mesh); + break; // 1-2-3 + case 15: // 0-1-2-3 { - case 7: this->addToMesh (pt_0, pt_1, pt_2, vi_0, vi_1, vi_2, mesh); break; // 0-1-2 - case 11: this->addToMesh (pt_0, pt_1, pt_3, vi_0, vi_1, vi_3, mesh); break; // 0-1-3 - case 13: this->addToMesh (pt_0, pt_2, pt_3, vi_0, vi_2, vi_3, mesh); break; // 0-2-3 - case 14: this->addToMesh (pt_1, pt_2, pt_3, vi_1, vi_2, vi_3, mesh); break; // 1-2-3 - case 15: // 0-1-2-3 - { - if (!distanceThreshold (pt_0, pt_1, pt_2, pt_3)) break; - if (!vi_0.isValid ()) vi_0 = mesh->addVertex (pt_0); - if (!vi_1.isValid ()) vi_1 = mesh->addVertex (pt_1); - if (!vi_2.isValid ()) vi_2 = mesh->addVertex (pt_2); - if (!vi_3.isValid ()) vi_3 = mesh->addVertex (pt_3); - if (vi_0==vi_1 || vi_0==vi_2 || vi_0==vi_3 || vi_1==vi_2 || vi_1==vi_3 || vi_2==vi_3) - { - return; - } - mesh->addTrianglePair (vi_0, vi_1, vi_2, vi_3); - + if (!distanceThreshold(pt_0, pt_1, pt_2, pt_3)) break; + if (!vi_0.isValid()) + vi_0 = mesh->addVertex(pt_0); + if (!vi_1.isValid()) + vi_1 = mesh->addVertex(pt_1); + if (!vi_2.isValid()) + vi_2 = mesh->addVertex(pt_2); + if (!vi_3.isValid()) + vi_3 = mesh->addVertex(pt_3); + if (vi_0 == vi_1 || vi_0 == vi_2 || vi_0 == vi_3 || vi_1 == vi_2 || vi_1 == vi_3 || + vi_2 == vi_3) { + return; } + mesh->addTrianglePair(vi_0, vi_1, vi_2, vi_3); + + break; + } } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::Integration::addToMesh (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2, - VertexIndex& vi_0, - VertexIndex& vi_1, - VertexIndex& vi_2, - const MeshPtr& mesh) const +pcl::ihs::Integration::addToMesh(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2, + VertexIndex& vi_0, + VertexIndex& vi_1, + VertexIndex& vi_2, + const MeshPtr& mesh) const { - if (!distanceThreshold (pt_0, pt_1, pt_2)) return; + if (!distanceThreshold(pt_0, pt_1, pt_2)) + return; - if (!vi_0.isValid ()) vi_0 = mesh->addVertex (pt_0); - if (!vi_1.isValid ()) vi_1 = mesh->addVertex (pt_1); - if (!vi_2.isValid ()) vi_2 = mesh->addVertex (pt_2); - if (vi_0==vi_1 || vi_0==vi_2 || vi_1==vi_2) - { + if (!vi_0.isValid()) + vi_0 = mesh->addVertex(pt_0); + if (!vi_1.isValid()) + vi_1 = mesh->addVertex(pt_1); + if (!vi_2.isValid()) + vi_2 = mesh->addVertex(pt_2); + if (vi_0 == vi_1 || vi_0 == vi_2 || vi_1 == vi_2) { return; } - mesh->addFace (vi_0, vi_1, vi_2); + mesh->addFace(vi_0, vi_1, vi_2); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::Integration::distanceThreshold (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2) const +pcl::ihs::Integration::distanceThreshold(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2) const { - if ((pt_0.getVector3fMap () - pt_1.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); - if ((pt_1.getVector3fMap () - pt_2.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); - if ((pt_2.getVector3fMap () - pt_0.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); + if ((pt_0.getVector3fMap() - pt_1.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); + if ((pt_1.getVector3fMap() - pt_2.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); + if ((pt_2.getVector3fMap() - pt_0.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); return (true); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::Integration::distanceThreshold (const PointIHS& pt_0, - const PointIHS& pt_1, - const PointIHS& pt_2, - const PointIHS& pt_3) const +pcl::ihs::Integration::distanceThreshold(const PointIHS& pt_0, + const PointIHS& pt_1, + const PointIHS& pt_2, + const PointIHS& pt_3) const { - if ((pt_0.getVector3fMap () - pt_1.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); - if ((pt_1.getVector3fMap () - pt_2.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); - if ((pt_2.getVector3fMap () - pt_3.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); - if ((pt_3.getVector3fMap () - pt_0.getVector3fMap ()).squaredNorm () > max_squared_distance_) return (false); + if ((pt_0.getVector3fMap() - pt_1.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); + if ((pt_1.getVector3fMap() - pt_2.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); + if ((pt_2.getVector3fMap() - pt_3.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); + if ((pt_3.getVector3fMap() - pt_0.getVector3fMap()).squaredNorm() > + max_squared_distance_) + return (false); return (true); } diff --git a/apps/in_hand_scanner/src/main.cpp b/apps/in_hand_scanner/src/main.cpp index d404dc0cdf9..05c4e03ba99 100644 --- a/apps/in_hand_scanner/src/main.cpp +++ b/apps/in_hand_scanner/src/main.cpp @@ -38,15 +38,15 @@ * */ -#include - #include +#include + int -main (int argc, char** argv) +main(int argc, char** argv) { - QApplication app (argc, argv); + QApplication app(argc, argv); pcl::ihs::MainWindow mw; - mw.show (); - return (QApplication::exec ()); + mw.show(); + return (QApplication::exec()); } diff --git a/apps/in_hand_scanner/src/main_offline_integration.cpp b/apps/in_hand_scanner/src/main_offline_integration.cpp index a8edc1bfc7e..5d2c36c6e7f 100644 --- a/apps/in_hand_scanner/src/main_offline_integration.cpp +++ b/apps/in_hand_scanner/src/main_offline_integration.cpp @@ -38,17 +38,17 @@ * */ +#include + #include #include -#include - int -main (int argc, char** argv) +main(int argc, char** argv) { - QApplication app (argc, argv); + QApplication app(argc, argv); pcl::ihs::OfflineIntegration oi; - QTimer::singleShot(0, &oi, SLOT (start ())); - oi.show (); - return (QApplication::exec ()); + QTimer::singleShot(0, &oi, SLOT(start())); + oi.show(); + return (QApplication::exec()); } diff --git a/apps/in_hand_scanner/src/main_window.cpp b/apps/in_hand_scanner/src/main_window.cpp index 8f21294cfb8..f32601307db 100644 --- a/apps/in_hand_scanner/src/main_window.cpp +++ b/apps/in_hand_scanner/src/main_window.cpp @@ -38,10 +38,12 @@ * */ +#include +#include +#include +#include +#include #include -#include "ui_main_window.h" - -#include #include #include @@ -50,339 +52,387 @@ #include #include -#include -#include -#include -#include -#include +#include "ui_main_window.h" + +#include //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::MainWindow::MainWindow (QWidget* parent) - : QMainWindow (parent), - ui_ (new Ui::MainWindow ()), - help_window_ (new HelpWindow (this)), - ihs_ (new InHandScanner ()) +pcl::ihs::MainWindow::MainWindow(QWidget* parent) +: QMainWindow(parent) +, ui_(new Ui::MainWindow()) +, help_window_(new HelpWindow(this)) +, ihs_(new InHandScanner()) { - ui_->setupUi (this); + ui_->setupUi(this); - QWidget* spacer = new QWidget (); - spacer->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - ui_->toolBar->insertWidget (ui_->actionHelp, spacer); + QWidget* spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + ui_->toolBar->insertWidget(ui_->actionHelp, spacer); - const double max = std::numeric_limits ::max (); + const double max = std::numeric_limits::max(); // In hand scanner - QHBoxLayout* layout = new QHBoxLayout (ui_->placeholder_in_hand_scanner); - layout->addWidget (ihs_); + QHBoxLayout* layout = new QHBoxLayout(ui_->placeholder_in_hand_scanner); + layout->addWidget(ihs_); // ui_->centralWidget->setLayout (layout); - QTimer::singleShot (0, ihs_, SLOT (startGrabber ())); + QTimer::singleShot(0, ihs_, SLOT(startGrabber())); - connect (ui_->toolButton_1, SIGNAL (clicked ()), ihs_, SLOT (showUnprocessedData ())); - connect (ui_->toolButton_2, SIGNAL (clicked ()), ihs_, SLOT (showProcessedData ())); - connect (ui_->toolButton_3, SIGNAL (clicked ()), ihs_, SLOT (registerContinuously ())); - connect (ui_->toolButton_4, SIGNAL (clicked ()), ihs_, SLOT (registerOnce ())); - connect (ui_->toolButton_5, SIGNAL (clicked ()), ihs_, SLOT (showModel ())); - connect (ui_->toolButton_6, SIGNAL (clicked ()), ihs_, SLOT (removeUnfitVertices ())); - connect (ui_->toolButton_0, SIGNAL (clicked ()), ihs_, SLOT (reset ())); + connect(ui_->toolButton_1, SIGNAL(clicked()), ihs_, SLOT(showUnprocessedData())); + connect(ui_->toolButton_2, SIGNAL(clicked()), ihs_, SLOT(showProcessedData())); + connect(ui_->toolButton_3, SIGNAL(clicked()), ihs_, SLOT(registerContinuously())); + connect(ui_->toolButton_4, SIGNAL(clicked()), ihs_, SLOT(registerOnce())); + connect(ui_->toolButton_5, SIGNAL(clicked()), ihs_, SLOT(showModel())); + connect(ui_->toolButton_6, SIGNAL(clicked()), ihs_, SLOT(removeUnfitVertices())); + connect(ui_->toolButton_0, SIGNAL(clicked()), ihs_, SLOT(reset())); - connect (ui_->actionReset_camera, SIGNAL (triggered ()), ihs_, SLOT (resetCamera ())); - connect (ui_->actionToggle_coloring, SIGNAL (triggered ()), ihs_, SLOT (toggleColoring ())); - connect (ui_->actionMesh_representation, SIGNAL (triggered ()), ihs_, SLOT (toggleMeshRepresentation ())); + connect(ui_->actionReset_camera, SIGNAL(triggered()), ihs_, SLOT(resetCamera())); + connect( + ui_->actionToggle_coloring, SIGNAL(triggered()), ihs_, SLOT(toggleColoring())); + connect(ui_->actionMesh_representation, + SIGNAL(triggered()), + ihs_, + SLOT(toggleMeshRepresentation())); - connect (ui_->actionSaveAs, SIGNAL (triggered ()), this, SLOT (saveAs ())); + connect(ui_->actionSaveAs, SIGNAL(triggered()), this, SLOT(saveAs())); - connect (ihs_, SIGNAL (runningModeChanged (RunningMode)), this, SLOT (runningModeChanged (RunningMode))); + connect(ihs_, + SIGNAL(runningModeChanged(RunningMode)), + this, + SLOT(runningModeChanged(RunningMode))); // Input data processing - const pcl::ihs::InputDataProcessing& idp = ihs_->getInputDataProcessing (); - - ui_->spinBox_x_min->setValue (static_cast (idp.getXMin ())); - ui_->spinBox_x_max->setValue (static_cast (idp.getXMax ())); - ui_->spinBox_y_min->setValue (static_cast (idp.getYMin ())); - ui_->spinBox_y_max->setValue (static_cast (idp.getYMax ())); - ui_->spinBox_z_min->setValue (static_cast (idp.getZMin ())); - ui_->spinBox_z_max->setValue (static_cast (idp.getZMax ())); - - ui_->spinBox_h_min->setValue (static_cast (idp.getHMin ())); - ui_->spinBox_h_max->setValue (static_cast (idp.getHMax ())); - ui_->spinBox_s_min->setValue (static_cast (idp.getSMin () * 100.f)); - ui_->spinBox_s_max->setValue (static_cast (idp.getSMax () * 100.f)); - ui_->spinBox_v_min->setValue (static_cast (idp.getVMin () * 100.f)); - ui_->spinBox_v_max->setValue (static_cast (idp.getVMax () * 100.f)); - - ui_->checkBox_color_segmentation_inverted->setChecked (idp.getColorSegmentationInverted ()); - ui_->checkBox_color_segmentation_enabled->setChecked (idp.getColorSegmentationEnabled ()); - - ui_->spinBox_xyz_erode_size->setValue (idp.getXYZErodeSize ()); - ui_->spinBox_hsv_dilate_size->setValue (idp.getHSVDilateSize ()); + const pcl::ihs::InputDataProcessing& idp = ihs_->getInputDataProcessing(); + + ui_->spinBox_x_min->setValue(static_cast(idp.getXMin())); + ui_->spinBox_x_max->setValue(static_cast(idp.getXMax())); + ui_->spinBox_y_min->setValue(static_cast(idp.getYMin())); + ui_->spinBox_y_max->setValue(static_cast(idp.getYMax())); + ui_->spinBox_z_min->setValue(static_cast(idp.getZMin())); + ui_->spinBox_z_max->setValue(static_cast(idp.getZMax())); + + ui_->spinBox_h_min->setValue(static_cast(idp.getHMin())); + ui_->spinBox_h_max->setValue(static_cast(idp.getHMax())); + ui_->spinBox_s_min->setValue(static_cast(idp.getSMin() * 100.f)); + ui_->spinBox_s_max->setValue(static_cast(idp.getSMax() * 100.f)); + ui_->spinBox_v_min->setValue(static_cast(idp.getVMin() * 100.f)); + ui_->spinBox_v_max->setValue(static_cast(idp.getVMax() * 100.f)); + + ui_->checkBox_color_segmentation_inverted->setChecked( + idp.getColorSegmentationInverted()); + ui_->checkBox_color_segmentation_enabled->setChecked( + idp.getColorSegmentationEnabled()); + + ui_->spinBox_xyz_erode_size->setValue(idp.getXYZErodeSize()); + ui_->spinBox_hsv_dilate_size->setValue(idp.getHSVDilateSize()); // Registration - ui_->lineEdit_epsilon->setValidator (new QDoubleValidator (0., max, 2)); - ui_->lineEdit_max_fitness->setValidator (new QDoubleValidator (0., max, 2)); + ui_->lineEdit_epsilon->setValidator(new QDoubleValidator(0., max, 2)); + ui_->lineEdit_max_fitness->setValidator(new QDoubleValidator(0., max, 2)); - ui_->lineEdit_epsilon->setText (QString ().setNum (ihs_->getICP ().getEpsilon ())); - ui_->spinBox_max_iterations->setValue (static_cast (ihs_->getICP ().getMaxIterations ())); - ui_->spinBox_min_overlap->setValue (static_cast (100.f * ihs_->getICP ().getMinOverlap ())); - ui_->lineEdit_max_fitness->setText (QString ().setNum (ihs_->getICP ().getMaxFitness ())); + ui_->lineEdit_epsilon->setText(QString().setNum(ihs_->getICP().getEpsilon())); + ui_->spinBox_max_iterations->setValue( + static_cast(ihs_->getICP().getMaxIterations())); + ui_->spinBox_min_overlap->setValue( + static_cast(100.f * ihs_->getICP().getMinOverlap())); + ui_->lineEdit_max_fitness->setText(QString().setNum(ihs_->getICP().getMaxFitness())); - ui_->doubleSpinBox_correspondence_rejection_factor->setValue (ihs_->getICP ().getCorrespondenceRejectionFactor ()); - ui_->spinBox_correspondence_rejection_max_angle->setValue (static_cast (ihs_->getICP ().getMaxAngle ())); + ui_->doubleSpinBox_correspondence_rejection_factor->setValue( + ihs_->getICP().getCorrespondenceRejectionFactor()); + ui_->spinBox_correspondence_rejection_max_angle->setValue( + static_cast(ihs_->getICP().getMaxAngle())); // Integration - ui_->lineEdit_max_squared_distance->setValidator (new QDoubleValidator (0., max, 2)); + ui_->lineEdit_max_squared_distance->setValidator(new QDoubleValidator(0., max, 2)); - ui_->lineEdit_max_squared_distance->setText (QString ().setNum (ihs_->getIntegration ().getMaxSquaredDistance ())); - ui_->spinBox_averaging_max_angle->setValue (static_cast (ihs_->getIntegration ().getMaxAngle ())); - ui_->spinBox_max_age->setValue (static_cast (ihs_->getIntegration ().getMaxAge ())); - ui_->spinBox_min_directions->setValue (static_cast (ihs_->getIntegration ().getMinDirections ())); + ui_->lineEdit_max_squared_distance->setText( + QString().setNum(ihs_->getIntegration().getMaxSquaredDistance())); + ui_->spinBox_averaging_max_angle->setValue( + static_cast(ihs_->getIntegration().getMaxAngle())); + ui_->spinBox_max_age->setValue(static_cast(ihs_->getIntegration().getMaxAge())); + ui_->spinBox_min_directions->setValue( + static_cast(ihs_->getIntegration().getMinDirections())); // Help - connect (ui_->actionHelp, SIGNAL (triggered ()), this, SLOT (showHelp ())); + connect(ui_->actionHelp, SIGNAL(triggered()), this, SLOT(showHelp())); } //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::MainWindow::~MainWindow () -{ - delete ui_; -} +pcl::ihs::MainWindow::~MainWindow() { delete ui_; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::showHelp () +pcl::ihs::MainWindow::showHelp() { - help_window_->show (); + help_window_->show(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::saveAs () +pcl::ihs::MainWindow::saveAs() { - QString filename = QFileDialog::getSaveFileName (this, "Save the model mesh.", "", "Polygon File Format (*.ply);;VTK File Format (*.vtk)"); + QString filename = QFileDialog::getSaveFileName( + this, + "Save the model mesh.", + "", + "Polygon File Format (*.ply);;VTK File Format (*.vtk)"); - if (filename.isEmpty ()) return; + if (filename.isEmpty()) + return; - if (filename.endsWith ("ply", Qt::CaseInsensitive)) - ihs_->saveAs (filename.toStdString (), pcl::ihs::InHandScanner::FT_PLY); - else if (filename.endsWith ("vtk", Qt::CaseInsensitive)) - ihs_->saveAs (filename.toStdString (), pcl::ihs::InHandScanner::FT_VTK); + if (filename.endsWith("ply", Qt::CaseInsensitive)) + ihs_->saveAs(filename.toStdString(), pcl::ihs::InHandScanner::FT_PLY); + else if (filename.endsWith("vtk", Qt::CaseInsensitive)) + ihs_->saveAs(filename.toStdString(), pcl::ihs::InHandScanner::FT_VTK); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::runningModeChanged (const RunningMode mode) -{ - switch (mode) - { - case InHandScanner::RM_UNPROCESSED: ui_->toolButton_1->setChecked (true); break; - case InHandScanner::RM_PROCESSED: ui_->toolButton_2->setChecked (true); break; - case InHandScanner::RM_REGISTRATION_CONT: ui_->toolButton_3->setChecked (true); break; - case InHandScanner::RM_REGISTRATION_SINGLE: break; - case InHandScanner::RM_SHOW_MODEL: ui_->toolButton_5->setChecked (true); break; +pcl::ihs::MainWindow::runningModeChanged(const RunningMode mode) +{ + switch (mode) { + case InHandScanner::RM_UNPROCESSED: + ui_->toolButton_1->setChecked(true); + break; + case InHandScanner::RM_PROCESSED: + ui_->toolButton_2->setChecked(true); + break; + case InHandScanner::RM_REGISTRATION_CONT: + ui_->toolButton_3->setChecked(true); + break; + case InHandScanner::RM_REGISTRATION_SINGLE: + break; + case InHandScanner::RM_SHOW_MODEL: + ui_->toolButton_5->setChecked(true); + break; } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::keyPressEvent (QKeyEvent* event) +pcl::ihs::MainWindow::keyPressEvent(QKeyEvent* event) { - ihs_->keyPressEvent (event); + ihs_->keyPressEvent(event); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::setXMin (const int x_min) +pcl::ihs::MainWindow::setXMin(const int x_min) { - ihs_->getInputDataProcessing ().setXMin (static_cast (x_min)); - ui_->spinBox_x_min->setValue (static_cast (ihs_->getInputDataProcessing ().getXMin ())); + ihs_->getInputDataProcessing().setXMin(static_cast(x_min)); + ui_->spinBox_x_min->setValue( + static_cast(ihs_->getInputDataProcessing().getXMin())); } void -pcl::ihs::MainWindow::setXMax (const int x_max) +pcl::ihs::MainWindow::setXMax(const int x_max) { - ihs_->getInputDataProcessing ().setXMax (static_cast (x_max)); - ui_->spinBox_x_max->setValue (static_cast (ihs_->getInputDataProcessing ().getXMax ())); + ihs_->getInputDataProcessing().setXMax(static_cast(x_max)); + ui_->spinBox_x_max->setValue( + static_cast(ihs_->getInputDataProcessing().getXMax())); } void -pcl::ihs::MainWindow::setYMin (const int y_min) +pcl::ihs::MainWindow::setYMin(const int y_min) { - ihs_->getInputDataProcessing ().setYMin (static_cast (y_min)); - ui_->spinBox_y_min->setValue (static_cast (ihs_->getInputDataProcessing ().getYMin ())); + ihs_->getInputDataProcessing().setYMin(static_cast(y_min)); + ui_->spinBox_y_min->setValue( + static_cast(ihs_->getInputDataProcessing().getYMin())); } void -pcl::ihs::MainWindow::setYMax (const int y_max) +pcl::ihs::MainWindow::setYMax(const int y_max) { - ihs_->getInputDataProcessing ().setYMax (static_cast (y_max)); - ui_->spinBox_y_max->setValue (static_cast (ihs_->getInputDataProcessing ().getYMax ())); + ihs_->getInputDataProcessing().setYMax(static_cast(y_max)); + ui_->spinBox_y_max->setValue( + static_cast(ihs_->getInputDataProcessing().getYMax())); } void -pcl::ihs::MainWindow::setZMin (const int z_min) +pcl::ihs::MainWindow::setZMin(const int z_min) { - ihs_->getInputDataProcessing ().setZMin (static_cast (z_min)); - ui_->spinBox_z_min->setValue (static_cast (ihs_->getInputDataProcessing ().getZMin ())); + ihs_->getInputDataProcessing().setZMin(static_cast(z_min)); + ui_->spinBox_z_min->setValue( + static_cast(ihs_->getInputDataProcessing().getZMin())); } void -pcl::ihs::MainWindow::setZMax (const int z_max) +pcl::ihs::MainWindow::setZMax(const int z_max) { - ihs_->getInputDataProcessing ().setZMax (static_cast (z_max)); - ui_->spinBox_z_max->setValue (static_cast (ihs_->getInputDataProcessing ().getZMax ())); + ihs_->getInputDataProcessing().setZMax(static_cast(z_max)); + ui_->spinBox_z_max->setValue( + static_cast(ihs_->getInputDataProcessing().getZMax())); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::setHMin (const int h_min) +pcl::ihs::MainWindow::setHMin(const int h_min) { - ihs_->getInputDataProcessing ().setHMin (static_cast (h_min)); - ui_->spinBox_h_min->setValue (static_cast (ihs_->getInputDataProcessing ().getHMin ())); + ihs_->getInputDataProcessing().setHMin(static_cast(h_min)); + ui_->spinBox_h_min->setValue( + static_cast(ihs_->getInputDataProcessing().getHMin())); } void -pcl::ihs::MainWindow::setHMax (const int h_max) +pcl::ihs::MainWindow::setHMax(const int h_max) { - ihs_->getInputDataProcessing ().setHMax (static_cast (h_max)); - ui_->spinBox_h_max->setValue (static_cast (ihs_->getInputDataProcessing ().getHMax ())); + ihs_->getInputDataProcessing().setHMax(static_cast(h_max)); + ui_->spinBox_h_max->setValue( + static_cast(ihs_->getInputDataProcessing().getHMax())); } void -pcl::ihs::MainWindow::setSMin (const int s_min) +pcl::ihs::MainWindow::setSMin(const int s_min) { - ihs_->getInputDataProcessing ().setSMin (.01f * static_cast (s_min)); - ui_->spinBox_s_min->setValue (static_cast (100.f * ihs_->getInputDataProcessing ().getSMin () + 0.5f)); + ihs_->getInputDataProcessing().setSMin(.01f * static_cast(s_min)); + ui_->spinBox_s_min->setValue( + static_cast(100.f * ihs_->getInputDataProcessing().getSMin() + 0.5f)); } void -pcl::ihs::MainWindow::setSMax (const int s_max) +pcl::ihs::MainWindow::setSMax(const int s_max) { - ihs_->getInputDataProcessing ().setSMax (.01f * static_cast (s_max)); - ui_->spinBox_s_max->setValue (static_cast (100.f * ihs_->getInputDataProcessing ().getSMax () + 0.5f)); + ihs_->getInputDataProcessing().setSMax(.01f * static_cast(s_max)); + ui_->spinBox_s_max->setValue( + static_cast(100.f * ihs_->getInputDataProcessing().getSMax() + 0.5f)); } void -pcl::ihs::MainWindow::setVMin (const int v_min) +pcl::ihs::MainWindow::setVMin(const int v_min) { - ihs_->getInputDataProcessing ().setVMin (.01f * static_cast (v_min)); - ui_->spinBox_v_min->setValue (static_cast (100.f * ihs_->getInputDataProcessing ().getVMin () + 0.5f)); + ihs_->getInputDataProcessing().setVMin(.01f * static_cast(v_min)); + ui_->spinBox_v_min->setValue( + static_cast(100.f * ihs_->getInputDataProcessing().getVMin() + 0.5f)); } void -pcl::ihs::MainWindow::setVMax (const int v_max) +pcl::ihs::MainWindow::setVMax(const int v_max) { - ihs_->getInputDataProcessing ().setVMax (.01f * static_cast (v_max)); - ui_->spinBox_v_max->setValue (static_cast (100.f * ihs_->getInputDataProcessing ().getVMax () + 0.5f)); + ihs_->getInputDataProcessing().setVMax(.01f * static_cast(v_max)); + ui_->spinBox_v_max->setValue( + static_cast(100.f * ihs_->getInputDataProcessing().getVMax() + 0.5f)); } void -pcl::ihs::MainWindow::setColorSegmentationInverted (const bool is_inverted) +pcl::ihs::MainWindow::setColorSegmentationInverted(const bool is_inverted) { - ihs_->getInputDataProcessing ().setColorSegmentationInverted (is_inverted); - ui_->checkBox_color_segmentation_inverted->setChecked (ihs_->getInputDataProcessing ().getColorSegmentationInverted ()); + ihs_->getInputDataProcessing().setColorSegmentationInverted(is_inverted); + ui_->checkBox_color_segmentation_inverted->setChecked( + ihs_->getInputDataProcessing().getColorSegmentationInverted()); } void -pcl::ihs::MainWindow::setColorSegmentationEnabled (const bool is_enabled) +pcl::ihs::MainWindow::setColorSegmentationEnabled(const bool is_enabled) { - ihs_->getInputDataProcessing ().setColorSegmentationEnabled (is_enabled); - ui_->checkBox_color_segmentation_enabled->setChecked (ihs_->getInputDataProcessing ().getColorSegmentationEnabled ()); + ihs_->getInputDataProcessing().setColorSegmentationEnabled(is_enabled); + ui_->checkBox_color_segmentation_enabled->setChecked( + ihs_->getInputDataProcessing().getColorSegmentationEnabled()); } void -pcl::ihs::MainWindow::setXYZErodeSize (const int size) +pcl::ihs::MainWindow::setXYZErodeSize(const int size) { - ihs_->getInputDataProcessing ().setXYZErodeSize (static_cast (size)); - ui_->spinBox_xyz_erode_size->setValue (static_cast (ihs_->getInputDataProcessing ().getXYZErodeSize ())); + ihs_->getInputDataProcessing().setXYZErodeSize(static_cast(size)); + ui_->spinBox_xyz_erode_size->setValue( + static_cast(ihs_->getInputDataProcessing().getXYZErodeSize())); } void -pcl::ihs::MainWindow::setHSVDilateSize (const int size) +pcl::ihs::MainWindow::setHSVDilateSize(const int size) { - ihs_->getInputDataProcessing ().setHSVDilateSize (static_cast (size)); - ui_->spinBox_hsv_dilate_size->setValue (static_cast (ihs_->getInputDataProcessing ().getHSVDilateSize ())); + ihs_->getInputDataProcessing().setHSVDilateSize(static_cast(size)); + ui_->spinBox_hsv_dilate_size->setValue( + static_cast(ihs_->getInputDataProcessing().getHSVDilateSize())); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::setEpsilon () +pcl::ihs::MainWindow::setEpsilon() { - ihs_->getICP ().setEpsilon (ui_->lineEdit_epsilon->text ().toFloat ()); - ui_->lineEdit_epsilon->setText (QString ().setNum (ihs_->getICP ().getEpsilon ())); + ihs_->getICP().setEpsilon(ui_->lineEdit_epsilon->text().toFloat()); + ui_->lineEdit_epsilon->setText(QString().setNum(ihs_->getICP().getEpsilon())); } void -pcl::ihs::MainWindow::setMaxIterations (const int iterations) +pcl::ihs::MainWindow::setMaxIterations(const int iterations) { - ihs_->getICP ().setMaxIterations (static_cast (iterations)); - ui_->spinBox_max_iterations->setValue (static_cast (ihs_->getICP ().getMaxIterations ())); + ihs_->getICP().setMaxIterations(static_cast(iterations)); + ui_->spinBox_max_iterations->setValue( + static_cast(ihs_->getICP().getMaxIterations())); } void -pcl::ihs::MainWindow::setMinOverlap (const int overlap) +pcl::ihs::MainWindow::setMinOverlap(const int overlap) { - ihs_->getICP ().setMinOverlap (.01f * static_cast (overlap)); - ui_->spinBox_min_overlap->setValue (static_cast (100.f * ihs_->getICP ().getMinOverlap () + 0.5f)); + ihs_->getICP().setMinOverlap(.01f * static_cast(overlap)); + ui_->spinBox_min_overlap->setValue( + static_cast(100.f * ihs_->getICP().getMinOverlap() + 0.5f)); } void -pcl::ihs::MainWindow::setMaxFitness () +pcl::ihs::MainWindow::setMaxFitness() { - ihs_->getICP ().setMaxFitness (ui_->lineEdit_max_fitness->text ().toFloat ()); - ui_->lineEdit_max_fitness->setText (QString ().setNum (ihs_->getICP ().getMaxFitness ())); + ihs_->getICP().setMaxFitness(ui_->lineEdit_max_fitness->text().toFloat()); + ui_->lineEdit_max_fitness->setText(QString().setNum(ihs_->getICP().getMaxFitness())); } void -pcl::ihs::MainWindow::setCorrespondenceRejectionFactor (const double factor) +pcl::ihs::MainWindow::setCorrespondenceRejectionFactor(const double factor) { - ihs_->getICP ().setCorrespondenceRejectionFactor (static_cast (factor)); - ui_->doubleSpinBox_correspondence_rejection_factor->setValue (static_cast (ihs_->getICP ().getCorrespondenceRejectionFactor ())); + ihs_->getICP().setCorrespondenceRejectionFactor(static_cast(factor)); + ui_->doubleSpinBox_correspondence_rejection_factor->setValue( + static_cast(ihs_->getICP().getCorrespondenceRejectionFactor())); } void -pcl::ihs::MainWindow::setCorrespondenceRejectionMaxAngle (const int angle) +pcl::ihs::MainWindow::setCorrespondenceRejectionMaxAngle(const int angle) { - ihs_->getICP ().setMaxAngle (static_cast (angle)); - ui_->spinBox_correspondence_rejection_max_angle->setValue (static_cast (ihs_->getICP ().getMaxAngle ())); + ihs_->getICP().setMaxAngle(static_cast(angle)); + ui_->spinBox_correspondence_rejection_max_angle->setValue( + static_cast(ihs_->getICP().getMaxAngle())); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MainWindow::setMaxSquaredDistance () +pcl::ihs::MainWindow::setMaxSquaredDistance() { - ihs_->getIntegration ().setMaxSquaredDistance (ui_->lineEdit_max_squared_distance->text ().toFloat ()); - ui_->lineEdit_max_squared_distance->setText (QString ().setNum (ihs_->getIntegration ().getMaxSquaredDistance ())); + ihs_->getIntegration().setMaxSquaredDistance( + ui_->lineEdit_max_squared_distance->text().toFloat()); + ui_->lineEdit_max_squared_distance->setText( + QString().setNum(ihs_->getIntegration().getMaxSquaredDistance())); } void -pcl::ihs::MainWindow::setAveragingMaxAngle (const int angle) +pcl::ihs::MainWindow::setAveragingMaxAngle(const int angle) { - ihs_->getIntegration ().setMaxAngle (static_cast (angle)); - ui_->spinBox_averaging_max_angle->setValue (static_cast (ihs_->getIntegration ().getMaxAngle ())); + ihs_->getIntegration().setMaxAngle(static_cast(angle)); + ui_->spinBox_averaging_max_angle->setValue( + static_cast(ihs_->getIntegration().getMaxAngle())); } void -pcl::ihs::MainWindow::setMaxAge (const int age) +pcl::ihs::MainWindow::setMaxAge(const int age) { - ihs_->getIntegration ().setMaxAge (static_cast (age)); - ui_->spinBox_max_age->setValue (static_cast (ihs_->getIntegration ().getMaxAge ())); + ihs_->getIntegration().setMaxAge(static_cast(age)); + ui_->spinBox_max_age->setValue(static_cast(ihs_->getIntegration().getMaxAge())); } void -pcl::ihs::MainWindow::setMinDirections (const int directions) +pcl::ihs::MainWindow::setMinDirections(const int directions) { - ihs_->getIntegration ().setMinDirections (static_cast (directions)); - ui_->spinBox_min_directions->setValue (static_cast (ihs_->getIntegration ().getMinDirections ())); + ihs_->getIntegration().setMinDirections(static_cast(directions)); + ui_->spinBox_min_directions->setValue( + static_cast(ihs_->getIntegration().getMinDirections())); } //////////////////////////////////////////////////////////////////////////////// diff --git a/apps/in_hand_scanner/src/mesh_processing.cpp b/apps/in_hand_scanner/src/mesh_processing.cpp index feaf6f48240..2885dfb811c 100644 --- a/apps/in_hand_scanner/src/mesh_processing.cpp +++ b/apps/in_hand_scanner/src/mesh_processing.cpp @@ -39,49 +39,48 @@ */ #include +#include #include -#include - //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::MeshProcessing::MeshProcessing () -{ -} +pcl::ihs::MeshProcessing::MeshProcessing() {} //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::MeshProcessing::processBoundary (Mesh& mesh, const std::vector & boundary_collection, const bool cleanup) const +pcl::ihs::MeshProcessing::processBoundary( + Mesh& mesh, + const std::vector& boundary_collection, + const bool cleanup) const { Mesh::VertexIndex vi_a, vi_b, vi_c, vi_d; Eigen::Vector3f ab, bc, ac, n_adb, n_plane; // Edges and normals Mesh::FaceIndex opposite_face; - for (const auto &boundary : boundary_collection) - { - if (boundary.size () == 3) - { - opposite_face = mesh.getOppositeFaceIndex (boundary [0]); + for (const auto& boundary : boundary_collection) { + if (boundary.size() == 3) { + opposite_face = mesh.getOppositeFaceIndex(boundary[0]); - if (mesh.getOppositeFaceIndex (boundary [1]) == opposite_face && - mesh.getOppositeFaceIndex (boundary [2]) == opposite_face) - { + if (mesh.getOppositeFaceIndex(boundary[1]) == opposite_face && + mesh.getOppositeFaceIndex(boundary[2]) == opposite_face) { // Isolated face. - mesh.deleteFace (opposite_face); + mesh.deleteFace(opposite_face); } - else - { + else { // Close triangular hole. - mesh.addFace (mesh.getTerminatingVertexIndex (boundary [0]), - mesh.getTerminatingVertexIndex (boundary [1]), - mesh.getTerminatingVertexIndex (boundary [2])); + mesh.addFace(mesh.getTerminatingVertexIndex(boundary[0]), + mesh.getTerminatingVertexIndex(boundary[1]), + mesh.getTerminatingVertexIndex(boundary[2])); } } else // size != 3 { - // Add triangles where the angle between the edges is below a threshold. In the example this would leave only triangles 1-2-3 and triangles 4-5-6 (threshold = 60 degrees). Triangle 1-2-3 should not be added because vertex 2 is not convex (as vertex 5). + // Add triangles where the angle between the edges is below a threshold. In the + // example this would leave only triangles 1-2-3 and triangles 4-5-6 (threshold = + // 60 degrees). Triangle 1-2-3 should not be added because vertex 2 is not convex + // (as vertex 5). // Example: The boundary is on the top. Vertex 7 is connected to vertex 0. // 2 // @@ -90,39 +89,42 @@ pcl::ihs::MeshProcessing::processBoundary (Mesh& mesh, const std::vector (); - bc = (v_c - v_b).head <3> (); - ac = (v_c - v_a).head <3> (); + ab = (v_b - v_a).head<3>(); + bc = (v_c - v_b).head<3>(); + ac = (v_c - v_a).head<3>(); - const float angle = std::acos (pcl::ihs::clamp (-ab.dot (bc) / ab.norm () / bc.norm (), -1.f, 1.f)); + const float angle = + std::acos(pcl::ihs::clamp(-ab.dot(bc) / ab.norm() / bc.norm(), -1.f, 1.f)); if (angle < 1.047197551196598f) // 60 * pi / 180 { // Third vertex belonging to the face of edge ab - vi_d = mesh.getTerminatingVertexIndex ( - mesh.getNextHalfEdgeIndex ( - mesh.getOppositeHalfEdgeIndex (boundary [i]))); - const Eigen::Vector4f& v_d = mesh.getVertexDataCloud () [vi_d.get ()].getVector4fMap (); + vi_d = mesh.getTerminatingVertexIndex( + mesh.getNextHalfEdgeIndex(mesh.getOppositeHalfEdgeIndex(boundary[i]))); + const Eigen::Vector4f& v_d = + mesh.getVertexDataCloud()[vi_d.get()].getVector4fMap(); // n_adb is the normal of triangle a-d-b. - // The plane goes through edge a-b and is perpendicular to the plane through a-d-b. - n_adb = (v_d - v_a).head <3> ().cross (ab)/*.normalized ()*/; - n_plane = n_adb.cross (ab/*.nomalized ()*/); + // The plane goes through edge a-b and is perpendicular to the plane through + // a-d-b. + n_adb = (v_d - v_a).head<3>().cross(ab) /*.normalized()*/; + n_plane = n_adb.cross(ab /*.nomalized()*/); - if (n_plane.dot (ac) > 0.f) - { - mesh.addFace (vi_a, vi_b, vi_c); + if (n_plane.dot(ac) > 0.f) { + mesh.addFace(vi_a, vi_b, vi_c); } } } @@ -130,7 +132,7 @@ pcl::ihs::MeshProcessing::processBoundary (Mesh& mesh, const std::vector #include +#include +#include +#include -#include -#include - -#include #include +#include #include #include -#include #include #include +#include -#include -#include -#include -#include +#include +#include //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::OfflineIntegration::OfflineIntegration (Base* parent) - : Base (parent), - mesh_model_ (new Mesh ()), - normal_estimation_ (new NormalEstimation ()), - integration_ (new Integration ()), - destructor_called_ (false) +pcl::ihs::OfflineIntegration::OfflineIntegration(Base* parent) +: Base(parent) +, mesh_model_(new Mesh()) +, normal_estimation_(new NormalEstimation()) +, integration_(new Integration()) +, destructor_called_(false) { - normal_estimation_->setNormalEstimationMethod (NormalEstimation::AVERAGE_3D_GRADIENT); - normal_estimation_->setMaxDepthChangeFactor (0.02f); // in meters - normal_estimation_->setNormalSmoothingSize (10.0f); - - integration_->setMaxSquaredDistance (1e-4); // in m^2 - integration_->setMinDirections (2); + normal_estimation_->setNormalEstimationMethod(NormalEstimation::AVERAGE_3D_GRADIENT); + normal_estimation_->setMaxDepthChangeFactor(0.02f); // in meters + normal_estimation_->setNormalSmoothingSize(10.0f); + integration_->setMaxSquaredDistance(1e-4); // in m^2 + integration_->setMinDirections(2); - Base::setVisibilityConfidenceNormalization (static_cast (integration_->getMinDirections ())); + Base::setVisibilityConfidenceNormalization( + static_cast(integration_->getMinDirections())); } //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::OfflineIntegration::~OfflineIntegration () +pcl::ihs::OfflineIntegration::~OfflineIntegration() { - std::lock_guard lock (mutex_); - std::lock_guard lock_quit (mutex_quit_); + std::lock_guard lock(mutex_); + std::lock_guard lock_quit(mutex_quit_); destructor_called_ = true; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OfflineIntegration::start () +pcl::ihs::OfflineIntegration::start() { - QString dir = QFileDialog::getExistingDirectory (nullptr, "Please select a directory containing .pcd and .transform files."); + QString dir = QFileDialog::getExistingDirectory( + nullptr, "Please select a directory containing .pcd and .transform files."); - if (dir.isEmpty ()) - { - return (QApplication::quit ()); + if (dir.isEmpty()) { + return (QApplication::quit()); } - path_dir_ = dir.toStdString (); - QtConcurrent::run ([this]{ computationThread (); }); + path_dir_ = dir.toStdString(); + QtConcurrent::run([this] { computationThread(); }); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OfflineIntegration::computationThread () +pcl::ihs::OfflineIntegration::computationThread() { - std::vector filenames; + std::vector filenames; - if (!this->getFilesFromDirectory (path_dir_, ".pcd", filenames)) - { - std::cerr << "ERROR in offline_integration.cpp: Could not get the files from the directory\n"; + if (!this->getFilesFromDirectory(path_dir_, ".pcd", filenames)) { + std::cerr << "ERROR in offline_integration.cpp: Could not get the files from the " + "directory\n"; return; } // First cloud is reference model - std::cerr << "Processing file " << std::setw (5) << 1 << " / " << filenames.size () << std::endl; - CloudXYZRGBNormalPtr cloud_model (new CloudXYZRGBNormal ()); - Eigen::Matrix4f T = Eigen::Matrix4f::Identity (); - if (!this->load (filenames [0], cloud_model, T)) - { + std::cerr << "Processing file " << std::setw(5) << 1 << " / " << filenames.size() + << std::endl; + CloudXYZRGBNormalPtr cloud_model(new CloudXYZRGBNormal()); + Eigen::Matrix4f T = Eigen::Matrix4f::Identity(); + if (!this->load(filenames[0], cloud_model, T)) { std::cerr << "ERROR in offline_integration.cpp: Could not load the model cloud.\n"; return; } - pcl::transformPointCloudWithNormals (*cloud_model, *cloud_model, T); + pcl::transformPointCloudWithNormals(*cloud_model, *cloud_model, T); - if (!integration_->reconstructMesh (cloud_model, mesh_model_)) - { - std::cerr << "ERROR in offline_integration.cpp: Could not reconstruct the model mesh.\n"; + if (!integration_->reconstructMesh(cloud_model, mesh_model_)) { + std::cerr + << "ERROR in offline_integration.cpp: Could not reconstruct the model mesh.\n"; return; } - Base::setPivot ("model"); - Base::addMesh (mesh_model_, "model"); + Base::setPivot("model"); + Base::addMesh(mesh_model_, "model"); - if (filenames.empty ()) - { + if (filenames.empty()) { return; } - for (std::size_t i=1; i lock (mutex_); - if (destructor_called_) return; + std::lock_guard lock(mutex_); + if (destructor_called_) + return; } - std::unique_lock lock_quit (mutex_quit_); + std::unique_lock lock_quit(mutex_quit_); - CloudXYZRGBNormalPtr cloud_data (new CloudXYZRGBNormal ()); - if (!this->load (filenames [i], cloud_data, T)) - { + CloudXYZRGBNormalPtr cloud_data(new CloudXYZRGBNormal()); + if (!this->load(filenames[i], cloud_data, T)) { std::cerr << "ERROR in offline_integration.cpp: Could not load the data cloud.\n"; return; } - if (!integration_->merge (cloud_data, mesh_model_, T)) - { + if (!integration_->merge(cloud_data, mesh_model_, T)) { std::cerr << "ERROR in offline_integration.cpp: merge failed.\n"; return; } - integration_->age (mesh_model_); + integration_->age(mesh_model_); { - lock_quit.unlock (); - std::lock_guard lock (mutex_); - if (destructor_called_) return; - - Base::addMesh (mesh_model_, "model", Eigen::Isometry3d (T.inverse ().cast ())); - Base::calcFPS (computation_fps_); + lock_quit.unlock(); + std::lock_guard lock(mutex_); + if (destructor_called_) + return; + + Base::addMesh( + mesh_model_, "model", Eigen::Isometry3d(T.inverse().cast())); + Base::calcFPS(computation_fps_); } } - Base::setPivot ("model"); + Base::setPivot("model"); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OfflineIntegration::getFilesFromDirectory (const std::string& path_dir, - const std::string& extension, - std::vector & files) const +pcl::ihs::OfflineIntegration::getFilesFromDirectory( + const std::string& path_dir, + const std::string& extension, + std::vector& files) const { - if (path_dir.empty() || !boost::filesystem::exists (path_dir)) - { - std::cerr << "ERROR in offline_integration.cpp: Invalid path\n '" << path_dir << "'\n"; + if (path_dir.empty() || !boost::filesystem::exists(path_dir)) { + std::cerr << "ERROR in offline_integration.cpp: Invalid path\n '" << path_dir + << "'\n"; return (false); } boost::filesystem::directory_iterator it_end; - for (boost::filesystem::directory_iterator it (path_dir); it != it_end; ++it) - { - if (!is_directory (it->status ()) && - boost::algorithm::to_upper_copy (boost::filesystem::extension (it->path ())) == boost::algorithm::to_upper_copy (extension)) - { - files.push_back (it->path ().string ()); + for (boost::filesystem::directory_iterator it(path_dir); it != it_end; ++it) { + if (!is_directory(it->status()) && + boost::algorithm::to_upper_copy(boost::filesystem::extension(it->path())) == + boost::algorithm::to_upper_copy(extension)) { + files.push_back(it->path().string()); } } - if (files.empty ()) - { - std::cerr << "ERROR in offline_integration.cpp: No '" << extension << "' files found\n"; + if (files.empty()) { + std::cerr << "ERROR in offline_integration.cpp: No '" << extension + << "' files found\n"; return (false); } - sort (files.begin (), files.end ()); + sort(files.begin(), files.end()); return (true); } @@ -215,82 +214,77 @@ pcl::ihs::OfflineIntegration::getFilesFromDirectory (const std::string& //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OfflineIntegration::loadTransform (const std::string& filename, - Eigen::Matrix4f& transform) const +pcl::ihs::OfflineIntegration::loadTransform(const std::string& filename, + Eigen::Matrix4f& transform) const { - Eigen::Matrix4d tr; - std::ifstream file; - file.open (filename.c_str (), std::ios::binary); - - if (!file.is_open ()) - { - std::cerr << "Error in offline_integration.cpp: Could not open the file '" << filename << "'\n"; - return (false); - } - - for (int i = 0; i < 4; ++i) - { - for (int j = 0; j < 4; ++j) - { - file.read (reinterpret_cast(&tr (i, j)), sizeof (double)); - - if (!file.good ()) - { - std::cerr << "Error in offline_integration.cpp: Could not read the transformation from the file.\n"; - return (false); - } - } - } - - transform = tr.cast (); - - return (true); + Eigen::Matrix4d tr; + std::ifstream file; + file.open(filename.c_str(), std::ios::binary); + + if (!file.is_open()) { + std::cerr << "Error in offline_integration.cpp: Could not open the file '" + << filename << "'\n"; + return (false); + } + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + file.read(reinterpret_cast(&tr(i, j)), sizeof(double)); + + if (!file.good()) { + std::cerr << "Error in offline_integration.cpp: Could not read the " + "transformation from the file.\n"; + return (false); + } + } + } + + transform = tr.cast(); + + return (true); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OfflineIntegration::load (const std::string& filename, - CloudXYZRGBNormalPtr& cloud, - Eigen::Matrix4f& T) const +pcl::ihs::OfflineIntegration::load(const std::string& filename, + CloudXYZRGBNormalPtr& cloud, + Eigen::Matrix4f& T) const { - if (!cloud) - { - cloud = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ()); + if (!cloud) { + cloud = CloudXYZRGBNormalPtr(new CloudXYZRGBNormal()); } // Load the cloud. - CloudXYZRGBAPtr cloud_input (new CloudXYZRGBA ()); + CloudXYZRGBAPtr cloud_input(new CloudXYZRGBA()); pcl::PCDReader reader; - if (reader.read (filename, *cloud_input) < 0) - { + if (reader.read(filename, *cloud_input) < 0) { std::cerr << "ERROR in offline_integration.cpp: Could not read the pcd file.\n"; return (false); } // Normal estimation. - normal_estimation_->setInputCloud (cloud_input); - normal_estimation_->compute (*cloud); + normal_estimation_->setInputCloud(cloud_input); + normal_estimation_->compute(*cloud); - pcl::copyPointCloud (*cloud_input, *cloud); + pcl::copyPointCloud(*cloud_input, *cloud); // Change the file extension of the file. // Load the transformation. std::string fn_transform = filename; - std::size_t pos = fn_transform.find_last_of ('.'); - if (pos == std::string::npos || pos == (fn_transform.size () - 1)) - { + std::size_t pos = fn_transform.find_last_of('.'); + if (pos == std::string::npos || pos == (fn_transform.size() - 1)) { std::cerr << "ERROR in offline_integration.cpp: No file extension\n"; return (false); } - fn_transform.replace (pos, std::string::npos, ".transform"); + fn_transform.replace(pos, std::string::npos, ".transform"); - if (!this->loadTransform (fn_transform, T)) - { - std::cerr << "ERROR in offline_integration.cpp: Could not load the transformation.\n"; + if (!this->loadTransform(fn_transform, T)) { + std::cerr + << "ERROR in offline_integration.cpp: Could not load the transformation.\n"; return (false); } @@ -300,59 +294,69 @@ pcl::ihs::OfflineIntegration::load (const std::string& filename, //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OfflineIntegration::paintEvent (QPaintEvent* event) +pcl::ihs::OfflineIntegration::paintEvent(QPaintEvent* event) { - Base::paintEvent (event); + Base::paintEvent(event); - QPainter painter (this); - painter.setPen (Qt::white); + QPainter painter(this); + painter.setPen(Qt::white); QFont font; - font.setPointSize (this->width () / 50); - painter.setFont (font); + font.setPointSize(this->width() / 50); + painter.setFont(font); - std::string vis_fps ("Visualization: "), comp_fps ("Computation: "); + std::string vis_fps("Visualization: "), comp_fps("Computation: "); { - std::lock_guard lock (mutex_); - this->calcFPS (visualization_fps_); + std::lock_guard lock(mutex_); + this->calcFPS(visualization_fps_); - vis_fps.append (visualization_fps_.str ()).append (" fps"); - comp_fps.append (computation_fps_.str ()).append (" fps"); + vis_fps.append(visualization_fps_.str()).append(" fps"); + comp_fps.append(computation_fps_.str()).append(" fps"); } - const std::string str = std::string (comp_fps).append ("\n").append (vis_fps); + const std::string str = std::string(comp_fps).append("\n").append(vis_fps); - painter.drawText (0, 0, this->width (), this->height (), Qt::AlignBottom | Qt::AlignLeft, str.c_str ()); + painter.drawText(0, + 0, + this->width(), + this->height(), + Qt::AlignBottom | Qt::AlignLeft, + str.c_str()); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OfflineIntegration::keyPressEvent (QKeyEvent* event) +pcl::ihs::OfflineIntegration::keyPressEvent(QKeyEvent* event) { - if (event->key () == Qt::Key_Escape) - { - std::lock_guard lock (mutex_); - QApplication::quit (); + if (event->key() == Qt::Key_Escape) { + std::lock_guard lock(mutex_); + QApplication::quit(); } - switch (event->key ()) - { - case Qt::Key_H: - { - std::cerr << "======================================================================\n" - << "Help:\n" - << "----------------------------------------------------------------------\n" - << "ESC: Quit the application.\n" - << "c : Reset the camera.\n" - << "k : Toggle the coloring (rgb, one color, visibility-confidence).\n" - << "s : Toggle the mesh representation between points and faces.\n" - << "======================================================================\n"; - break; - } - case Qt::Key_C: Base::resetCamera (); break; - case Qt::Key_K: Base::toggleColoring (); break; - case Qt::Key_S: Base::toggleMeshRepresentation (); break; - default: break; + switch (event->key()) { + case Qt::Key_H: { + std::cerr + << "======================================================================\n" + << "Help:\n" + << "----------------------------------------------------------------------\n" + << "ESC: Quit the application.\n" + << "c : Reset the camera.\n" + << "k : Toggle the coloring (rgb, one color, visibility-confidence).\n" + << "s : Toggle the mesh representation between points and faces.\n" + << "======================================================================\n"; + break; + } + case Qt::Key_C: + Base::resetCamera(); + break; + case Qt::Key_K: + Base::toggleColoring(); + break; + case Qt::Key_S: + Base::toggleMeshRepresentation(); + break; + default: + break; } } diff --git a/apps/in_hand_scanner/src/opengl_viewer.cpp b/apps/in_hand_scanner/src/opengl_viewer.cpp index 9cdab712889..2ff9bd64cd7 100644 --- a/apps/in_hand_scanner/src/opengl_viewer.cpp +++ b/apps/in_hand_scanner/src/opengl_viewer.cpp @@ -39,63 +39,60 @@ */ #include +#include #include -#include #include - -#include +#include #ifdef OPENGL_IS_A_FRAMEWORK -# include -# include +#include +#include #else -# include -# include +#include +#include #endif -#include - +#include #include #include // TODO: PointIHS is not registered -#include + +#include //////////////////////////////////////////////////////////////////////////////// // FaceVertexMesh //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::detail::FaceVertexMesh::FaceVertexMesh () - : transformation (Eigen::Isometry3d::Identity ()) -{ -} +pcl::ihs::detail::FaceVertexMesh::FaceVertexMesh() +: transformation(Eigen::Isometry3d::Identity()) +{} //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::detail::FaceVertexMesh::FaceVertexMesh (const Mesh& mesh, const Eigen::Isometry3d& T) - : vertices (mesh.getVertexDataCloud ()), - transformation (T) +pcl::ihs::detail::FaceVertexMesh::FaceVertexMesh(const Mesh& mesh, + const Eigen::Isometry3d& T) +: vertices(mesh.getVertexDataCloud()), transformation(T) { - if (typeid (Mesh::MeshTag) != typeid (pcl::geometry::TriangleMeshTag)) - { - std::cerr << "In opengl_viewer.cpp: Only triangle meshes are currently supported!\n"; - exit (EXIT_FAILURE); + if (typeid(Mesh::MeshTag) != typeid(pcl::geometry::TriangleMeshTag)) { + std::cerr + << "In opengl_viewer.cpp: Only triangle meshes are currently supported!\n"; + exit(EXIT_FAILURE); } - for (auto &vertex : vertices) - { - std::swap (vertex.r, vertex.b); + for (auto& vertex : vertices) { + std::swap(vertex.r, vertex.b); } - triangles.reserve (mesh.sizeFaces ()); + triangles.reserve(mesh.sizeFaces()); pcl::ihs::detail::FaceVertexMesh::Triangle triangle; - for (std::size_t i=0; istart (33); + connect(timer_vis_.get(), SIGNAL(timeout()), this, SLOT(timerCallback())); + timer_vis_->start(33); // http://doc.qt.digia.com/qt/opengl-overpainting.html - QWidget::setAutoFillBackground (false); + QWidget::setAutoFillBackground(false); // http://doc.qt.digia.com/qt/qwidget.html#keyPressEvent - this->setFocusPolicy (Qt::StrongFocus); + this->setFocusPolicy(Qt::StrongFocus); // http://doc.qt.digia.com/qt/qmetatype.html#qRegisterMetaType - qRegisterMetaType ("MeshRepresentation"); - qRegisterMetaType ("Coloring"); + qRegisterMetaType("MeshRepresentation"); + qRegisterMetaType("Coloring"); ////////////////////////////////////////////////////////////////////////////// - // Code to generate the colormap (I don't want to link against vtk just for the colormap). + // Code to generate the colormap (I don't want to link against vtk just for the + // colormap). ////////////////////////////////////////////////////////////////////////////// //#include @@ -144,321 +142,320 @@ pcl::ihs::OpenGLViewer::OpenGLViewer (QWidget* parent) //#include //#include - //int - //main () - //{ - // static const unsigned int n = 256; - // // double rgb_1 [] = { 59./255., 76./255., 192./255.}; - // // double rgb_2 [] = {180./255., 4./255., 38./255.}; - // double rgb_1 [] = {180./255., 0./255., 0./255.}; - // double rgb_2 [] = { 0./255., 180./255., 0./255.}; - - // vtkSmartPointer ctf = vtkColorTransferFunction::New (); - // ctf->SetColorSpaceToDiverging (); - // ctf->AddRGBPoint ( 0., rgb_1 [0], rgb_1 [1], rgb_1 [2]); - // ctf->AddRGBPoint ( 1., rgb_2 [0], rgb_2 [1], rgb_2 [2]); - // ctf->Build (); - - // const unsigned char* colormap = ctf->GetTable (0., 1., n); - - // for (unsigned int i=0; i (colormap [3 * i ]); - // const unsigned int g = static_cast (colormap [3 * i + 1]); - // const unsigned int b = static_cast (colormap [3 * i + 2]); - - // std::cerr << "colormap_.col (" - // << std::setw (3) << i << ") = Color (" - // << std::setw (3) << r << ", " - // << std::setw (3) << g << ", " - // << std::setw (3) << b << ");\n"; - // } - - // return (EXIT_SUCCESS); - //} - - colormap_.col ( 0) = Color (180, 0, 0); - colormap_.col ( 1) = Color (182, 9, 1); - colormap_.col ( 2) = Color (184, 17, 1); - colormap_.col ( 3) = Color (186, 24, 2); - colormap_.col ( 4) = Color (188, 29, 2); - colormap_.col ( 5) = Color (190, 33, 3); - colormap_.col ( 6) = Color (192, 38, 4); - colormap_.col ( 7) = Color (194, 42, 5); - colormap_.col ( 8) = Color (196, 46, 6); - colormap_.col ( 9) = Color (197, 49, 7); - colormap_.col ( 10) = Color (199, 53, 9); - colormap_.col ( 11) = Color (201, 56, 10); - colormap_.col ( 12) = Color (203, 59, 12); - colormap_.col ( 13) = Color (205, 63, 13); - colormap_.col ( 14) = Color (207, 66, 15); - colormap_.col ( 15) = Color (208, 69, 17); - colormap_.col ( 16) = Color (210, 72, 18); - colormap_.col ( 17) = Color (212, 75, 20); - colormap_.col ( 18) = Color (214, 78, 21); - colormap_.col ( 19) = Color (215, 81, 23); - colormap_.col ( 20) = Color (217, 84, 25); - colormap_.col ( 21) = Color (219, 87, 26); - colormap_.col ( 22) = Color (221, 89, 28); - colormap_.col ( 23) = Color (222, 92, 30); - colormap_.col ( 24) = Color (224, 95, 32); - colormap_.col ( 25) = Color (225, 98, 33); - colormap_.col ( 26) = Color (227, 101, 35); - colormap_.col ( 27) = Color (229, 103, 37); - colormap_.col ( 28) = Color (230, 106, 39); - colormap_.col ( 29) = Color (232, 109, 40); - colormap_.col ( 30) = Color (233, 112, 42); - colormap_.col ( 31) = Color (235, 114, 44); - colormap_.col ( 32) = Color (236, 117, 46); - colormap_.col ( 33) = Color (238, 120, 48); - colormap_.col ( 34) = Color (239, 122, 50); - colormap_.col ( 35) = Color (241, 125, 52); - colormap_.col ( 36) = Color (242, 127, 54); - colormap_.col ( 37) = Color (244, 130, 56); - colormap_.col ( 38) = Color (245, 133, 58); - colormap_.col ( 39) = Color (246, 135, 60); - colormap_.col ( 40) = Color (248, 138, 62); - colormap_.col ( 41) = Color (249, 140, 64); - colormap_.col ( 42) = Color (250, 143, 66); - colormap_.col ( 43) = Color (252, 145, 68); - colormap_.col ( 44) = Color (253, 148, 70); - colormap_.col ( 45) = Color (254, 150, 73); - colormap_.col ( 46) = Color (255, 153, 75); - colormap_.col ( 47) = Color (255, 154, 76); - colormap_.col ( 48) = Color (255, 156, 78); - colormap_.col ( 49) = Color (255, 158, 80); - colormap_.col ( 50) = Color (255, 159, 82); - colormap_.col ( 51) = Color (255, 161, 84); - colormap_.col ( 52) = Color (255, 163, 86); - colormap_.col ( 53) = Color (255, 164, 88); - colormap_.col ( 54) = Color (255, 166, 90); - colormap_.col ( 55) = Color (255, 168, 92); - colormap_.col ( 56) = Color (255, 169, 93); - colormap_.col ( 57) = Color (255, 171, 95); - colormap_.col ( 58) = Color (255, 172, 97); - colormap_.col ( 59) = Color (255, 174, 99); - colormap_.col ( 60) = Color (255, 176, 101); - colormap_.col ( 61) = Color (255, 177, 103); - colormap_.col ( 62) = Color (255, 179, 105); - colormap_.col ( 63) = Color (255, 180, 107); - colormap_.col ( 64) = Color (255, 182, 109); - colormap_.col ( 65) = Color (255, 183, 111); - colormap_.col ( 66) = Color (255, 185, 113); - colormap_.col ( 67) = Color (255, 186, 115); - colormap_.col ( 68) = Color (255, 188, 117); - colormap_.col ( 69) = Color (255, 189, 119); - colormap_.col ( 70) = Color (255, 191, 122); - colormap_.col ( 71) = Color (255, 192, 124); - colormap_.col ( 72) = Color (255, 194, 126); - colormap_.col ( 73) = Color (255, 195, 128); - colormap_.col ( 74) = Color (255, 196, 130); - colormap_.col ( 75) = Color (255, 198, 132); - colormap_.col ( 76) = Color (255, 199, 134); - colormap_.col ( 77) = Color (255, 201, 136); - colormap_.col ( 78) = Color (255, 202, 139); - colormap_.col ( 79) = Color (255, 203, 141); - colormap_.col ( 80) = Color (255, 205, 143); - colormap_.col ( 81) = Color (255, 206, 145); - colormap_.col ( 82) = Color (255, 207, 147); - colormap_.col ( 83) = Color (255, 209, 149); - colormap_.col ( 84) = Color (255, 210, 152); - colormap_.col ( 85) = Color (255, 211, 154); - colormap_.col ( 86) = Color (255, 213, 156); - colormap_.col ( 87) = Color (255, 214, 158); - colormap_.col ( 88) = Color (255, 215, 161); - colormap_.col ( 89) = Color (255, 216, 163); - colormap_.col ( 90) = Color (255, 218, 165); - colormap_.col ( 91) = Color (255, 219, 168); - colormap_.col ( 92) = Color (255, 220, 170); - colormap_.col ( 93) = Color (255, 221, 172); - colormap_.col ( 94) = Color (255, 223, 175); - colormap_.col ( 95) = Color (255, 224, 177); - colormap_.col ( 96) = Color (255, 225, 179); - colormap_.col ( 97) = Color (255, 226, 182); - colormap_.col ( 98) = Color (255, 227, 184); - colormap_.col ( 99) = Color (255, 228, 186); - colormap_.col (100) = Color (255, 230, 189); - colormap_.col (101) = Color (255, 231, 191); - colormap_.col (102) = Color (255, 232, 193); - colormap_.col (103) = Color (255, 233, 196); - colormap_.col (104) = Color (255, 234, 198); - colormap_.col (105) = Color (255, 235, 201); - colormap_.col (106) = Color (255, 236, 203); - colormap_.col (107) = Color (255, 237, 205); - colormap_.col (108) = Color (255, 238, 208); - colormap_.col (109) = Color (255, 239, 210); - colormap_.col (110) = Color (255, 240, 213); - colormap_.col (111) = Color (255, 241, 215); - colormap_.col (112) = Color (255, 242, 218); - colormap_.col (113) = Color (255, 243, 220); - colormap_.col (114) = Color (255, 244, 222); - colormap_.col (115) = Color (255, 245, 225); - colormap_.col (116) = Color (255, 246, 227); - colormap_.col (117) = Color (255, 247, 230); - colormap_.col (118) = Color (255, 248, 232); - colormap_.col (119) = Color (255, 249, 235); - colormap_.col (120) = Color (255, 249, 237); - colormap_.col (121) = Color (255, 250, 239); - colormap_.col (122) = Color (255, 251, 242); - colormap_.col (123) = Color (255, 252, 244); - colormap_.col (124) = Color (255, 253, 247); - colormap_.col (125) = Color (255, 253, 249); - colormap_.col (126) = Color (255, 254, 251); - colormap_.col (127) = Color (255, 255, 254); - colormap_.col (128) = Color (255, 255, 254); - colormap_.col (129) = Color (254, 255, 253); - colormap_.col (130) = Color (253, 255, 252); - colormap_.col (131) = Color (252, 255, 250); - colormap_.col (132) = Color (251, 255, 249); - colormap_.col (133) = Color (250, 255, 248); - colormap_.col (134) = Color (249, 255, 246); - colormap_.col (135) = Color (248, 255, 245); - colormap_.col (136) = Color (247, 255, 244); - colormap_.col (137) = Color (246, 255, 242); - colormap_.col (138) = Color (245, 255, 241); - colormap_.col (139) = Color (244, 255, 240); - colormap_.col (140) = Color (243, 255, 238); - colormap_.col (141) = Color (242, 255, 237); - colormap_.col (142) = Color (241, 255, 236); - colormap_.col (143) = Color (240, 255, 235); - colormap_.col (144) = Color (239, 255, 233); - colormap_.col (145) = Color (238, 255, 232); - colormap_.col (146) = Color (237, 255, 231); - colormap_.col (147) = Color (236, 255, 229); - colormap_.col (148) = Color (235, 255, 228); - colormap_.col (149) = Color (234, 255, 227); - colormap_.col (150) = Color (234, 255, 225); - colormap_.col (151) = Color (233, 255, 224); - colormap_.col (152) = Color (232, 255, 223); - colormap_.col (153) = Color (231, 255, 221); - colormap_.col (154) = Color (230, 255, 220); - colormap_.col (155) = Color (229, 255, 219); - colormap_.col (156) = Color (228, 255, 218); - colormap_.col (157) = Color (227, 255, 216); - colormap_.col (158) = Color (226, 255, 215); - colormap_.col (159) = Color (225, 255, 214); - colormap_.col (160) = Color (224, 255, 212); - colormap_.col (161) = Color (223, 255, 211); - colormap_.col (162) = Color (222, 255, 210); - colormap_.col (163) = Color (221, 255, 208); - colormap_.col (164) = Color (220, 255, 207); - colormap_.col (165) = Color (219, 255, 206); - colormap_.col (166) = Color (218, 255, 204); - colormap_.col (167) = Color (217, 255, 203); - colormap_.col (168) = Color (216, 255, 202); - colormap_.col (169) = Color (215, 255, 201); - colormap_.col (170) = Color (214, 255, 199); - colormap_.col (171) = Color (213, 255, 198); - colormap_.col (172) = Color (211, 255, 197); - colormap_.col (173) = Color (210, 255, 195); - colormap_.col (174) = Color (209, 255, 194); - colormap_.col (175) = Color (208, 255, 193); - colormap_.col (176) = Color (207, 255, 191); - colormap_.col (177) = Color (206, 255, 190); - colormap_.col (178) = Color (205, 255, 188); - colormap_.col (179) = Color (204, 255, 187); - colormap_.col (180) = Color (203, 255, 186); - colormap_.col (181) = Color (202, 255, 184); - colormap_.col (182) = Color (201, 255, 183); - colormap_.col (183) = Color (199, 255, 182); - colormap_.col (184) = Color (198, 255, 180); - colormap_.col (185) = Color (197, 255, 179); - colormap_.col (186) = Color (196, 255, 177); - colormap_.col (187) = Color (195, 255, 176); - colormap_.col (188) = Color (194, 255, 174); - colormap_.col (189) = Color (192, 255, 173); - colormap_.col (190) = Color (191, 255, 172); - colormap_.col (191) = Color (190, 255, 170); - colormap_.col (192) = Color (189, 255, 169); - colormap_.col (193) = Color (188, 255, 167); - colormap_.col (194) = Color (186, 255, 166); - colormap_.col (195) = Color (185, 255, 164); - colormap_.col (196) = Color (184, 255, 163); - colormap_.col (197) = Color (183, 255, 161); - colormap_.col (198) = Color (181, 255, 160); - colormap_.col (199) = Color (180, 255, 158); - colormap_.col (200) = Color (179, 255, 157); - colormap_.col (201) = Color (177, 255, 155); - colormap_.col (202) = Color (176, 255, 154); - colormap_.col (203) = Color (175, 255, 152); - colormap_.col (204) = Color (173, 255, 150); - colormap_.col (205) = Color (172, 255, 149); - colormap_.col (206) = Color (170, 255, 147); - colormap_.col (207) = Color (169, 255, 145); - colormap_.col (208) = Color (166, 253, 143); - colormap_.col (209) = Color (164, 252, 141); - colormap_.col (210) = Color (162, 251, 138); - colormap_.col (211) = Color (159, 250, 136); - colormap_.col (212) = Color (157, 248, 134); - colormap_.col (213) = Color (155, 247, 131); - colormap_.col (214) = Color (152, 246, 129); - colormap_.col (215) = Color (150, 245, 127); - colormap_.col (216) = Color (148, 243, 124); - colormap_.col (217) = Color (145, 242, 122); - colormap_.col (218) = Color (143, 240, 119); - colormap_.col (219) = Color (140, 239, 117); - colormap_.col (220) = Color (138, 238, 114); - colormap_.col (221) = Color (135, 236, 112); - colormap_.col (222) = Color (133, 235, 110); - colormap_.col (223) = Color (130, 233, 107); - colormap_.col (224) = Color (128, 232, 105); - colormap_.col (225) = Color (125, 230, 102); - colormap_.col (226) = Color (122, 229, 100); - colormap_.col (227) = Color (120, 227, 97); - colormap_.col (228) = Color (117, 226, 94); - colormap_.col (229) = Color (114, 224, 92); - colormap_.col (230) = Color (111, 223, 89); - colormap_.col (231) = Color (109, 221, 87); - colormap_.col (232) = Color (106, 220, 84); - colormap_.col (233) = Color (103, 218, 82); - colormap_.col (234) = Color (100, 217, 79); - colormap_.col (235) = Color ( 97, 215, 76); - colormap_.col (236) = Color ( 94, 213, 73); - colormap_.col (237) = Color ( 91, 212, 71); - colormap_.col (238) = Color ( 88, 210, 68); - colormap_.col (239) = Color ( 85, 208, 65); - colormap_.col (240) = Color ( 82, 207, 62); - colormap_.col (241) = Color ( 78, 205, 59); - colormap_.col (242) = Color ( 75, 203, 57); - colormap_.col (243) = Color ( 71, 201, 54); - colormap_.col (244) = Color ( 68, 200, 50); - colormap_.col (245) = Color ( 64, 198, 47); - colormap_.col (246) = Color ( 60, 196, 44); - colormap_.col (247) = Color ( 56, 195, 41); - colormap_.col (248) = Color ( 52, 193, 37); - colormap_.col (249) = Color ( 47, 191, 33); - colormap_.col (250) = Color ( 42, 189, 29); - colormap_.col (251) = Color ( 37, 187, 25); - colormap_.col (252) = Color ( 31, 186, 20); - colormap_.col (253) = Color ( 24, 184, 15); - colormap_.col (254) = Color ( 14, 182, 7); - colormap_.col (255) = Color ( 0, 180, 0); + // int + // main() + // { + // static const unsigned int n = 256; + // // double rgb_1 [] = { 59./255., 76./255., 192./255.}; + // // double rgb_2 [] = {180./255., 4./255., 38./255.}; + // double rgb_1 [] = {180./255., 0./255., 0./255.}; + // double rgb_2 [] = { 0./255., 180./255., 0./255.}; + // + // vtkSmartPointer ctf = vtkColorTransferFunction::New(); + // ctf->SetColorSpaceToDiverging(); + // ctf->AddRGBPoint(0., rgb_1 [0], rgb_1 [1], rgb_1 [2]); + // ctf->AddRGBPoint(1., rgb_2 [0], rgb_2 [1], rgb_2 [2]); + // ctf->Build(); + // + // const unsigned char* colormap = ctf->GetTable (0., 1., n); + // + // for (unsigned int i=0; i (colormap [3 * i ]); + // const unsigned int g = static_cast (colormap [3 * i + 1]); + // const unsigned int b = static_cast (colormap [3 * i + 2]); + // + // std::cerr << "colormap_.col (" + // << std::setw (3) << i << ") = Color (" + // << std::setw (3) << r << ", " + // << std::setw (3) << g << ", " + // << std::setw (3) << b << ");\n"; + // } + // + // return (EXIT_SUCCESS); + // } + + colormap_.col(0) = Color(180, 0, 0); + colormap_.col(1) = Color(182, 9, 1); + colormap_.col(2) = Color(184, 17, 1); + colormap_.col(3) = Color(186, 24, 2); + colormap_.col(4) = Color(188, 29, 2); + colormap_.col(5) = Color(190, 33, 3); + colormap_.col(6) = Color(192, 38, 4); + colormap_.col(7) = Color(194, 42, 5); + colormap_.col(8) = Color(196, 46, 6); + colormap_.col(9) = Color(197, 49, 7); + colormap_.col(10) = Color(199, 53, 9); + colormap_.col(11) = Color(201, 56, 10); + colormap_.col(12) = Color(203, 59, 12); + colormap_.col(13) = Color(205, 63, 13); + colormap_.col(14) = Color(207, 66, 15); + colormap_.col(15) = Color(208, 69, 17); + colormap_.col(16) = Color(210, 72, 18); + colormap_.col(17) = Color(212, 75, 20); + colormap_.col(18) = Color(214, 78, 21); + colormap_.col(19) = Color(215, 81, 23); + colormap_.col(20) = Color(217, 84, 25); + colormap_.col(21) = Color(219, 87, 26); + colormap_.col(22) = Color(221, 89, 28); + colormap_.col(23) = Color(222, 92, 30); + colormap_.col(24) = Color(224, 95, 32); + colormap_.col(25) = Color(225, 98, 33); + colormap_.col(26) = Color(227, 101, 35); + colormap_.col(27) = Color(229, 103, 37); + colormap_.col(28) = Color(230, 106, 39); + colormap_.col(29) = Color(232, 109, 40); + colormap_.col(30) = Color(233, 112, 42); + colormap_.col(31) = Color(235, 114, 44); + colormap_.col(32) = Color(236, 117, 46); + colormap_.col(33) = Color(238, 120, 48); + colormap_.col(34) = Color(239, 122, 50); + colormap_.col(35) = Color(241, 125, 52); + colormap_.col(36) = Color(242, 127, 54); + colormap_.col(37) = Color(244, 130, 56); + colormap_.col(38) = Color(245, 133, 58); + colormap_.col(39) = Color(246, 135, 60); + colormap_.col(40) = Color(248, 138, 62); + colormap_.col(41) = Color(249, 140, 64); + colormap_.col(42) = Color(250, 143, 66); + colormap_.col(43) = Color(252, 145, 68); + colormap_.col(44) = Color(253, 148, 70); + colormap_.col(45) = Color(254, 150, 73); + colormap_.col(46) = Color(255, 153, 75); + colormap_.col(47) = Color(255, 154, 76); + colormap_.col(48) = Color(255, 156, 78); + colormap_.col(49) = Color(255, 158, 80); + colormap_.col(50) = Color(255, 159, 82); + colormap_.col(51) = Color(255, 161, 84); + colormap_.col(52) = Color(255, 163, 86); + colormap_.col(53) = Color(255, 164, 88); + colormap_.col(54) = Color(255, 166, 90); + colormap_.col(55) = Color(255, 168, 92); + colormap_.col(56) = Color(255, 169, 93); + colormap_.col(57) = Color(255, 171, 95); + colormap_.col(58) = Color(255, 172, 97); + colormap_.col(59) = Color(255, 174, 99); + colormap_.col(60) = Color(255, 176, 101); + colormap_.col(61) = Color(255, 177, 103); + colormap_.col(62) = Color(255, 179, 105); + colormap_.col(63) = Color(255, 180, 107); + colormap_.col(64) = Color(255, 182, 109); + colormap_.col(65) = Color(255, 183, 111); + colormap_.col(66) = Color(255, 185, 113); + colormap_.col(67) = Color(255, 186, 115); + colormap_.col(68) = Color(255, 188, 117); + colormap_.col(69) = Color(255, 189, 119); + colormap_.col(70) = Color(255, 191, 122); + colormap_.col(71) = Color(255, 192, 124); + colormap_.col(72) = Color(255, 194, 126); + colormap_.col(73) = Color(255, 195, 128); + colormap_.col(74) = Color(255, 196, 130); + colormap_.col(75) = Color(255, 198, 132); + colormap_.col(76) = Color(255, 199, 134); + colormap_.col(77) = Color(255, 201, 136); + colormap_.col(78) = Color(255, 202, 139); + colormap_.col(79) = Color(255, 203, 141); + colormap_.col(80) = Color(255, 205, 143); + colormap_.col(81) = Color(255, 206, 145); + colormap_.col(82) = Color(255, 207, 147); + colormap_.col(83) = Color(255, 209, 149); + colormap_.col(84) = Color(255, 210, 152); + colormap_.col(85) = Color(255, 211, 154); + colormap_.col(86) = Color(255, 213, 156); + colormap_.col(87) = Color(255, 214, 158); + colormap_.col(88) = Color(255, 215, 161); + colormap_.col(89) = Color(255, 216, 163); + colormap_.col(90) = Color(255, 218, 165); + colormap_.col(91) = Color(255, 219, 168); + colormap_.col(92) = Color(255, 220, 170); + colormap_.col(93) = Color(255, 221, 172); + colormap_.col(94) = Color(255, 223, 175); + colormap_.col(95) = Color(255, 224, 177); + colormap_.col(96) = Color(255, 225, 179); + colormap_.col(97) = Color(255, 226, 182); + colormap_.col(98) = Color(255, 227, 184); + colormap_.col(99) = Color(255, 228, 186); + colormap_.col(100) = Color(255, 230, 189); + colormap_.col(101) = Color(255, 231, 191); + colormap_.col(102) = Color(255, 232, 193); + colormap_.col(103) = Color(255, 233, 196); + colormap_.col(104) = Color(255, 234, 198); + colormap_.col(105) = Color(255, 235, 201); + colormap_.col(106) = Color(255, 236, 203); + colormap_.col(107) = Color(255, 237, 205); + colormap_.col(108) = Color(255, 238, 208); + colormap_.col(109) = Color(255, 239, 210); + colormap_.col(110) = Color(255, 240, 213); + colormap_.col(111) = Color(255, 241, 215); + colormap_.col(112) = Color(255, 242, 218); + colormap_.col(113) = Color(255, 243, 220); + colormap_.col(114) = Color(255, 244, 222); + colormap_.col(115) = Color(255, 245, 225); + colormap_.col(116) = Color(255, 246, 227); + colormap_.col(117) = Color(255, 247, 230); + colormap_.col(118) = Color(255, 248, 232); + colormap_.col(119) = Color(255, 249, 235); + colormap_.col(120) = Color(255, 249, 237); + colormap_.col(121) = Color(255, 250, 239); + colormap_.col(122) = Color(255, 251, 242); + colormap_.col(123) = Color(255, 252, 244); + colormap_.col(124) = Color(255, 253, 247); + colormap_.col(125) = Color(255, 253, 249); + colormap_.col(126) = Color(255, 254, 251); + colormap_.col(127) = Color(255, 255, 254); + colormap_.col(128) = Color(255, 255, 254); + colormap_.col(129) = Color(254, 255, 253); + colormap_.col(130) = Color(253, 255, 252); + colormap_.col(131) = Color(252, 255, 250); + colormap_.col(132) = Color(251, 255, 249); + colormap_.col(133) = Color(250, 255, 248); + colormap_.col(134) = Color(249, 255, 246); + colormap_.col(135) = Color(248, 255, 245); + colormap_.col(136) = Color(247, 255, 244); + colormap_.col(137) = Color(246, 255, 242); + colormap_.col(138) = Color(245, 255, 241); + colormap_.col(139) = Color(244, 255, 240); + colormap_.col(140) = Color(243, 255, 238); + colormap_.col(141) = Color(242, 255, 237); + colormap_.col(142) = Color(241, 255, 236); + colormap_.col(143) = Color(240, 255, 235); + colormap_.col(144) = Color(239, 255, 233); + colormap_.col(145) = Color(238, 255, 232); + colormap_.col(146) = Color(237, 255, 231); + colormap_.col(147) = Color(236, 255, 229); + colormap_.col(148) = Color(235, 255, 228); + colormap_.col(149) = Color(234, 255, 227); + colormap_.col(150) = Color(234, 255, 225); + colormap_.col(151) = Color(233, 255, 224); + colormap_.col(152) = Color(232, 255, 223); + colormap_.col(153) = Color(231, 255, 221); + colormap_.col(154) = Color(230, 255, 220); + colormap_.col(155) = Color(229, 255, 219); + colormap_.col(156) = Color(228, 255, 218); + colormap_.col(157) = Color(227, 255, 216); + colormap_.col(158) = Color(226, 255, 215); + colormap_.col(159) = Color(225, 255, 214); + colormap_.col(160) = Color(224, 255, 212); + colormap_.col(161) = Color(223, 255, 211); + colormap_.col(162) = Color(222, 255, 210); + colormap_.col(163) = Color(221, 255, 208); + colormap_.col(164) = Color(220, 255, 207); + colormap_.col(165) = Color(219, 255, 206); + colormap_.col(166) = Color(218, 255, 204); + colormap_.col(167) = Color(217, 255, 203); + colormap_.col(168) = Color(216, 255, 202); + colormap_.col(169) = Color(215, 255, 201); + colormap_.col(170) = Color(214, 255, 199); + colormap_.col(171) = Color(213, 255, 198); + colormap_.col(172) = Color(211, 255, 197); + colormap_.col(173) = Color(210, 255, 195); + colormap_.col(174) = Color(209, 255, 194); + colormap_.col(175) = Color(208, 255, 193); + colormap_.col(176) = Color(207, 255, 191); + colormap_.col(177) = Color(206, 255, 190); + colormap_.col(178) = Color(205, 255, 188); + colormap_.col(179) = Color(204, 255, 187); + colormap_.col(180) = Color(203, 255, 186); + colormap_.col(181) = Color(202, 255, 184); + colormap_.col(182) = Color(201, 255, 183); + colormap_.col(183) = Color(199, 255, 182); + colormap_.col(184) = Color(198, 255, 180); + colormap_.col(185) = Color(197, 255, 179); + colormap_.col(186) = Color(196, 255, 177); + colormap_.col(187) = Color(195, 255, 176); + colormap_.col(188) = Color(194, 255, 174); + colormap_.col(189) = Color(192, 255, 173); + colormap_.col(190) = Color(191, 255, 172); + colormap_.col(191) = Color(190, 255, 170); + colormap_.col(192) = Color(189, 255, 169); + colormap_.col(193) = Color(188, 255, 167); + colormap_.col(194) = Color(186, 255, 166); + colormap_.col(195) = Color(185, 255, 164); + colormap_.col(196) = Color(184, 255, 163); + colormap_.col(197) = Color(183, 255, 161); + colormap_.col(198) = Color(181, 255, 160); + colormap_.col(199) = Color(180, 255, 158); + colormap_.col(200) = Color(179, 255, 157); + colormap_.col(201) = Color(177, 255, 155); + colormap_.col(202) = Color(176, 255, 154); + colormap_.col(203) = Color(175, 255, 152); + colormap_.col(204) = Color(173, 255, 150); + colormap_.col(205) = Color(172, 255, 149); + colormap_.col(206) = Color(170, 255, 147); + colormap_.col(207) = Color(169, 255, 145); + colormap_.col(208) = Color(166, 253, 143); + colormap_.col(209) = Color(164, 252, 141); + colormap_.col(210) = Color(162, 251, 138); + colormap_.col(211) = Color(159, 250, 136); + colormap_.col(212) = Color(157, 248, 134); + colormap_.col(213) = Color(155, 247, 131); + colormap_.col(214) = Color(152, 246, 129); + colormap_.col(215) = Color(150, 245, 127); + colormap_.col(216) = Color(148, 243, 124); + colormap_.col(217) = Color(145, 242, 122); + colormap_.col(218) = Color(143, 240, 119); + colormap_.col(219) = Color(140, 239, 117); + colormap_.col(220) = Color(138, 238, 114); + colormap_.col(221) = Color(135, 236, 112); + colormap_.col(222) = Color(133, 235, 110); + colormap_.col(223) = Color(130, 233, 107); + colormap_.col(224) = Color(128, 232, 105); + colormap_.col(225) = Color(125, 230, 102); + colormap_.col(226) = Color(122, 229, 100); + colormap_.col(227) = Color(120, 227, 97); + colormap_.col(228) = Color(117, 226, 94); + colormap_.col(229) = Color(114, 224, 92); + colormap_.col(230) = Color(111, 223, 89); + colormap_.col(231) = Color(109, 221, 87); + colormap_.col(232) = Color(106, 220, 84); + colormap_.col(233) = Color(103, 218, 82); + colormap_.col(234) = Color(100, 217, 79); + colormap_.col(235) = Color(97, 215, 76); + colormap_.col(236) = Color(94, 213, 73); + colormap_.col(237) = Color(91, 212, 71); + colormap_.col(238) = Color(88, 210, 68); + colormap_.col(239) = Color(85, 208, 65); + colormap_.col(240) = Color(82, 207, 62); + colormap_.col(241) = Color(78, 205, 59); + colormap_.col(242) = Color(75, 203, 57); + colormap_.col(243) = Color(71, 201, 54); + colormap_.col(244) = Color(68, 200, 50); + colormap_.col(245) = Color(64, 198, 47); + colormap_.col(246) = Color(60, 196, 44); + colormap_.col(247) = Color(56, 195, 41); + colormap_.col(248) = Color(52, 193, 37); + colormap_.col(249) = Color(47, 191, 33); + colormap_.col(250) = Color(42, 189, 29); + colormap_.col(251) = Color(37, 187, 25); + colormap_.col(252) = Color(31, 186, 20); + colormap_.col(253) = Color(24, 184, 15); + colormap_.col(254) = Color(14, 182, 7); + colormap_.col(255) = Color(0, 180, 0); } //////////////////////////////////////////////////////////////////////////////// -pcl::ihs::OpenGLViewer::~OpenGLViewer () -{ - this->stopTimer (); -} +pcl::ihs::OpenGLViewer::~OpenGLViewer() { this->stopTimer(); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OpenGLViewer::addMesh (const MeshConstPtr& mesh, const std::string& id, const Eigen::Isometry3d& T) +pcl::ihs::OpenGLViewer::addMesh(const MeshConstPtr& mesh, + const std::string& id, + const Eigen::Isometry3d& T) { - if (!mesh) - { + if (!mesh) { std::cerr << "ERROR in opengl_viewer.cpp: Input mesh is not valid.\n"; return (false); } - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); - if (this->getMeshIsAdded (id)) - drawn_meshes_ [id] = FaceVertexMeshPtr (new FaceVertexMesh (*mesh, T)); + if (this->getMeshIsAdded(id)) + drawn_meshes_[id] = FaceVertexMeshPtr(new FaceVertexMesh(*mesh, T)); else - drawn_meshes_.insert (std::make_pair (id, FaceVertexMeshPtr (new FaceVertexMesh (*mesh, T)))); + drawn_meshes_.insert( + std::make_pair(id, FaceVertexMeshPtr(new FaceVertexMesh(*mesh, T)))); return (true); } @@ -466,15 +463,15 @@ pcl::ihs::OpenGLViewer::addMesh (const MeshConstPtr& mesh, const std::string& id //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OpenGLViewer::addMesh (const CloudXYZRGBNormalConstPtr& cloud, const std::string& id, const Eigen::Isometry3d& T) +pcl::ihs::OpenGLViewer::addMesh(const CloudXYZRGBNormalConstPtr& cloud, + const std::string& id, + const Eigen::Isometry3d& T) { - if (!cloud) - { + if (!cloud) { std::cerr << "ERROR in opengl_viewer.cpp: Input cloud is not valid.\n"; return (false); } - if (!cloud->isOrganized ()) - { + if (!cloud->isOrganized()) { std::cerr << "ERROR in opengl_viewer.cpp: Input cloud is not organized.\n"; return (false); } @@ -483,31 +480,31 @@ pcl::ihs::OpenGLViewer::addMesh (const CloudXYZRGBNormalConstPtr& cloud, const s // 2 - 1 // // | / | // // 3 - 0 // - const int w = cloud->width; - const int h = cloud->height; + const int w = cloud->width; + const int h = cloud->height; const int offset_1 = -w; const int offset_2 = -w - 1; - const int offset_3 = - 1; + const int offset_3 = -1; - FaceVertexMeshPtr mesh (new FaceVertexMesh ()); + FaceVertexMeshPtr mesh(new FaceVertexMesh()); mesh->transformation = T; - std::vector indices (w * h, -1); // Map the original indices to the vertex indices. + std::vector indices(w * h, + -1); // Map the original indices to the vertex indices. CloudIHS& vertices = mesh->vertices; - std::vector & triangles = mesh->triangles; - vertices.reserve (cloud->size ()); - triangles.reserve (2 * (w-1) * (h-1)); + std::vector& triangles = mesh->triangles; + vertices.reserve(cloud->size()); + triangles.reserve(2 * (w - 1) * (h - 1)); // Helper functor - struct AddVertex - { - inline int operator () (const PointXYZRGBNormal& pt, CloudIHS& vertices, int& ind_o) const + struct AddVertex { + inline int + operator()(const PointXYZRGBNormal& pt, CloudIHS& vertices, int& ind_o) const { - if (ind_o == -1) - { - ind_o = vertices.size (); - vertices.push_back (PointIHS (pt, -pt.normal_z)); - std::swap (vertices.back ().r, vertices.back ().b); + if (ind_o == -1) { + ind_o = vertices.size(); + vertices.push_back(PointIHS(pt, -pt.normal_z)); + std::swap(vertices.back().r, vertices.back().b); } return (ind_o); } @@ -517,44 +514,39 @@ pcl::ihs::OpenGLViewer::addMesh (const CloudXYZRGBNormalConstPtr& cloud, const s int ind_o_0, ind_o_1, ind_o_2, ind_o_3; // Index into the organized cloud. int ind_v_0, ind_v_1, ind_v_2, ind_v_3; // Index to the new vertices. - for (int r=1; roperator [] (ind_o_0); - const PointXYZRGBNormal& pt_1 = cloud->operator [] (ind_o_1); - const PointXYZRGBNormal& pt_2 = cloud->operator [] (ind_o_2); - const PointXYZRGBNormal& pt_3 = cloud->operator [] (ind_o_3); + const PointXYZRGBNormal& pt_0 = cloud->operator[](ind_o_0); + const PointXYZRGBNormal& pt_1 = cloud->operator[](ind_o_1); + const PointXYZRGBNormal& pt_2 = cloud->operator[](ind_o_2); + const PointXYZRGBNormal& pt_3 = cloud->operator[](ind_o_3); - if (!std::isnan (pt_1.x) && !std::isnan (pt_3.x)) - { - if (!std::isnan (pt_2.x)) // 1-2-3 is valid + if (!std::isnan(pt_1.x) && !std::isnan(pt_3.x)) { + if (!std::isnan(pt_2.x)) // 1-2-3 is valid { - if (std::abs (pt_1.z - pt_2.z) < 1 && - std::abs (pt_1.z - pt_3.z) < 1 && - std::abs (pt_2.z - pt_3.z) < 1) // distance threshold + if (std::abs(pt_1.z - pt_2.z) < 1 && std::abs(pt_1.z - pt_3.z) < 1 && + std::abs(pt_2.z - pt_3.z) < 1) // distance threshold { - ind_v_1 = addVertex (pt_1, vertices, indices [ind_o_1]); - ind_v_2 = addVertex (pt_2, vertices, indices [ind_o_2]); - ind_v_3 = addVertex (pt_3, vertices, indices [ind_o_3]); + ind_v_1 = addVertex(pt_1, vertices, indices[ind_o_1]); + ind_v_2 = addVertex(pt_2, vertices, indices[ind_o_2]); + ind_v_3 = addVertex(pt_3, vertices, indices[ind_o_3]); triangles.emplace_back(ind_v_1, ind_v_2, ind_v_3); } } - if (!std::isnan (pt_0.x)) // 0-1-3 is valid + if (!std::isnan(pt_0.x)) // 0-1-3 is valid { - if (std::abs (pt_0.z - pt_1.z) < 1 && - std::abs (pt_0.z - pt_3.z) < 1 && - std::abs (pt_1.z - pt_3.z) < 1) // distance threshold + if (std::abs(pt_0.z - pt_1.z) < 1 && std::abs(pt_0.z - pt_3.z) < 1 && + std::abs(pt_1.z - pt_3.z) < 1) // distance threshold { - ind_v_1 = addVertex (pt_1, vertices, indices [ind_o_1]); - ind_v_3 = addVertex (pt_3, vertices, indices [ind_o_3]); - ind_v_0 = addVertex (pt_0, vertices, indices [ind_o_0]); + ind_v_1 = addVertex(pt_1, vertices, indices[ind_o_1]); + ind_v_3 = addVertex(pt_3, vertices, indices[ind_o_3]); + ind_v_0 = addVertex(pt_0, vertices, indices[ind_o_0]); triangles.emplace_back(ind_v_1, ind_v_3, ind_v_0); } @@ -564,12 +556,12 @@ pcl::ihs::OpenGLViewer::addMesh (const CloudXYZRGBNormalConstPtr& cloud, const s } // Finally add the mesh. - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); - if (this->getMeshIsAdded (id)) - drawn_meshes_ [id] = mesh; + if (this->getMeshIsAdded(id)) + drawn_meshes_[id] = mesh; else - drawn_meshes_.insert (std::make_pair (id, mesh)); + drawn_meshes_.insert(std::make_pair(id, mesh)); return (true); } @@ -577,12 +569,13 @@ pcl::ihs::OpenGLViewer::addMesh (const CloudXYZRGBNormalConstPtr& cloud, const s //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OpenGLViewer::removeMesh (const std::string& id) +pcl::ihs::OpenGLViewer::removeMesh(const std::string& id) { - std::lock_guard lock (mutex_vis_); - if (!this->getMeshIsAdded (id)) return (false); + std::lock_guard lock(mutex_vis_); + if (!this->getMeshIsAdded(id)) + return (false); - drawn_meshes_.erase (id); + drawn_meshes_.erase(id); return (true); } @@ -590,34 +583,34 @@ pcl::ihs::OpenGLViewer::removeMesh (const std::string& id) //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::removeAllMeshes () +pcl::ihs::OpenGLViewer::removeAllMeshes() { - std::lock_guard lock (mutex_vis_); - drawn_meshes_.clear (); + std::lock_guard lock(mutex_vis_); + drawn_meshes_.clear(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setBoxCoefficients (const BoxCoefficients& coeffs) +pcl::ihs::OpenGLViewer::setBoxCoefficients(const BoxCoefficients& coeffs) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); box_coefficients_ = coeffs; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setDrawBox (const bool enabled) +pcl::ihs::OpenGLViewer::setDrawBox(const bool enabled) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); draw_box_ = enabled; } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OpenGLViewer::getDrawBox () const +pcl::ihs::OpenGLViewer::getDrawBox() const { return (draw_box_); } @@ -625,39 +618,38 @@ pcl::ihs::OpenGLViewer::getDrawBox () const //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setPivot (const Eigen::Vector3d& pivot) +pcl::ihs::OpenGLViewer::setPivot(const Eigen::Vector3d& pivot) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); cam_pivot_ = pivot; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setPivot (const std::string& id) +pcl::ihs::OpenGLViewer::setPivot(const std::string& id) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); cam_pivot_id_ = id; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::stopTimer () +pcl::ihs::OpenGLViewer::stopTimer() { - std::lock_guard lock (mutex_vis_); - if (timer_vis_) - { - timer_vis_->stop (); + std::lock_guard lock(mutex_vis_); + if (timer_vis_) { + timer_vis_->stop(); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setVisibilityConfidenceNormalization (const float vis_conf_norm) +pcl::ihs::OpenGLViewer::setVisibilityConfidenceNormalization(const float vis_conf_norm) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); vis_conf_norm_ = vis_conf_norm < 1 ? 1 : vis_conf_norm; } @@ -665,74 +657,88 @@ pcl::ihs::OpenGLViewer::setVisibilityConfidenceNormalization (const float vis_co //////////////////////////////////////////////////////////////////////////////// QSize -pcl::ihs::OpenGLViewer::minimumSizeHint () const +pcl::ihs::OpenGLViewer::minimumSizeHint() const { - return (QSize (160, 120)); + return (QSize(160, 120)); } //////////////////////////////////////////////////////////////////////////////// QSize -pcl::ihs::OpenGLViewer::sizeHint () const +pcl::ihs::OpenGLViewer::sizeHint() const { - return (QSize (640, 480)); + return (QSize(640, 480)); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setScalingFactor (const double scale) +pcl::ihs::OpenGLViewer::setScalingFactor(const double scale) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); scaling_factor_ = scale; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::timerCallback () +pcl::ihs::OpenGLViewer::timerCallback() { - QWidget::update (); + QWidget::update(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::resetCamera () +pcl::ihs::OpenGLViewer::resetCamera() { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); - R_cam_ = Eigen::Quaterniond (1., 0., 0., 0.); - t_cam_ = Eigen::Vector3d (0., 0., 0.); + R_cam_ = Eigen::Quaterniond(1., 0., 0., 0.); + t_cam_ = Eigen::Vector3d(0., 0., 0.); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::toggleMeshRepresentation () +pcl::ihs::OpenGLViewer::toggleMeshRepresentation() { - switch (mesh_representation_) - { - case MR_POINTS: this->setMeshRepresentation (MR_EDGES); break; - case MR_EDGES: this->setMeshRepresentation (MR_FACES); break; - case MR_FACES: this->setMeshRepresentation (MR_POINTS); break; - default: std::cerr << "ERROR in opengl_viewer.cpp: Unknown mesh representation\n"; exit (EXIT_FAILURE); + switch (mesh_representation_) { + case MR_POINTS: + this->setMeshRepresentation(MR_EDGES); + break; + case MR_EDGES: + this->setMeshRepresentation(MR_FACES); + break; + case MR_FACES: + this->setMeshRepresentation(MR_POINTS); + break; + default: + std::cerr << "ERROR in opengl_viewer.cpp: Unknown mesh representation\n"; + exit(EXIT_FAILURE); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setMeshRepresentation (const MeshRepresentation& representation) +pcl::ihs::OpenGLViewer::setMeshRepresentation(const MeshRepresentation& representation) { - std::lock_guard lock (mutex_vis_); - - switch (mesh_representation_) - { - case MR_POINTS: std::cerr << "Drawing the points.\n"; break; - case MR_EDGES: std::cerr << "Drawing the edges.\n"; break; - case MR_FACES: std::cerr << "Drawing the faces.\n"; break; - default: std::cerr << "ERROR in opengl_viewer.cpp: Unknown mesh representation\n"; exit (EXIT_FAILURE); + std::lock_guard lock(mutex_vis_); + + switch (mesh_representation_) { + case MR_POINTS: + std::cerr << "Drawing the points.\n"; + break; + case MR_EDGES: + std::cerr << "Drawing the edges.\n"; + break; + case MR_FACES: + std::cerr << "Drawing the faces.\n"; + break; + default: + std::cerr << "ERROR in opengl_viewer.cpp: Unknown mesh representation\n"; + exit(EXIT_FAILURE); } mesh_representation_ = representation; @@ -741,30 +747,44 @@ pcl::ihs::OpenGLViewer::setMeshRepresentation (const MeshRepresentation& represe //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::toggleColoring () +pcl::ihs::OpenGLViewer::toggleColoring() { - switch (coloring_) - { - case COL_RGB: this->setColoring (COL_ONE_COLOR); break; - case COL_ONE_COLOR: this->setColoring (COL_VISCONF); break; - case COL_VISCONF: this->setColoring (COL_RGB); break; - default: std::cerr << "ERROR in opengl_viewer.cpp: Unknown coloring\n"; exit (EXIT_FAILURE); + switch (coloring_) { + case COL_RGB: + this->setColoring(COL_ONE_COLOR); + break; + case COL_ONE_COLOR: + this->setColoring(COL_VISCONF); + break; + case COL_VISCONF: + this->setColoring(COL_RGB); + break; + default: + std::cerr << "ERROR in opengl_viewer.cpp: Unknown coloring\n"; + exit(EXIT_FAILURE); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setColoring (const Coloring& coloring) +pcl::ihs::OpenGLViewer::setColoring(const Coloring& coloring) { - std::lock_guard lock (mutex_vis_); - - switch (coloring) - { - case COL_RGB: std::cerr << "Coloring according to the rgb values.\n"; break; - case COL_ONE_COLOR: std::cerr << "Use one color for all points.\n"; break; - case COL_VISCONF: std::cerr << "Coloring according to the visibility confidence.\n"; break; - default: std::cerr << "ERROR in opengl_viewer.cpp: Unknown coloring\n"; exit (EXIT_FAILURE); + std::lock_guard lock(mutex_vis_); + + switch (coloring) { + case COL_RGB: + std::cerr << "Coloring according to the rgb values.\n"; + break; + case COL_ONE_COLOR: + std::cerr << "Use one color for all points.\n"; + break; + case COL_VISCONF: + std::cerr << "Coloring according to the visibility confidence.\n"; + break; + default: + std::cerr << "ERROR in opengl_viewer.cpp: Unknown coloring\n"; + exit(EXIT_FAILURE); } coloring_ = coloring; } @@ -772,16 +792,16 @@ pcl::ihs::OpenGLViewer::setColoring (const Coloring& coloring) //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::paintEvent (QPaintEvent* /*event*/) +pcl::ihs::OpenGLViewer::paintEvent(QPaintEvent* /*event*/) { - this->calcPivot (); - this->makeCurrent (); + this->calcPivot(); + this->makeCurrent(); // Clear information from the last draw - glClearColor (0.f, 0.f, 0.f, 0.f); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - this->setupViewport (this->width (), this->height ()); + this->setupViewport(this->width(), this->height()); // Move light with camera (see example 5-7) // http://www.glprogramming.com/red/chapter05.html @@ -789,258 +809,283 @@ pcl::ihs::OpenGLViewer::paintEvent (QPaintEvent* /*event*/) glLoadIdentity(); // light 0 (directional) - glLightfv (GL_LIGHT0, GL_AMBIENT , Eigen::Vector4f (0.1f, 0.1f, 0.1f, 1.0f).eval ().data ()); - glLightfv (GL_LIGHT0, GL_DIFFUSE , Eigen::Vector4f (0.6f, 0.6f, 0.6f, 1.0f).eval ().data () ); - glLightfv (GL_LIGHT0, GL_SPECULAR, Eigen::Vector4f (0.2f, 0.2f, 0.2f, 1.0f).eval ().data ()); - glLightfv (GL_LIGHT0, GL_POSITION, Eigen::Vector4f (0.3f, 0.5f, 0.8f, 0.0f).normalized ().eval ().data ()); + glLightfv( + GL_LIGHT0, GL_AMBIENT, Eigen::Vector4f(0.1f, 0.1f, 0.1f, 1.0f).eval().data()); + glLightfv( + GL_LIGHT0, GL_DIFFUSE, Eigen::Vector4f(0.6f, 0.6f, 0.6f, 1.0f).eval().data()); + glLightfv( + GL_LIGHT0, GL_SPECULAR, Eigen::Vector4f(0.2f, 0.2f, 0.2f, 1.0f).eval().data()); + glLightfv(GL_LIGHT0, + GL_POSITION, + Eigen::Vector4f(0.3f, 0.5f, 0.8f, 0.0f).normalized().eval().data()); // light 1 (directional) - glLightfv (GL_LIGHT1, GL_AMBIENT , Eigen::Vector4f ( 0.0f, 0.0f, 0.0f, 1.0f).eval ().data ()); - glLightfv (GL_LIGHT1, GL_DIFFUSE , Eigen::Vector4f ( 0.3f, 0.3f, 0.3f, 1.0f).eval ().data () ); - glLightfv (GL_LIGHT1, GL_SPECULAR, Eigen::Vector4f ( 0.1f, 0.1f, 0.1f, 1.0f).eval ().data ()); - glLightfv (GL_LIGHT1, GL_POSITION, Eigen::Vector4f (-0.3f, 0.5f, 0.8f, 0.0f).normalized ().eval ().data ()); + glLightfv( + GL_LIGHT1, GL_AMBIENT, Eigen::Vector4f(0.0f, 0.0f, 0.0f, 1.0f).eval().data()); + glLightfv( + GL_LIGHT1, GL_DIFFUSE, Eigen::Vector4f(0.3f, 0.3f, 0.3f, 1.0f).eval().data()); + glLightfv( + GL_LIGHT1, GL_SPECULAR, Eigen::Vector4f(0.1f, 0.1f, 0.1f, 1.0f).eval().data()); + glLightfv(GL_LIGHT1, + GL_POSITION, + Eigen::Vector4f(-0.3f, 0.5f, 0.8f, 0.0f).normalized().eval().data()); // Material - glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - glMaterialfv (GL_FRONT, GL_SPECULAR , Eigen::Vector4f (0.1f, 0.1f, 0.1f, 1.0f).eval ().data ()); - glMaterialf (GL_FRONT, GL_SHININESS, 25.f); - - glEnable (GL_DEPTH_TEST); - glEnable (GL_NORMALIZE); - glEnable (GL_COLOR_MATERIAL); - glEnable (GL_LIGHTING); - glEnable (GL_LIGHT0); - glEnable (GL_LIGHT1); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + glMaterialfv( + GL_FRONT, GL_SPECULAR, Eigen::Vector4f(0.1f, 0.1f, 0.1f, 1.0f).eval().data()); + glMaterialf(GL_FRONT, GL_SHININESS, 25.f); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); // Projection matrix - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - gluPerspective (43., 4./3., 0.01 / scaling_factor_, 10. / scaling_factor_); - glMatrixMode (GL_MODELVIEW); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(43., 4. / 3., 0.01 / scaling_factor_, 10. / scaling_factor_); + glMatrixMode(GL_MODELVIEW); // ModelView matrix Eigen::Quaterniond R_cam; - Eigen::Vector3d t_cam; + Eigen::Vector3d t_cam; { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); R_cam = R_cam_; t_cam = t_cam_; } - const Eigen::Vector3d o = Eigen::Vector3d::Zero (); - const Eigen::Vector3d ey = Eigen::Vector3d::UnitY (); - const Eigen::Vector3d ez = Eigen::Vector3d::UnitZ (); + const Eigen::Vector3d o = Eigen::Vector3d::Zero(); + const Eigen::Vector3d ey = Eigen::Vector3d::UnitY(); + const Eigen::Vector3d ez = Eigen::Vector3d::UnitZ(); - const Eigen::Vector3d eye = R_cam * o + t_cam; - const Eigen::Vector3d center = R_cam * ez + t_cam; - const Eigen::Vector3d up = (R_cam * -ey).normalized (); + const Eigen::Vector3d eye = R_cam * o + t_cam; + const Eigen::Vector3d center = R_cam * ez + t_cam; + const Eigen::Vector3d up = (R_cam * -ey).normalized(); - glMatrixMode (GL_MODELVIEW); - gluLookAt (eye. x (), eye. y (), eye. z (), - center.x (), center.y (), center.z (), - up. x (), up. y (), up. z ()); + glMatrixMode(GL_MODELVIEW); + gluLookAt(eye.x(), + eye.y(), + eye.z(), + center.x(), + center.y(), + center.z(), + up.x(), + up.y(), + up.z()); // Draw everything - this->drawMeshes (); + this->drawMeshes(); - glDisable (GL_LIGHTING); // This is needed so the color is right. - this->drawBox (); + glDisable(GL_LIGHTING); // This is needed so the color is right. + this->drawBox(); } //////////////////////////////////////////////////////////////////////////////// bool -pcl::ihs::OpenGLViewer::getMeshIsAdded (const std::string& id) +pcl::ihs::OpenGLViewer::getMeshIsAdded(const std::string& id) { // std::lock_guard lock (mutex_vis_); - return (drawn_meshes_.find (id) != drawn_meshes_.end ()); + return (drawn_meshes_.find(id) != drawn_meshes_.end()); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::calcPivot () +pcl::ihs::OpenGLViewer::calcPivot() { - std::unique_lock lock (mutex_vis_); - if (this->getMeshIsAdded (cam_pivot_id_)) - { + std::unique_lock lock(mutex_vis_); + if (this->getMeshIsAdded(cam_pivot_id_)) { Eigen::Vector4f pivot; - const FaceVertexMeshConstPtr mesh = drawn_meshes_ [cam_pivot_id_]; + const FaceVertexMeshConstPtr mesh = drawn_meshes_[cam_pivot_id_]; - if (pcl::compute3DCentroid (mesh->vertices, pivot)) - { - const Eigen::Vector3d p = mesh->transformation * pivot.head <3> ().cast (); - lock.unlock (); - this->setPivot (p); + if (pcl::compute3DCentroid(mesh->vertices, pivot)) { + const Eigen::Vector3d p = mesh->transformation * pivot.head<3>().cast(); + lock.unlock(); + this->setPivot(p); } } - cam_pivot_id_.clear (); + cam_pivot_id_.clear(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::drawMeshes () +pcl::ihs::OpenGLViewer::drawMeshes() { - std::lock_guard lock (mutex_vis_); - - glEnableClientState (GL_VERTEX_ARRAY); - glEnableClientState (GL_NORMAL_ARRAY); - switch (coloring_) - { - case COL_RGB: glEnableClientState (GL_COLOR_ARRAY); break; - case COL_ONE_COLOR: glDisableClientState (GL_COLOR_ARRAY); break; - case COL_VISCONF: glEnableClientState (GL_COLOR_ARRAY); break; - default: std::cerr << "ERROR in opengl_viewer.cpp: Unknown coloring\n"; exit (EXIT_FAILURE); + std::lock_guard lock(mutex_vis_); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + switch (coloring_) { + case COL_RGB: + glEnableClientState(GL_COLOR_ARRAY); + break; + case COL_ONE_COLOR: + glDisableClientState(GL_COLOR_ARRAY); + break; + case COL_VISCONF: + glEnableClientState(GL_COLOR_ARRAY); + break; + default: + std::cerr << "ERROR in opengl_viewer.cpp: Unknown coloring\n"; + exit(EXIT_FAILURE); } - switch (mesh_representation_) - { - case MR_POINTS: break; - case MR_EDGES: glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); break; - case MR_FACES: glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); break; - default: std::cerr << "ERROR in opengl_viewer.cpp: Unknown mesh representation\n"; exit (EXIT_FAILURE); + switch (mesh_representation_) { + case MR_POINTS: + break; + case MR_EDGES: + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + break; + case MR_FACES: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + break; + default: + std::cerr << "ERROR in opengl_viewer.cpp: Unknown mesh representation\n"; + exit(EXIT_FAILURE); } - for (FaceVertexMeshMap::const_iterator it=drawn_meshes_.begin (); it!=drawn_meshes_.end (); ++it) - { - if (it->second && !it->second->vertices.empty ()) - { + for (FaceVertexMeshMap::const_iterator it = drawn_meshes_.begin(); + it != drawn_meshes_.end(); + ++it) { + if (it->second && !it->second->vertices.empty()) { const FaceVertexMesh& mesh = *it->second; - glVertexPointer (3, GL_FLOAT, sizeof (PointIHS), &(mesh.vertices [0].x )); - glNormalPointer ( GL_FLOAT, sizeof (PointIHS), &(mesh.vertices [0].normal_x)); + glVertexPointer(3, GL_FLOAT, sizeof(PointIHS), &(mesh.vertices[0].x)); + glNormalPointer(GL_FLOAT, sizeof(PointIHS), &(mesh.vertices[0].normal_x)); - Colors colors (3, mesh.vertices.size ()); + Colors colors(3, mesh.vertices.size()); - switch (coloring_) - { - case COL_RGB: - { - glColorPointer (3, GL_UNSIGNED_BYTE, sizeof (PointIHS), &(mesh.vertices [0].b)); - break; - } - case COL_ONE_COLOR: - { - glColor3f (.7f, .7f, .7f); - break; + switch (coloring_) { + case COL_RGB: { + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(PointIHS), &(mesh.vertices[0].b)); + break; + } + case COL_ONE_COLOR: { + glColor3f(.7f, .7f, .7f); + break; + } + case COL_VISCONF: { + for (std::size_t i = 0; i < mesh.vertices.size(); ++i) { + const unsigned int n = pcl::ihs::countDirections(mesh.vertices[i].directions); + const unsigned int index = + static_cast(static_cast(colormap_.cols()) * + static_cast(n) / vis_conf_norm_); + + colors.col(i) = colormap_.col(index < 256 ? index : 255); } - case COL_VISCONF: - { - for (std::size_t i=0; i ( - static_cast (colormap_.cols ()) * - static_cast (n) / vis_conf_norm_); - - colors.col (i) = colormap_.col (index < 256 ? index : 255); - } - glColorPointer (3, GL_UNSIGNED_BYTE, 0, colors.data ()); - } + glColorPointer(3, GL_UNSIGNED_BYTE, 0, colors.data()); + } } - glPushMatrix (); + glPushMatrix(); { - glMultMatrixd (mesh.transformation.matrix ().data ()); + glMultMatrixd(mesh.transformation.matrix().data()); - switch (mesh_representation_) - { - case MR_POINTS: - { - glDrawArrays (GL_POINTS, 0, mesh.vertices.size ()); - break; - } - case MR_EDGES: case MR_FACES: - { - glDrawElements (GL_TRIANGLES, 3*mesh.triangles.size (), GL_UNSIGNED_INT, &mesh.triangles [0]); - break; - } + switch (mesh_representation_) { + case MR_POINTS: { + glDrawArrays(GL_POINTS, 0, mesh.vertices.size()); + break; + } + case MR_EDGES: + case MR_FACES: { + glDrawElements(GL_TRIANGLES, + 3 * mesh.triangles.size(), + GL_UNSIGNED_INT, + &mesh.triangles[0]); + break; + } } } - glPopMatrix (); + glPopMatrix(); } } - glDisableClientState (GL_VERTEX_ARRAY); - glDisableClientState (GL_NORMAL_ARRAY); - glDisableClientState (GL_COLOR_ARRAY); - glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::drawBox () +pcl::ihs::OpenGLViewer::drawBox() { BoxCoefficients coeffs; { - std::lock_guard lock (mutex_vis_); - if (draw_box_) coeffs = box_coefficients_; - else return; + std::lock_guard lock(mutex_vis_); + if (draw_box_) + coeffs = box_coefficients_; + else + return; } - glColor3f (1.f, 1.f, 1.f); + glColor3f(1.f, 1.f, 1.f); - glPushMatrix (); + glPushMatrix(); { - glMultMatrixd (coeffs.transformation.matrix ().data ()); + glMultMatrixd(coeffs.transformation.matrix().data()); // Front glBegin(GL_LINE_STRIP); { - glVertex3f (coeffs.x_min, coeffs.y_min, coeffs.z_min); - glVertex3f (coeffs.x_max, coeffs.y_min, coeffs.z_min); - glVertex3f (coeffs.x_max, coeffs.y_max, coeffs.z_min); - glVertex3f (coeffs.x_min, coeffs.y_max, coeffs.z_min); - glVertex3f (coeffs.x_min, coeffs.y_min, coeffs.z_min); + glVertex3f(coeffs.x_min, coeffs.y_min, coeffs.z_min); + glVertex3f(coeffs.x_max, coeffs.y_min, coeffs.z_min); + glVertex3f(coeffs.x_max, coeffs.y_max, coeffs.z_min); + glVertex3f(coeffs.x_min, coeffs.y_max, coeffs.z_min); + glVertex3f(coeffs.x_min, coeffs.y_min, coeffs.z_min); } glEnd(); // Back - glBegin (GL_LINE_STRIP); + glBegin(GL_LINE_STRIP); { - glVertex3f (coeffs.x_min, coeffs.y_min, coeffs.z_max); - glVertex3f (coeffs.x_max, coeffs.y_min, coeffs.z_max); - glVertex3f (coeffs.x_max, coeffs.y_max, coeffs.z_max); - glVertex3f (coeffs.x_min, coeffs.y_max, coeffs.z_max); - glVertex3f (coeffs.x_min, coeffs.y_min, coeffs.z_max); + glVertex3f(coeffs.x_min, coeffs.y_min, coeffs.z_max); + glVertex3f(coeffs.x_max, coeffs.y_min, coeffs.z_max); + glVertex3f(coeffs.x_max, coeffs.y_max, coeffs.z_max); + glVertex3f(coeffs.x_min, coeffs.y_max, coeffs.z_max); + glVertex3f(coeffs.x_min, coeffs.y_min, coeffs.z_max); } glEnd(); // Sides - glBegin (GL_LINES); + glBegin(GL_LINES); { - glVertex3f (coeffs.x_min, coeffs.y_min, coeffs.z_min); - glVertex3f (coeffs.x_min, coeffs.y_min, coeffs.z_max); + glVertex3f(coeffs.x_min, coeffs.y_min, coeffs.z_min); + glVertex3f(coeffs.x_min, coeffs.y_min, coeffs.z_max); - glVertex3f (coeffs.x_max, coeffs.y_min, coeffs.z_min); - glVertex3f (coeffs.x_max, coeffs.y_min, coeffs.z_max); + glVertex3f(coeffs.x_max, coeffs.y_min, coeffs.z_min); + glVertex3f(coeffs.x_max, coeffs.y_min, coeffs.z_max); - glVertex3f (coeffs.x_max, coeffs.y_max, coeffs.z_min); - glVertex3f (coeffs.x_max, coeffs.y_max, coeffs.z_max); + glVertex3f(coeffs.x_max, coeffs.y_max, coeffs.z_min); + glVertex3f(coeffs.x_max, coeffs.y_max, coeffs.z_max); - glVertex3f (coeffs.x_min, coeffs.y_max, coeffs.z_min); - glVertex3f (coeffs.x_min, coeffs.y_max, coeffs.z_max); + glVertex3f(coeffs.x_min, coeffs.y_max, coeffs.z_min); + glVertex3f(coeffs.x_min, coeffs.y_max, coeffs.z_max); } glEnd(); } - glPopMatrix (); + glPopMatrix(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::initializeGL () -{ -} +pcl::ihs::OpenGLViewer::initializeGL() +{} //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::setupViewport (const int w, const int h) +pcl::ihs::OpenGLViewer::setupViewport(const int w, const int h) { - const float aspect_ratio = 4./3.; + const float aspect_ratio = 4. / 3.; // Use the biggest possible area of the window to draw to // case 1 (w < w_scaled): case 2 (w >= w_scaled): @@ -1053,105 +1098,107 @@ pcl::ihs::OpenGLViewer::setupViewport (const int w, const int h) const float w_scaled = h * aspect_ratio; const float h_scaled = w / aspect_ratio; - if (w < w_scaled) - { - glViewport (0, static_cast ((h - h_scaled) / 2.f), w, static_cast (h_scaled)); + if (w < w_scaled) { + glViewport( + 0, static_cast((h - h_scaled) / 2.f), w, static_cast(h_scaled)); } - else - { - glViewport (static_cast ((w - w_scaled) / 2.f), 0, static_cast (w_scaled), h); + else { + glViewport( + static_cast((w - w_scaled) / 2.f), 0, static_cast(w_scaled), h); } } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::resizeGL (int w, int h) +pcl::ihs::OpenGLViewer::resizeGL(int w, int h) { - this->setupViewport (w, h); + this->setupViewport(w, h); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::mousePressEvent (QMouseEvent* /*event*/) +pcl::ihs::OpenGLViewer::mousePressEvent(QMouseEvent* /*event*/) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); mouse_pressed_begin_ = true; } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::mouseMoveEvent (QMouseEvent* event) +pcl::ihs::OpenGLViewer::mouseMoveEvent(QMouseEvent* event) { - std::lock_guard lock (mutex_vis_); + std::lock_guard lock(mutex_vis_); - if (mouse_pressed_begin_) - { - x_prev_ = event->pos ().x (); - y_prev_ = event->pos ().y (); + if (mouse_pressed_begin_) { + x_prev_ = event->pos().x(); + y_prev_ = event->pos().y(); mouse_pressed_begin_ = false; return; } - if (event->pos ().x () == x_prev_ && event->pos ().y () == y_prev_) return; - if (this->width () == 0 || this->height () == 0) return; + if (event->pos().x() == x_prev_ && event->pos().y() == y_prev_) + return; + if (this->width() == 0 || this->height() == 0) + return; - const double dx = static_cast (event->pos ().x ()) - static_cast (x_prev_); - const double dy = static_cast (event->pos ().y ()) - static_cast (y_prev_); - const double w = static_cast (this->width ()); - const double h = static_cast (this->height ()); - const double d = std::sqrt (w*w + h*h); + const double dx = + static_cast(event->pos().x()) - static_cast(x_prev_); + const double dy = + static_cast(event->pos().y()) - static_cast(y_prev_); + const double w = static_cast(this->width()); + const double h = static_cast(this->height()); + const double d = std::sqrt(w * w + h * h); - const Eigen::Vector3d o = Eigen::Vector3d::Zero (); - const Eigen::Vector3d ex = Eigen::Vector3d::UnitX (); - const Eigen::Vector3d ey = Eigen::Vector3d::UnitY (); - const Eigen::Vector3d ez = Eigen::Vector3d::UnitZ (); + const Eigen::Vector3d o = Eigen::Vector3d::Zero(); + const Eigen::Vector3d ex = Eigen::Vector3d::UnitX(); + const Eigen::Vector3d ey = Eigen::Vector3d::UnitY(); + const Eigen::Vector3d ez = Eigen::Vector3d::UnitZ(); // Scale with the distance between the pivot and camera eye. - const double scale = std::max ((cam_pivot_ - R_cam_ * o - t_cam_).norm (), .1 / scaling_factor_) / d; + const double scale = + std::max((cam_pivot_ - R_cam_ * o - t_cam_).norm(), .1 / scaling_factor_) / d; - if (QApplication::mouseButtons () == Qt::LeftButton) - { - const double rot_angle = -7. * std::atan (std::sqrt ((dx*dx + dy*dy)) / d); - const Eigen::Vector3d rot_axis = (R_cam_ * ex * dy - R_cam_ * ey * dx).normalized (); + if (QApplication::mouseButtons() == Qt::LeftButton) { + const double rot_angle = -7. * std::atan(std::sqrt((dx * dx + dy * dy)) / d); + const Eigen::Vector3d rot_axis = (R_cam_ * ex * dy - R_cam_ * ey * dx).normalized(); - const Eigen::Quaterniond dR (Eigen::AngleAxisd (rot_angle, rot_axis)); + const Eigen::Quaterniond dR(Eigen::AngleAxisd(rot_angle, rot_axis)); t_cam_ = dR * (t_cam_ - cam_pivot_) + cam_pivot_; - R_cam_ = (dR * R_cam_).normalized (); + R_cam_ = (dR * R_cam_).normalized(); } - else if (QApplication::mouseButtons () == Qt::MiddleButton) - { - t_cam_ += 1.3 * scale * Eigen::Vector3d (R_cam_ * (ey * -dy + ex * -dx)); + else if (QApplication::mouseButtons() == Qt::MiddleButton) { + t_cam_ += 1.3 * scale * Eigen::Vector3d(R_cam_ * (ey * -dy + ex * -dx)); } - else if (QApplication::mouseButtons () == Qt::RightButton) - { - t_cam_ += 2.6 * scale * Eigen::Vector3d (R_cam_ * (ez * -dy)); + else if (QApplication::mouseButtons() == Qt::RightButton) { + t_cam_ += 2.6 * scale * Eigen::Vector3d(R_cam_ * (ez * -dy)); } - x_prev_ = event->pos ().x (); - y_prev_ = event->pos ().y (); + x_prev_ = event->pos().x(); + y_prev_ = event->pos().y(); } //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::OpenGLViewer::wheelEvent (QWheelEvent* event) +pcl::ihs::OpenGLViewer::wheelEvent(QWheelEvent* event) { - if (QApplication::mouseButtons () == Qt::NoButton) - { - std::lock_guard lock (mutex_vis_); + if (QApplication::mouseButtons() == Qt::NoButton) { + std::lock_guard lock(mutex_vis_); // Scale with the distance between the pivot and camera eye. - const Eigen::Vector3d o = Eigen::Vector3d::Zero (); - const Eigen::Vector3d ez = Eigen::Vector3d::UnitZ (); - const double w = static_cast (this->width ()); - const double h = static_cast (this->height ()); - const double d = std::sqrt (w*w + h*h); - const double scale = std::max ((cam_pivot_ - R_cam_ * o - t_cam_).norm (), .1 / scaling_factor_) / d; + const Eigen::Vector3d o = Eigen::Vector3d::Zero(); + const Eigen::Vector3d ez = Eigen::Vector3d::UnitZ(); + const double w = static_cast(this->width()); + const double h = static_cast(this->height()); + const double d = std::sqrt(w * w + h * h); + const double scale = + std::max((cam_pivot_ - R_cam_ * o - t_cam_).norm(), .1 / scaling_factor_) / d; // http://doc.qt.digia.com/qt/qwheelevent.html#delta - t_cam_ += scale * Eigen::Vector3d (R_cam_ * (ez * static_cast (event->delta ()))); + t_cam_ += + scale * Eigen::Vector3d(R_cam_ * (ez * static_cast(event->delta()))); } } diff --git a/apps/in_hand_scanner/src/visibility_confidence.cpp b/apps/in_hand_scanner/src/visibility_confidence.cpp index d0bda321ff8..a067eff64bf 100644 --- a/apps/in_hand_scanner/src/visibility_confidence.cpp +++ b/apps/in_hand_scanner/src/visibility_confidence.cpp @@ -40,95 +40,94 @@ #include -pcl::ihs::Dome::Dome () +#include // for Isometry3f + +pcl::ihs::Dome::Dome() { - vertices_.col ( 0) = Eigen::Vector4f (-0.000000119f, 0.000000000f, 1.000000000f, 0.f); - vertices_.col ( 1) = Eigen::Vector4f ( 0.894427180f, 0.000000000f, 0.447213739f, 0.f); - vertices_.col ( 2) = Eigen::Vector4f ( 0.276393145f, 0.850650907f, 0.447213650f, 0.f); - vertices_.col ( 3) = Eigen::Vector4f (-0.723606884f, 0.525731146f, 0.447213531f, 0.f); - vertices_.col ( 4) = Eigen::Vector4f (-0.723606884f, -0.525731146f, 0.447213531f, 0.f); - vertices_.col ( 5) = Eigen::Vector4f ( 0.276393145f, -0.850650907f, 0.447213650f, 0.f); - vertices_.col ( 6) = Eigen::Vector4f ( 0.343278527f, 0.000000000f, 0.939233720f, 0.f); - vertices_.col ( 7) = Eigen::Vector4f ( 0.686557174f, 0.000000000f, 0.727075875f, 0.f); - vertices_.col ( 8) = Eigen::Vector4f ( 0.792636156f, 0.326477438f, 0.514918089f, 0.f); - vertices_.col ( 9) = Eigen::Vector4f ( 0.555436373f, 0.652954817f, 0.514918029f, 0.f); - vertices_.col (10) = Eigen::Vector4f ( 0.106078848f, 0.326477438f, 0.939233720f, 0.f); - vertices_.col (11) = Eigen::Vector4f ( 0.212157741f, 0.652954817f, 0.727075756f, 0.f); - vertices_.col (12) = Eigen::Vector4f (-0.065560505f, 0.854728878f, 0.514917910f, 0.f); - vertices_.col (13) = Eigen::Vector4f (-0.449357629f, 0.730025530f, 0.514917850f, 0.f); - vertices_.col (14) = Eigen::Vector4f (-0.277718395f, 0.201774135f, 0.939233661f, 0.f); - vertices_.col (15) = Eigen::Vector4f (-0.555436671f, 0.403548241f, 0.727075696f, 0.f); - vertices_.col (16) = Eigen::Vector4f (-0.833154857f, 0.201774105f, 0.514917850f, 0.f); - vertices_.col (17) = Eigen::Vector4f (-0.833154857f, -0.201774150f, 0.514917850f, 0.f); - vertices_.col (18) = Eigen::Vector4f (-0.277718395f, -0.201774135f, 0.939233661f, 0.f); - vertices_.col (19) = Eigen::Vector4f (-0.555436671f, -0.403548241f, 0.727075696f, 0.f); - vertices_.col (20) = Eigen::Vector4f (-0.449357659f, -0.730025649f, 0.514917910f, 0.f); - vertices_.col (21) = Eigen::Vector4f (-0.065560460f, -0.854728937f, 0.514917850f, 0.f); - vertices_.col (22) = Eigen::Vector4f ( 0.106078848f, -0.326477438f, 0.939233720f, 0.f); - vertices_.col (23) = Eigen::Vector4f ( 0.212157741f, -0.652954817f, 0.727075756f, 0.f); - vertices_.col (24) = Eigen::Vector4f ( 0.555436373f, -0.652954757f, 0.514917970f, 0.f); - vertices_.col (25) = Eigen::Vector4f ( 0.792636156f, -0.326477349f, 0.514918089f, 0.f); - vertices_.col (26) = Eigen::Vector4f ( 0.491123378f, 0.356822133f, 0.794654608f, 0.f); - vertices_.col (27) = Eigen::Vector4f (-0.187592626f, 0.577350259f, 0.794654429f, 0.f); - vertices_.col (28) = Eigen::Vector4f (-0.607062101f, -0.000000016f, 0.794654369f, 0.f); - vertices_.col (29) = Eigen::Vector4f (-0.187592626f, -0.577350378f, 0.794654489f, 0.f); - vertices_.col (30) = Eigen::Vector4f ( 0.491123348f, -0.356822133f, 0.794654548f, 0.f); - - for (Eigen::Index i=0; i < vertices_.cols (); ++i) - { - vertices_.col (i).head <3> ().normalize (); + vertices_.col(0) = Eigen::Vector4f(-0.000000119f, 0.000000000f, 1.000000000f, 0.f); + vertices_.col(1) = Eigen::Vector4f(0.894427180f, 0.000000000f, 0.447213739f, 0.f); + vertices_.col(2) = Eigen::Vector4f(0.276393145f, 0.850650907f, 0.447213650f, 0.f); + vertices_.col(3) = Eigen::Vector4f(-0.723606884f, 0.525731146f, 0.447213531f, 0.f); + vertices_.col(4) = Eigen::Vector4f(-0.723606884f, -0.525731146f, 0.447213531f, 0.f); + vertices_.col(5) = Eigen::Vector4f(0.276393145f, -0.850650907f, 0.447213650f, 0.f); + vertices_.col(6) = Eigen::Vector4f(0.343278527f, 0.000000000f, 0.939233720f, 0.f); + vertices_.col(7) = Eigen::Vector4f(0.686557174f, 0.000000000f, 0.727075875f, 0.f); + vertices_.col(8) = Eigen::Vector4f(0.792636156f, 0.326477438f, 0.514918089f, 0.f); + vertices_.col(9) = Eigen::Vector4f(0.555436373f, 0.652954817f, 0.514918029f, 0.f); + vertices_.col(10) = Eigen::Vector4f(0.106078848f, 0.326477438f, 0.939233720f, 0.f); + vertices_.col(11) = Eigen::Vector4f(0.212157741f, 0.652954817f, 0.727075756f, 0.f); + vertices_.col(12) = Eigen::Vector4f(-0.065560505f, 0.854728878f, 0.514917910f, 0.f); + vertices_.col(13) = Eigen::Vector4f(-0.449357629f, 0.730025530f, 0.514917850f, 0.f); + vertices_.col(14) = Eigen::Vector4f(-0.277718395f, 0.201774135f, 0.939233661f, 0.f); + vertices_.col(15) = Eigen::Vector4f(-0.555436671f, 0.403548241f, 0.727075696f, 0.f); + vertices_.col(16) = Eigen::Vector4f(-0.833154857f, 0.201774105f, 0.514917850f, 0.f); + vertices_.col(17) = Eigen::Vector4f(-0.833154857f, -0.201774150f, 0.514917850f, 0.f); + vertices_.col(18) = Eigen::Vector4f(-0.277718395f, -0.201774135f, 0.939233661f, 0.f); + vertices_.col(19) = Eigen::Vector4f(-0.555436671f, -0.403548241f, 0.727075696f, 0.f); + vertices_.col(20) = Eigen::Vector4f(-0.449357659f, -0.730025649f, 0.514917910f, 0.f); + vertices_.col(21) = Eigen::Vector4f(-0.065560460f, -0.854728937f, 0.514917850f, 0.f); + vertices_.col(22) = Eigen::Vector4f(0.106078848f, -0.326477438f, 0.939233720f, 0.f); + vertices_.col(23) = Eigen::Vector4f(0.212157741f, -0.652954817f, 0.727075756f, 0.f); + vertices_.col(24) = Eigen::Vector4f(0.555436373f, -0.652954757f, 0.514917970f, 0.f); + vertices_.col(25) = Eigen::Vector4f(0.792636156f, -0.326477349f, 0.514918089f, 0.f); + vertices_.col(26) = Eigen::Vector4f(0.491123378f, 0.356822133f, 0.794654608f, 0.f); + vertices_.col(27) = Eigen::Vector4f(-0.187592626f, 0.577350259f, 0.794654429f, 0.f); + vertices_.col(28) = Eigen::Vector4f(-0.607062101f, -0.000000016f, 0.794654369f, 0.f); + vertices_.col(29) = Eigen::Vector4f(-0.187592626f, -0.577350378f, 0.794654489f, 0.f); + vertices_.col(30) = Eigen::Vector4f(0.491123348f, -0.356822133f, 0.794654548f, 0.f); + + for (Eigen::Index i = 0; i < vertices_.cols(); ++i) { + vertices_.col(i).head<3>().normalize(); } } //////////////////////////////////////////////////////////////////////////////// pcl::ihs::Dome::Vertices -pcl::ihs::Dome::getVertices () const +pcl::ihs::Dome::getVertices() const { return (vertices_); } //////////////////////////////////////////////////////////////////////////////// -namespace pcl -{ - namespace ihs - { - static const pcl::ihs::Dome dome; - } // End namespace ihs +namespace pcl { +namespace ihs { +static const pcl::ihs::Dome dome; +} // End namespace ihs } // End namespace pcl //////////////////////////////////////////////////////////////////////////////// void -pcl::ihs::addDirection (const Eigen::Vector4f& normal, - const Eigen::Vector4f& direction, - std::uint32_t& directions) +pcl::ihs::addDirection(const Eigen::Vector4f& normal, + const Eigen::Vector4f& direction, + std::uint32_t& directions) { // Find the rotation that aligns the normal with [0; 0; 1] - const float dot = normal.z (); + const float dot = normal.z(); - Eigen::Isometry3f R = Eigen::Isometry3f::Identity (); + Eigen::Isometry3f R = Eigen::Isometry3f::Identity(); - // No need to transform if the normal is already very close to [0; 0; 1] (also avoids numerical issues) + // No need to transform if the normal is already very close to [0; 0; 1] (also avoids + // numerical issues) // TODO: The threshold is hard coded for a frequency=3. // It can be calculated with // - max_z = maximum z value of the dome vertices (excluding [0; 0; 1]) // - thresh = std::cos (std::acos (max_z) / 2) // - always round up! // - with max_z = 0.939 -> thresh = 0.9847 ~ 0.985 - if (dot <= .985f) - { - const Eigen::Vector3f axis = Eigen::Vector3f (normal.y (), -normal.x (), 0.f).normalized (); - R = Eigen::Isometry3f (Eigen::AngleAxisf (std::acos (dot), axis)); + if (dot <= .985f) { + const auto axis = Eigen::Vector3f(normal.y(), -normal.x(), 0.f).normalized(); + R = Eigen::Isometry3f(Eigen::AngleAxisf(std::acos(dot), axis)); } - // Transform the direction into the dome coordinate system (which is aligned with the normal) + // Transform the direction into the dome coordinate system (which is aligned with the + // normal) Eigen::Vector4f aligned_direction = (R * direction); - aligned_direction.head <3> ().normalize (); + aligned_direction.head<3>().normalize(); - if (aligned_direction.z () < 0) - { + if (aligned_direction.z() < 0) { return; } @@ -137,7 +136,9 @@ pcl::ihs::addDirection (const Eigen::Vector4f& normal, // std::acos (angle) = dot (a, b) / (norm (a) * norm (b) // m_sphere_vertices are already normalized unsigned int index = 0; - aligned_direction.transpose ().lazyProduct (pcl::ihs::dome.getVertices ()).maxCoeff (&index); + aligned_direction.transpose() + .lazyProduct(pcl::ihs::dome.getVertices()) + .maxCoeff(&index); // Set the observed direction bit at 'index' // http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c/47990#47990 @@ -147,7 +148,7 @@ pcl::ihs::addDirection (const Eigen::Vector4f& normal, //////////////////////////////////////////////////////////////////////////////// unsigned int -pcl::ihs::countDirections (const std::uint32_t directions) +pcl::ihs::countDirections(const std::uint32_t directions) { // http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer/109025#109025 unsigned int i = directions - ((directions >> 1) & 0x55555555); diff --git a/apps/include/pcl/apps/impl/dominant_plane_segmentation.hpp b/apps/include/pcl/apps/impl/dominant_plane_segmentation.hpp index 31229eafc9c..549f893bcff 100644 --- a/apps/include/pcl/apps/impl/dominant_plane_segmentation.hpp +++ b/apps/include/pcl/apps/impl/dominant_plane_segmentation.hpp @@ -34,7 +34,7 @@ */ #include // for ExtractIndices -#include // for pcl::make_shared +#include // for pcl::make_shared template void @@ -310,7 +310,7 @@ pcl::apps::DominantPlaneSegmentation::compute_fast( std::map connected_labels; float c_intensity = 0.1f; - float intensity_incr = 0.1f; + const float intensity_incr = 0.1f; { diff --git a/apps/include/pcl/apps/manual_registration.h b/apps/include/pcl/apps/manual_registration.h index e0858a84310..d9fffbdbc35 100644 --- a/apps/include/pcl/apps/manual_registration.h +++ b/apps/include/pcl/apps/manual_registration.h @@ -45,7 +45,6 @@ #include #include #include -#include using PointT = pcl::PointXYZRGBA; diff --git a/apps/include/pcl/apps/nn_classification.h b/apps/include/pcl/apps/nn_classification.h index fcca0ec6ef8..d1dc06dad69 100644 --- a/apps/include/pcl/apps/nn_classification.h +++ b/apps/include/pcl/apps/nn_classification.h @@ -42,6 +42,9 @@ #include #include +#include +#include // for std::map + namespace pcl { /** @@ -78,7 +81,7 @@ class NNClassification { { // Do not limit the number of dimensions used in the tree typename pcl::CustomPointRepresentation::Ptr cpr( - new pcl::CustomPointRepresentation(INT_MAX, 0)); + new pcl::CustomPointRepresentation(std::numeric_limits::max(), 0)); tree_.reset(new pcl::KdTreeFLANN); tree_->setPointRepresentation(cpr); tree_->setInputCloud(features); @@ -189,9 +192,12 @@ class NNClassification { * \return pair of label and score for each training class from the neighborhood */ ResultPtr - classify(const PointT& p_q, double radius, float gaussian_param, int max_nn = INT_MAX) + classify(const PointT& p_q, + double radius, + float gaussian_param, + int max_nn = std::numeric_limits::max()) { - std::vector k_indices; + pcl::Indices k_indices; std::vector k_sqr_distances; getSimilarExemplars(p_q, radius, k_indices, k_sqr_distances, max_nn); return getGaussianBestScores(gaussian_param, k_indices, k_sqr_distances); @@ -210,7 +216,7 @@ class NNClassification { int getKNearestExemplars(const PointT& p_q, int k, - std::vector& k_indices, + pcl::Indices& k_indices, std::vector& k_sqr_distances) { k_indices.resize(k); @@ -230,9 +236,9 @@ class NNClassification { int getSimilarExemplars(const PointT& p_q, double radius, - std::vector& k_indices, + pcl::Indices& k_indices, std::vector& k_sqr_distances, - int max_nn = INT_MAX) + int max_nn = std::numeric_limits::max()) { return tree_->radiusSearch(p_q, radius, k_indices, k_sqr_distances, max_nn); } @@ -244,17 +250,17 @@ class NNClassification { * \return a square distance to each training class */ std::shared_ptr> - getSmallestSquaredDistances(std::vector& k_indices, + getSmallestSquaredDistances(pcl::Indices& k_indices, std::vector& k_sqr_distances) { // Reserve space for distances - auto sqr_distances = std::make_shared>(classes_.size(), FLT_MAX); + auto sqr_distances = std::make_shared>( + classes_.size(), std::numeric_limits::max()); // Select square distance to each class - for (std::vector::const_iterator i = k_indices.begin(); i != k_indices.end(); - ++i) - if ((*sqr_distances)[labels_idx_[*i]] > k_sqr_distances[i - k_indices.begin()]) - (*sqr_distances)[labels_idx_[*i]] = k_sqr_distances[i - k_indices.begin()]; + for (auto i = k_indices.cbegin(); i != k_indices.cend(); ++i) + if ((*sqr_distances)[labels_idx_[*i]] > k_sqr_distances[i - k_indices.cbegin()]) + (*sqr_distances)[labels_idx_[*i]] = k_sqr_distances[i - k_indices.cbegin()]; return sqr_distances; } @@ -267,7 +273,7 @@ class NNClassification { * \return pair of label and score for each training class from the neighborhood */ ResultPtr - getLinearBestScores(std::vector& k_indices, std::vector& k_sqr_distances) + getLinearBestScores(pcl::Indices& k_indices, std::vector& k_sqr_distances) { // Get smallest squared distances and transform them to a score for each class auto sqr_distances = getSmallestSquaredDistances(k_indices, k_sqr_distances); @@ -281,7 +287,7 @@ class NNClassification { for (std::vector::const_iterator it = sqr_distances->begin(); it != sqr_distances->end(); ++it) - if (*it != FLT_MAX) { + if (*it != std::numeric_limits::max()) { result->first.push_back(classes_[it - sqr_distances->begin()]); result->second.push_back(sqrt(*it)); sum_dist += result->second.back(); @@ -305,7 +311,7 @@ class NNClassification { */ ResultPtr getGaussianBestScores(float gaussian_param, - std::vector& k_indices, + pcl::Indices& k_indices, std::vector& k_sqr_distances) { // Get smallest squared distances and transform them to a score for each class @@ -319,7 +325,7 @@ class NNClassification { for (std::vector::const_iterator it = sqr_distances->begin(); it != sqr_distances->end(); ++it) - if (*it != FLT_MAX) { + if (*it != std::numeric_limits::max()) { result->first.push_back(classes_[it - sqr_distances->begin()]); // TODO leave it squared, and relate param to sigma... result->second.push_back(std::exp(-std::sqrt(*it) / gaussian_param)); diff --git a/apps/include/pcl/apps/openni_passthrough.h b/apps/include/pcl/apps/openni_passthrough.h index cb315758303..941a49a7e7c 100644 --- a/apps/include/pcl/apps/openni_passthrough.h +++ b/apps/include/pcl/apps/openni_passthrough.h @@ -88,7 +88,7 @@ class OpenNIPassthrough : public QMainWindow { protected: void refreshView(); - + pcl::visualization::PCLVisualizer::Ptr vis_; pcl::OpenNIGrabber& grabber_; std::string device_id_; diff --git a/apps/modeler/CMakeLists.txt b/apps/modeler/CMakeLists.txt index c7dd1b6a173..aa61605218b 100644 --- a/apps/modeler/CMakeLists.txt +++ b/apps/modeler/CMakeLists.txt @@ -1,26 +1,9 @@ set(SUBSUBSYS_NAME modeler) set(SUBSUBSYS_DESC "PCLModeler: PCL based reconstruction platform") set(SUBSUBSYS_DEPS common geometry io filters sample_consensus segmentation visualization kdtree features surface octree registration keypoints tracking search apps) +set(SUBSUBSYS_EXT_DEPS vtk ${QTX}) set(REASON "") -# Find VTK -if(NOT VTK_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "VTK was not found.") -else() - set(DEFAULT TRUE) - set(REASON) -endif() - -# QT5 Found? -if(NOT Qt5_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "Qt5 was not found.") -elseif(NOT ${DEFAULT} STREQUAL "AUTO_OFF") - set(DEFAULT TRUE) - set(REASON) -endif() - # QVTK? if(NOT HAVE_QVTK) set(DEFAULT AUTO_OFF) @@ -36,7 +19,7 @@ if(${DEFAULT} STREQUAL "TRUE") endif() PCL_SUBSUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" "${SUBSUBSYS_DESC}" ${DEFAULT} "${REASON}") -PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" DEPS ${SUBSUBSYS_DEPS} EXT_DEPS vtk) +PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" DEPS ${SUBSUBSYS_DEPS} EXT_DEPS ${SUBSUBSYS_EXT_DEPS}) PCL_ADD_DOC("${SUBSUBSYS_NAME}") @@ -51,21 +34,17 @@ set(uis main_window.ui ) -set(moc_incs - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/main_window.h" - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/scene_tree.h" - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/parameter_dialog.h" - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/thread_controller.h" - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/abstract_worker.h" - "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/cloud_mesh_item_updater.h" -) - set(resources resources/resources.qrc ) set(incs - ${moc_incs} + "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/main_window.h" + "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/scene_tree.h" + "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/parameter_dialog.h" + "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/thread_controller.h" + "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/abstract_worker.h" + "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/cloud_mesh_item_updater.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/dock_widget.h" "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/abstract_item.h" @@ -124,29 +103,22 @@ set(impl_incs "include/pcl/${SUBSYS_NAME}/${SUBSUBSYS_NAME}/impl/scene_tree.hpp" ) -# Qt stuff -QT5_WRAP_UI(ui_srcs ${uis}) -QT5_WRAP_CPP(moc_srcs ${moc_incs} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) -QT5_ADD_RESOURCES(resource_srcs ${resources}) - -# Organize files -source_group("Resources" FILES ${uis} ${resources} ${EXE_ICON}) -source_group("Generated" FILES ${ui_srcs} ${moc_srcs} ${resource_srcs} ${RCS_SOURCES}) -set_source_files_properties(${srcs} PROPERTIES OBJECT_DEPENDS "${ui_srcs}") +list(APPEND CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}") # Generate executable set(EXE_NAME "pcl_${SUBSUBSYS_NAME}") -PCL_ADD_EXECUTABLE(${EXE_NAME} COMPONENT ${SUBSUBSYS_NAME} SOURCES ${ui_srcs} ${moc_srcs} ${resource_srcs} ${srcs} ${incs} ${impl_incs}) -target_link_libraries("${EXE_NAME}" pcl_common pcl_io pcl_kdtree pcl_filters pcl_visualization pcl_segmentation pcl_surface pcl_features pcl_sample_consensus pcl_search Qt5::Widgets) -#TODO: Update when CMAKE 3.10 is available -if(NOT (${VTK_VERSION} VERSION_LESS 9.0)) - target_link_libraries("${EXE_NAME}" VTK::GUISupportQt) -endif() - -# Put the ui in the windows project file -if(("${CMAKE_BUILD_TOOL}" MATCHES "msdev") OR("${CMAKE_BUILD_TOOL}" MATCHES "devenv")) - list(APPEND srcs ${uis}) -endif() +PCL_ADD_EXECUTABLE( + ${EXE_NAME} + COMPONENT + ${SUBSUBSYS_NAME} + SOURCES + ${uis} + ${resources} + ${srcs} + ${incs} + ${impl_incs}) + +target_link_libraries("${EXE_NAME}" pcl_common pcl_io pcl_kdtree pcl_filters pcl_visualization pcl_segmentation pcl_surface pcl_features pcl_sample_consensus pcl_search ${QTX}::Widgets) # Install include files PCL_ADD_INCLUDES("${SUBSUBSYS_NAME}" "${SUBSUBSYS_NAME}" ${incs}) diff --git a/apps/modeler/include/pcl/apps/modeler/render_window.h b/apps/modeler/include/pcl/apps/modeler/render_window.h index 0413e85b6d2..7e5cb4660fb 100755 --- a/apps/modeler/include/pcl/apps/modeler/render_window.h +++ b/apps/modeler/include/pcl/apps/modeler/render_window.h @@ -50,7 +50,7 @@ class RenderWindow : public PCLQVTKWidget { public: RenderWindow(RenderWindowItem* render_window_item, QWidget* parent = nullptr, - Qt::WindowFlags flags = nullptr); + Qt::WindowFlags flags = {}); ~RenderWindow(); QSize diff --git a/apps/modeler/src/cloud_mesh.cpp b/apps/modeler/src/cloud_mesh.cpp index 0a3e5c4cb0d..c7936b3be9d 100755 --- a/apps/modeler/src/cloud_mesh.cpp +++ b/apps/modeler/src/cloud_mesh.cpp @@ -174,7 +174,7 @@ pcl::modeler::CloudMesh::updateVtkPoints() } // Need to check for NaNs, Infs, ec else { - pcl::IndicesPtr indices(new std::vector()); + pcl::IndicesPtr indices(new pcl::Indices()); pcl::removeNaNFromPointCloud(*cloud_, *indices); data->SetNumberOfValues(3 * indices->size()); @@ -203,7 +203,7 @@ pcl::modeler::CloudMesh::updateVtkPolygons() } } else { - pcl::IndicesPtr indices(new std::vector()); + pcl::IndicesPtr indices(new pcl::Indices()); pcl::removeNaNFromPointCloud(*cloud_, *indices); for (const auto& polygon : polygons_) { diff --git a/apps/modeler/src/normal_estimation_worker.cpp b/apps/modeler/src/normal_estimation_worker.cpp index 56fce622185..468d7362fea 100755 --- a/apps/modeler/src/normal_estimation_worker.cpp +++ b/apps/modeler/src/normal_estimation_worker.cpp @@ -112,7 +112,7 @@ pcl::modeler::NormalEstimationWorker::processImpl(CloudMeshItem* cloud_mesh_item pcl::NormalEstimation normal_estimator; normal_estimator.setInputCloud(cloud); - pcl::IndicesPtr indices(new std::vector()); + pcl::IndicesPtr indices(new pcl::Indices()); pcl::removeNaNFromPointCloud(*cloud, *indices); normal_estimator.setIndices(indices); diff --git a/apps/modeler/src/normals_actor_item.cpp b/apps/modeler/src/normals_actor_item.cpp index b9141fdafa5..6530c56095e 100644 --- a/apps/modeler/src/normals_actor_item.cpp +++ b/apps/modeler/src/normals_actor_item.cpp @@ -95,7 +95,7 @@ pcl::modeler::NormalsActorItem::createNormalLines() } } else { - pcl::IndicesPtr indices(new std::vector()); + pcl::IndicesPtr indices(new pcl::Indices()); pcl::removeNaNFromPointCloud(*cloud, *indices); vtkIdType nr_normals = static_cast((indices->size() - 1) / level_ + 1); diff --git a/apps/point_cloud_editor/CMakeLists.txt b/apps/point_cloud_editor/CMakeLists.txt index cb749b65143..e5321278920 100644 --- a/apps/point_cloud_editor/CMakeLists.txt +++ b/apps/point_cloud_editor/CMakeLists.txt @@ -1,25 +1,7 @@ set(SUBSUBSYS_NAME point_cloud_editor) set(SUBSUBSYS_DESC "Point Cloud Editor - Simple editor for 3D point clouds") set(SUBSUBSYS_DEPS common filters io apps) - -# QT5 Found? -if(NOT Qt5_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "Qt5 was not found.") -elseif(NOT ${DEFAULT} STREQUAL "AUTO_OFF") - set(DEFAULT TRUE) - set(REASON) -endif() - -# Find OpenGL -if(NOT OPENGL_FOUND) - set(DEFAULT AUTO_OFF) - set(REASON "OpenGL was not found.") -elseif(NOT ${DEFAULT} STREQUAL "AUTO_OFF") - set(DEFAULT TRUE) - set(REASON) -endif() - +set(SUBSUBSYS_EXT_DEPS vtk ${QTX} OpenGL) # Default to not building for now if(${DEFAULT} STREQUAL "TRUE") @@ -27,25 +9,22 @@ if(${DEFAULT} STREQUAL "TRUE") endif() PCL_SUBSUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" "${SUBSYS_DESC}" ${DEFAULT} "${REASON}") -PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" ${SUBSYS_DEPS}) +PCL_SUBSUBSYS_DEPEND(build "${SUBSYS_NAME}" "${SUBSUBSYS_NAME}" ${SUBSUBSYS_DEPS} EXT_DEPS ${SUBSUBSYS_EXT_DEPS}) PCL_ADD_DOC(${SUBSUBSYS_NAME}) if(NOT build) return() endif() -set(MOC_INCS - "include/pcl/apps/${SUBSUBSYS_NAME}/cloudEditorWidget.h" - "include/pcl/apps/${SUBSUBSYS_NAME}/mainWindow.h" - "include/pcl/apps/${SUBSUBSYS_NAME}/denoiseParameterForm.h" - "include/pcl/apps/${SUBSUBSYS_NAME}/statisticsDialog.h" -) - set(RSRC resources/pceditor_resources.qrc ) -set(INCS ${MOC_INCS} +set(INCS + "include/pcl/apps/${SUBSUBSYS_NAME}/cloudEditorWidget.h" + "include/pcl/apps/${SUBSUBSYS_NAME}/mainWindow.h" + "include/pcl/apps/${SUBSUBSYS_NAME}/denoiseParameterForm.h" + "include/pcl/apps/${SUBSUBSYS_NAME}/statisticsDialog.h" "include/pcl/apps/${SUBSUBSYS_NAME}/cloud.h" "include/pcl/apps/${SUBSUBSYS_NAME}/cloudTransformTool.h" "include/pcl/apps/${SUBSUBSYS_NAME}/command.h" @@ -92,18 +71,22 @@ set(SRCS src/denoiseParameterForm.cpp ) -qt5_wrap_cpp(MOC_SRCS ${MOC_INCS} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) -qt5_add_resources(RESOURCES_SRCS ${RSRC}) - include_directories( "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include" ) set(EXE_NAME "pcl_${SUBSUBSYS_NAME}") -PCL_ADD_EXECUTABLE(${EXE_NAME} COMPONENT ${SUBSUBSYS_NAME} SOURCES ${SRCS} ${RESOURCES_SRCS} ${MOC_SRCS} ${INCS}) - -target_link_libraries("${EXE_NAME}" Qt5::Widgets Qt5::OpenGL ${OPENGL_LIBRARIES} ${BOOST_LIBRARIES} pcl_common pcl_io pcl_filters) +PCL_ADD_EXECUTABLE( + ${EXE_NAME} + COMPONENT + ${SUBSUBSYS_NAME} + SOURCES + ${SRCS} + ${RSRC} + ${INCS}) + +target_link_libraries("${EXE_NAME}" ${QTX}::Widgets ${QTX}::OpenGL ${OPENGL_LIBRARIES} ${BOOST_LIBRARIES} pcl_common pcl_io pcl_filters) PCL_ADD_INCLUDES("${SUBSUBSYS_NAME}" "${SUBSYS_NAME}/${SUBSUBSYS_NAME}" ${INCS}) PCL_MAKE_PKGCONFIG(${EXE_NAME} COMPONENT ${SUBSUBSYS_NAME} DESC ${SUBSUBSYS_DESC}) diff --git a/apps/point_cloud_editor/include/pcl/apps/point_cloud_editor/selection.h b/apps/point_cloud_editor/include/pcl/apps/point_cloud_editor/selection.h index 3e744e30e88..7855e1711cf 100644 --- a/apps/point_cloud_editor/include/pcl/apps/point_cloud_editor/selection.h +++ b/apps/point_cloud_editor/include/pcl/apps/point_cloud_editor/selection.h @@ -60,6 +60,11 @@ class Selection : public Statistics registerStats(); } + /// @brief Copy constructor. + /// @param selection a const reference to a selection object whose + /// properties will be copied. + Selection (const Selection& selection) = default; + /// @brief Equal operator /// @param selection a const reference to a selection object whose /// properties will be copied. diff --git a/apps/point_cloud_editor/src/cloudEditorWidget.cpp b/apps/point_cloud_editor/src/cloudEditorWidget.cpp index b9a1ba19586..b9150f7bcfe 100644 --- a/apps/point_cloud_editor/src/cloudEditorWidget.cpp +++ b/apps/point_cloud_editor/src/cloudEditorWidget.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include @@ -101,7 +103,7 @@ void CloudEditorWidget::load () { QString file_path = QFileDialog::getOpenFileName(this, tr("Open File")); - + if (file_path.isEmpty()) return; @@ -129,7 +131,7 @@ CloudEditorWidget::save () } QString file_path = QFileDialog::getSaveFileName(this,tr("Save point cloud")); - + std::string file_path_std = file_path.toStdString(); if ( (file_path_std.empty()) || (!cloud_ptr_) ) return; @@ -487,9 +489,10 @@ CloudEditorWidget::resizeGL (int width, int height) void CloudEditorWidget::mousePressEvent (QMouseEvent *event) { + auto ratio = this->devicePixelRatio(); if (!tool_ptr_) return; - tool_ptr_ -> start(event -> x(), event -> y(), + tool_ptr_ -> start(event -> x()*ratio, event -> y()*ratio, event -> modifiers(), event -> buttons()); update(); } @@ -497,9 +500,10 @@ CloudEditorWidget::mousePressEvent (QMouseEvent *event) void CloudEditorWidget::mouseMoveEvent (QMouseEvent *event) { + auto ratio = this->devicePixelRatio(); if (!tool_ptr_) return; - tool_ptr_ -> update(event -> x(), event -> y(), + tool_ptr_ -> update(event -> x()*ratio, event -> y()*ratio, event -> modifiers(), event -> buttons()); update(); } @@ -507,9 +511,10 @@ CloudEditorWidget::mouseMoveEvent (QMouseEvent *event) void CloudEditorWidget::mouseReleaseEvent (QMouseEvent *event) { + auto ratio = this->devicePixelRatio(); if (!tool_ptr_) return; - tool_ptr_ -> end(event -> x(), event -> y(), + tool_ptr_ -> end(event -> x()*ratio, event -> y()*ratio, event -> modifiers(), event -> button()); update(); } @@ -528,13 +533,13 @@ CloudEditorWidget::keyPressEvent (QKeyEvent *event) void CloudEditorWidget::loadFilePCD(const std::string &filename) -{ +{ PclCloudPtr pcl_cloud_ptr; Cloud3D tmp; if (pcl::io::loadPCDFile(filename, tmp) == -1) throw; pcl_cloud_ptr = PclCloudPtr(new Cloud3D(tmp)); - std::vector index; + pcl::Indices index; pcl::removeNaNFromPointCloud(*pcl_cloud_ptr, *pcl_cloud_ptr, index); Statistics::clear(); cloud_ptr_ = CloudPtr(new Cloud(*pcl_cloud_ptr, true)); @@ -597,7 +602,7 @@ CloudEditorWidget::swapRBValues () void CloudEditorWidget::initKeyMap () -{ +{ key_map_[Qt::Key_1] = &CloudEditorWidget::colorByPure; key_map_[Qt::Key_2] = &CloudEditorWidget::colorByX; key_map_[Qt::Key_3] = &CloudEditorWidget::colorByY; diff --git a/apps/src/face_detection/filesystem_face_detection.cpp b/apps/src/face_detection/filesystem_face_detection.cpp index ec2deeceb1a..fcb5028b66a 100644 --- a/apps/src/face_detection/filesystem_face_detection.cpp +++ b/apps/src/face_detection/filesystem_face_detection.cpp @@ -46,8 +46,8 @@ run(pcl::RFFaceDetectorTrainer& fdrf, float rgb_m; bool exists_m; - pcl::for_each_type(pcl::CopyIfFieldExists( - (*scene_vis)[0], "rgb", exists_m, rgb_m)); + pcl::for_each_type( + pcl::CopyIfFieldExists((*scene_vis)[0], "rgb", exists_m, rgb_m)); std::cout << "Color exists:" << static_cast(exists_m) << std::endl; if (exists_m) { diff --git a/apps/src/feature_matching.cpp b/apps/src/feature_matching.cpp index e1ee3c6408c..488af48cca1 100644 --- a/apps/src/feature_matching.cpp +++ b/apps/src/feature_matching.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -222,7 +221,7 @@ ICCVTutorial::segmentation( extract.setNegative(true); extract.filter(*segmented); - std::vector indices; + pcl::Indices indices; pcl::removeNaNFromPointCloud(*segmented, *segmented, indices); std::cout << "OK" << std::endl; @@ -247,7 +246,7 @@ ICCVTutorial::segmentation( if (cluster_indices.size() > 1) std::cout << " Using largest one..."; std::cout << std::endl; - typename pcl::IndicesPtr indices(new std::vector); + typename pcl::IndicesPtr indices(new pcl::Indices); *indices = cluster_indices[0].indices; extract.setInputCloud(segmented); extract.setIndices(indices); @@ -326,7 +325,7 @@ ICCVTutorial::findCorrespondences( // Find the index of the best match for each keypoint, and store it in // "correspondences_out" const int k = 1; - std::vector k_indices(k); + pcl::Indices k_indices(k); std::vector k_squared_distances(k); for (int i = 0; i < static_cast(source->size()); ++i) { descriptor_kdtree.nearestKSearch(*source, i, k, k_indices, k_squared_distances); diff --git a/apps/src/grabcut_2d.cpp b/apps/src/grabcut_2d.cpp index ff4912e8f07..d383f55a8d9 100644 --- a/apps/src/grabcut_2d.cpp +++ b/apps/src/grabcut_2d.cpp @@ -236,11 +236,8 @@ GrabCutHelper::display(int display_type) break; case 1: - glDrawPixels(gmm_image_->width, - gmm_image_->height, - GL_RGB, - GL_FLOAT, - &((*gmm_image_)[0])); + glDrawPixels( + gmm_image_->width, gmm_image_->height, GL_RGB, GL_FLOAT, &((*gmm_image_)[0])); break; case 2: diff --git a/apps/src/manual_registration/manual_registration.cpp b/apps/src/manual_registration/manual_registration.cpp index 4f92ac19e22..8e4c4699373 100644 --- a/apps/src/manual_registration/manual_registration.cpp +++ b/apps/src/manual_registration/manual_registration.cpp @@ -45,11 +45,12 @@ #include #include #include +#include #include +#include #include #include -#include using namespace pcl; @@ -72,11 +73,12 @@ ManualRegistration::ManualRegistration() auto renderer_src = vtkSmartPointer::New(); auto renderWindow_src = vtkSmartPointer::New(); renderWindow_src->AddRenderer(renderer_src); - vis_src_.reset(new pcl::visualization::PCLVisualizer(renderer_src, renderWindow_src, "", false)); + vis_src_.reset( + new pcl::visualization::PCLVisualizer(renderer_src, renderWindow_src, "", false)); #else vis_src_.reset(new pcl::visualization::PCLVisualizer("", false)); #endif // VTK_MAJOR_VERSION > 8 - setRenderWindowCompat(*(ui_->qvtk_widget_src),*(vis_src_->getRenderWindow())); + setRenderWindowCompat(*(ui_->qvtk_widget_src), *(vis_src_->getRenderWindow())); vis_src_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget_src)), getRenderWindowCompat(*(ui_->qvtk_widget_src))); @@ -91,7 +93,8 @@ ManualRegistration::ManualRegistration() auto renderer_dst = vtkSmartPointer::New(); auto renderWindow_dst = vtkSmartPointer::New(); renderWindow_dst->AddRenderer(renderer_dst); - vis_dst_.reset(new pcl::visualization::PCLVisualizer(renderer_dst, renderWindow_dst, "", false)); + vis_dst_.reset( + new pcl::visualization::PCLVisualizer(renderer_dst, renderWindow_dst, "", false)); #else vis_dst_.reset(new pcl::visualization::PCLVisualizer("", false)); #endif // VTK_MAJOR_VERSION > 8 @@ -99,15 +102,14 @@ ManualRegistration::ManualRegistration() vis_dst_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget_dst)), getRenderWindowCompat(*(ui_->qvtk_widget_dst))); - vis_dst_->getInteractorStyle()->setKeyboardModifier( - pcl::visualization::INTERACTOR_KB_MOD_SHIFT); + pcl::visualization::INTERACTOR_KB_MOD_SHIFT); vis_dst_->registerPointPickingCallback(&ManualRegistration::DstPointPickCallback, *this); // Render view refreshView(); - + // Connect all buttons connect(ui_->confirmSrcPointButton, SIGNAL(clicked()), @@ -175,8 +177,7 @@ ManualRegistration::confirmSrcPointPressed() { if (src_point_selected_) { src_pc_.push_back(src_point_); - PCL_INFO("Selected %zu source points\n", - static_cast(src_pc_.size())); + PCL_INFO("Selected %zu source points\n", static_cast(src_pc_.size())); src_point_selected_ = false; src_pc_.width = src_pc_.size(); } diff --git a/apps/src/multiscale_feature_persistence_example.cpp b/apps/src/multiscale_feature_persistence_example.cpp index 372c4cf428b..5ae97db8dcc 100644 --- a/apps/src/multiscale_feature_persistence_example.cpp +++ b/apps/src/multiscale_feature_persistence_example.cpp @@ -108,7 +108,7 @@ main(int argc, char** argv) feature_persistence.setDistanceMetric(pcl::CS); PointCloud::Ptr output_features(new PointCloud()); - auto output_indices = pcl::make_shared>(); + auto output_indices = pcl::make_shared(); feature_persistence.determinePersistentFeatures(*output_features, output_indices); PCL_INFO("persistent features cloud size: %zu\n", diff --git a/apps/src/ni_agast.cpp b/apps/src/ni_agast.cpp index 25c038ed178..6793e490d0a 100644 --- a/apps/src/ni_agast.cpp +++ b/apps/src/ni_agast.cpp @@ -221,9 +221,8 @@ class AGASTDemo { std::size_t j = 0; for (std::size_t i = 0; i < keypoints->size(); ++i) { - const PointT& pt = - (*cloud)(static_cast((*keypoints)[i].u), - static_cast((*keypoints)[i].v)); + const PointT& pt = (*cloud)(static_cast((*keypoints)[i].u), + static_cast((*keypoints)[i].v)); if (!std::isfinite(pt.x) || !std::isfinite(pt.y) || !std::isfinite(pt.z)) continue; diff --git a/apps/src/ni_brisk.cpp b/apps/src/ni_brisk.cpp index 2b17a794e34..274cdf5a8d6 100644 --- a/apps/src/ni_brisk.cpp +++ b/apps/src/ni_brisk.cpp @@ -174,8 +174,7 @@ class BRISKDemo { std::size_t j = 0; for (std::size_t i = 0; i < keypoints->size(); ++i) { - PointT pt = - bilinearInterpolation(cloud, (*keypoints)[i].x, (*keypoints)[i].y); + PointT pt = bilinearInterpolation(cloud, (*keypoints)[i].x, (*keypoints)[i].y); keypoints3d[j].x = pt.x; keypoints3d[j].y = pt.y; diff --git a/apps/src/ni_linemod.cpp b/apps/src/ni_linemod.cpp index 5b55674d1aa..52452ec0bd6 100644 --- a/apps/src/ni_linemod.cpp +++ b/apps/src/ni_linemod.cpp @@ -208,7 +208,7 @@ class NILinemod { * \param[out] object the segmented resultant object */ void - segmentObject(int picked_idx, + segmentObject(pcl::index_t picked_idx, const CloudConstPtr& cloud, const PointIndices::Ptr& plane_indices, const PointIndices::Ptr& plane_boundary_indices, @@ -230,7 +230,7 @@ class NILinemod { for (int p_it = 0; p_it < static_cast(indices_fullset_.size()); ++p_it) indices_fullset_[p_it] = p_it; } - std::vector indices_subset = plane_indices->indices; + pcl::Indices indices_subset = plane_indices->indices; std::sort(indices_subset.begin(), indices_subset.end()); set_difference(indices_fullset_.begin(), indices_fullset_.end(), @@ -293,7 +293,7 @@ class NILinemod { ///////////////////////////////////////////////////////////////////////// void segment(const PointT& picked_point, - int picked_idx, + pcl::index_t picked_idx, PlanarRegion& region, PointIndices&, CloudPtr& object) @@ -385,7 +385,7 @@ class NILinemod { if (idx == -1) return; - std::vector indices(1); + pcl::Indices indices(1); std::vector distances(1); // Use mutices to make sure we get the right cloud @@ -569,7 +569,7 @@ class NILinemod { bool first_frame_; // Segmentation - std::vector indices_fullset_; + pcl::Indices indices_fullset_; PointIndices::Ptr plane_indices_; CloudPtr plane_; IntegralImageNormalEstimation ne_; diff --git a/apps/src/openni_change_viewer.cpp b/apps/src/openni_change_viewer.cpp index 68616234524..b07a4e860e5 100644 --- a/apps/src/openni_change_viewer.cpp +++ b/apps/src/openni_change_viewer.cpp @@ -70,7 +70,7 @@ class OpenNIChangeViewer { octree->addPointsFromInputCloud(); std::cerr << octree->getLeafCount() << " -- "; - std::vector newPointIdxVector; + pcl::Indices newPointIdxVector; // get a vector of new points, which did not exist in previous buffer octree->getPointIndicesFromNewVoxels(newPointIdxVector, noise_filter_); @@ -84,7 +84,7 @@ class OpenNIChangeViewer { filtered_cloud.reset(new pcl::PointCloud(*cloud)); filtered_cloud->points.reserve(newPointIdxVector.size()); - for (const int& idx : newPointIdxVector) + for (const auto& idx : newPointIdxVector) (*filtered_cloud)[idx].rgba = 255 << 16; if (!viewer.wasStopped()) @@ -96,7 +96,7 @@ class OpenNIChangeViewer { filtered_cloud->points.reserve(newPointIdxVector.size()); - for (const int& idx : newPointIdxVector) + for (const auto& idx : newPointIdxVector) filtered_cloud->points.push_back((*cloud)[idx]); if (!viewer.wasStopped()) diff --git a/apps/src/openni_feature_persistence.cpp b/apps/src/openni_feature_persistence.cpp index 01b7d69a2ad..17ac919576a 100644 --- a/apps/src/openni_feature_persistence.cpp +++ b/apps/src/openni_feature_persistence.cpp @@ -131,7 +131,7 @@ class OpenNIFeaturePersistence { cloud_subsampled_.reset(new typename pcl::PointCloud()); normals_.reset(new pcl::PointCloud()); features_.reset(new pcl::PointCloud()); - feature_indices_.reset(new std::vector()); + feature_indices_.reset(new pcl::Indices()); feature_locations_.reset(new typename pcl::PointCloud()); // Subsample input cloud @@ -152,7 +152,8 @@ class OpenNIFeaturePersistence { extract_indices_filter_.setIndices(feature_indices_); extract_indices_filter_.filter(*feature_locations_); - PCL_INFO("Persistent feature locations %zu\n", static_cast(feature_locations_->size())); + PCL_INFO("Persistent feature locations %zu\n", + static_cast(feature_locations_->size())); cloud_ = cloud; diff --git a/apps/src/openni_grab_frame.cpp b/apps/src/openni_grab_frame.cpp index 052231301f8..f61ff619405 100644 --- a/apps/src/openni_grab_frame.cpp +++ b/apps/src/openni_grab_frame.cpp @@ -158,7 +158,7 @@ class OpenNIGrabFrame { { FPS_CALC("I/O"); const std::string time = boost::posix_time::to_iso_string( - boost::posix_time::microsec_clock::local_time()); + boost::posix_time::microsec_clock::local_time()); const std::string filepath = dir_name_ + '/' + file_name_ + '_' + time + ".pcd"; if (format_ & 1) { diff --git a/apps/src/openni_grab_images.cpp b/apps/src/openni_grab_images.cpp index 7dacf080ef5..37b6fd55bd7 100644 --- a/apps/src/openni_grab_images.cpp +++ b/apps/src/openni_grab_images.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include diff --git a/apps/src/openni_klt.cpp b/apps/src/openni_klt.cpp index ff17a983fe8..b553ef59d71 100644 --- a/apps/src/openni_klt.cpp +++ b/apps/src/openni_klt.cpp @@ -41,9 +41,10 @@ #include #include #include -#include #include +#include // for to_iso_string, local_time + #include #define SHOW_FPS 1 @@ -251,14 +252,14 @@ class OpenNIViewer { if (tracker_->getInitialized() && cloud_) { if (points_mutex_.try_lock()) { keypoints_ = tracker_->getTrackedPoints(); - points_status_ = tracker_->getPointsToTrackStatus(); + points_status_ = tracker_->getStatusOfPointsToTrack(); points_mutex_.unlock(); } std::vector markers; markers.reserve(keypoints_->size() * 2); for (std::size_t i = 0; i < keypoints_->size(); ++i) { - if (points_status_->indices[i] < 0) + if ((*points_status_)[i] < 0) continue; const pcl::PointUV& uv = (*keypoints_)[i]; markers.push_back(uv.u); @@ -295,7 +296,7 @@ class OpenNIViewer { typename pcl::tracking::PyramidalKLTTracker::Ptr tracker_; pcl::PointCloud::ConstPtr keypoints_; pcl::PointIndicesConstPtr points_; - pcl::PointIndicesConstPtr points_status_; + pcl::shared_ptr> points_status_; int counter_; }; diff --git a/apps/src/openni_mls_smoothing.cpp b/apps/src/openni_mls_smoothing.cpp index d21d28aa9d3..c451e11bd93 100644 --- a/apps/src/openni_mls_smoothing.cpp +++ b/apps/src/openni_mls_smoothing.cpp @@ -37,12 +37,12 @@ #include #include #include +#include // for KdTree #include #include // for KeyboardEvent #include // for PCLVisualizer #include #include -#include // for KdTree #include diff --git a/apps/src/openni_octree_compression.cpp b/apps/src/openni_octree_compression.cpp index bba10c7ed01..7203f1b2b23 100644 --- a/apps/src/openni_octree_compression.cpp +++ b/apps/src/openni_octree_compression.cpp @@ -383,7 +383,8 @@ main(int argc, char** argv) if (bEnDecode) { // ENCODING std::ofstream compressedPCFile; - compressedPCFile.open(fileName.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); + compressedPCFile.open(fileName.c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); if (!bShowInputCloud) { EventHelper v(compressedPCFile, octreeCoder, field_name, min_v, max_v); diff --git a/apps/src/openni_organized_compression.cpp b/apps/src/openni_organized_compression.cpp index 569bd3bcbee..ae855521875 100644 --- a/apps/src/openni_organized_compression.cpp +++ b/apps/src/openni_organized_compression.cpp @@ -396,7 +396,8 @@ main(int argc, char** argv) if (bEnDecode) { // ENCODING std::ofstream compressedPCFile; - compressedPCFile.open(fileName.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); + compressedPCFile.open(fileName.c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); if (!bShowInputCloud) { EventHelper v(compressedPCFile, diff --git a/apps/src/openni_organized_edge_detection.cpp b/apps/src/openni_organized_edge_detection.cpp index b06f8c2e4ec..2f4d07cb9cb 100644 --- a/apps/src/openni_organized_edge_detection.cpp +++ b/apps/src/openni_organized_edge_detection.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include diff --git a/apps/src/openni_passthrough.cpp b/apps/src/openni_passthrough.cpp index cf218c978b4..b516e68e59f 100644 --- a/apps/src/openni_passthrough.cpp +++ b/apps/src/openni_passthrough.cpp @@ -35,18 +35,17 @@ * */ -#include - #include #include #include #include #include +#include +#include #include #include -#include #include @@ -64,7 +63,7 @@ OpenNIPassthrough::OpenNIPassthrough(pcl::OpenNIGrabber& grabber) ui_->setupUi(this); this->setWindowTitle("PCL OpenNI PassThrough Viewer"); - //Create the QVTKWidget + // Create the QVTKWidget #if VTK_MAJOR_VERSION > 8 auto renderer = vtkSmartPointer::New(); auto renderWindow = vtkSmartPointer::New(); @@ -73,11 +72,13 @@ OpenNIPassthrough::OpenNIPassthrough(pcl::OpenNIGrabber& grabber) #else vis_.reset(new pcl::visualization::PCLVisualizer("", false)); #endif // VTK_MAJOR_VERSION > 8 - setRenderWindowCompat(*(ui_->qvtk_widget),*(vis_->getRenderWindow())); - vis_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget)), getRenderWindowCompat(*(ui_->qvtk_widget))); - - vis_->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT); - + setRenderWindowCompat(*(ui_->qvtk_widget), *(vis_->getRenderWindow())); + vis_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget)), + getRenderWindowCompat(*(ui_->qvtk_widget))); + + vis_->getInteractorStyle()->setKeyboardModifier( + pcl::visualization::INTERACTOR_KB_MOD_SHIFT); + refreshView(); // Start the OpenNI data acquision diff --git a/apps/src/openni_tracking.cpp b/apps/src/openni_tracking.cpp index bc003de4b3f..ccc6377a218 100644 --- a/apps/src/openni_tracking.cpp +++ b/apps/src/openni_tracking.cpp @@ -435,12 +435,12 @@ class OpenNISegmentTracking { result.width = cloud->width; result.height = cloud->height; result.is_dense = cloud->is_dense; - for (std::size_t i = 0; i < cloud->size(); i++) { + for (const auto& pt : *cloud) { RefPointType point; - point.x = (*cloud)[i].x; - point.y = (*cloud)[i].y; - point.z = (*cloud)[i].z; - point.rgba = (*cloud)[i].rgba; + point.x = pt.x; + point.y = pt.y; + point.z = pt.z; + point.rgba = pt.rgba; result.push_back(point); } } @@ -468,7 +468,7 @@ class OpenNISegmentTracking { void removeZeroPoints(const CloudConstPtr& cloud, Cloud& result) { - for (const auto& point: *cloud) { + for (const auto& point : *cloud) { if (!(std::abs(point.x) < 0.01 && std::abs(point.y) < 0.01 && std::abs(point.z) < 0.01) && !std::isnan(point.x) && !std::isnan(point.y) && !std::isnan(point.z)) diff --git a/apps/src/organized_segmentation_demo.cpp b/apps/src/organized_segmentation_demo.cpp index 5529eb87d6e..e4ce56193aa 100644 --- a/apps/src/organized_segmentation_demo.cpp +++ b/apps/src/organized_segmentation_demo.cpp @@ -11,9 +11,9 @@ #include #include +#include #include #include -#include // #include // for boost::filesystem::directory_iterator #include // for boost::signals2::connection @@ -206,7 +206,7 @@ OrganizedSegmentationDemo::OrganizedSegmentationDemo(pcl::Grabber& grabber) ui_->setupUi(this); this->setWindowTitle("PCL Organized Connected Component Segmentation Demo"); - + #if VTK_MAJOR_VERSION > 8 auto renderer = vtkSmartPointer::New(); auto renderWindow = vtkSmartPointer::New(); @@ -215,14 +215,14 @@ OrganizedSegmentationDemo::OrganizedSegmentationDemo(pcl::Grabber& grabber) #else vis_.reset(new pcl::visualization::PCLVisualizer("", false)); #endif // VTK_MAJOR_VERSION > 8 - setRenderWindowCompat(*(ui_->qvtk_widget),*(vis_->getRenderWindow())); - vis_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget)), getRenderWindowCompat(*(ui_->qvtk_widget))); - + setRenderWindowCompat(*(ui_->qvtk_widget), *(vis_->getRenderWindow())); + vis_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget)), + getRenderWindowCompat(*(ui_->qvtk_widget))); + refreshView(); - + vis_->getInteractorStyle()->setKeyboardModifier( pcl::visualization::INTERACTOR_KB_MOD_SHIFT); - std::function f = [this](const CloudConstPtr& cloud) { cloud_cb(cloud); diff --git a/apps/src/pcd_organized_multi_plane_segmentation.cpp b/apps/src/pcd_organized_multi_plane_segmentation.cpp index 10c1a173cb3..82d4507034d 100644 --- a/apps/src/pcd_organized_multi_plane_segmentation.cpp +++ b/apps/src/pcd_organized_multi_plane_segmentation.cpp @@ -198,13 +198,12 @@ class PCDOrganizedMultiPlaneSegmentation { "approx_plane_%02zu_%03zu", static_cast(i), static_cast(idx)); - viewer.addLine( - (*approx_contour)[idx], - (*approx_contour)[(idx + 1) % approx_contour->size()], - 0.5 * red[i], - 0.5 * grn[i], - 0.5 * blu[i], - name); + viewer.addLine((*approx_contour)[idx], + (*approx_contour)[(idx + 1) % approx_contour->size()], + 0.5 * red[i], + 0.5 * grn[i], + 0.5 * blu[i], + name); } } } diff --git a/apps/src/pcd_select_object_plane.cpp b/apps/src/pcd_select_object_plane.cpp index b4cf492089b..b7914d72668 100644 --- a/apps/src/pcd_select_object_plane.cpp +++ b/apps/src/pcd_select_object_plane.cpp @@ -149,7 +149,7 @@ class ObjectSelection { * \param[out] object the segmented resultant object */ void - segmentObject(int picked_idx, + segmentObject(pcl::index_t picked_idx, const typename PointCloud::ConstPtr& cloud, const PointIndices::Ptr& plane_indices, PointCloud& object) @@ -179,9 +179,8 @@ class ObjectSelection { exppd.setInputCloud(cloud); exppd.setIndices(indices_but_the_plane); exppd.setInputPlanarHull(plane_hull); - exppd.setViewPoint((*cloud)[picked_idx].x, - (*cloud)[picked_idx].y, - (*cloud)[picked_idx].z); + exppd.setViewPoint( + (*cloud)[picked_idx].x, (*cloud)[picked_idx].y, (*cloud)[picked_idx].z); exppd.setHeightLimits(0.001, 0.5); // up to half a meter exppd.segment(*points_above_plane); @@ -258,7 +257,7 @@ class ObjectSelection { ///////////////////////////////////////////////////////////////////////// void segment(const PointT& picked_point, - int picked_idx, + pcl::index_t picked_idx, PlanarRegion& region, typename PointCloud::Ptr& object) { @@ -441,7 +440,7 @@ class ObjectSelection { if (idx == -1) return; - std::vector indices(1); + pcl::Indices indices(1); std::vector distances(1); // Get the point that was picked diff --git a/apps/src/pcd_video_player/pcd_video_player.cpp b/apps/src/pcd_video_player/pcd_video_player.cpp index a5d2286dac0..0e90e874379 100644 --- a/apps/src/pcd_video_player/pcd_video_player.cpp +++ b/apps/src/pcd_video_player/pcd_video_player.cpp @@ -35,8 +35,6 @@ * */ -#include - #include #include #include @@ -49,11 +47,12 @@ #include #include #include +#include #include +#include #include #include -#include #include #include @@ -83,7 +82,7 @@ PCDVideoPlayer::PCDVideoPlayer() // Setup the cloud pointer cloud_.reset(new pcl::PointCloud); - //Create the QVTKWidget + // Create the QVTKWidget #if VTK_MAJOR_VERSION > 8 auto renderer = vtkSmartPointer::New(); auto renderWindow = vtkSmartPointer::New(); @@ -92,10 +91,12 @@ PCDVideoPlayer::PCDVideoPlayer() #else vis_.reset(new pcl::visualization::PCLVisualizer("", false)); #endif // VTK_MAJOR_VERSION > 8 - setRenderWindowCompat(*(ui_->qvtk_widget),*(vis_->getRenderWindow())); - vis_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget)), getRenderWindowCompat(*(ui_->qvtk_widget))); + setRenderWindowCompat(*(ui_->qvtk_widget), *(vis_->getRenderWindow())); + vis_->setupInteractor(getInteractorCompat(*(ui_->qvtk_widget)), + getRenderWindowCompat(*(ui_->qvtk_widget))); - vis_->getInteractorStyle()->setKeyboardModifier(pcl::visualization::INTERACTOR_KB_MOD_SHIFT); + vis_->getInteractorStyle()->setKeyboardModifier( + pcl::visualization::INTERACTOR_KB_MOD_SHIFT); refreshView(); diff --git a/apps/src/ppf_object_recognition.cpp b/apps/src/ppf_object_recognition.cpp index d0c16d19ed4..e02d9d62b1a 100644 --- a/apps/src/ppf_object_recognition.cpp +++ b/apps/src/ppf_object_recognition.cpp @@ -86,8 +86,7 @@ main(int argc, char** argv) while (cloud_scene->size() > 0.3 * nr_points) { seg.setInputCloud(cloud_scene); seg.segment(*inliers, *coefficients); - PCL_INFO("Plane inliers: %zu\n", - static_cast(inliers->indices.size())); + PCL_INFO("Plane inliers: %zu\n", static_cast(inliers->indices.size())); if (inliers->indices.size() < 50000) break; diff --git a/apps/src/render_views_tesselated_sphere.cpp b/apps/src/render_views_tesselated_sphere.cpp index 002e28c3d12..ac248ac0ff9 100644 --- a/apps/src/render_views_tesselated_sphere.cpp +++ b/apps/src/render_views_tesselated_sphere.cpp @@ -6,14 +6,15 @@ */ #include -#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include @@ -94,21 +94,6 @@ pcl::apps::RenderViewsTesselatedSphere::generateViews() mapper->SetInputConnection(trans_filter_scale->GetOutputPort()); mapper->Update(); - ////////////////////////////// - // * Compute area of the mesh - ////////////////////////////// - vtkSmartPointer cells = mapper->GetInput()->GetPolys(); - vtkIdType npts = 0; - vtkCellPtsPtr ptIds = nullptr; - - double p1[3], p2[3], p3[3], totalArea = 0; - for (cells->InitTraversal(); cells->GetNextCell(npts, ptIds);) { - polydata_->GetPoint(ptIds[0], p1); - polydata_->GetPoint(ptIds[1], p2); - polydata_->GetPoint(ptIds[2], p3); - totalArea += vtkTriangle::TriangleArea(p1, p2, p3); - } - // create icosahedron vtkSmartPointer ico = vtkSmartPointer::New(); diff --git a/apps/src/stereo_ground_segmentation.cpp b/apps/src/stereo_ground_segmentation.cpp index c320bc2c2ba..baabce972a9 100755 --- a/apps/src/stereo_ground_segmentation.cpp +++ b/apps/src/stereo_ground_segmentation.cpp @@ -50,6 +50,8 @@ #include #include +#include // for directory_iterator + #include using PointT = pcl::PointXYZRGB; @@ -439,8 +441,7 @@ class HRCSSegmentation { // note the NAN points in the image as well for (std::size_t i = 0; i < cloud->size(); i++) { if (!pcl::isFinite((*cloud)[i])) { - (*ground_image)[i].b = - static_cast(((*cloud)[i].b + 255) / 2); + (*ground_image)[i].b = static_cast(((*cloud)[i].b + 255) / 2); (*label_image)[i].r = 0; (*label_image)[i].g = 0; (*label_image)[i].b = 255; diff --git a/apps/src/test_search.cpp b/apps/src/test_search.cpp index da14b536a32..e561ce51d70 100644 --- a/apps/src/test_search.cpp +++ b/apps/src/test_search.cpp @@ -55,9 +55,9 @@ main(int argc, char** argv) query.y = 0.5; query.z = 0.5; - std::vector kd_indices; + pcl::Indices kd_indices; std::vector kd_distances; - std::vector bf_indices; + pcl::Indices bf_indices; std::vector bf_distances; double start, stop; diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 00000000000..6fccc23f74f --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,25 @@ +set(SUBSYS_NAME benchmarks) +set(SUBSYS_DESC "Point cloud library benchmarks") +set(SUBSYS_DEPS common filters features search kdtree io) +set(DEFAULT OFF) +set(build TRUE) +set(REASON "Disabled by default") +PCL_SUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSYS_DESC}" ${DEFAULT} "${REASON}") +PCL_SUBSYS_DEPEND(build "${SUBSYS_NAME}" DEPS ${SUBSYS_DEPS}) +if(NOT build) + return() +endif() + +find_package(benchmark REQUIRED) +add_custom_target(run_benchmarks) + +PCL_ADD_BENCHMARK(features_normal_3d FILES features/normal_3d.cpp + LINK_WITH pcl_io pcl_search pcl_features + ARGUMENTS "${PCL_SOURCE_DIR}/test/table_scene_mug_stereo_textured.pcd" + "${PCL_SOURCE_DIR}/test/milk_cartoon_all_small_clorox.pcd") + +PCL_ADD_BENCHMARK(filters_voxel_grid FILES filters/voxel_grid.cpp + LINK_WITH pcl_io pcl_filters + ARGUMENTS "${PCL_SOURCE_DIR}/test/table_scene_mug_stereo_textured.pcd" + "${PCL_SOURCE_DIR}/test/milk_cartoon_all_small_clorox.pcd") + diff --git a/benchmarks/features/normal_3d.cpp b/benchmarks/features/normal_3d.cpp new file mode 100644 index 00000000000..958a0cd4342 --- /dev/null +++ b/benchmarks/features/normal_3d.cpp @@ -0,0 +1,69 @@ +#include // for NormalEstimation +#include // for NormalEstimationOMP +#include // for PCDReader + +#include + +static void +BM_NormalEstimation(benchmark::State& state, const std::string& file) +{ + // Perform setup here + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + pcl::PCDReader reader; + reader.read(file, *cloud); + pcl::NormalEstimation ne; + ne.setInputCloud(cloud); + ne.setKSearch(state.range(0)); + pcl::PointCloud::Ptr cloud_normals(new pcl::PointCloud); + for (auto _ : state) { + // This code gets timed + ne.compute(*cloud_normals); + } +} + +#ifdef _OPENMP +static void +BM_NormalEstimationOMP(benchmark::State& state, const std::string& file) +{ + // Perform setup here + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + pcl::PCDReader reader; + reader.read(file, *cloud); + pcl::NormalEstimationOMP ne; + ne.setInputCloud(cloud); + ne.setKSearch(100); + pcl::PointCloud::Ptr cloud_normals(new pcl::PointCloud); + for (auto _ : state) { + // This code gets timed + ne.compute(*cloud_normals); + } +} +#endif + +int +main(int argc, char** argv) +{ + if (argc < 3) { + std::cerr + << "No test files given. Please download `table_scene_mug_stereo_textured.pcd` " + "and `milk_cartoon_all_small_clorox.pcd`, and pass their paths to the test." + << std::endl; + return (-1); + } + benchmark::RegisterBenchmark("BM_NormalEstimation_mug", &BM_NormalEstimation, argv[1]) + ->Arg(50) + ->Arg(100) + ->Unit(benchmark::kMillisecond); + benchmark::RegisterBenchmark( + "BM_NormalEstimation_milk", &BM_NormalEstimation, argv[2]) + ->Arg(50) + ->Arg(100) + ->Unit(benchmark::kMillisecond); +#ifdef _OPENMP + benchmark::RegisterBenchmark( + "BM_NormalEstimationOMP", &BM_NormalEstimationOMP, argv[1]) + ->Unit(benchmark::kMillisecond); +#endif + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/benchmarks/filters/voxel_grid.cpp b/benchmarks/filters/voxel_grid.cpp new file mode 100644 index 00000000000..066cacc6980 --- /dev/null +++ b/benchmarks/filters/voxel_grid.cpp @@ -0,0 +1,72 @@ +#include +#include +#include // for PCDReader + +#include + +static void +BM_VoxelGrid(benchmark::State& state, const std::string& file) +{ + // Perform setup here + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + pcl::PCDReader reader; + reader.read(file, *cloud); + + pcl::VoxelGrid vg; + vg.setLeafSize(0.01, 0.01, 0.01); + vg.setInputCloud(cloud); + + pcl::PointCloud::Ptr cloud_voxelized( + new pcl::PointCloud); + for (auto _ : state) { + // This code gets timed + vg.filter(*cloud_voxelized); + } +} + +static void +BM_ApproxVoxelGrid(benchmark::State& state, const std::string& file) +{ + // Perform setup here + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + pcl::PCDReader reader; + reader.read(file, *cloud); + + pcl::ApproximateVoxelGrid avg; + avg.setLeafSize(0.01, 0.01, 0.01); + avg.setInputCloud(cloud); + + pcl::PointCloud::Ptr cloud_voxelized( + new pcl::PointCloud); + for (auto _ : state) { + // This code gets timed + avg.filter(*cloud_voxelized); + } +} + +int +main(int argc, char** argv) +{ + if (argc < 3) { + std::cerr + << "No test files given. Please download `table_scene_mug_stereo_textured.pcd` " + "and `milk_cartoon_all_small_clorox.pcd`, and pass their paths to the test." + << std::endl; + return (-1); + } + + benchmark::RegisterBenchmark("BM_VoxelGrid_milk", &BM_VoxelGrid, argv[2]) + ->Unit(benchmark::kMillisecond); + benchmark::RegisterBenchmark( + "BM_ApproximateVoxelGrid_milk", &BM_ApproxVoxelGrid, argv[2]) + ->Unit(benchmark::kMillisecond); + + benchmark::RegisterBenchmark("BM_VoxelGrid_mug", &BM_VoxelGrid, argv[1]) + ->Unit(benchmark::kMillisecond); + benchmark::RegisterBenchmark( + "BM_ApproximateVoxelGrid_mug", &BM_ApproxVoxelGrid, argv[1]) + ->Unit(benchmark::kMillisecond); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/cmake/CudaComputeTargetFlags.cmake b/cmake/CudaComputeTargetFlags.cmake deleted file mode 100644 index 928c664c5a0..00000000000 --- a/cmake/CudaComputeTargetFlags.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# -# Compute target flags macros by Anatoly Baksheev -# -# Usage in CmakeLists.txt: -# include(CudaComputeTargetFlags.cmake) -# APPEND_TARGET_ARCH_FLAGS() - -#compute flags macros -macro(CUDA_COMPUTE_TARGET_FLAGS arch_bin arch_ptx cuda_nvcc_target_flags) - string(REGEX REPLACE "\\." "" ARCH_BIN_WITHOUT_DOTS "${${arch_bin}}") - string(REGEX REPLACE "\\." "" ARCH_PTX_WITHOUT_DOTS "${${arch_ptx}}") - - set(cuda_computer_target_flags_temp "") - - # Tell NVCC to add binaries for the specified GPUs - string(REGEX MATCHALL "[0-9()]+" ARCH_LIST "${ARCH_BIN_WITHOUT_DOTS}") - foreach(ARCH IN LISTS ARCH_LIST) - if(ARCH MATCHES "([0-9]+)\\(([0-9]+)\\)") - # User explicitly specified PTX for the concrete BIN - set(cuda_computer_target_flags_temp ${cuda_computer_target_flags_temp} -gencode arch=compute_${CMAKE_MATCH_2},code=sm_${CMAKE_MATCH_1}) - else() - # User didn't explicitly specify PTX for the concrete BIN, we assume PTX=BIN - set(cuda_computer_target_flags_temp ${cuda_computer_target_flags_temp} -gencode arch=compute_${ARCH},code=sm_${ARCH}) - endif() - endforeach() - - # Tell NVCC to add PTX intermediate code for the specified architectures - string(REGEX MATCHALL "[0-9]+" ARCH_LIST "${ARCH_PTX_WITHOUT_DOTS}") - foreach(ARCH IN LISTS ARCH_LIST) - set(cuda_computer_target_flags_temp ${cuda_computer_target_flags_temp} -gencode arch=compute_${ARCH},code=compute_${ARCH}) - endforeach() - - set(${cuda_nvcc_target_flags} ${cuda_computer_target_flags_temp}) -endmacro() - -macro(APPEND_TARGET_ARCH_FLAGS) - set(cuda_nvcc_target_flags "") - CUDA_COMPUTE_TARGET_FLAGS(CUDA_ARCH_BIN CUDA_ARCH_PTX cuda_nvcc_target_flags) - if(cuda_nvcc_target_flags) - message(STATUS "CUDA NVCC target flags: ${cuda_nvcc_target_flags}") - list(APPEND CUDA_NVCC_FLAGS ${cuda_nvcc_target_flags}) - endif() -endmacro() diff --git a/cmake/Modules/FindFLANN.cmake b/cmake/Modules/FindFLANN.cmake index fd15d1bb75f..9b46b2256f7 100644 --- a/cmake/Modules/FindFLANN.cmake +++ b/cmake/Modules/FindFLANN.cmake @@ -42,16 +42,38 @@ endif() # First try to locate FLANN using modern config find_package(flann NO_MODULE ${FLANN_FIND_VERSION} QUIET) + if(flann_FOUND) unset(flann_FOUND) set(FLANN_FOUND ON) + # Create interface library that effectively becomes an alias for the appropriate (static/dynamic) imported FLANN target add_library(FLANN::FLANN INTERFACE IMPORTED) - if(FLANN_USE_STATIC) + + if(TARGET flann::flann_cpp_s AND TARGET flann::flann_cpp) + if(PCL_FLANN_REQUIRED_TYPE MATCHES "SHARED") + set_property(TARGET FLANN::FLANN APPEND PROPERTY INTERFACE_LINK_LIBRARIES flann::flann_cpp) + set(FLANN_LIBRARY_TYPE SHARED) + elseif(PCL_FLANN_REQUIRED_TYPE MATCHES "STATIC") + set_property(TARGET FLANN::FLANN APPEND PROPERTY INTERFACE_LINK_LIBRARIES flann::flann_cpp_s) + set(FLANN_LIBRARY_TYPE STATIC) + else() + if(PCL_SHARED_LIBS) + set_property(TARGET FLANN::FLANN APPEND PROPERTY INTERFACE_LINK_LIBRARIES flann::flann_cpp) + set(FLANN_LIBRARY_TYPE SHARED) + else() + set_property(TARGET FLANN::FLANN APPEND PROPERTY INTERFACE_LINK_LIBRARIES flann::flann_cpp_s) + set(FLANN_LIBRARY_TYPE STATIC) + endif() + endif() + elseif(TARGET flann::flann_cpp_s) set_property(TARGET FLANN::FLANN APPEND PROPERTY INTERFACE_LINK_LIBRARIES flann::flann_cpp_s) + set(FLANN_LIBRARY_TYPE STATIC) else() set_property(TARGET FLANN::FLANN APPEND PROPERTY INTERFACE_LINK_LIBRARIES flann::flann_cpp) + set(FLANN_LIBRARY_TYPE SHARED) endif() + # Determine FLANN installation root based on the path to the processed Config file get_filename_component(_config_dir "${flann_CONFIG}" DIRECTORY) get_filename_component(FLANN_ROOT "${_config_dir}/../../.." ABSOLUTE) @@ -82,19 +104,23 @@ find_path(FLANN_INCLUDE_DIR include ) -if(FLANN_USE_STATIC) - set(FLANN_RELEASE_NAME flann_cpp_s) - set(FLANN_DEBUG_NAME flann_cpp_s-gd) - set(FLANN_LIBRARY_TYPE STATIC) -else() - set(FLANN_RELEASE_NAME flann_cpp) - set(FLANN_DEBUG_NAME flann_cpp-gd) - set(FLANN_LIBRARY_TYPE SHARED) -endif() +find_library(FLANN_LIBRARY_SHARED + NAMES + flann_cpp + HINTS + ${PC_FLANN_LIBRARY_DIRS} + ${FLANN_ROOT} + $ENV{FLANN_ROOT} + PATHS + $ENV{PROGRAMFILES}/Flann + $ENV{PROGRAMW6432}/Flann + PATH_SUFFIXES + lib +) -find_library(FLANN_LIBRARY +find_library(FLANN_LIBRARY_DEBUG_SHARED NAMES - ${FLANN_RELEASE_NAME} + flann_cpp-gd flann_cppd HINTS ${PC_FLANN_LIBRARY_DIRS} ${FLANN_ROOT} @@ -106,9 +132,9 @@ find_library(FLANN_LIBRARY lib ) -find_library(FLANN_LIBRARY_DEBUG +find_library(FLANN_LIBRARY_STATIC NAMES - ${FLANN_DEBUG_NAME} + flann_cpp_s HINTS ${PC_FLANN_LIBRARY_DIRS} ${FLANN_ROOT} @@ -120,6 +146,44 @@ find_library(FLANN_LIBRARY_DEBUG lib ) +find_library(FLANN_LIBRARY_DEBUG_STATIC + NAMES + flann_cpp_s-gd flann_cpp_sd + HINTS + ${PC_FLANN_LIBRARY_DIRS} + ${FLANN_ROOT} + $ENV{FLANN_ROOT} + PATHS + $ENV{PROGRAMFILES}/Flann + $ENV{PROGRAMW6432}/Flann + PATH_SUFFIXES + lib +) + +if(FLANN_LIBRARY_SHARED AND FLANN_LIBRARY_STATIC) + if(PCL_FLANN_REQUIRED_TYPE MATCHES "SHARED") + set(FLANN_LIBRARY_TYPE SHARED) + set(FLANN_LIBRARY ${FLANN_LIBRARY_SHARED}) + elseif(PCL_FLANN_REQUIRED_TYPE MATCHES "STATIC") + set(FLANN_LIBRARY_TYPE STATIC) + set(FLANN_LIBRARY ${FLANN_LIBRARY_STATIC}) + else() + if(PCL_SHARED_LIBS) + set(FLANN_LIBRARY_TYPE SHARED) + set(FLANN_LIBRARY ${FLANN_LIBRARY_SHARED}) + else() + set(FLANN_LIBRARY_TYPE STATIC) + set(FLANN_LIBRARY ${FLANN_LIBRARY_STATIC}) + endif() + endif() +elseif(FLANN_LIBRARY_STATIC) + set(FLANN_LIBRARY_TYPE STATIC) + set(FLANN_LIBRARY ${FLANN_LIBRARY_STATIC}) +elseif(FLANN_LIBRARY_SHARED) + set(FLANN_LIBRARY_TYPE SHARED) + set(FLANN_LIBRARY ${FLANN_LIBRARY_SHARED}) +endif() + include(FindPackageHandleStandardArgs) find_package_handle_standard_args( FLANN DEFAULT_MSG @@ -132,7 +196,7 @@ if(FLANN_FOUND) set_target_properties(FLANN::FLANN PROPERTIES INTERFACE_COMPILE_DEFINITIONS "${PC_FLANN_CFLAGS_OTHER}") set_property(TARGET FLANN::FLANN APPEND PROPERTY IMPORTED_CONFIGURATIONS "RELEASE") set_target_properties(FLANN::FLANN PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX") - if(WIN32 AND NOT FLANN_USE_STATIC) + if(WIN32 AND (NOT FLANN_LIBRARY_TYPE MATCHES "STATIC")) set_target_properties(FLANN::FLANN PROPERTIES IMPORTED_IMPLIB_RELEASE "${FLANN_LIBRARY}") else() set_target_properties(FLANN::FLANN PROPERTIES IMPORTED_LOCATION_RELEASE "${FLANN_LIBRARY}") @@ -140,7 +204,7 @@ if(FLANN_FOUND) if(FLANN_LIBRARY_DEBUG) set_property(TARGET FLANN::FLANN APPEND PROPERTY IMPORTED_CONFIGURATIONS "DEBUG") set_target_properties(FLANN::FLANN PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX") - if(WIN32 AND NOT FLANN_USE_STATIC) + if(WIN32 AND (NOT FLANN_LIBRARY_TYPE MATCHES "STATIC")) set_target_properties(FLANN::FLANN PROPERTIES IMPORTED_IMPLIB_DEBUG "${FLANN_LIBRARY_DEBUG}") else() set_target_properties(FLANN::FLANN PROPERTIES IMPORTED_LOCATION_DEBUG "${FLANN_LIBRARY_DEBUG}") @@ -154,4 +218,5 @@ if(FLANN_FOUND) endif() endforeach() get_filename_component(FLANN_ROOT "${FLANN_INCLUDE_DIR}" PATH) + message(STATUS "FLANN found (include: ${FLANN_INCLUDE_DIR}, lib: ${FLANN_LIBRARY})") endif() diff --git a/cmake/Modules/FindOpenMP.cmake b/cmake/Modules/FindOpenMP.cmake new file mode 100644 index 00000000000..cd17a179fcf --- /dev/null +++ b/cmake/Modules/FindOpenMP.cmake @@ -0,0 +1,617 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: + +FindOpenMP is added to PCL local Cmake modules due to bug in earlier version. +TODO: Can be removed when Cmake 3.11 is required. +See https://gitlab.kitware.com/cmake/cmake/-/issues/20364 + +FindOpenMP +---------- + +Finds Open Multi-Processing (OpenMP) support. + +This module can be used to detect OpenMP support in a compiler. If +the compiler supports OpenMP, the flags required to compile with +OpenMP support are returned in variables for the different languages. +The variables may be empty if the compiler does not need a special +flag to support OpenMP. + +Variables +^^^^^^^^^ + +The module exposes the components ``C``, ``CXX``, and ``Fortran``. +Each of these controls the various languages to search OpenMP support for. + +Depending on the enabled components the following variables will be set: + +``OpenMP_FOUND`` + Variable indicating that OpenMP flags for all requested languages have been found. + If no components are specified, this is true if OpenMP settings for all enabled languages + were detected. +``OpenMP_VERSION`` + Minimal version of the OpenMP standard detected among the requested languages, + or all enabled languages if no components were specified. + +This module will set the following variables per language in your +project, where ```` is one of C, CXX, or Fortran: + +``OpenMP__FOUND`` + Variable indicating if OpenMP support for ```` was detected. +``OpenMP__FLAGS`` + OpenMP compiler flags for ````, separated by spaces. +``OpenMP__INCLUDE_DIRS`` + Directories that must be added to the header search path for ```` + when using OpenMP. + +For linking with OpenMP code written in ````, the following +variables are provided: + +``OpenMP__LIB_NAMES`` + :ref:`;-list ` of libraries for OpenMP programs for ````. +``OpenMP__LIBRARY`` + Location of the individual libraries needed for OpenMP support in ````. +``OpenMP__LIBRARIES`` + A list of libraries needed to link with OpenMP code written in ````. + +Additionally, the module provides :prop_tgt:`IMPORTED` targets: + +``OpenMP::OpenMP_`` + Target for using OpenMP from ````. + +Specifically for Fortran, the module sets the following variables: + +``OpenMP_Fortran_HAVE_OMPLIB_HEADER`` + Boolean indicating if OpenMP is accessible through ``omp_lib.h``. +``OpenMP_Fortran_HAVE_OMPLIB_MODULE`` + Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module. + +The module will also try to provide the OpenMP version variables: + +``OpenMP__SPEC_DATE`` + Date of the OpenMP specification implemented by the ```` compiler. +``OpenMP__VERSION_MAJOR`` + Major version of OpenMP implemented by the ```` compiler. +``OpenMP__VERSION_MINOR`` + Minor version of OpenMP implemented by the ```` compiler. +``OpenMP__VERSION`` + OpenMP version implemented by the ```` compiler. + +The specification date is formatted as given in the OpenMP standard: +``yyyymm`` where ``yyyy`` and ``mm`` represents the year and month of +the OpenMP specification implemented by the ```` compiler. + +For some compilers, it may be necessary to add a header search path to find +the relevant OpenMP headers. This location may be language-specific. Where +this is needed, the module may attempt to find the location, but it can be +provided directly by setting the ``OpenMP__INCLUDE_DIR`` cache variable. +Note that this variable is an _input_ control to the module. Project code +should use the ``OpenMP__INCLUDE_DIRS`` _output_ variable if it needs +to know what include directories are needed. +#]=======================================================================] + +cmake_policy(PUSH) +cmake_policy(SET CMP0012 NEW) # if() recognizes numbers and booleans +cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced +cmake_policy(SET CMP0057 NEW) # if IN_LIST + +function(_OPENMP_FLAG_CANDIDATES LANG) + if(NOT OpenMP_${LANG}_FLAG) + unset(OpenMP_FLAG_CANDIDATES) + + set(OMP_FLAG_GNU "-fopenmp") + set(OMP_FLAG_Clang "-fopenmp=libomp" "-fopenmp=libiomp5" "-fopenmp" "-Xclang -fopenmp") + set(OMP_FLAG_AppleClang "-Xclang -fopenmp") + set(OMP_FLAG_HP "+Oopenmp") + if(WIN32) + set(OMP_FLAG_Intel "-Qopenmp") + elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Intel" AND + "${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS "15.0.0.20140528") + set(OMP_FLAG_Intel "-openmp") + else() + set(OMP_FLAG_Intel "-qopenmp") + endif() + set(OMP_FLAG_MSVC "-openmp") + set(OMP_FLAG_PathScale "-openmp") + set(OMP_FLAG_NAG "-openmp") + set(OMP_FLAG_Absoft "-openmp") + set(OMP_FLAG_PGI "-mp") + set(OMP_FLAG_Flang "-fopenmp") + set(OMP_FLAG_SunPro "-xopenmp") + set(OMP_FLAG_XL "-qsmp=omp") + # Cray compiler activate OpenMP with -h omp, which is enabled by default. + set(OMP_FLAG_Cray " " "-h omp") + + # If we know the correct flags, use those + if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}) + set(OpenMP_FLAG_CANDIDATES "${OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID}}") + # Fall back to reasonable default tries otherwise + else() + set(OpenMP_FLAG_CANDIDATES "-openmp" "-fopenmp" "-mp" " ") + endif() + set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_FLAG_CANDIDATES}" PARENT_SCOPE) + else() + set(OpenMP_${LANG}_FLAG_CANDIDATES "${OpenMP_${LANG}_FLAG}" PARENT_SCOPE) + endif() +endfunction() + +# sample openmp source code to test +set(OpenMP_C_CXX_TEST_SOURCE +" +#include +int main(void) { +#ifdef _OPENMP + omp_get_max_threads(); + return 0; +#elif defined(__HIP_DEVICE_COMPILE__) + return 0; +#else + breaks_on_purpose +#endif +} +") + +# in Fortran, an implementation may provide an omp_lib.h header +# or omp_lib module, or both (OpenMP standard, section 3.1) +# Furthmore !$ is the Fortran equivalent of #ifdef _OPENMP (OpenMP standard, 2.2.2) +# Without the conditional compilation, some compilers (e.g. PGI) might compile OpenMP code +# while not actually enabling OpenMP, building code sequentially +set(OpenMP_Fortran_TEST_SOURCE + " + program test + @OpenMP_Fortran_INCLUDE_LINE@ + !$ integer :: n + n = omp_get_num_threads() + end program test + " +) + +function(_OPENMP_WRITE_SOURCE_FILE LANG SRC_FILE_CONTENT_VAR SRC_FILE_NAME SRC_FILE_FULLPATH) + set(WORK_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP) + if("${LANG}" STREQUAL "C") + set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.c") + file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}") + elseif("${LANG}" STREQUAL "CXX") + set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.cpp") + file(WRITE "${SRC_FILE}" "${OpenMP_C_CXX_${SRC_FILE_CONTENT_VAR}}") + elseif("${LANG}" STREQUAL "Fortran") + set(SRC_FILE "${WORK_DIR}/${SRC_FILE_NAME}.f90") + file(WRITE "${SRC_FILE}_in" "${OpenMP_Fortran_${SRC_FILE_CONTENT_VAR}}") + configure_file("${SRC_FILE}_in" "${SRC_FILE}" @ONLY) + endif() + set(${SRC_FILE_FULLPATH} "${SRC_FILE}" PARENT_SCOPE) +endfunction() + +include(CMakeParseImplicitLinkInfo) + +function(_OPENMP_GET_FLAGS LANG FLAG_MODE OPENMP_FLAG_VAR OPENMP_LIB_NAMES_VAR) + _OPENMP_FLAG_CANDIDATES("${LANG}") + _OPENMP_WRITE_SOURCE_FILE("${LANG}" "TEST_SOURCE" OpenMPTryFlag _OPENMP_TEST_SRC) + + unset(OpenMP_VERBOSE_COMPILE_OPTIONS) + separate_arguments(OpenMP_VERBOSE_OPTIONS NATIVE_COMMAND "${CMAKE_${LANG}_VERBOSE_FLAG}") + foreach(_VERBOSE_OPTION IN LISTS OpenMP_VERBOSE_OPTIONS) + if(NOT _VERBOSE_OPTION MATCHES "^-Wl,") + list(APPEND OpenMP_VERBOSE_COMPILE_OPTIONS ${_VERBOSE_OPTION}) + endif() + endforeach() + + foreach(OPENMP_FLAG IN LISTS OpenMP_${LANG}_FLAG_CANDIDATES) + set(OPENMP_FLAGS_TEST "${OPENMP_FLAG}") + if(OpenMP_VERBOSE_COMPILE_OPTIONS) + string(APPEND OPENMP_FLAGS_TEST " ${OpenMP_VERBOSE_COMPILE_OPTIONS}") + endif() + string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}") + try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" + LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} + OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT + ) + + if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) + set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE) + + if(CMAKE_${LANG}_VERBOSE_FLAG) + unset(OpenMP_${LANG}_IMPLICIT_LIBRARIES) + unset(OpenMP_${LANG}_IMPLICIT_LINK_DIRS) + unset(OpenMP_${LANG}_IMPLICIT_FWK_DIRS) + unset(OpenMP_${LANG}_LOG_VAR) + + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Detecting ${LANG} OpenMP compiler ABI info compiled with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n") + + cmake_parse_implicit_link_info("${OpenMP_TRY_COMPILE_OUTPUT}" + OpenMP_${LANG}_IMPLICIT_LIBRARIES + OpenMP_${LANG}_IMPLICIT_LINK_DIRS + OpenMP_${LANG}_IMPLICIT_FWK_DIRS + OpenMP_${LANG}_LOG_VAR + "${CMAKE_${LANG}_IMPLICIT_OBJECT_REGEX}" + ) + + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Parsed ${LANG} OpenMP implicit link information from above output:\n${OpenMP_${LANG}_LOG_VAR}\n\n") + + unset(_OPENMP_LIB_NAMES) + foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_IMPLICIT_LIBRARIES) + get_filename_component(_OPENMP_IMPLICIT_LIB_DIR "${_OPENMP_IMPLICIT_LIB}" DIRECTORY) + get_filename_component(_OPENMP_IMPLICIT_LIB_NAME "${_OPENMP_IMPLICIT_LIB}" NAME) + get_filename_component(_OPENMP_IMPLICIT_LIB_PLAIN "${_OPENMP_IMPLICIT_LIB}" NAME_WE) + string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PLAIN_ESC "${_OPENMP_IMPLICIT_LIB_PLAIN}") + string(REGEX REPLACE "([][+.*?()^$])" "\\\\\\1" _OPENMP_IMPLICIT_LIB_PATH_ESC "${_OPENMP_IMPLICIT_LIB}") + if(NOT ( "${_OPENMP_IMPLICIT_LIB}" IN_LIST CMAKE_${LANG}_IMPLICIT_LINK_LIBRARIES + OR "${CMAKE_${LANG}_STANDARD_LIBRARIES}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" + OR "${CMAKE_${LANG}_LINK_EXECUTABLE}" MATCHES "(^| )(-Wl,)?(-l)?(${_OPENMP_IMPLICIT_LIB_PLAIN_ESC}|${_OPENMP_IMPLICIT_LIB_PATH_ESC})( |$)" ) ) + if(_OPENMP_IMPLICIT_LIB_DIR) + set(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY "${_OPENMP_IMPLICIT_LIB}" CACHE FILEPATH + "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP") + else() + find_library(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY + NAMES "${_OPENMP_IMPLICIT_LIB_NAME}" + DOC "Path to the ${_OPENMP_IMPLICIT_LIB_PLAIN} library for OpenMP" + HINTS ${OpenMP_${LANG}_IMPLICIT_LINK_DIRS} + CMAKE_FIND_ROOT_PATH_BOTH + NO_DEFAULT_PATH + ) + endif() + mark_as_advanced(OpenMP_${_OPENMP_IMPLICIT_LIB_PLAIN}_LIBRARY) + list(APPEND _OPENMP_LIB_NAMES ${_OPENMP_IMPLICIT_LIB_PLAIN}) + endif() + endforeach() + set("${OPENMP_LIB_NAMES_VAR}" "${_OPENMP_LIB_NAMES}" PARENT_SCOPE) + else() + # We do not know how to extract implicit OpenMP libraries for this compiler. + # Assume that it handles them automatically, e.g. the Intel Compiler on + # Windows should put the dependency in its object files. + set("${OPENMP_LIB_NAMES_VAR}" "" PARENT_SCOPE) + endif() + break() + elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "AppleClang" + AND CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0") + + # Check for separate OpenMP library on AppleClang 7+ + find_library(OpenMP_libomp_LIBRARY + NAMES omp gomp iomp5 + HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES} + ) + mark_as_advanced(OpenMP_libomp_LIBRARY) + + if(OpenMP_libomp_LIBRARY) + # Try without specifying include directory first. We only want to + # explicitly add a search path if the header can't be found on the + # default header search path already. + try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" + LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY} + OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT + ) + if(NOT OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) + find_path(OpenMP_${LANG}_INCLUDE_DIR omp.h) + mark_as_advanced(OpenMP_${LANG}_INCLUDE_DIR) + set(OpenMP_${LANG}_INCLUDE_DIR "${OpenMP_${LANG}_INCLUDE_DIR}" PARENT_SCOPE) + if(OpenMP_${LANG}_INCLUDE_DIR) + try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" + "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}" + LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY} + OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT + ) + endif() + endif() + if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) + set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE) + set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE) + break() + endif() + endif() + elseif(CMAKE_${LANG}_COMPILER_ID STREQUAL "Clang" AND WIN32) + # Check for separate OpenMP library for Clang on Windows + find_library(OpenMP_libomp_LIBRARY + NAMES libomp libgomp libiomp5 + HINTS ${CMAKE_${LANG}_IMPLICIT_LINK_DIRECTORIES} + ) + mark_as_advanced(OpenMP_libomp_LIBRARY) + if(OpenMP_libomp_LIBRARY) + try_compile( OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG} ${CMAKE_BINARY_DIR} ${_OPENMP_TEST_SRC} + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OPENMP_FLAGS_TEST}" + LINK_LIBRARIES ${CMAKE_${LANG}_VERBOSE_FLAG} ${OpenMP_libomp_LIBRARY} + OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT + ) + if(OpenMP_COMPILE_RESULT_${FLAG_MODE}_${OPENMP_PLAIN_FLAG}) + set("${OPENMP_FLAG_VAR}" "${OPENMP_FLAG}" PARENT_SCOPE) + set("${OPENMP_LIB_NAMES_VAR}" "libomp" PARENT_SCOPE) + break() + endif() + endif() + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Detecting ${LANG} OpenMP failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n") + endif() + set("${OPENMP_LIB_NAMES_VAR}" "NOTFOUND" PARENT_SCOPE) + set("${OPENMP_FLAG_VAR}" "NOTFOUND" PARENT_SCOPE) + endforeach() + + unset(OpenMP_VERBOSE_COMPILE_OPTIONS) +endfunction() + +set(OpenMP_C_CXX_CHECK_VERSION_SOURCE +" +#include +#include +const char ompver_str[] = { 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', + 'P', '-', 'd', 'a', 't', 'e', '[', + ('0' + ((_OPENMP/100000)%10)), + ('0' + ((_OPENMP/10000)%10)), + ('0' + ((_OPENMP/1000)%10)), + ('0' + ((_OPENMP/100)%10)), + ('0' + ((_OPENMP/10)%10)), + ('0' + ((_OPENMP/1)%10)), + ']', '\\0' }; +int main(void) +{ + puts(ompver_str); + return 0; +} +") + +set(OpenMP_Fortran_CHECK_VERSION_SOURCE +" + program omp_ver + @OpenMP_Fortran_INCLUDE_LINE@ + integer, parameter :: zero = ichar('0') + integer, parameter :: ompv = openmp_version + character, dimension(24), parameter :: ompver_str =& + (/ 'I', 'N', 'F', 'O', ':', 'O', 'p', 'e', 'n', 'M', 'P', '-',& + 'd', 'a', 't', 'e', '[',& + char(zero + mod(ompv/100000, 10)),& + char(zero + mod(ompv/10000, 10)),& + char(zero + mod(ompv/1000, 10)),& + char(zero + mod(ompv/100, 10)),& + char(zero + mod(ompv/10, 10)),& + char(zero + mod(ompv/1, 10)), ']' /) + print *, ompver_str + end program omp_ver +") + +function(_OPENMP_GET_SPEC_DATE LANG SPEC_DATE) + _OPENMP_WRITE_SOURCE_FILE("${LANG}" "CHECK_VERSION_SOURCE" OpenMPCheckVersion _OPENMP_TEST_SRC) + + unset(_includeDirFlags) + if(OpenMP_${LANG}_INCLUDE_DIR) + set(_includeDirFlags "-DINCLUDE_DIRECTORIES:STRING=${OpenMP_${LANG}_INCLUDE_DIR}") + endif() + + set(BIN_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/FindOpenMP/ompver_${LANG}.bin") + string(REGEX REPLACE "[-/=+]" "" OPENMP_PLAIN_FLAG "${OPENMP_FLAG}") + try_compile(OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG} "${CMAKE_BINARY_DIR}" "${_OPENMP_TEST_SRC}" + CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=${OpenMP_${LANG}_FLAGS}" ${_includeDirFlags} + COPY_FILE ${BIN_FILE} + OUTPUT_VARIABLE OpenMP_TRY_COMPILE_OUTPUT) + + if(${OpenMP_SPECTEST_${LANG}_${OPENMP_PLAIN_FLAG}}) + file(STRINGS ${BIN_FILE} specstr LIMIT_COUNT 1 REGEX "INFO:OpenMP-date") + set(regex_spec_date ".*INFO:OpenMP-date\\[0*([^]]*)\\].*") + if("${specstr}" MATCHES "${regex_spec_date}") + set(${SPEC_DATE} "${CMAKE_MATCH_1}" PARENT_SCOPE) + endif() + else() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Detecting ${LANG} OpenMP version failed with the following output:\n${OpenMP_TRY_COMPILE_OUTPUT}\n\n") + endif() +endfunction() + +macro(_OPENMP_SET_VERSION_BY_SPEC_DATE LANG) + set(OpenMP_SPEC_DATE_MAP + # Preview versions + "201611=5.0" # OpenMP 5.0 preview 1 + # Combined versions, 2.5 onwards + "201811=5.0" + "201511=4.5" + "201307=4.0" + "201107=3.1" + "200805=3.0" + "200505=2.5" + # C/C++ version 2.0 + "200203=2.0" + # Fortran version 2.0 + "200011=2.0" + # Fortran version 1.1 + "199911=1.1" + # C/C++ version 1.0 (there's no 1.1 for C/C++) + "199810=1.0" + # Fortran version 1.0 + "199710=1.0" + ) + if(MSVC) + list(APPEND OpenMP_SPEC_DATE_MAP "2019=2.0") + endif() + + if(OpenMP_${LANG}_SPEC_DATE) + string(REGEX MATCHALL "${OpenMP_${LANG}_SPEC_DATE}=([0-9]+)\\.([0-9]+)" _version_match "${OpenMP_SPEC_DATE_MAP}") + else() + set(_version_match "") + endif() + if(NOT _version_match STREQUAL "") + set(OpenMP_${LANG}_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(OpenMP_${LANG}_VERSION_MINOR ${CMAKE_MATCH_2}) + set(OpenMP_${LANG}_VERSION "${OpenMP_${LANG}_VERSION_MAJOR}.${OpenMP_${LANG}_VERSION_MINOR}") + else() + unset(OpenMP_${LANG}_VERSION_MAJOR) + unset(OpenMP_${LANG}_VERSION_MINOR) + unset(OpenMP_${LANG}_VERSION) + endif() + unset(_version_match) + unset(OpenMP_SPEC_DATE_MAP) +endmacro() + +foreach(LANG IN ITEMS C CXX) + if(CMAKE_${LANG}_COMPILER_LOADED) + if(NOT DEFINED OpenMP_${LANG}_FLAGS OR "${OpenMP_${LANG}_FLAGS}" STREQUAL "NOTFOUND" + OR NOT DEFINED OpenMP_${LANG}_LIB_NAMES OR "${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND") + _OPENMP_GET_FLAGS("${LANG}" "${LANG}" OpenMP_${LANG}_FLAGS_WORK OpenMP_${LANG}_LIB_NAMES_WORK) + set(OpenMP_${LANG}_FLAGS "${OpenMP_${LANG}_FLAGS_WORK}" + CACHE STRING "${LANG} compiler flags for OpenMP parallelization" FORCE) + set(OpenMP_${LANG}_LIB_NAMES "${OpenMP_${LANG}_LIB_NAMES_WORK}" + CACHE STRING "${LANG} compiler libraries for OpenMP parallelization" FORCE) + mark_as_advanced(OpenMP_${LANG}_FLAGS OpenMP_${LANG}_LIB_NAMES) + endif() + endif() +endforeach() + +if(CMAKE_Fortran_COMPILER_LOADED) + if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND" + OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND" + OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE) + set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none") + _OPENMP_GET_FLAGS("Fortran" "FortranHeader" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK) + if(OpenMP_Fortran_FLAGS_WORK) + set(OpenMP_Fortran_HAVE_OMPLIB_MODULE TRUE CACHE BOOL INTERNAL "") + endif() + + set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}" + CACHE STRING "Fortran compiler flags for OpenMP parallelization") + set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES_WORK}" + CACHE STRING "Fortran compiler libraries for OpenMP parallelization") + mark_as_advanced(OpenMP_Fortran_FLAGS OpenMP_Fortran_LIB_NAMES) + endif() + + if(NOT DEFINED OpenMP_Fortran_FLAGS OR "${OpenMP_Fortran_FLAGS}" STREQUAL "NOTFOUND" + OR NOT DEFINED OpenMP_Fortran_LIB_NAMES OR "${OpenMP_Fortran_LIB_NAMES}" STREQUAL "NOTFOUND" + OR NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER) + set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'") + _OPENMP_GET_FLAGS("Fortran" "FortranModule" OpenMP_Fortran_FLAGS_WORK OpenMP_Fortran_LIB_NAMES_WORK) + if(OpenMP_Fortran_FLAGS_WORK) + set(OpenMP_Fortran_HAVE_OMPLIB_HEADER TRUE CACHE BOOL INTERNAL "") + endif() + + set(OpenMP_Fortran_FLAGS "${OpenMP_Fortran_FLAGS_WORK}" + CACHE STRING "Fortran compiler flags for OpenMP parallelization") + + set(OpenMP_Fortran_LIB_NAMES "${OpenMP_Fortran_LIB_NAMES}" + CACHE STRING "Fortran compiler libraries for OpenMP parallelization") + endif() + + if(OpenMP_Fortran_HAVE_OMPLIB_MODULE) + set(OpenMP_Fortran_INCLUDE_LINE "use omp_lib\n implicit none") + else() + set(OpenMP_Fortran_INCLUDE_LINE "implicit none\n include 'omp_lib.h'") + endif() +endif() + +if(NOT OpenMP_FIND_COMPONENTS) + set(OpenMP_FINDLIST C CXX Fortran) +else() + set(OpenMP_FINDLIST ${OpenMP_FIND_COMPONENTS}) +endif() + +unset(_OpenMP_MIN_VERSION) + +include(FindPackageHandleStandardArgs) + +foreach(LANG IN LISTS OpenMP_FINDLIST) + if(CMAKE_${LANG}_COMPILER_LOADED) + if (NOT OpenMP_${LANG}_SPEC_DATE AND OpenMP_${LANG}_FLAGS) + _OPENMP_GET_SPEC_DATE("${LANG}" OpenMP_${LANG}_SPEC_DATE_INTERNAL) + set(OpenMP_${LANG}_SPEC_DATE "${OpenMP_${LANG}_SPEC_DATE_INTERNAL}" CACHE + INTERNAL "${LANG} compiler's OpenMP specification date") + endif() + _OPENMP_SET_VERSION_BY_SPEC_DATE("${LANG}") + + set(OpenMP_${LANG}_FIND_QUIETLY ${OpenMP_FIND_QUIETLY}) + set(OpenMP_${LANG}_FIND_REQUIRED ${OpenMP_FIND_REQUIRED}) + set(OpenMP_${LANG}_FIND_VERSION ${OpenMP_FIND_VERSION}) + set(OpenMP_${LANG}_FIND_VERSION_EXACT ${OpenMP_FIND_VERSION_EXACT}) + + set(_OPENMP_${LANG}_REQUIRED_VARS OpenMP_${LANG}_FLAGS) + if("${OpenMP_${LANG}_LIB_NAMES}" STREQUAL "NOTFOUND") + set(_OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${LANG}_LIB_NAMES) + else() + foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES) + list(APPEND _OPENMP_${LANG}_REQUIRED_LIB_VARS OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY) + endforeach() + endif() + + if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.17") + find_package_handle_standard_args(OpenMP_${LANG} + NAME_MISMATCHED + REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS} + VERSION_VAR OpenMP_${LANG}_VERSION + ) + else() + find_package_handle_standard_args(OpenMP_${LANG} + REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS} + VERSION_VAR OpenMP_${LANG}_VERSION + ) + endif() + + if(OpenMP_${LANG}_FOUND) + if(DEFINED OpenMP_${LANG}_VERSION) + if(NOT _OpenMP_MIN_VERSION OR _OpenMP_MIN_VERSION VERSION_GREATER OpenMP_${LANG}_VERSION) + set(_OpenMP_MIN_VERSION OpenMP_${LANG}_VERSION) + endif() + endif() + set(OpenMP_${LANG}_LIBRARIES "") + foreach(_OPENMP_IMPLICIT_LIB IN LISTS OpenMP_${LANG}_LIB_NAMES) + list(APPEND OpenMP_${LANG}_LIBRARIES "${OpenMP_${_OPENMP_IMPLICIT_LIB}_LIBRARY}") + endforeach() + if(OpenMP_${LANG}_INCLUDE_DIR) + set(OpenMP_${LANG}_INCLUDE_DIRS ${OpenMP_${LANG}_INCLUDE_DIR}) + else() + set(OpenMP_${LANG}_INCLUDE_DIRS "") + endif() + + if(NOT TARGET OpenMP::OpenMP_${LANG}) + add_library(OpenMP::OpenMP_${LANG} INTERFACE IMPORTED) + endif() + if(OpenMP_${LANG}_FLAGS) + separate_arguments(_OpenMP_${LANG}_OPTIONS NATIVE_COMMAND "${OpenMP_${LANG}_FLAGS}") + set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY + INTERFACE_COMPILE_OPTIONS "$<$:${_OpenMP_${LANG}_OPTIONS}>") + unset(_OpenMP_${LANG}_OPTIONS) + endif() + if(OpenMP_${LANG}_INCLUDE_DIRS) + set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "$") + endif() + if(OpenMP_${LANG}_LIBRARIES) + set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY + INTERFACE_LINK_LIBRARIES "${OpenMP_${LANG}_LIBRARIES}") + endif() + endif() + endif() +endforeach() + +unset(_OpenMP_REQ_VARS) +foreach(LANG IN ITEMS C CXX Fortran) + if((NOT OpenMP_FIND_COMPONENTS AND CMAKE_${LANG}_COMPILER_LOADED) OR LANG IN_LIST OpenMP_FIND_COMPONENTS) + list(APPEND _OpenMP_REQ_VARS "OpenMP_${LANG}_FOUND") + endif() +endforeach() + +find_package_handle_standard_args(OpenMP + REQUIRED_VARS ${_OpenMP_REQ_VARS} + VERSION_VAR ${_OpenMP_MIN_VERSION} + HANDLE_COMPONENTS) + +set(OPENMP_FOUND ${OpenMP_FOUND}) + +if(CMAKE_Fortran_COMPILER_LOADED AND OpenMP_Fortran_FOUND) + if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_MODULE) + set(OpenMP_Fortran_HAVE_OMPLIB_MODULE FALSE CACHE BOOL INTERNAL "") + endif() + if(NOT DEFINED OpenMP_Fortran_HAVE_OMPLIB_HEADER) + set(OpenMP_Fortran_HAVE_OMPLIB_HEADER FALSE CACHE BOOL INTERNAL "") + endif() +endif() + +if(NOT ( CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED )) + message(SEND_ERROR "FindOpenMP requires the C, CXX or Fortran languages to be enabled") +endif() + +unset(OpenMP_C_CXX_TEST_SOURCE) +unset(OpenMP_Fortran_TEST_SOURCE) +unset(OpenMP_C_CXX_CHECK_VERSION_SOURCE) +unset(OpenMP_Fortran_CHECK_VERSION_SOURCE) +unset(OpenMP_Fortran_INCLUDE_LINE) + +cmake_policy(POP) diff --git a/cmake/Modules/FindOpenNI.cmake b/cmake/Modules/FindOpenNI.cmake index 09a6081138a..e86ab40b2ab 100644 --- a/cmake/Modules/FindOpenNI.cmake +++ b/cmake/Modules/FindOpenNI.cmake @@ -11,30 +11,6 @@ # OPENNI_DEFINITIONS Compiler flags for OpenNI find_package(PkgConfig QUIET) - -# Find LibUSB -if(NOT WIN32) - pkg_check_modules(PC_USB_10 libusb-1.0) - find_path(USB_10_INCLUDE_DIR libusb-1.0/libusb.h - HINTS ${PC_USB_10_INCLUDEDIR} ${PC_USB_10_INCLUDE_DIRS} "${USB_10_ROOT}" "$ENV{USB_10_ROOT}" - PATH_SUFFIXES libusb-1.0) - - find_library(USB_10_LIBRARY - NAMES usb-1.0 - HINTS ${PC_USB_10_LIBDIR} ${PC_USB_10_LIBRARY_DIRS} "${USB_10_ROOT}" "$ENV{USB_10_ROOT}" - PATH_SUFFIXES lib) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(USB_10 DEFAULT_MSG USB_10_LIBRARY USB_10_INCLUDE_DIR) - - if(NOT USB_10_FOUND) - message(STATUS "OpenNI disabled because libusb-1.0 not found.") - return() - else() - include_directories(SYSTEM ${USB_10_INCLUDE_DIR}) - endif() -endif() - pkg_check_modules(PC_OPENNI QUIET libopenni) set(OPENNI_DEFINITIONS ${PC_OPENNI_CFLAGS_OTHER}) @@ -75,8 +51,9 @@ if(OPENNI_INCLUDE_DIR AND OPENNI_LIBRARY) mark_as_advanced(OPENNI_INCLUDE_DIRS) # Libraries - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set(OPENNI_LIBRARIES ${OPENNI_LIBRARY} ${LIBUSB_1_LIBRARIES}) + if(NOT WIN32) + find_package(libusb REQUIRED) + set(OPENNI_LIBRARIES ${OPENNI_LIBRARY} libusb::libusb) else() set(OPENNI_LIBRARIES ${OPENNI_LIBRARY}) endif() @@ -85,12 +62,24 @@ if(OPENNI_INCLUDE_DIR AND OPENNI_LIBRARY) endif() +if(EXISTS "${OPENNI_INCLUDE_DIR}/XnVersion.h") + file(STRINGS "${OPENNI_INCLUDE_DIR}/XnVersion.h" _contents REGEX "^#define[ \t]+XN_[A-Z]+_VERSION[ \t]+[0-9]+") + if(_contents) + string(REGEX REPLACE ".*#define[ \t]+XN_MAJOR_VERSION[ \t]+([0-9]+).*" "\\1" OPENNI_VERSION_MAJOR "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+XN_MINOR_VERSION[ \t]+([0-9]+).*" "\\1" OPENNI_VERSION_MINOR "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+XN_MAINTENANCE_VERSION[ \t]+([0-9]+).*" "\\1" OPENNI_VERSION_PATCH "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+XN_BUILD_VERSION[ \t]+([0-9]+).*" "\\1" OPENNI_VERSION_BUILD "${_contents}") + set(OPENNI_VERSION "${OPENNI_VERSION_MAJOR}.${OPENNI_VERSION_MINOR}.${OPENNI_VERSION_PATCH}.${OPENNI_VERSION_BUILD}") + endif() +endif() + include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenNI FOUND_VAR OPENNI_FOUND REQUIRED_VARS OPENNI_LIBRARIES OPENNI_INCLUDE_DIRS + VERSION_VAR OPENNI_VERSION ) if(OPENNI_FOUND) - message(STATUS "OpenNI found (include: ${OPENNI_INCLUDE_DIRS}, lib: ${OPENNI_LIBRARIES})") + message(STATUS "OpenNI found (version: ${OPENNI_VERSION}, include: ${OPENNI_INCLUDE_DIRS}, lib: ${OPENNI_LIBRARIES})") endif() diff --git a/cmake/Modules/FindOpenNI2.cmake b/cmake/Modules/FindOpenNI2.cmake index 10263311293..5ab50743b4e 100644 --- a/cmake/Modules/FindOpenNI2.cmake +++ b/cmake/Modules/FindOpenNI2.cmake @@ -11,30 +11,6 @@ # OPENNI2_DEFINITIONS Compiler flags for OpenNI2 find_package(PkgConfig QUIET) - -# Find LibUSB -if(NOT WIN32) - pkg_check_modules(PC_USB_10 libusb-1.0) - find_path(USB_10_INCLUDE_DIR libusb-1.0/libusb.h - HINTS ${PC_USB_10_INCLUDEDIR} ${PC_USB_10_INCLUDE_DIRS} "${USB_10_ROOT}" "$ENV{USB_10_ROOT}" - PATH_SUFFIXES libusb-1.0) - - find_library(USB_10_LIBRARY - NAMES usb-1.0 - HINTS ${PC_USB_10_LIBDIR} ${PC_USB_10_LIBRARY_DIRS} "${USB_10_ROOT}" "$ENV{USB_10_ROOT}" - PATH_SUFFIXES lib) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(USB_10 DEFAULT_MSG USB_10_LIBRARY USB_10_INCLUDE_DIR) - - if(NOT USB_10_FOUND) - message(STATUS "OpenNI 2 disabled because libusb-1.0 not found.") - return() - else() - include_directories(SYSTEM ${USB_10_INCLUDE_DIR}) - endif() -endif() - pkg_check_modules(PC_OPENNI2 QUIET libopenni2) set(OPENNI2_DEFINITIONS ${PC_OPENNI_CFLAGS_OTHER}) @@ -65,8 +41,9 @@ if(OPENNI2_INCLUDE_DIR AND OPENNI2_LIBRARY) mark_as_advanced(OPENNI2_INCLUDE_DIRS) # Libraries - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set(OPENNI2_LIBRARIES ${OPENNI2_LIBRARY} ${LIBUSB_1_LIBRARIES}) + if(NOT WIN32) + find_package(libusb REQUIRED) + set(OPENNI2_LIBRARIES ${OPENNI2_LIBRARY} libusb::libusb) else() set(OPENNI2_LIBRARIES ${OPENNI2_LIBRARY}) endif() @@ -78,12 +55,24 @@ if(OPENNI2_INCLUDE_DIR AND OPENNI2_LIBRARY) endif() +if(EXISTS "${OPENNI2_INCLUDE_DIR}/OniVersion.h") + file(STRINGS "${OPENNI2_INCLUDE_DIR}/OniVersion.h" _contents REGEX "^#define[ \t]+ONI_VERSION_[A-Z]+[ \t]+[0-9]+") + if(_contents) + string(REGEX REPLACE ".*#define[ \t]+ONI_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" OPENNI2_VERSION_MAJOR "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+ONI_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" OPENNI2_VERSION_MINOR "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+ONI_VERSION_MAINTENANCE[ \t]+([0-9]+).*" "\\1" OPENNI2_VERSION_PATCH "${_contents}") + string(REGEX REPLACE ".*#define[ \t]+ONI_VERSION_BUILD[ \t]+([0-9]+).*" "\\1" OPENNI2_VERSION_BUILD "${_contents}") + set(OPENNI2_VERSION "${OPENNI2_VERSION_MAJOR}.${OPENNI2_VERSION_MINOR}.${OPENNI2_VERSION_PATCH}.${OPENNI2_VERSION_BUILD}") + endif() +endif() + include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenNI2 FOUND_VAR OPENNI2_FOUND REQUIRED_VARS OPENNI2_LIBRARIES OPENNI2_INCLUDE_DIRS + VERSION_VAR OPENNI2_VERSION ) if(OPENNI2_FOUND) - message(STATUS "OpenNI2 found (include: ${OPENNI2_INCLUDE_DIRS}, lib: ${OPENNI2_LIBRARIES})") + message(STATUS "OpenNI2 found (version: ${OPENNI2_VERSION}, include: ${OPENNI2_INCLUDE_DIRS}, lib: ${OPENNI2_LIBRARIES})") endif() diff --git a/cmake/Modules/FindQhull.cmake b/cmake/Modules/FindQhull.cmake old mode 100644 new mode 100755 index 7f3cf90dc11..5368c1dcbf7 --- a/cmake/Modules/FindQhull.cmake +++ b/cmake/Modules/FindQhull.cmake @@ -1,39 +1,99 @@ -############################################################################### -# Find QHULL +#.rst: +# FindQhull +# -------- +# +# Try to find QHULL library and headers. This module supports both old released versions +# of QHULL ≤ 7.3.2 and newer development versions that ship with a modern config file, +# but its limited to only the reentrant version of Qhull. +# +# PCL_QHULL_REQUIRED_TYPE can be used to select if you want static or shared libraries, but it defaults to "don't care". +# +# IMPORTED Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines the :prop_tgt:`IMPORTED` targets: +# +# ``QHULL::QHULL`` +# Defined if the system has QHULL. +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module sets the following variables: +# +# :: +# +# QHULL_FOUND True in case QHULL is found, otherwise false +# +# Example usage +# ^^^^^^^^^^^^^ +# +# :: +# +# find_package(QHULL REQUIRED) +# +# add_executable(foo foo.cc) +# target_link_libraries(foo QHULL::QHULL) # -# This sets the following variables: -# QHULL_FOUND - True if QHULL was found. -# QHULL_INCLUDE_DIRS - Directories containing the QHULL include files. -# QHULL_LIBRARIES - Libraries needed to use QHULL. -# QHULL_DEFINITIONS - Compiler flags for QHULL. -# If QHULL_USE_STATIC is specified then look for static libraries ONLY else -# look for shared ones -set(QHULL_MAJOR_VERSION 6) +# Skip if QHULL::QHULL is already defined +if(TARGET QHULL::QHULL) + return() +endif() -if(QHULL_USE_STATIC) - set(QHULL_RELEASE_NAME qhullstatic) - set(QHULL_DEBUG_NAME qhullstatic_d) -else() - set(QHULL_RELEASE_NAME qhull_p qhull${QHULL_MAJOR_VERSION} qhull) - set(QHULL_DEBUG_NAME qhull_p_d qhull${QHULL_MAJOR_VERSION}_d qhull_d${QHULL_MAJOR_VERSION} qhull_d) +# Try to locate QHull using modern cmake config (available on latest Qhull version). +find_package(Qhull CONFIG QUIET) + +if(Qhull_FOUND) + unset(Qhull_FOUND) + set(QHULL_FOUND ON) + set(HAVE_QHULL ON) + + message(STATUS "Found Qhull version ${Qhull_VERSION}") + + # Create interface library that effectively becomes an alias for the appropriate (static/dynamic) imported QHULL target + add_library(QHULL::QHULL INTERFACE IMPORTED) + + if(TARGET Qhull::qhull_r AND TARGET Qhull::qhullstatic_r) + if(PCL_QHULL_REQUIRED_TYPE MATCHES "SHARED") + set_property(TARGET QHULL::QHULL APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qhull::qhull_r) + set(QHULL_LIBRARY_TYPE SHARED) + elseif(PCL_QHULL_REQUIRED_TYPE MATCHES "STATIC") + set_property(TARGET QHULL::QHULL APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qhull::qhullstatic_r) + set(QHULL_LIBRARY_TYPE STATIC) + else() + if(PCL_SHARED_LIBS) + set_property(TARGET QHULL::QHULL APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qhull::qhull_r) + set(QHULL_LIBRARY_TYPE SHARED) + else() + set_property(TARGET QHULL::QHULL APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qhull::qhullstatic_r) + set(QHULL_LIBRARY_TYPE STATIC) + endif() + endif() + elseif(TARGET Qhull::qhullstatic_r) + set_property(TARGET QHULL::QHULL APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qhull::qhullstatic_r) + set(QHULL_LIBRARY_TYPE STATIC) + else() + set_property(TARGET QHULL::QHULL APPEND PROPERTY INTERFACE_LINK_LIBRARIES Qhull::qhull_r) + set(QHULL_LIBRARY_TYPE SHARED) + endif() + + return() endif() find_file(QHULL_HEADER - NAMES libqhull/libqhull.h qhull.h + NAMES libqhull_r.h HINTS "${QHULL_ROOT}" "$ENV{QHULL_ROOT}" "${QHULL_INCLUDE_DIR}" PATHS "$ENV{PROGRAMFILES}/QHull" "$ENV{PROGRAMW6432}/QHull" - PATH_SUFFIXES qhull src/libqhull libqhull include) + PATH_SUFFIXES qhull_r src/libqhull_r libqhull_r include) set(QHULL_HEADER "${QHULL_HEADER}" CACHE INTERNAL "QHull header" FORCE ) if(QHULL_HEADER) get_filename_component(qhull_header ${QHULL_HEADER} NAME_WE) - if("${qhull_header}" STREQUAL "qhull") - set(HAVE_QHULL_2011 OFF) + if("${qhull_header}" STREQUAL "qhull_r") get_filename_component(QHULL_INCLUDE_DIR ${QHULL_HEADER} PATH) - elseif("${qhull_header}" STREQUAL "libqhull") - set(HAVE_QHULL_2011 ON) + elseif("${qhull_header}" STREQUAL "libqhull_r") get_filename_component(QHULL_INCLUDE_DIR ${QHULL_HEADER} PATH) get_filename_component(QHULL_INCLUDE_DIR ${QHULL_INCLUDE_DIR} PATH) endif() @@ -41,54 +101,82 @@ else() set(QHULL_INCLUDE_DIR "QHULL_INCLUDE_DIR-NOTFOUND") endif() -find_library(QHULL_LIBRARY - NAMES ${QHULL_RELEASE_NAME} +find_library(QHULL_LIBRARY_SHARED + NAMES qhull_r qhull HINTS "${QHULL_ROOT}" "$ENV{QHULL_ROOT}" PATHS "$ENV{PROGRAMFILES}/QHull" "$ENV{PROGRAMW6432}/QHull" PATH_SUFFIXES project build bin lib) -get_filename_component(QHULL_LIBRARY_NAME "${QHULL_LIBRARY}" NAME) - find_library(QHULL_LIBRARY_DEBUG - NAMES ${QHULL_DEBUG_NAME} ${QHULL_RELEASE_NAME} + NAMES qhull_rd qhull_d HINTS "${QHULL_ROOT}" "$ENV{QHULL_ROOT}" PATHS "$ENV{PROGRAMFILES}/QHull" "$ENV{PROGRAMW6432}/QHull" PATH_SUFFIXES project build bin lib debug/lib) -if(NOT QHULL_LIBRARY_DEBUG) - set(QHULL_LIBRARY_DEBUG ${QHULL_LIBRARY}) -endif() - -get_filename_component(QHULL_LIBRARY_DEBUG_NAME "${QHULL_LIBRARY_DEBUG}" NAME) - -if(QHULL_INCLUDE_DIR AND QHULL_LIBRARY) - - # Include directories - set(QHULL_INCLUDE_DIRS ${QHULL_INCLUDE_DIR}) - unset(QHULL_INCLUDE_DIR) - mark_as_advanced(QHULL_INCLUDE_DIRS) +find_library(QHULL_LIBRARY_STATIC + NAMES qhullstatic_r + HINTS "${QHULL_ROOT}" "$ENV{QHULL_ROOT}" + PATHS "$ENV{PROGRAMFILES}/QHull" "$ENV{PROGRAMW6432}/QHull" + PATH_SUFFIXES project build bin lib) - # Libraries - set(QHULL_LIBRARIES optimized ${QHULL_LIBRARY} debug ${QHULL_LIBRARY_DEBUG}) - unset(QHULL_LIBRARY) - unset(QHULL_LIBRARY_DEBUG) - mark_as_advanced(QHULL_LIBRARIES) +find_library(QHULL_LIBRARY_DEBUG_STATIC + NAMES qhullstatic_rd + HINTS "${QHULL_ROOT}" "$ENV{QHULL_ROOT}" + PATHS "$ENV{PROGRAMFILES}/QHull" "$ENV{PROGRAMW6432}/QHull" + PATH_SUFFIXES project build bin lib debug/lib) +if(QHULL_LIBRARY_SHARED AND QHULL_LIBRARY_STATIC) + if(PCL_QHULL_REQUIRED_TYPE MATCHES "SHARED") + set(QHULL_LIBRARY_TYPE SHARED) + set(QHULL_LIBRARY ${QHULL_LIBRARY_SHARED}) + elseif(PCL_QHULL_REQUIRED_TYPE MATCHES "STATIC") + set(QHULL_LIBRARY_TYPE STATIC) + set(QHULL_LIBRARY ${QHULL_LIBRARY_STATIC}) + else() + if(PCL_SHARED_LIBS) + set(QHULL_LIBRARY_TYPE SHARED) + set(QHULL_LIBRARY ${QHULL_LIBRARY_SHARED}) + else() + set(QHULL_LIBRARY_TYPE STATIC) + set(QHULL_LIBRARY ${QHULL_LIBRARY_STATIC}) + endif() + endif() +elseif(QHULL_LIBRARY_STATIC) + set(QHULL_LIBRARY_TYPE STATIC) + set(QHULL_LIBRARY ${QHULL_LIBRARY_STATIC}) +elseif(QHULL_LIBRARY_SHARED) + set(QHULL_LIBRARY_TYPE SHARED) + set(QHULL_LIBRARY ${QHULL_LIBRARY_SHARED}) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Qhull FOUND_VAR QHULL_FOUND - REQUIRED_VARS QHULL_LIBRARIES QHULL_INCLUDE_DIRS + REQUIRED_VARS QHULL_LIBRARY QHULL_INCLUDE_DIR ) if(QHULL_FOUND) set(HAVE_QHULL ON) - if(NOT QHULL_USE_STATIC) - add_definitions("-Dqh_QHpointer") - if(MSVC) - add_definitions("-Dqh_QHpointer_dllimport") + add_library(QHULL::QHULL ${QHULL_LIBRARY_TYPE} IMPORTED) + set_target_properties(QHULL::QHULL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${QHULL_INCLUDE_DIR}") + set_property(TARGET QHULL::QHULL APPEND PROPERTY IMPORTED_CONFIGURATIONS "RELEASE") + set_target_properties(QHULL::QHULL PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX") + set_target_properties(QHULL::QHULL PROPERTIES INTERFACE_COMPILE_DEFINITIONS "qh_QHpointer") + if(MSVC) + set_target_properties(QHULL::QHULL PROPERTIES INTERFACE_COMPILE_DEFINITIONS "qh_QHpointer_dllimport") + endif() + if(WIN32 AND NOT (PCL_QHULL_REQUIRED_TYPE MATCHES "STATIC")) + set_target_properties(QHULL::QHULL PROPERTIES IMPORTED_IMPLIB_RELEASE "${QHULL_LIBRARY}") + else() + set_target_properties(QHULL::QHULL PROPERTIES IMPORTED_LOCATION_RELEASE "${QHULL_LIBRARY}") + endif() + if(QHULL_LIBRARY_DEBUG) + set_property(TARGET QHULL::QHULL APPEND PROPERTY IMPORTED_CONFIGURATIONS "DEBUG") + if(WIN32 AND NOT (PCL_QHULL_REQUIRED_TYPE MATCHES "STATIC")) + set_target_properties(QHULL::QHULL PROPERTIES IMPORTED_IMPLIB_DEBUG "${QHULL_LIBRARY_DEBUG}") + else() + set_target_properties(QHULL::QHULL PROPERTIES IMPORTED_LOCATION_DEBUG "${QHULL_LIBRARY_DEBUG}") endif() endif() - message(STATUS "QHULL found (include: ${QHULL_INCLUDE_DIRS}, lib: ${QHULL_LIBRARIES})") + message(STATUS "QHULL found (include: ${QHULL_INCLUDE_DIR}, lib: ${QHULL_LIBRARY})") endif() diff --git a/cmake/Modules/Findlibusb-1.0.cmake b/cmake/Modules/Findlibusb-1.0.cmake deleted file mode 100644 index 564eb8e300e..00000000000 --- a/cmake/Modules/Findlibusb-1.0.cmake +++ /dev/null @@ -1,72 +0,0 @@ -# - Try to find libusb-1.0 -# Once done this will define -# -# LIBUSB_1_FOUND - system has libusb -# LIBUSB_1_INCLUDE_DIRS - the libusb include directory -# LIBUSB_1_LIBRARIES - Link these to use libusb -# LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb -# -# Adapted from cmake-modules Google Code project -# -# Copyright (c) 2006 Andreas Schneider -# -# (Changes for libusb) Copyright (c) 2008 Kyle Machulis -# -# Point Cloud Library (PCL) - www.pointclouds.org -# Copyright (c) 2012, Willow Garage, Inc. (use of FindPackageHandleStandardArgs) -# -# Redistribution and use is allowed according to the terms of the New BSD license. -# -# CMake-Modules Project New BSD License -# -# 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 CMake-Modules Project 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. -# - -if(LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) - # in cache already - set(LIBUSB_FOUND TRUE) - set(LIBUSB_1_FOUND TRUE) -else() - find_path(LIBUSB_1_INCLUDE_DIR - NAMES libusb-1.0/libusb.h - PATHS /usr/include /usr/local/include /opt/local/include /sw/include - PATH_SUFFIXES libusb-1.0) - - # We need to look for libusb-1.0 too because find_library does not attempt to find - # library files with a "lib" prefix implicitly on Windows - find_library(LIBUSB_1_LIBRARY - NAMES usb-1.0 libusb-1.0 - PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib) - - set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR}) - set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY}) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(libusb-1.0 DEFAULT_MSG LIBUSB_1_LIBRARY LIBUSB_1_INCLUDE_DIR) - - # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view - mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) -endif() diff --git a/cmake/Modules/Findlibusb.cmake b/cmake/Modules/Findlibusb.cmake new file mode 100644 index 00000000000..aab82269018 --- /dev/null +++ b/cmake/Modules/Findlibusb.cmake @@ -0,0 +1,73 @@ +#.rst: +# Findlibusb +# -------- +# +# Try to find libusb library and headers. +# +# IMPORTED Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines the :prop_tgt:`IMPORTED` targets: +# +# ``libusb::libusb`` +# Defined if the system has libusb. +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module sets the following variables: +# +# :: +# +# LIBUSB_FOUND True in case libusb is found, otherwise false +# LIBUSB_ROOT Path to the root of found libusb installation +# +# Example usage +# ^^^^^^^^^^^^^ +# +# :: +# +# find_package(libusb REQUIRED) +# +# add_executable(foo foo.cc) +# target_link_libraries(foo libusb::libusb) +# + +# Early return if libusb target is already defined. This makes it safe to run +# this script multiple times. +if(TARGET libusb::libusb) + return() +endif() + +find_package(PkgConfig QUIET) +if(libusb_FIND_VERSION) + pkg_check_modules(PC_libusb libusb-1.0>=${libusb_FIND_VERSION}) +else() + pkg_check_modules(PC_libusb libusb-1.0) +endif() + +find_path(libusb_INCLUDE_DIR + NAMES + libusb-1.0/libusb.h + PATHS + ${PC_libusb_INCLUDEDIR} +) + +find_library(libusb_LIBRARIES + NAMES + usb-1.0 + libusb + PATHS + ${PC_libusb_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(libusb DEFAULT_MSG libusb_LIBRARIES libusb_INCLUDE_DIR) + +mark_as_advanced(libusb_INCLUDE_DIRS libusb_LIBRARIES) + +if(libusb_FOUND) + add_library(libusb::libusb UNKNOWN IMPORTED) + set_target_properties(libusb::libusb PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${libusb_INCLUDE_DIR}") + set_target_properties(libusb::libusb PROPERTIES IMPORTED_LOCATION "${libusb_LIBRARIES}") +endif() diff --git a/cmake/pcl_all_in_one_installer.cmake b/cmake/pcl_all_in_one_installer.cmake index 9d006a358f9..52309dc412b 100644 --- a/cmake/pcl_all_in_one_installer.cmake +++ b/cmake/pcl_all_in_one_installer.cmake @@ -7,13 +7,16 @@ if(NOT BUILD_all_in_one_installer) return() endif() -get_filename_component(BOOST_ROOT "${Boost_INCLUDE_DIR}" PATH) -get_filename_component(BOOST_ROOT "${BOOST_ROOT}" PATH) -get_filename_component(EIGEN_ROOT "${EIGEN_INCLUDE_DIRS}" PATH) -get_filename_component(QHULL_ROOT "${QHULL_INCLUDE_DIRS}" PATH) -get_filename_component(VTK_ROOT "${VTK_DIR}" PATH) -get_filename_component(VTK_ROOT "${VTK_ROOT}" PATH) -get_filename_component(VTK_ROOT "${VTK_ROOT}" PATH) +# get root directory of each dependency libraries to be copied to PCL/3rdParty +get_filename_component(BOOST_ROOT "${Boost_INCLUDE_DIR}" PATH) # ../Boost/include/boost-x_x/ -> ../Boost/include/ +get_filename_component(BOOST_ROOT "${BOOST_ROOT}" PATH) # ../Boost/include/ -> ../Boost/ +get_filename_component(EIGEN_ROOT "${EIGEN_INCLUDE_DIRS}" PATH) # ../Eigen3/include/ -> ../Eigen3/ +get_filename_component(QHULL_ROOT "${Qhull_DIR}" PATH) # ../qhull/lib/cmake/Qhull/ -> ../qhull/lib/cmake +get_filename_component(QHULL_ROOT "${QHULL_ROOT}" PATH) # ../qhull/lib/cmake/ -> ../qhull/lib/ +get_filename_component(QHULL_ROOT "${QHULL_ROOT}" PATH) # ../qhull/lib/ -> ../qhull/ +get_filename_component(VTK_ROOT "${VTK_DIR}" PATH) # ../VTK/lib/cmake/vtk-x.x/ -> ../VTK/lib/cmake/ +get_filename_component(VTK_ROOT "${VTK_ROOT}" PATH) # ../VTK/lib/cmake/ -> ../VTK/lib/ +get_filename_component(VTK_ROOT "${VTK_ROOT}" PATH) # ../VTK/lib/ -> ../VTK/ set(PCL_3RDPARTY_COMPONENTS) foreach(dep Eigen Boost Qhull FLANN VTK) diff --git a/cmake/pcl_cpack.cmake b/cmake/pcl_cpack.cmake index 5f036cd9825..b00433b2784 100644 --- a/cmake/pcl_cpack.cmake +++ b/cmake/pcl_cpack.cmake @@ -43,6 +43,8 @@ if(WIN32) string(APPEND CPACK_NSIS_PACKAGE_NAME "-msvc2017-${win_system_name}") elseif(MSVC_VERSION MATCHES "^192[0-9]$") string(APPEND CPACK_NSIS_PACKAGE_NAME "-msvc2019-${win_system_name}") + elseif(MSVC_VERSION MATCHES "^193[0-9]$") + string(APPEND CPACK_NSIS_PACKAGE_NAME "-msvc2022-${win_system_name}") else() string(APPEND CPACK_NSIS_PACKAGE_NAME "-${win_system_name}") endif() diff --git a/cmake/pcl_find_avx.cmake b/cmake/pcl_find_avx.cmake new file mode 100644 index 00000000000..f760a16393e --- /dev/null +++ b/cmake/pcl_find_avx.cmake @@ -0,0 +1,59 @@ +############################################################################### +# Check for the presence of AVX and figure out the flags to use for it. +function(PCL_CHECK_FOR_AVX) + set(AVX_FLAGS) + + include(CheckCXXSourceRuns) + + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) + # Setting -march & -mtune just as required flags for check_cxx_source_runs, + # and CMAKE_REQUIRED_FLAGS will be restored after test runs. + set(CMAKE_REQUIRED_FLAGS "-march=native -mtune=native") + endif() + + check_cxx_source_runs(" + #include + int main() + { + __m256i a = {0}; + a = _mm256_abs_epi16(a); + return 0; + }" + HAVE_AVX2) + + if(NOT HAVE_AVX2) + check_cxx_source_runs(" + #include + int main() + { + __m256 a; + a = _mm256_set1_ps(0); + return 0; + }" + HAVE_AVX) + endif() + + set(CMAKE_REQUIRED_FLAGS) + +# Setting the -mavx/-mavx2 defines __AVX(2)__, see here https://stackoverflow.com/a/28939692 +# and this allows the compiler to use the codes for AVX behind code guards. + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) + if(HAVE_AVX2) + set(AVX_FLAGS "-mavx2" PARENT_SCOPE) + elseif(HAVE_AVX) + set(AVX_FLAGS "-mavx" PARENT_SCOPE) + endif() + endif() + +# Setting the /arch defines __AVX(2)__, see here https://docs.microsoft.com/en-us/cpp/build/reference/arch-x64?view=msvc-160 +# AVX2 extends and includes AVX. +# Setting these defines allows the compiler to use AVX instructions as well as code guarded with the defines. +# TODO: Add AVX512 variant if needed. + if(MSVC) + if(HAVE_AVX2) + set(AVX_FLAGS "/arch:AVX2" PARENT_SCOPE) + elseif(HAVE_AVX) + set(AVX_FLAGS "/arch:AVX" PARENT_SCOPE) + endif() + endif() +endfunction() diff --git a/cmake/pcl_find_boost.cmake b/cmake/pcl_find_boost.cmake index f4eb87c54dd..7f32224bab1 100644 --- a/cmake/pcl_find_boost.cmake +++ b/cmake/pcl_find_boost.cmake @@ -14,30 +14,20 @@ else() endif() set(Boost_ADDITIONAL_VERSIONS - "1.75.0" "1.75" + "1.79.0" "1.79" "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74" "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" - "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" - "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" - "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55") - -# Disable the config mode of find_package(Boost) -set(Boost_NO_BOOST_CMAKE ON) + "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65") # Optional boost modules -find_package(Boost 1.55.0 QUIET COMPONENTS serialization mpi) +find_package(Boost 1.65.0 QUIET COMPONENTS serialization mpi) if(Boost_SERIALIZATION_FOUND) set(BOOST_SERIALIZATION_FOUND TRUE) endif() # Required boost modules set(BOOST_REQUIRED_MODULES filesystem date_time iostreams system) -find_package(Boost 1.55.0 REQUIRED COMPONENTS ${BOOST_REQUIRED_MODULES}) +find_package(Boost 1.65.0 REQUIRED COMPONENTS ${BOOST_REQUIRED_MODULES}) if(Boost_FOUND) set(BOOST_FOUND TRUE) - # Obtain diagnostic information about Boost's automatic linking outputted - # during compilation time. - add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) - include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) - link_directories(${Boost_LIBRARY_DIRS}) endif() diff --git a/cmake/pcl_find_cuda.cmake b/cmake/pcl_find_cuda.cmake index 58096b36b4a..21aeac2e1dc 100644 --- a/cmake/pcl_find_cuda.cmake +++ b/cmake/pcl_find_cuda.cmake @@ -1,5 +1,4 @@ # Find CUDA - if(MSVC) # Setting this to true brakes Visual Studio builds. set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE OFF CACHE BOOL "CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE") @@ -10,46 +9,55 @@ find_package(CUDA 9.0) if(CUDA_FOUND) message(STATUS "Found CUDA Toolkit v${CUDA_VERSION_STRING}") + + enable_language(CUDA) set(HAVE_CUDA TRUE) - # CUDA_ARCH_BIN is a space separated list of versions to include in output so-file. So you can set CUDA_ARCH_BIN = 10 11 12 13 20 - # Also user can specify virtual arch in parenthesis to limit instructions set, - # for example CUDA_ARCH_BIN = 11(11) 12(11) 13(11) 20(11) 21(11) -> forces using only sm_11 instructions. - # The CMake scripts interpret XX as XX (XX). This allows user to omit parenthesis. - # Arch 21 is an exceptional case since it doesn't have own sm_21 instructions set. - # So 21 = 21(21) is an invalid configuration and user has to explicitly force previous sm_20 instruction set via 21(20). - # CUDA_ARCH_BIN adds support of only listed GPUs. As alternative CMake scripts also parse 'CUDA_ARCH_PTX' variable, - # which is a list of intermediate PTX codes to include in final so-file. The PTX code can/will be JIT compiled for any current or future GPU. - # To add support of older GPU for kinfu, I would embed PTX 11 and 12 into so-file. GPU with sm_13 will run PTX 12 code (no difference for kinfu) - - # Find a complete list for CUDA compute capabilities at http://developer.nvidia.com/cuda-gpus - - # For a list showing CUDA toolkit version support for compute capabilities see: https://en.wikipedia.org/wiki/CUDA - # or the nvidia release notes ie: - # https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#cuda-general-new-features - # or - # https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#deprecated-features - - if(NOT ${CUDA_VERSION_STRING} VERSION_LESS "11.0") - set(__cuda_arch_bin "3.5 3.7 5.0 5.2 5.3 6.0 6.1 6.2 7.0 7.2 7.5 8.0") - elseif(NOT ${CUDA_VERSION_STRING} VERSION_LESS "10.0") - set(__cuda_arch_bin "3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.1 6.2 7.0 7.2 7.5") - elseif(NOT ${CUDA_VERSION_STRING} VERSION_LESS "9.0") - set(__cuda_arch_bin "3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.1 6.2 7.0 7.2") + if (CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") + if(${CUDA_VERSION_STRING} VERSION_GREATER_EQUAL "11.1") + execute_process(COMMAND ${CMAKE_CUDA_COMPILER} --list-gpu-code RESULT_VARIABLE EXIT_CODE OUTPUT_VARIABLE OUTPUT_VAL) + if(EXIT_CODE EQUAL 0) + #Remove sm_ + string(REPLACE "sm_" "" OUTPUT_VAL ${OUTPUT_VAL}) + #Convert to list + string(REPLACE "\n" ";" __CUDA_ARCH_BIN ${OUTPUT_VAL}) + #Remove last empty entry + list(REMOVE_AT __CUDA_ARCH_BIN -1) + else() + message(FATAL_ERROR "Failed to run NVCC to get list of GPU codes: ${EXIT_CODE}") + endif() + elseif(${CUDA_VERSION_STRING} VERSION_GREATER_EQUAL "11.0") + set(__CUDA_ARCH_BIN "35;37;50;52;53;60;61;62;70;72;75;80") + elseif(${CUDA_VERSION_STRING} VERSION_GREATER_EQUAL "10.0") + set(__CUDA_ARCH_BIN "30;32;35;37;50;52;53;60;61;62;70;72;75") + elseif(${CUDA_VERSION_STRING} VERSION_GREATER_EQUAL "9.1") + set(__CUDA_ARCH_BIN "30;32;35;37;50;52;53;60;61;62;70;72") + else() + set(__CUDA_ARCH_BIN "30;32;35;37;50;52;53;60;61;62;70") + endif() + else() + message(FATAL_ERROR "Unsupported CUDA compiler ${CMAKE_CUDA_COMPILER_ID}.") endif() - set(CUDA_ARCH_BIN ${__cuda_arch_bin} CACHE STRING "Specify 'real' GPU architectures to build binaries for, BIN(PTX) format is supported") - - set(CUDA_ARCH_PTX "" CACHE STRING "Specify 'virtual' PTX arch to build PTX intermediate code for. Example: 1.0 1.2 or 10 12") - #set(CUDA_ARCH_PTX "1.1 1.2" CACHE STRING "Specify 'virtual' PTX arch to build PTX intermediate code for. Example: 1.0 1.2 or 10 12") - - # Guess this macros will be included in cmake distributive - include(${PCL_SOURCE_DIR}/cmake/CudaComputeTargetFlags.cmake) - APPEND_TARGET_ARCH_FLAGS() - - # Prevent compilation issues between recent gcc versions and old CUDA versions - list(APPEND CUDA_NVCC_FLAGS "-D_FORCE_INLINES") + set(CUDA_ARCH_BIN ${__CUDA_ARCH_BIN} CACHE STRING "Specify 'real' GPU architectures to build binaries for") - # Allow calling a constexpr __host__ function from a __device__ function. - list(APPEND CUDA_NVCC_FLAGS "--expt-relaxed-constexpr") + if(POLICY CMP0104) + cmake_policy(SET CMP0104 NEW) + set(CMAKE_CUDA_ARCHITECTURES ${CUDA_ARCH_BIN}) + message(STATUS "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}") + + #Add empty project as its not required with newer CMake + add_library(pcl_cuda INTERFACE) + else() + # Generate SASS + set(CMAKE_CUDA_ARCHITECTURES ${CUDA_ARCH_BIN}) + # Generate PTX for last architecture + list(GET CUDA_ARCH_BIN -1 ver) + set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode arch=compute_${ver},code=compute_${ver}") + message(STATUS "CMAKE_CUDA_FLAGS: ${CMAKE_CUDA_FLAGS}") + + add_library(pcl_cuda INTERFACE) + target_include_directories(pcl_cuda INTERFACE ${CUDA_TOOLKIT_INCLUDE}) + + endif () endif() diff --git a/cmake/pcl_find_libusb.cmake b/cmake/pcl_find_libusb.cmake new file mode 100644 index 00000000000..666594b5493 --- /dev/null +++ b/cmake/pcl_find_libusb.cmake @@ -0,0 +1,34 @@ +# +#pcl_find_libusb is used due to VCPKG making impossible to use local findXX modules. +# and VCPKG findlibusb doesn't create the libusb targets. + +# Find and set libusb +find_package(libusb) + +if(TARGET libusb::libusb) + #libusb target is found by the find_package script. + #VCPKG skip PCLs findlibusb and sets its own variables which is handled below. + return() +endif() + +#Handle VCPKG definitions +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(libusb DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIRS) + +mark_as_advanced(LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES) + +if(libusb_FOUND) + add_library(libusb::libusb UNKNOWN IMPORTED) + if(${LIBUSB_INCLUDE_DIRS}) + set_target_properties(libusb::libusb PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBUSB_INCLUDE_DIRS}") + endif() + if(EXISTS "${LIBUSB_LIBRARY}") + set_target_properties(libusb::libusb PROPERTIES IMPORTED_LOCATION ${LIBUSB_LIBRARY}) + endif() + if(EXISTS "${LIBUSB_LIBRARY_DEBUG}") + set_target_properties(libusb::libusb PROPERTIES IMPORTED_LOCATION_DEBUG ${LIBUSB_LIBRARY_DEBUG}) + endif() + if(EXISTS "${LIBUSB_LIBRARY_RELEASE}") + set_target_properties(libusb::libusb PROPERTIES IMPORTED_LOCATION_RELEASE ${LIBUSB_LIBRARY_RELEASE}) + endif() +endif() diff --git a/cmake/pcl_find_qt.cmake b/cmake/pcl_find_qt.cmake new file mode 100644 index 00000000000..09192e30d1b --- /dev/null +++ b/cmake/pcl_find_qt.cmake @@ -0,0 +1,77 @@ +# This file is not processed if WITH_QT evaluates to a CMake false constant. +# +# First we convert WITH_QT to WITH_QT_STR with +# - CMake true constants to string YES (except numbers unequal 1) +# - Other values to upper case string +# +# Background: WITH_QT was previously boolean and we want to be backwards compatible. +# +# This if condition matches all CMake true constants (`${WITH_QT}`) except numbers other than 1 (`NOT (WITH_QT LESS 1 OR WITH_QT GREATER 1)`). +# +# This way we prevent things like -DWITH_QT=5 to be handled as YES instead of QT5. +# Setting -DWITH_QT=5 will error and inform you to use -DWITH_QT=QT5 instead. +# (This breaks backward compatibility, but hopefully no one will use values not equal to 1 if they want to express true.) +# +# Note: "NOT (WITH_QT LESS 1 OR WITH_QT GREATER 1)" is not the same as +# "WITH_QT EQUAL 1" because "LESS/GREATER/EQUAL" all pre-check if WITH_QT is a valid number. +if(${WITH_QT} AND NOT (WITH_QT LESS 1 OR WITH_QT GREATER 1)) + set(WITH_QT_STR "YES") +else() + string(TOUPPER ${WITH_QT} WITH_QT_STR) +endif() + +if(NOT WITH_QT_STR MATCHES "^(AUTO|YES|QT6|QT5)$") + message(FATAL_ERROR "Option WITH_QT must be one of AUTO|YES|QT6|QT5|NO but is '${WITH_QT}'") +endif() + +if(WITH_QT_STR MATCHES "^(AUTO|YES|QT6)$") + find_package(Qt6 QUIET COMPONENTS Concurrent OpenGL Widgets) + set(QT6_FOUND ${Qt6_FOUND}) + set(QT_FOUND ${QT6_FOUND}) + if (QT6_FOUND) + set(QTX Qt6) + endif() +endif() + +if(WITH_QT_STR MATCHES "^(AUTO|YES|QT5)$" AND NOT QT6_FOUND) + find_package(Qt5 5.9.5 QUIET COMPONENTS Concurrent OpenGL Widgets) + set(QT5_FOUND ${Qt5_FOUND}) + set(QT_FOUND ${QT5_FOUND}) + if(QT5_FOUND) + set(QTX Qt5) + endif() +endif() + +if(NOT WITH_QT_STR MATCHES "^(AUTO)$" AND NOT QT_FOUND) + message(FATAL_ERROR "Can not find Qt required by WITH_QT=${WITH_QT}.") +endif() + +if(NOT QT_FOUND) + message(STATUS "Qt is not found.") + return() +endif() + +set(QT_VERSION ${${QTX}_VERSION}) +message(STATUS "Qt version: ${QT_VERSION}") + +set(QT_DISABLE_PRECATED_BEFORE_VAL "0x050900") + +#Set Cmake Auto features to skip .hh files +if(POLICY CMP0100) + cmake_policy(SET CMP0100 OLD) +endif() + +#If building CUDA required libraries +#Change ${QTX}::Core fixed -fPIC flags to conditionally only CXX +#TODO: To be removed when QT is >5.14.1 +if(BUILD_CUDA OR BUILD_GPU) + if(${QTX}Widgets_VERSION VERSION_LESS 5.14.1) + get_property(core_options TARGET ${QTX}::Core PROPERTY INTERFACE_COMPILE_OPTIONS) + string(REPLACE "-fPIC" "$,-fPIC,>" new_core_options ${core_options}) + set_property(TARGET ${QTX}::Core PROPERTY INTERFACE_COMPILE_OPTIONS ${new_core_options}) + endif() +endif() + +get_property(core_def TARGET ${QTX}::Core PROPERTY INTERFACE_COMPILE_DEFINITIONS) +list(APPEND core_def "QT_DISABLE_DEPRECATED_BEFORE=${QT_DISABLE_PRECATED_BEFORE_VAL}") +set_property(TARGET ${QTX}::Core PROPERTY INTERFACE_COMPILE_DEFINITIONS ${core_def}) diff --git a/cmake/pcl_find_sse.cmake b/cmake/pcl_find_sse.cmake index b64f6bce0d6..25d1522bee1 100644 --- a/cmake/pcl_find_sse.cmake +++ b/cmake/pcl_find_sse.cmake @@ -1,210 +1,260 @@ ############################################################################### # Check for the presence of SSE and figure out the flags to use for it. -macro(PCL_CHECK_FOR_SSE) - set(SSE_FLAGS) - set(SSE_DEFINITIONS) - - if(NOT CMAKE_CROSSCOMPILING) - # Test GCC/G++ and CLANG - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - include(CheckCXXCompilerFlag) - check_cxx_compiler_flag("-march=native" HAVE_MARCH) - if(HAVE_MARCH) - list(APPEND SSE_FLAGS "-march=native") - else() - list(APPEND SSE_FLAGS "-mtune=native") - endif() - message(STATUS "Using CPU native flags for SSE optimization: ${SSE_FLAGS}") - endif() - endif() - - # Unfortunately we need to check for SSE to enable "-mfpmath=sse" alongside - # "-march=native". The reason for this is that by default, 32bit architectures - # tend to use the x87 FPU (which has 80 bit internal precision), thus leading - # to different results than 64bit architectures which are using SSE2 (64 bit internal - # precision). One solution would be to use "-ffloat-store" on 32bit (see - # http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html), but that slows code down, - # so the preferred solution is to try "-mpfmath=sse" first. - include(CheckCXXSourceRuns) - set(CMAKE_REQUIRED_FLAGS) +function(PCL_CHECK_FOR_SSE) + set(SSE_FLAGS) + set(SSE_DEFINITIONS) - check_cxx_source_runs(" - // Intel compiler defines an incompatible _mm_malloc signature - #if defined(__INTEL_COMPILER) - #include - #else - #include - #endif - int main() - { - void* mem = _mm_malloc (100, 16); - return 0; - }" - HAVE_MM_MALLOC) + if(PCL_ENABLE_MARCHNATIVE AND (NOT CMAKE_CROSSCOMPILING)) + # Test GCC/G++ and CLANG + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-march=native" HAVE_MARCH) + endif() + endif() - check_cxx_source_runs(" - #include - int main() - { - void* mem; - return posix_memalign (&mem, 16, 100); - }" - HAVE_POSIX_MEMALIGN) + # Unfortunately we need to check for SSE to enable "-mfpmath=sse" alongside + # "-march=native". The reason for this is that by default, 32bit architectures + # tend to use the x87 FPU (which has 80 bit internal precision), thus leading + # to different results than 64bit architectures which are using SSE2 (64 bit internal + # precision). One solution would be to use "-ffloat-store" on 32bit (see + # http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html), but that slows code down, + # so the preferred solution is to try "-mpfmath=sse" first. + include(CheckCXXSourceRuns) + set(CMAKE_REQUIRED_FLAGS) + set(SSE_LEVEL 0) + + check_cxx_source_runs(" + // Intel compiler defines an incompatible _mm_malloc signature + #if defined(__INTEL_COMPILER) + #include + #else + #include + #endif + int main() + { + void* mem = _mm_malloc (100, 16); + return 0; + }" + HAVE_MM_MALLOC) + + check_cxx_source_runs(" + #include + int main() + { + void* mem; + return posix_memalign (&mem, 16, 100); + }" + HAVE_POSIX_MEMALIGN) + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) + set(CMAKE_REQUIRED_FLAGS "-msse4.2") + endif() + + check_cxx_source_runs(" + #include + #include + int main () + { + long long a[2] = { 1, 2 }; + long long b[2] = { -1, 3 }; + long long c[2]; + __m128i va = _mm_loadu_si128 ((__m128i*)a); + __m128i vb = _mm_loadu_si128 ((__m128i*)b); + __m128i vc = _mm_cmpgt_epi64 (va, vb); + + _mm_storeu_si128 ((__m128i*)c, vc); + if (c[0] == -1LL && c[1] == 0LL) + return (0); + else + return (1); + }" + HAVE_SSE4_2_EXTENSIONS) + + if(HAVE_SSE4_2_EXTENSIONS) + set(SSE_LEVEL 4.2) + endif() + + if(SSE_LEVEL LESS 4.2) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - set(CMAKE_REQUIRED_FLAGS "-msse4.2") + set(CMAKE_REQUIRED_FLAGS "-msse4.1") endif() check_cxx_source_runs(" - #include - #include - int main () - { - long long a[2] = { 1, 2 }; - long long b[2] = { -1, 3 }; - long long c[2]; - __m128i va = _mm_loadu_si128 ((__m128i*)a); - __m128i vb = _mm_loadu_si128 ((__m128i*)b); - __m128i vc = _mm_cmpgt_epi64 (va, vb); - - _mm_storeu_si128 ((__m128i*)c, vc); - if (c[0] == -1LL && c[1] == 0LL) - return (0); - else - return (1); - }" - HAVE_SSE4_2_EXTENSIONS) + #include + int main () + { + __m128 a, b; + float vals[4] = {1, 2, 3, 4}; + const int mask = 123; + a = _mm_loadu_ps (vals); + b = a; + b = _mm_dp_ps (a, a, mask); + _mm_storeu_ps (vals,b); + return (0); + }" + HAVE_SSE4_1_EXTENSIONS) + + if(HAVE_SSE4_1_EXTENSIONS) + set(SSE_LEVEL 4.1) + endif() + endif() + if(SSE_LEVEL LESS 4.1) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - set(CMAKE_REQUIRED_FLAGS "-msse4.1") + set(CMAKE_REQUIRED_FLAGS "-mssse3") endif() - + check_cxx_source_runs(" - #include - int main () - { - __m128 a, b; - float vals[4] = {1, 2, 3, 4}; - const int mask = 123; - a = _mm_loadu_ps (vals); - b = a; - b = _mm_dp_ps (a, a, mask); - _mm_storeu_ps (vals,b); - return (0); - }" - HAVE_SSE4_1_EXTENSIONS) + #include + int main () + { + __m128i a, b; + int vals[4] = {-1, -2, -3, -4}; + a = _mm_loadu_si128 ((const __m128i*)vals); + b = _mm_abs_epi32 (a); + _mm_storeu_si128 ((__m128i*)vals, b); + return (0); + }" + HAVE_SSSE3_EXTENSIONS) + if(HAVE_SSSE3_EXTENSIONS) + set(SSE_LEVEL 3.1) + endif() + endif() + + if(SSE_LEVEL LESS 3.1) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - set(CMAKE_REQUIRED_FLAGS "-mssse3") + set(CMAKE_REQUIRED_FLAGS "-msse3") endif() check_cxx_source_runs(" - #include - int main () - { - __m128i a, b; - int vals[4] = {-1, -2, -3, -4}; - a = _mm_loadu_si128 ((const __m128i*)vals); - b = _mm_abs_epi32 (a); - _mm_storeu_si128 ((__m128i*)vals, b); + #include + int main () + { + __m128d a, b; + double vals[2] = {0}; + a = _mm_loadu_pd (vals); + b = _mm_hadd_pd (a,a); + _mm_storeu_pd (vals, b); return (0); - }" - HAVE_SSSE3_EXTENSIONS) + }" + HAVE_SSE3_EXTENSIONS) - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - set(CMAKE_REQUIRED_FLAGS "-msse3") + if(HAVE_SSE3_EXTENSIONS) + set( SSE_LEVEL 3.0) endif() + endif() - check_cxx_source_runs(" - #include - int main () - { - __m128d a, b; - double vals[2] = {0}; - a = _mm_loadu_pd (vals); - b = _mm_hadd_pd (a,a); - _mm_storeu_pd (vals, b); - return (0); - }" - HAVE_SSE3_EXTENSIONS) - + if(SSE_LEVEL LESS 3.0) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - set(CMAKE_REQUIRED_FLAGS "-msse2") + set(CMAKE_REQUIRED_FLAGS "-msse2") elseif(MSVC AND NOT CMAKE_CL_64) - set(CMAKE_REQUIRED_FLAGS "/arch:SSE2") + set(CMAKE_REQUIRED_FLAGS "/arch:SSE2") endif() check_cxx_source_runs(" - #include - int main () - { - __m128d a, b; - double vals[2] = {0}; - a = _mm_loadu_pd (vals); - b = _mm_add_pd (a,a); - _mm_storeu_pd (vals,b); - return (0); - }" - HAVE_SSE2_EXTENSIONS) + #include + int main () + { + __m128d a, b; + double vals[2] = {0}; + a = _mm_loadu_pd (vals); + b = _mm_add_pd (a,a); + _mm_storeu_pd (vals,b); + return (0); + }" + HAVE_SSE2_EXTENSIONS) + if(HAVE_SSE2_EXTENSIONS) + set(SSE_LEVEL 2.0) + endif() + endif() + + if(SSE_LEVEL LESS 2.0) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - set(CMAKE_REQUIRED_FLAGS "-msse") + set(CMAKE_REQUIRED_FLAGS "-msse") elseif(MSVC AND NOT CMAKE_CL_64) - set(CMAKE_REQUIRED_FLAGS "/arch:SSE") + set(CMAKE_REQUIRED_FLAGS "/arch:SSE") endif() check_cxx_source_runs(" - #include - int main () - { - __m128 a, b; - float vals[4] = {0}; - a = _mm_loadu_ps (vals); - b = a; - b = _mm_add_ps (a,b); - _mm_storeu_ps (vals,b); - return (0); - }" - HAVE_SSE_EXTENSIONS) - - set(CMAKE_REQUIRED_FLAGS) + #include + int main () + { + __m128 a, b; + float vals[4] = {0}; + a = _mm_loadu_ps (vals); + b = a; + b = _mm_add_ps (a,b); + _mm_storeu_ps (vals,b); + return (0); + }" + HAVE_SSE_EXTENSIONS) - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) - if(HAVE_SSE4_2_EXTENSIONS) - list(APPEND SSE_FLAGS "-msse4.2" "-mfpmath=sse") - elseif(HAVE_SSE4_1_EXTENSIONS) - list(APPEND SSE_FLAGS "-msse4.1" "-mfpmath=sse") - elseif(HAVE_SSSE3_EXTENSIONS) - list(APPEND SSE_FLAGS "-mssse3" "-mfpmath=sse") - elseif(HAVE_SSE3_EXTENSIONS) - list(APPEND SSE_FLAGS "-msse3" "-mfpmath=sse") - elseif(HAVE_SSE2_EXTENSIONS) - list(APPEND SSE_FLAGS "-msse2" "-mfpmath=sse") - elseif(HAVE_SSE_EXTENSIONS) - list(APPEND SSE_FLAGS "-msse" "-mfpmath=sse") - else() - # Setting -ffloat-store to alleviate 32bit vs 64bit discrepancies on non-SSE - # platforms. - list(APPEND SSE_FLAGS "-ffloat-store") - endif() - elseif(MSVC AND NOT CMAKE_CL_64) - if(HAVE_SSE2_EXTENSIONS) - list(APPEND SSE_FLAGS "/arch:SSE2") - elseif(HAVE_SSE_EXTENSIONS) - list(APPEND SSE_FLAGS "/arch:SSE") - endif() - endif() - - if(MSVC) - if(HAVE_SSSE3_EXTENSIONS) - string(APPEND SSE_DEFINITIONS " -D__SSSE3__") - endif() - if(HAVE_SSE2_EXTENSIONS) - string(APPEND SSE_DEFINITIONS " -D__SSE2__") - endif() - if(HAVE_SSE_EXTENSIONS) - string(APPEND SSE_DEFINITIONS " -D__SSE__") - endif() - endif() - string(REPLACE ";" " " SSE_FLAGS_STR "${SSE_FLAGS}") -endmacro() + if(HAVE_SSE_EXTENSIONS) + set(SSE_LEVEL 1.0) + endif() + endif() + + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) + if(SSE_LEVEL GREATER_EQUAL 1.0) + if(SSE_LEVEL GREATER_EQUAL 4.2) + set(SSE_FLAGS "-msse4.2") + elseif(SSE_LEVEL GREATER_EQUAL 4.1) + set(SSE_FLAGS "-msse4.1") + elseif(SSE_LEVEL GREATER_EQUAL 3.1) + set(SSE_FLAGS "-msse3") + elseif(SSE_LEVEL GREATER_EQUAL 3.0) + set(SSE_FLAGS "-msse3") + elseif(SSE_LEVEL GREATER_EQUAL 2.0) + set(SSE_FLAGS "-msse2") + else() + set(SSE_FLAGS "-msse") + endif() + string(APPEND SSE_FLAGS " -mfpmath=sse") + else() + # Setting -ffloat-store to alleviate 32bit vs 64bit discrepancies on non-SSE + # platforms. + string(APPEND SSE_FLAGS " -ffloat-store") + endif() + + if(PCL_ENABLE_MARCHNATIVE AND (NOT CMAKE_CROSSCOMPILING)) + if(HAVE_MARCH) + string(APPEND SSE_FLAGS " -march=native") + else() + string(APPEND SSE_FLAGS " -mtune=native") + endif() + message(STATUS "Using CPU native flags for SSE optimization: ${SSE_FLAGS}") + endif() + elseif(MSVC AND NOT CMAKE_SIZEOF_VOID_P) + if(SSE_LEVEL GREATER_EQUAL 2.0) + set( SSE_FLAGS "/arch:SSE2") + elseif(SSE_LEVEL GREATER_EQUAL 1.0) + set( SSE_FLAGS "/arch:SSE") + endif() + elseif(MSVC) + if(SSE_LEVEL GREATER_EQUAL 4.2) + string(APPEND SSE_DEFINITIONS " -D__SSE4_2__") + endif() + if(SSE_LEVEL GREATER_EQUAL 4.1) + string(APPEND SSE_DEFINITIONS " -D__SSE4_1__") + endif() + if(SSE_LEVEL GREATER_EQUAL 3.1) + string(APPEND SSE_DEFINITIONS " -D__SSSE3__") + endif() + if(SSE_LEVEL GREATER_EQUAL 3.0) + string(APPEND SSE_DEFINITIONS " -D__SSE3__") + endif() + if(SSE_LEVEL GREATER_EQUAL 2.0) + string(APPEND SSE_DEFINITIONS " -D__SSE2__") + endif() + if(SSE_LEVEL GREATER_EQUAL 1.0) + string(APPEND SSE_DEFINITIONS " -D__SSE__") + endif() + endif() + + set(SSE_FLAGS ${SSE_FLAGS} PARENT_SCOPE) + set(SSE_DEFINITIONS ${SSE_DEFINITIONS} PARENT_SCOPE) + + unset(CMAKE_REQUIRED_FLAGS) +endfunction() diff --git a/cmake/pcl_find_vtk.cmake b/cmake/pcl_find_vtk.cmake index 99f8d558606..4fc81774db5 100644 --- a/cmake/pcl_find_vtk.cmake +++ b/cmake/pcl_find_vtk.cmake @@ -37,6 +37,7 @@ endif() set(NON_PREFIX_PCL_VTK_COMPONENTS ChartsCore CommonColor + CommonComputationalGeometry CommonCore CommonDataModel CommonExecutionModel @@ -51,6 +52,7 @@ set(NON_PREFIX_PCL_VTK_COMPONENTS FiltersSources ImagingCore ImagingSources + InteractionImage InteractionStyle InteractionWidgets IOCore @@ -81,7 +83,7 @@ else() set(VTK_RENDERING_BACKEND_OPENGL_VERSION "2") endif() -list(APPEND NON_PREFIX_PCL_VTK_COMPONENTS Rendering${VTK_RENDERING_BACKEND}) +list(APPEND NON_PREFIX_PCL_VTK_COMPONENTS Rendering${VTK_RENDERING_BACKEND} RenderingContext${VTK_RENDERING_BACKEND}) #Append vtk to components if version is <9.0 if(VTK_VERSION VERSION_LESS 9.0) @@ -97,32 +99,23 @@ endif() checkVTKComponents(COMPONENTS ${PCL_VTK_COMPONENTS} MISSING_COMPONENTS vtkMissingComponents) if (vtkMissingComponents) - set(VTK_FOUND FALSE) - message(WARNING "Missing vtk modules: ${vtkMissingComponents}") + message(FATAL_ERROR "Missing vtk modules: ${vtkMissingComponents}") endif() -if(WITH_QT) - if(VTK_VERSION VERSION_LESS 9.0) - if(";${VTK_MODULES_ENABLED};" MATCHES ";vtkGUISupportQt;" AND ";${VTK_MODULES_ENABLED};" MATCHES ";vtkRenderingQt;") - set(HAVE_QVTK TRUE) - #PCL_VTK_COMPONENTS is used in the PCLConfig.cmake to refind the required modules. - #Pre vtk 9.0, all vtk libraries are linked into pcl_visualizer. - #Subprojects can link against pcl_visualizer and directly use VTK-QT libraries. - list(APPEND PCL_VTK_COMPONENTS vtkRenderingQt vtkGUISupportQt) - else() - unset(HAVE_QVTK) - endif() - else() - if(";${VTK_AVAILABLE_COMPONENTS};" MATCHES ";GUISupportQt;" AND ";${VTK_AVAILABLE_COMPONENTS};" MATCHES ";RenderingQt;") - set(HAVE_QVTK TRUE) - #PCL_VTK_COMPONENTS is used in the PCLConfig.cmake to refind the required modules. - #Post vtk 9.0, only required libraries are linked against pcl_visualizer. - #Subprojects need to manually link to VTK-QT libraries. - list(APPEND PCL_VTK_COMPONENTS RenderingQt GUISupportQt) - else() - unset(HAVE_QVTK) - endif() - endif() +if("vtkGUISupportQt" IN_LIST VTK_MODULES_ENABLED) + set(HAVE_QVTK TRUE) + #PCL_VTK_COMPONENTS is used in the PCLConfig.cmake to refind the required modules. + #Pre vtk 9.0, all vtk libraries are linked into pcl_visualizer. + #Subprojects can link against pcl_visualizer and directly use VTK-QT libraries. + list(APPEND PCL_VTK_COMPONENTS vtkGUISupportQt) +elseif("GUISupportQt" IN_LIST VTK_AVAILABLE_COMPONENTS AND "RenderingQt" IN_LIST VTK_AVAILABLE_COMPONENTS) + set(HAVE_QVTK TRUE) + #PCL_VTK_COMPONENTS is used in the PCLConfig.cmake to refind the required modules. + #Post vtk 9.0, only required libraries are linked against pcl_visualizer. + #Subprojects need to manually link to VTK-QT libraries. + list(APPEND PCL_VTK_COMPONENTS GUISupportQt) +else() + unset(HAVE_QVTK) endif() if(PCL_SHARED_LIBS OR (NOT (PCL_SHARED_LIBS) AND NOT (VTK_BUILD_SHARED_LIBS))) @@ -145,14 +138,10 @@ endif() message(STATUS "VTK version: ${VTK_VERSION}") message(STATUS "VTK rendering backend: ${VTK_RENDERING_BACKEND}") -if(WITH_QT) - if(HAVE_QVTK) - message(STATUS "VTK Qt support: YES") - else() - message(STATUS "VTK Qt support: NOTFOUND") - endif() +if(HAVE_QVTK) + message(STATUS "VTK Qt support: YES") else() - message(STATUS "VTK Qt support: NO") + message(STATUS "VTK Qt support: NOTFOUND") endif() if(VTK_INCLUDE_DIRS) diff --git a/cmake/pcl_options.cmake b/cmake/pcl_options.cmake index 52b590f974f..e4ca977857a 100644 --- a/cmake/pcl_options.cmake +++ b/cmake/pcl_options.cmake @@ -1,20 +1,33 @@ # Options for building PCL. +# By default, PCL restricts the dependency search to only shared or only static libraries, +# depending on whether PCL itself is built as a shared or static library. +# This restriction is undesirable when a dependency is available +# only as a shared library while building PCL as a static library, or vice versa. +# In such cases, the user may prefer to use the found dependency anyway. +# For example, the user may prefer to build PCL as a static library +# using a shared OpenGL library provided by the system. +# This option allows to override the restriction imposed by default. +option(PCL_ALLOW_BOTH_SHARED_AND_STATIC_DEPENDENCIES, "Do not force PCL dependencies to be all shared or all static." OFF) + # Build shared libraries by default. option(PCL_SHARED_LIBS "Build shared libraries." ON) if(PCL_SHARED_LIBS) set(PCL_LIB_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) set(PCL_LIB_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) set(PCL_LIB_TYPE "SHARED") -# set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) - if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_IMPORT_LIBRARY_SUFFIX}) + if(NOT PCL_ALLOW_BOTH_SHARED_AND_STATIC_DEPENDENCIES) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_IMPORT_LIBRARY_SUFFIX}) + endif() endif() else() set(PCL_LIB_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX}) set(PCL_LIB_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX}) set(PCL_LIB_TYPE "STATIC") - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + if(NOT PCL_ALLOW_BOTH_SHARED_AND_STATIC_DEPENDENCIES) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() endif() mark_as_advanced(PCL_SHARED_LIBS) @@ -22,13 +35,15 @@ mark_as_advanced(PCL_SHARED_LIBS) option(PCL_BUILD_WITH_BOOST_DYNAMIC_LINKING_WIN32 "Build against a dynamically linked Boost on Win32 platforms." OFF) mark_as_advanced(PCL_BUILD_WITH_BOOST_DYNAMIC_LINKING_WIN32) -# Build with dynamic linking for FLANN (advanced users) -option(PCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32 "Build against a dynamically linked FLANN on Win32 platforms." OFF) -mark_as_advanced(PCL_BUILD_WITH_FLANN_DYNAMIC_LINKING_WIN32) +# Build with shared/static linking for FLANN (advanced users) +set(PCL_FLANN_REQUIRED_TYPE "DONTCARE" CACHE STRING "Select build type to use STATIC or SHARED.") +set_property(CACHE PCL_FLANN_REQUIRED_TYPE PROPERTY STRINGS DONTCARE SHARED STATIC) +mark_as_advanced(PCL_FLANN_REQUIRED_TYPE) # Build with dynamic linking for QHull (advanced users) -option(PCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32 "Build against a dynamically linked QHull on Win32 platforms." OFF) -mark_as_advanced(PCL_BUILD_WITH_QHULL_DYNAMIC_LINKING_WIN32) +set(PCL_QHULL_REQUIRED_TYPE "DONTCARE" CACHE STRING "Select build type to use STATIC or SHARED.") +set_property(CACHE PCL_QHULL_REQUIRED_TYPE PROPERTY STRINGS DONTCARE SHARED STATIC) +mark_as_advanced(PCL_QHULL_REQUIRED_TYPE) # Precompile for a minimal set of point types instead of all. option(PCL_ONLY_CORE_POINT_TYPES "Compile explicitly only for a small subset of point types (e.g., pcl::PointXYZ instead of PCL_XYZ_POINT_TYPES)." OFF) @@ -42,6 +57,18 @@ mark_as_advanced(PCL_NO_PRECOMPILE) option(PCL_ENABLE_SSE "Enable or Disable SSE optimizations." ON) mark_as_advanced(PCL_ENABLE_SSE) +# Enable or Disable the check for AVX optimizations +option(PCL_ENABLE_AVX "Enable or Disable AVX optimizations." ON) +mark_as_advanced(PCL_ENABLE_AVX) + +if(UNIX) + # Enable or Disable the check for March Native optimizations + option(PCL_ENABLE_MARCHNATIVE "Enable or Disable march native optimizations." ON) + mark_as_advanced(PCL_ENABLE_MARCHNATIVE) +else() + set(PCL_ENABLE_MARCHNATIVE FALSE) +endif() + # Allow the user to enable compiler cache option(PCL_ENABLE_CCACHE "Enable using compiler cache for compilation" OFF) mark_as_advanced(PCL_ENABLE_CCACHE) @@ -81,3 +108,6 @@ endif() # (Used to prevent gpu tests from executing in CI where GPU hardware is unavailable) option(PCL_DISABLE_GPU_TESTS "Disable running GPU tests. If disabled, tests will still be built." OFF) +# Set whether visualizations tests should be run +# (Used to prevent visualizations tests from executing in CI where visualization is unavailable) +option(PCL_DISABLE_VISUALIZATION_TESTS "Disable running visualizations tests. If disabled, tests will still be built." OFF) diff --git a/cmake/pcl_pclconfig.cmake b/cmake/pcl_pclconfig.cmake index 42880bc6456..40e5ad80ba6 100644 --- a/cmake/pcl_pclconfig.cmake +++ b/cmake/pcl_pclconfig.cmake @@ -14,6 +14,7 @@ set(PCLCONFIG_EXTERNAL_DEPENDENCIES) set(PCLCONFIG_OPTIONAL_DEPENDENCIES) set(PCLCONFIG_SSE_DEFINITIONS "${SSE_DEFINITIONS}") set(PCLCONFIG_SSE_COMPILE_OPTIONS ${SSE_FLAGS}) +set(PCLCONFIG_AVX_COMPILE_OPTIONS ${AVX_FLAGS}) foreach(_ss ${PCL_SUBSYSTEMS_MODULES}) PCL_GET_SUBSYS_STATUS(_status ${_ss}) diff --git a/cmake/pcl_targets.cmake b/cmake/pcl_targets.cmake index 5bd84d2aa3b..1e3de26883e 100644 --- a/cmake/pcl_targets.cmake +++ b/cmake/pcl_targets.cmake @@ -170,7 +170,7 @@ macro(PCL_SUBSUBSYS_DEPEND _var _parent _name) if(SUBSUBSYS_EXT_DEPS) foreach(_dep ${SUBSUBSYS_EXT_DEPS}) string(TOUPPER "${_dep}_found" EXT_DEP_FOUND) - if(NOT EXT_DEP_FOUND) + if(NOT ${EXT_DEP_FOUND}) set(${_var} FALSE) PCL_SET_SUBSYS_STATUS(${_parent}_${_name} FALSE "Requires external library ${_dep}.") endif() @@ -223,14 +223,14 @@ function(PCL_ADD_LIBRARY _name) add_library(${_name} ${PCL_LIB_TYPE} ${ADD_LIBRARY_OPTION_SOURCES}) PCL_ADD_VERSION_INFO(${_name}) target_compile_features(${_name} PUBLIC ${PCL_CXX_COMPILE_FEATURES}) - # must link explicitly against boost. - target_link_libraries(${_name} ${Boost_LIBRARIES} Threads::Threads) + + target_link_libraries(${_name} Threads::Threads) if(TARGET OpenMP::OpenMP_CXX) target_link_libraries(${_name} OpenMP::OpenMP_CXX) endif() if((UNIX AND NOT ANDROID) OR MINGW) - target_link_libraries(${_name} m) + target_link_libraries(${_name} m ${ATOMIC_LIBRARY}) endif() if(MINGW) @@ -251,6 +251,11 @@ function(PCL_ADD_LIBRARY _name) RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT pcl_${ADD_LIBRARY_OPTION_COMPONENT} LIBRARY DESTINATION ${LIB_INSTALL_DIR} COMPONENT pcl_${ADD_LIBRARY_OPTION_COMPONENT} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT pcl_${ADD_LIBRARY_OPTION_COMPONENT}) + + # Copy PDB if available + if(MSVC AND PCL_SHARED_LIBS) + install(FILES $ DESTINATION ${BIN_INSTALL_DIR} OPTIONAL) + endif() endfunction() ############################################################################### @@ -265,20 +270,18 @@ function(PCL_CUDA_ADD_LIBRARY _name) cmake_parse_arguments(ADD_LIBRARY_OPTION "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) REMOVE_VTK_DEFINITIONS() - if(PCL_SHARED_LIBS) - # to overcome a limitation in cuda_add_library, we add manually PCLAPI_EXPORTS macro - cuda_add_library(${_name} ${PCL_LIB_TYPE} ${ADD_LIBRARY_OPTION_SOURCES} OPTIONS -DPCLAPI_EXPORTS) - else() - cuda_add_library(${_name} ${PCL_LIB_TYPE} ${ADD_LIBRARY_OPTION_SOURCES}) - endif() + + add_library(${_name} ${PCL_LIB_TYPE} ${ADD_LIBRARY_OPTION_SOURCES}) + PCL_ADD_VERSION_INFO(${_name}) - # must link explicitly against boost. - target_link_libraries(${_name} ${Boost_LIBRARIES}) + target_compile_options(${_name} PRIVATE $<$: ${GEN_CODE} --expt-relaxed-constexpr>) + + target_include_directories(${_name} PRIVATE ${CUDA_TOOLKIT_INCLUDE}) set_target_properties(${_name} PROPERTIES VERSION ${PCL_VERSION} - SOVERSION ${PCL_VERSION_MAJOR} + SOVERSION ${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR} DEFINE_SYMBOL "PCLAPI_EXPORTS") set_target_properties(${_name} PROPERTIES FOLDER "Libraries") @@ -306,8 +309,8 @@ function(PCL_ADD_EXECUTABLE _name) add_executable(${_name} ${ADD_LIBRARY_OPTION_SOURCES}) endif() PCL_ADD_VERSION_INFO(${_name}) - # must link explicitly against boost. - target_link_libraries(${_name} ${Boost_LIBRARIES} Threads::Threads) + + target_link_libraries(${_name} Threads::Threads) if(WIN32 AND MSVC) set_target_properties(${_name} PROPERTIES DEBUG_OUTPUT_NAME ${_name}${CMAKE_DEBUG_POSTFIX} @@ -346,11 +349,14 @@ function(PCL_CUDA_ADD_EXECUTABLE _name) cmake_parse_arguments(ADD_LIBRARY_OPTION "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) REMOVE_VTK_DEFINITIONS() - cuda_add_executable(${_name} ${ADD_LIBRARY_OPTION_SOURCES}) + + add_executable(${_name} ${ADD_LIBRARY_OPTION_SOURCES}) + PCL_ADD_VERSION_INFO(${_name}) - # must link explicitly against boost. - target_link_libraries(${_name} ${Boost_LIBRARIES}) + target_compile_options(${_name} PRIVATE $<$: ${GEN_CODE} --expt-relaxed-constexpr>) + + target_include_directories(${_name} PRIVATE ${CUDA_TOOLKIT_INCLUDE}) if(WIN32 AND MSVC) set_target_properties(${_name} PROPERTIES DEBUG_OUTPUT_NAME ${_name}${CMAKE_DEBUG_POSTFIX} @@ -385,10 +391,7 @@ macro(PCL_ADD_TEST _name _exename) #target_link_libraries(${_exename} ${GTEST_BOTH_LIBRARIES} ${PCL_ADD_TEST_LINK_WITH}) target_link_libraries(${_exename} ${PCL_ADD_TEST_LINK_WITH} ${CLANG_LIBRARIES}) - target_link_libraries(${_exename} Threads::Threads) - - # must link explicitly against boost only on Windows - target_link_libraries(${_exename} ${Boost_LIBRARIES}) + target_link_libraries(${_exename} Threads::Threads ${ATOMIC_LIBRARY}) #Only applies to MSVC if(MSVC) @@ -411,6 +414,46 @@ macro(PCL_ADD_TEST _name _exename) add_dependencies(tests ${_exename}) endmacro() +############################################################################### +# Add a benchmark target. +# _name The benchmark name. +# ARGN : +# FILES the source files for the benchmark +# ARGUMENTS Arguments for benchmark executable +# LINK_WITH link benchmark executable with libraries +function(PCL_ADD_BENCHMARK _name) + set(options) + set(oneValueArgs) + set(multiValueArgs FILES ARGUMENTS LINK_WITH) + cmake_parse_arguments(PCL_ADD_BENCHMARK "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + add_executable(benchmark_${_name} ${PCL_ADD_BENCHMARK_FILES}) + set_target_properties(benchmark_${_name} PROPERTIES FOLDER "Benchmarks") + target_link_libraries(benchmark_${_name} benchmark::benchmark ${PCL_ADD_BENCHMARK_LINK_WITH}) + set_target_properties(benchmark_${_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + #Only applies to MSVC + if(MSVC) + #Requires CMAKE version 3.13.0 + get_target_property(BenchmarkArgumentWarningShown run_benchmarks PCL_BENCHMARK_ARGUMENTS_WARNING_SHOWN) + if(CMAKE_VERSION VERSION_LESS "3.13.0" AND (NOT BenchmarkArgumentWarningShown)) + message(WARNING "Arguments for benchmark projects are not added - this requires at least CMake 3.13. Can be added manually in \"Project settings -> Debugging -> Command arguments\"") + set_target_properties(run_benchmarks PROPERTIES PCL_BENCHMARK_ARGUMENTS_WARNING_SHOWN TRUE) + else() + #Only add if there are arguments to test + if(PCL_ADD_BENCHMARK_ARGUMENTS) + string (REPLACE ";" " " PCL_ADD_BENCHMARK_ARGUMENTS_STR "${PCL_ADD_BENCHMARK_ARGUMENTS}") + set_target_properties(benchmark_${_name} PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS ${PCL_ADD_BENCHMARK_ARGUMENTS_STR}) + endif() + endif() + endif() + + add_custom_target(run_benchmark_${_name} benchmark_${_name} ${PCL_ADD_BENCHMARK_ARGUMENTS}) + set_target_properties(run_benchmark_${_name} PROPERTIES FOLDER "Benchmarks") + + add_dependencies(run_benchmarks run_benchmark_${_name}) +endfunction() + ############################################################################### # Add an example target. # _name The example name. @@ -466,7 +509,7 @@ endmacro() ############################################################################### # Make a pkg-config file for a library. Do not include general PCL stuff in the # arguments; they will be added automatically. -# _name The library name. "pcl_" will be preprended to this. +# _name The library name. Please prepend "pcl_" to ensure no conflicts in user systems # COMPONENT The part of PCL that this pkg-config file belongs to. # DESC Description of the library. # PCL_DEPS External dependencies to pcl libs, as a list. (will get mangled to external pkg-config name) @@ -487,14 +530,14 @@ function(PCL_MAKE_PKGCONFIG _name) set(PKG_LIBFLAGS ${PKGCONFIG_LIB_FLAGS}) LIST_TO_STRING(PKG_EXTERNAL_DEPS "${PKGCONFIG_EXT_DEPS}") foreach(_dep ${PKGCONFIG_PCL_DEPS}) - string(APPEND PKG_EXTERNAL_DEPS " pcl_${_dep}-${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR}") + string(APPEND PKG_EXTERNAL_DEPS " pcl_${_dep}") endforeach() set(PKG_INTERNAL_DEPS "") foreach(_dep ${PKGCONFIG_INT_DEPS}) string(APPEND PKG_INTERNAL_DEPS " -l${_dep}") endforeach() - set(_pc_file ${CMAKE_CURRENT_BINARY_DIR}/${_name}-${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR}.pc) + set(_pc_file ${CMAKE_CURRENT_BINARY_DIR}/${_name}.pc) if(PKGCONFIG_HEADER_ONLY) configure_file(${PROJECT_SOURCE_DIR}/cmake/pkgconfig-headeronly.cmake.in ${_pc_file} @ONLY) else() diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index cc5a4a504d1..5cb766be51d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -175,6 +175,8 @@ set(LIB_NAME "pcl_${SUBSYS_NAME}") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include") PCL_ADD_LIBRARY(${LIB_NAME} COMPONENT ${SUBSYS_NAME} SOURCES ${srcs} ${kissfft_srcs} ${incs} ${common_incs} ${impl_incs} ${tools_incs} ${kissfft_incs} ${common_incs_impl} ${range_image_incs} ${range_image_incs_impl}) +target_link_libraries(${LIB_NAME} Boost::boost) + if(MSVC AND NOT (MSVC_VERSION LESS 1915)) # MSVC resolved a byte alignment issue in compiler version 15.9 # We get this due to using Eigen objects and allocating those objects with make_shared @@ -182,7 +184,8 @@ if(MSVC AND NOT (MSVC_VERSION LESS 1915)) target_compile_definitions(${LIB_NAME} PUBLIC _ENABLE_EXTENDED_ALIGNED_STORAGE) endif() -PCL_MAKE_PKGCONFIG(${LIB_NAME} COMPONENT ${SUBSYS_NAME} DESC ${SUBSYS_DESC}) +set(EXT_DEPS eigen3) +PCL_MAKE_PKGCONFIG(${LIB_NAME} COMPONENT ${SUBSYS_NAME} DESC ${SUBSYS_DESC} EXT_DEPS ${EXT_DEPS}) # Install include files PCL_ADD_INCLUDES("${SUBSYS_NAME}" "" ${incs}) diff --git a/common/include/pcl/PCLImage.h b/common/include/pcl/PCLImage.h index 2ac69498cb8..475acb8c642 100644 --- a/common/include/pcl/PCLImage.h +++ b/common/include/pcl/PCLImage.h @@ -13,12 +13,12 @@ namespace pcl { ::pcl::PCLHeader header; - index_t height = 0; - index_t width = 0; + uindex_t height = 0; + uindex_t width = 0; std::string encoding; std::uint8_t is_bigendian = 0; - index_t step = 0; + uindex_t step = 0; std::vector data; diff --git a/common/include/pcl/PCLPointCloud2.h b/common/include/pcl/PCLPointCloud2.h index cde7e6e08d8..50520f66e11 100644 --- a/common/include/pcl/PCLPointCloud2.h +++ b/common/include/pcl/PCLPointCloud2.h @@ -17,15 +17,15 @@ namespace pcl { ::pcl::PCLHeader header; - index_t height = 0; - index_t width = 0; + uindex_t height = 0; + uindex_t width = 0; std::vector<::pcl::PCLPointField> fields; static_assert(BOOST_ENDIAN_BIG_BYTE || BOOST_ENDIAN_LITTLE_BYTE, "unable to determine system endianness"); std::uint8_t is_bigendian = BOOST_ENDIAN_BIG_BYTE; - index_t point_step = 0; - index_t row_step = 0; + uindex_t point_step = 0; + uindex_t row_step = 0; std::vector data; diff --git a/common/include/pcl/PCLPointField.h b/common/include/pcl/PCLPointField.h index 73d829735e7..06f12eae9d6 100644 --- a/common/include/pcl/PCLPointField.h +++ b/common/include/pcl/PCLPointField.h @@ -41,7 +41,17 @@ namespace pcl s << "offset: "; s << " " << v.offset << std::endl; s << "datatype: "; - s << " " << v.datatype << std::endl; + switch(v.datatype) { + case ::pcl::PCLPointField::PointFieldTypes::INT8: s << " INT8" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::UINT8: s << " UINT8" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::INT16: s << " INT16" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::UINT16: s << " UINT16" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::INT32: s << " INT32" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::UINT32: s << " UINT32" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::FLOAT32: s << " FLOAT32" << std::endl; break; + case ::pcl::PCLPointField::PointFieldTypes::FLOAT64: s << " FLOAT64" << std::endl; break; + default: s << " " << static_cast(v.datatype) << std::endl; + } s << "count: "; s << " " << v.count << std::endl; return (s); diff --git a/common/include/pcl/PolygonMesh.h b/common/include/pcl/PolygonMesh.h index 89aefabd37a..dd15962f828 100644 --- a/common/include/pcl/PolygonMesh.h +++ b/common/include/pcl/PolygonMesh.h @@ -29,6 +29,8 @@ namespace pcl static bool concatenate (pcl::PolygonMesh &mesh1, const pcl::PolygonMesh &mesh2) { + const auto point_offset = mesh1.cloud.width * mesh1.cloud.height; + bool success = pcl::PCLPointCloud2::concatenate(mesh1.cloud, mesh2.cloud); if (success == false) { return false; @@ -36,7 +38,6 @@ namespace pcl // Make the resultant polygon mesh take the newest stamp mesh1.header.stamp = std::max(mesh1.header.stamp, mesh2.header.stamp); - const auto point_offset = mesh1.cloud.width * mesh1.cloud.height; std::transform(mesh2.polygons.begin (), mesh2.polygons.end (), std::back_inserter (mesh1.polygons), @@ -55,7 +56,7 @@ namespace pcl return true; } - /** \brief Concatenate two pcl::PCLPointCloud2 + /** \brief Concatenate two pcl::PolygonMesh * \param[in] mesh1 the first input mesh * \param[in] mesh2 the second input mesh * \param[out] mesh_out the resultant output mesh diff --git a/common/include/pcl/TextureMesh.h b/common/include/pcl/TextureMesh.h index 88119906f6f..3a819b8ccac 100644 --- a/common/include/pcl/TextureMesh.h +++ b/common/include/pcl/TextureMesh.h @@ -91,9 +91,17 @@ namespace pcl pcl::PCLHeader header; - std::vector > tex_polygons; // polygon which is mapped with specific texture defined in TexMaterial - std::vector > > tex_coordinates; // UV coordinates - std::vector tex_materials; // define texture material + /** \brief polygon which is mapped with specific texture defined in TexMaterial */ + std::vector > tex_polygons; + /** \brief UV coordinates */ + std::vector > > tex_coordinates; + /** \brief define texture material */ + std::vector tex_materials; + /** \brief Specifies which texture coordinates from tex_coordinates each polygon/face uses. + * The vectors must have the same sizes as in tex_polygons, but the pcl::Vertices + * may be empty for those polygons/faces that do not use coordinates. + */ + std::vector > tex_coord_indices; public: using Ptr = shared_ptr; diff --git a/common/include/pcl/common/boost.h b/common/include/pcl/common/boost.h index 09908e61164..232d1df5f3b 100644 --- a/common/include/pcl/common/boost.h +++ b/common/include/pcl/common/boost.h @@ -41,6 +41,7 @@ #ifdef __GNUC__ #pragma GCC system_header #endif +PCL_DEPRECATED_HEADER(1, 15, "Please include the needed boost headers directly.") #ifndef Q_MOC_RUN // Marking all Boost headers as system headers to remove warnings diff --git a/common/include/pcl/common/colors.h b/common/include/pcl/common/colors.h index 5490c06bb52..7c1fc883c66 100644 --- a/common/include/pcl/common/colors.h +++ b/common/include/pcl/common/colors.h @@ -40,6 +40,9 @@ #include #include +#include // for is_floating_point +#include // for std::array especially in Clang Darwin and MSVC + namespace pcl { @@ -83,4 +86,85 @@ namespace pcl using GlasbeyLUT = ColorLUT; using ViridisLUT = ColorLUT; -} + /** + * @brief Returns a Look-Up Table useful in converting RGB to sRGB + * @tparam T floating point type with resultant value + * @tparam bits depth of RGB + * @return 1-D LUT for converting R, G or B into Rs, Gs or Bs + * @remarks sRGB was proposed by Stokes et al. as a uniform default color + * space for the internet + * M. Stokes, M. Anderson, S. Chandrasekar, and R. Motta: A standard default colorspace for the internet - sRGB (Nov 1996) + * IEC 61966-2.1 Default RGB Colour Space - sRGB (International Electrotechnical Commission, Geneva, Switzerland, 1999) + * www.srgb.com, www.color.org/srgb.html + */ + template + PCL_EXPORTS inline std::array + RGB2sRGB_LUT() noexcept + { + static_assert(std::is_floating_point::value, "LUT value must be a floating point"); + + constexpr const std::size_t size = 1 << bits; + + static const auto sRGB_LUT = [&]() { + // MSVC wouldn't take `size` here instead of the expression + std::array LUT; + for (std::size_t i = 0; i < size; ++i) { + T f = static_cast(i) / static_cast(size - 1); + if (f > 0.04045) { + // ((f + 0.055)/1.055)^2.4 + LUT[i] = static_cast( + std::pow((f + static_cast(0.055)) / static_cast(1.055), + static_cast(2.4))); + } + else { + // f / 12.92 + LUT[i] = f / static_cast(12.92); + } + } + return LUT; + }(); + return sRGB_LUT; + } + + /** + * @brief Returns a Look-Up Table useful in converting scaled CIE XYZ into CIE L*a*b* + * @details The function assumes that the XYZ values are + * * not normalized using reference illuminant + * * scaled such that reference illuminant has Xn = Yn = Zn = discretizations + * @tparam T floating point type with resultant value + * @tparam discretizations number of levels for the LUT + * @return 1-D LUT with results of f(X/Xn) + * @note This function doesn't convert from CIE XYZ to CIE L*a*b*. The actual conversion + * is as follows: + * L* = 116 * [f(Y/Yn) - 16/116] + * a* = 500 * [f(X/Xn) - f(Y/Yn)] + * b* = 200 * [f(Y/Yn) - f(Z/Zn)] + * Where, Xn, Yn and Zn are values of the reference illuminant (at prescribed angle) + * f is appropriate function such that L* = 100, a* = b* = 0 for white color + * Reference: Billmeyer and Saltzman’s Principles of Color Technology + */ + template + PCL_EXPORTS inline const std::array& + XYZ2LAB_LUT() noexcept + { + static_assert(std::is_floating_point::value, "LUT value must be a floating point"); + + static const auto f_LUT = [&]() { + std::array LUT; + for (std::size_t i = 0; i < discretizations; ++i) { + T f = static_cast(i) / static_cast(discretizations); + if (f > static_cast(0.008856)) { + // f^(1/3) + LUT[i] = static_cast(std::pow(f, (static_cast(1) / static_cast(3)))); + } + else { + // 7.87 * f + 16/116 + LUT[i] = + static_cast(7.87) * f + (static_cast(16) / static_cast(116)); + } + } + return LUT; + }(); + return f_LUT; + } +} // namespace pcl diff --git a/common/include/pcl/common/common.h b/common/include/pcl/common/common.h index 97a41df5a95..af32634ca65 100644 --- a/common/include/pcl/common/common.h +++ b/common/include/pcl/common/common.h @@ -60,6 +60,7 @@ namespace pcl /** \brief Compute the smallest angle between two 3D vectors in radians (default) or degree. * \param v1 the first 3D vector (represented as a \a Eigen::Vector4f) * \param v2 the second 3D vector (represented as a \a Eigen::Vector4f) + * \param in_degree determine if angle should be in radians or degrees * \return the angle between v1 and v2 in radians or degrees * \note Handles rounding error for parallel and anti-parallel vectors * \ingroup common @@ -281,7 +282,12 @@ namespace pcl * \ingroup common */ template inline auto - computeMedian (IteratorT begin, IteratorT end, Functor f) noexcept -> typename std::result_of::type + computeMedian (IteratorT begin, IteratorT end, Functor f) noexcept -> + #if __cpp_lib_is_invocable + std::invoke_result_t + #else + std::result_of_t + #endif { const std::size_t size = std::distance(begin, end); const std::size_t mid = size/2; diff --git a/common/include/pcl/common/eigen.h b/common/include/pcl/common/eigen.h index 30514900da3..15b079a19fa 100644 --- a/common/include/pcl/common/eigen.h +++ b/common/include/pcl/common/eigen.h @@ -249,7 +249,7 @@ namespace pcl const Eigen::Vector3f& origin, Eigen::Affine3f& transformation); - /** \brief Extract the Euler angles (XYZ-convention) from the given transformation + /** \brief Extract the Euler angles (intrinsic rotations, ZYX-convention) from the given transformation * \param[in] t the input transformation matrix * \param[in] roll the resulting roll angle * \param[in] pitch the resulting pitch angle @@ -259,19 +259,7 @@ namespace pcl template void getEulerAngles (const Eigen::Transform &t, Scalar &roll, Scalar &pitch, Scalar &yaw); - inline void - getEulerAngles (const Eigen::Affine3f &t, float &roll, float &pitch, float &yaw) - { - getEulerAngles (t, roll, pitch, yaw); - } - - inline void - getEulerAngles (const Eigen::Affine3d &t, double &roll, double &pitch, double &yaw) - { - getEulerAngles (t, roll, pitch, yaw); - } - - /** Extract x,y,z and the Euler angles (XYZ-convention) from the given transformation + /** Extract x,y,z and the Euler angles (intrinsic rotations, ZYX-convention) from the given transformation * \param[in] t the input transformation matrix * \param[out] x the resulting x translation * \param[out] y the resulting y translation @@ -286,23 +274,7 @@ namespace pcl Scalar &x, Scalar &y, Scalar &z, Scalar &roll, Scalar &pitch, Scalar &yaw); - inline void - getTranslationAndEulerAngles (const Eigen::Affine3f &t, - float &x, float &y, float &z, - float &roll, float &pitch, float &yaw) - { - getTranslationAndEulerAngles (t, x, y, z, roll, pitch, yaw); - } - - inline void - getTranslationAndEulerAngles (const Eigen::Affine3d &t, - double &x, double &y, double &z, - double &roll, double &pitch, double &yaw) - { - getTranslationAndEulerAngles (t, x, y, z, roll, pitch, yaw); - } - - /** \brief Create a transformation from the given translation and Euler angles (XYZ-convention) + /** \brief Create a transformation from the given translation and Euler angles (intrinsic rotations, ZYX-convention) * \param[in] x the input x translation * \param[in] y the input y translation * \param[in] z the input z translation @@ -330,7 +302,7 @@ namespace pcl return (getTransformation (x, y, z, roll, pitch, yaw, t)); } - /** \brief Create a transformation from the given translation and Euler angles (XYZ-convention) + /** \brief Create a transformation from the given translation and Euler angles (intrinsic rotations, ZYX-convention) * \param[in] x the input x translation * \param[in] y the input y translation * \param[in] z the input z translation @@ -423,22 +395,6 @@ namespace pcl point_out = (transformation * point).template head<3> (); } - inline void - transformPoint (const Eigen::Vector3f &point_in, - Eigen::Vector3f &point_out, - const Eigen::Affine3f &transformation) - { - transformPoint (point_in, point_out, transformation); - } - - inline void - transformPoint (const Eigen::Vector3d &point_in, - Eigen::Vector3d &point_out, - const Eigen::Affine3d &transformation) - { - transformPoint (point_in, point_out, transformation); - } - /** \brief Transform a vector using an affine matrix * \param[in] vector_in the vector to be transformed * \param[out] vector_out the transformed vector @@ -454,22 +410,6 @@ namespace pcl vector_out = transformation.linear () * vector_in; } - inline void - transformVector (const Eigen::Vector3f &vector_in, - Eigen::Vector3f &vector_out, - const Eigen::Affine3f &transformation) - { - transformVector (vector_in, vector_out, transformation); - } - - inline void - transformVector (const Eigen::Vector3d &vector_in, - Eigen::Vector3d &vector_out, - const Eigen::Affine3d &transformation) - { - transformVector (vector_in, vector_out, transformation); - } - /** \brief Transform a line using an affine matrix * \param[in] line_in the line to be transformed * \param[out] line_out the transformed line @@ -486,22 +426,6 @@ namespace pcl Eigen::Matrix &line_out, const Eigen::Transform &transformation); - inline bool - transformLine (const Eigen::VectorXf &line_in, - Eigen::VectorXf &line_out, - const Eigen::Affine3f &transformation) - { - return (transformLine (line_in, line_out, transformation)); - } - - inline bool - transformLine (const Eigen::VectorXd &line_in, - Eigen::VectorXd &line_out, - const Eigen::Affine3d &transformation) - { - return (transformLine (line_in, line_out, transformation)); - } - /** \brief Transform plane vectors using an affine matrix * \param[in] plane_in the plane coefficients to be transformed * \param[out] plane_out the transformed plane coefficients to fill @@ -516,22 +440,6 @@ namespace pcl Eigen::Matrix &plane_out, const Eigen::Transform &transformation); - inline void - transformPlane (const Eigen::Matrix &plane_in, - Eigen::Matrix &plane_out, - const Eigen::Transform &transformation) - { - transformPlane (plane_in, plane_out, transformation); - } - - inline void - transformPlane (const Eigen::Matrix &plane_in, - Eigen::Matrix &plane_out, - const Eigen::Transform &transformation) - { - transformPlane (plane_in, plane_out, transformation); - } - /** \brief Transform plane vectors using an affine matrix * \param[in] plane_in the plane coefficients to be transformed * \param[out] plane_out the transformed plane coefficients to fill @@ -547,22 +455,6 @@ namespace pcl pcl::ModelCoefficients::Ptr plane_out, const Eigen::Transform &transformation); - inline void - transformPlane (const pcl::ModelCoefficients::ConstPtr plane_in, - pcl::ModelCoefficients::Ptr plane_out, - const Eigen::Transform &transformation) - { - transformPlane (plane_in, plane_out, transformation); - } - - inline void - transformPlane (const pcl::ModelCoefficients::ConstPtr plane_in, - pcl::ModelCoefficients::Ptr plane_out, - const Eigen::Transform &transformation) - { - transformPlane (plane_in, plane_out, transformation); - } - /** \brief Check coordinate system integrity * \param[in] line_x the first axis * \param[in] line_y the second axis @@ -592,24 +484,6 @@ namespace pcl const Scalar norm_limit = 1e-3, const Scalar dot_limit = 1e-3); - inline bool - checkCoordinateSystem (const Eigen::Matrix &line_x, - const Eigen::Matrix &line_y, - const double norm_limit = 1e-3, - const double dot_limit = 1e-3) - { - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - - inline bool - checkCoordinateSystem (const Eigen::Matrix &line_x, - const Eigen::Matrix &line_y, - const float norm_limit = 1e-3, - const float dot_limit = 1e-3) - { - return (checkCoordinateSystem (line_x, line_y, norm_limit, dot_limit)); - } - /** \brief Check coordinate system integrity * \param[in] origin the origin of the coordinate system * \param[in] x_direction the first axis @@ -685,26 +559,6 @@ namespace pcl const Eigen::Matrix to_line_y, Eigen::Transform &transformation); - inline bool - transformBetween2CoordinateSystems (const Eigen::Matrix from_line_x, - const Eigen::Matrix from_line_y, - const Eigen::Matrix to_line_x, - const Eigen::Matrix to_line_y, - Eigen::Transform &transformation) - { - return (transformBetween2CoordinateSystems (from_line_x, from_line_y, to_line_x, to_line_y, transformation)); - } - - inline bool - transformBetween2CoordinateSystems (const Eigen::Matrix from_line_x, - const Eigen::Matrix from_line_y, - const Eigen::Matrix to_line_x, - const Eigen::Matrix to_line_y, - Eigen::Transform &transformation) - { - return (transformBetween2CoordinateSystems (from_line_x, from_line_y, to_line_x, to_line_y, transformation)); - } - } #include diff --git a/common/include/pcl/common/impl/centroid.hpp b/common/include/pcl/common/impl/centroid.hpp index 7cf88a6766f..f83b12ca2be 100644 --- a/common/include/pcl/common/impl/centroid.hpp +++ b/common/include/pcl/common/impl/centroid.hpp @@ -56,10 +56,9 @@ template inline unsigned int compute3DCentroid (ConstCloudIterator &cloud_iterator, Eigen::Matrix ¢roid) { - // Initialize to 0 - centroid.setZero (); + Eigen::Matrix accumulator {0, 0, 0, 0}; - unsigned cp = 0; + unsigned int cp = 0; // For each point in the cloud // If the data is dense, we don't need to check for NaN @@ -68,15 +67,19 @@ compute3DCentroid (ConstCloudIterator &cloud_iterator, // Check if the point is invalid if (pcl::isFinite (*cloud_iterator)) { - centroid[0] += cloud_iterator->x; - centroid[1] += cloud_iterator->y; - centroid[2] += cloud_iterator->z; + accumulator[0] += cloud_iterator->x; + accumulator[1] += cloud_iterator->y; + accumulator[2] += cloud_iterator->z; ++cp; } ++cloud_iterator; } - centroid /= static_cast (cp); - centroid[3] = 1; + + if (cp > 0) { + centroid = accumulator; + centroid /= static_cast (cp); + centroid[3] = 1; + } return (cp); } @@ -88,12 +91,12 @@ compute3DCentroid (const pcl::PointCloud &cloud, if (cloud.empty ()) return (0); - // Initialize to 0 - centroid.setZero (); // For each point in the cloud // If the data is dense, we don't need to check for NaN if (cloud.is_dense) { + // Initialize to 0 + centroid.setZero (); for (const auto& point: cloud) { centroid[0] += point.x; @@ -106,20 +109,24 @@ compute3DCentroid (const pcl::PointCloud &cloud, return (static_cast (cloud.size ())); } // NaN or Inf values could exist => check for them - unsigned cp = 0; + unsigned int cp = 0; + Eigen::Matrix accumulator {0, 0, 0, 0}; for (const auto& point: cloud) { // Check if the point is invalid if (!isFinite (point)) continue; - centroid[0] += point.x; - centroid[1] += point.y; - centroid[2] += point.z; + accumulator[0] += point.x; + accumulator[1] += point.y; + accumulator[2] += point.z; ++cp; } - centroid /= static_cast (cp); - centroid[3] = 1; + if (cp > 0) { + centroid = accumulator; + centroid /= static_cast (cp); + centroid[3] = 1; + } return (cp); } @@ -133,11 +140,11 @@ compute3DCentroid (const pcl::PointCloud &cloud, if (indices.empty ()) return (0); - // Initialize to 0 - centroid.setZero (); // If the data is dense, we don't need to check for NaN if (cloud.is_dense) { + // Initialize to 0 + centroid.setZero (); for (const auto& index : indices) { centroid[0] += cloud[index].x; @@ -149,20 +156,24 @@ compute3DCentroid (const pcl::PointCloud &cloud, return (static_cast (indices.size ())); } // NaN or Inf values could exist => check for them - unsigned cp = 0; + Eigen::Matrix accumulator {0, 0, 0, 0}; + unsigned int cp = 0; for (const auto& index : indices) { // Check if the point is invalid if (!isFinite (cloud [index])) continue; - centroid[0] += cloud[index].x; - centroid[1] += cloud[index].y; - centroid[2] += cloud[index].z; + accumulator[0] += cloud[index].x; + accumulator[1] += cloud[index].y; + accumulator[2] += cloud[index].z; ++cp; } - centroid /= static_cast (cp); - centroid[3] = 1; + if (cp > 0) { + centroid = accumulator; + centroid /= static_cast (cp); + centroid[3] = 1; + } return (cp); } @@ -184,13 +195,11 @@ computeCovarianceMatrix (const pcl::PointCloud &cloud, if (cloud.empty ()) return (0); - // Initialize to 0 - covariance_matrix.setZero (); - unsigned point_count; // If the data is dense, we don't need to check for NaN if (cloud.is_dense) { + covariance_matrix.setZero (); point_count = static_cast (cloud.size ()); // For each point in the cloud for (const auto& point: cloud) @@ -214,6 +223,8 @@ computeCovarianceMatrix (const pcl::PointCloud &cloud, // NaN or Inf values could exist => check for them else { + Eigen::Matrix temp_covariance_matrix; + temp_covariance_matrix.setZero(); point_count = 0; // For each point in the cloud for (const auto& point: cloud) @@ -227,17 +238,23 @@ computeCovarianceMatrix (const pcl::PointCloud &cloud, pt[1] = point.y - centroid[1]; pt[2] = point.z - centroid[2]; - covariance_matrix (1, 1) += pt.y () * pt.y (); - covariance_matrix (1, 2) += pt.y () * pt.z (); + temp_covariance_matrix (1, 1) += pt.y () * pt.y (); + temp_covariance_matrix (1, 2) += pt.y () * pt.z (); - covariance_matrix (2, 2) += pt.z () * pt.z (); + temp_covariance_matrix (2, 2) += pt.z () * pt.z (); pt *= pt.x (); - covariance_matrix (0, 0) += pt.x (); - covariance_matrix (0, 1) += pt.y (); - covariance_matrix (0, 2) += pt.z (); + temp_covariance_matrix (0, 0) += pt.x (); + temp_covariance_matrix (0, 1) += pt.y (); + temp_covariance_matrix (0, 2) += pt.z (); ++point_count; } + if (point_count > 0) { + covariance_matrix = temp_covariance_matrix; + } + } + if (point_count == 0) { + return 0; } covariance_matrix (1, 0) = covariance_matrix (0, 1); covariance_matrix (2, 0) = covariance_matrix (0, 2); @@ -268,13 +285,11 @@ computeCovarianceMatrix (const pcl::PointCloud &cloud, if (indices.empty ()) return (0); - // Initialize to 0 - covariance_matrix.setZero (); - std::size_t point_count; // If the data is dense, we don't need to check for NaN if (cloud.is_dense) { + covariance_matrix.setZero (); point_count = indices.size (); // For each point in the cloud for (const auto& idx: indices) @@ -298,6 +313,8 @@ computeCovarianceMatrix (const pcl::PointCloud &cloud, // NaN or Inf values could exist => check for them else { + Eigen::Matrix temp_covariance_matrix; + temp_covariance_matrix.setZero (); point_count = 0; // For each point in the cloud for (const auto &index : indices) @@ -311,17 +328,23 @@ computeCovarianceMatrix (const pcl::PointCloud &cloud, pt[1] = cloud[index].y - centroid[1]; pt[2] = cloud[index].z - centroid[2]; - covariance_matrix (1, 1) += pt.y () * pt.y (); - covariance_matrix (1, 2) += pt.y () * pt.z (); + temp_covariance_matrix (1, 1) += pt.y () * pt.y (); + temp_covariance_matrix (1, 2) += pt.y () * pt.z (); - covariance_matrix (2, 2) += pt.z () * pt.z (); + temp_covariance_matrix (2, 2) += pt.z () * pt.z (); pt *= pt.x (); - covariance_matrix (0, 0) += pt.x (); - covariance_matrix (0, 1) += pt.y (); - covariance_matrix (0, 2) += pt.z (); + temp_covariance_matrix (0, 0) += pt.x (); + temp_covariance_matrix (0, 1) += pt.y (); + temp_covariance_matrix (0, 2) += pt.z (); ++point_count; } + if (point_count > 0) { + covariance_matrix = temp_covariance_matrix; + } + } + if (point_count == 0) { + return 0; } covariance_matrix (1, 0) = covariance_matrix (0, 1); covariance_matrix (2, 0) = covariance_matrix (0, 2); @@ -486,8 +509,14 @@ computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, Eigen::Matrix &covariance_matrix, Eigen::Matrix ¢roid) { + // Shifted data/with estimate of mean. This gives very good accuracy and good performance. // create the buffer on the stack which is much faster than using cloud[indices[i]] and centroid as a buffer Eigen::Matrix accu = Eigen::Matrix::Zero (); + Eigen::Matrix K(0.0, 0.0, 0.0); + for(const auto& point: cloud) + if(isFinite(point)) { + K.x() = point.x; K.y() = point.y; K.z() = point.z; break; + } std::size_t point_count; if (cloud.is_dense) { @@ -495,15 +524,16 @@ computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, // For each point in the cloud for (const auto& point: cloud) { - accu [0] += point.x * point.x; - accu [1] += point.x * point.y; - accu [2] += point.x * point.z; - accu [3] += point.y * point.y; // 4 - accu [4] += point.y * point.z; // 5 - accu [5] += point.z * point.z; // 8 - accu [6] += point.x; - accu [7] += point.y; - accu [8] += point.z; + Scalar x = point.x - K.x(), y = point.y - K.y(), z = point.z - K.z(); + accu [0] += x * x; + accu [1] += x * y; + accu [2] += x * z; + accu [3] += y * y; + accu [4] += y * z; + accu [5] += z * z; + accu [6] += x; + accu [7] += y; + accu [8] += z; } } else @@ -514,23 +544,23 @@ computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, if (!isFinite (point)) continue; - accu [0] += point.x * point.x; - accu [1] += point.x * point.y; - accu [2] += point.x * point.z; - accu [3] += point.y * point.y; - accu [4] += point.y * point.z; - accu [5] += point.z * point.z; - accu [6] += point.x; - accu [7] += point.y; - accu [8] += point.z; + Scalar x = point.x - K.x(), y = point.y - K.y(), z = point.z - K.z(); + accu [0] += x * x; + accu [1] += x * y; + accu [2] += x * z; + accu [3] += y * y; + accu [4] += y * z; + accu [5] += z * z; + accu [6] += x; + accu [7] += y; + accu [8] += z; ++point_count; } } - accu /= static_cast (point_count); if (point_count != 0) { - //centroid.head<3> () = accu.tail<3> (); -- does not compile with Clang 3.0 - centroid[0] = accu[6]; centroid[1] = accu[7]; centroid[2] = accu[8]; + accu /= static_cast (point_count); + centroid[0] = accu[6] + K.x(); centroid[1] = accu[7] + K.y(); centroid[2] = accu[8] + K.z(); centroid[3] = 1; covariance_matrix.coeffRef (0) = accu [0] - accu [6] * accu [6]; covariance_matrix.coeffRef (1) = accu [1] - accu [6] * accu [7]; @@ -552,24 +582,30 @@ computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, Eigen::Matrix &covariance_matrix, Eigen::Matrix ¢roid) { + // Shifted data/with estimate of mean. This gives very good accuracy and good performance. // create the buffer on the stack which is much faster than using cloud[indices[i]] and centroid as a buffer Eigen::Matrix accu = Eigen::Matrix::Zero (); + Eigen::Matrix K(0.0, 0.0, 0.0); + for(const auto& index : indices) + if(isFinite(cloud[index])) { + K.x() = cloud[index].x; K.y() = cloud[index].y; K.z() = cloud[index].z; break; + } std::size_t point_count; if (cloud.is_dense) { point_count = indices.size (); for (const auto &index : indices) { - //const PointT& point = cloud[*iIt]; - accu [0] += cloud[index].x * cloud[index].x; - accu [1] += cloud[index].x * cloud[index].y; - accu [2] += cloud[index].x * cloud[index].z; - accu [3] += cloud[index].y * cloud[index].y; - accu [4] += cloud[index].y * cloud[index].z; - accu [5] += cloud[index].z * cloud[index].z; - accu [6] += cloud[index].x; - accu [7] += cloud[index].y; - accu [8] += cloud[index].z; + Scalar x = cloud[index].x - K.x(), y = cloud[index].y - K.y(), z = cloud[index].z - K.z(); + accu [0] += x * x; + accu [1] += x * y; + accu [2] += x * z; + accu [3] += y * y; + accu [4] += y * z; + accu [5] += z * z; + accu [6] += x; + accu [7] += y; + accu [8] += z; } } else @@ -581,34 +617,34 @@ computeMeanAndCovarianceMatrix (const pcl::PointCloud &cloud, continue; ++point_count; - accu [0] += cloud[index].x * cloud[index].x; - accu [1] += cloud[index].x * cloud[index].y; - accu [2] += cloud[index].x * cloud[index].z; - accu [3] += cloud[index].y * cloud[index].y; // 4 - accu [4] += cloud[index].y * cloud[index].z; // 5 - accu [5] += cloud[index].z * cloud[index].z; // 8 - accu [6] += cloud[index].x; - accu [7] += cloud[index].y; - accu [8] += cloud[index].z; + Scalar x = cloud[index].x - K.x(), y = cloud[index].y - K.y(), z = cloud[index].z - K.z(); + accu [0] += x * x; + accu [1] += x * y; + accu [2] += x * z; + accu [3] += y * y; + accu [4] += y * z; + accu [5] += z * z; + accu [6] += x; + accu [7] += y; + accu [8] += z; } } - accu /= static_cast (point_count); - //Eigen::Vector3f vec = accu.tail<3> (); - //centroid.head<3> () = vec;//= accu.tail<3> (); - //centroid.head<3> () = accu.tail<3> (); -- does not compile with Clang 3.0 - centroid[0] = accu[6]; centroid[1] = accu[7]; centroid[2] = accu[8]; - centroid[3] = 1; - covariance_matrix.coeffRef (0) = accu [0] - accu [6] * accu [6]; - covariance_matrix.coeffRef (1) = accu [1] - accu [6] * accu [7]; - covariance_matrix.coeffRef (2) = accu [2] - accu [6] * accu [8]; - covariance_matrix.coeffRef (4) = accu [3] - accu [7] * accu [7]; - covariance_matrix.coeffRef (5) = accu [4] - accu [7] * accu [8]; - covariance_matrix.coeffRef (8) = accu [5] - accu [8] * accu [8]; - covariance_matrix.coeffRef (3) = covariance_matrix.coeff (1); - covariance_matrix.coeffRef (6) = covariance_matrix.coeff (2); - covariance_matrix.coeffRef (7) = covariance_matrix.coeff (5); - + if (point_count != 0) + { + accu /= static_cast (point_count); + centroid[0] = accu[6] + K.x(); centroid[1] = accu[7] + K.y(); centroid[2] = accu[8] + K.z(); + centroid[3] = 1; + covariance_matrix.coeffRef (0) = accu [0] - accu [6] * accu [6]; + covariance_matrix.coeffRef (1) = accu [1] - accu [6] * accu [7]; + covariance_matrix.coeffRef (2) = accu [2] - accu [6] * accu [8]; + covariance_matrix.coeffRef (4) = accu [3] - accu [7] * accu [7]; + covariance_matrix.coeffRef (5) = accu [4] - accu [7] * accu [8]; + covariance_matrix.coeffRef (8) = accu [5] - accu [8] * accu [8]; + covariance_matrix.coeffRef (3) = covariance_matrix.coeff (1); + covariance_matrix.coeffRef (6) = covariance_matrix.coeff (2); + covariance_matrix.coeffRef (7) = covariance_matrix.coeff (5); + } return (static_cast (point_count)); } diff --git a/common/include/pcl/common/impl/common.hpp b/common/include/pcl/common/impl/common.hpp index 78df9b7a025..b4e80224aba 100644 --- a/common/include/pcl/common/impl/common.hpp +++ b/common/include/pcl/common/impl/common.hpp @@ -40,7 +40,7 @@ #include #include -#include // for FLT_MAX +#include ////////////////////////////////////////////////////////////////////////////////////////////// inline double @@ -196,7 +196,7 @@ pcl::getPointsInBox (const pcl::PointCloud &cloud, template inline void pcl::getMaxDistance (const pcl::PointCloud &cloud, const Eigen::Vector4f &pivot_pt, Eigen::Vector4f &max_pt) { - float max_dist = -FLT_MAX; + float max_dist = std::numeric_limits::lowest(); int max_idx = -1; float dist; const Eigen::Vector3f pivot_pt3 = pivot_pt.head<3> (); @@ -244,7 +244,7 @@ template inline void pcl::getMaxDistance (const pcl::PointCloud &cloud, const Indices &indices, const Eigen::Vector4f &pivot_pt, Eigen::Vector4f &max_pt) { - float max_dist = -FLT_MAX; + float max_dist = std::numeric_limits::lowest(); int max_idx = -1; float dist; const Eigen::Vector3f pivot_pt3 = pivot_pt.head<3> (); @@ -304,8 +304,8 @@ pcl::getMinMax3D (const pcl::PointCloud &cloud, PointT &min_pt, PointT & template inline void pcl::getMinMax3D (const pcl::PointCloud &cloud, Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt) { - min_pt.setConstant (FLT_MAX); - max_pt.setConstant (-FLT_MAX); + min_pt.setConstant (std::numeric_limits::max()); + max_pt.setConstant (std::numeric_limits::lowest()); // If the data is dense, we don't need to check for NaN if (cloud.is_dense) @@ -348,8 +348,8 @@ template inline void pcl::getMinMax3D (const pcl::PointCloud &cloud, const Indices &indices, Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt) { - min_pt.setConstant (FLT_MAX); - max_pt.setConstant (-FLT_MAX); + min_pt.setConstant (std::numeric_limits::max()); + max_pt.setConstant (std::numeric_limits::lowest()); // If the data is dense, we don't need to check for NaN if (cloud.is_dense) @@ -399,8 +399,8 @@ pcl::getCircumcircleRadius (const PointT &pa, const PointT &pb, const PointT &pc template inline void pcl::getMinMax (const PointT &histogram, int len, float &min_p, float &max_p) { - min_p = FLT_MAX; - max_p = -FLT_MAX; + min_p = std::numeric_limits::max(); + max_p = std::numeric_limits::lowest(); for (int i = 0; i < len; ++i) { diff --git a/common/include/pcl/common/impl/intensity.hpp b/common/include/pcl/common/impl/intensity.hpp index 526bcd94a17..687d934c40b 100644 --- a/common/include/pcl/common/impl/intensity.hpp +++ b/common/include/pcl/common/impl/intensity.hpp @@ -276,6 +276,40 @@ namespace pcl } }; + template<> + struct IntensityFieldAccessor + { + inline float + operator () (const pcl::PointXYZLAB &p) const + { + return (p.L); + } + + inline void + get (const pcl::PointXYZLAB &p, float &intensity) const + { + intensity = p.L; + } + + inline void + set (pcl::PointXYZLAB &p, float intensity) const + { + p.L = intensity; + } + + inline void + demean (pcl::PointXYZLAB& p, float value) const + { + p.L -= value; + } + + inline void + add (pcl::PointXYZLAB& p, float value) const + { + p.L += value; + } + }; + template<> struct IntensityFieldAccessor { diff --git a/common/include/pcl/common/impl/io.hpp b/common/include/pcl/common/impl/io.hpp index 4a147385f5b..230d319bbac 100644 --- a/common/include/pcl/common/impl/io.hpp +++ b/common/include/pcl/common/impl/io.hpp @@ -44,7 +44,6 @@ #include #include #include -#include namespace pcl @@ -117,6 +116,28 @@ getFieldsList (const pcl::PointCloud &) return (result); } +namespace detail +{ + + template void + copyPointCloudMemcpy (const pcl::PointCloud &cloud_in, + pcl::PointCloud &cloud_out) + { + // Iterate over each point, if the point types of two clouds are different + for (std::size_t i = 0; i < cloud_in.size (); ++i) + copyPoint (cloud_in[i], cloud_out[i]); + } + + + template void + copyPointCloudMemcpy (const pcl::PointCloud &cloud_in, + pcl::PointCloud &cloud_out) + { + // Use std::copy directly, if the point types of two clouds are same + std::copy (&cloud_in[0], (&cloud_in[0]) + cloud_in.size (), &cloud_out[0]); + } + +} // namespace detail template void copyPointCloud (const pcl::PointCloud &cloud_in, @@ -131,16 +152,8 @@ copyPointCloud (const pcl::PointCloud &cloud_in, cloud_out.sensor_origin_ = cloud_in.sensor_origin_; cloud_out.resize (cloud_in.size ()); - if (cloud_in.empty ()) - return; - - if (isSamePointType ()) - // Copy the whole memory block - memcpy (&cloud_out[0], &cloud_in[0], cloud_in.size () * sizeof (PointInT)); - else - // Iterate over each point - for (std::size_t i = 0; i < cloud_in.size (); ++i) - copyPoint (cloud_in[i], cloud_out[i]); + if (!cloud_in.empty ()) + detail::copyPointCloudMemcpy (cloud_in, cloud_out); } diff --git a/common/include/pcl/common/impl/transforms.hpp b/common/include/pcl/common/impl/transforms.hpp index 7c51e8fb82c..6c884d16c08 100644 --- a/common/include/pcl/common/impl/transforms.hpp +++ b/common/include/pcl/common/impl/transforms.hpp @@ -306,6 +306,45 @@ transformPointCloud (const pcl::PointCloud &cloud_in, } +inline void +transformPointCloud(const pcl::PointCloud &cloud_in, + pcl::PointCloud &cloud_out, + const Eigen::Affine2f &transform, + bool copy_all_fields) + { + if (&cloud_in != &cloud_out) + { + cloud_out.header = cloud_in.header; + cloud_out.is_dense = cloud_in.is_dense; + cloud_out.reserve (cloud_in.size ()); + if (copy_all_fields) + cloud_out.assign (cloud_in.begin (), cloud_in.end (), cloud_in.width); + else + cloud_out.resize (cloud_in.width, cloud_in.height); + cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_; + cloud_out.sensor_origin_ = cloud_in.sensor_origin_; + } + if(cloud_in.is_dense) + { + for (std::size_t i = 0; i < cloud_out.size (); ++i) + { + cloud_out[i].getVector2fMap () = transform * cloud_in[i].getVector2fMap(); + } + } + else + { + for (std::size_t i = 0; i < cloud_out.size (); ++i) + { + if (!std::isfinite(cloud_in[i].x) || !std::isfinite(cloud_in[i].y)) + { + continue; + } + cloud_out[i].getVector2fMap () = transform * cloud_in[i].getVector2fMap(); + } + } + } + + template void transformPointCloudWithNormals (const pcl::PointCloud &cloud_in, pcl::PointCloud &cloud_out, diff --git a/common/include/pcl/common/io.h b/common/include/pcl/common/io.h index 33dfaf049e5..4e765e4ea20 100644 --- a/common/include/pcl/common/io.h +++ b/common/include/pcl/common/io.h @@ -254,10 +254,8 @@ namespace pcl /** \brief Concatenate two pcl::PCLPointCloud2 * - * \warning This function subtly differs from the deprecated concatenatePointCloud() - * The difference is that this function will concatenate IFF the non-skip fields - * are in the correct order and same in number. The deprecated function skipped - * fields even if both clouds didn't agree on the number of output fields + * \warning This function will concatenate IFF the non-skip fields are in the correct + * order and same in number. * \param[in] cloud1 the first input point cloud dataset * \param[in] cloud2 the second input point cloud dataset * \param[out] cloud_out the resultant output point cloud dataset @@ -287,19 +285,6 @@ namespace pcl return pcl::PolygonMesh::concatenate(mesh1, mesh2, mesh_out); } - /** \brief Concatenate two pcl::PCLPointCloud2 - * \param[in] cloud1 the first input point cloud dataset - * \param[in] cloud2 the second input point cloud dataset - * \param[out] cloud_out the resultant output point cloud dataset - * \return true if successful, false otherwise (e.g., name/number of fields differs) - * \ingroup common - */ - PCL_DEPRECATED(1, 12, "use pcl::concatenate() instead, but beware of subtle difference in behavior (see documentation)") - PCL_EXPORTS bool - concatenatePointCloud (const pcl::PCLPointCloud2 &cloud1, - const pcl::PCLPointCloud2 &cloud2, - pcl::PCLPointCloud2 &cloud_out); - /** \brief Extract the indices of a given point cloud as a new point cloud * \param[in] cloud_in the input point cloud dataset * \param[in] indices the vector of indices representing the points to be copied from \a cloud_in @@ -347,7 +332,7 @@ namespace pcl * \note Assumes unique indices. * \ingroup common */ - template > void + template > void copyPointCloud (const pcl::PointCloud &cloud_in, const IndicesAllocator< IndicesVectorAllocator> &indices, pcl::PointCloud &cloud_out); @@ -392,7 +377,7 @@ namespace pcl * \note Assumes unique indices. * \ingroup common */ - template > void + template > void copyPointCloud (const pcl::PointCloud &cloud_in, const IndicesAllocator &indices, pcl::PointCloud &cloud_out); diff --git a/common/include/pcl/common/point_tests.h b/common/include/pcl/common/point_tests.h index abd58c3508a..dc11edef481 100644 --- a/common/include/pcl/common/point_tests.h +++ b/common/include/pcl/common/point_tests.h @@ -69,8 +69,13 @@ namespace pcl template<> inline bool isFinite(const pcl::BRISKSignature512&) { return (true); } template<> inline bool isFinite(const pcl::BorderDescription &) { return true; } template<> inline bool isFinite(const pcl::Boundary&) { return (true); } + template<> inline bool isFinite(const pcl::CPPFSignature&) { return (true); } template<> inline bool isFinite(const pcl::ESFSignature640&) { return (true); } template<> inline bool isFinite(const pcl::FPFHSignature33&) { return (true); } + template<> inline bool isFinite(const pcl::GASDSignature512&) { return (true); } + template<> inline bool isFinite(const pcl::GASDSignature984&) { return (true); } + template<> inline bool isFinite(const pcl::GASDSignature7992&) { return (true); } + template<> inline bool isFinite(const pcl::GRSDSignature21&) { return (true); } template<> inline bool isFinite(const pcl::Intensity&) { return (true); } template<> inline bool isFinite(const pcl::IntensityGradient&) { return (true); } template<> inline bool isFinite(const pcl::Label&) { return (true); } @@ -79,7 +84,12 @@ namespace pcl template<> inline bool isFinite(const pcl::PFHRGBSignature250&) { return (true); } template<> inline bool isFinite(const pcl::PFHSignature125&) { return (true); } template<> inline bool isFinite(const pcl::PPFRGBSignature&) { return (true); } - template<> inline bool isFinite(const pcl::PPFSignature&) { return (true); } + + template<> inline bool isFinite(const pcl::PPFSignature& pt) + { + return std::isfinite(pt.f1) && std::isfinite(pt.f2) && std::isfinite(pt.f3) && std::isfinite(pt.f4) && std::isfinite(pt.alpha_m); + } + template<> inline bool isFinite(const pcl::PrincipalCurvatures&) { return (true); } template<> inline bool isFinite(const pcl::PrincipalRadiiRSD&) { return (true); } template<> inline bool isFinite(const pcl::RGB&) { return (true); } diff --git a/common/include/pcl/common/random.h b/common/include/pcl/common/random.h index 6262172b9e1..6f8a2bc39fb 100644 --- a/common/include/pcl/common/random.h +++ b/common/include/pcl/common/random.h @@ -69,7 +69,7 @@ namespace pcl }; /** \brief UniformGenerator class generates a random number from range [min, max] at each run picked - * according to a uniform distribution i.e eaach number within [min, max] has almost the same + * according to a uniform distribution i.e each number within [min, max] has almost the same * probability of being drawn. * * \author Nizar Sallem diff --git a/common/include/pcl/common/time_trigger.h b/common/include/pcl/common/time_trigger.h index b9cfa72c264..1432cdcf1fc 100644 --- a/common/include/pcl/common/time_trigger.h +++ b/common/include/pcl/common/time_trigger.h @@ -39,9 +39,8 @@ #pragma once #include -#ifndef Q_MOC_RUN + #include -#endif #include #include diff --git a/common/include/pcl/common/transforms.h b/common/include/pcl/common/transforms.h index 347643f290d..5aa46b81848 100644 --- a/common/include/pcl/common/transforms.h +++ b/common/include/pcl/common/transforms.h @@ -40,7 +40,6 @@ #pragma once #include -#include #include #include #include @@ -437,6 +436,20 @@ namespace pcl return (transformPointCloudWithNormals (cloud_in, cloud_out, offset, rotation, copy_all_fields)); } + /** \brief Apply an affine transform on a pointcloud having points of type PointXY + * \param[in] cloud_in the input point cloud + * \param[out] cloud_out the resultant output point cloud + * \param[in] transform an affine transformation + * \param[in] copy_all_fields flag that controls whether the contents of the fields + * (other than x, y, z) should be copied into the new transformed cloud + * \ingroup common + */ + void + transformPointCloud(const pcl::PointCloud& cloud_in, + pcl::PointCloud& cloud_out, + const Eigen::Affine2f& transform, + bool copy_all_fields = true); + /** \brief Transform a point with members x,y,z * \param[in] point the point to transform * \param[out] transform the transformation to apply diff --git a/common/include/pcl/console/print.h b/common/include/pcl/console/print.h index 6e536234a12..0e84427b1c9 100644 --- a/common/include/pcl/console/print.h +++ b/common/include/pcl/console/print.h @@ -42,6 +42,18 @@ #include #include +// Use e.g. like this: +// PCL_INFO_STREAM("Info: this is a point: " << pcl::PointXYZ(1.0, 2.0, 3.0) << std::endl); +// PCL_ERROR_STREAM("Error: an Eigen vector: " << std::endl << Eigen::Vector3f(1.0, 2.0, 3.0) << std::endl); +#define PCL_LOG_STREAM(LEVEL, STREAM, CSTR, ATTR, FG, ARGS) if(pcl::console::isVerbosityLevelEnabled(pcl::console::LEVEL)) { fflush(stdout); pcl::console::change_text_color(CSTR, pcl::console::ATTR, pcl::console::FG); STREAM << ARGS; pcl::console::reset_text_color(CSTR); } +#define PCL_ALWAYS_STREAM(ARGS) PCL_LOG_STREAM(L_ALWAYS, std::cout, stdout, TT_RESET, TT_WHITE, ARGS) +#define PCL_ERROR_STREAM(ARGS) PCL_LOG_STREAM(L_ERROR, std::cerr, stderr, TT_BRIGHT, TT_RED, ARGS) +#define PCL_WARN_STREAM(ARGS) PCL_LOG_STREAM(L_WARN, std::cerr, stderr, TT_BRIGHT, TT_YELLOW, ARGS) +#define PCL_INFO_STREAM(ARGS) PCL_LOG_STREAM(L_INFO, std::cout, stdout, TT_RESET, TT_WHITE, ARGS) +#define PCL_DEBUG_STREAM(ARGS) PCL_LOG_STREAM(L_DEBUG, std::cout, stdout, TT_RESET, TT_GREEN, ARGS) +#define PCL_VERBOSE_STREAM(ARGS) PCL_LOG_STREAM(L_VERBOSE, std::cout, stdout, TT_RESET, TT_WHITE, ARGS) + + #define PCL_ALWAYS(...) pcl::console::print (pcl::console::L_ALWAYS, __VA_ARGS__) #define PCL_ERROR(...) pcl::console::print (pcl::console::L_ERROR, __VA_ARGS__) #define PCL_WARN(...) pcl::console::print (pcl::console::L_WARN, __VA_ARGS__) diff --git a/common/include/pcl/conversions.h b/common/include/pcl/conversions.h index 177b6be87ee..2732d5cf469 100644 --- a/common/include/pcl/conversions.h +++ b/common/include/pcl/conversions.h @@ -50,9 +50,6 @@ #include #include #include -#ifndef Q_MOC_RUN -#include -#endif namespace pcl { @@ -67,10 +64,10 @@ namespace pcl template void operator() () { pcl::PCLPointField f; - f.name = traits::name::value; - f.offset = traits::offset::value; - f.datatype = traits::datatype::value; - f.count = traits::datatype::size; + f.name = pcl::traits::name::value; + f.offset = pcl::traits::offset::value; + f.datatype = pcl::traits::datatype::value; + f.count = pcl::traits::datatype::size; fields_.push_back (f); } @@ -96,14 +93,14 @@ namespace pcl { FieldMapping mapping; mapping.serialized_offset = field.offset; - mapping.struct_offset = traits::offset::value; - mapping.size = sizeof (typename traits::datatype::type); + mapping.struct_offset = pcl::traits::offset::value; + mapping.size = sizeof (typename pcl::traits::datatype::type); map_.push_back (mapping); return; } } // Disable thrown exception per #595: http://dev.pointclouds.org/issues/595 - PCL_WARN ("Failed to find match for field '%s'.\n", traits::name::value); + PCL_WARN ("Failed to find match for field '%s'.\n", pcl::traits::name::value); //throw pcl::InvalidConversionException (ss.str ()); } @@ -174,8 +171,7 @@ namespace pcl cloud.is_dense = msg.is_dense == 1; // Copy point data - std::uint32_t num_points = msg.width * msg.height; - cloud.resize (num_points); + cloud.resize (msg.width * msg.height); std::uint8_t* cloud_data = reinterpret_cast(&cloud[0]); // Check if we can copy adjacent points in a single memcpy. We can do so if there @@ -187,7 +183,7 @@ namespace pcl field_map[0].size == msg.point_step && field_map[0].size == sizeof(PointT)) { - std::uint32_t cloud_row_step = static_cast (sizeof (PointT) * cloud.width); + const auto cloud_row_step = (sizeof (PointT) * cloud.width); const std::uint8_t* msg_data = &msg.data[0]; // Should usually be able to copy all rows at once if (msg.row_step == cloud_row_step) @@ -196,7 +192,7 @@ namespace pcl } else { - for (std::uint32_t i = 0; i < msg.height; ++i, cloud_data += cloud_row_step, msg_data += msg.row_step) + for (uindex_t i = 0; i < msg.height; ++i, cloud_data += cloud_row_step, msg_data += msg.row_step) memcpy (cloud_data, msg_data, cloud_row_step); } @@ -204,10 +200,10 @@ namespace pcl else { // If not, memcpy each group of contiguous fields separately - for (index_t row = 0; row < msg.height; ++row) + for (uindex_t row = 0; row < msg.height; ++row) { const std::uint8_t* row_data = &msg.data[row * msg.row_step]; - for (index_t col = 0; col < msg.width; ++col) + for (uindex_t col = 0; col < msg.width; ++col) { const std::uint8_t* msg_data = row_data + col * msg.point_step; for (const detail::FieldMapping& mapping : field_map) @@ -266,7 +262,7 @@ namespace pcl msg.header = cloud.header; msg.point_step = sizeof (PointT); - msg.row_step = static_cast (sizeof (PointT) * msg.width); + msg.row_step = (sizeof (PointT) * msg.width); msg.is_dense = cloud.is_dense; /// @todo msg.is_bigendian = ?; } @@ -327,13 +323,13 @@ namespace pcl msg.height = cloud.height; msg.width = cloud.width; } - int rgb_offset = cloud.fields[rgb_index].offset; - int point_step = cloud.point_step; + auto rgb_offset = cloud.fields[rgb_index].offset; + const auto point_step = cloud.point_step; // pcl::image_encodings::BGR8; msg.header = cloud.header; msg.encoding = "bgr8"; - msg.step = static_cast(msg.width * sizeof (std::uint8_t) * 3); + msg.step = (msg.width * sizeof (std::uint8_t) * 3); msg.data.resize (msg.step * msg.height); for (std::size_t y = 0; y < cloud.height; y++) diff --git a/common/include/pcl/correspondence.h b/common/include/pcl/correspondence.h index 0b8d1f8b84c..825e20557e3 100644 --- a/common/include/pcl/correspondence.h +++ b/common/include/pcl/correspondence.h @@ -71,7 +71,7 @@ namespace pcl }; /** \brief Standard constructor. - * Sets \ref index_query to 0, \ref index_match to -1, and \ref distance to FLT_MAX. + * Sets \ref index_query to 0, \ref index_match to -1, and \ref distance to std::numeric_limits::max(). */ inline Correspondence () = default; diff --git a/common/include/pcl/for_each_type.h b/common/include/pcl/for_each_type.h index 3abbad748f2..fc5ca3502ab 100644 --- a/common/include/pcl/for_each_type.h +++ b/common/include/pcl/for_each_type.h @@ -43,7 +43,6 @@ #pragma GCC system_header #endif -#ifndef Q_MOC_RUN #include #include #include @@ -53,7 +52,6 @@ #include #include #include -#endif #include @@ -76,7 +74,7 @@ namespace pcl { using arg = typename boost::mpl::deref::type; -#if (defined _WIN32 && defined _MSC_VER) +#if (defined _WIN32 && defined _MSC_VER && !defined(__clang__)) boost::mpl::aux::unwrap (f, 0).operator() (); #else boost::mpl::aux::unwrap (f, 0).template operator() (); diff --git a/common/include/pcl/impl/point_types.hpp b/common/include/pcl/impl/point_types.hpp index 7b57a62ed5f..3a30465051d 100644 --- a/common/include/pcl/impl/point_types.hpp +++ b/common/include/pcl/impl/point_types.hpp @@ -68,6 +68,7 @@ (pcl::PointXYZRGBA) \ (pcl::PointXYZRGB) \ (pcl::PointXYZRGBL) \ + (pcl::PointXYZLAB) \ (pcl::PointXYZHSV) \ (pcl::PointXY) \ (pcl::InterestPoint) \ @@ -125,6 +126,7 @@ (pcl::PointXYZRGBA) \ (pcl::PointXYZRGB) \ (pcl::PointXYZRGBL) \ + (pcl::PointXYZLAB) \ (pcl::PointXYZHSV) \ (pcl::InterestPoint) \ (pcl::PointNormal) \ @@ -170,9 +172,55 @@ (pcl::BRISKSignature512) \ (pcl::Narf36) +// Define all point types that have descriptorSize() member function +#define PCL_DESCRIPTOR_FEATURE_POINT_TYPES \ + (pcl::PFHSignature125) \ + (pcl::PFHRGBSignature250) \ + (pcl::FPFHSignature33) \ + (pcl::VFHSignature308) \ + (pcl::GASDSignature512) \ + (pcl::GASDSignature984) \ + (pcl::GASDSignature7992) \ + (pcl::GRSDSignature21) \ + (pcl::ESFSignature640) \ + (pcl::BRISKSignature512) \ + (pcl::Narf36) + + namespace pcl { - + namespace detail + { + namespace traits + { + template struct descriptorSize {}; + + template<> struct descriptorSize { static constexpr const int value = 125; }; + template<> struct descriptorSize { static constexpr const int value = 250; }; + template<> struct descriptorSize { static constexpr const int value = 1980; }; + template<> struct descriptorSize { static constexpr const int value = 1960; }; + template<> struct descriptorSize { static constexpr const int value = 352; }; + template<> struct descriptorSize { static constexpr const int value = 1344; }; + template<> struct descriptorSize { static constexpr const int value = 33; }; + template<> struct descriptorSize { static constexpr const int value = 308; }; + template<> struct descriptorSize { static constexpr const int value = 21; }; + template<> struct descriptorSize { static constexpr const int value = 512; }; + template<> struct descriptorSize { static constexpr const int value = 640; }; + template<> struct descriptorSize { static constexpr const int value = 512; }; + template<> struct descriptorSize { static constexpr const int value = 984; }; + template<> struct descriptorSize { static constexpr const int value = 7992; }; + template<> struct descriptorSize { static constexpr const int value = 16; }; + template<> struct descriptorSize { static constexpr const int value = 36; }; + template struct descriptorSize> { static constexpr const int value = N; }; + + + template + static constexpr int descriptorSize_v = descriptorSize::value; + } + } + + using Vector2fMap = Eigen::Map; + using Vector2fMapConst = const Eigen::Map; using Array3fMap = Eigen::Map; using Array3fMapConst = const Eigen::Map; using Array4fMap = Eigen::Map; @@ -200,6 +248,8 @@ namespace pcl }; #define PCL_ADD_EIGEN_MAPS_POINT4D \ + inline pcl::Vector2fMap getVector2fMap () { return (pcl::Vector2fMap (data)); } \ + inline pcl::Vector2fMapConst getVector2fMap () const { return (pcl::Vector2fMapConst (data)); } \ inline pcl::Vector3fMap getVector3fMap () { return (pcl::Vector3fMap (data)); } \ inline pcl::Vector3fMapConst getVector3fMap () const { return (pcl::Vector3fMapConst (data)); } \ inline pcl::Vector4fMap getVector4fMap () { return (pcl::Vector4fMap (data)); } \ @@ -558,13 +608,13 @@ namespace pcl rgba = p.rgba; } - inline PointXYZRGBA (): PointXYZRGBA (0, 0, 0, 0) {} + inline PointXYZRGBA (): PointXYZRGBA (0, 0, 0, 255) {} inline PointXYZRGBA (std::uint8_t _r, std::uint8_t _g, std::uint8_t _b, std::uint8_t _a): PointXYZRGBA (0.f, 0.f, 0.f, _r, _g, _b, _a) {} inline PointXYZRGBA (float _x, float _y, float _z): - PointXYZRGBA (_x, _y, _z, 0, 0, 0, 0) {} + PointXYZRGBA (_x, _y, _z, 0, 0, 0, 255) {} inline PointXYZRGBA (float _x, float _y, float _z, std::uint8_t _r, std::uint8_t _g, std::uint8_t _b, std::uint8_t _a) @@ -690,6 +740,47 @@ namespace pcl }; + struct EIGEN_ALIGN16 _PointXYZLAB + { + PCL_ADD_POINT4D; // this adds the members x,y,z + union + { + struct + { + float L; + float a; + float b; + }; + float data_lab[4]; + }; + PCL_MAKE_ALIGNED_OPERATOR_NEW + }; + + PCL_EXPORTS std::ostream& operator << (std::ostream& os, const PointXYZLAB& p); + /** \brief A point structure representing Euclidean xyz coordinates, and the CIELAB color. + * \ingroup common + */ + struct PointXYZLAB : public _PointXYZLAB + { + inline PointXYZLAB (const _PointXYZLAB &p) + { + x = p.x; y = p.y; z = p.z; data[3] = 1.0f; + L = p.L; a = p.a; b = p.b; + } + + inline PointXYZLAB() + { + x = y = z = 0.0f; + data[3] = 1.0f; // important for homogeneous coordinates + L = a = b = 0.0f; + data_lab[3] = 0.0f; + } + + friend std::ostream& operator << (std::ostream& os, const PointXYZLAB& p); + PCL_MAKE_ALIGNED_OPERATOR_NEW + }; + + struct EIGEN_ALIGN16 _PointXYZHSV { PCL_ADD_POINT4D; // This adds the members x,y,z which can also be accessed using the point (which is float[4]) @@ -743,13 +834,22 @@ namespace pcl */ struct PointXY { - float x = 0.f; - float y = 0.f; - - inline PointXY() = default; + union + { + float data[2]; + struct + { + float x; + float y; + }; + }; inline PointXY(float _x, float _y): x(_x), y(_y) {} - + inline PointXY():x(0.0f),y(0.0f) {} + + inline pcl::Vector2fMap getVector2fMap () { return (pcl::Vector2fMap (data)); } + inline pcl::Vector2fMapConst getVector2fMap () const { return (pcl::Vector2fMapConst (data)); } + friend std::ostream& operator << (std::ostream& os, const PointXY& p); }; @@ -1264,13 +1364,14 @@ namespace pcl struct PFHSignature125 { float histogram[125] = {0.f}; - static int descriptorSize () { return 125; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline PFHSignature125 () = default; friend std::ostream& operator << (std::ostream& os, const PFHSignature125& p); }; + PCL_EXPORTS std::ostream& operator << (std::ostream& os, const PFHRGBSignature250& p); /** \brief A point structure representing the Point Feature Histogram with colors (PFHRGB). * \ingroup common @@ -1278,7 +1379,7 @@ namespace pcl struct PFHRGBSignature250 { float histogram[250] = {0.f}; - static int descriptorSize () { return 250; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline PFHRGBSignature250 () = default; @@ -1365,7 +1466,7 @@ namespace pcl { float descriptor[1980] = {0.f}; float rf[9] = {0.f}; - static int descriptorSize () { return 1980; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline ShapeContext1980 () = default; @@ -1380,7 +1481,7 @@ namespace pcl { float descriptor[1960] = {0.f}; float rf[9] = {0.f}; - static int descriptorSize () { return 1960; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline UniqueShapeContext1960 () = default; @@ -1395,7 +1496,7 @@ namespace pcl { float descriptor[352] = {0.f}; float rf[9] = {0.f}; - static int descriptorSize () { return 352; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline SHOT352 () = default; @@ -1411,7 +1512,7 @@ namespace pcl { float descriptor[1344] = {0.f}; float rf[9] = {0.f}; - static int descriptorSize () { return 1344; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline SHOT1344 () = default; @@ -1476,7 +1577,7 @@ namespace pcl struct FPFHSignature33 { float histogram[33] = {0.f}; - static int descriptorSize () { return 33; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline FPFHSignature33 () = default; @@ -1490,7 +1591,7 @@ namespace pcl struct VFHSignature308 { float histogram[308] = {0.f}; - static int descriptorSize () { return 308; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline VFHSignature308 () = default; @@ -1504,7 +1605,7 @@ namespace pcl struct GRSDSignature21 { float histogram[21] = {0.f}; - static int descriptorSize () { return 21; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline GRSDSignature21 () = default; @@ -1520,7 +1621,7 @@ namespace pcl float scale = 0.f; float orientation = 0.f; unsigned char descriptor[64] = {0}; - static int descriptorSize () { return 64; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline BRISKSignature512 () = default; @@ -1536,7 +1637,7 @@ namespace pcl struct ESFSignature640 { float histogram[640] = {0.f}; - static int descriptorSize () { return 640; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline ESFSignature640 () = default; @@ -1550,7 +1651,7 @@ namespace pcl struct GASDSignature512 { float histogram[512] = {0.f}; - static int descriptorSize() { return 512; } + static constexpr int descriptorSize() { return detail::traits::descriptorSize_v; } inline GASDSignature512 () = default; @@ -1564,7 +1665,7 @@ namespace pcl struct GASDSignature984 { float histogram[984] = {0.f}; - static int descriptorSize() { return 984; } + static constexpr int descriptorSize() { return detail::traits::descriptorSize_v; } inline GASDSignature984 () = default; @@ -1578,7 +1679,7 @@ namespace pcl struct GASDSignature7992 { float histogram[7992] = {0.f}; - static int descriptorSize() { return 7992; } + static constexpr int descriptorSize() { return detail::traits::descriptorSize_v; } inline GASDSignature7992 () = default; @@ -1592,7 +1693,7 @@ namespace pcl struct GFPFHSignature16 { float histogram[16] = {0.f}; - static int descriptorSize () { return 16; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline GFPFHSignature16 () = default; @@ -1607,7 +1708,7 @@ namespace pcl { float x = 0.f, y = 0.f, z = 0.f, roll = 0.f, pitch = 0.f, yaw = 0.f; float descriptor[36] = {0.f}; - static int descriptorSize () { return 36; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v; } inline Narf36 () = default; @@ -1669,7 +1770,7 @@ namespace pcl struct Histogram { float histogram[N]; - static int descriptorSize () { return N; } + static constexpr int descriptorSize () { return detail::traits::descriptorSize_v>; } }; struct EIGEN_ALIGN16 _PointWithScale @@ -1818,7 +1919,7 @@ namespace pcl operator << (std::ostream& os, const Histogram& p) { // make constexpr - if (N > 0) + PCL_IF_CONSTEXPR(N > 0) { os << "(" << p.histogram[0]; std::for_each(p.histogram + 1, std::end(p.histogram), @@ -1882,6 +1983,16 @@ POINT_CLOUD_REGISTER_POINT_STRUCT (pcl::_PointXYZRGBL, ) POINT_CLOUD_REGISTER_POINT_WRAPPER(pcl::PointXYZRGBL, pcl::_PointXYZRGBL) +POINT_CLOUD_REGISTER_POINT_STRUCT (pcl::_PointXYZLAB, + (float, x, x) + (float, y, y) + (float, z, z) + (float, L, L) + (float, a, a) + (float, b, b) +) +POINT_CLOUD_REGISTER_POINT_WRAPPER(pcl::PointXYZLAB, pcl::_PointXYZLAB) + POINT_CLOUD_REGISTER_POINT_STRUCT (pcl::_PointXYZHSV, (float, x, x) (float, y, y) diff --git a/common/include/pcl/pcl_macros.h b/common/include/pcl/pcl_macros.h index 6239707a869..a615d477b1b 100644 --- a/common/include/pcl/pcl_macros.h +++ b/common/include/pcl/pcl_macros.h @@ -376,44 +376,48 @@ pcl_round (float number) #endif #endif +namespace pcl { + inline void* -aligned_malloc (std::size_t size) +aligned_malloc(std::size_t size) { - void *ptr; -#if defined (MALLOC_ALIGNED) - ptr = std::malloc (size); -#elif defined (HAVE_POSIX_MEMALIGN) - if (posix_memalign (&ptr, 16, size)) + void* ptr; +#if defined(MALLOC_ALIGNED) + ptr = std::malloc(size); +#elif defined(HAVE_POSIX_MEMALIGN) + if (posix_memalign(&ptr, 16, size)) ptr = 0; -#elif defined (HAVE_MM_MALLOC) - ptr = _mm_malloc (size, 16); -#elif defined (_MSC_VER) - ptr = _aligned_malloc (size, 16); -#elif defined (ANDROID) - ptr = memalign (16, size); +#elif defined(HAVE_MM_MALLOC) + ptr = _mm_malloc(size, 16); +#elif defined(_MSC_VER) + ptr = _aligned_malloc(size, 16); +#elif defined(ANDROID) + ptr = memalign(16, size); #else - #error aligned_malloc not supported on your platform +#error aligned_malloc not supported on your platform ptr = 0; #endif return (ptr); } inline void -aligned_free (void* ptr) +aligned_free(void* ptr) { -#if defined (MALLOC_ALIGNED) || defined (HAVE_POSIX_MEMALIGN) - std::free (ptr); -#elif defined (HAVE_MM_MALLOC) - _mm_free (ptr); -#elif defined (_MSC_VER) - _aligned_free (ptr); -#elif defined (ANDROID) - free (ptr); +#if defined(MALLOC_ALIGNED) || defined(HAVE_POSIX_MEMALIGN) + std::free(ptr); +#elif defined(HAVE_MM_MALLOC) + _mm_free(ptr); +#elif defined(_MSC_VER) + _aligned_free(ptr); +#elif defined(ANDROID) + free(ptr); #else - #error aligned_free not supported on your platform +#error aligned_free not supported on your platform #endif } +} // namespace pcl + /** * \brief Macro to add a no-op or a fallthrough attribute based on compiler feature * @@ -438,3 +442,40 @@ aligned_free (void* ptr) #else #define PCL_NODISCARD #endif + +#ifdef __cpp_if_constexpr + #define PCL_IF_CONSTEXPR(x) if constexpr(x) +#else + #define PCL_IF_CONSTEXPR(x) if (x) +#endif + +// [[unlikely]] can be used on any conditional branch, but __builtin_expect is restricted to the evaluation point +// This makes it quite difficult to create a single macro for switch and while/if +/** + * @def PCL_CONDITION_UNLIKELY + * @brief Tries to inform the compiler to optimize codegen assuming that the condition will probably evaluate to false + * @note Prefer using `PCL_{IF,WHILE}_UNLIKELY` + * @warning This can't be used with switch statements + * @details This tries to help the compiler optimize for the unlikely case. + * Most compilers assume that the condition would evaluate to true in if and while loops (reference needed) + * As such the opposite of this macro (PCL_CONDITION_LIKELY) will not result in significant performance improvement + * + * Some sample usage: + * @code{.cpp} + * if PCL_CONDITION_UNLIKELY(x == 0) { return; } else { throw std::runtime_error("some error"); } + * // + * while PCL_CONDITION_UNLIKELY(wait_for_result) { sleep(1); } // busy wait, with minimal chances of waiting + * @endcode + */ +#if __has_cpp_attribute(unlikely) + #define PCL_CONDITION_UNLIKELY(x) (static_cast(x)) [[unlikely]] +#elif defined(__GNUC__) + #define PCL_CONDITION_UNLIKELY(x) (__builtin_expect(static_cast(x), 0)) +#elif defined(__clang__) && (PCL_LINEAR_VERSION(__clang_major__, __clang_minor__, 0) >= PCL_LINEAR_VERSION(3, 9, 0)) + #define PCL_CONDITION_UNLIKELY(x) (__builtin_expect(static_cast(x), 0)) +#else // MSVC has no such alternative + #define PCL_CONDITION_UNLIKELY(x) (x) +#endif + +#define PCL_IF_UNLIKELY(x) if PCL_CONDITION_UNLIKELY(x) +#define PCL_WHILE_UNLIKELY(x) while PCL_CONDITION_UNLIKELY(x) diff --git a/common/include/pcl/pcl_tests.h b/common/include/pcl/pcl_tests.h index 2b7f5e4b30b..7cdb9b577d9 100644 --- a/common/include/pcl/pcl_tests.h +++ b/common/include/pcl/pcl_tests.h @@ -64,7 +64,7 @@ namespace pcl { SCOPED_TRACE("EXPECT_EQ_VECTORS failed"); EXPECT_EQ (v1.size (), v2.size ()); - std::size_t length = v1.size (); + std::size_t length = std::min (v1.size (), v2.size ()); for (std::size_t i = 0; i < length; ++i) EXPECT_EQ (v1[i], v2[i]); } @@ -74,7 +74,7 @@ namespace pcl { SCOPED_TRACE("EXPECT_NEAR_VECTORS failed"); EXPECT_EQ (v1.size (), v2.size ()); - std::size_t length = v1.size (); + std::size_t length = std::min (v1.size (), v2.size()); for (std::size_t i = 0; i < length; ++i) EXPECT_NEAR (v1[i], v2[i], epsilon); } diff --git a/common/include/pcl/point_cloud.h b/common/include/pcl/point_cloud.h index 905a1647c68..fa2172df178 100644 --- a/common/include/pcl/point_cloud.h +++ b/common/include/pcl/point_cloud.h @@ -315,9 +315,12 @@ namespace pcl /** \brief Return an Eigen MatrixXf (assumes float values) mapped to the specified dimensions of the PointCloud. * \note This method is for advanced users only! Use with care! * - * \attention Since 1.4.0, Eigen matrices are forced to Row Major to increase the efficiency of the algorithms in PCL - * This means that the behavior of getMatrixXfMap changed, and is now correctly mapping 1-1 with a PointCloud structure, - * that is: number of points in a cloud = rows in a matrix, number of point dimensions = columns in a matrix + * \attention Compile time flags used for Eigen might affect the dimension of the Eigen::Map returned. If Eigen + * is using row major storage, the matrix shape would be (number of Points X elements in a Point) else + * the matrix shape would be (elements in a Point X number of Points). Essentially, + * * Major direction: number of points in cloud + * * Minor direction: number of point dimensions + * By default, as of Eigen 3.3, Eigen uses Column major storage * * \param[in] dim the number of dimensions to consider for each point * \param[in] stride the number of values in each point (will be the number of values that separate two of the columns) @@ -338,9 +341,12 @@ namespace pcl /** \brief Return an Eigen MatrixXf (assumes float values) mapped to the specified dimensions of the PointCloud. * \note This method is for advanced users only! Use with care! * - * \attention Since 1.4.0, Eigen matrices are forced to Row Major to increase the efficiency of the algorithms in PCL - * This means that the behavior of getMatrixXfMap changed, and is now correctly mapping 1-1 with a PointCloud structure, - * that is: number of points in a cloud = rows in a matrix, number of point dimensions = columns in a matrix + * \attention Compile time flags used for Eigen might affect the dimension of the Eigen::Map returned. If Eigen + * is using row major storage, the matrix shape would be (number of Points X elements in a Point) else + * the matrix shape would be (elements in a Point X number of Points). Essentially, + * * Major direction: number of points in cloud + * * Minor direction: number of point dimensions + * By default, as of Eigen 3.3, Eigen uses Column major storage * * \param[in] dim the number of dimensions to consider for each point * \param[in] stride the number of values in each point (will be the number of values that separate two of the columns) @@ -536,6 +542,7 @@ namespace pcl * \note This breaks the organized structure of the cloud by setting the height to * 1! * \param[in] count new size of the point cloud + * \param[in] value value each point of the cloud should have */ inline void assign(index_t count, const PointT& value) @@ -549,6 +556,7 @@ namespace pcl * \brief Replaces the points with `new_width * new_height` copies of `value` * \param[in] new_width new width of the point cloud * \param[in] new_height new height of the point cloud + * \param[in] value value each point of the cloud should have */ inline void assign(index_t new_width, index_t new_height, const PointT& value) @@ -580,18 +588,25 @@ namespace pcl * `*this` * \note This calculates the height based on size and width provided. This means * the assignment happens even if the size is not perfectly divisible by width + * \param[in] first, last the range from which the points are copied * \param[in] new_width new width of the point cloud */ template inline void assign(InputIterator first, InputIterator last, index_t new_width) { + if (new_width == 0) { + PCL_WARN("Assignment with new_width equal to 0," + "setting width to size of the cloud and height to 1\n"); + return assign(std::move(first), std::move(last)); + } + points.assign(std::move(first), std::move(last)); width = new_width; height = size() / width; if (width * height != size()) { PCL_WARN("Mismatch in assignment. Requested width (%zu) doesn't divide " - "provided size (%zu) cleanly. Setting height to 1", + "provided size (%zu) cleanly. Setting height to 1\n", static_cast(width), static_cast(size())); width = size(); @@ -616,17 +631,23 @@ namespace pcl * \brief Replaces the points with the elements from the initializer list `ilist` * \note This calculates the height based on size and width provided. This means * the assignment happens even if the size is not perfectly divisible by width + * \param[in] ilist initializer list from which the points are copied * \param[in] new_width new width of the point cloud */ void inline assign(std::initializer_list ilist, index_t new_width) { + if (new_width == 0) { + PCL_WARN("Assignment with new_width equal to 0," + "setting width to size of the cloud and height to 1\n"); + return assign(std::move(ilist)); + } points.assign(std::move(ilist)); width = new_width; height = size() / width; if (width * height != size()) { PCL_WARN("Mismatch in assignment. Requested width (%zu) doesn't divide " - "provided size (%zu) cleanly. Setting height to 1", + "provided size (%zu) cleanly. Setting height to 1\n", static_cast(width), static_cast(size())); width = size(); diff --git a/common/include/pcl/point_struct_traits.h b/common/include/pcl/point_struct_traits.h index 6640a0c2644..1299d8132e8 100644 --- a/common/include/pcl/point_struct_traits.h +++ b/common/include/pcl/point_struct_traits.h @@ -37,8 +37,6 @@ #pragma once -// https://bugreports.qt-project.org/browse/QTBUG-22829 -#ifndef Q_MOC_RUN #include // for BOOST_MPL_ASSERT_MSG #include // for boost::mpl::identity @@ -46,7 +44,6 @@ #include // for BOOST_PP_SEQ_ENUM #include // for BOOST_PP_TUPLE_ELEM #include // for BOOST_PP_STRINGIZE -#endif // This is required for the workaround at line 84 #ifdef _MSC_VER diff --git a/common/include/pcl/point_types.h b/common/include/pcl/point_types.h index 1d47ba2edb0..b1f20e0bd5c 100644 --- a/common/include/pcl/point_types.h +++ b/common/include/pcl/point_types.h @@ -111,6 +111,11 @@ namespace pcl */ struct PointXYZRGBL; + /** \brief Members: float x, y, z, L, a, b + * \ingroup common + */ + struct PointXYZLAB; + /** \brief Members: float x, y, z, h, s, v * \ingroup common */ diff --git a/common/include/pcl/point_types_conversion.h b/common/include/pcl/point_types_conversion.h index a220e6060e7..a4afdace339 100644 --- a/common/include/pcl/point_types_conversion.h +++ b/common/include/pcl/point_types_conversion.h @@ -43,6 +43,8 @@ #include #include +#include // for RGB2sRGB_LUT + namespace pcl { // r,g,b, i values are from 0 to 255 @@ -134,6 +136,57 @@ namespace pcl if (out.h < 0.f) out.h += 360.f; } + /** \brief Convert a XYZRGB-based point type to a XYZLAB + * \param[in] in the input XYZRGB(XYZRGBA, XYZRGBL, etc.) point + * \param[out] out the output XYZLAB point + */ + template = true> + inline void + PointXYZRGBtoXYZLAB (const PointT& in, + PointXYZLAB& out) + { + out.x = in.x; + out.y = in.y; + out.z = in.z; + out.data[3] = 1.0; // important for homogeneous coordinates + + // convert sRGB to CIELAB + // for sRGB -> CIEXYZ see http://www.easyrgb.com/index.php?X=MATH&H=02#text2 + // for CIEXYZ -> CIELAB see http://www.easyrgb.com/index.php?X=MATH&H=07#text7 + // an overview at: https://www.comp.nus.edu.sg/~leowwk/papers/colordiff.pdf + + const auto& sRGB_LUT = RGB2sRGB_LUT(); + + const double R = sRGB_LUT[in.r]; + const double G = sRGB_LUT[in.g]; + const double B = sRGB_LUT[in.b]; + + // linear sRGB -> CIEXYZ, D65 illuminant, observer at 2 degrees + const double X = R * 0.4124 + G * 0.3576 + B * 0.1805; + const double Y = R * 0.2126 + G * 0.7152 + B * 0.0722; + const double Z = R * 0.0193 + G * 0.1192 + B * 0.9505; + + // normalize X, Y, Z with tristimulus values for Xn, Yn, Zn + float f[3] = {static_cast(X), static_cast(Y), static_cast(Z)}; + f[0] /= 0.95047; + f[1] /= 1; + f[2] /= 1.08883; + + // CIEXYZ -> CIELAB + for (int i = 0; i < 3; ++i) { + if (f[i] > 0.008856) { + f[i] = std::pow(f[i], 1.0 / 3.0); + } + else { + f[i] = 7.787 * f[i] + 16.0 / 116.0; + } + } + + out.L = 116.0f * f[1] - 16.0f; + out.a = 500.0f * (f[0] - f[1]); + out.b = 200.0f * (f[1] - f[2]); + } + /** \brief Convert a XYZRGBA point type to a XYZHSV * \param[in] in the input XYZRGBA point * \param[out] out the output XYZHSV point @@ -250,7 +303,7 @@ namespace pcl { out.width = in.width; out.height = in.height; - for (const auto &point : in.points) + for (const auto &point : in) { Intensity p; PointRGBtoI (point, p); @@ -268,7 +321,7 @@ namespace pcl { out.width = in.width; out.height = in.height; - for (const auto &point : in.points) + for (const auto &point : in) { Intensity8u p; PointRGBtoI (point, p); @@ -286,7 +339,7 @@ namespace pcl { out.width = in.width; out.height = in.height; - for (const auto &point : in.points) + for (const auto &point : in) { Intensity32u p; PointRGBtoI (point, p); @@ -304,13 +357,31 @@ namespace pcl { out.width = in.width; out.height = in.height; - for (const auto &point : in.points) + for (const auto &point : in) { PointXYZHSV p; PointXYZRGBtoXYZHSV (point, p); out.push_back (p); } } + + /** \brief Convert a XYZHSV point cloud to a XYZRGB + * \param[in] in the input XYZHSV point cloud + * \param[out] out the output XYZRGB point cloud + */ + inline void + PointCloudXYZHSVtoXYZRGB (const PointCloud& in, + PointCloud& out) + { + out.width = in.width; + out.height = in.height; + for (const auto &point : in) + { + PointXYZRGB p; + PointXYZHSVtoXYZRGB (point, p); + out.push_back (p); + } + } /** \brief Convert a XYZRGB point cloud to a XYZHSV * \param[in] in the input XYZRGB point cloud @@ -322,7 +393,7 @@ namespace pcl { out.width = in.width; out.height = in.height; - for (const auto &point : in.points) + for (const auto &point : in) { PointXYZHSV p; PointXYZRGBAtoXYZHSV (point, p); @@ -340,7 +411,7 @@ namespace pcl { out.width = in.width; out.height = in.height; - for (const auto &point : in.points) + for (const auto &point : in) { PointXYZI p; PointXYZRGBtoXYZI (point, p); diff --git a/common/include/pcl/range_image/impl/range_image.hpp b/common/include/pcl/range_image/impl/range_image.hpp index 62cfe2ae6b8..84bf9f2fc49 100644 --- a/common/include/pcl/range_image/impl/range_image.hpp +++ b/common/include/pcl/range_image/impl/range_image.hpp @@ -135,9 +135,11 @@ RangeImage::createFromPointCloud (const PointCloudType& point_cloud, int top=height, right=-1, bottom=-1, left=width; doZBuffer (point_cloud, noise_level, min_range, top, right, bottom, left); - cropImage (border_size, top, right, bottom, left); + if (border_size != std::numeric_limits::min()) { + cropImage (border_size, top, right, bottom, left); - recalculate3DPointPositions (); + recalculate3DPointPositions (); + } } ///////////////////////////////////////////////////////////////////////// @@ -196,9 +198,11 @@ RangeImage::createFromPointCloudWithKnownSize (const PointCloudType& point_cloud int top=height, right=-1, bottom=-1, left=width; doZBuffer (point_cloud, noise_level, min_range, top, right, bottom, left); - cropImage (border_size, top, right, bottom, left); + if (border_size != std::numeric_limits::min()) { + cropImage (border_size, top, right, bottom, left); - recalculate3DPointPositions (); + recalculate3DPointPositions (); + } } ///////////////////////////////////////////////////////////////////////// @@ -356,6 +360,11 @@ RangeImage::getImagePoint (const Eigen::Vector3f& point, float& image_x, float& { Eigen::Vector3f transformedPoint = to_range_image_system_ * point; range = transformedPoint.norm (); + if (range < std::numeric_limits::epsilon()) { + PCL_DEBUG ("[pcl::RangeImage::getImagePoint] Transformed point is (0,0,0), cannot project it.\n"); + image_x = image_y = 0.0f; + return; + } float angle_x = atan2LookUp (transformedPoint[0], transformedPoint[2]), angle_y = asinLookUp (transformedPoint[1]/range); getImagePointFromAngles (angle_x, angle_y, image_x, image_y); diff --git a/common/include/pcl/range_image/range_image.h b/common/include/pcl/range_image/range_image.h index 4405ed0da7e..782516d564b 100644 --- a/common/include/pcl/range_image/range_image.h +++ b/common/include/pcl/range_image/range_image.h @@ -139,7 +139,7 @@ namespace pcl * but the mean of the points. If 0.0 it is equivalent to a normal z-buffer and * will always take the minimum per cell. * \param min_range the minimum visible range (defaults to 0) - * \param border_size the border size (defaults to 0) + * \param border_size the border size (defaults to 0). Set to `std::numeric_limits::min()` to turn cropping off. */ template void createFromPointCloud (const PointCloudType& point_cloud, float angular_resolution=pcl::deg2rad (0.5f), @@ -163,7 +163,7 @@ namespace pcl * but the mean of the points. If 0.0 it is equivalent to a normal z-buffer and * will always take the minimum per cell. * \param min_range the minimum visible range (defaults to 0) - * \param border_size the border size (defaults to 0) + * \param border_size the border size (defaults to 0). Set to `std::numeric_limits::min()` to turn cropping off. */ template void createFromPointCloud (const PointCloudType& point_cloud, @@ -186,7 +186,7 @@ namespace pcl * but the mean of the points. If 0.0 it is equivalent to a normal z-buffer and * will always take the minimum per cell. * \param min_range the minimum visible range (defaults to 0) - * \param border_size the border size (defaults to 0) + * \param border_size the border size (defaults to 0). Set to `std::numeric_limits::min()` to turn cropping off. */ template void createFromPointCloudWithKnownSize (const PointCloudType& point_cloud, float angular_resolution, @@ -211,7 +211,7 @@ namespace pcl * but the mean of the points. If 0.0 it is equivalent to a normal z-buffer and * will always take the minimum per cell. * \param min_range the minimum visible range (defaults to 0) - * \param border_size the border size (defaults to 0) + * \param border_size the border size (defaults to 0). Set to `std::numeric_limits::min()` to turn cropping off. */ template void createFromPointCloudWithKnownSize (const PointCloudType& point_cloud, @@ -232,7 +232,7 @@ namespace pcl * but the mean of the points. If 0.0 it is equivalent to a normal z-buffer and * will always take the minimum per cell. * \param min_range the minimum visible range (defaults to 0) - * \param border_size the border size (defaults to 0) + * \param border_size the border size (defaults to 0). Set to `std::numeric_limits::min()` to turn cropping off. * \note If wrong_coordinate_system is true, the sensor pose will be rotated to change from a coordinate frame * with x to the front, y to the left and z to the top to the coordinate frame we use here (x to the right, y * to the bottom and z to the front) */ @@ -256,7 +256,7 @@ namespace pcl * but the mean of the points. If 0.0 it is equivalent to a normal z-buffer and * will always take the minimum per cell. * \param min_range the minimum visible range (defaults to 0) - * \param border_size the border size (defaults to 0) + * \param border_size the border size (defaults to 0). Set to `std::numeric_limits::min()` to turn cropping off. * \note If wrong_coordinate_system is true, the sensor pose will be rotated to change from a coordinate frame * with x to the front, y to the left and z to the top to the coordinate frame we use here (x to the right, y * to the bottom and z to the front) */ diff --git a/common/include/pcl/register_point_struct.h b/common/include/pcl/register_point_struct.h index 27cd2d2520a..1a09228b834 100644 --- a/common/include/pcl/register_point_struct.h +++ b/common/include/pcl/register_point_struct.h @@ -50,15 +50,12 @@ #pragma warning (disable: 4244) #endif -//https://bugreports.qt-project.org/browse/QTBUG-22829 -#ifndef Q_MOC_RUN #include // for pcl::traits::POD, POINT_CLOUD_REGISTER_FIELD_(NAME, OFFSET, DATATYPE), POINT_CLOUD_REGISTER_POINT_FIELD_LIST #include // for BOOST_MPL_ASSERT_MSG #include // for BOOST_PP_SEQ_FOR_EACH #include // for BOOST_PP_SEQ_TRANSFORM #include // for BOOST_PP_TUPLE_ELEM #include // for BOOST_PP_CAT -#endif #include // for std::uint32_t #include // for std::enable_if_t, std::is_array, std::remove_const_t, std::remove_all_extents_t @@ -192,6 +189,23 @@ namespace pcl for (std::uint32_t i = 0; i < count; ++i) p[i] /= scalar; } + + template inline + std::enable_if_t::value> + divscalar2 (NoArrayT &p, const ScalarT &scalar) + { + p = scalar / p; + } + + template inline + std::enable_if_t::value> + divscalar2 (ArrayT &p, const ScalarT &scalar) + { + using type = std::remove_all_extents_t; + static const std::uint32_t count = sizeof (ArrayT) / sizeof (type); + for (std::uint32_t i = 0; i < count; ++i) + p[i] = scalar / p[i]; + } } } @@ -228,6 +242,11 @@ namespace pcl scalar); /***/ +#define PCL_DIVEQSC2_POINT_TAG(r, data, elem) \ + pcl::traits::divscalar2 (p.BOOST_PP_TUPLE_ELEM(3, 1, elem), \ + scalar); + /***/ + // Construct type traits given full sequence of (type, name, tag) triples // BOOST_MPL_ASSERT_MSG(std::is_pod::value, // REGISTERED_POINT_TYPE_MUST_BE_PLAIN_OLD_DATA, (name)); @@ -266,6 +285,16 @@ namespace pcl inline const name operator+ (const name& p, const float& scalar) \ { name result = p; result += scalar; return (result); } \ inline const name& \ + operator*= (name& p, const float& scalar) \ + { \ + BOOST_PP_SEQ_FOR_EACH(PCL_MULEQSC_POINT_TAG, _, seq) \ + return (p); \ + } \ + inline const name operator* (const float& scalar, const name& p) \ + { name result = p; result *= scalar; return (result); } \ + inline const name operator* (const name& p, const float& scalar) \ + { name result = p; result *= scalar; return (result); } \ + inline const name& \ operator-= (name& lhs, const name& rhs) \ { \ BOOST_PP_SEQ_FOR_EACH(PCL_MINUSEQ_POINT_TAG, _, seq) \ @@ -280,27 +309,18 @@ namespace pcl inline const name operator- (const name& lhs, const name& rhs) \ { name result = lhs; result -= rhs; return (result); } \ inline const name operator- (const float& scalar, const name& p) \ - { name result = p; result -= scalar; return (result); } \ + { name result = p; result *= -1.0f; result += scalar; return (result); } \ inline const name operator- (const name& p, const float& scalar) \ { name result = p; result -= scalar; return (result); } \ inline const name& \ - operator*= (name& p, const float& scalar) \ - { \ - BOOST_PP_SEQ_FOR_EACH(PCL_MULEQSC_POINT_TAG, _, seq) \ - return (p); \ - } \ - inline const name operator* (const float& scalar, const name& p) \ - { name result = p; result *= scalar; return (result); } \ - inline const name operator* (const name& p, const float& scalar) \ - { name result = p; result *= scalar; return (result); } \ - inline const name& \ operator/= (name& p, const float& scalar) \ { \ BOOST_PP_SEQ_FOR_EACH(PCL_DIVEQSC_POINT_TAG, _, seq) \ return (p); \ } \ - inline const name operator/ (const float& scalar, const name& p) \ - { name result = p; result /= scalar; return (result); } \ + inline const name operator/ (const float& scalar, const name& p_in) \ + { name p = p_in; BOOST_PP_SEQ_FOR_EACH(PCL_DIVEQSC2_POINT_TAG, _, seq) \ + return (p); } \ inline const name operator/ (const name& p, const float& scalar) \ { name result = p; result /= scalar; return (result); } \ } \ diff --git a/common/include/pcl/types.h b/common/include/pcl/types.h index ca2e8e69e9a..06cfb6a577d 100644 --- a/common/include/pcl/types.h +++ b/common/include/pcl/types.h @@ -49,6 +49,8 @@ #include +#include + namespace pcl { namespace detail { @@ -129,5 +131,11 @@ namespace pcl * \brief Type used for indices in PCL */ using Indices = IndicesAllocator<>; + + /** + * \brief Type used for aligned vector of Eigen objects in PCL + */ + template + using AlignedVector = std::vector>; } // namespace pcl diff --git a/common/src/PCLPointCloud2.cpp b/common/src/PCLPointCloud2.cpp index 5940cae67c5..20d18d66c3a 100644 --- a/common/src/PCLPointCloud2.cpp +++ b/common/src/PCLPointCloud2.cpp @@ -149,7 +149,7 @@ pcl::PCLPointCloud2::concatenate (pcl::PCLPointCloud2 &cloud1, const pcl::PCLPoi } const auto data1_size = cloud1.data.size (); cloud1.data.resize(data1_size + cloud2.data.size ()); - for (index_t cp = 0; cp < size2; ++cp) + for (uindex_t cp = 0; cp < size2; ++cp) { for (const auto& field_data: valid_fields) { diff --git a/common/src/feature_histogram.cpp b/common/src/feature_histogram.cpp index d436ed54378..122eaf50729 100644 --- a/common/src/feature_histogram.cpp +++ b/common/src/feature_histogram.cpp @@ -133,7 +133,7 @@ pcl::FeatureHistogram::getMeanValue () 0.25f * histogram_[histogram_.size () - 2] * 2.0f; if (last_value > max) { - max_idx = histogram_.size (); + max_idx = histogram_.size () - 1; } // Compute mean value. diff --git a/common/src/fft/kiss_fft.c b/common/src/fft/kiss_fft.c index a996887d949..1112589ff94 100644 --- a/common/src/fft/kiss_fft.c +++ b/common/src/fft/kiss_fft.c @@ -252,7 +252,7 @@ void kf_work( // top-level (not recursive) if (fstride==1 && p<=5) { - int k; + int k=0; // execute the p different work units in different threads // We cannot use OPENMP_LEGACY_CONST_DATA_SHARING_RULE here, because we cannot include @@ -260,11 +260,13 @@ void kf_work( #if (defined _OPENMP && (_OPENMP <= 201307)) || (defined __GNUC__ && (__GNUC__ >= 6 && __GNUC__ < 9)) #pragma omp parallel for \ default(none) \ - shared(f, factors, Fout, in_stride) + shared(f, factors, Fout, in_stride) \ + private(k) #else #pragma omp parallel for \ default(none) \ - shared(f, factors, Fout, fstride, in_stride, m, p, st) + shared(f, factors, Fout, fstride, in_stride, m, p, st) \ + private(k) #endif for (k=0;k 0) - { - cloud_out = cloud2; - return (true); - } - if (cloud1.width*cloud1.height > 0 && cloud2.width*cloud2.height == 0) - { - cloud_out = cloud1; - return (true); - } - - bool strip = false; - for (const auto &field : cloud1.fields) - if (field.name == "_") - strip = true; - - for (const auto &field : cloud2.fields) - if (field.name == "_") - strip = true; - - if (!strip && cloud1.fields.size () != cloud2.fields.size ()) - { - PCL_ERROR ("[pcl::concatenatePointCloud] Number of fields in cloud1 (%u) != Number of fields in cloud2 (%u)\n", cloud1.fields.size (), cloud2.fields.size ()); - return (false); - } - - // Copy cloud1 into cloud_out - cloud_out = cloud1; - std::size_t nrpts = cloud_out.data.size (); - // Height = 1 => no more organized - cloud_out.width = cloud1.width * cloud1.height + cloud2.width * cloud2.height; - cloud_out.height = 1; - if (!cloud1.is_dense || !cloud2.is_dense) - cloud_out.is_dense = false; - else - cloud_out.is_dense = true; - - // We need to strip the extra padding fields - if (strip) - { - // Get the field sizes for the second cloud - std::vector fields2; - std::vector fields2_sizes; - for (const auto &field : cloud2.fields) - { - if (field.name == "_") - continue; - - fields2_sizes.push_back (field.count * - pcl::getFieldSize (field.datatype)); - fields2.push_back (field); - } - - cloud_out.data.resize (nrpts + (cloud2.width * cloud2.height) * cloud_out.point_step); - - // Copy the second cloud - for (index_t cp = 0; cp < cloud2.width * cloud2.height; ++cp) - { - int i = 0; - for (std::size_t j = 0; j < fields2.size (); ++j) - { - if (cloud1.fields[i].name == "_") - { - ++i; - continue; - } - - // We're fine with the special RGB vs RGBA use case - if ((cloud1.fields[i].name == "rgb" && fields2[j].name == "rgba") || - (cloud1.fields[i].name == "rgba" && fields2[j].name == "rgb") || - (cloud1.fields[i].name == fields2[j].name)) - { - memcpy (reinterpret_cast (&cloud_out.data[nrpts + cp * cloud1.point_step + cloud1.fields[i].offset]), - reinterpret_cast (&cloud2.data[cp * cloud2.point_step + cloud2.fields[j].offset]), - fields2_sizes[j]); - ++i; // increment the field size i - } - } - } - } - else - { - for (std::size_t i = 0; i < cloud1.fields.size (); ++i) - { - // We're fine with the special RGB vs RGBA use case - if ((cloud1.fields[i].name == "rgb" && cloud2.fields[i].name == "rgba") || - (cloud1.fields[i].name == "rgba" && cloud2.fields[i].name == "rgb")) - continue; - // Otherwise we need to make sure the names are the same - if (cloud1.fields[i].name != cloud2.fields[i].name) - { - PCL_ERROR ("[pcl::concatenatePointCloud] Name of field %d in cloud1, %s, does not match name in cloud2, %s\n", i, cloud1.fields[i].name.c_str (), cloud2.fields[i].name.c_str ()); - return (false); - } - } - - cloud_out.data.resize (nrpts + cloud2.data.size ()); - memcpy (&cloud_out.data[nrpts], &cloud2.data[0], cloud2.data.size ()); - } - return (true); -} - ////////////////////////////////////////////////////////////////////////// bool pcl::getPointCloudAsEigen (const pcl::PCLPointCloud2 &in, Eigen::MatrixXf &out) @@ -438,7 +329,7 @@ pcl::copyPointCloud ( void pcl::copyPointCloud ( const pcl::PCLPointCloud2 &cloud_in, - const IndicesAllocator< Eigen::aligned_allocator > &indices, + const IndicesAllocator< Eigen::aligned_allocator > &indices, pcl::PCLPointCloud2 &cloud_out) { cloud_out.header = cloud_in.header; diff --git a/common/src/parse.cpp b/common/src/parse.cpp index b6d67eeb9d7..1d8d9d63e91 100644 --- a/common/src/parse.cpp +++ b/common/src/parse.cpp @@ -181,14 +181,20 @@ parse_argument (int argc, const char * const * argv, const char * str, T &val) n int pcl::console::parse_argument (int argc, const char * const * argv, const char * str, double &val) { - return parse_generic(strtod, argc, argv, str, val); + // added lambda wrapper for `strtod` to handle noexcept-type warning in GCC 7, + // refer to: https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning + const auto strtod_l = [](const char *str, char **str_end){ return strtod(str, str_end); }; + return parse_generic(strtod_l, argc, argv, str, val); } //////////////////////////////////////////////////////////////////////////////// int pcl::console::parse_argument (int argc, const char * const * argv, const char * str, float &val) { - return parse_generic(strtof, argc, argv, str, val); + // added lambda wrapper for `strtof` to handle noexcept-type warning in GCC 7, + // refer to: https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning + const auto strtof_l = [](const char *str, char **str_end){ return strtof(str, str_end); }; + return parse_generic(strtof_l, argc, argv, str, val); } //////////////////////////////////////////////////////////////////////////////// diff --git a/common/src/pcl_base.cpp b/common/src/pcl_base.cpp index ca03ffc4c48..e591812d72f 100644 --- a/common/src/pcl_base.cpp +++ b/common/src/pcl_base.cpp @@ -126,7 +126,7 @@ pcl::PCLBase::initCompute () } // If we have a set of fake indices, but they do not match the number of points in the cloud, update them - if (fake_indices_ && indices_->size () != static_cast((input_->width * input_->height))) + if (fake_indices_ && indices_->size () != (input_->width * input_->height)) { const auto indices_size = indices_->size (); try diff --git a/common/src/point_types.cpp b/common/src/point_types.cpp index 03d8f7984f4..e3ab796fa79 100644 --- a/common/src/point_types.cpp +++ b/common/src/point_types.cpp @@ -130,6 +130,13 @@ namespace pcl return (os); } + std::ostream& + operator << (std::ostream& os, const PointXYZLAB& p) + { + os << "(" << p.x << "," << p.y << "," << p.z << " - " << p.L << " , " << p.a << " , " << p.b << ")"; + return (os); + } + std::ostream& operator << (std::ostream& os, const PointXYZHSV& p) { diff --git a/common/src/range_image.cpp b/common/src/range_image.cpp index 93227a20552..48b0a6a1583 100644 --- a/common/src/range_image.cpp +++ b/common/src/range_image.cpp @@ -833,7 +833,7 @@ RangeImage::extractFarRanges (const pcl::PCLPointCloud2& point_cloud_data, vp_z_offset = point_cloud_data.fields[vp_z_idx].offset, distance_offset = point_cloud_data.fields[distance_idx].offset; - for (index_t point_idx = 0; point_idx < point_cloud_data.width*point_cloud_data.height; ++point_idx) + for (uindex_t point_idx = 0; point_idx < point_cloud_data.width*point_cloud_data.height; ++point_idx) { float x = *reinterpret_cast (data+x_offset), y = *reinterpret_cast (data+y_offset), diff --git a/cuda/CMakeLists.txt b/cuda/CMakeLists.txt index 72cbd38b772..c327f95e5dc 100644 --- a/cuda/CMakeLists.txt +++ b/cuda/CMakeLists.txt @@ -11,7 +11,9 @@ endif() if(CMAKE_COMPILER_IS_GNUCXX) string(REPLACE "-Wold-style-cast" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "-Wno-invalid-offsetof" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-conversion -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-but-set-variable") + string(APPEND CMAKE_CXX_FLAGS " -Wno-conversion -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-but-set-variable") + # allow deprecation warnings in Eigen(3.3.7)/Core, see here: https://gitlab.kitware.com/vtk/vtk/-/issues/17661 + string(APPEND CMAKE_CXX_FLAGS " -Wno-error=cpp") endif() collect_subproject_directory_names("${CMAKE_CURRENT_SOURCE_DIR}" "CMakeLists.txt" PCL_CUDA_MODULES_NAMES PCL_CUDA_MODULES_DIRS) diff --git a/cuda/common/CMakeLists.txt b/cuda/common/CMakeLists.txt index b5775afe577..e7a2ff2a8f4 100644 --- a/cuda/common/CMakeLists.txt +++ b/cuda/common/CMakeLists.txt @@ -29,10 +29,10 @@ set(common_incs ) include_directories(./include) -#set(LIB_NAME pcl_${SUBSYS_NAME}) +set(LIB_NAME "pcl_${SUBSYS_NAME}") set(EXT_DEPS CUDA) -#PCL_MAKE_PKGCONFIG(${LIB_NAME} ${SUBSYS_NAME} "${SUBSYS_DESC}" -# "${SUBSYS_DEPS}" "${EXT_DEPS}" "" "" "") +PCL_MAKE_PKGCONFIG(${LIB_NAME} COMPONENT ${SUBSYS_NAME} DESC "${SUBSYS_DESC}" + PCL_DEPS "${SUBSYS_DEPS}" EXT_DEPS "" HEADER_ONLY) # Install include files PCL_ADD_INCLUDES(${SUBSYS_NAME} "cuda" ${incs}) diff --git a/cuda/common/include/pcl/cuda/common/eigen.h b/cuda/common/include/pcl/cuda/common/eigen.h index 5ae2f949411..0d1eb8dd0a4 100644 --- a/cuda/common/include/pcl/cuda/common/eigen.h +++ b/cuda/common/include/pcl/cuda/common/eigen.h @@ -93,7 +93,6 @@ #include #include -#include namespace pcl { @@ -102,7 +101,9 @@ namespace pcl inline __host__ __device__ bool isMuchSmallerThan (float x, float y) { - float prec_sqr = FLT_EPSILON * FLT_EPSILON; // copied from /include/Eigen/src/Core/NumTraits.h + // inspired by Eigen's implementation + float prec_sqr = + std::numeric_limits::epsilon() * std::numeric_limits::epsilon(); return x * x <= prec_sqr * y * y; } @@ -179,7 +180,7 @@ namespace pcl float c2 = m.data[0].x + m.data[1].y + m.data[2].z; - if (std::abs(c0) < FLT_EPSILON) // one root is 0 -> quadratic equation + if (std::abs(c0) < std::numeric_limits::epsilon()) // one root is 0 -> quadratic equation computeRoots2 (c2, c1, roots); else { @@ -233,7 +234,7 @@ namespace pcl //Scalar scale = mat.cwiseAbs ().maxCoeff (); float3 scale_tmp = fmaxf (fmaxf (fabs (mat.data[0]), fabs (mat.data[1])), fabs (mat.data[2])); float scale = fmaxf (fmaxf (scale_tmp.x, scale_tmp.y), scale_tmp.z); - if (scale <= FLT_MIN) + if (scale <= std::numeric_limits::min()) scale = 1.0f; CovarianceMatrix scaledMat; @@ -244,14 +245,14 @@ namespace pcl // Compute the eigenvalues computeRoots (scaledMat, evals); - if ((evals.z-evals.x) <= FLT_EPSILON) + if ((evals.z - evals.x) <= std::numeric_limits::epsilon()) { // all three equal evecs.data[0] = make_float3 (1.0f, 0.0f, 0.0f); evecs.data[1] = make_float3 (0.0f, 1.0f, 0.0f); evecs.data[2] = make_float3 (0.0f, 0.0f, 1.0f); } - else if ((evals.y-evals.x) <= FLT_EPSILON) + else if ((evals.y - evals.x) <= std::numeric_limits::epsilon()) { // first and second equal CovarianceMatrix tmp; @@ -281,7 +282,7 @@ namespace pcl evecs.data[1] = unitOrthogonal (evecs.data[2]); evecs.data[0] = cross (evecs.data[1], evecs.data[2]); } - else if ((evals.z-evals.y) <= FLT_EPSILON) + else if ((evals.z - evals.y) <= std::numeric_limits::epsilon()) { // second and third equal CovarianceMatrix tmp; diff --git a/cuda/filters/include/pcl/cuda/filters/filter.h b/cuda/filters/include/pcl/cuda/filters/filter.h index 416fc88dd56..ae26d836bba 100644 --- a/cuda/filters/include/pcl/cuda/filters/filter.h +++ b/cuda/filters/include/pcl/cuda/filters/filter.h @@ -36,7 +36,7 @@ #pragma once #include -#include +#include namespace pcl_cuda { @@ -69,7 +69,8 @@ namespace pcl_cuda /** \brief Empty constructor. */ Filter () : filter_field_name_ (""), - filter_limit_min_ (-FLT_MAX), filter_limit_max_ (FLT_MAX), + filter_limit_min_ (std::numeric_limits::lowest()), + filter_limit_max_ (std::numeric_limits::max()), filter_limit_negative_ (false) {}; @@ -98,7 +99,7 @@ namespace pcl_cuda } /** \brief Get the field filter limits (min/max) set by the user. - * The default values are -FLT_MAX, FLT_MAX. + * The default values are std::numeric_limits::lowest(), std::numeric_limits::max(). * \param limit_min the minimum limit * \param limit_max the maximum limit */ @@ -123,8 +124,14 @@ namespace pcl_cuda * returned (true) or inside (false). * \param limit_negative the limit_negative flag */ + PCL_DEPRECATED(1, 16, "use bool getFilterLimitsNegative() instead") inline void getFilterLimitsNegative (bool &limit_negative) { limit_negative = filter_limit_negative_; } + + /** \brief Get whether the data outside the interval (min/max) is to be + * returned (true) or inside (false). + * \return true if data \b outside the interval [min; max] is to be returned, false otherwise + */ inline bool getFilterLimitsNegative () { return (filter_limit_negative_); } diff --git a/cuda/filters/include/pcl/cuda/filters/voxel_grid.h b/cuda/filters/include/pcl/cuda/filters/voxel_grid.h index 39c207bac17..f54b3a195ad 100644 --- a/cuda/filters/include/pcl/cuda/filters/voxel_grid.h +++ b/cuda/filters/include/pcl/cuda/filters/voxel_grid.h @@ -35,6 +35,8 @@ #pragma once +PCL_DEPRECATED_HEADER(1, 16, "The CUDA VoxelGrid filter does not work. Use the CPU VoxelGrid filter instead.") + #include #include #include diff --git a/cuda/io/CMakeLists.txt b/cuda/io/CMakeLists.txt index b792231b040..f60a472e52d 100644 --- a/cuda/io/CMakeLists.txt +++ b/cuda/io/CMakeLists.txt @@ -2,16 +2,17 @@ set(SUBSYS_NAME cuda_io) set(SUBSYS_PATH cuda/io) set(SUBSYS_DESC "Point cloud CUDA IO library") set(SUBSYS_DEPS cuda_common io common) +set(SUBSYS_EXT_DEPS openni) # ---[ Point Cloud Library - pcl/cuda/io set(build TRUE) PCL_SUBSYS_OPTION(build "${SUBSYS_NAME}" "${SUBSYS_DESC}" OFF) mark_as_advanced("BUILD_${SUBSYS_NAME}") -PCL_SUBSYS_DEPEND(build "${SUBSYS_NAME}" DEPS ${SUBSYS_DEPS}) +PCL_SUBSYS_DEPEND(build "${SUBSYS_NAME}" DEPS ${SUBSYS_DEPS} EXT_DEPS ${SUBSYS_EXT_DEPS}) PCL_SET_SUBSYS_INCLUDE_DIR("${SUBSYS_NAME}" "${SUBSYS_PATH}") -if(NOT (build AND HAVE_OPENNI)) +if(NOT build) return() endif() @@ -37,9 +38,7 @@ set(LIB_NAME "pcl_${SUBSYS_NAME}") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include") PCL_CUDA_ADD_LIBRARY(${LIB_NAME} COMPONENT ${SUBSYS_NAME} SOURCES ${srcs} ${incs}) -set(EXT_DEPS "") -#set(EXT_DEPS CUDA) -PCL_MAKE_PKGCONFIG(${LIB_NAME} COMPONENT ${SUBSYS_NAME} DESC ${SUBSYS_DESC} PCL_DEPS ${SUBSYS_DEPS} EXT_DEPS ${EXT_DEPS}) +PCL_MAKE_PKGCONFIG(${LIB_NAME} COMPONENT ${SUBSYS_NAME} DESC ${SUBSYS_DESC} PCL_DEPS ${SUBSYS_DEPS} EXT_DEPS ${SUBSYS_EXT_DEPS}) # Install include files PCL_ADD_INCLUDES("${SUBSYS_NAME}" "${SUBSYS_PATH}" ${incs}) diff --git a/cuda/io/src/debayering.cu b/cuda/io/src/debayering.cu index 9c0e55d9ac2..b9f23e95a7f 100644 --- a/cuda/io/src/debayering.cu +++ b/cuda/io/src/debayering.cu @@ -114,8 +114,8 @@ namespace pcl OpenNIRGB DebayerBilinear::operator () (int index) const { // get position - int xIdx = index % width; - int yIdx = index / width; + unsigned int xIdx = index % width; + unsigned int yIdx = index / width; OpenNIRGB result; diff --git a/cuda/nn/organized_neighbor_search.h b/cuda/nn/organized_neighbor_search.h index f177fbe9cfb..ed98779603f 100644 --- a/cuda/nn/organized_neighbor_search.h +++ b/cuda/nn/organized_neighbor_search.h @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -111,7 +112,7 @@ namespace pcl int radiusSearch (const PointCloudConstPtr &cloud_arg, int index_arg, double radius_arg, std::vector &k_indices_arg, std::vector &k_sqr_distances_arg, - int max_nn_arg = INT_MAX); + int max_nn_arg = std::numeric_limits::max()); /** \brief Search for all neighbors of query point that are within a given radius. * \param index_arg index representing the query point in the dataset given by \a setInputCloud. @@ -124,7 +125,7 @@ namespace pcl */ int radiusSearch (int index_arg, const double radius_arg, std::vector &k_indices_arg, - std::vector &k_sqr_distances_arg, int max_nn_arg = INT_MAX) const; + std::vector &k_sqr_distances_arg, int max_nn_arg = std::numeric_limits::max()) const; /** \brief Search for all neighbors of query point that are within a given radius. * \param p_q_arg the given query point @@ -136,7 +137,7 @@ namespace pcl */ int radiusSearch (const PointT &p_q_arg, const double radius_arg, std::vector &k_indices_arg, - std::vector &k_sqr_distances_arg, int max_nn_arg = INT_MAX) const; + std::vector &k_sqr_distances_arg, int max_nn_arg = std::numeric_limits::max()) const; /** \brief Search for k-nearest neighbors at the query point. * \param cloud_arg the point cloud data diff --git a/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac.h b/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac.h index 10b126191fd..d384df39b09 100644 --- a/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac.h +++ b/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac.h @@ -39,7 +39,7 @@ #include #include -#include +#include //#include namespace pcl @@ -72,8 +72,8 @@ namespace pcl * \param model a Sample Consensus model */ SampleConsensus (const SampleConsensusModelPtr &model) : - sac_model_(model), probability_ (0.99), iterations_ (0), threshold_ (DBL_MAX), - max_iterations_ (1000) + sac_model_(model), probability_(0.99), iterations_(0), + threshold_(std::numeric_limits::max()), max_iterations_(1000) {}; /** \brief Constructor for base SAC. diff --git a/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac_model.h b/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac_model.h index ba27c9b7511..18a084cbc0f 100644 --- a/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac_model.h +++ b/cuda/sample_consensus/include/pcl/cuda/sample_consensus/sac_model.h @@ -37,7 +37,7 @@ #pragma once -#include +#include #include #include #include @@ -108,7 +108,9 @@ namespace pcl private: /** \brief Empty constructor for base SampleConsensusModel. */ - SampleConsensusModel () : radius_min_ (-FLT_MAX), radius_max_ (FLT_MAX) + SampleConsensusModel() : + radius_min_(std::numeric_limits::lowest()), + radius_max_(std::numeric_limits::max()) {}; public: @@ -116,7 +118,8 @@ namespace pcl * \param cloud the input point cloud dataset */ SampleConsensusModel (const PointCloudConstPtr &cloud) : - radius_min_ (-FLT_MAX), radius_max_ (FLT_MAX) + radius_min_(std::numeric_limits::lowest()), + radius_max_(std::numeric_limits::max()) { // Sets the input cloud and creates a vector of "fake" indices setInputCloud (cloud); @@ -129,7 +132,8 @@ namespace pcl /* SampleConsensusModel (const PointCloudConstPtr &cloud, const std::vector &indices) : input_ (cloud), indices_ (boost::make_shared > (indices)), - radius_min_ (-DBL_MAX), radius_max_ (DBL_MAX) + radius_min_ (std::numeric_limits::lowest()), + radius_max_ (std::numeric_limits::max()) { if (indices_->size () > input_->points.size ()) diff --git a/cuda/sample_consensus/src/msac.cpp b/cuda/sample_consensus/src/msac.cpp index 73daa198a72..397403c5df5 100644 --- a/cuda/sample_consensus/src/msac.cpp +++ b/cuda/sample_consensus/src/msac.cpp @@ -38,6 +38,7 @@ #include #include #include +#include //CUPRINTF #include "cuPrintf.cu" int min_nr_in_shape = 5000; @@ -47,7 +48,7 @@ template