cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
kdtree_impl.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5#include <vector>
7
8namespace toolbox::pcl
9{
10
11// Generic KD-tree implementation
12template<typename Element, typename Metric>
14{
15 m_data = std::make_shared<container_type>(data);
16 if (validate_metric())
17 {
18 build_tree();
19 }
20 return m_data->size();
21}
22
23template<typename Element, typename Metric>
25{
26 m_data = data;
27 if (m_data && !m_data->empty() && validate_metric())
28 {
29 build_tree();
30 }
31 return m_data ? m_data->size() : 0;
32}
33
34template<typename Element, typename Metric>
36{
37 m_compile_time_metric = metric;
38 m_use_runtime_metric = false;
39 if (m_data && !m_data->empty() && validate_metric())
40 {
41 build_tree();
42 }
43}
44
45template<typename Element, typename Metric>
47 std::shared_ptr<toolbox::metrics::IMetric<value_type>> metric)
48{
49 m_runtime_metric = metric;
50 m_use_runtime_metric = true;
51 // Note: Runtime metrics are not supported by nanoflann KD-tree
52 // This will use brute-force fallback in kneighbors/radius_neighbors
53}
54
55template<typename Element, typename Metric>
57{
58 // nanoflann KD-tree only supports L2 metric efficiently
59 // For other metrics, we would need to fall back to brute-force
60 if (m_use_runtime_metric)
61 {
62 return false; // Runtime metrics not supported by KD-tree
63 }
64
65 // Check if metric is L2 (we can check this at compile time for known metrics)
66 return std::is_same_v<Metric, toolbox::metrics::L2Metric<value_type>>;
67}
68
69template<typename Element, typename Metric>
70void kdtree_generic_t<Element, Metric>::build_tree()
71{
72 if (!m_data || m_data->empty())
73 {
74 m_kdtree.reset();
75 m_adaptor.reset();
76 return;
77 }
78
79 // Create adaptor
80 m_adaptor = std::make_unique<data_adaptor_t>(m_data);
81
82 // Create and build KD-tree
83 m_kdtree = std::make_unique<kd_tree_t>(
84 3, // dimensions
85 *m_adaptor,
86 nanoflann::KDTreeSingleIndexAdaptorParams(m_max_leaf_size)
87 );
88
89 m_kdtree->buildIndex();
90}
91
92template<typename Element, typename Metric>
94 const element_type& query,
95 std::size_t num_neighbors,
96 std::vector<std::size_t>& indices,
97 std::vector<distance_type>& distances)
98{
99 if (!m_data || m_data->empty())
100 {
101 return false;
102 }
103
104 // If metric is not supported by KD-tree, fall back to brute-force
105 if (!validate_metric())
106 {
108 bfknn.set_input(m_data);
109 if (m_use_runtime_metric)
110 {
111 bfknn.set_metric(m_runtime_metric);
112 }
113 else
114 {
115 bfknn.set_metric(m_compile_time_metric);
116 }
117 return bfknn.kneighbors(query, num_neighbors, indices, distances);
118 }
119
120 if (!m_kdtree)
121 {
122 return false;
123 }
124
125 const std::size_t data_size = m_data->size();
126 num_neighbors = std::min(num_neighbors, data_size);
127
128 // Prepare query point
129 value_type query_pt[3] = {query.x, query.y, query.z};
130
131 // Search
132 indices.resize(num_neighbors);
133 distances.resize(num_neighbors);
134
135 m_kdtree->knnSearch(
136 &query_pt[0],
137 num_neighbors,
138 &indices[0],
139 &distances[0]
140 );
141
142 // nanoflann returns squared distances for L2, so we need to take square root
143 if (std::is_same_v<Metric, toolbox::metrics::L2Metric<value_type>>)
144 {
145 for (auto& dist : distances)
146 {
147 dist = std::sqrt(dist);
148 }
149 }
150
151 return true;
152}
153
154template<typename Element, typename Metric>
156 const element_type& query,
157 distance_type radius,
158 std::vector<std::size_t>& indices,
159 std::vector<distance_type>& distances)
160{
161 if (!m_data || m_data->empty() || radius <= 0)
162 {
163 return false;
164 }
165
166 // If metric is not supported by KD-tree, fall back to brute-force
167 if (!validate_metric())
168 {
170 bfknn.set_input(m_data);
171 if (m_use_runtime_metric)
172 {
173 bfknn.set_metric(m_runtime_metric);
174 }
175 else
176 {
177 bfknn.set_metric(m_compile_time_metric);
178 }
179 return bfknn.radius_neighbors(query, radius, indices, distances);
180 }
181
182 if (!m_kdtree)
183 {
184 return false;
185 }
186
187 indices.clear();
188 distances.clear();
189
190 // Prepare query point
191 value_type query_pt[3] = {query.x, query.y, query.z};
192
193 // For L2 metric, nanoflann expects squared radius
194 distance_type search_radius = radius;
195 if (std::is_same_v<Metric, toolbox::metrics::L2Metric<value_type>>)
196 {
197 search_radius = radius * radius;
198 }
199
200 // Search
201 std::vector<nanoflann::ResultItem<std::size_t, distance_type>> matches;
202 const std::size_t num_matches = m_kdtree->radiusSearch(
203 &query_pt[0],
204 search_radius,
205 matches,
206 nanoflann::SearchParameters()
207 );
208
209 // Extract results
210 indices.reserve(num_matches);
211 distances.reserve(num_matches);
212
213 for (const auto& match : matches)
214 {
215 indices.push_back(match.first);
216 distance_type dist = match.second;
217
218 // nanoflann returns squared distances for L2
219 if (std::is_same_v<Metric, toolbox::metrics::L2Metric<value_type>>)
220 {
221 dist = std::sqrt(dist);
222 }
223
224 distances.push_back(dist);
225 }
226
227 return true;
228}
229
230} // namespace toolbox::pcl
Definition metric_factory.hpp:23
Definition vector_metrics.hpp:18
bool kneighbors(const element_type &query, std::size_t num_neighbors, std::vector< std::size_t > &indices, std::vector< distance_type > &distances)
K近邻搜索 / K-nearest neighbors search.
Definition base_knn.hpp:179
void set_metric(const metric_type &metric)
设置度量方式(编译时版本) / Set metric (compile-time version)
Definition base_knn.hpp:129
bool radius_neighbors(const element_type &query, distance_type radius, std::vector< std::size_t > &indices, std::vector< distance_type > &distances)
半径近邻搜索 / Radius neighbors search
Definition base_knn.hpp:208
std::size_t set_input(const container_type &data)
设置输入数据 / Set input data
Definition base_knn.hpp:83
暴力K近邻搜索算法的通用实现 / Generic brute-force K-nearest neighbors search implementation
Definition bfknn.hpp:45
Definition kdtree.hpp:14
typename base_type::container_ptr container_ptr
Definition kdtree.hpp:22
void set_metric_impl(const metric_type &metric)
Definition kdtree_impl.hpp:35
typename traits_type::distance_type distance_type
Definition kdtree.hpp:20
bool kneighbors_impl(const element_type &query, std::size_t num_neighbors, std::vector< std::size_t > &indices, std::vector< distance_type > &distances)
Definition kdtree_impl.hpp:93
typename base_type::container_type container_type
Definition kdtree.hpp:21
typename traits_type::element_type element_type
Definition kdtree.hpp:18
typename Element::value_type value_type
Definition kdtree.hpp:23
bool radius_neighbors_impl(const element_type &query, distance_type radius, std::vector< std::size_t > &indices, std::vector< distance_type > &distances)
Definition kdtree_impl.hpp:155
std::size_t set_input_impl(const container_type &data)
Definition kdtree_impl.hpp:13
typename traits_type::metric_type metric_type
Definition kdtree.hpp:19
Definition base_correspondence_generator.hpp:18