From f0f1dc40fe6d354b3424b77b291cc5f44b1d690f Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 10 Sep 2026 16:45:49 -0700 Subject: [PATCH] Consolidate tests and remove obsolete build helpers --- CHANGELOG.md | 6 + CMakeLists.txt | 9 +- README.md | 4 +- cmake/FindEigen3.cmake | 96 ------ cmake/conan.cmake | 673 ----------------------------------------- test/regression.cpp | 128 ++++++++ test/test.cpp | 127 -------- 7 files changed, 137 insertions(+), 906 deletions(-) delete mode 100644 cmake/FindEigen3.cmake delete mode 100644 cmake/conan.cmake delete mode 100644 test/test.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 894176d..0f76c2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +- Consolidate all regression coverage under `KDTREEPP_BUILD_TESTS`; remove the separate Catch2 2.x suite and unused Conan 1/Eigen find modules. +- Replace temporary release-branch wording in the README with installation guidance. + + ## 2.0.0 (release candidate) - Provide a Bzlmod library target with transitive Eigen and independent consumer checks. diff --git a/CMakeLists.txt b/CMakeLists.txt index fa7ad64..ef72b56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,9 +12,8 @@ target_include_directories(kdtreepp INTERFACE $) target_link_libraries(kdtreepp INTERFACE Eigen3::Eigen) option(KDTREEPP_BUILD_TESTS "Build regression tests" OFF) -option(KDTREEPP_BUILD_LEGACY_TESTS "Build Catch2 2.x tests" OFF) option(KDTREEPP_BUILD_BENCHMARKS "Build Google Benchmark benchmarks" OFF) -if(KDTREEPP_BUILD_TESTS OR KDTREEPP_BUILD_LEGACY_TESTS) +if(KDTREEPP_BUILD_TESTS) enable_testing() endif() if(KDTREEPP_BUILD_TESTS) @@ -22,12 +21,6 @@ if(KDTREEPP_BUILD_TESTS) target_link_libraries(kdtreepp-regression PRIVATE kdtreepp::kdtreepp) add_test(NAME kdtreepp-regression COMMAND kdtreepp-regression) endif() -if(KDTREEPP_BUILD_LEGACY_TESTS) - find_package(Catch2 2 REQUIRED) - add_executable(unit-tests test/test.cpp) - target_link_libraries(unit-tests PRIVATE kdtreepp::kdtreepp Catch2::Catch2) - add_test(NAME unit-tests COMMAND unit-tests) -endif() if(KDTREEPP_BUILD_BENCHMARKS) find_package(benchmark REQUIRED) add_executable(bench-tests bench/run.cpp) diff --git a/README.md b/README.md index c068c43..b84fa17 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ For custom objects, return an Eigen point from the sort accessor and a point or ## Bazel / Bzlmod -The 2.0.0 build integration is prepared in this branch and is not yet registered in the Bazel Central Registry. Start with a local checkout in your monorepo: +Use Bzlmod to consume a local checkout in your monorepo. This example does not require a Bazel Central Registry entry: ```starlark # MODULE.bazel @@ -125,7 +125,7 @@ ctest --test-dir build --output-on-failure Regression tests compare nearest-neighbor results with brute force, including empty, singleton, duplicate and boundary-sized inputs. CI also checks sanitizers, installed CMake consumers, Conan, Make targets and a checksum-verified archive consumed through a temporary Bazel registry. -Enable `KDTREEPP_BUILD_LEGACY_TESTS` with Catch2 2.x installed for the original suite, or `KDTREEPP_BUILD_BENCHMARKS` with Google Benchmark installed. [RELEASING.md](RELEASING.md) documents Make, coverage and release commands; [CHANGELOG.md](CHANGELOG.md) describes the version 2 build migration. No general performance improvement is claimed by that migration. +The standard regression suite also covers version reporting, spatial pruning, region queries, and in-place visitor mutation; no separate test framework is required. Enable `KDTREEPP_BUILD_BENCHMARKS` with Google Benchmark installed to run benchmarks. [RELEASING.md](RELEASING.md) documents Make, coverage and release commands; [CHANGELOG.md](CHANGELOG.md) describes the version 2 build migration. No general performance improvement is claimed by that migration. ## License diff --git a/cmake/FindEigen3.cmake b/cmake/FindEigen3.cmake deleted file mode 100644 index 0d2b3ce..0000000 --- a/cmake/FindEigen3.cmake +++ /dev/null @@ -1,96 +0,0 @@ -# - Try to find Eigen3 lib -# -# This module supports requiring a minimum version, e.g. you can do -# find_package(Eigen3 3.1.2) -# to require version 3.1.2 or newer of Eigen3. -# -# Once done this will define -# -# EIGEN3_FOUND - system has eigen lib with correct version -# EIGEN3_INCLUDE_DIR - the eigen include directory -# EIGEN3_VERSION - eigen version -# -# This module reads hints about search locations from -# the following enviroment variables: -# -# EIGEN3_ROOT -# EIGEN3_ROOT_DIR - -# Copyright (c) 2006, 2007 Montel Laurent, -# Copyright (c) 2008, 2009 Gael Guennebaud, -# Copyright (c) 2009 Benoit Jacob -# Redistribution and use is allowed according to the terms of the 2-clause BSD license. - -if(NOT Eigen3_FIND_VERSION) - if(NOT Eigen3_FIND_VERSION_MAJOR) - set(Eigen3_FIND_VERSION_MAJOR 2) - endif(NOT Eigen3_FIND_VERSION_MAJOR) - if(NOT Eigen3_FIND_VERSION_MINOR) - set(Eigen3_FIND_VERSION_MINOR 91) - endif(NOT Eigen3_FIND_VERSION_MINOR) - if(NOT Eigen3_FIND_VERSION_PATCH) - set(Eigen3_FIND_VERSION_PATCH 0) - endif(NOT Eigen3_FIND_VERSION_PATCH) - - set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") -endif(NOT Eigen3_FIND_VERSION) - -macro(_eigen3_check_version) - file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) - - string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") - set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") - string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") - set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") - string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") - set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") - - set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) - if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) - set(EIGEN3_VERSION_OK FALSE) - else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) - set(EIGEN3_VERSION_OK TRUE) - endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) - - if(NOT EIGEN3_VERSION_OK) - - message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " - "but at least version ${Eigen3_FIND_VERSION} is required") - endif(NOT EIGEN3_VERSION_OK) -endmacro(_eigen3_check_version) - -if (EIGEN3_INCLUDE_DIR) - - # in cache already - _eigen3_check_version() - set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) - -else (EIGEN3_INCLUDE_DIR) - - # search first if an Eigen3Config.cmake is available in the system, - # if successful this would set EIGEN3_INCLUDE_DIR and the rest of - # the script will work as usual - find_package(Eigen3 ${Eigen3_FIND_VERSION} NO_MODULE QUIET) - - if(NOT EIGEN3_INCLUDE_DIR) - find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library - HINTS - ENV EIGEN3_ROOT - ENV EIGEN3_ROOT_DIR - PATHS - ${CMAKE_INSTALL_PREFIX}/include - ${KDE4_INCLUDE_DIR} - PATH_SUFFIXES eigen3 eigen - ) - endif(NOT EIGEN3_INCLUDE_DIR) - - if(EIGEN3_INCLUDE_DIR) - _eigen3_check_version() - endif(EIGEN3_INCLUDE_DIR) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) - - mark_as_advanced(EIGEN3_INCLUDE_DIR) - -endif(EIGEN3_INCLUDE_DIR) diff --git a/cmake/conan.cmake b/cmake/conan.cmake deleted file mode 100644 index 7fb881d..0000000 --- a/cmake/conan.cmake +++ /dev/null @@ -1,673 +0,0 @@ -# The MIT License (MIT) - -# Copyright (c) 2018 JFrog - -# 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. - - - -# This file comes from: https://github.com/conan-io/cmake-conan. Please refer -# to this repository for issues and documentation. - -# Its purpose is to wrap and launch Conan C/C++ Package Manager when cmake is called. -# It will take CMake current settings (os, compiler, compiler version, architecture) -# and translate them to conan settings for installing and retrieving dependencies. - -# It is intended to facilitate developers building projects that have conan dependencies, -# but it is only necessary on the end-user side. It is not necessary to create conan -# packages, in fact it shouldn't be use for that. Check the project documentation. - -# version: 0.16.0-dev - -include(CMakeParseArguments) - -function(_get_msvc_ide_version result) - set(${result} "" PARENT_SCOPE) - if(NOT MSVC_VERSION VERSION_LESS 1400 AND MSVC_VERSION VERSION_LESS 1500) - set(${result} 8 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1500 AND MSVC_VERSION VERSION_LESS 1600) - set(${result} 9 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1600 AND MSVC_VERSION VERSION_LESS 1700) - set(${result} 10 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1700 AND MSVC_VERSION VERSION_LESS 1800) - set(${result} 11 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1800 AND MSVC_VERSION VERSION_LESS 1900) - set(${result} 12 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1900 AND MSVC_VERSION VERSION_LESS 1910) - set(${result} 14 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1910 AND MSVC_VERSION VERSION_LESS 1920) - set(${result} 15 PARENT_SCOPE) - elseif(NOT MSVC_VERSION VERSION_LESS 1920 AND MSVC_VERSION VERSION_LESS 1930) - set(${result} 16 PARENT_SCOPE) - else() - message(FATAL_ERROR "Conan: Unknown MSVC compiler version [${MSVC_VERSION}]") - endif() -endfunction() - -function(conan_cmake_settings result) - #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER}) - #message(STATUS "COMPILER " ${CMAKE_CXX_COMPILER_ID}) - #message(STATUS "VERSION " ${CMAKE_CXX_COMPILER_VERSION}) - #message(STATUS "FLAGS " ${CMAKE_LANG_FLAGS}) - #message(STATUS "LIB ARCH " ${CMAKE_CXX_LIBRARY_ARCHITECTURE}) - #message(STATUS "BUILD TYPE " ${CMAKE_BUILD_TYPE}) - #message(STATUS "GENERATOR " ${CMAKE_GENERATOR}) - #message(STATUS "GENERATOR WIN64 " ${CMAKE_CL_64}) - - message(STATUS "Conan: Automatic detection of conan settings from cmake") - - conan_parse_arguments(${ARGV}) - - if(ARGUMENTS_BUILD_TYPE) - set(_CONAN_SETTING_BUILD_TYPE ${ARGUMENTS_BUILD_TYPE}) - elseif(CMAKE_BUILD_TYPE) - set(_CONAN_SETTING_BUILD_TYPE ${CMAKE_BUILD_TYPE}) - else() - message(FATAL_ERROR "Please specify in command line CMAKE_BUILD_TYPE (-DCMAKE_BUILD_TYPE=Release)") - endif() - - string(TOUPPER ${_CONAN_SETTING_BUILD_TYPE} _CONAN_SETTING_BUILD_TYPE_UPPER) - if (_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "DEBUG") - set(_CONAN_SETTING_BUILD_TYPE "Debug") - elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELEASE") - set(_CONAN_SETTING_BUILD_TYPE "Release") - elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "RELWITHDEBINFO") - set(_CONAN_SETTING_BUILD_TYPE "RelWithDebInfo") - elseif(_CONAN_SETTING_BUILD_TYPE_UPPER STREQUAL "MINSIZEREL") - set(_CONAN_SETTING_BUILD_TYPE "MinSizeRel") - endif() - - if(ARGUMENTS_ARCH) - set(_CONAN_SETTING_ARCH ${ARGUMENTS_ARCH}) - endif() - #handle -s os setting - if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic") - #use default conan os setting if CMAKE_SYSTEM_NAME is not defined - set(CONAN_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}) - if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(CONAN_SYSTEM_NAME Macos) - endif() - if(${CMAKE_SYSTEM_NAME} STREQUAL "QNX") - set(CONAN_SYSTEM_NAME Neutrino) - endif() - set(CONAN_SUPPORTED_PLATFORMS Windows Linux Macos Android iOS FreeBSD WindowsStore WindowsCE watchOS tvOS FreeBSD SunOS AIX Arduino Emscripten Neutrino) - list (FIND CONAN_SUPPORTED_PLATFORMS "${CONAN_SYSTEM_NAME}" _index) - if (${_index} GREATER -1) - #check if the cmake system is a conan supported one - set(_CONAN_SETTING_OS ${CONAN_SYSTEM_NAME}) - else() - message(FATAL_ERROR "cmake system ${CONAN_SYSTEM_NAME} is not supported by conan. Use one of ${CONAN_SUPPORTED_PLATFORMS}") - endif() - endif() - - get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES) - if (";${_languages};" MATCHES ";CXX;") - set(LANGUAGE CXX) - set(USING_CXX 1) - elseif (";${_languages};" MATCHES ";C;") - set(LANGUAGE C) - set(USING_CXX 0) - else () - message(FATAL_ERROR "Conan: Neither C or C++ was detected as a language for the project. Unabled to detect compiler version.") - endif() - - if (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL GNU) - # using GCC - # TODO: Handle other params - string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) - list(GET VERSION_LIST 0 MAJOR) - list(GET VERSION_LIST 1 MINOR) - set(COMPILER_VERSION ${MAJOR}.${MINOR}) - if(${MAJOR} GREATER 4) - set(COMPILER_VERSION ${MAJOR}) - endif() - set(_CONAN_SETTING_COMPILER gcc) - set(_CONAN_SETTING_COMPILER_VERSION ${COMPILER_VERSION}) - if (USING_CXX) - conan_cmake_detect_unix_libcxx(_LIBCXX) - set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) - endif () - elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL AppleClang) - # using AppleClang - string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) - list(GET VERSION_LIST 0 MAJOR) - list(GET VERSION_LIST 1 MINOR) - set(_CONAN_SETTING_COMPILER apple-clang) - set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) - if (USING_CXX) - conan_cmake_detect_unix_libcxx(_LIBCXX) - set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) - endif () - elseif (${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL Clang) - string(REPLACE "." ";" VERSION_LIST ${CMAKE_${LANGUAGE}_COMPILER_VERSION}) - list(GET VERSION_LIST 0 MAJOR) - list(GET VERSION_LIST 1 MINOR) - set(_CONAN_SETTING_COMPILER clang) - set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}.${MINOR}) - if(APPLE) - cmake_policy(GET CMP0025 APPLE_CLANG_POLICY) - if(NOT APPLE_CLANG_POLICY STREQUAL NEW) - message(STATUS "Conan: APPLE and Clang detected. Assuming apple-clang compiler. Set CMP0025 to avoid it") - set(_CONAN_SETTING_COMPILER apple-clang) - endif() - endif() - if(${_CONAN_SETTING_COMPILER} STREQUAL clang AND ${MAJOR} GREATER 7) - set(_CONAN_SETTING_COMPILER_VERSION ${MAJOR}) - endif() - if (USING_CXX) - conan_cmake_detect_unix_libcxx(_LIBCXX) - set(_CONAN_SETTING_COMPILER_LIBCXX ${_LIBCXX}) - endif () - elseif(${CMAKE_${LANGUAGE}_COMPILER_ID} STREQUAL MSVC) - set(_VISUAL "Visual Studio") - _get_msvc_ide_version(_VISUAL_VERSION) - if("${_VISUAL_VERSION}" STREQUAL "") - message(FATAL_ERROR "Conan: Visual Studio not recognized") - else() - set(_CONAN_SETTING_COMPILER ${_VISUAL}) - set(_CONAN_SETTING_COMPILER_VERSION ${_VISUAL_VERSION}) - endif() - - if(NOT _CONAN_SETTING_ARCH) - if (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "64") - set(_CONAN_SETTING_ARCH x86_64) - elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "^ARM") - message(STATUS "Conan: Using default ARM architecture from MSVC") - set(_CONAN_SETTING_ARCH armv6) - elseif (MSVC_${LANGUAGE}_ARCHITECTURE_ID MATCHES "86") - set(_CONAN_SETTING_ARCH x86) - else () - message(FATAL_ERROR "Conan: Unknown MSVC architecture [${MSVC_${LANGUAGE}_ARCHITECTURE_ID}]") - endif() - endif() - - conan_cmake_detect_vs_runtime(_vs_runtime) - message(STATUS "Conan: Detected VS runtime: ${_vs_runtime}") - set(_CONAN_SETTING_COMPILER_RUNTIME ${_vs_runtime}) - - if (CMAKE_GENERATOR_TOOLSET) - set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) - elseif(CMAKE_VS_PLATFORM_TOOLSET AND (CMAKE_GENERATOR STREQUAL "Ninja")) - set(_CONAN_SETTING_COMPILER_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) - endif() - else() - message(FATAL_ERROR "Conan: compiler setup not recognized") - endif() - - # If profile is defined it is used - if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND ARGUMENTS_DEBUG_PROFILE) - set(_APPLIED_PROFILES ${ARGUMENTS_DEBUG_PROFILE}) - elseif(CMAKE_BUILD_TYPE STREQUAL "Release" AND ARGUMENTS_RELEASE_PROFILE) - set(_APPLIED_PROFILES ${ARGUMENTS_RELEASE_PROFILE}) - elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" AND ARGUMENTS_RELWITHDEBINFO_PROFILE) - set(_APPLIED_PROFILES ${ARGUMENTS_RELWITHDEBINFO_PROFILE}) - elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" AND ARGUMENTS_MINSIZEREL_PROFILE) - set(_APPLIED_PROFILES ${ARGUMENTS_MINSIZEREL_PROFILE}) - elseif(ARGUMENTS_PROFILE) - set(_APPLIED_PROFILES ${ARGUMENTS_PROFILE}) - endif() - - foreach(ARG ${_APPLIED_PROFILES}) - set(_SETTINGS ${_SETTINGS} -pr=${ARG}) - endforeach() - foreach(ARG ${ARGUMENTS_PROFILE_BUILD}) - conan_check(VERSION 1.24.0 REQUIRED DETECT_QUIET) - set(_SETTINGS ${_SETTINGS} -pr:b=${ARG}) - endforeach() - - if(NOT _SETTINGS OR ARGUMENTS_PROFILE_AUTO STREQUAL "ALL") - set(ARGUMENTS_PROFILE_AUTO arch build_type compiler compiler.version - compiler.runtime compiler.libcxx compiler.toolset) - endif() - - # remove any manually specified settings from the autodetected settings - foreach(ARG ${ARGUMENTS_SETTINGS}) - string(REGEX MATCH "[^=]*" MANUAL_SETTING "${ARG}") - message(STATUS "Conan: ${MANUAL_SETTING} was added as an argument. Not using the autodetected one.") - list(REMOVE_ITEM ARGUMENTS_PROFILE_AUTO "${MANUAL_SETTING}") - endforeach() - - # Automatic from CMake - foreach(ARG ${ARGUMENTS_PROFILE_AUTO}) - string(TOUPPER ${ARG} _arg_name) - string(REPLACE "." "_" _arg_name ${_arg_name}) - if(_CONAN_SETTING_${_arg_name}) - set(_SETTINGS ${_SETTINGS} -s ${ARG}=${_CONAN_SETTING_${_arg_name}}) - endif() - endforeach() - - foreach(ARG ${ARGUMENTS_SETTINGS}) - set(_SETTINGS ${_SETTINGS} -s ${ARG}) - endforeach() - - message(STATUS "Conan: Settings= ${_SETTINGS}") - - set(${result} ${_SETTINGS} PARENT_SCOPE) -endfunction() - - -function(conan_cmake_detect_unix_libcxx result) - # Take into account any -stdlib in compile options - get_directory_property(compile_options DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) - string(GENEX_STRIP "${compile_options}" compile_options) - - # Take into account any _GLIBCXX_USE_CXX11_ABI in compile definitions - get_directory_property(defines DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) - string(GENEX_STRIP "${defines}" defines) - - foreach(define ${defines}) - if(define MATCHES "_GLIBCXX_USE_CXX11_ABI") - if(define MATCHES "^-D") - set(compile_options ${compile_options} "${define}") - else() - set(compile_options ${compile_options} "-D${define}") - endif() - endif() - endforeach() - - # add additional compiler options ala cmRulePlaceholderExpander::ExpandRuleVariable - set(EXPAND_CXX_COMPILER ${CMAKE_CXX_COMPILER}) - if(CMAKE_CXX_COMPILER_ARG1) - # CMake splits CXX="foo bar baz" into CMAKE_CXX_COMPILER="foo", CMAKE_CXX_COMPILER_ARG1="bar baz" - # without this, ccache, winegcc, or other wrappers might lose all their arguments - separate_arguments(SPLIT_CXX_COMPILER_ARG1 NATIVE_COMMAND ${CMAKE_CXX_COMPILER_ARG1}) - list(APPEND EXPAND_CXX_COMPILER ${SPLIT_CXX_COMPILER_ARG1}) - endif() - - if(CMAKE_CXX_COMPILE_OPTIONS_TARGET AND CMAKE_CXX_COMPILER_TARGET) - # without --target= we may be calling the wrong underlying GCC - list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_TARGET}${CMAKE_CXX_COMPILER_TARGET}") - endif() - - if(CMAKE_CXX_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN AND CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN) - list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN}${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}") - endif() - - if(CMAKE_CXX_COMPILE_OPTIONS_SYSROOT) - # without --sysroot= we may find the wrong #include - if(CMAKE_SYSROOT_COMPILE) - list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT_COMPILE}") - elseif(CMAKE_SYSROOT) - list(APPEND EXPAND_CXX_COMPILER "${CMAKE_CXX_COMPILE_OPTIONS_SYSROOT}${CMAKE_SYSROOT}") - endif() - endif() - - separate_arguments(SPLIT_CXX_FLAGS NATIVE_COMMAND ${CMAKE_CXX_FLAGS}) - - if(CMAKE_OSX_SYSROOT) - set(xcode_sysroot_option "--sysroot=${CMAKE_OSX_SYSROOT}") - endif() - - execute_process( - COMMAND ${CMAKE_COMMAND} -E echo "#include " - COMMAND ${EXPAND_CXX_COMPILER} ${SPLIT_CXX_FLAGS} -x c++ ${xcode_sysroot_option} ${compile_options} -E -dM - - OUTPUT_VARIABLE string_defines - ) - - if(string_defines MATCHES "#define __GLIBCXX__") - # Allow -D_GLIBCXX_USE_CXX11_ABI=ON/OFF as argument to cmake - if(DEFINED _GLIBCXX_USE_CXX11_ABI) - if(_GLIBCXX_USE_CXX11_ABI) - set(${result} libstdc++11 PARENT_SCOPE) - return() - else() - set(${result} libstdc++ PARENT_SCOPE) - return() - endif() - endif() - - if(string_defines MATCHES "#define _GLIBCXX_USE_CXX11_ABI 1\n") - set(${result} libstdc++11 PARENT_SCOPE) - else() - # Either the compiler is missing the define because it is old, and so - # it can't use the new abi, or the compiler was configured to use the - # old abi by the user or distro (e.g. devtoolset on RHEL/CentOS) - set(${result} libstdc++ PARENT_SCOPE) - endif() - else() - set(${result} libc++ PARENT_SCOPE) - endif() -endfunction() - -function(conan_cmake_detect_vs_runtime result) - string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) - set(variables CMAKE_CXX_FLAGS_${build_type} CMAKE_C_FLAGS_${build_type} CMAKE_CXX_FLAGS CMAKE_C_FLAGS) - foreach(variable ${variables}) - if(NOT "${${variable}}" STREQUAL "") - string(REPLACE " " ";" flags "${${variable}}") - foreach (flag ${flags}) - if("${flag}" STREQUAL "/MD" OR "${flag}" STREQUAL "/MDd" OR "${flag}" STREQUAL "/MT" OR "${flag}" STREQUAL "/MTd") - string(SUBSTRING "${flag}" 1 -1 runtime) - set(${result} "${runtime}" PARENT_SCOPE) - return() - endif() - endforeach() - endif() - endforeach() - if("${build_type}" STREQUAL "DEBUG") - set(${result} "MDd" PARENT_SCOPE) - else() - set(${result} "MD" PARENT_SCOPE) - endif() -endfunction() - - -macro(conan_parse_arguments) - set(options BASIC_SETUP CMAKE_TARGETS UPDATE KEEP_RPATHS NO_LOAD NO_OUTPUT_DIRS OUTPUT_QUIET NO_IMPORTS SKIP_STD) - set(oneValueArgs CONANFILE ARCH BUILD_TYPE INSTALL_FOLDER CONAN_COMMAND) - set(multiValueArgs DEBUG_PROFILE RELEASE_PROFILE RELWITHDEBINFO_PROFILE MINSIZEREL_PROFILE - PROFILE REQUIRES OPTIONS IMPORTS SETTINGS BUILD ENV GENERATORS PROFILE_AUTO - INSTALL_ARGS CONFIGURATION_TYPES PROFILE_BUILD) - cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) -endmacro() - -function(conan_cmake_install) - # Calls "conan install" - # Argument BUILD is equivalant to --build={missing, PkgName,...} or - # --build when argument is 'BUILD all' (which builds all packages from source) - # Argument CONAN_COMMAND, to specify the conan path, e.g. in case of running from source - # cmake does not identify conan as command, even if it is +x and it is in the path - conan_parse_arguments(${ARGV}) - - if(CONAN_CMAKE_MULTI) - set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake_multi) - else() - set(ARGUMENTS_GENERATORS ${ARGUMENTS_GENERATORS} cmake) - endif() - - set(CONAN_BUILD_POLICY "") - foreach(ARG ${ARGUMENTS_BUILD}) - if(${ARG} STREQUAL "all") - set(CONAN_BUILD_POLICY ${CONAN_BUILD_POLICY} --build) - break() - else() - set(CONAN_BUILD_POLICY ${CONAN_BUILD_POLICY} --build=${ARG}) - endif() - endforeach() - if(ARGUMENTS_CONAN_COMMAND) - set(CONAN_CMD ${ARGUMENTS_CONAN_COMMAND}) - else() - conan_check(REQUIRED) - endif() - set(CONAN_OPTIONS "") - if(ARGUMENTS_CONANFILE) - if(IS_ABSOLUTE ${ARGUMENTS_CONANFILE}) - set(CONANFILE ${ARGUMENTS_CONANFILE}) - else() - set(CONANFILE ${CMAKE_CURRENT_SOURCE_DIR}/${ARGUMENTS_CONANFILE}) - endif() - else() - set(CONANFILE ".") - endif() - foreach(ARG ${ARGUMENTS_OPTIONS}) - set(CONAN_OPTIONS ${CONAN_OPTIONS} -o=${ARG}) - endforeach() - if(ARGUMENTS_UPDATE) - set(CONAN_INSTALL_UPDATE --update) - endif() - if(ARGUMENTS_NO_IMPORTS) - set(CONAN_INSTALL_NO_IMPORTS --no-imports) - endif() - set(CONAN_INSTALL_FOLDER "") - if(ARGUMENTS_INSTALL_FOLDER) - set(CONAN_INSTALL_FOLDER -if=${ARGUMENTS_INSTALL_FOLDER}) - endif() - foreach(ARG ${ARGUMENTS_GENERATORS}) - set(CONAN_GENERATORS ${CONAN_GENERATORS} -g=${ARG}) - endforeach() - foreach(ARG ${ARGUMENTS_ENV}) - set(CONAN_ENV_VARS ${CONAN_ENV_VARS} -e=${ARG}) - endforeach() - set(conan_args install ${CONANFILE} ${settings} ${CONAN_ENV_VARS} ${CONAN_GENERATORS} ${CONAN_BUILD_POLICY} ${CONAN_INSTALL_UPDATE} ${CONAN_INSTALL_NO_IMPORTS} ${CONAN_OPTIONS} ${CONAN_INSTALL_FOLDER} ${ARGUMENTS_INSTALL_ARGS}) - - string (REPLACE ";" " " _conan_args "${conan_args}") - message(STATUS "Conan executing: ${CONAN_CMD} ${_conan_args}") - - if(ARGUMENTS_OUTPUT_QUIET) - execute_process(COMMAND ${CONAN_CMD} ${conan_args} - RESULT_VARIABLE return_code - OUTPUT_VARIABLE conan_output - ERROR_VARIABLE conan_output - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - else() - execute_process(COMMAND ${CONAN_CMD} ${conan_args} - RESULT_VARIABLE return_code - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - endif() - - if(NOT "${return_code}" STREQUAL "0") - message(FATAL_ERROR "Conan install failed='${return_code}'") - endif() - -endfunction() - - -function(conan_cmake_setup_conanfile) - conan_parse_arguments(${ARGV}) - if(ARGUMENTS_CONANFILE) - get_filename_component(_CONANFILE_NAME ${ARGUMENTS_CONANFILE} NAME) - # configure_file will make sure cmake re-runs when conanfile is updated - configure_file(${ARGUMENTS_CONANFILE} ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk COPYONLY) - file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/${_CONANFILE_NAME}.junk) - else() - conan_cmake_generate_conanfile(${ARGV}) - endif() -endfunction() - -function(conan_cmake_generate_conanfile) - # Generate, writing in disk a conanfile.txt with the requires, options, and imports - # specified as arguments - # This will be considered as temporary file, generated in CMAKE_CURRENT_BINARY_DIR) - conan_parse_arguments(${ARGV}) - set(_FN "${CMAKE_CURRENT_BINARY_DIR}/conanfile.txt") - - file(WRITE ${_FN} "[generators]\ncmake\n\n[requires]\n") - foreach(ARG ${ARGUMENTS_REQUIRES}) - file(APPEND ${_FN} ${ARG} "\n") - endforeach() - - file(APPEND ${_FN} ${ARG} "\n[imports]\n") - foreach(ARG ${ARGUMENTS_IMPORTS}) - file(APPEND ${_FN} ${ARG} "\n") - endforeach() -endfunction() - - -macro(conan_load_buildinfo) - if(CONAN_CMAKE_MULTI) - set(_CONANBUILDINFO conanbuildinfo_multi.cmake) - else() - set(_CONANBUILDINFO conanbuildinfo.cmake) - endif() - if(ARGUMENTS_INSTALL_FOLDER) - set(_CONANBUILDINFOFOLDER ${ARGUMENTS_INSTALL_FOLDER}) - else() - set(_CONANBUILDINFOFOLDER ${CMAKE_CURRENT_BINARY_DIR}) - endif() - # Checks for the existence of conanbuildinfo.cmake, and loads it - # important that it is macro, so variables defined at parent scope - if(EXISTS "${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}") - message(STATUS "Conan: Loading ${_CONANBUILDINFO}") - include(${_CONANBUILDINFOFOLDER}/${_CONANBUILDINFO}) - else() - message(FATAL_ERROR "${_CONANBUILDINFO} doesn't exist in ${CMAKE_CURRENT_BINARY_DIR}") - endif() -endmacro() - - -macro(conan_cmake_run) - conan_parse_arguments(${ARGV}) - - if(ARGUMENTS_CONFIGURATION_TYPES AND NOT CMAKE_CONFIGURATION_TYPES) - message(WARNING "CONFIGURATION_TYPES should only be specified for multi-configuration generators") - elseif(ARGUMENTS_CONFIGURATION_TYPES AND ARGUMENTS_BUILD_TYPE) - message(WARNING "CONFIGURATION_TYPES and BUILD_TYPE arguments should not be defined at the same time.") - endif() - - if(CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE AND NOT CONAN_EXPORTED - AND NOT ARGUMENTS_BUILD_TYPE) - set(CONAN_CMAKE_MULTI ON) - if (NOT ARGUMENTS_CONFIGURATION_TYPES) - set(ARGUMENTS_CONFIGURATION_TYPES "Release;Debug") - endif() - message(STATUS "Conan: Using cmake-multi generator") - else() - set(CONAN_CMAKE_MULTI OFF) - endif() - - if(NOT CONAN_EXPORTED) - conan_cmake_setup_conanfile(${ARGV}) - if(CONAN_CMAKE_MULTI) - foreach(CMAKE_BUILD_TYPE ${ARGUMENTS_CONFIGURATION_TYPES}) - set(ENV{CONAN_IMPORT_PATH} ${CMAKE_BUILD_TYPE}) - conan_cmake_settings(settings ${ARGV}) - conan_cmake_install(SETTINGS ${settings} ${ARGV}) - endforeach() - set(CMAKE_BUILD_TYPE) - else() - conan_cmake_settings(settings ${ARGV}) - conan_cmake_install(SETTINGS ${settings} ${ARGV}) - endif() - endif() - - if (NOT ARGUMENTS_NO_LOAD) - conan_load_buildinfo() - endif() - - if(ARGUMENTS_BASIC_SETUP) - foreach(_option CMAKE_TARGETS KEEP_RPATHS NO_OUTPUT_DIRS SKIP_STD) - if(ARGUMENTS_${_option}) - if(${_option} STREQUAL "CMAKE_TARGETS") - list(APPEND _setup_options "TARGETS") - else() - list(APPEND _setup_options ${_option}) - endif() - endif() - endforeach() - conan_basic_setup(${_setup_options}) - endif() -endmacro() - -macro(conan_check) - # Checks conan availability in PATH - # Arguments REQUIRED, DETECT_QUIET and VERSION are optional - # Example usage: - # conan_check(VERSION 1.0.0 REQUIRED) - set(options REQUIRED DETECT_QUIET) - set(oneValueArgs VERSION) - cmake_parse_arguments(CONAN "${options}" "${oneValueArgs}" "" ${ARGN}) - if(NOT CONAN_DETECT_QUIET) - message(STATUS "Conan: checking conan executable") - endif() - - find_program(CONAN_CMD conan) - if(NOT CONAN_CMD AND CONAN_REQUIRED) - message(FATAL_ERROR "Conan executable not found! Please install conan.") - endif() - if(NOT CONAN_DETECT_QUIET) - message(STATUS "Conan: Found program ${CONAN_CMD}") - endif() - execute_process(COMMAND ${CONAN_CMD} --version - OUTPUT_VARIABLE CONAN_VERSION_OUTPUT - ERROR_VARIABLE CONAN_VERSION_OUTPUT) - if(NOT CONAN_DETECT_QUIET) - message(STATUS "Conan: Version found ${CONAN_VERSION_OUTPUT}") - endif() - - if(DEFINED CONAN_VERSION) - string(REGEX MATCH ".*Conan version ([0-9]+\\.[0-9]+\\.[0-9]+)" FOO - "${CONAN_VERSION_OUTPUT}") - if(${CMAKE_MATCH_1} VERSION_LESS ${CONAN_VERSION}) - message(FATAL_ERROR "Conan outdated. Installed: ${CMAKE_MATCH_1}, \ - required: ${CONAN_VERSION}. Consider updating via 'pip \ - install conan==${CONAN_VERSION}'.") - endif() - endif() -endmacro() - -function(conan_add_remote) - # Adds a remote - # Arguments URL and NAME are required, INDEX, COMMAND and VERIFY_SSL are optional - # Example usage: - # conan_add_remote(NAME bincrafters INDEX 1 - # URL https://api.bintray.com/conan/bincrafters/public-conan - # VERIFY_SSL True) - set(oneValueArgs URL NAME INDEX COMMAND VERIFY_SSL) - cmake_parse_arguments(CONAN "" "${oneValueArgs}" "" ${ARGN}) - - if(DEFINED CONAN_INDEX) - set(CONAN_INDEX_ARG "-i ${CONAN_INDEX}") - endif() - if(DEFINED CONAN_COMMAND) - set(CONAN_CMD ${CONAN_COMMAND}) - else() - conan_check(REQUIRED) - endif() - set(CONAN_VERIFY_SSL_ARG "True") - if(DEFINED CONAN_VERIFY_SSL) - set(CONAN_VERIFY_SSL_ARG ${CONAN_VERIFY_SSL}) - endif() - message(STATUS "Conan: Adding ${CONAN_NAME} remote repository (${CONAN_URL}) verify ssl (${CONAN_VERIFY_SSL_ARG})") - execute_process(COMMAND ${CONAN_CMD} remote add ${CONAN_NAME} ${CONAN_INDEX_ARG} -f ${CONAN_URL} ${CONAN_VERIFY_SSL_ARG}) -endfunction() - -macro(conan_config_install) - # install a full configuration from a local or remote zip file - # Argument ITEM is required, arguments TYPE, SOURCE, TARGET and VERIFY_SSL are optional - # Example usage: - # conan_config_install(ITEM https://github.com/conan-io/cmake-conan.git - # TYPE git SOURCE source-folder TARGET target-folder VERIFY_SSL false) - set(oneValueArgs ITEM TYPE SOURCE TARGET VERIFY_SSL) - set(multiValueArgs ARGS) - cmake_parse_arguments(CONAN "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - find_program(CONAN_CMD conan) - if(NOT CONAN_CMD AND CONAN_REQUIRED) - message(FATAL_ERROR "Conan executable not found!") - endif() - - if(DEFINED CONAN_VERIFY_SSL) - set(CONAN_VERIFY_SSL_ARG "--verify-ssl=${CONAN_VERIFY_SSL}") - endif() - - if(DEFINED CONAN_TYPE) - set(CONAN_TYPE_ARG "--type=${CONAN_TYPE}") - endif() - - if(DEFINED CONAN_ARGS) - set(CONAN_ARGS_ARGS "--args=\"${CONAN_ARGS}\"") - endif() - - if(DEFINED CONAN_SOURCE) - set(CONAN_SOURCE_ARGS "--source-folder=${CONAN_SOURCE}") - endif() - - if(DEFINED CONAN_TARGET) - set(CONAN_TARGET_ARGS "--target-folder=${CONAN_TARGET}") - endif() - - set (CONAN_CONFIG_INSTALL_ARGS ${CONAN_VERIFY_SSL_ARG} - ${CONAN_TYPE_ARG} - ${CONAN_ARGS_ARGS} - ${CONAN_SOURCE_ARGS} - ${CONAN_TARGET_ARGS}) - - message(STATUS "Conan: Installing config from ${CONAN_ITEM}") - execute_process(COMMAND ${CONAN_CMD} config install ${CONAN_ITEM} ${CONAN_CONFIG_INSTALL_ARGS}) -endmacro() diff --git a/test/regression.cpp b/test/regression.cpp index 4477238..31416be 100644 --- a/test/regression.cpp +++ b/test/regression.cpp @@ -2,10 +2,138 @@ #include #include #include +#include +#include void check(bool value) { if (!value) { std::cerr << "check failed\n"; std::exit(1); } } +using Vector2 = Eigen::Vector2d; +using Vector3 = Eigen::Vector3d; +using AlignedBox2 = Eigen::AlignedBox2d; +using AlignedBox3 = Eigen::AlignedBox3d; + +static void CHECK_VEC3_EQ(const Vector3& a, const Vector3& b) { + check(std::abs(a[0] - b[0]) < 1e-12); + check(std::abs(a[1] - b[1]) < 1e-12); + check(std::abs(a[2] - b[2]) < 1e-12); +} + +static void checkVersion() { check(KDTREEPP_VERSION_STRING == std::string("2.0.0")); } + +static void checkPointTree() { + // Build a k-d tree from a list of points + + std::vector> points; + std::mt19937_64 randGen{size_t(42)}; + std::uniform_real_distribution dist{-1000.0, 1000.0}; + + // Make random points + constexpr size_t count = 1500; + points.resize(count); + for (auto& point : points) { + point << dist(randGen), dist(randGen), dist(randGen); + } + + const auto node = kdtreepp::MakeEigenKdTreeNode( + points.begin(), points.end(), [](const Vector3& p) { return p; }, + [](const Vector3& p) { return p; }); + + const Vector3 checkPoint{dist(randGen), dist(randGen), dist(randGen)}; + + // Find closest point via brute force search + double bruteMinDistSq = std::numeric_limits::max(); + Vector3 bruteClosestPoint; + for (const auto& point : points) { + const double rSq = (point - checkPoint).squaredNorm(); + if (rSq < bruteMinDistSq) { + bruteMinDistSq = rSq; + bruteClosestPoint = point; + } + } + + // Find closest point using kdtree + double minDistSq = std::numeric_limits::max(); + Vector3 closestPoint; + size_t numBoundsChecks = 0; + size_t numPointChecks = 0; + node.visit( + [&minDistSq, checkPoint, &numBoundsChecks](const AlignedBox3& bounds) { + ++numBoundsChecks; + return bounds.squaredExteriorDistance(checkPoint) < minDistSq; + }, + + [&minDistSq, &closestPoint, checkPoint, &numPointChecks](const Vector3& point) { + ++numPointChecks; + const double rSq = (point - checkPoint).squaredNorm(); + if (rSq < minDistSq) { + minDistSq = rSq; + closestPoint = point; + } + }); + + CHECK_VEC3_EQ(bruteClosestPoint, closestPoint); + check(numBoundsChecks < count); + check(numPointChecks < count); + + // Count points within a bounding box + AlignedBox3 searchBounds{Vector3{-500.0, -500.0, -500.0}, Vector3{500.0, 500.0, 500.0}}; + size_t foundPoints = 0; + node.visit([&searchBounds](const AlignedBox3& bounds) { return searchBounds.intersects(bounds); }, + [&searchBounds, &foundPoints](const Vector3& point) { + if (searchBounds.contains(point)) { + ++foundPoints; + } + }); + + check(foundPoints > count / 10); + check(foundPoints < count / 2); +} + +static void checkModifyInPlace() { + // Build a k-d tree from a list of points + + std::vector> points; + std::mt19937_64 randGen{size_t(42)}; + std::uniform_real_distribution dist{0.1, 1.0}; + + // Make random points + constexpr size_t count = 100; + points.resize(count); + for (auto& point : points) { + point << dist(randGen), dist(randGen); + } + + auto node = kdtreepp::MakeEigenKdTreeNode( + points.begin(), points.end(), [](const Vector2& p) { return p; }, + [](const Vector2& p) { return p; }); + + size_t numBoundsChecks = 0; + size_t numPointChecks = 0; + node.visit( + [&numBoundsChecks](const AlignedBox2& bounds) { + (void)bounds; + ++numBoundsChecks; + return true; + }, + + [&numPointChecks](Vector2& point) { + ++numPointChecks; + point *= -1.0; + }); + + check(numBoundsChecks < count); + check(numPointChecks == count); + + for (const auto& point : points) { + check(point.x() < 0.0); + check(point.y() < 0.0); + } +} + int main() { + checkVersion(); + checkPointTree(); + checkModifyInPlace(); using Point = Eigen::Vector3d; for (int count : {0, 1, 2, 8, 9, 1500}) { std::mt19937 random(42); diff --git a/test/test.cpp b/test/test.cpp deleted file mode 100644 index dba8700..0000000 --- a/test/test.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include -#define CATCH_CONFIG_MAIN -#include - -using Vector2 = Eigen::Vector2d; -using Vector3 = Eigen::Vector3d; -using AlignedBox2 = Eigen::AlignedBox2d; -using AlignedBox3 = Eigen::AlignedBox3d; - -static void CHECK_VEC3_EQ(const Vector3& a, const Vector3& b) { - CHECK(a[0] == Approx(b[0])); - CHECK(a[1] == Approx(b[1])); - CHECK(a[2] == Approx(b[2])); -} - -TEST_CASE("VERSION_STRING") { REQUIRE(KDTREEPP_VERSION_STRING == std::string("2.0.0")); } - -TEST_CASE("PointTreeTest") { - // Build a k-d tree from a list of points - - std::vector> points; - std::mt19937_64 randGen{size_t(42)}; - std::uniform_real_distribution dist{-1000.0, 1000.0}; - - // Make random points - constexpr size_t count = 1500; - points.resize(count); - for (auto& point : points) { - point << dist(randGen), dist(randGen), dist(randGen); - } - - const auto node = kdtreepp::MakeEigenKdTreeNode( - points.begin(), points.end(), [](const Vector3& p) { return p; }, - [](const Vector3& p) { return p; }); - - const Vector3 checkPoint{dist(randGen), dist(randGen), dist(randGen)}; - - // Find closest point via brute force search - double bruteMinDistSq = std::numeric_limits::max(); - Vector3 bruteClosestPoint; - for (const auto& point : points) { - const double rSq = (point - checkPoint).squaredNorm(); - if (rSq < bruteMinDistSq) { - bruteMinDistSq = rSq; - bruteClosestPoint = point; - } - } - - // Find closest point using kdtree - double minDistSq = std::numeric_limits::max(); - Vector3 closestPoint; - size_t numBoundsChecks = 0; - size_t numPointChecks = 0; - node.visit( - [&minDistSq, checkPoint, &numBoundsChecks](const AlignedBox3& bounds) { - ++numBoundsChecks; - return bounds.squaredExteriorDistance(checkPoint) < minDistSq; - }, - - [&minDistSq, &closestPoint, checkPoint, &numPointChecks](const Vector3& point) { - ++numPointChecks; - const double rSq = (point - checkPoint).squaredNorm(); - if (rSq < minDistSq) { - minDistSq = rSq; - closestPoint = point; - } - }); - - CHECK_VEC3_EQ(bruteClosestPoint, closestPoint); - CHECK(numBoundsChecks < count); - CHECK(numPointChecks < count); - - // Count points within a bounding box - AlignedBox3 searchBounds{Vector3{-500.0, -500.0, -500.0}, Vector3{500.0, 500.0, 500.0}}; - size_t foundPoints = 0; - node.visit([&searchBounds](const AlignedBox3& bounds) { return searchBounds.intersects(bounds); }, - [&searchBounds, &foundPoints](const Vector3& point) { - if (searchBounds.contains(point)) { - ++foundPoints; - } - }); - - CHECK(foundPoints > count / 10); - CHECK(foundPoints < count / 2); -} - -TEST_CASE("ModifyInPlace") { - // Build a k-d tree from a list of points - - std::vector> points; - std::mt19937_64 randGen{size_t(42)}; - std::uniform_real_distribution dist{0.1, 1.0}; - - // Make random points - constexpr size_t count = 100; - points.resize(count); - for (auto& point : points) { - point << dist(randGen), dist(randGen); - } - - auto node = kdtreepp::MakeEigenKdTreeNode( - points.begin(), points.end(), [](const Vector2& p) { return p; }, - [](const Vector2& p) { return p; }); - - size_t numBoundsChecks = 0; - size_t numPointChecks = 0; - node.visit( - [&numBoundsChecks](const AlignedBox2& bounds) { - (void)bounds; - ++numBoundsChecks; - return true; - }, - - [&numPointChecks](Vector2& point) { - ++numPointChecks; - point *= -1.0; - }); - - CHECK(numBoundsChecks < count); - CHECK(numPointChecks == count); - - for (const auto& point : points) { - CHECK(point.x() < 0.0); - CHECK(point.y() < 0.0); - } -}