Skip to content

Commit 278ede5

Browse files
refactor: remove legacy KNN API and add comprehensive documentation
- Remove all legacy KNN classes and metric_type_t enum - Convert legacy classes to type aliases for easier migration - Update all features and descriptors to use generic KNN API - Fix runtime metric usage with IMetric interface - Add operator() overloads for CosineMetric and AngularMetric - Update all tests and benchmarks to use new API - Add comprehensive Doxygen documentation for: - KNN algorithms (base_knn, bfknn, bfknn_parallel, kdtree) - Normal extraction algorithms (base_norm, pca_norm) - Descriptor extraction base classes - All documentation includes Chinese/English bilingual comments - Create unified export headers: - knn/knn.hpp: Unified interface for all KNN algorithms - norm/norm.hpp: Unified interface for normal extraction - descriptors/descriptors.hpp: Unified interface for descriptor extraction - Include usage examples and algorithm selection guides This completes the migration to the new metrics infrastructure, making the codebase more unified and flexible. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e8b2483 commit 278ede5

Some content is hidden

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

42 files changed

+1277
-617
lines changed

benchmark/pcl/knn_benc.cpp

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -157,40 +157,6 @@ TEST_CASE("KNN Benchmark - Different Metrics", "[pcl][knn][benchmark]")
157157
auto cloud = generate_benchmark_cloud<scalar_t>(cloud_size);
158158
auto queries = generate_query_points<scalar_t>(num_queries);
159159

160-
SECTION("Legacy interface metrics")
161-
{
162-
auto knn = std::make_unique<bfknn_t<scalar_t>>();
163-
knn->set_input(cloud);
164-
165-
std::vector<metric_type_t> metrics = {
166-
metric_type_t::euclidean,
167-
metric_type_t::manhattan,
168-
metric_type_t::chebyshev,
169-
metric_type_t::minkowski
170-
};
171-
172-
std::vector<std::string> metric_names = {
173-
"Euclidean",
174-
"Manhattan",
175-
"Chebyshev",
176-
"Minkowski"
177-
};
178-
179-
for (std::size_t i = 0; i < metrics.size(); ++i)
180-
{
181-
knn->set_metric(metrics[i]);
182-
183-
BENCHMARK("BruteForce " + metric_names[i] + " - " + std::to_string(cloud_size) + " points")
184-
{
185-
std::vector<std::size_t> indices;
186-
std::vector<scalar_t> distances;
187-
for (const auto& query : queries)
188-
{
189-
knn->kneighbors(query, k, indices, distances);
190-
}
191-
};
192-
}
193-
}
194160

195161
SECTION("Generic interface metrics")
196162
{
@@ -272,8 +238,8 @@ TEST_CASE("KNN Benchmark - Different Metrics", "[pcl][knn][benchmark]")
272238
bfknn_generic_t<point_t<scalar_t>, L2Metric<scalar_t>> knn;
273239
knn.set_input(points);
274240

275-
auto metric = MetricFactory<scalar_t>::create("L2");
276-
knn.set_metric(metric);
241+
auto metric = MetricFactory<scalar_t>::instance().create("L2");
242+
knn.set_metric(std::move(metric));
277243

278244
std::vector<std::size_t> indices;
279245
std::vector<scalar_t> distances;
@@ -288,8 +254,8 @@ TEST_CASE("KNN Benchmark - Different Metrics", "[pcl][knn][benchmark]")
288254
bfknn_generic_t<point_t<scalar_t>, L2Metric<scalar_t>> knn;
289255
knn.set_input(points);
290256

291-
auto metric = MetricFactory<scalar_t>::create("L1");
292-
knn.set_metric(metric);
257+
auto metric = MetricFactory<scalar_t>::instance().create("L1");
258+
knn.set_metric(std::move(metric));
293259

294260
std::vector<std::size_t> indices;
295261
std::vector<scalar_t> distances;
@@ -317,9 +283,9 @@ TEST_CASE("KNN Benchmark - Radius Neighbors", "[pcl][knn][benchmark]")
317283
auto bfknn_parallel = std::make_unique<bfknn_parallel_t<scalar_t>>();
318284
auto kdtree = std::make_unique<kdtree_t<scalar_t>>();
319285

320-
bfknn->set_input(cloud);
321-
bfknn_parallel->set_input(cloud);
322-
kdtree->set_input(cloud);
286+
bfknn->set_input(cloud.points);
287+
bfknn_parallel->set_input(cloud.points);
288+
kdtree->set_input(cloud.points);
323289

324290
BENCHMARK("BruteForce Radius Search - " + std::to_string(cloud_size) + " points")
325291
{
@@ -364,7 +330,7 @@ TEST_CASE("KNN Benchmark - Parallel Scaling", "[pcl][knn][benchmark]")
364330
auto queries = generate_query_points<scalar_t>(num_queries);
365331

366332
auto bfknn_parallel = std::make_unique<bfknn_parallel_t<scalar_t>>();
367-
bfknn_parallel->set_input(cloud);
333+
bfknn_parallel->set_input(cloud.points);
368334

369335
BENCHMARK("Parallel Enabled - " + std::to_string(cloud_size) + " points")
370336
{
@@ -401,11 +367,11 @@ TEST_CASE("KNN Benchmark - KDTree Fallback for Metrics", "[pcl][knn][benchmark]"
401367
auto queries = generate_query_points<scalar_t>(num_queries);
402368

403369
auto kdtree = std::make_unique<kdtree_t<scalar_t>>();
404-
kdtree->set_input(cloud);
370+
kdtree->set_input(cloud.points);
405371

406372
BENCHMARK("KDTree with Euclidean (Native)")
407373
{
408-
kdtree->set_metric(metric_type_t::euclidean);
374+
// KDTree uses L2 metric by default
409375
std::vector<std::size_t> indices;
410376
std::vector<scalar_t> distances;
411377
for (const auto& query : queries)
@@ -414,9 +380,10 @@ TEST_CASE("KNN Benchmark - KDTree Fallback for Metrics", "[pcl][knn][benchmark]"
414380
}
415381
};
416382

417-
BENCHMARK("KDTree with Manhattan (Fallback)")
383+
BENCHMARK("KDTree with L1 (Fallback)")
418384
{
419-
kdtree->set_metric(metric_type_t::manhattan);
385+
auto metric_l1 = MetricFactory<scalar_t>::instance().create("l1");
386+
kdtree->set_metric(std::move(metric_l1));
420387
std::vector<std::size_t> indices;
421388
std::vector<scalar_t> distances;
422389
for (const auto& query : queries)

src/include/cpp-toolbox/metrics/angular_metrics.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ class CosineMetric : public base_metric_t<CosineMetric<T>, T>
5151
T dist = distance_impl(a, b, size);
5252
return dist * dist;
5353
}
54+
55+
// Overload for point_t types
56+
template<typename U>
57+
constexpr auto operator()(const toolbox::types::point_t<U>& a,
58+
const toolbox::types::point_t<U>& b) const
59+
{
60+
T arr_a[3] = {static_cast<T>(a.x), static_cast<T>(a.y), static_cast<T>(a.z)};
61+
T arr_b[3] = {static_cast<T>(b.x), static_cast<T>(b.y), static_cast<T>(b.z)};
62+
return distance_impl(arr_a, arr_b, 3);
63+
}
5464
};
5565

5666
template<typename T>
@@ -94,6 +104,16 @@ class AngularMetric : public base_metric_t<AngularMetric<T>, T>
94104
T dist = distance_impl(a, b, size);
95105
return dist * dist;
96106
}
107+
108+
// Overload for point_t types
109+
template<typename U>
110+
constexpr auto operator()(const toolbox::types::point_t<U>& a,
111+
const toolbox::types::point_t<U>& b) const
112+
{
113+
T arr_a[3] = {static_cast<T>(a.x), static_cast<T>(a.y), static_cast<T>(a.z)};
114+
T arr_b[3] = {static_cast<T>(b.x), static_cast<T>(b.y), static_cast<T>(b.z)};
115+
return distance_impl(arr_a, arr_b, 3);
116+
}
97117
};
98118

99119
// Normalized angular distance (scaled to [0, 1])

src/include/cpp-toolbox/pcl/descriptors/3dsc_extractor.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
#include <cpp-toolbox/concurrent/parallel.hpp>
88
#include <cpp-toolbox/pcl/descriptors/base_descriptor_extractor.hpp>
9+
#include <cpp-toolbox/pcl/knn/kdtree.hpp>
910
#include <cpp-toolbox/pcl/norm/pca_norm.hpp>
1011
#include <cpp-toolbox/types/point.hpp>
12+
#include <cpp-toolbox/metrics/vector_metrics.hpp>
1113

1214
namespace toolbox::pcl
1315
{
@@ -29,7 +31,8 @@ struct dsc3d_signature_t : public base_signature_t<DataType, dsc3d_signature_t<D
2931
}
3032
};
3133

32-
template<typename DataType, typename KNN>
34+
template<typename DataType,
35+
typename KNN = kdtree_generic_t<point_t<DataType>, toolbox::metrics::L2Metric<DataType>>>
3336
class dsc3d_extractor_t
3437
: public base_descriptor_extractor_t<dsc3d_extractor_t<DataType, KNN>,
3538
DataType,

src/include/cpp-toolbox/pcl/descriptors/base_descriptor_extractor.hpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,84 @@
88
namespace toolbox::pcl
99
{
1010

11+
/**
12+
* @brief 描述子签名的基类 / Base class for descriptor signatures
13+
*
14+
* 该类定义了所有描述子签名类型的通用接口,主要提供距离计算功能。
15+
* This class defines the common interface for all descriptor signature types,
16+
* mainly providing distance calculation functionality.
17+
*
18+
* @tparam DataType 数据类型(如float或double) / Data type (e.g., float or double)
19+
* @tparam Derived 派生的签名类型 / Derived signature type
20+
*
21+
* @code
22+
* // 自定义描述子签名示例 / Custom descriptor signature example
23+
* struct my_signature_t : base_signature_t<float, my_signature_t> {
24+
* std::array<float, 128> histogram;
25+
*
26+
* float distance_impl(const my_signature_t& other) const {
27+
* float dist = 0;
28+
* for (size_t i = 0; i < 128; ++i) {
29+
* dist += std::abs(histogram[i] - other.histogram[i]);
30+
* }
31+
* return dist;
32+
* }
33+
* };
34+
* @endcode
35+
*/
1136
template<typename DataType, class Derived>
1237
struct base_signature_t
1338
{
1439
using data_type = DataType;
1540
using derived_type = Derived;
1641

42+
/**
43+
* @brief 计算与另一个签名的距离 / Calculate distance to another signature
44+
* @param other 另一个签名 / Another signature
45+
* @return 距离值 / Distance value
46+
*/
1747
DataType distance(const Derived& other) const
1848
{
1949
return static_cast<const Derived*>(this)->distance_impl(other);
2050
}
2151
}; // struct base_signature_t
2252

53+
/**
54+
* @brief 描述子提取器的基类(CRTP模式) / Base class for descriptor extractors (CRTP pattern)
55+
*
56+
* 该类定义了所有描述子提取算法的通用接口。描述子是用于描述点云局部特征的向量,
57+
* 常用于物体识别、配准、分类等任务。
58+
* This class defines the common interface for all descriptor extraction algorithms.
59+
* Descriptors are vectors that describe local features of point clouds, commonly
60+
* used for object recognition, registration, classification, and other tasks.
61+
*
62+
* @tparam Derived 派生的提取器类型 / Derived extractor type
63+
* @tparam DataType 数据类型(如float或double) / Data type (e.g., float or double)
64+
* @tparam Signature 描述子签名类型 / Descriptor signature type
65+
*
66+
* @code
67+
* // 使用描述子提取器的示例 / Example of using descriptor extractor
68+
* fpfh_extractor_t<float> extractor;
69+
* extractor.set_search_radius(0.05f);
70+
*
71+
* // 在关键点处计算描述子 / Compute descriptors at keypoints
72+
* std::vector<fpfh_signature_t<float>> descriptors;
73+
* extractor.compute(cloud, keypoint_indices, descriptors);
74+
*
75+
* // 使用描述子进行匹配 / Use descriptors for matching
76+
* for (size_t i = 0; i < descriptors.size(); ++i) {
77+
* float min_dist = std::numeric_limits<float>::max();
78+
* size_t best_match = 0;
79+
* for (size_t j = 0; j < target_descriptors.size(); ++j) {
80+
* float dist = descriptors[i].distance(target_descriptors[j]);
81+
* if (dist < min_dist) {
82+
* min_dist = dist;
83+
* best_match = j;
84+
* }
85+
* }
86+
* }
87+
* @endcode
88+
*/
2389
template<class Derived, typename DataType, typename Signature>
2490
class base_descriptor_extractor_t
2591
{
@@ -33,11 +99,31 @@ class base_descriptor_extractor_t
3399
default;
34100
virtual ~base_descriptor_extractor_t() = default;
35101

102+
/**
103+
* @brief 启用或禁用并行计算 / Enable or disable parallel computation
104+
* @param enable true启用并行,false禁用 / true to enable parallel, false to disable
105+
*/
36106
void enable_parallel(bool enable)
37107
{
38108
static_cast<Derived*>(this)->enable_parallel_impl(enable);
39109
}
40110

111+
/**
112+
* @brief 计算指定关键点的描述子 / Compute descriptors at specified keypoints
113+
* @param cloud 输入点云 / Input point cloud
114+
* @param keypoint_indices 关键点索引列表 / List of keypoint indices
115+
* @param descriptors [out] 输出描述子向量 / Output descriptor vector
116+
*
117+
* @code
118+
* // 计算所有关键点的描述子 / Compute descriptors for all keypoints
119+
* std::vector<size_t> keypoint_indices = detect_keypoints(cloud);
120+
* std::vector<fpfh_signature_t<float>> descriptors;
121+
* extractor.compute(cloud, keypoint_indices, descriptors);
122+
*
123+
* std::cout << "计算了 / Computed " << descriptors.size()
124+
* << " 个描述子 / descriptors" << std::endl;
125+
* @endcode
126+
*/
41127
void compute(const toolbox::types::point_cloud_t<DataType>& cloud,
42128
const std::vector<std::size_t>& keypoint_indices,
43129
std::vector<Signature>& descriptors)
@@ -46,6 +132,12 @@ class base_descriptor_extractor_t
46132
cloud, keypoint_indices, descriptors);
47133
}
48134

135+
/**
136+
* @brief 计算指定关键点的描述子(智能指针版本) / Compute descriptors at specified keypoints (smart pointer version)
137+
* @param cloud 输入点云 / Input point cloud
138+
* @param keypoint_indices 关键点索引列表 / List of keypoint indices
139+
* @param descriptors [out] 输出描述子向量的智能指针 / Smart pointer to output descriptor vector
140+
*/
49141
void compute(const toolbox::types::point_cloud_t<DataType>& cloud,
50142
const std::vector<std::size_t>& keypoint_indices,
51143
std::unique_ptr<std::vector<Signature>> descriptors)

src/include/cpp-toolbox/pcl/descriptors/cvfh_extractor.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
#include <cpp-toolbox/concurrent/parallel.hpp>
88
#include <cpp-toolbox/pcl/descriptors/base_descriptor_extractor.hpp>
9+
#include <cpp-toolbox/pcl/knn/kdtree.hpp>
910
#include <cpp-toolbox/pcl/norm/pca_norm.hpp>
1011
#include <cpp-toolbox/types/point.hpp>
12+
#include <cpp-toolbox/metrics/vector_metrics.hpp>
1113

1214
namespace toolbox::pcl
1315
{
@@ -29,7 +31,8 @@ struct cvfh_signature_t : public base_signature_t<DataType, cvfh_signature_t<Dat
2931
}
3032
};
3133

32-
template<typename DataType, typename KNN>
34+
template<typename DataType,
35+
typename KNN = kdtree_generic_t<point_t<DataType>, toolbox::metrics::L2Metric<DataType>>>
3336
class cvfh_extractor_t
3437
: public base_descriptor_extractor_t<cvfh_extractor_t<DataType, KNN>,
3538
DataType,

0 commit comments

Comments
 (0)