diff --git a/.github/workflows/buildAndDocumentation.yml b/.github/workflows/buildAndDocumentation.yml
index 79dffdbf..69225ce6 100644
--- a/.github/workflows/buildAndDocumentation.yml
+++ b/.github/workflows/buildAndDocumentation.yml
@@ -12,7 +12,7 @@ env:
CONFIG_GLOBAL:
CONFIG_LINUX: -DWITH_MAGICK=true -DWITH_GMP=true -DWITH_FFTW3=true -DWARNING_AS_ERROR=ON -DWITH_HDF5=true -DWITH_QGLVIEWER=true -DWITH_CAIRO=true -DWITH_EIGEN=true -DDGTAL_ENABLE_FLOATING_POINT_EXCEPTIONS=true
CONFIG_MAC: -DWITH_EIGEN=true -DWITH_GMP=tue
- CONFIG_WINDOWS: -DWITH_OPENMP=true -DENABLE_CONAN=true #-DWITH_FFTW3=true #-DWITH_CAIRO=true #-DWITH_ITK=true -DWITH_GMP=true
+ CONFIG_WINDOWS: -DWITH_OPENMP=true -DENABLE_CONAN=true -DDISABLE_POLYSCOPE=ON #-DWITH_FFTW3=true #-DWITH_CAIRO=true #-DWITH_ITK=true -DWITH_GMP=true
jobs:
@@ -33,7 +33,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
- sudo apt-get install zsh libqglviewer-dev-qt5 libboost-dev libeigen3-dev ninja-build libhdf5-serial-dev libboost-dev libcairo2-dev libgmp-dev libgraphicsmagick++1-dev libfftw3-dev
+ sudo apt-get install zsh libqglviewer-dev-qt5 libboost-dev libeigen3-dev ninja-build libhdf5-serial-dev libboost-dev libcairo2-dev libgmp-dev libgraphicsmagick++1-dev libfftw3-dev xorg-dev libglu1-mesa-dev freeglut3-dev mesa-common-dev
- name: Get white list tools
run : |
@@ -142,7 +142,7 @@ jobs:
- name: Set up
run: |
sudo apt-get update
- sudo apt-get install libboost-dev graphviz texlive doxygen libqglviewer-dev-qt5 libeigen3-dev ninja-build libhdf5-serial-dev libboost-dev libcairo2-dev libgmp-dev libgraphicsmagick++1-dev libfftw3-dev
+ sudo apt-get install libboost-dev graphviz texlive doxygen libqglviewer-dev-qt5 libeigen3-dev ninja-build libhdf5-serial-dev libboost-dev libcairo2-dev libgmp-dev libgraphicsmagick++1-dev libfftw3-dev xorg-dev libglu1-mesa-dev freeglut3-dev
- name: DGtalBuild (linux)
shell: bash
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 486c2139..1ab3a3cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,7 @@ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
SET(DGTALTOOLS_RANDOMIZED_BUILD_THRESHOLD "100" CACHE INTERNAL "Threshold for the random selection of tools to build.")
SET(DGTALTOOLS_RANDOMIZED_BUILD_WHITELIST "" CACHE INTERNAL "List of whitelisted tools to build.")
option(NO_ADD_STBIMAGE_IMPLEMENT "To avoid duplicated linking errors (like LNK2005 in MSVC)" OFF)
+option(DISABLE_POLYSCOPE "Disable polyscope based tools" OFF)
@@ -106,6 +107,20 @@ if ( WITH_ITK )
ENDIF( WITH_ITK )
+
+#-----------------------------------------------------------------------------
+# polyscope
+#-----------------------------------------------------------------------------
+if (NOT(DISABLE_POLYSCOPE))
+ message(STATUS "Enabling polyscope tools")
+ include(CPM)
+ include(polyscope)
+else()
+ message(STATUS "Disabling polyscope tools")
+endif()
+
+
+
# -----------------------------------------------------------------------------
# Documentation
# -----------------------------------------------------------------------------
diff --git a/ChangeLog.md b/ChangeLog.md
index 715386a9..add30418 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,11 @@
# DGtalTools 1.4 (beta)
+- *build*
+ - Remove STBimage preprocessor instruction used to fix MVSC that is
+ no more usefull since DGtal PR [175](https://github.com/DGtal-team/DGtal/pull/1715)
+ (Bertrand Kerautret [#459](https://github.com/DGtal-team/DGtalTools/pull/459))
+
+
- *visualisation*
- meshViewer: new options to change the default background color, to
load camera settings at startup, to change at startup the light
@@ -13,9 +19,22 @@
- meshViewer: new option to set alpha channel of the mesh color.
(Bertrand Kerautret
[#451](https://github.com/DGtal-team/DGtalTools/pull/451))
+ - 3dSDPViewer: new option to set alpha channel of the mesh color.
+ (Xun Gong
+ [#452](https://github.com/DGtal-team/DGtalTools/pull/452))
+ - meshViewer: Add colored SDP option in meshViewer when input texts is an alpha mesh and a colored SDP respectively.
+ (Xun Gong
+ [#452](https://github.com/DGtal-team/DGtalTools/pull/452))
+ - volscope new vol visualization tool using polyscope (David Coeurjolly,
+ [#455](https://github.com/DGtal-team/DGtalTools/pull/455))
+ - volscope documentation enhanced (David Coeurjolly,
+ [#460](https://github.com/DGtal-team/DGtalTools/pull/460))
+
- *volumetric*
- volReSample: fix the impossibility to export to vol when ITK is activated
(Bertrand Kerautret [#445](https://github.com/DGtal-team/DGtalTools/pull/445))
+ - volFillInterior: add new option to set the filling value.
+ (Bertrand Kerautret [#456](https://github.com/DGtal-team/DGtalTools/pull/456))
- *converters*
- mesh2vol: small fix to read generic mesh.
diff --git a/README.md b/README.md
index 24f7ea25..5fd95a75 100644
--- a/README.md
+++ b/README.md
@@ -197,6 +197,13 @@ Galleries
3dCompSurfelData |
3dImplicitSurfaceExtractorByThickening |
+
+
+
+ |
+
+ volscope |
+
diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake
new file mode 100644
index 00000000..70aebf10
--- /dev/null
+++ b/cmake/CPM.cmake
@@ -0,0 +1,1154 @@
+# CPM.cmake - CMake's missing package manager
+# ===========================================
+# See https://github.com/cpm-cmake/CPM.cmake for usage and update instructions.
+#
+# MIT License
+# -----------
+#[[
+ Copyright (c) 2019-2022 Lars Melchior and contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+]]
+
+cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
+
+# Initialize logging prefix
+if(NOT CPM_INDENT)
+ set(CPM_INDENT
+ "CPM:"
+ CACHE INTERNAL ""
+ )
+endif()
+
+if(NOT COMMAND cpm_message)
+ function(cpm_message)
+ message(${ARGV})
+ endfunction()
+endif()
+
+set(CURRENT_CPM_VERSION 0.38.1)
+
+get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
+if(CPM_DIRECTORY)
+ if(NOT CPM_DIRECTORY STREQUAL CPM_CURRENT_DIRECTORY)
+ if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION)
+ message(
+ AUTHOR_WARNING
+ "${CPM_INDENT} \
+A dependency is using a more recent CPM version (${CURRENT_CPM_VERSION}) than the current project (${CPM_VERSION}). \
+It is recommended to upgrade CPM to the most recent version. \
+See https://github.com/cpm-cmake/CPM.cmake for more information."
+ )
+ endif()
+ if(${CMAKE_VERSION} VERSION_LESS "3.17.0")
+ include(FetchContent)
+ endif()
+ return()
+ endif()
+
+ get_property(
+ CPM_INITIALIZED GLOBAL ""
+ PROPERTY CPM_INITIALIZED
+ SET
+ )
+ if(CPM_INITIALIZED)
+ return()
+ endif()
+endif()
+
+if(CURRENT_CPM_VERSION MATCHES "development-version")
+ message(
+ WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \
+Please update to a recent release if possible. \
+See https://github.com/cpm-cmake/CPM.cmake for details."
+ )
+endif()
+
+set_property(GLOBAL PROPERTY CPM_INITIALIZED true)
+
+macro(cpm_set_policies)
+ # the policy allows us to change options without caching
+ cmake_policy(SET CMP0077 NEW)
+ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
+
+ # the policy allows us to change set(CACHE) without caching
+ if(POLICY CMP0126)
+ cmake_policy(SET CMP0126 NEW)
+ set(CMAKE_POLICY_DEFAULT_CMP0126 NEW)
+ endif()
+
+ # The policy uses the download time for timestamp, instead of the timestamp in the archive. This
+ # allows for proper rebuilds when a projects url changes
+ if(POLICY CMP0135)
+ cmake_policy(SET CMP0135 NEW)
+ set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
+ endif()
+endmacro()
+cpm_set_policies()
+
+option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies"
+ $ENV{CPM_USE_LOCAL_PACKAGES}
+)
+option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies"
+ $ENV{CPM_LOCAL_PACKAGES_ONLY}
+)
+option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL})
+option(CPM_DONT_UPDATE_MODULE_PATH "Don't update the module path to allow using find_package"
+ $ENV{CPM_DONT_UPDATE_MODULE_PATH}
+)
+option(CPM_DONT_CREATE_PACKAGE_LOCK "Don't create a package lock file in the binary path"
+ $ENV{CPM_DONT_CREATE_PACKAGE_LOCK}
+)
+option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK
+ "Add all packages added through CPM.cmake to the package lock"
+ $ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK}
+)
+option(CPM_USE_NAMED_CACHE_DIRECTORIES
+ "Use additional directory of package name in cache on the most nested level."
+ $ENV{CPM_USE_NAMED_CACHE_DIRECTORIES}
+)
+
+set(CPM_VERSION
+ ${CURRENT_CPM_VERSION}
+ CACHE INTERNAL ""
+)
+set(CPM_DIRECTORY
+ ${CPM_CURRENT_DIRECTORY}
+ CACHE INTERNAL ""
+)
+set(CPM_FILE
+ ${CMAKE_CURRENT_LIST_FILE}
+ CACHE INTERNAL ""
+)
+set(CPM_PACKAGES
+ ""
+ CACHE INTERNAL ""
+)
+set(CPM_DRY_RUN
+ OFF
+ CACHE INTERNAL "Don't download or configure dependencies (for testing)"
+)
+
+if(DEFINED ENV{CPM_SOURCE_CACHE})
+ set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
+else()
+ set(CPM_SOURCE_CACHE_DEFAULT OFF)
+endif()
+
+set(CPM_SOURCE_CACHE
+ ${CPM_SOURCE_CACHE_DEFAULT}
+ CACHE PATH "Directory to download CPM dependencies"
+)
+
+if(NOT CPM_DONT_UPDATE_MODULE_PATH)
+ set(CPM_MODULE_PATH
+ "${CMAKE_BINARY_DIR}/CPM_modules"
+ CACHE INTERNAL ""
+ )
+ # remove old modules
+ file(REMOVE_RECURSE ${CPM_MODULE_PATH})
+ file(MAKE_DIRECTORY ${CPM_MODULE_PATH})
+ # locally added CPM modules should override global packages
+ set(CMAKE_MODULE_PATH "${CPM_MODULE_PATH};${CMAKE_MODULE_PATH}")
+endif()
+
+if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
+ set(CPM_PACKAGE_LOCK_FILE
+ "${CMAKE_BINARY_DIR}/cpm-package-lock.cmake"
+ CACHE INTERNAL ""
+ )
+ file(WRITE ${CPM_PACKAGE_LOCK_FILE}
+ "# CPM Package Lock\n# This file should be committed to version control\n\n"
+ )
+endif()
+
+include(FetchContent)
+
+# Try to infer package name from git repository uri (path or url)
+function(cpm_package_name_from_git_uri URI RESULT)
+ if("${URI}" MATCHES "([^/:]+)/?.git/?$")
+ set(${RESULT}
+ ${CMAKE_MATCH_1}
+ PARENT_SCOPE
+ )
+ else()
+ unset(${RESULT} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Try to infer package name and version from a url
+function(cpm_package_name_and_ver_from_url url outName outVer)
+ if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)")
+ # We matched an archive
+ set(filename "${CMAKE_MATCH_1}")
+
+ if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)")
+ # We matched - (ie foo-1.2.3)
+ set(${outName}
+ "${CMAKE_MATCH_1}"
+ PARENT_SCOPE
+ )
+ set(${outVer}
+ "${CMAKE_MATCH_2}"
+ PARENT_SCOPE
+ )
+ elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)")
+ # We couldn't find a name, but we found a version
+ #
+ # In many cases (which we don't handle here) the url would look something like
+ # `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly
+ # distinguish the package name from the irrelevant bits. Moreover if we try to match the
+ # package name from the filename, we'd get bogus at best.
+ unset(${outName} PARENT_SCOPE)
+ set(${outVer}
+ "${CMAKE_MATCH_1}"
+ PARENT_SCOPE
+ )
+ else()
+ # Boldly assume that the file name is the package name.
+ #
+ # Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but
+ # such cases should be quite rare. No popular service does this... we think.
+ set(${outName}
+ "${filename}"
+ PARENT_SCOPE
+ )
+ unset(${outVer} PARENT_SCOPE)
+ endif()
+ else()
+ # No ideas yet what to do with non-archives
+ unset(${outName} PARENT_SCOPE)
+ unset(${outVer} PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(cpm_find_package NAME VERSION)
+ string(REPLACE " " ";" EXTRA_ARGS "${ARGN}")
+ find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET)
+ if(${CPM_ARGS_NAME}_FOUND)
+ if(DEFINED ${CPM_ARGS_NAME}_VERSION)
+ set(VERSION ${${CPM_ARGS_NAME}_VERSION})
+ endif()
+ cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}")
+ CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}")
+ set(CPM_PACKAGE_FOUND
+ YES
+ PARENT_SCOPE
+ )
+ else()
+ set(CPM_PACKAGE_FOUND
+ NO
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
+
+# Create a custom FindXXX.cmake module for a CPM package This prevents `find_package(NAME)` from
+# finding the system library
+function(cpm_create_module_file Name)
+ if(NOT CPM_DONT_UPDATE_MODULE_PATH)
+ # erase any previous modules
+ file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake
+ "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)"
+ )
+ endif()
+endfunction()
+
+# Find a package locally or fallback to CPMAddPackage
+function(CPMFindPackage)
+ set(oneValueArgs NAME VERSION GIT_TAG FIND_PACKAGE_ARGUMENTS)
+
+ cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN})
+
+ if(NOT DEFINED CPM_ARGS_VERSION)
+ if(DEFINED CPM_ARGS_GIT_TAG)
+ cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
+ endif()
+ endif()
+
+ set(downloadPackage ${CPM_DOWNLOAD_ALL})
+ if(DEFINED CPM_DOWNLOAD_${CPM_ARGS_NAME})
+ set(downloadPackage ${CPM_DOWNLOAD_${CPM_ARGS_NAME}})
+ elseif(DEFINED ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}})
+ set(downloadPackage $ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}})
+ endif()
+ if(downloadPackage)
+ CPMAddPackage(${ARGN})
+ cpm_export_variables(${CPM_ARGS_NAME})
+ return()
+ endif()
+
+ cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
+ if(CPM_PACKAGE_ALREADY_ADDED)
+ cpm_export_variables(${CPM_ARGS_NAME})
+ return()
+ endif()
+
+ cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
+
+ if(NOT CPM_PACKAGE_FOUND)
+ CPMAddPackage(${ARGN})
+ cpm_export_variables(${CPM_ARGS_NAME})
+ endif()
+
+endfunction()
+
+# checks if a package has been added before
+function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION)
+ if("${CPM_ARGS_NAME}" IN_LIST CPM_PACKAGES)
+ CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION)
+ if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}")
+ message(
+ WARNING
+ "${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})."
+ )
+ endif()
+ cpm_get_fetch_properties(${CPM_ARGS_NAME})
+ set(${CPM_ARGS_NAME}_ADDED NO)
+ set(CPM_PACKAGE_ALREADY_ADDED
+ YES
+ PARENT_SCOPE
+ )
+ cpm_export_variables(${CPM_ARGS_NAME})
+ else()
+ set(CPM_PACKAGE_ALREADY_ADDED
+ NO
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
+
+# Parse the argument of CPMAddPackage in case a single one was provided and convert it to a list of
+# arguments which can then be parsed idiomatically. For example gh:foo/bar@1.2.3 will be converted
+# to: GITHUB_REPOSITORY;foo/bar;VERSION;1.2.3
+function(cpm_parse_add_package_single_arg arg outArgs)
+ # Look for a scheme
+ if("${arg}" MATCHES "^([a-zA-Z]+):(.+)$")
+ string(TOLOWER "${CMAKE_MATCH_1}" scheme)
+ set(uri "${CMAKE_MATCH_2}")
+
+ # Check for CPM-specific schemes
+ if(scheme STREQUAL "gh")
+ set(out "GITHUB_REPOSITORY;${uri}")
+ set(packageType "git")
+ elseif(scheme STREQUAL "gl")
+ set(out "GITLAB_REPOSITORY;${uri}")
+ set(packageType "git")
+ elseif(scheme STREQUAL "bb")
+ set(out "BITBUCKET_REPOSITORY;${uri}")
+ set(packageType "git")
+ # A CPM-specific scheme was not found. Looks like this is a generic URL so try to determine
+ # type
+ elseif(arg MATCHES ".git/?(@|#|$)")
+ set(out "GIT_REPOSITORY;${arg}")
+ set(packageType "git")
+ else()
+ # Fall back to a URL
+ set(out "URL;${arg}")
+ set(packageType "archive")
+
+ # We could also check for SVN since FetchContent supports it, but SVN is so rare these days.
+ # We just won't bother with the additional complexity it will induce in this function. SVN is
+ # done by multi-arg
+ endif()
+ else()
+ if(arg MATCHES ".git/?(@|#|$)")
+ set(out "GIT_REPOSITORY;${arg}")
+ set(packageType "git")
+ else()
+ # Give up
+ message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'")
+ endif()
+ endif()
+
+ # For all packages we interpret @... as version. Only replace the last occurrence. Thus URIs
+ # containing '@' can be used
+ string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}")
+
+ # Parse the rest according to package type
+ if(packageType STREQUAL "git")
+ # For git repos we interpret #... as a tag or branch or commit hash
+ string(REGEX REPLACE "#([^#]+)$" ";GIT_TAG;\\1" out "${out}")
+ elseif(packageType STREQUAL "archive")
+ # For archives we interpret #... as a URL hash.
+ string(REGEX REPLACE "#([^#]+)$" ";URL_HASH;\\1" out "${out}")
+ # We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url
+ # should do this at a later point
+ else()
+ # We should never get here. This is an assertion and hitting it means there's a bug in the code
+ # above. A packageType was set, but not handled by this if-else.
+ message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'")
+ endif()
+
+ set(${outArgs}
+ ${out}
+ PARENT_SCOPE
+ )
+endfunction()
+
+# Check that the working directory for a git repo is clean
+function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean)
+
+ find_package(Git REQUIRED)
+
+ if(NOT GIT_EXECUTABLE)
+ # No git executable, assume directory is clean
+ set(${isClean}
+ TRUE
+ PARENT_SCOPE
+ )
+ return()
+ endif()
+
+ # check for uncommitted changes
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} status --porcelain
+ RESULT_VARIABLE resultGitStatus
+ OUTPUT_VARIABLE repoStatus
+ OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET
+ WORKING_DIRECTORY ${repoPath}
+ )
+ if(resultGitStatus)
+ # not supposed to happen, assume clean anyway
+ message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed")
+ set(${isClean}
+ TRUE
+ PARENT_SCOPE
+ )
+ return()
+ endif()
+
+ if(NOT "${repoStatus}" STREQUAL "")
+ set(${isClean}
+ FALSE
+ PARENT_SCOPE
+ )
+ return()
+ endif()
+
+ # check for committed changes
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} diff -s --exit-code ${gitTag}
+ RESULT_VARIABLE resultGitDiff
+ OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_QUIET
+ WORKING_DIRECTORY ${repoPath}
+ )
+
+ if(${resultGitDiff} EQUAL 0)
+ set(${isClean}
+ TRUE
+ PARENT_SCOPE
+ )
+ else()
+ set(${isClean}
+ FALSE
+ PARENT_SCOPE
+ )
+ endif()
+
+endfunction()
+
+# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload
+# FetchContent calls. As these are internal cmake properties, this method should be used carefully
+# and may need modification in future CMake versions. Source:
+# https://github.com/Kitware/CMake/blob/dc3d0b5a0a7d26d43d6cfeb511e224533b5d188f/Modules/FetchContent.cmake#L1152
+function(cpm_override_fetchcontent contentName)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "")
+ if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
+ message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ string(TOLOWER ${contentName} contentNameLower)
+ set(prefix "_FetchContent_${contentNameLower}")
+
+ set(propertyName "${prefix}_sourceDir")
+ define_property(
+ GLOBAL
+ PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}")
+
+ set(propertyName "${prefix}_binaryDir")
+ define_property(
+ GLOBAL
+ PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}")
+
+ set(propertyName "${prefix}_populated")
+ define_property(
+ GLOBAL
+ PROPERTY ${propertyName}
+ BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()"
+ FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}"
+ )
+ set_property(GLOBAL PROPERTY ${propertyName} TRUE)
+endfunction()
+
+# Download and add a package from source
+function(CPMAddPackage)
+ cpm_set_policies()
+
+ list(LENGTH ARGN argnLength)
+ if(argnLength EQUAL 1)
+ cpm_parse_add_package_single_arg("${ARGN}" ARGN)
+
+ # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM
+ set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;")
+ endif()
+
+ set(oneValueArgs
+ NAME
+ FORCE
+ VERSION
+ GIT_TAG
+ DOWNLOAD_ONLY
+ GITHUB_REPOSITORY
+ GITLAB_REPOSITORY
+ BITBUCKET_REPOSITORY
+ GIT_REPOSITORY
+ SOURCE_DIR
+ DOWNLOAD_COMMAND
+ FIND_PACKAGE_ARGUMENTS
+ NO_CACHE
+ SYSTEM
+ GIT_SHALLOW
+ EXCLUDE_FROM_ALL
+ SOURCE_SUBDIR
+ )
+
+ set(multiValueArgs URL OPTIONS)
+
+ cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
+
+ # Set default values for arguments
+
+ if(NOT DEFINED CPM_ARGS_VERSION)
+ if(DEFINED CPM_ARGS_GIT_TAG)
+ cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
+ endif()
+ endif()
+
+ if(CPM_ARGS_DOWNLOAD_ONLY)
+ set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY})
+ else()
+ set(DOWNLOAD_ONLY NO)
+ endif()
+
+ if(DEFINED CPM_ARGS_GITHUB_REPOSITORY)
+ set(CPM_ARGS_GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git")
+ elseif(DEFINED CPM_ARGS_GITLAB_REPOSITORY)
+ set(CPM_ARGS_GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git")
+ elseif(DEFINED CPM_ARGS_BITBUCKET_REPOSITORY)
+ set(CPM_ARGS_GIT_REPOSITORY "https://bitbucket.org/${CPM_ARGS_BITBUCKET_REPOSITORY}.git")
+ endif()
+
+ if(DEFINED CPM_ARGS_GIT_REPOSITORY)
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY ${CPM_ARGS_GIT_REPOSITORY})
+ if(NOT DEFINED CPM_ARGS_GIT_TAG)
+ set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION})
+ endif()
+
+ # If a name wasn't provided, try to infer it from the git repo
+ if(NOT DEFINED CPM_ARGS_NAME)
+ cpm_package_name_from_git_uri(${CPM_ARGS_GIT_REPOSITORY} CPM_ARGS_NAME)
+ endif()
+ endif()
+
+ set(CPM_SKIP_FETCH FALSE)
+
+ if(DEFINED CPM_ARGS_GIT_TAG)
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG})
+ # If GIT_SHALLOW is explicitly specified, honor the value.
+ if(DEFINED CPM_ARGS_GIT_SHALLOW)
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW ${CPM_ARGS_GIT_SHALLOW})
+ endif()
+ endif()
+
+ if(DEFINED CPM_ARGS_URL)
+ # If a name or version aren't provided, try to infer them from the URL
+ list(GET CPM_ARGS_URL 0 firstUrl)
+ cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl)
+ # If we fail to obtain name and version from the first URL, we could try other URLs if any.
+ # However multiple URLs are expected to be quite rare, so for now we won't bother.
+
+ # If the caller provided their own name and version, they trump the inferred ones.
+ if(NOT DEFINED CPM_ARGS_NAME)
+ set(CPM_ARGS_NAME ${nameFromUrl})
+ endif()
+ if(NOT DEFINED CPM_ARGS_VERSION)
+ set(CPM_ARGS_VERSION ${verFromUrl})
+ endif()
+
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}")
+ endif()
+
+ # Check for required arguments
+
+ if(NOT DEFINED CPM_ARGS_NAME)
+ message(
+ FATAL_ERROR
+ "${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'"
+ )
+ endif()
+
+ # Check if package has been added before
+ cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
+ if(CPM_PACKAGE_ALREADY_ADDED)
+ cpm_export_variables(${CPM_ARGS_NAME})
+ return()
+ endif()
+
+ # Check for manual overrides
+ if(NOT CPM_ARGS_FORCE AND NOT "${CPM_${CPM_ARGS_NAME}_SOURCE}" STREQUAL "")
+ set(PACKAGE_SOURCE ${CPM_${CPM_ARGS_NAME}_SOURCE})
+ set(CPM_${CPM_ARGS_NAME}_SOURCE "")
+ CPMAddPackage(
+ NAME "${CPM_ARGS_NAME}"
+ SOURCE_DIR "${PACKAGE_SOURCE}"
+ EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}"
+ SYSTEM "${CPM_ARGS_SYSTEM}"
+ OPTIONS "${CPM_ARGS_OPTIONS}"
+ SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}"
+ DOWNLOAD_ONLY "${DOWNLOAD_ONLY}"
+ FORCE True
+ )
+ cpm_export_variables(${CPM_ARGS_NAME})
+ return()
+ endif()
+
+ # Check for available declaration
+ if(NOT CPM_ARGS_FORCE AND NOT "${CPM_DECLARATION_${CPM_ARGS_NAME}}" STREQUAL "")
+ set(declaration ${CPM_DECLARATION_${CPM_ARGS_NAME}})
+ set(CPM_DECLARATION_${CPM_ARGS_NAME} "")
+ CPMAddPackage(${declaration})
+ cpm_export_variables(${CPM_ARGS_NAME})
+ # checking again to ensure version and option compatibility
+ cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
+ return()
+ endif()
+
+ if(NOT CPM_ARGS_FORCE)
+ if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY)
+ cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
+
+ if(CPM_PACKAGE_FOUND)
+ cpm_export_variables(${CPM_ARGS_NAME})
+ return()
+ endif()
+
+ if(CPM_LOCAL_PACKAGES_ONLY)
+ message(
+ SEND_ERROR
+ "${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})"
+ )
+ endif()
+ endif()
+ endif()
+
+ CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}")
+
+ if(DEFINED CPM_ARGS_GIT_TAG)
+ set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}")
+ elseif(DEFINED CPM_ARGS_SOURCE_DIR)
+ set(PACKAGE_INFO "${CPM_ARGS_SOURCE_DIR}")
+ else()
+ set(PACKAGE_INFO "${CPM_ARGS_VERSION}")
+ endif()
+
+ if(DEFINED FETCHCONTENT_BASE_DIR)
+ # respect user's FETCHCONTENT_BASE_DIR if set
+ set(CPM_FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR})
+ else()
+ set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps)
+ endif()
+
+ if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND)
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND})
+ elseif(DEFINED CPM_ARGS_SOURCE_DIR)
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR})
+ if(NOT IS_ABSOLUTE ${CPM_ARGS_SOURCE_DIR})
+ # Expand `CPM_ARGS_SOURCE_DIR` relative path. This is important because EXISTS doesn't work
+ # for relative paths.
+ get_filename_component(
+ source_directory ${CPM_ARGS_SOURCE_DIR} REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ else()
+ set(source_directory ${CPM_ARGS_SOURCE_DIR})
+ endif()
+ if(NOT EXISTS ${source_directory})
+ string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
+ # remove timestamps so CMake will re-download the dependency
+ file(REMOVE_RECURSE "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild")
+ endif()
+ elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE)
+ string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
+ set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS})
+ list(SORT origin_parameters)
+ if(CPM_USE_NAMED_CACHE_DIRECTORIES)
+ string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG")
+ set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME})
+ else()
+ string(SHA1 origin_hash "${origin_parameters}")
+ set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash})
+ endif()
+ # Expand `download_directory` relative path. This is important because EXISTS doesn't work for
+ # relative paths.
+ get_filename_component(download_directory ${download_directory} ABSOLUTE)
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory})
+
+ if(CPM_SOURCE_CACHE)
+ file(LOCK ${download_directory}/../cmake.lock)
+ endif()
+
+ if(EXISTS ${download_directory})
+ if(CPM_SOURCE_CACHE)
+ file(LOCK ${download_directory}/../cmake.lock RELEASE)
+ endif()
+
+ cpm_store_fetch_properties(
+ ${CPM_ARGS_NAME} "${download_directory}"
+ "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build"
+ )
+ cpm_get_fetch_properties("${CPM_ARGS_NAME}")
+
+ if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS))
+ # warn if cache has been changed since checkout
+ cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN)
+ if(NOT ${IS_CLEAN})
+ message(
+ WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty"
+ )
+ endif()
+ endif()
+
+ cpm_add_subdirectory(
+ "${CPM_ARGS_NAME}"
+ "${DOWNLOAD_ONLY}"
+ "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}"
+ "${${CPM_ARGS_NAME}_BINARY_DIR}"
+ "${CPM_ARGS_EXCLUDE_FROM_ALL}"
+ "${CPM_ARGS_SYSTEM}"
+ "${CPM_ARGS_OPTIONS}"
+ )
+ set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}")
+
+ # As the source dir is already cached/populated, we override the call to FetchContent.
+ set(CPM_SKIP_FETCH TRUE)
+ cpm_override_fetchcontent(
+ "${lower_case_name}" SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}"
+ BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}"
+ )
+
+ else()
+ # Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but
+ # it should guarantee no commit hash get mis-detected.
+ if(NOT DEFINED CPM_ARGS_GIT_SHALLOW)
+ cpm_is_git_tag_commit_hash("${CPM_ARGS_GIT_TAG}" IS_HASH)
+ if(NOT ${IS_HASH})
+ list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW TRUE)
+ endif()
+ endif()
+
+ # remove timestamps so CMake will re-download the dependency
+ file(REMOVE_RECURSE ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild)
+ set(PACKAGE_INFO "${PACKAGE_INFO} to ${download_directory}")
+ endif()
+ endif()
+
+ cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")")
+
+ if(CPM_PACKAGE_LOCK_ENABLED)
+ if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK)
+ cpm_add_to_package_lock(${CPM_ARGS_NAME} "${ARGN}")
+ elseif(CPM_ARGS_SOURCE_DIR)
+ cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "local directory")
+ else()
+ cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "${ARGN}")
+ endif()
+ endif()
+
+ cpm_message(
+ STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})"
+ )
+
+ if(NOT CPM_SKIP_FETCH)
+ cpm_declare_fetch(
+ "${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}" "${PACKAGE_INFO}" "${CPM_ARGS_UNPARSED_ARGUMENTS}"
+ )
+ cpm_fetch_package("${CPM_ARGS_NAME}" populated)
+ if(CPM_CACHE_SOURCE AND download_directory)
+ file(LOCK ${download_directory}/../cmake.lock RELEASE)
+ endif()
+ if(${populated})
+ cpm_add_subdirectory(
+ "${CPM_ARGS_NAME}"
+ "${DOWNLOAD_ONLY}"
+ "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}"
+ "${${CPM_ARGS_NAME}_BINARY_DIR}"
+ "${CPM_ARGS_EXCLUDE_FROM_ALL}"
+ "${CPM_ARGS_SYSTEM}"
+ "${CPM_ARGS_OPTIONS}"
+ )
+ endif()
+ cpm_get_fetch_properties("${CPM_ARGS_NAME}")
+ endif()
+
+ set(${CPM_ARGS_NAME}_ADDED YES)
+ cpm_export_variables("${CPM_ARGS_NAME}")
+endfunction()
+
+# Fetch a previously declared package
+macro(CPMGetPackage Name)
+ if(DEFINED "CPM_DECLARATION_${Name}")
+ CPMAddPackage(NAME ${Name})
+ else()
+ message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available")
+ endif()
+endmacro()
+
+# export variables available to the caller to the parent scope expects ${CPM_ARGS_NAME} to be set
+macro(cpm_export_variables name)
+ set(${name}_SOURCE_DIR
+ "${${name}_SOURCE_DIR}"
+ PARENT_SCOPE
+ )
+ set(${name}_BINARY_DIR
+ "${${name}_BINARY_DIR}"
+ PARENT_SCOPE
+ )
+ set(${name}_ADDED
+ "${${name}_ADDED}"
+ PARENT_SCOPE
+ )
+ set(CPM_LAST_PACKAGE_NAME
+ "${name}"
+ PARENT_SCOPE
+ )
+endmacro()
+
+# declares a package, so that any call to CPMAddPackage for the package name will use these
+# arguments instead. Previous declarations will not be overridden.
+macro(CPMDeclarePackage Name)
+ if(NOT DEFINED "CPM_DECLARATION_${Name}")
+ set("CPM_DECLARATION_${Name}" "${ARGN}")
+ endif()
+endmacro()
+
+function(cpm_add_to_package_lock Name)
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
+ cpm_prettify_package_arguments(PRETTY_ARGN false ${ARGN})
+ file(APPEND ${CPM_PACKAGE_LOCK_FILE} "# ${Name}\nCPMDeclarePackage(${Name}\n${PRETTY_ARGN})\n")
+ endif()
+endfunction()
+
+function(cpm_add_comment_to_package_lock Name)
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
+ cpm_prettify_package_arguments(PRETTY_ARGN true ${ARGN})
+ file(APPEND ${CPM_PACKAGE_LOCK_FILE}
+ "# ${Name} (unversioned)\n# CPMDeclarePackage(${Name}\n${PRETTY_ARGN}#)\n"
+ )
+ endif()
+endfunction()
+
+# includes the package lock file if it exists and creates a target `cpm-update-package-lock` to
+# update it
+macro(CPMUsePackageLock file)
+ if(NOT CPM_DONT_CREATE_PACKAGE_LOCK)
+ get_filename_component(CPM_ABSOLUTE_PACKAGE_LOCK_PATH ${file} ABSOLUTE)
+ if(EXISTS ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH})
+ include(${CPM_ABSOLUTE_PACKAGE_LOCK_PATH})
+ endif()
+ if(NOT TARGET cpm-update-package-lock)
+ add_custom_target(
+ cpm-update-package-lock COMMAND ${CMAKE_COMMAND} -E copy ${CPM_PACKAGE_LOCK_FILE}
+ ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}
+ )
+ endif()
+ set(CPM_PACKAGE_LOCK_ENABLED true)
+ endif()
+endmacro()
+
+# registers a package that has been added to CPM
+function(CPMRegisterPackage PACKAGE VERSION)
+ list(APPEND CPM_PACKAGES ${PACKAGE})
+ set(CPM_PACKAGES
+ ${CPM_PACKAGES}
+ CACHE INTERNAL ""
+ )
+ set("CPM_PACKAGE_${PACKAGE}_VERSION"
+ ${VERSION}
+ CACHE INTERNAL ""
+ )
+endfunction()
+
+# retrieve the current version of the package to ${OUTPUT}
+function(CPMGetPackageVersion PACKAGE OUTPUT)
+ set(${OUTPUT}
+ "${CPM_PACKAGE_${PACKAGE}_VERSION}"
+ PARENT_SCOPE
+ )
+endfunction()
+
+# declares a package in FetchContent_Declare
+function(cpm_declare_fetch PACKAGE VERSION INFO)
+ if(${CPM_DRY_RUN})
+ cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)")
+ return()
+ endif()
+
+ FetchContent_Declare(${PACKAGE} ${ARGN})
+endfunction()
+
+# returns properties for a package previously defined by cpm_declare_fetch
+function(cpm_get_fetch_properties PACKAGE)
+ if(${CPM_DRY_RUN})
+ return()
+ endif()
+
+ set(${PACKAGE}_SOURCE_DIR
+ "${CPM_PACKAGE_${PACKAGE}_SOURCE_DIR}"
+ PARENT_SCOPE
+ )
+ set(${PACKAGE}_BINARY_DIR
+ "${CPM_PACKAGE_${PACKAGE}_BINARY_DIR}"
+ PARENT_SCOPE
+ )
+endfunction()
+
+function(cpm_store_fetch_properties PACKAGE source_dir binary_dir)
+ if(${CPM_DRY_RUN})
+ return()
+ endif()
+
+ set(CPM_PACKAGE_${PACKAGE}_SOURCE_DIR
+ "${source_dir}"
+ CACHE INTERNAL ""
+ )
+ set(CPM_PACKAGE_${PACKAGE}_BINARY_DIR
+ "${binary_dir}"
+ CACHE INTERNAL ""
+ )
+endfunction()
+
+# adds a package as a subdirectory if viable, according to provided options
+function(
+ cpm_add_subdirectory
+ PACKAGE
+ DOWNLOAD_ONLY
+ SOURCE_DIR
+ BINARY_DIR
+ EXCLUDE
+ SYSTEM
+ OPTIONS
+)
+
+ if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt)
+ set(addSubdirectoryExtraArgs "")
+ if(EXCLUDE)
+ list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL)
+ endif()
+ if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25")
+ # https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM
+ list(APPEND addSubdirectoryExtraArgs SYSTEM)
+ endif()
+ if(OPTIONS)
+ foreach(OPTION ${OPTIONS})
+ cpm_parse_option("${OPTION}")
+ set(${OPTION_KEY} "${OPTION_VALUE}")
+ endforeach()
+ endif()
+ set(CPM_OLD_INDENT "${CPM_INDENT}")
+ set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:")
+ add_subdirectory(${SOURCE_DIR} ${BINARY_DIR} ${addSubdirectoryExtraArgs})
+ set(CPM_INDENT "${CPM_OLD_INDENT}")
+ endif()
+endfunction()
+
+# downloads a previously declared package via FetchContent and exports the variables
+# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope
+function(cpm_fetch_package PACKAGE populated)
+ set(${populated}
+ FALSE
+ PARENT_SCOPE
+ )
+ if(${CPM_DRY_RUN})
+ cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)")
+ return()
+ endif()
+
+ FetchContent_GetProperties(${PACKAGE})
+
+ string(TOLOWER "${PACKAGE}" lower_case_name)
+
+ if(NOT ${lower_case_name}_POPULATED)
+ FetchContent_Populate(${PACKAGE})
+ set(${populated}
+ TRUE
+ PARENT_SCOPE
+ )
+ endif()
+
+ cpm_store_fetch_properties(
+ ${CPM_ARGS_NAME} ${${lower_case_name}_SOURCE_DIR} ${${lower_case_name}_BINARY_DIR}
+ )
+
+ set(${PACKAGE}_SOURCE_DIR
+ ${${lower_case_name}_SOURCE_DIR}
+ PARENT_SCOPE
+ )
+ set(${PACKAGE}_BINARY_DIR
+ ${${lower_case_name}_BINARY_DIR}
+ PARENT_SCOPE
+ )
+endfunction()
+
+# splits a package option
+function(cpm_parse_option OPTION)
+ string(REGEX MATCH "^[^ ]+" OPTION_KEY "${OPTION}")
+ string(LENGTH "${OPTION}" OPTION_LENGTH)
+ string(LENGTH "${OPTION_KEY}" OPTION_KEY_LENGTH)
+ if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH)
+ # no value for key provided, assume user wants to set option to "ON"
+ set(OPTION_VALUE "ON")
+ else()
+ math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1")
+ string(SUBSTRING "${OPTION}" "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE)
+ endif()
+ set(OPTION_KEY
+ "${OPTION_KEY}"
+ PARENT_SCOPE
+ )
+ set(OPTION_VALUE
+ "${OPTION_VALUE}"
+ PARENT_SCOPE
+ )
+endfunction()
+
+# guesses the package version from a git tag
+function(cpm_get_version_from_git_tag GIT_TAG RESULT)
+ string(LENGTH ${GIT_TAG} length)
+ if(length EQUAL 40)
+ # GIT_TAG is probably a git hash
+ set(${RESULT}
+ 0
+ PARENT_SCOPE
+ )
+ else()
+ string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG})
+ set(${RESULT}
+ ${CMAKE_MATCH_1}
+ PARENT_SCOPE
+ )
+ endif()
+endfunction()
+
+# guesses if the git tag is a commit hash or an actual tag or a branch name.
+function(cpm_is_git_tag_commit_hash GIT_TAG RESULT)
+ string(LENGTH "${GIT_TAG}" length)
+ # full hash has 40 characters, and short hash has at least 7 characters.
+ if(length LESS 7 OR length GREATER 40)
+ set(${RESULT}
+ 0
+ PARENT_SCOPE
+ )
+ else()
+ if(${GIT_TAG} MATCHES "^[a-fA-F0-9]+$")
+ set(${RESULT}
+ 1
+ PARENT_SCOPE
+ )
+ else()
+ set(${RESULT}
+ 0
+ PARENT_SCOPE
+ )
+ endif()
+ endif()
+endfunction()
+
+function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT)
+ set(oneValueArgs
+ NAME
+ FORCE
+ VERSION
+ GIT_TAG
+ DOWNLOAD_ONLY
+ GITHUB_REPOSITORY
+ GITLAB_REPOSITORY
+ GIT_REPOSITORY
+ SOURCE_DIR
+ DOWNLOAD_COMMAND
+ FIND_PACKAGE_ARGUMENTS
+ NO_CACHE
+ SYSTEM
+ GIT_SHALLOW
+ )
+ set(multiValueArgs OPTIONS)
+ cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ foreach(oneArgName ${oneValueArgs})
+ if(DEFINED CPM_ARGS_${oneArgName})
+ if(${IS_IN_COMMENT})
+ string(APPEND PRETTY_OUT_VAR "#")
+ endif()
+ if(${oneArgName} STREQUAL "SOURCE_DIR")
+ string(REPLACE ${CMAKE_SOURCE_DIR} "\${CMAKE_SOURCE_DIR}" CPM_ARGS_${oneArgName}
+ ${CPM_ARGS_${oneArgName}}
+ )
+ endif()
+ string(APPEND PRETTY_OUT_VAR " ${oneArgName} ${CPM_ARGS_${oneArgName}}\n")
+ endif()
+ endforeach()
+ foreach(multiArgName ${multiValueArgs})
+ if(DEFINED CPM_ARGS_${multiArgName})
+ if(${IS_IN_COMMENT})
+ string(APPEND PRETTY_OUT_VAR "#")
+ endif()
+ string(APPEND PRETTY_OUT_VAR " ${multiArgName}\n")
+ foreach(singleOption ${CPM_ARGS_${multiArgName}})
+ if(${IS_IN_COMMENT})
+ string(APPEND PRETTY_OUT_VAR "#")
+ endif()
+ string(APPEND PRETTY_OUT_VAR " \"${singleOption}\"\n")
+ endforeach()
+ endif()
+ endforeach()
+
+ if(NOT "${CPM_ARGS_UNPARSED_ARGUMENTS}" STREQUAL "")
+ if(${IS_IN_COMMENT})
+ string(APPEND PRETTY_OUT_VAR "#")
+ endif()
+ string(APPEND PRETTY_OUT_VAR " ")
+ foreach(CPM_ARGS_UNPARSED_ARGUMENT ${CPM_ARGS_UNPARSED_ARGUMENTS})
+ string(APPEND PRETTY_OUT_VAR " ${CPM_ARGS_UNPARSED_ARGUMENT}")
+ endforeach()
+ string(APPEND PRETTY_OUT_VAR "\n")
+ endif()
+
+ set(${OUT_VAR}
+ ${PRETTY_OUT_VAR}
+ PARENT_SCOPE
+ )
+
+endfunction()
diff --git a/cmake/polyscope.cmake b/cmake/polyscope.cmake
new file mode 100644
index 00000000..f95964c3
--- /dev/null
+++ b/cmake/polyscope.cmake
@@ -0,0 +1,14 @@
+if (TARGET polyscope)
+ return()
+endif()
+
+set(CMAKE_CXX_FLAGS_DEBUG_OLD "${CMAKE_CXX_FLAGS_DEBUG}")
+set(CMAKE_CXX_FLAGS_DEBUG "-w")
+
+CPMAddPackage(
+ NAME polyscope
+ VERSION 1.2.0
+ GITHUB_REPOSITORY "nmwsharp/polyscope"
+)
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG_OLD}")
diff --git a/doc/images/volscope-surface.png b/doc/images/volscope-surface.png
new file mode 100644
index 00000000..3c1c0c4b
Binary files /dev/null and b/doc/images/volscope-surface.png differ
diff --git a/doc/images/volscope-volumetric.png b/doc/images/volscope-volumetric.png
new file mode 100644
index 00000000..f4987a9c
Binary files /dev/null and b/doc/images/volscope-volumetric.png differ
diff --git a/doc/visualization.dox b/doc/visualization.dox
index e8f1b6c9..f458ab1c 100644
--- a/doc/visualization.dox
+++ b/doc/visualization.dox
@@ -18,7 +18,7 @@
@section visualization_Doc Visualization
-
+ - @ref volscope : a new generic VOL file viewer using polyscope.
- @ref Doc2dCompImage : compare images and displays differences (squared and absolute differences).
- @ref CompSurfelData : computes generic scalar surfel data comparisons (squared error) ( given from an input data file and from a reference one).
- @ref Doc3DCurvatureViewer : permits to compute and visualize mean or gaussian curvature of binary shapes.
diff --git a/visualisation/3dSDPViewer.cpp b/visualisation/3dSDPViewer.cpp
index a4d44537..845e2a52 100644
--- a/visualisation/3dSDPViewer.cpp
+++ b/visualisation/3dSDPViewer.cpp
@@ -45,8 +45,6 @@
#include "CLI11.hpp"
-
-
using namespace std;
using namespace DGtal;
using namespace Z3i;
@@ -55,13 +53,13 @@ typedef Viewer3D Viewer;
/**
@page Doc3DSDPViewer 3DSDPViewer
-
+
@brief Displays a sequence of 3d discrete points by using QGLviewer.
@b Usage: 3dSDPViewer [OPTIONS] 1 [f] [lineSize] [filterVectors]
@b Allowed @b options @b are :
-
+
@code
Positionals:
@@ -75,6 +73,7 @@ typedef Viewer3D Viewer;
-l,--lineColor INT x 4 set the color of line: r g b a.
-m,--addMesh TEXT append a mesh (off/obj) to the point set visualization.
--customColorMesh UINT x 4 set the R, G, B, A components of the colors of the mesh faces (mesh added with option --addMesh).
+ --customAlphaMesh UINT set single alpha(A) components of the colors of the mesh faces (mesh added with option --addMesh).
--importColors import point colors from the input file (R G B colors should be by default at index 3, 4, 5).
--setColorsIndex UINT x 3 Needs: --importColors
customize the index of the imported colors in the source file (used by --importColor). By default the initial indexes are 3, 4, 5.
@@ -96,11 +95,11 @@ typedef Viewer3D Viewer;
-u,--unitVector FLOAT=0 specifies that the SDP vector file format (of --drawVectors option) should be interpreted as unit vectors (each vector position is be defined from the input point (with input order) with a constant norm defined by [arg]).
--filterVectors FLOAT=100 filters vector input file in order to display only the [arg] percent of the input vectors (uniformly selected, to be used with option --drawVectors else no effect).
--interactiveDisplayVoxCoords by using this option the coordinates can be displayed after selection (shift+left click on voxel).
-
+
@endcode
- @b Basic @b example:
+ @b Basic @b example:
You can display a set of 3D points with sphere primitive and lines:
@code
@@ -115,14 +114,14 @@ typedef Viewer3D Viewer;
@b Example @b with @b interactive @b selection :
This tool can be useful to recover coordinates from a set of voxels. To do it, you have to add the option allowing to activate the interactive selection (with --interactiveDisplayVoxCoords), for instance if you apply:
-@code
+@code
$ 3dSDPViewer $DGtal/tests/samples/sinus3D.dat --interactiveDisplayVoxCoords
-
-@endcode
+
+@endcode
you should be able to select a voxel by using the SHIFT key and by clicking on a voxel:
@image html res3DSDPViewerInteractive.png " "
-
+
@b Visualization @b of @b large @b point @b set
If you need to display an important number of points, you can use the primitive @e glPoints instead @e voxel or @e sphere (-p glPoints). You will obtain such type of a visualization:
@@ -136,245 +135,250 @@ If you need to display an important number of points, you can use the primitive
*/
-
-
// call back function to display voxel coordinates
-int
-displayCoordsCallBack( void* viewer, int name, void* data )
+int displayCoordsCallBack(void *viewer, int name, void *data)
{
- vector *vectVoxels = (vector *) data;
+ vector *vectVoxels = (vector *)data;
std::stringstream ss;
- ss << "Selected voxel: (" << (*vectVoxels)[name][0] << ", ";
- ss << (*vectVoxels)[name][1] << ", ";
- ss << (*vectVoxels)[name][2] << ") ";
- ((Viewer *) viewer)->displayMessage(QString(ss.str().c_str()), 100000);
-
+ ss << "Selected voxel: (" << (*vectVoxels)[name][0] << ", ";
+ ss << (*vectVoxels)[name][1] << ", ";
+ ss << (*vectVoxels)[name][2] << ") ";
+ ((Viewer *)viewer)->displayMessage(QString(ss.str().c_str()), 100000);
+
return 0;
}
-
-int main( int argc, char** argv )
+int main(int argc, char **argv)
{
// parse command line using CLI ----------------------------------------------
CLI::App app;
std::string inputFileName;
- std::vector vectIndexSDP {0,1,2};
+ std::vector vectIndexSDP{0, 1, 2};
Color lineColor(100, 100, 250);
Color pointColor(250, 250, 250);
std::vector vectColorPt;
std::vector vectColorLine;
std::string meshName;
- std::string typePrimitive {"voxel"};
+ std::string typePrimitive{"voxel"};
std::string vectorsFileName;
std::vector vectSphereRadius;
std::vector vectColMesh;
- std::vector vectIndexColorImport {3,4,5};
- bool importColorLabels {false};
- bool noPointDisplay {false};
- bool drawLines {false};
- bool sphereRadiusFromInput {true};
- bool importColors {false};
- bool interactiveDisplayVoxCoords {false};
- float sx {1.0};
- float sy {1.0};
- float sz {1.0};
- unsigned int sphereResolution {30};
- double sphereRadius {0.2};
- double lineSize {0.2};
- double filterValue {100.0};
- double constantNorm {0.0};
- double percentageFilterVect {100.0};
+ std::vector vectIndexColorImport{3, 4, 5};
+ bool importColorLabels{false};
+ bool noPointDisplay{false};
+ bool drawLines{false};
+ bool sphereRadiusFromInput{true};
+ bool importColors{false};
+ bool interactiveDisplayVoxCoords{false};
+ float sx{1.0};
+ float sy{1.0};
+ float sz{1.0};
+ unsigned int sphereResolution{30};
+ double sphereRadius{0.2};
+ double lineSize{0.2};
+ double filterValue{100.0};
+ double constantNorm{0.0};
+ double percentageFilterVect{100.0};
+ unsigned int customAlphaMesh;
unsigned int colorLabelIndex = 3;
-
+
app.description("Display sequence of 3d discrete points by using QGLviewer.");
- app.add_option("-i,--input,1", inputFileName, "input file: sdp (sequence of discrete points)." )
- ->required()
- ->check(CLI::ExistingFile);
- app.add_option("--SDPindex",vectIndexSDP, "specify the sdp index (by default 0,1,2).")
- ->expected(3);
- app.add_option("--pointColor,-c",vectColorPt, "set the color of points: r g b a.")
- ->expected(4);
- app.add_option("--lineColor,-l",vectColorLine, "set the color of line: r g b a.")
- ->expected(4);
- app.add_option("--addMesh,-m",meshName, "append a mesh (off/obj) to the point set visualization.");
- auto optMesh = app.add_option("--customColorMesh",vectColMesh, "set the R, G, B, A components of the colors of the mesh faces (mesh added with option --addMesh).")
- ->expected(4);
- auto importColOpt = app.add_flag("--importColors",importColors, "import point colors from the input file (R G B colors should be by default at index 3, 4, 5).");
- app.add_option("--setColorsIndex", vectIndexColorImport,"customize the index of the imported colors in the source file (used by --importColor). By default the initial indexes are 3, 4, 5.")
- ->expected(3)
- ->needs(importColOpt);
-
- app.add_flag("--importColorLabels", importColorLabels,"import color labels from the input file (label index should be by default at index 3)." );
+ app.add_option("-i,--input,1", inputFileName, "input file: sdp (sequence of discrete points).")
+ ->required()
+ ->check(CLI::ExistingFile);
+ app.add_option("--SDPindex", vectIndexSDP, "specify the sdp index (by default 0,1,2).")
+ ->expected(3);
+ app.add_option("--pointColor,-c", vectColorPt, "set the color of points: r g b a.")
+ ->expected(4);
+ app.add_option("--lineColor,-l", vectColorLine, "set the color of line: r g b a.")
+ ->expected(4);
+ app.add_option("--addMesh,-m", meshName, "append a mesh (off/obj) to the point set visualization.");
+ app.add_option("--customAlphaMesh", customAlphaMesh, "set the alpha components of the colors of the mesh faces (can be applied for each mesh).");
+ auto optMesh = app.add_option("--customColorMesh", vectColMesh, "set the R, G, B, A components of the colors of the mesh faces (mesh added with option --addMesh).")
+ ->expected(4);
+ auto importColOpt = app.add_flag("--importColors", importColors, "import point colors from the input file (R G B colors should be by default at index 3, 4, 5).");
+ app.add_option("--setColorsIndex", vectIndexColorImport, "customize the index of the imported colors in the source file (used by --importColor). By default the initial indexes are 3, 4, 5.")
+ ->expected(3)
+ ->needs(importColOpt);
+
+ app.add_flag("--importColorLabels", importColorLabels, "import color labels from the input file (label index should be by default at index 3).");
app.add_option("--setColorLabelIndex", colorLabelIndex, "customize the index of the imported color labels in the source file (used by -importColorLabels).", true);
app.add_option("--filter,-f", filterValue, "filter input file in order to display only the [arg] percent of the input 3D points (uniformly selected).", true);
- app.add_flag("--noPointDisplay",noPointDisplay, "usefull for instance to only display the lines between points." );
- app.add_flag("--drawLines", drawLines, "draw the line between discrete points." );
- app.add_option("--scaleX,-x", sx, "set the scale value in the X direction", true );
- app.add_option("--scaleY,-y", sy, "set the scale value in the Y direction", true );
- app.add_option("--scaleZ,-z", sy, "set the scale value in the Z direction", true );
- app.add_option("--sphereResolution",sphereResolution, "defines the sphere resolution (used when the primitive is set to the sphere).", true );
+ app.add_flag("--noPointDisplay", noPointDisplay, "usefull for instance to only display the lines between points.");
+ app.add_flag("--drawLines", drawLines, "draw the line between discrete points.");
+ app.add_option("--scaleX,-x", sx, "set the scale value in the X direction", true);
+ app.add_option("--scaleY,-y", sy, "set the scale value in the Y direction", true);
+ app.add_option("--scaleZ,-z", sy, "set the scale value in the Z direction", true);
+ app.add_option("--sphereResolution", sphereResolution, "defines the sphere resolution (used when the primitive is set to the sphere).", true);
app.add_option("-s,--sphereRadius", sphereRadius, "defines the sphere radius (used when the primitive is set to the sphere).", true);
app.add_flag("--sphereRadiusFromInput", sphereRadiusFromInput, "takes, as sphere radius, the 4th field of the sdp input file.");
app.add_option("--lineSize", lineSize, "defines the line size (used when the --drawLines or --drawVectors option is selected).", true);
- app.add_option("--primitive,-p",typePrimitive, "set the primitive to display the set of points.", true )
- -> check(CLI::IsMember({"voxel", "glPoints", "sphere"}));
- app.add_option("--drawVectors,-v",vectorsFileName, "SDP vector file: draw a set of vectors from the given file (each vector are determined by two consecutive point given, each point represented by its coordinates on a single line.");
-
- app.add_option("--unitVector,-u", constantNorm, "specifies that the SDP vector file format (of --drawVectors option) should be interpreted as unit vectors (each vector position is be defined from the input point (with input order) with a constant norm defined by [arg]).", true );
-
- app.add_option("--filterVectors", percentageFilterVect, "filters vector input file in order to display only the [arg] percent of the input vectors (uniformly selected, to be used with option --drawVectors else no effect). ", true );
+ app.add_option("--primitive,-p", typePrimitive, "set the primitive to display the set of points.", true)
+ ->check(CLI::IsMember({"voxel", "glPoints", "sphere"}));
+ app.add_option("--drawVectors,-v", vectorsFileName, "SDP vector file: draw a set of vectors from the given file (each vector are determined by two consecutive point given, each point represented by its coordinates on a single line.");
+
+ app.add_option("--unitVector,-u", constantNorm, "specifies that the SDP vector file format (of --drawVectors option) should be interpreted as unit vectors (each vector position is be defined from the input point (with input order) with a constant norm defined by [arg]).", true);
+
+ app.add_option("--filterVectors", percentageFilterVect, "filters vector input file in order to display only the [arg] percent of the input vectors (uniformly selected, to be used with option --drawVectors else no effect). ", true);
app.add_flag("--interactiveDisplayVoxCoords", interactiveDisplayVoxCoords, " by using this option the coordinates can be displayed after selection (shift+left click on voxel).");
-
-
+
app.get_formatter()->column_width(40);
CLI11_PARSE(app, argc, argv);
// END parse command line using CLI ----------------------------------------------
-
- if (vectColorLine.size() == 4){
+ if (vectColorLine.size() == 4)
+ {
lineColor.setRGBi(vectColorLine[0], vectColorLine[1], vectColorLine[2], vectColorLine[3]);
}
- if (vectColorPt.size() == 4){
+ if (vectColorPt.size() == 4)
+ {
pointColor.setRGBi(vectColorPt[0], vectColorPt[1], vectColorPt[2], vectColorPt[3]);
}
-
- QApplication application(argc,argv);
-
-
+ QApplication application(argc, argv);
+
bool useUnitVector = constantNorm != 0.0;
-
+
typedef Viewer3D Viewer;
Z3i::KSpace K;
- Viewer viewer( K );
+ Viewer viewer(K);
viewer.setWindowTitle("3dSPD Viewer");
viewer.show();
viewer.setGLScale(sx, sy, sz);
viewer.myGLLineMinWidth = lineSize;
viewer << CustomColors3D(pointColor, pointColor);
-
-
+
// Get vector of colors if imported.
std::vector vectColors;
- if(importColors)
+ if (importColors)
{
- std::vector r = TableReader::getColumnElementsFromFile(inputFileName,vectIndexColorImport[0]);
- std::vector g = TableReader::getColumnElementsFromFile(inputFileName,vectIndexColorImport[1]);
- std::vector b = TableReader::getColumnElementsFromFile(inputFileName,vectIndexColorImport[2]);
- for (unsigned int i = 0; i r = TableReader::getColumnElementsFromFile(inputFileName, vectIndexColorImport[0]);
+ std::vector g = TableReader::getColumnElementsFromFile(inputFileName, vectIndexColorImport[1]);
+ std::vector b = TableReader::getColumnElementsFromFile(inputFileName, vectIndexColorImport[2]);
+ for (unsigned int i = 0; i < r.size(); i++)
+ {
vectColors.push_back(Color(r[i], g[i], b[i]));
}
}
// Get vector of colors if imported.
- std::vector< int> vectColorLabels;
+ std::vector vectColorLabels;
unsigned int maxLabel = 1;
- if(importColorLabels)
+ if (importColorLabels)
{
- vectColorLabels = TableReader< int>::getColumnElementsFromFile(inputFileName, colorLabelIndex);
+ vectColorLabels = TableReader::getColumnElementsFromFile(inputFileName, colorLabelIndex);
maxLabel = *(std::max_element(vectColorLabels.begin(), vectColorLabels.end()));
}
HueShadeColorMap aColorMap(0, maxLabel);
-
-
- if(sphereRadiusFromInput)
+
+ if (sphereRadiusFromInput)
{
- vectSphereRadius = TableReader::getColumnElementsFromFile(inputFileName,3);
+ vectSphereRadius = TableReader::getColumnElementsFromFile(inputFileName, 3);
}
-
+
vector vectVoxels;
vectVoxels = PointListReader::getPointsFromFile(inputFileName, vectIndexSDP);
-
+
int name = 0;
- if(!noPointDisplay){
+ if (!noPointDisplay)
+ {
if (typePrimitive == "glPoints")
+ {
+ viewer.setUseGLPointForBalls(true);
+ }
+
+ int step = max(1, (int)(100 / filterValue));
+ for (unsigned int i = 0; i < vectVoxels.size(); i = i + step)
+ {
+ if (importColors)
{
- viewer.setUseGLPointForBalls(true);
+ Color col = vectColors[i];
+ viewer.setFillColor(col);
+ }
+ else if (importColorLabels)
+ {
+ unsigned int index = vectColorLabels[i];
+ Color col = aColorMap(index);
+ viewer.setFillColor(col);
}
- int step = max(1, (int) (100/filterValue));
- for(unsigned int i=0;i< vectVoxels.size(); i=i+step){
- if(importColors)
- {
- Color col = vectColors[i];
- viewer.setFillColor(col);
- }
- else if(importColorLabels)
- {
- unsigned int index = vectColorLabels[i];
- Color col = aColorMap(index);
- viewer.setFillColor(col);
- }
-
- if(typePrimitive=="voxel" ){
+ if (typePrimitive == "voxel")
+ {
if (interactiveDisplayVoxCoords)
{
- viewer << SetName3D( name++ ) ;
+ viewer << SetName3D(name++);
}
viewer << Z3i::Point((int)vectVoxels.at(i)[0],
(int)vectVoxels.at(i)[1],
(int)vectVoxels.at(i)[2]);
}
else
- {
- viewer.addBall(vectVoxels.at(i), sphereRadius, sphereResolution);
- }
+ {
+ viewer.addBall(vectVoxels.at(i), sphereRadius, sphereResolution);
+ }
}
-
+
viewer << CustomColors3D(lineColor, lineColor);
- if(drawLines)
+ if (drawLines)
{
- for(unsigned int i=1;i< vectVoxels.size(); i++)
+ for (unsigned int i = 1; i < vectVoxels.size(); i++)
{
- viewer.addLine(vectVoxels.at(i-1), vectVoxels.at(i), lineSize);
+ viewer.addLine(vectVoxels.at(i - 1), vectVoxels.at(i), lineSize);
}
}
-
- if(vectorsFileName != "")
+
+ if (vectorsFileName != "")
{
std::vector vectorsPt = PointListReader::getPointsFromFile(vectorsFileName);
- if (vectorsPt.size()%2==1)
+ if (vectorsPt.size() % 2 == 1)
{
- trace.info()<<"Warning the two set of points doesn't contains the same number of points, some vectors will be skipped." << std::endl;
+ trace.info() << "Warning the two set of points doesn't contains the same number of points, some vectors will be skipped." << std::endl;
}
double percentage = percentageFilterVect;
- int step = max(1, (int) (100/percentage));
-
- if(useUnitVector)
+ int step = max(1, (int)(100 / percentage));
+
+ if (useUnitVector)
{
- for(unsigned int i =0; i< std::min(vectVoxels.size(), vectorsPt.size()); i=i+2*step)
+ for (unsigned int i = 0; i < std::min(vectVoxels.size(), vectorsPt.size()); i = i + 2 * step)
{
- viewer.addLine(vectVoxels.at(i), vectVoxels.at(i)+vectorsPt.at(i)*constantNorm, lineSize);
+ viewer.addLine(vectVoxels.at(i), vectVoxels.at(i) + vectorsPt.at(i) * constantNorm, lineSize);
}
}
else
{
- for(unsigned int i =0; i mesh(!customColorMesh);
- mesh << meshName ;
- viewer << mesh;
- }
- if (interactiveDisplayVoxCoords)
- {
- viewer << SetSelectCallback3D( displayCoordsCallBack, &vectVoxels, 0, vectVoxels.size()-1 );
+ mesh << meshName;
+ if (customAlphaMesh)
+ {
+ for (unsigned int j = 0; j < mesh.nbFaces(); j++)
+ {
+ auto c = mesh.getFaceColor(j);
+ mesh.setFaceColor(j, Color(c.red(), c.green(), c.blue(), customAlphaMesh));
+ }
+ viewer << mesh;
+ }
+ if (interactiveDisplayVoxCoords)
+ {
+ viewer << SetSelectCallback3D(displayCoordsCallBack, &vectVoxels, 0, vectVoxels.size() - 1);
+ }
+
+ viewer << Viewer3D<>::updateDisplay;
+ return application.exec();
}
-
- viewer << Viewer3D<>::updateDisplay;
- return application.exec();
}
}
-
diff --git a/visualisation/CMakeLists.txt b/visualisation/CMakeLists.txt
index 58cbc111..57ffd96d 100644
--- a/visualisation/CMakeLists.txt
+++ b/visualisation/CMakeLists.txt
@@ -45,8 +45,23 @@ if ( WITH_VISU3D_QGLVIEWER )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Xml_EXECUTABLE_COMPILE_FLAGS}")
DGtalTools_add_tool(sliceViewer ${ui_sliceViewer_FORMS_HEADERS})
endif (WITH_QT4)
-
endif (WITH_VISU3D_QGLVIEWER)
+if ( NOT(DISABLE_POLYSCOPE) )
+ SET(DGTALTOOLS_POLYSCOPE_SRC
+ volscope)
+
+ FOREACH(tool_file ${DGTALTOOLS_POLYSCOPE_SRC})
+ add_executable(${tool_file} ${tool_file}.cpp)
+ target_link_libraries (${tool_file} ${DGTAL_LIBRARIES} ${DGtalLibDependencies} ${DGtalToolsLibDependencies} polyscope)
+ install(TARGETS ${tool_file}
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib)
+ endforeach (tool_file)
+endif ()
+
+
+
diff --git a/visualisation/meshViewer.cpp b/visualisation/meshViewer.cpp
index 84a87f5c..cf4a8803 100644
--- a/visualisation/meshViewer.cpp
+++ b/visualisation/meshViewer.cpp
@@ -37,28 +37,25 @@
#include "DGtal/helpers/StdDefs.h"
#include "DGtal/io/readers/PointListReader.h"
-
#include "CLI11.hpp"
-
using namespace std;
using namespace DGtal;
-
/**
@page meshViewer meshViewer
-
+
@brief Displays OFF mesh file by using QGLviewer.
-
+
@b Usage: meshViewer [input]
-
+
@b Allowed @b options @b are :
-
+
@code
-
+
Positionals:
1 TEXT:FILE ... REQUIRED inputFileNames.off files (.off), or OFS file (.ofs)
-
+
Options:
-h,--help Print this help message and exit
-i,--input TEXT:FILE ... REQUIRED inputFileNames.off files (.off), or OFS file (.ofs)
@@ -81,20 +78,20 @@ using namespace DGtal;
-l,--fixLightToScene Fix light source to scence instead to camera
-n,--invertNormal invert face normal vectors.
-v,--drawVertex draw the vertex of the mesh
-
+
@endcode
-
-
+
+
@b Example:
-
+
@code
$ meshViewer bunny.off
-
+
@endcode
-
+
You should obtain such a result:
@image html resMeshViewer.png "Resulting visualization."
-
+
@see
@ref meshViewer.cpp
@@ -104,273 +101,331 @@ using namespace DGtal;
* Custom Viewer3D to override KeyPressEvent method and handle new key display.
* It also desactivate the double Rendering mode for more efficiency.
**/
-class CustomViewer3D: public Viewer3D<>
+class CustomViewer3D : public Viewer3D<>
{
protected:
-
virtual void init()
{
Viewer3D<>::init();
- Viewer3D<>::setKeyDescription ( Qt::Key_I, "Display mesh informations about #faces, #vertices" );
+ Viewer3D<>::setKeyDescription(Qt::Key_I, "Display mesh informations about #faces, #vertices");
Viewer3D<>::setGLDoubleRenderingMode(false);
-
}
-
- virtual void keyPressEvent(QKeyEvent *e){
+
+ virtual void keyPressEvent(QKeyEvent *e)
+ {
bool handled = false;
- if( e->key() == Qt::Key_I)
+ if (e->key() == Qt::Key_I)
{
- handled=true;
+ handled = true;
myIsDisplayingInfoMode = !myIsDisplayingInfoMode;
stringstream ss;
qglviewer::Vec camPos = camera()->position();
- DGtal::Z3i::RealPoint c (camPos[0], camPos[1], camPos[2]);
- ss << myInfoDisplay << " distance to camera: " << (c-centerMesh).norm();
- Viewer3D<>::displayMessage(QString(myIsDisplayingInfoMode ?
- ss.str().c_str() : " "), 1000000);
-
+ DGtal::Z3i::RealPoint c(camPos[0], camPos[1], camPos[2]);
+ ss << myInfoDisplay << " distance to camera: " << (c - centerMesh).norm();
+ Viewer3D<>::displayMessage(QString(myIsDisplayingInfoMode ? ss.str().c_str() : " "), 1000000);
+
Viewer3D<>::update();
}
- if(!handled)
+ if (!handled)
{
Viewer3D<>::keyPressEvent(e);
}
};
-
-public:
+
+public:
void changeDefaultBGColor(const DGtal::Color &col)
- {
- myDefaultBackgroundColor = col;
- Viewer3D<>::update();
- Viewer3D<>::draw();
- }
+ {
+ myDefaultBackgroundColor = col;
+ Viewer3D<>::update();
+ Viewer3D<>::draw();
+ }
std::string myInfoDisplay = "No information loaded...";
bool myIsDisplayingInfoMode = false;
DGtal::Z3i::RealPoint centerMesh;
};
-
-int main( int argc, char** argv )
+int main(int argc, char **argv)
{
- float sx {1.0};
- float sy {1.0};
- float sz {1.0};
-
- unsigned int meshColorR {240};
- unsigned int meshColorG {240};
- unsigned int meshColorB {240};
- unsigned int meshColorA {255};
-
- unsigned int meshColorRLine {0};
- unsigned int meshColorGLine {0};
- unsigned int meshColorBLine {0};
- unsigned int meshColorALine {255};
-
- unsigned int sdpColorR {240};
- unsigned int sdpColorG {240};
- unsigned int sdpColorB {240};
- unsigned int sdpColorA {255};
-
- float lineWidth {1.5};
-
- std::vector customColorMesh;
- std::vector customColorSDP;
- std::vector customLineColor;
- std::vector customBGColor;
- std::vector vectFieldIndices = {0,1,2,3,4,5};
+ float sx{1.0};
+ float sy{1.0};
+ float sz{1.0};
+
+ unsigned int meshColorR{240};
+ unsigned int meshColorG{240};
+ unsigned int meshColorB{240};
+ unsigned int meshColorA{255};
+
+ unsigned int meshColorRLine{0};
+ unsigned int meshColorGLine{0};
+ unsigned int meshColorBLine{0};
+ unsigned int meshColorALine{255};
+
+ unsigned int sdpColorR{240};
+ unsigned int sdpColorG{240};
+ unsigned int sdpColorB{240};
+ unsigned int sdpColorA{255};
+
+ float lineWidth{1.5};
+
+ std::vector customColorMesh;
+ std::vector customColorSDP;
+ std::vector customLineColor;
+ std::vector customBGColor;
+ std::vector customAlphaMesh;
+ std::vector vectFieldIndices = {0, 1, 2, 3, 4, 5};
std::string displayVectorField;
-
+
std::string snapshotFile;
std::string filenameSDP;
- double ballRadius {0.5};
- bool invertNormal {false};
- bool drawVertex {false};
- bool useLastCamSet {false};
- bool fixLightToScene {false};
- float ambiantLight {0.0};
- std::vector customAlphaMesh;
-
+ double ballRadius{0.5};
+ bool invertNormal{false};
+ bool drawVertex{false};
+ bool useLastCamSet{false};
+ bool fixLightToScene{false};
+ float ambiantLight{0.0};
+
// parse command line using CLI ----------------------------------------------
CLI::App app;
std::vector inputFileNames;
- std::string outputFileName {"result.raw"};
+ std::string outputFileName{"result.raw"};
app.description("Display OFF mesh file by using QGLviewer");
- app.add_option("-i,--input,1", inputFileNames, "inputFileNames.off files (.off), or OFS file (.ofs)" )
- ->check(CLI::ExistingFile)
- ->required();
+ app.add_option("-i,--input,1", inputFileNames, "inputFileNames.off files (.off), or OFS file (.ofs)")
+ ->check(CLI::ExistingFile)
+ ->required();
app.add_option("-x,--scaleX", sx, "set the scale value in the X direction (default 1.0)");
app.add_option("-y,--scaleY", sy, "set the scale value in the y direction (default 1.0)");
app.add_option("-z,--scaleZ", sz, "set the scale value in the z direction (default 1.0)");
app.add_option("--minLineWidth", lineWidth, "set the min line width of the mesh faces (default 1.5)", true);
app.add_option("--customColorMesh", customColorMesh, "set the R, G, B, A components of the colors of the mesh faces and eventually the color R, G, B, A of the mesh edge lines (set by default to black).");
- app.add_option("--customAlphaMesh", customAlphaMesh, "set the alpha components of the colors of the mesh faces (can be applied for each mesh).");
-
- app.add_option("--customColorSDP", customColorSDP, "set the R, G, B, A components of the colors of the sdp view")
- ->expected(4);
+ app.add_option("--customAlphaMesh", customAlphaMesh, "set the alpha(A) components of the colors of the mesh faces (can be applied for each mesh).");
+ app.add_option("--customColorSDP", customColorSDP, "set the R, G, B, A components of the colors of the sdp view")
+ ->expected(4);
app.add_option("--displayVectorField,-f", displayVectorField, "display a vector field from a simple sdp file (two points per line)");
- app.add_option("--vectorFieldIndex", vectFieldIndices, "specify special indices for the two point coordinates (instead usinf the default indices: 0 1, 2, 3, 4, 5)" )
- ->expected(6);
+ app.add_option("--vectorFieldIndex", vectFieldIndices, "specify special indices for the two point coordinates (instead usinf the default indices: 0 1, 2, 3, 4, 5)")
+ ->expected(6);
app.add_option("--customLineColor", customLineColor, "set the R, G, B components of the colors of the lines displayed from the --displayVectorField option (red by default).")
- ->expected(4);
+ ->expected(4);
app.add_option("--SDPradius", ballRadius, "change the ball radius to display a set of discrete points (used with displaySDP option)", true);
- app.add_option("--displaySDP,-s", filenameSDP, "add the display of a set of discrete points as ball of radius 0.5.");
- app.add_option("--addAmbientLight,-A", ambiantLight, "add an ambient light for better display (between 0 and 1)." );
+ app.add_option("--displaySDP,-s", filenameSDP, "add the display of a set of discrete points as ball of radius 0.5.");
+ app.add_option("--addAmbientLight,-A", ambiantLight, "add an ambient light for better display (between 0 and 1).");
app.add_option("--customBGColor,-b", customBGColor, "set the R, G, B components of the colors of the background color.")
- ->expected(3);
+ ->expected(3);
app.add_option("--doSnapShotAndExit,-d", snapshotFile, "save display snapshot into file. Notes that the camera setting is set by default according the last saved configuration (use SHIFT+Key_M to save current camera setting in the Viewer3D). If the camera setting was not saved it will use the default camera setting.");
app.add_flag("--useLastCameraSetting,-c", useLastCamSet, "use the last camera setting of the user (i.e if a .qglviewer.xml file is present in the current directory)");
app.add_flag("--fixLightToScene,-l", fixLightToScene, "Fix light source to scence instead to camera");
app.add_flag("--invertNormal,-n", invertNormal, "invert face normal vectors.");
app.add_flag("--drawVertex,-v", drawVertex, "draw the vertex of the mesh");
-
app.get_formatter()->column_width(40);
CLI11_PARSE(app, argc, argv);
// END parse command line using CLI ----------------------------------------------
-
-
-
+
DGtal::Color vFieldLineColor = DGtal::Color::Red;
- if( customLineColor.size() == 4)
+ if (customLineColor.size() == 4)
{
vFieldLineColor.setRGBi(customLineColor[0], customLineColor[1], customLineColor[2], 255);
}
-
- if( customColorMesh.size() != 0 )
+
+ if (customColorMesh.size() != 0)
{
- if(customColorMesh.size()<4 )
+ if (customColorMesh.size() < 4)
{
- trace.error() << "colors specification should contain R,G,B and Alpha values"<< std::endl;
+ trace.error() << "colors specification should contain R,G,B and Alpha values" << std::endl;
}
-
}
-
- if(customColorSDP.size() == 4)
+
+ if (customColorSDP.size() == 4)
{
sdpColorR = customColorSDP[0];
sdpColorG = customColorSDP[1];
sdpColorB = customColorSDP[2];
sdpColorA = customColorSDP[3];
}
-
- QApplication application(argc,argv);
+
+ QApplication application(argc, argv);
CustomViewer3D viewer;
- if(snapshotFile != "")
+ if (snapshotFile != "")
{
viewer.setSnapshotFileName(QString(snapshotFile.c_str()));
}
-
+
std::stringstream title;
- title << "Simple Mesh Viewer: " << inputFileNames[0];
+ title << "Simple Mesh Viewer: " << inputFileNames[0];
viewer.setWindowTitle(title.str().c_str());
viewer.show();
viewer.myGLLineMinWidth = lineWidth;
viewer.setGLScale(sx, sy, sz);
- if (customBGColor.size() == 3){
- viewer.changeDefaultBGColor(DGtal::Color(customBGColor[0],
- customBGColor[1],
- customBGColor[2], 255));
+ if (customBGColor.size() == 3)
+ {
+ viewer.changeDefaultBGColor(DGtal::Color(customBGColor[0],
+ customBGColor[1],
+ customBGColor[2], 255));
}
- if(ambiantLight != 0.0)
+ if (ambiantLight != 0.0)
{
- GLfloat lightAmbientCoeffs [4] = {ambiantLight,ambiantLight, ambiantLight, 1.0f};
+ GLfloat lightAmbientCoeffs[4] = {ambiantLight, ambiantLight, ambiantLight, 1.0f};
viewer.setGLLightAmbientCoefficients(lightAmbientCoeffs);
}
-
+
trace.info() << "Importing mesh... ";
-
- std::vector > vectMesh;
- for(unsigned int i = 0; i< inputFileNames.size(); i++)
+
+ std::vector> vectMesh;
+ for (unsigned int i = 0; i < inputFileNames.size(); i++)
{
Mesh aMesh(customColorMesh.size() != 4 && customColorMesh.size() != 8);
aMesh << inputFileNames[i];
- // for obj mesh by default the mesh color face are not necessary uniform.
- if (aMesh.isStoringFaceColors() && customColorMesh.size() >= 4 ){
- if ( i*8 < customColorMesh.size() ) {meshColorR = customColorMesh[i*8];}
- if ( i*8+1< customColorMesh.size() ) {meshColorG = customColorMesh[i*8+1];}
- if ( i*8+2 < customColorMesh.size() ) {meshColorB = customColorMesh[i*8+2];}
- if ( i*8+3 < customColorMesh.size() ) {meshColorA = customColorMesh[i*8+3];}
- for (unsigned int j = 0; j < aMesh.nbFaces(); j++){
- aMesh.setFaceColor(j, Color(meshColorR, meshColorG, meshColorB, meshColorA));
- }
- }else if (customAlphaMesh.size() > 0 ) {
- for (unsigned int j = 0; j < aMesh.nbFaces(); j++){
- auto c = aMesh.getFaceColor(j);
- aMesh.setFaceColor(j, Color(c.red(), c.green(), c.blue(), customAlphaMesh.at(i= 4)
+ {
+ if (i * 8 < customColorMesh.size())
+ {
+ meshColorR = customColorMesh[i * 8];
}
-
+ if (i * 8 + 1 < customColorMesh.size())
+ {
+ meshColorG = customColorMesh[i * 8 + 1];
+ }
+ if (i * 8 + 2 < customColorMesh.size())
+ {
+ meshColorB = customColorMesh[i * 8 + 2];
+ }
+ if (i * 8 + 3 < customColorMesh.size())
+ {
+ meshColorA = customColorMesh[i * 8 + 3];
+ }
+ for (unsigned int j = 0; j < aMesh.nbFaces(); j++)
+ {
+ aMesh.setFaceColor(j, Color(meshColorR, meshColorG, meshColorB, meshColorA));
+ }
+ }
+ else if (customAlphaMesh.size() > 0)
+ {
+ for (unsigned int j = 0; j < aMesh.nbFaces(); j++)
+ {
+ auto c = aMesh.getFaceColor(j);
+ aMesh.setFaceColor(j, Color(c.red(), c.green(), c.blue(), customAlphaMesh.at(i < customAlphaMesh.size() ? i : 0)));
+ }
+ }
+
vectMesh.push_back(aMesh);
}
DGtal::Z3i::RealPoint centerMeshes;
- unsigned int tot=0;
- for(const auto & m: vectMesh)
+ unsigned int tot = 0;
+ for (const auto &m : vectMesh)
{
- for( auto p = m.vertexBegin(); p!=m.vertexEnd(); ++p)
+ for (auto p = m.vertexBegin(); p != m.vertexEnd(); ++p)
centerMeshes += *p;
- tot+=m.nbVertex();
+ tot += m.nbVertex();
}
centerMeshes /= tot;
viewer.centerMesh = centerMeshes;
- bool import = vectMesh.size()==inputFileNames.size();
- if(!import)
+ bool import = vectMesh.size() == inputFileNames.size();
+ if (!import)
{
trace.info() << "File import failed. " << std::endl;
return 0;
}
-
- trace.info() << "[done]. "<< std::endl;
- if(filenameSDP != "")
+
+ trace.info() << "[done]. " << std::endl;
+ if (filenameSDP != "")
{
- vector vectPoints;
- vectPoints = PointListReader::getPointsFromFile(filenameSDP);
- viewer << CustomColors3D(Color(sdpColorR, sdpColorG, sdpColorB, sdpColorA),
- Color(sdpColorR, sdpColorG, sdpColorB, sdpColorA));
- for(unsigned int i=0;i< vectPoints.size(); i++){
- viewer.addBall(vectPoints.at(i), ballRadius);
+ if (customAlphaMesh.size() > 0)
+ {
+ trace.info() << "New meshViewer" << std::endl;
+ auto vOrigins = PointListReader>::getPolygonsFromFile(filenameSDP);
+ viewer << CustomColors3D(Color(sdpColorR, sdpColorG, sdpColorB, sdpColorA),
+ Color(sdpColorR, sdpColorG, sdpColorB, sdpColorA));
+ for (auto l : vOrigins)
+ {
+ DGtal::Z3i::Point pt(l[0][0], l[1][0], l[2][0]);
+ DGtal::Color cl(l[3][0], l[4][0], l[5][0], sdpColorA);
+ viewer.setFillColor(cl);
+ viewer.addBall(pt, ballRadius);
+ }
+ }
+ else
+ {
+ vector vectPoints;
+ vectPoints = PointListReader::getPointsFromFile(filenameSDP);
+ viewer << CustomColors3D(Color(sdpColorR, sdpColorG, sdpColorB, sdpColorA),
+ Color(sdpColorR, sdpColorG, sdpColorB, sdpColorA));
+ for (unsigned int i = 0; i < vectPoints.size(); i++)
+ {
+ viewer.addBall(vectPoints.at(i), ballRadius);
+ }
}
}
- if(invertNormal)
+ if (invertNormal)
{
- for(unsigned int i=0; i::VertexStorage::const_iterator it = vectMesh[i].vertexBegin();
- it!=vectMesh[i].vertexEnd(); ++it){
+
+ if (drawVertex)
+ {
+ for (unsigned int i = 0; i < vectMesh.size(); i++)
+ {
+ for (Mesh::VertexStorage::const_iterator it = vectMesh[i].vertexBegin();
+ it != vectMesh[i].vertexEnd(); ++it)
+ {
DGtal::Z3i::Point pt;
- pt[0]=(*it)[0]; pt[1]=(*it)[1]; pt[2]=(*it)[2];
+ pt[0] = (*it)[0];
+ pt[1] = (*it)[1];
+ pt[2] = (*it)[2];
viewer << pt;
}
}
}
-
+
if (displayVectorField != "")
{
- std::vector vectFieldIndices1 = {vectFieldIndices[0],vectFieldIndices[1], vectFieldIndices[2]};
- std::vector vectFieldIndices2 = {vectFieldIndices[3],vectFieldIndices[4], vectFieldIndices[5]};
+ std::vector vectFieldIndices1 = {vectFieldIndices[0], vectFieldIndices[1], vectFieldIndices[2]};
+ std::vector vectFieldIndices2 = {vectFieldIndices[3], vectFieldIndices[4], vectFieldIndices[5]};
std::vector vectPt1 = PointListReader::getPointsFromFile(displayVectorField, vectFieldIndices1);
std::vector vectPt2 = PointListReader::getPointsFromFile(displayVectorField, vectFieldIndices2);
viewer.createNewLineList();
@@ -382,44 +437,44 @@ int main( int argc, char** argv )
}
unsigned int nbVertex = 0;
unsigned int nbFaces = 0;
- for(auto const &m: vectMesh)
+ for (auto const &m : vectMesh)
{
nbVertex += m.nbVertex();
- nbFaces +=m.nbFaces();
+ nbFaces += m.nbFaces();
}
stringstream ss;
- ss << "# faces: " << std::fixed << nbFaces << " #vertex: " << nbVertex ;
+ ss << "# faces: " << std::fixed << nbFaces << " #vertex: " << nbVertex;
viewer.myInfoDisplay = ss.str();
- viewer << CustomViewer3D::updateDisplay;
+ viewer << CustomViewer3D::updateDisplay;
if (fixLightToScene)
{
- viewer.setLightModeFixToCamera(false, false);
+ viewer.setLightModeFixToCamera(false, false);
}
if (useLastCamSet)
{
- viewer.restoreStateFromFile();
+ viewer.restoreStateFromFile();
}
else
{
- // useful in non interactive case in order to retain the default camera settings (that are not saved in case of process kill).
- viewer.saveStateToFile();
+ // useful in non interactive case in order to retain the default camera settings (that are not saved in case of process kill).
+ viewer.saveStateToFile();
}
// First display transparency improve
viewer.sortTriangleFromCamera();
viewer.sortQuadFromCamera();
viewer.sortSurfelFromCamera();
viewer.sortPolygonFromCamera();
- viewer << CustomViewer3D::updateDisplay;
-
- if(snapshotFile != "" )
+ viewer << CustomViewer3D::updateDisplay;
+
+ if (snapshotFile != "")
{
// Recover mesh position
viewer.restoreStateFromFile();
viewer.saveSnapshot(QString(snapshotFile.c_str()), true);
return 0;
}
- trace.info() << "[display ready]"<< std::endl;
+ trace.info() << "[display ready]" << std::endl;
return application.exec();
}
diff --git a/visualisation/volscope.cpp b/visualisation/volscope.cpp
new file mode 100644
index 00000000..f98e7684
--- /dev/null
+++ b/visualisation/volscope.cpp
@@ -0,0 +1,198 @@
+/**
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ **/
+/**
+ * @file volscope.cpp
+ * @ingroup visualization
+ * @author David Coeurjolly (\c david.coeurjolly@cnrs.fr )
+ * Laboratoire d'InfoRmatique en Image et Systèmes d'information - LIRIS (CNRS, UMR 5205), CNRS,
+ * France
+ *
+ * @date 2023/12/22
+ *
+ * Vol visualization using polyscope.
+ *
+ * This file is part of the DGtal library.
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include "polyscope/surface_mesh.h"
+#include "polyscope/volume_mesh.h"
+#include "polyscope/point_cloud.h"
+
+#include "CLI11.hpp"
+
+// Using standard 3D digital space.
+using namespace DGtal;
+using namespace Z3i;
+typedef Shortcuts SH3;
+
+
+/**
+ @page volscope volscope
+
+ @brief Volumetric file visualization using polyscope
+
+ @b Usage: volscope [options] --input \
+
+
+ @b Allowed @b options @b are :
+ @code
+ Usage: ./volscope [OPTIONS] 1
+
+ Positionals:
+ 1 TEXT:FILE REQUIRED Input vol file.
+
+ Options:
+ -h,--help Print this help message and exit
+ -i,--input TEXT:FILE REQUIRED Input vol file.
+ --volumetricMode Activate the volumetric mode instead of the isosurface visualization.
+ --point-cloud-only In the volumetric mode, visualize the vol file as a point cloud instead of an hex mesh (default: false)
+-m, --min INT For isosurface visualization and voxel filtering, specifies the threshold min (excluded) (default: 0).
+ -M, --max INT For isosurface visualization and voxel filtering, specifies the threshold max (included) (default: 255).
+ @endcode
+
+
+ @image html volscope-surface.png "Default visualization mode." width=50%
+
+ @image html volscope-volumetric.png "Volumetric visualization using polyscope slice planes." width=50%
+
+
+
+
+**/
+
+int main(int argc, char**argv)
+{
+ // parse command line using CLI ----------------------------------------------
+ CLI::App app;
+ app.description("Vol file vizualization using polyscope");
+
+ std::string inputFileName;
+ app.add_option("-i,--input,1", inputFileName, "Input vol file.")->required()->check(CLI::ExistingFile);
+
+ bool volumetricMode = false;
+ app.add_flag("--volumetricMode",volumetricMode, "Activate the volumetric mode instead of the isosurface visualization.");
+
+ bool pclOnly = false;
+ app.add_flag("--point-cloud-only",pclOnly, "In the volumetric mode, visualize the vol file as a point cloud instead of an hex mesh (default: false)");
+
+ int thresholdMin=0;
+ app.add_option("--min,--thresholdMin,-m", thresholdMin, "For isosurface visualization and voxel filtering, specifies the threshold min (excluded) (default: 0).");
+ int thresholdMax=255;
+ app.add_option("--max, --thresholdMax,-M", thresholdMax, "For isosurface visualization and voxel filtering, specifies the threshold max (included) (default: 255).");
+
+
+ app.get_formatter()->column_width(40);
+ CLI11_PARSE(app, argc, argv);
+
+ polyscope::options::programName = "volscope " + inputFileName + " - (DGtalTools)";
+ polyscope::init();
+
+ if(!volumetricMode)
+ {
+ trace.beginBlock("Loading vol");
+ auto params = SH3::defaultParameters();
+ params("thresholdMin",thresholdMin)("thresholdMax",thresholdMax);
+ auto volimage = SH3::makeBinaryImage(inputFileName, params );
+ auto K = SH3::getKSpace( volimage );
+ auto surface = SH3::makeLightDigitalSurface( volimage, K, params );
+ auto primalSurface = SH3::makePrimalSurfaceMesh(surface);
+ trace.endBlock();
+
+ trace.beginBlock("Creating polyscope surface");
+ std::vector> faces;
+ for(auto face= 0 ; face < primalSurface->nbFaces(); ++face)
+ faces.push_back(primalSurface->incidentVertices( face ));
+ polyscope::registerSurfaceMesh("Vol file", primalSurface->positions(), faces);
+ trace.endBlock();
+ }
+ else
+ {
+ std::vector vertexPos;
+ std::vector pclPos;
+ std::vector pclData;
+ std::vector> hexIndices;
+ std::vector hexData;
+
+ trace.beginBlock("Loading vol");
+ auto volimage = SH3::makeGrayScaleImage(inputFileName);
+ trace.endBlock();
+ trace.beginBlock("Creating polyscope HexMesh/Point Cloud");
+ auto dom = volimage->domain();
+ auto W = dom.upperBound() - dom.lowerBound() + Point::diagonal(1);
+ auto WW = W + Point::diagonal(1); //for dual grid
+ trace.info()< hex;
+ for(auto k=0; k <= W[2]; ++k)
+ for(auto j=0; j <= W[1]; ++j)
+ for(auto i=0; i <= W[0]; ++i)
+ {
+ p=Point(i,j,k);
+ if ((ithresholdMin) && (val <=thresholdMax))
+ {
+ pclPos.push_back(p);
+ pclData.push_back(val);
+ }
+ }
+ else
+ {
+ vertexPos.push_back(p+dom.lowerBound() -RealPoint::diagonal(0.5) );
+ hex = { cpt, cpt +1 , cpt + 1 + WW[0] , cpt +WW[0] , cpt + WW[0]*WW[1], cpt +1 + WW[0]*WW[1], cpt + 1 + WW[0]*WW[1]+WW[0] , cpt + WW[0]*WW[1]+WW[0]};
+
+ if (((i+1)< WW[0]) && ((j+1)< WW[1]) && ((k+1)< WW[2])&& (val>thresholdMin) && (val <=thresholdMax))
+ {
+ hexData.push_back(val);
+ hexIndices.push_back(hex);
+ }
+ ++cpt;
+ }
+ }
+
+ if (pclOnly)
+ {
+ auto ps = polyscope::registerPointCloud("Vol file", pclPos);
+ ps->addScalarQuantity("values", pclData);
+ trace.info()<<"Nb vertices ="<addCellScalarQuantity("values", hexData);
+ trace.info()<<"Nb points ="< MyImageC;
+
// parse command line using CLI ----------------------------------------------
CLI::App app;
std::string inputFileName;
std::string outputFileName {"result.vol"};
+ MyImageC::Value fillValue = 128;
app.description("Fill the interior of a voxel set by filling the exterior using the 6-adjacency.\nThe exterior is the set of voxels with value zero and the interior voxels have value 128\n Basic usage:\n\tvolFillInterior ");
@@ -98,14 +105,15 @@ int main(int argc, char**argv)
->required()
->check(CLI::ExistingFile);
app.add_option("-o,--output,2",outputFileName, "Output filename.", true);
-
+ app.add_option("-v,--fillValue,3", fillValue, "Set the filling value other than the default value of 128.", false);
+
app.get_formatter()->column_width(40);
CLI11_PARSE(app, argc, argv);
// END parse command line using CLI ----------------------------------------------
trace.beginBlock("Loading");
- typedef ImageContainerBySTLVector MyImageC;
+
MyImageC image = VolReader< MyImageC >::importVol ( inputFileName );
trace.info() << image << std::endl;
trace.endBlock();
@@ -142,7 +150,7 @@ int main(int argc, char**argv)
trace.beginBlock("Complement");
for(auto &p : image.domain())
if ((image(p) == 0) && (!imageFlag(p)))
- image.setValue(p,128);
+ image.setValue(p, fillValue);
trace.endBlock();
trace.beginBlock("Saving");