Skip to content

Commit 0fb8f73

Browse files
authored
Interface Rework (#28)
Size type consistency. Updated containers and adaptors. CMake qol update. Sequence renamed to Point. SearchBox ReportNode update. Small 3-5% benchark performance improvement. Moved KdTree functors to their own header files. Split KdTree unit tests. Removed the KdTree Dim template argument. KdTree Splitter argument type replaced. Google Code Guide update for output function arguments. Added SpaceWrapper to simplify interfacing with a Space. Minimum required C++ standard updated from C++11 to C++17. kDynamicDim to kDynamicSize. Minor KdTreeBuilder rework. Moved KdTreeData to its own header file. Renamed StdPointTraits to PointTraits. PointTraits moved to its own header file. Eigen and OpenCV header files renamed. Map and its traits moved into PicoTree from PycoTree. CvTraits now uses PointMap instead of CvMatRow. Metrics now use iterators instead of points. Trait dependency removed for metrics. Eigen metrics removed. Added PointWrapper to simplify interfacing with a Point. Split space and point related traits. Updated Aknn functions to be overloads of the Knn functions. Added the SE2Squared metric. Added the Midpoint splitting rule. Code reduction/reuse of point classes. Traits PointTraitsFor requirement removed. PointTraits used directly. Traits IndexType requirement removed. Moved (back) to the KdTree. Traits PointSdim and PointCoords requirement removed. PointTraits used directly. Created SpaceTraits and updated Eigen, OpenCV, Vector and Map traits accordingly. KdTree and CoverTree now take a Space as template argument, not the traits. Split up the CoverTree. Added default SpaceTraits overload for reference_wrapper<SpaceType>. More consistent interface between points, spaces and their traits. Using SpaceWrapper and PointWrapper in unit tests. Version updated to 8.0.0.
1 parent f0e28e3 commit 0fb8f73

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+3762
-3623
lines changed

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ include (${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils.cmake)
66

77
project(pico_tree
88
LANGUAGES CXX
9-
VERSION 0.7.5
10-
DESCRIPTION "PicoTree is a C++ header only library with Python bindings for nearest neighbor searches and range searches using a KdTree."
9+
VERSION 0.8.0
10+
DESCRIPTION "PicoTree is a C++ header only library for fast nearest neighbor searches and range searches using a KdTree."
1111
HOMEPAGE_URL "https://github.com/Jaybro/pico_tree")
1212

1313
if (NOT CMAKE_BUILD_TYPE)
@@ -59,7 +59,7 @@ if(NOT SKBUILD)
5959
${DOC_TARGET_NAME}
6060
src/pico_tree)
6161

62-
message(STATUS "Doxygen found. Documentation can be build as: make ${DOC_TARGET_NAME}")
62+
message(STATUS "Doxygen found. To build the documentation: cmake --build . --target ${DOC_TARGET_NAME}")
6363
else()
6464
message(STATUS "Doxygen not found. Documentation cannot be build.")
6565
endif()

COPYING.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2020,2021,2022 Jonathan Broere
3+
Copyright (c) 2020,2021,2022,2023 Jonathan Broere
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy of
66
this software and associated documentation files (the "Software"), to deal in

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ See the table below to get an impression of the performance provided by the [KdT
1313
| [Scikit-learn KDTree][skkd] 0.22.2 | ... | 12.2s | ... | 44.5s |
1414
| [pykdtree][pykd] 1.3.6 | ... | 1.0s | ... | 6.6s |
1515
| [OpenCV FLANN][cvfn] 4.6.0 | 1.9s | ... | 4.7s | ... |
16-
| PicoTree KdTree v0.7.5 | 0.9s | 1.0s | 2.8s | 3.1s |
16+
| PicoTree KdTree v0.8.0 | 0.9s | 1.0s | 2.8s | 3.1s |
1717

1818
It compares the performance of the build and query algorithms using two [LiDAR](./docs/benchmark.md) based point clouds of sizes 7733372 and 7200863. The first point cloud is used to compare build times and both are used to compare query times. All benchmarks were generated with the following parameters: `max_leaf_size=10`, `knn=1` and `OMP_NUM_THREADS=1`. A more detailed [C++ comparison](./docs/benchmark.md) of PicoTree is available with respect to [nanoflann][nano].
1919

@@ -27,22 +27,27 @@ Available under the [MIT](https://en.wikipedia.org/wiki/MIT_License) license.
2727

2828
# Capabilities
2929

30-
* KdTree
31-
* Nearest neighbors, approximate nearest neighbors, radius, and box searches.
32-
* Customizable nearest neighbor searches, [metrics](https://en.wikipedia.org/wiki/Metric_(mathematics)) and tree splitting techniques.
33-
* Support for topological spaces with identifications. E.g., points on the circle `[-pi, pi]`.
30+
* KdTree:
31+
* Nearest neighbor, approximate nearest neighbor, radius, box, and customizable nearest neighbor searches.
32+
* Multiple tree splitting rules: `kLongestMedian`, `kMidpoint` and `kSlidingMidpoint`.
33+
* [Metrics](https://en.wikipedia.org/wiki/Metric_(mathematics)):
34+
* Support for topological spaces with identifications. E.g., points on the circle `[-pi, pi]`.
35+
* Available metrics: `L1`, `L2Squared`, `SO2`, and `SE2Squared`. Metrics can be customized.
3436
* Compile time and run time known dimensions.
3537
* Static tree builds.
3638
* Thread safe queries.
37-
* PicoTree can interface with different types of points or point sets through a traits class. This can be a custom implementation or one of the traits classes provided by this library:
38-
* `pico_tree::StdTraits<>` supports interfacing with any `std::vector<PointType>`. It requires a specialization of `pico_tree::StdPointTraits<>` for each `PointType`. There are default `pico_tree::StdPointTraits<>` available for Eigen and OpenCV point types.
39-
* `pico_tree::EigenTraits<>` supports interfacing with Eigen matrices.
40-
* `pico_tree::CvTraits<>` supports interfacing with OpenCV matrices.
39+
* PicoTree can interface with different types of points or point sets through traits classes. These can be custom implementations or one of the `pico_tree::PointTraits<>` and `pico_tree::SpaceTraits<>` classes provided by this library. There is default support for the following data types:
40+
* `std::vector<PointType>`.
41+
* A specialization of `pico_tree::PointTraits<>` is required for each `PointType`. There are traits available for Eigen and OpenCV point types.
42+
* `pico_tree::SpaceMap<PointType>` and `pico_tree::PointMap<>`.
43+
* These classes allow interfacing with raw pointers. It is assumed that points and their coordinates are laid out contiguously in memory.
44+
* `Eigen::Matrix` and `Eigen::Map<Eigen::Matrix>`.
45+
* `cv::Mat`.
4146

4247
# Examples
4348

44-
* [Minimal working example](./examples/kd_tree/kd_tree_point_traits.cpp) for building and querying a KdTree using a custom point type.
45-
* Creating a [traits](./examples/kd_tree/kd_tree_traits.cpp) class for a custom type of point set.
49+
* [Minimal working example](./examples/kd_tree/kd_tree_minimal.cpp) using an std::vector of points.
50+
* Creating [traits](./examples/kd_tree/kd_tree_traits.cpp) classes for a custom point and point set.
4651
* Using the KdTree's [search](./examples/kd_tree/kd_tree_search.cpp) options and creating a custom search visitor.
4752
* Support for [Eigen](./examples/eigen/eigen.cpp) and [OpenCV](./examples/opencv/opencv.cpp) data types.
4853
* How to use the [KdTree with Python](./examples/python/kd_tree.py).
@@ -51,7 +56,7 @@ Available under the [MIT](https://en.wikipedia.org/wiki/MIT_License) license.
5156

5257
Minimum:
5358

54-
* A compiler that is compliant with the C++11 standard or higher.
59+
* A compiler that is compliant with the C++17 standard or higher.
5560
* [CMake](https://cmake.org/). It is also possible to just copy and paste the [pico_tree](./src/pico_tree/) directory into an include directory.
5661

5762
Optional:
@@ -60,7 +65,7 @@ Optional:
6065
* [Google Test](https://github.com/google/googletest). Used for running unit tests.
6166
* [Eigen](http://eigen.tuxfamily.org). To run the example that shows how Eigen data types can be used in combination with PicoTree.
6267
* [OpenCV](https://opencv.org/). To run the OpenCV example that shows how to work with OpenCV data types.
63-
* [Google Benchmark](https://github.com/google/benchmark) and a compiler that is compliant with the C++17 standard are needed to run any of the benchmarks. The [nanoflann](https://github.com/jlblancoc/nanoflann) and [OpenCV](https://opencv.org/) benchmarks also require their respective libraries to be installed.
68+
* [Google Benchmark](https://github.com/google/benchmark) is needed to run any of the benchmarks. The [nanoflann](https://github.com/jlblancoc/nanoflann) and [OpenCV](https://opencv.org/) benchmarks also require their respective libraries to be installed.
6469

6570
Python bindings:
6671
* [Python](https://www.python.org/). Version 3.7 or higher.

docs/benchmark.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The different KdTree implementations are compared to each other with respect to
1818
* Nanoflann Midpoint variation.
1919
* PicoTree Sliding Midpoint (along the longest axis).
2020
* Radius search algorithm: The radius in meters divided by 10 (i.e. 1.5m and 3.0m).
21-
* Knn algorithm: The amount of neighbors searched.
21+
* Knn algorithm: The number of neighbors searched.
2222

2323
The running time of the benchmark was kept reasonable by using two subsets of points and storing those in a simple binary format. The final point cloud sizes were as follows:
2424

examples/CMakeLists.txt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,12 @@ else()
2424
message(STATUS "OpenCV not found. OpenCV example skipped.")
2525
endif()
2626

27-
has_cxx_compile_feature(HAS_CPP17_FEATURE cxx_std_17)
2827
find_package(benchmark QUIET)
29-
if(benchmark_FOUND AND ${HAS_CPP17_FEATURE})
30-
message(STATUS "benchmark and C++17 found. Building PicoTree benchmarks.")
28+
if(benchmark_FOUND)
29+
message(STATUS "benchmark found. Building PicoTree benchmarks.")
3130
add_subdirectory(benchmark)
3231
else()
33-
message(STATUS "benchmark or C++17 not found. PicoTree benchmarks skipped.")
32+
message(STATUS "benchmark not found. PicoTree benchmarks skipped.")
3433
endif()
3534

3635
# The Python examples only get copied when the bindings module will be build.

examples/benchmark/CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ endif()
4444
add_executable(uosr_to_bin uosr_to_bin.cpp)
4545
set_default_target_properties(uosr_to_bin)
4646
target_link_libraries(uosr_to_bin PRIVATE pico_toolshed)
47-
# This executable requires <filesystem>
48-
target_compile_features(uosr_to_bin PRIVATE cxx_std_17)
4947

5048
################################################################################
5149
# bin_to_ascii
@@ -54,8 +52,6 @@ target_compile_features(uosr_to_bin PRIVATE cxx_std_17)
5452
add_executable(bin_to_ascii bin_to_ascii.cpp)
5553
set_default_target_properties(bin_to_ascii)
5654
target_link_libraries(bin_to_ascii PRIVATE pico_toolshed)
57-
# This executable requires <filesystem>
58-
target_compile_features(bin_to_ascii PRIVATE cxx_std_17)
5955

6056
################################################################################
6157
# plot_benchmarks

examples/benchmark/benchmark.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include "format_bin.hpp"
66

7-
// It seems that there is a "threshold" to the amount of functions being
7+
// It seems that there is a "threshold" to the number of functions being
88
// benchmarked. Having "too many" of them makes them become slow(er). This
99
// appears to be due to code alignment. See similar issue and video referencing
1010
// that issue:

examples/benchmark/bm_nanoflann.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ BENCHMARK_DEFINE_F(BmNanoflann, KnnCt)(benchmark::State& state) {
7979
std::size_t sum = 0;
8080
for (auto const& p : points_test_) {
8181
benchmark::DoNotOptimize(
82-
sum +=
83-
tree.knnSearch(p.data, knn_count, indices.data(), distances.data()));
82+
sum += tree.knnSearch(
83+
p.data(), knn_count, indices.data(), distances.data()));
8484
}
8585
}
8686
}
@@ -135,7 +135,10 @@ BENCHMARK_DEFINE_F(BmNanoflann, RadiusCt)(benchmark::State& state) {
135135
for (auto const& p : points_test_) {
136136
benchmark::DoNotOptimize(
137137
sum += tree.radiusSearch(
138-
p.data, squared, results, nanoflann::SearchParams{0, 0, false}));
138+
p.data(),
139+
squared,
140+
results,
141+
nanoflann::SearchParams{0, 0, false}));
139142
}
140143
}
141144
}

examples/benchmark/bm_opencv_flann.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,13 @@ struct L2_3D {
5656

5757
} // namespace cvflann
5858

59-
template <typename Scalar, int Dim>
59+
template <typename Scalar, std::size_t Dim>
6060
Scalar* RawCopy(std::vector<Point<Scalar, Dim>> const& points) {
6161
Scalar* copy = new Scalar[points.size() * Dim];
6262
std::copy(
63-
points.begin()->data, points.begin()->data + points.size() * Dim, copy);
63+
points.begin()->data(),
64+
points.begin()->data() + points.size() * Dim,
65+
copy);
6466
return copy;
6567
}
6668

@@ -120,7 +122,7 @@ BENCHMARK_DEFINE_F(BmOpenCvFlann, KnnCt)(benchmark::State& state) {
120122
fl::Matrix<Scalar> mat_distances(distances.data(), 1, knn_count);
121123

122124
for (auto& p : points_test_) {
123-
fl::Matrix<Scalar> query(p.data, 1, 3);
125+
fl::Matrix<Scalar> query(p.data(), 1, 3);
124126
tree.knnSearch(query, mat_indices, mat_distances, knn_count, psearch);
125127
}
126128
}

examples/benchmark/bm_pico_cover_tree.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <pico_toolshed/point.hpp>
22
#include <pico_toolshed/scoped_timer.hpp>
3+
#include <pico_tree/vector_traits.hpp>
34
#include <pico_understory/cover_tree.hpp>
45

56
#include "benchmark.hpp"
@@ -10,11 +11,10 @@ class BmPicoCoverTree : public pico_tree::Benchmark {
1011

1112
// Index explicitly set to int.
1213
template <typename PointX>
13-
using PicoTraits =
14-
pico_tree::StdTraits<std::reference_wrapper<std::vector<PointX>>, int>;
14+
using PicoSpace = std::reference_wrapper<std::vector<PointX>>;
1515

1616
template <typename PointX>
17-
using PicoCoverTree = pico_tree::CoverTree<PicoTraits<PointX>>;
17+
using PicoCoverTree = pico_tree::CoverTree<PicoSpace<PointX>>;
1818

1919
// ****************************************************************************
2020
// Building the tree
@@ -54,7 +54,7 @@ BENCHMARK_DEFINE_F(BmPicoCoverTree, KnnCt)(benchmark::State& state) {
5454
ScopedTimer timer("query_group");
5555
for (; pi < group_end; ++pi) {
5656
auto const& p = points_test_[pi];
57-
tree.SearchKnn(p, knn_count, &results);
57+
tree.SearchKnn(p, knn_count, results);
5858
benchmark::DoNotOptimize(sum += results.size());
5959
}
6060
}

0 commit comments

Comments
 (0)