diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 3f786675..a78a36de 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -17,7 +17,7 @@ jobs: matrix: config: [ { - os: macos-14, + os: macos-15, arch: arm64, cmakeBuildType: Release, }, diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0ebc1e14..29d05f07 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -100,7 +100,7 @@ jobs: if: matrix.config.checkCodeFormat run: | set +x -euo pipefail - python -m pip install clang-format==19.1.0 + python -m pip install clang-format==20.1.5 ./scripts/format/c++.sh git diff --name-only git diff --exit-code || (echo "Code formatting failed" && exit 1) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2cfde898..3acfd2c6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -17,14 +17,7 @@ jobs: matrix: config: [ { - os: windows-2022, - cmakeBuildType: Release, - cudaEnabled: true, - testsEnabled: true, - exportPackage: true, - }, - { - os: windows-2022, + os: windows-2025, cmakeBuildType: Release, cudaEnabled: false, testsEnabled: true, @@ -37,13 +30,13 @@ jobs: COMPILER_CACHE_DIR: ${{ github.workspace }}/compiler-cache CCACHE_DIR: ${{ github.workspace }}/compiler-cache/ccache CCACHE_BASEDIR: ${{ github.workspace }} - VCPKG_COMMIT_ID: bc3512a509f9d29b37346a7e7e929f9a26e66c7e + VCPKG_COMMIT_ID: 2ad7bd06128280e02bfe02361d8ffd7d465cfcf0 GLOG_v: 1 GLOG_logtostderr: 1 steps: - uses: actions/checkout@v4 - + # We define the vcpkg binary sources using separate variables for read and # write operations: # * Read sources are defined as inline. These can be read by anyone and, @@ -74,7 +67,7 @@ jobs: key: v${{ env.COMPILER_CACHE_VERSION }}-${{ matrix.config.os }}-${{ matrix.config.cmakeBuildType }}-${{ matrix.config.asanEnabled }}--${{ matrix.config.cudaEnabled }}-${{ github.run_id }}-${{ github.run_number }} restore-keys: v${{ env.COMPILER_CACHE_VERSION }}-${{ matrix.config.os }}-${{ matrix.config.cmakeBuildType }}-${{ matrix.config.asanEnabled }}--${{ matrix.config.cudaEnabled }} path: ${{ env.COMPILER_CACHE_DIR }} - + - name: Install ccache shell: pwsh run: | diff --git a/.gitignore b/.gitignore index 5066fb1b..9220f287 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /data /.vscode /compile_commands.json +.cache diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c0f9ab3..87c0992e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,17 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_NO_CYCLES ON) +# Determine project compiler. +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(IS_MSVC TRUE) +endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(IS_GNU TRUE) +endif() +if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(IS_CLANG TRUE) +endif() + include(cmake/FindDependencies.cmake) if (TESTS_ENABLED) @@ -45,8 +56,7 @@ else() message(STATUS "Disabling ccache support") endif() - -if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +if(IS_MSVC) # Some fixes for the Glog library. add_definitions("-DGLOG_USE_GLOG_EXPORT") add_definitions("-DGLOG_NO_ABBREVIATED_SEVERITIES") @@ -62,4 +72,5 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") endif() endif() +add_subdirectory(thirdparty) add_subdirectory(glomap) diff --git a/cmake/FindDependencies.cmake b/cmake/FindDependencies.cmake index c1d0110e..a656c221 100644 --- a/cmake/FindDependencies.cmake +++ b/cmake/FindDependencies.cmake @@ -1,10 +1,6 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -find_package(Eigen3 3.4 REQUIRED) -find_package(CHOLMOD QUIET) -if(NOT TARGET SuiteSparse::CHOLMOD) - find_package(SuiteSparse COMPONENTS CHOLMOD REQUIRED) -endif() +find_package(Eigen3 REQUIRED) find_package(Ceres REQUIRED COMPONENTS SuiteSparse) find_package(Boost REQUIRED) find_package(OpenMP REQUIRED COMPONENTS C CXX) @@ -24,36 +20,6 @@ if(TESTS_ENABLED) find_package(GTest REQUIRED) endif() -include(FetchContent) -FetchContent_Declare(PoseLib - GIT_REPOSITORY https://github.com/PoseLib/PoseLib.git - GIT_TAG 7e9f5f53372e43f89655040d4dfc4a00e5ace11c # 2.0.5 - EXCLUDE_FROM_ALL - SYSTEM -) -message(STATUS "Configuring PoseLib...") -if (FETCH_POSELIB) - FetchContent_MakeAvailable(PoseLib) -else() - find_package(PoseLib REQUIRED) -endif() -message(STATUS "Configuring PoseLib... done") - -FetchContent_Declare(COLMAP - GIT_REPOSITORY https://github.com/colmap/colmap.git - GIT_TAG c5f9cefc87e5dd596b638e4cee0ff543c7d14755 # Oct 23 2025 - EXCLUDE_FROM_ALL -) -message(STATUS "Configuring COLMAP...") -set(UNINSTALL_ENABLED OFF CACHE INTERNAL "") -set(GUI_ENABLED OFF CACHE INTERNAL "") -if (FETCH_COLMAP) - FetchContent_MakeAvailable(COLMAP) -else() - find_package(COLMAP REQUIRED) -endif() -message(STATUS "Configuring COLMAP... done") - set(CUDA_MIN_VERSION "7.0") if(CUDA_ENABLED) if(CMAKE_VERSION VERSION_LESS 3.17) diff --git a/cmake/FindSuiteSparse.cmake b/cmake/FindSuiteSparse.cmake deleted file mode 100644 index bccd89fe..00000000 --- a/cmake/FindSuiteSparse.cmake +++ /dev/null @@ -1,537 +0,0 @@ -# Ceres Solver - A fast non-linear least squares minimizer -# Copyright 2023 Google Inc. All rights reserved. -# http://ceres-solver.org/ -# -# 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 Google Inc. nor the names of its contributors may be -# used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# Author: alexs.mac@gmail.com (Alex Stewart) -# - -#[=======================================================================[.rst: -FindSuiteSparse -=============== - -Module for locating SuiteSparse libraries and its dependencies. - -This module defines the following variables: - -``SuiteSparse_FOUND`` - ``TRUE`` iff SuiteSparse and all dependencies have been found. - -``SuiteSparse_VERSION`` - Extracted from ``SuiteSparse_config.h`` (>= v4). - -``SuiteSparse_VERSION_MAJOR`` - Equal to 4 if ``SuiteSparse_VERSION`` = 4.2.1 - -``SuiteSparse_VERSION_MINOR`` - Equal to 2 if ``SuiteSparse_VERSION`` = 4.2.1 - -``SuiteSparse_VERSION_PATCH`` - Equal to 1 if ``SuiteSparse_VERSION`` = 4.2.1 - -The following variables control the behaviour of this module: - -``SuiteSparse_NO_CMAKE`` - Do not attempt to use the native SuiteSparse CMake package configuration. - - -Targets -------- - -The following targets define the SuiteSparse components searched for. - -``SuiteSparse::AMD`` - Symmetric Approximate Minimum Degree (AMD) - -``SuiteSparse::CAMD`` - Constrained Approximate Minimum Degree (CAMD) - -``SuiteSparse::COLAMD`` - Column Approximate Minimum Degree (COLAMD) - -``SuiteSparse::CCOLAMD`` - Constrained Column Approximate Minimum Degree (CCOLAMD) - -``SuiteSparse::CHOLMOD`` - Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD) - -``SuiteSparse::Partition`` - CHOLMOD with METIS support - -``SuiteSparse::SPQR`` - Multifrontal Sparse QR (SuiteSparseQR) - -``SuiteSparse::Config`` - Common configuration for all but CSparse (SuiteSparse version >= 4). - -Optional SuiteSparse dependencies: - -``METIS::METIS`` - Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS) -]=======================================================================] - -if (NOT SuiteSparse_NO_CMAKE) - find_package (SuiteSparse NO_MODULE QUIET) -endif (NOT SuiteSparse_NO_CMAKE) - -if (SuiteSparse_FOUND) - return () -endif (SuiteSparse_FOUND) - -# Push CMP0057 to enable support for IN_LIST, when cmake_minimum_required is -# set to <3.3. -cmake_policy (PUSH) -cmake_policy (SET CMP0057 NEW) - -if (NOT SuiteSparse_FIND_COMPONENTS) - set (SuiteSparse_FIND_COMPONENTS - AMD - CAMD - CCOLAMD - CHOLMOD - COLAMD - SPQR - ) - - foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS) - set (SuiteSparse_FIND_REQUIRED_${component} TRUE) - endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS) -endif (NOT SuiteSparse_FIND_COMPONENTS) - -# Assume SuiteSparse was found and set it to false only if third-party -# dependencies could not be located. SuiteSparse components are handled by -# FindPackageHandleStandardArgs HANDLE_COMPONENTS option. -set (SuiteSparse_FOUND TRUE) - -include (CheckLibraryExists) -include (CheckSymbolExists) -include (CMakePushCheckState) - -# Config is a base component and thus always required -set (SuiteSparse_IMPLICIT_COMPONENTS Config) - -# CHOLMOD depends on AMD, CAMD, CCOLAMD, and COLAMD. -if (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS) - list (APPEND SuiteSparse_IMPLICIT_COMPONENTS AMD CAMD CCOLAMD COLAMD) -endif (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS) - -# SPQR depends on CHOLMOD. -if (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS) - list (APPEND SuiteSparse_IMPLICIT_COMPONENTS CHOLMOD) -endif (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS) - -# Implicit components are always required -foreach (component IN LISTS SuiteSparse_IMPLICIT_COMPONENTS) - set (SuiteSparse_FIND_REQUIRED_${component} TRUE) -endforeach (component IN LISTS SuiteSparse_IMPLICIT_COMPONENTS) - -list (APPEND SuiteSparse_FIND_COMPONENTS ${SuiteSparse_IMPLICIT_COMPONENTS}) - -# Do not list components multiple times. -list (REMOVE_DUPLICATES SuiteSparse_FIND_COMPONENTS) - -# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when -# FindSuiteSparse was invoked. -macro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX) - if (MSVC) - set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}") - endif (MSVC) -endmacro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX) - -# Called if we failed to find SuiteSparse or any of it's required dependencies, -# unsets all public (designed to be used externally) variables and reports -# error message at priority depending upon [REQUIRED/QUIET/] argument. -macro(SuiteSparse_REPORT_NOT_FOUND REASON_MSG) - # Will be set to FALSE by find_package_handle_standard_args - unset (SuiteSparse_FOUND) - - # Do NOT unset SuiteSparse_REQUIRED_VARS here, as it is used by - # FindPackageHandleStandardArgs() to generate the automatic error message on - # failure which highlights which components are missing. - - suitesparse_reset_find_library_prefix() - - # Note _FIND_[REQUIRED/QUIETLY] variables defined by FindPackage() - # use the camelcase library name, not uppercase. - if (SuiteSparse_FIND_QUIETLY) - message(STATUS "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN}) - elseif (SuiteSparse_FIND_REQUIRED) - message(FATAL_ERROR "Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN}) - else() - # Neither QUIETLY nor REQUIRED, use no priority which emits a message - # but continues configuration and allows generation. - message("-- Failed to find SuiteSparse - " ${REASON_MSG} ${ARGN}) - endif (SuiteSparse_FIND_QUIETLY) - - # Do not call return(), s/t we keep processing if not called with REQUIRED - # and report all missing components, rather than bailing after failing to find - # the first. -endmacro(SuiteSparse_REPORT_NOT_FOUND) - -# Handle possible presence of lib prefix for libraries on MSVC, see -# also SuiteSparse_RESET_FIND_LIBRARY_PREFIX(). -if (MSVC) - # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES - # s/t we can set it back before returning. - set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}") - # The empty string in this list is important, it represents the case when - # the libraries have no prefix (shared libraries / DLLs). - set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}") -endif (MSVC) - -# Additional suffixes to try appending to each search path. -list(APPEND SuiteSparse_CHECK_PATH_SUFFIXES - suitesparse) # Windows/Ubuntu - -# Wrappers to find_path/library that pass the SuiteSparse search hints/paths. -# -# suitesparse_find_component( [FILES name1 [name2 ...]] -# [LIBRARIES name1 [name2 ...]]) -macro(suitesparse_find_component COMPONENT) - include(CMakeParseArguments) - set(MULTI_VALUE_ARGS FILES LIBRARIES) - cmake_parse_arguments(SuiteSparse_FIND_COMPONENT_${COMPONENT} - "" "" "${MULTI_VALUE_ARGS}" ${ARGN}) - - set(SuiteSparse_${COMPONENT}_FOUND TRUE) - if (SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES) - find_path(SuiteSparse_${COMPONENT}_INCLUDE_DIR - NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES} - PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES}) - if (SuiteSparse_${COMPONENT}_INCLUDE_DIR) - message(STATUS "Found ${COMPONENT} headers in: " - "${SuiteSparse_${COMPONENT}_INCLUDE_DIR}") - mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR) - else() - # Specified headers not found. - set(SuiteSparse_${COMPONENT}_FOUND FALSE) - if (SuiteSparse_FIND_REQUIRED_${COMPONENT}) - suitesparse_report_not_found( - "Did not find ${COMPONENT} header (required SuiteSparse component).") - else() - message(STATUS "Did not find ${COMPONENT} header (optional " - "SuiteSparse component).") - # Hide optional vars from CMake GUI even if not found. - mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR) - endif() - endif() - endif() - - if (SuiteSparse_FIND_COMPONENT_${COMPONENT}_LIBRARIES) - find_library(SuiteSparse_${COMPONENT}_LIBRARY - NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_LIBRARIES} - PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES}) - if (SuiteSparse_${COMPONENT}_LIBRARY) - message(STATUS "Found ${COMPONENT} library: ${SuiteSparse_${COMPONENT}_LIBRARY}") - mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY) - else () - # Specified libraries not found. - set(SuiteSparse_${COMPONENT}_FOUND FALSE) - if (SuiteSparse_FIND_REQUIRED_${COMPONENT}) - suitesparse_report_not_found( - "Did not find ${COMPONENT} library (required SuiteSparse component).") - else() - message(STATUS "Did not find ${COMPONENT} library (optional SuiteSparse " - "dependency)") - # Hide optional vars from CMake GUI even if not found. - mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY) - endif() - endif() - endif() - - # A component can be optional (given to OPTIONAL_COMPONENTS). However, if the - # component is implicit (must be always present, such as the Config component) - # assume it be required as well. - if (SuiteSparse_FIND_REQUIRED_${COMPONENT}) - list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_${COMPONENT}_INCLUDE_DIR) - list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_${COMPONENT}_LIBRARY) - endif (SuiteSparse_FIND_REQUIRED_${COMPONENT}) - - # Define the target only if the include directory and the library were found - if (SuiteSparse_${COMPONENT}_INCLUDE_DIR AND SuiteSparse_${COMPONENT}_LIBRARY) - if (NOT TARGET SuiteSparse::${COMPONENT}) - add_library(SuiteSparse::${COMPONENT} IMPORTED UNKNOWN) - endif (NOT TARGET SuiteSparse::${COMPONENT}) - - set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY - INTERFACE_INCLUDE_DIRECTORIES ${SuiteSparse_${COMPONENT}_INCLUDE_DIR}) - set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY - IMPORTED_LOCATION ${SuiteSparse_${COMPONENT}_LIBRARY}) - endif (SuiteSparse_${COMPONENT}_INCLUDE_DIR AND SuiteSparse_${COMPONENT}_LIBRARY) -endmacro() - -# Given the number of components of SuiteSparse, and to ensure that the -# automatic failure message generated by FindPackageHandleStandardArgs() -# when not all required components are found is helpful, we maintain a list -# of all variables that must be defined for SuiteSparse to be considered found. -unset(SuiteSparse_REQUIRED_VARS) - -# BLAS. -find_package(BLAS QUIET) -if (NOT BLAS_FOUND) - suitesparse_report_not_found( - "Did not find BLAS library (required for SuiteSparse).") -endif (NOT BLAS_FOUND) - -# LAPACK. -find_package(LAPACK QUIET) -if (NOT LAPACK_FOUND) - suitesparse_report_not_found( - "Did not find LAPACK library (required for SuiteSparse).") -endif (NOT LAPACK_FOUND) - -foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS) - if (component STREQUAL Partition) - # Partition is a meta component that neither provides additional headers nor - # a separate library. It is strictly part of CHOLMOD. - continue () - endif (component STREQUAL Partition) - string (TOLOWER ${component} component_library) - - if (component STREQUAL "Config") - set (component_header SuiteSparse_config.h) - set (component_library suitesparseconfig) - elseif (component STREQUAL "SPQR") - set (component_header SuiteSparseQR.hpp) - else (component STREQUAL "SPQR") - set (component_header ${component_library}.h) - endif (component STREQUAL "Config") - - suitesparse_find_component(${component} - FILES ${component_header} - LIBRARIES ${component_library}) -endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS) - -if (TARGET SuiteSparse::SPQR) - # SuiteSparseQR may be compiled with Intel Threading Building Blocks, - # we assume that if TBB is installed, SuiteSparseQR was compiled with - # support for it, this will do no harm if it wasn't. - find_package(TBB QUIET) - if (TBB_FOUND) - message(STATUS "Found Intel Thread Building Blocks (TBB) library " - "(${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR} / ${TBB_INTERFACE_VERSION}) " - "include location: ${TBB_INCLUDE_DIRS}. Assuming SuiteSparseQR was " - "compiled with TBB.") - # Add the TBB libraries to the SuiteSparseQR libraries (the only - # libraries to optionally depend on TBB). - if (TARGET TBB::tbb) - # Native TBB package configuration provides an imported target. Use it if - # available. - set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY - INTERFACE_LINK_LIBRARIES TBB::tbb) - else (TARGET TBB::tbb) - set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY - INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS}) - set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY - INTERFACE_LINK_LIBRARIES ${TBB_LIBRARIES}) - endif (TARGET TBB::tbb) - else (TBB_FOUND) - message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was " - "not compiled with TBB.") - endif (TBB_FOUND) -endif (TARGET SuiteSparse::SPQR) - -check_library_exists(rt shm_open "" HAVE_LIBRT) - -if (TARGET SuiteSparse::Config) - # SuiteSparse_config (SuiteSparse version >= 4) requires librt library for - # timing by default when compiled on Linux or Unix, but not on OSX (which - # does not have librt). - if (HAVE_LIBRT) - message(STATUS "Adding librt to " - "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if " - "SuiteSparse is compiled with timing).") - set_property (TARGET SuiteSparse::Config APPEND PROPERTY - INTERFACE_LINK_LIBRARIES $) - else (HAVE_LIBRT) - message(STATUS "Could not find librt, but found SuiteSparse_config, " - "assuming that SuiteSparse was compiled without timing.") - endif (HAVE_LIBRT) - - # Add BLAS and LAPACK as dependencies of SuiteSparse::Config for convenience - # given that all components depend on it. - if (BLAS_FOUND) - if (TARGET BLAS::BLAS) - set_property (TARGET SuiteSparse::Config APPEND PROPERTY - INTERFACE_LINK_LIBRARIES $) - else (TARGET BLAS::BLAS) - set_property (TARGET SuiteSparse::Config APPEND PROPERTY - INTERFACE_LINK_LIBRARIES ${BLAS_LIBRARIES}) - endif (TARGET BLAS::BLAS) - endif (BLAS_FOUND) - - if (LAPACK_FOUND) - if (TARGET LAPACK::LAPACK) - set_property (TARGET SuiteSparse::Config APPEND PROPERTY - INTERFACE_LINK_LIBRARIES $) - else (TARGET LAPACK::LAPACK) - set_property (TARGET SuiteSparse::Config APPEND PROPERTY - INTERFACE_LINK_LIBRARIES ${LAPACK_LIBRARIES}) - endif (TARGET LAPACK::LAPACK) - endif (LAPACK_FOUND) - - # SuiteSparse version >= 4. - set(SuiteSparse_VERSION_FILE - ${SuiteSparse_Config_INCLUDE_DIR}/SuiteSparse_config.h) - if (NOT EXISTS ${SuiteSparse_VERSION_FILE}) - suitesparse_report_not_found( - "Could not find file: ${SuiteSparse_VERSION_FILE} containing version " - "information for >= v4 SuiteSparse installs, but SuiteSparse_config was " - "found (only present in >= v4 installs).") - else (NOT EXISTS ${SuiteSparse_VERSION_FILE}) - file(READ ${SuiteSparse_VERSION_FILE} Config_CONTENTS) - - string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION[ \t]+([0-9]+)" - SuiteSparse_VERSION_LINE "${Config_CONTENTS}") - set (SuiteSparse_VERSION_MAJOR ${CMAKE_MATCH_1}) - - string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION[ \t]+([0-9]+)" - SuiteSparse_VERSION_LINE "${Config_CONTENTS}") - set (SuiteSparse_VERSION_MINOR ${CMAKE_MATCH_1}) - - string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION[ \t]+([0-9]+)" - SuiteSparse_VERSION_LINE "${Config_CONTENTS}") - set (SuiteSparse_VERSION_PATCH ${CMAKE_MATCH_1}) - - unset (SuiteSparse_VERSION_LINE) - - # This is on a single line s/t CMake does not interpret it as a list of - # elements and insert ';' separators which would result in 4.;2.;1 nonsense. - set(SuiteSparse_VERSION - "${SuiteSparse_VERSION_MAJOR}.${SuiteSparse_VERSION_MINOR}.${SuiteSparse_VERSION_PATCH}") - - if (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - set(SuiteSparse_VERSION_COMPONENTS 3) - else (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - message (WARNING "Could not parse SuiteSparse_config.h: SuiteSparse " - "version will not be available") - - unset (SuiteSparse_VERSION) - unset (SuiteSparse_VERSION_MAJOR) - unset (SuiteSparse_VERSION_MINOR) - unset (SuiteSparse_VERSION_PATCH) - endif (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - endif (NOT EXISTS ${SuiteSparse_VERSION_FILE}) -endif (TARGET SuiteSparse::Config) - -# CHOLMOD requires AMD CAMD CCOLAMD COLAMD -if (TARGET SuiteSparse::CHOLMOD) - foreach (component IN ITEMS AMD CAMD CCOLAMD COLAMD) - if (TARGET SuiteSparse::${component}) - set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY - INTERFACE_LINK_LIBRARIES SuiteSparse::${component}) - else (TARGET SuiteSparse::${component}) - # Consider CHOLMOD not found if COLAMD cannot be found - set (SuiteSparse_CHOLMOD_FOUND FALSE) - endif (TARGET SuiteSparse::${component}) - endforeach (component IN ITEMS AMD CAMD CCOLAMD COLAMD) -endif (TARGET SuiteSparse::CHOLMOD) - -# SPQR requires CHOLMOD -if (TARGET SuiteSparse::SPQR) - if (TARGET SuiteSparse::CHOLMOD) - set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY - INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD) - else (TARGET SuiteSparse::CHOLMOD) - # Consider SPQR not found if CHOLMOD cannot be found - set (SuiteSparse_SQPR_FOUND FALSE) - endif (TARGET SuiteSparse::CHOLMOD) -endif (TARGET SuiteSparse::SPQR) - -# Add SuiteSparse::Config as dependency to all components -if (TARGET SuiteSparse::Config) - foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS) - if (component STREQUAL Config) - continue () - endif (component STREQUAL Config) - - if (TARGET SuiteSparse::${component}) - set_property (TARGET SuiteSparse::${component} APPEND PROPERTY - INTERFACE_LINK_LIBRARIES SuiteSparse::Config) - endif (TARGET SuiteSparse::${component}) - endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS) -endif (TARGET SuiteSparse::Config) - -# Check whether CHOLMOD was compiled with METIS support. The check can be -# performed only after the main components have been set up. -if (TARGET SuiteSparse::CHOLMOD) - # NOTE If SuiteSparse was compiled as a static library we'll need to link - # against METIS already during the check. Otherwise, the check can fail due to - # undefined references even though SuiteSparse was compiled with METIS. - find_package (METIS) - - if (TARGET METIS::METIS) - cmake_push_check_state (RESET) - set (CMAKE_REQUIRED_LIBRARIES SuiteSparse::CHOLMOD METIS::METIS) - check_symbol_exists (cholmod_metis cholmod.h SuiteSparse_CHOLMOD_USES_METIS) - cmake_pop_check_state () - - if (SuiteSparse_CHOLMOD_USES_METIS) - set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY - INTERFACE_LINK_LIBRARIES $) - - # Provide the SuiteSparse::Partition component whose availability indicates - # that CHOLMOD was compiled with the Partition module. - if (NOT TARGET SuiteSparse::Partition) - add_library (SuiteSparse::Partition IMPORTED INTERFACE) - endif (NOT TARGET SuiteSparse::Partition) - - set_property (TARGET SuiteSparse::Partition APPEND PROPERTY - INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD) - endif (SuiteSparse_CHOLMOD_USES_METIS) - endif (TARGET METIS::METIS) -endif (TARGET SuiteSparse::CHOLMOD) - -# We do not use suitesparse_find_component to find Partition and therefore must -# handle the availability in an extra step. -if (TARGET SuiteSparse::Partition) - set (SuiteSparse_Partition_FOUND TRUE) -else (TARGET SuiteSparse::Partition) - set (SuiteSparse_Partition_FOUND FALSE) -endif (TARGET SuiteSparse::Partition) - -suitesparse_reset_find_library_prefix() - -# Handle REQUIRED and QUIET arguments to FIND_PACKAGE -include(FindPackageHandleStandardArgs) -if (SuiteSparse_FOUND) - find_package_handle_standard_args(SuiteSparse - REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS} - VERSION_VAR SuiteSparse_VERSION - FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse." - HANDLE_COMPONENTS) -else (SuiteSparse_FOUND) - # Do not pass VERSION_VAR to FindPackageHandleStandardArgs() if we failed to - # find SuiteSparse to avoid a confusing autogenerated failure message - # that states 'not found (missing: FOO) (found version: x.y.z)'. - find_package_handle_standard_args(SuiteSparse - REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS} - FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse." - HANDLE_COMPONENTS) -endif (SuiteSparse_FOUND) - -# Pop CMP0057. -cmake_policy (POP) diff --git a/glomap/CMakeLists.txt b/glomap/CMakeLists.txt index 145adc4d..69b7c761 100644 --- a/glomap/CMakeLists.txt +++ b/glomap/CMakeLists.txt @@ -47,11 +47,9 @@ set(HEADERS io/colmap_io.h io/pose_io.h math/gravity.h - math/l1_solver.h math/rigid3d.h math/tree.h math/two_view_geometry.h - math/union_find.h processors/image_pair_inliers.h processors/image_undistorter.h processors/reconstruction_normalizer.h @@ -86,7 +84,6 @@ target_link_libraries( PUBLIC Eigen3::Eigen Ceres::ceres - SuiteSparse::CHOLMOD OpenMP::OpenMP_CXX ${BOOST_LIBRARIES} ) @@ -97,7 +94,6 @@ if(MSVC) else() target_compile_options(glomap PRIVATE -Wall - -Werror -Wno-sign-compare -Wno-unused-variable ) diff --git a/glomap/controllers/global_mapper_test.cc b/glomap/controllers/global_mapper_test.cc index dee5cada..98b8fc2b 100644 --- a/glomap/controllers/global_mapper_test.cc +++ b/glomap/controllers/global_mapper_test.cc @@ -60,7 +60,6 @@ TEST(GlobalMapper, WithoutNoise) { synthetic_dataset_options.num_cameras_per_rig = 1; synthetic_dataset_options.num_frames_per_rig = 7; synthetic_dataset_options.num_points3D = 50; - synthetic_dataset_options.point2D_stddev = 0; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); @@ -97,7 +96,6 @@ TEST(GlobalMapper, WithoutNoiseWithNonTrivialKnownRig) { synthetic_dataset_options.num_cameras_per_rig = 2; synthetic_dataset_options.num_frames_per_rig = 7; synthetic_dataset_options.num_points3D = 50; - synthetic_dataset_options.point2D_stddev = 0; synthetic_dataset_options.sensor_from_rig_translation_stddev = 0.1; // No noise synthetic_dataset_options.sensor_from_rig_rotation_stddev = 5.; // No noise @@ -137,7 +135,6 @@ TEST(GlobalMapper, WithoutNoiseWithNonTrivialUnknownRig) { synthetic_dataset_options.num_cameras_per_rig = 3; synthetic_dataset_options.num_frames_per_rig = 7; synthetic_dataset_options.num_points3D = 50; - synthetic_dataset_options.point2D_stddev = 0; synthetic_dataset_options.sensor_from_rig_translation_stddev = 0.1; // No noise synthetic_dataset_options.sensor_from_rig_rotation_stddev = 5.; // No noise @@ -187,10 +184,13 @@ TEST(GlobalMapper, WithNoiseAndOutliers) { synthetic_dataset_options.num_cameras_per_rig = 1; synthetic_dataset_options.num_frames_per_rig = 4; synthetic_dataset_options.num_points3D = 100; - synthetic_dataset_options.point2D_stddev = 0.5; synthetic_dataset_options.inlier_match_ratio = 0.6; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); + colmap::SyntheticNoiseOptions synthetic_noise_options; + synthetic_noise_options.point2D_stddev = 0.5; + colmap::SynthesizeNoise( + synthetic_noise_options, >_reconstruction, database.get()); ViewGraph view_graph; std::unordered_map cameras; diff --git a/glomap/controllers/rotation_averager_test.cc b/glomap/controllers/rotation_averager_test.cc index 095ff437..1dac8abd 100644 --- a/glomap/controllers/rotation_averager_test.cc +++ b/glomap/controllers/rotation_averager_test.cc @@ -135,7 +135,6 @@ TEST(RotationEstimator, WithoutNoise) { synthetic_dataset_options.num_cameras_per_rig = 1; synthetic_dataset_options.num_frames_per_rig = 5; synthetic_dataset_options.num_points3D = 50; - synthetic_dataset_options.point2D_stddev = 0; synthetic_dataset_options.sensor_from_rig_rotation_stddev = 20.; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); @@ -181,7 +180,6 @@ TEST(RotationEstimator, WithoutNoiseWithNoneTrivialKnownRig) { synthetic_dataset_options.num_cameras_per_rig = 2; synthetic_dataset_options.num_frames_per_rig = 4; synthetic_dataset_options.num_points3D = 50; - synthetic_dataset_options.point2D_stddev = 0; synthetic_dataset_options.sensor_from_rig_rotation_stddev = 20.; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); @@ -225,7 +223,6 @@ TEST(RotationEstimator, WithoutNoiseWithNoneTrivialUnknownRig) { synthetic_dataset_options.num_cameras_per_rig = 2; synthetic_dataset_options.num_frames_per_rig = 4; synthetic_dataset_options.num_points3D = 50; - synthetic_dataset_options.point2D_stddev = 0; synthetic_dataset_options.sensor_from_rig_rotation_stddev = 20.; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); @@ -277,10 +274,13 @@ TEST(RotationEstimator, WithNoiseAndOutliers) { synthetic_dataset_options.num_cameras_per_rig = 1; synthetic_dataset_options.num_frames_per_rig = 7; synthetic_dataset_options.num_points3D = 100; - synthetic_dataset_options.point2D_stddev = 1; synthetic_dataset_options.inlier_match_ratio = 0.6; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); + colmap::SyntheticNoiseOptions synthetic_noise_options; + synthetic_noise_options.point2D_stddev = 1; + colmap::SynthesizeNoise( + synthetic_noise_options, >_reconstruction, database.get()); ViewGraph view_graph; std::unordered_map rigs; @@ -323,10 +323,13 @@ TEST(RotationEstimator, WithNoiseAndOutliersWithNonTrivialKnownRigs) { synthetic_dataset_options.num_cameras_per_rig = 2; synthetic_dataset_options.num_frames_per_rig = 7; synthetic_dataset_options.num_points3D = 100; - synthetic_dataset_options.point2D_stddev = 1; synthetic_dataset_options.inlier_match_ratio = 0.6; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); + colmap::SyntheticNoiseOptions synthetic_noise_options; + synthetic_noise_options.point2D_stddev = 1; + colmap::SynthesizeNoise( + synthetic_noise_options, >_reconstruction, database.get()); ViewGraph view_graph; std::unordered_map rigs; @@ -372,7 +375,6 @@ TEST(RotationEstimator, RefineGravity) { synthetic_dataset_options.num_cameras_per_rig = 1; synthetic_dataset_options.num_frames_per_rig = 25; synthetic_dataset_options.num_points3D = 100; - synthetic_dataset_options.point2D_stddev = 0; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); @@ -416,7 +418,6 @@ TEST(RotationEstimator, RefineGravityWithNontrivialRigs) { synthetic_dataset_options.num_cameras_per_rig = 2; synthetic_dataset_options.num_frames_per_rig = 25; synthetic_dataset_options.num_points3D = 100; - synthetic_dataset_options.point2D_stddev = 0; colmap::SynthesizeDataset( synthetic_dataset_options, >_reconstruction, database.get()); diff --git a/glomap/controllers/track_establishment.cc b/glomap/controllers/track_establishment.cc index d4396ed3..77c307ec 100644 --- a/glomap/controllers/track_establishment.cc +++ b/glomap/controllers/track_establishment.cc @@ -5,7 +5,7 @@ namespace glomap { size_t TrackEngine::EstablishFullTracks( std::unordered_map& tracks) { tracks.clear(); - uf_.Clear(); + uf_ = {}; // Blindly concatenate tracks if any matches occur BlindConcatenation(); diff --git a/glomap/controllers/track_establishment.h b/glomap/controllers/track_establishment.h index 7e0c3ef0..1eb6a58b 100644 --- a/glomap/controllers/track_establishment.h +++ b/glomap/controllers/track_establishment.h @@ -1,9 +1,10 @@ #pragma once -#include "glomap/math/union_find.h" #include "glomap/scene/types_sfm.h" +#include + namespace glomap { struct TrackEstablishmentOptions { @@ -53,7 +54,7 @@ class TrackEngine { const std::unordered_map& images_; // Internal structure used for concatenating tracks - UnionFind uf_; + colmap::UnionFind uf_; }; } // namespace glomap diff --git a/glomap/estimators/global_rotation_averaging.cc b/glomap/estimators/global_rotation_averaging.cc index c78ee1cc..75b46d04 100644 --- a/glomap/estimators/global_rotation_averaging.cc +++ b/glomap/estimators/global_rotation_averaging.cc @@ -1,14 +1,17 @@ #include "global_rotation_averaging.h" #include "glomap/estimators/rotation_initializer.h" -#include "glomap/math/l1_solver.h" #include "glomap/math/rigid3d.h" #include "glomap/math/tree.h" +#include +#include + #include #include -#include "colmap/geometry/pose.h" +#include +#include namespace glomap { namespace { @@ -477,11 +480,15 @@ bool RotationEstimator::SolveL1Regression( const ViewGraph& view_graph, std::unordered_map& frames, std::unordered_map& images) { - L1SolverOptions opt_l1_solver; - opt_l1_solver.max_num_iterations = 10; + colmap::LeastAbsoluteDeviationSolver::Options l1_solver_options; + l1_solver_options.max_num_iterations = 10; + l1_solver_options.solver_type = colmap::LeastAbsoluteDeviationSolver:: + Options::SolverType::SupernodalCholmodLLT; + + const Eigen::SparseMatrix A = + weights_.matrix().asDiagonal() * sparse_matrix_; - L1Solver> l1_solver( - opt_l1_solver, weights_.matrix().asDiagonal() * sparse_matrix_); + colmap::LeastAbsoluteDeviationSolver l1_solver(l1_solver_options, A); double last_norm = 0; double curr_norm = 0; @@ -526,8 +533,8 @@ bool RotationEstimator::SolveL1Regression( iteration++; break; } - opt_l1_solver.max_num_iterations = - std::min(opt_l1_solver.max_num_iterations * 2, 100); + l1_solver_options.max_num_iterations = + std::min(l1_solver_options.max_num_iterations * 2, 100); } VLOG(2) << "L1 ADMM total iteration: " << iteration; return true; diff --git a/glomap/estimators/global_rotation_averaging.h b/glomap/estimators/global_rotation_averaging.h index fa0bdab4..e3d5057c 100644 --- a/glomap/estimators/global_rotation_averaging.h +++ b/glomap/estimators/global_rotation_averaging.h @@ -1,12 +1,13 @@ #pragma once -#include "glomap/math/l1_solver.h" #include "glomap/scene/types_sfm.h" #include "glomap/types.h" #include #include +#include + // Code is adapted from Theia's RobustRotationEstimator // (http://www.theia-sfm.org/). For gravity aligned rotation averaging, refere // to the paper "Gravity Aligned Rotation Averaging" diff --git a/glomap/estimators/rotation_initializer.cc b/glomap/estimators/rotation_initializer.cc index 3d1ca90e..2fd6c5e1 100644 --- a/glomap/estimators/rotation_initializer.cc +++ b/glomap/estimators/rotation_initializer.cc @@ -1,6 +1,7 @@ #include "glomap/estimators/rotation_initializer.h" -#include "colmap/geometry/pose.h" +#include + namespace glomap { bool ConvertRotationsFromImageToRig( diff --git a/glomap/io/colmap_converter.cc b/glomap/io/colmap_converter.cc index 9fc1cc53..3fcb0959 100644 --- a/glomap/io/colmap_converter.cc +++ b/glomap/io/colmap_converter.cc @@ -2,7 +2,7 @@ #include "glomap/math/two_view_geometry.h" -#include "colmap/scene/reconstruction_io_utils.h" +#include namespace glomap { diff --git a/glomap/math/l1_solver.h b/glomap/math/l1_solver.h deleted file mode 100644 index 1327bcae..00000000 --- a/glomap/math/l1_solver.h +++ /dev/null @@ -1,113 +0,0 @@ -// This code is adapted from Theia library (http://theia-sfm.org/), -// with its original L1 solver adapted from -// "https://web.stanford.edu/~boyd/papers/admm/least_abs_deviations/lad.html" - -#pragma once - -#include - -#include -#include -#include - -// An L1 norm (|| A * x - b ||_1) approximation solver based on ADMM -// (alternating direction method of multipliers, -// https://web.stanford.edu/~boyd/papers/pdf/admm_distr_stats.pdf). -namespace glomap { - -// TODO: L1 solver for dense matrix -struct L1SolverOptions { - int max_num_iterations = 1000; - // Rho is the augmented Lagrangian parameter. - double rho = 1.0; - // Alpha is the over-relaxation parameter (typically between 1.0 and 1.8). - double alpha = 1.0; - - double absolute_tolerance = 1e-4; - double relative_tolerance = 1e-2; -}; - -template -class L1Solver { - public: - L1Solver(const L1SolverOptions& options, const MatrixType& mat) - : options_(options), a_(mat) { - // Pre-compute the sparsity pattern. - const MatrixType spd_mat = a_.transpose() * a_; - linear_solver_.compute(spd_mat); - } - - void Solve(const Eigen::VectorXd& rhs, Eigen::VectorXd* solution) { - Eigen::VectorXd& x = *solution; - Eigen::VectorXd z(a_.rows()), u(a_.rows()); - z.setZero(); - u.setZero(); - - Eigen::VectorXd a_times_x(a_.rows()), z_old(z.size()), ax_hat(a_.rows()); - // Precompute some convergence terms. - const double rhs_norm = rhs.norm(); - const double primal_abs_tolerance_eps = - std::sqrt(a_.rows()) * options_.absolute_tolerance; - const double dual_abs_tolerance_eps = - std::sqrt(a_.cols()) * options_.absolute_tolerance; - - const std::string row_format = - " % 4d % 4.4e % 4.4e % 4.4e % 4.4e"; - for (int i = 0; i < options_.max_num_iterations; i++) { - // Update x. - x.noalias() = linear_solver_.solve(a_.transpose() * (rhs + z - u)); - if (linear_solver_.info() != Eigen::Success) { - LOG(ERROR) << "L1 Minimization failed. Could not solve the sparse " - "linear system with Cholesky Decomposition"; - return; - } - - a_times_x.noalias() = a_ * x; - ax_hat.noalias() = options_.alpha * a_times_x; - ax_hat.noalias() += (1.0 - options_.alpha) * (z + rhs); - - // Update z and set z_old. - std::swap(z, z_old); - z.noalias() = Shrinkage(ax_hat - rhs + u, 1.0 / options_.rho); - - // Update u. - u.noalias() += ax_hat - z - rhs; - - // Compute the convergence terms. - const double r_norm = (a_times_x - z - rhs).norm(); - const double s_norm = - (-options_.rho * a_.transpose() * (z - z_old)).norm(); - const double max_norm = std::max({a_times_x.norm(), z.norm(), rhs_norm}); - const double primal_eps = - primal_abs_tolerance_eps + options_.relative_tolerance * max_norm; - const double dual_eps = dual_abs_tolerance_eps + - options_.relative_tolerance * - (options_.rho * a_.transpose() * u).norm(); - - // Determine if the minimizer has converged. - if (r_norm < primal_eps && s_norm < dual_eps) { - break; - } - } - } - - private: - const L1SolverOptions& options_; - - // Matrix A in || Ax - b ||_1 - const MatrixType a_; - - // Cholesky linear solver. Since our linear system will be a SPD matrix we can - // utilize the Cholesky factorization. - Eigen::CholmodSupernodalLLT> linear_solver_; - - static Eigen::VectorXd Shrinkage(const Eigen::VectorXd& vec, - const double kappa) { - Eigen::ArrayXd zero_vec(vec.size()); - zero_vec.setZero(); - return zero_vec.max(vec.array() - kappa) - - zero_vec.max(-vec.array() - kappa); - } -}; - -} // namespace glomap diff --git a/glomap/math/union_find.h b/glomap/math/union_find.h deleted file mode 100644 index 8c9687f9..00000000 --- a/glomap/math/union_find.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include - -namespace glomap { - -// UnionFind class to maintain disjoint sets for creating tracks -template -class UnionFind { - public: - // Find the root of the element x - DataType Find(DataType x) { - // If x is not in parent map, initialize it with x as its parent - auto parentIt = parent_.find(x); - if (parentIt == parent_.end()) { - parent_.emplace_hint(parentIt, x, x); - return x; - } - // Path compression: set the parent of x to the root of the set containing x - if (parentIt->second != x) { - parentIt->second = Find(parentIt->second); - } - return parentIt->second; - } - - // Unite the sets containing x and y - void Union(DataType x, DataType y) { - DataType root_x = Find(x); - DataType root_y = Find(y); - if (root_x != root_y) parent_[root_x] = root_y; - } - - void Clear() { parent_.clear(); } - - private: - // Map to store the parent of each element - std::unordered_map parent_; -}; - -} // namespace glomap diff --git a/glomap/processors/reconstruction_normalizer.h b/glomap/processors/reconstruction_normalizer.h index 3d3c3193..6566b849 100644 --- a/glomap/processors/reconstruction_normalizer.h +++ b/glomap/processors/reconstruction_normalizer.h @@ -2,7 +2,7 @@ #include "glomap/scene/types_sfm.h" -#include "colmap/geometry/pose.h" +#include namespace glomap { @@ -16,4 +16,5 @@ colmap::Sim3d NormalizeReconstruction( double extent = 10., double p0 = 0.1, double p1 = 0.9); + } // namespace glomap diff --git a/glomap/processors/view_graph_manipulation.cc b/glomap/processors/view_graph_manipulation.cc index db5bc3ca..e63a57a2 100644 --- a/glomap/processors/view_graph_manipulation.cc +++ b/glomap/processors/view_graph_manipulation.cc @@ -1,8 +1,8 @@ #include "view_graph_manipulation.h" #include "glomap/math/two_view_geometry.h" -#include "glomap/math/union_find.h" +#include #include namespace glomap { @@ -77,7 +77,8 @@ image_t ViewGraphManipulater::EstablishStrongClusters( view_graph.KeepLargestConnectedComponents(frames, images); // Construct the initial cluster by keeping the pairs with weight > min_thres - UnionFind uf; + colmap::UnionFind uf; + uf.Reserve(frames.size()); // Go through the edges, and add the edge with weight > min_thres for (auto& [pair_id, image_pair] : view_graph.image_pairs) { if (image_pair.is_valid == false) continue; diff --git a/glomap/scene/view_graph.cc b/glomap/scene/view_graph.cc index b1835b30..60009116 100644 --- a/glomap/scene/view_graph.cc +++ b/glomap/scene/view_graph.cc @@ -1,7 +1,5 @@ #include "glomap/scene/view_graph.h" -#include "glomap/math/union_find.h" - #include namespace glomap { diff --git a/scripts/format/c++.sh b/scripts/format/c++.sh index 2b5a64b9..15ddc2f0 100755 --- a/scripts/format/c++.sh +++ b/scripts/format/c++.sh @@ -3,12 +3,12 @@ # This script applies clang-format to the whole repository. # Check version -version_string=$(clang-format --version | sed -E 's/^.* ([0-9]+\.[0-9]+)\..*$/\1/') -expected_version_string='19.1' -if [[ "$version_string" == "$expected_version_string" ]]; then - echo "clang-format major.minor version '$version_string' matches expected '$expected_version_string'" +version_string=$(clang-format --version | sed -E 's/^.*(\d+\.\d+\.\d+-.*).*$/\1/') +expected_version_string='20.1.5' +if [[ "$version_string" =~ "$expected_version_string" ]]; then + echo "clang-format version '$version_string' matches '$expected_version_string'" else - echo "clang-format major.minor version '$version_string' doesn't match expected '$expected_version_string'" + echo "clang-format version '$version_string' doesn't match '$expected_version_string'" exit 1 fi diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt new file mode 100644 index 00000000..b9107f1c --- /dev/null +++ b/thirdparty/CMakeLists.txt @@ -0,0 +1,37 @@ +if(IS_GNU OR IS_CLANG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") +endif() + +include(FetchContent) + +FetchContent_Declare(poselib + GIT_REPOSITORY https://github.com/PoseLib/PoseLib.git + GIT_TAG f119951fca625133112acde48daffa5f20eba451 + EXCLUDE_FROM_ALL + SYSTEM +) +message(STATUS "Configuring PoseLib...") +if(FETCH_POSELIB) + set(MARCH_NATIVE OFF CACHE BOOL "") + FetchContent_MakeAvailable(poselib) +else() + find_package(PoseLib REQUIRED) +endif() +message(STATUS "Configuring PoseLib... done") + +FetchContent_Declare(COLMAP + GIT_REPOSITORY https://github.com/colmap/colmap.git + GIT_TAG b6b7b54eca6078070f73a3f0a084f79c629a6f10 # Nov 20, 2025 + EXCLUDE_FROM_ALL + SYSTEM +) +message(STATUS "Configuring COLMAP...") +set(UNINSTALL_ENABLED OFF CACHE INTERNAL "") +set(GUI_ENABLED OFF CACHE INTERNAL "") +if (FETCH_COLMAP) + FetchContent_MakeAvailable(COLMAP) +else() + find_package(COLMAP REQUIRED) +endif() +message(STATUS "Configuring COLMAP... done")