cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
point_utils.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm> // For std::generate_n, std::min, std::max
4#include <cmath> // For std::ceil
5#include <functional> // For std::ref if needed
6#include <future> // For std::future
7#include <iterator> // For std::back_inserter
8#include <random>
9#include <thread> // For std::thread::hardware_concurrency (used indirectly via default_pool)
10#include <vector>
11
12#include <cpp-toolbox/cpp-toolbox_export.hpp> // For CPP_TOOLBOX_EXPORT
13#include <cpp-toolbox/logger/thread_logger.hpp> // For LOG_* macros
14#include <cpp-toolbox/types/minmax.hpp> // Needs minmax_t definition (and includes parallel.hpp)
15#include <cpp-toolbox/types/point.hpp> // Needs point_t definition
16#include <cpp-toolbox/concurrent/parallel.hpp> // For parallel_for_each
17#include <Eigen/Core> // For Matrix operations
18
19namespace toolbox::types
20{
21
45template<typename T>
46CPP_TOOLBOX_EXPORT auto generate_random_points(
47 const std::size_t& num_points, const minmax_t<point_t<T>>& minmax)
48 -> std::vector<point_t<T>>
49{
50 std::vector<point_t<T>> points;
51 points.reserve(num_points);
52
53 std::random_device rd;
54 std::mt19937 gen(rd());
55
56 std::uniform_real_distribution<T> dist_x(minmax.min.x, minmax.max.x);
57 std::uniform_real_distribution<T> dist_y(minmax.min.y, minmax.max.y);
58 std::uniform_real_distribution<T> dist_z(minmax.min.z, minmax.max.z);
59
60 std::generate_n(
61 std::back_inserter(points),
62 num_points,
63 [&]() { return point_t<T>(dist_x(gen), dist_y(gen), dist_z(gen)); });
64
65 return points;
66}
67
95template<typename T>
96CPP_TOOLBOX_EXPORT auto generate_random_points_parallel(
97 const std::size_t& num_points, const minmax_t<point_t<T>>& minmax)
98 -> std::vector<point_t<T>>
99{
100 LOG_DEBUG_S << "Generating " << num_points << " points in parallel.";
101 if (num_points == 0) {
102 return {};
103 }
104
105 // 预分配整个向量以避免并行任务中的调整大小 / Pre-allocate the entire vector
106 // to avoid resizing in parallel tasks
107 std::vector<point_t<T>> points(num_points);
108
109 // --- 使用线程池的并行执行逻辑 / Parallel execution logic using thread pool
110 // ---
112 const size_t num_threads = pool.get_thread_count();
113 const size_t hardware_threads =
114 std::max(1u, std::thread::hardware_concurrency());
115
116 // 定义分块策略(根据性能测试调整参数) / Define chunking strategy (adjust
117 // parameters based on performance testing)
118 const size_t min_chunk_size =
119 1024; // 每个任务的最小点数 / Minimum points per task
120 const size_t max_tasks = std::max(
121 static_cast<size_t>(1), std::max(num_threads, hardware_threads) * 4);
122 size_t chunk_size =
123 std::max(min_chunk_size,
124 static_cast<size_t>(
125 std::ceil(static_cast<double>(num_points) / max_tasks)));
126 size_t num_tasks = static_cast<size_t>(
127 std::ceil(static_cast<double>(num_points) / chunk_size));
128 if (num_tasks == 0 && num_points > 0)
129 num_tasks = 1; // 如果num_points > 0,确保至少有一个任务 / Ensure at least
130 // one task if num_points > 0
131
132 std::vector<std::future<void>> futures;
133 futures.reserve(num_tasks);
134
135 std::random_device rd;
136 unsigned int base_seed =
137 rd(); // 生成基础种子以确保线程间的可重现性 / Generate a base seed for
138 // reproducibility across threads
139
140 LOG_DEBUG_S << "Parallel generation using " << num_tasks
141 << " tasks with chunk size ~" << chunk_size;
142
143 size_t start_idx = 0;
144 for (size_t i = 0; i < num_tasks; ++i) {
145 size_t remaining_size = num_points - start_idx;
146 size_t current_chunk_actual_size = std::min(chunk_size, remaining_size);
147 if (current_chunk_actual_size == 0)
148 break; // 如果逻辑正确则不应发生 / Should not happen if logic is correct
149 size_t end_idx = start_idx + current_chunk_actual_size;
150
151 // 向线程池提交任务 / Submit task to the thread pool
152 futures.emplace_back(pool.submit(
153 // 通过值/引用捕获必要的变量 / Capture necessary variables by
154 // value/reference 'points'通过引用捕获 - 由于预分配和索引访问是安全的 /
155 // 'points' is captured by reference - safe due to pre-allocation and
156 // indexed access 'minmax'通过引用捕获(const) / 'minmax' captured by
157 // reference (const)
158 [start_idx, end_idx, &points, &minmax, base_seed, task_id = i]()
159 {
160 // --- 线程本地设置 / Thread-local setup ---
161 // 必须为每个任务/线程创建分布,因为它们可能保持状态 / Distributions
162 // must be created per task/thread as they might hold state
163 std::uniform_real_distribution<T> dist_x(minmax.min.x, minmax.max.x);
164 std::uniform_real_distribution<T> dist_y(minmax.min.y, minmax.max.y);
165 std::uniform_real_distribution<T> dist_z(minmax.min.z, minmax.max.z);
166
167 // 每个任务/线程的随机数生成器使用唯一种子 / Per-task/thread random
168 // number generator seeded uniquely 组合基础种子和任务ID提供变化 /
169 // Combining base seed and task ID provides variation
170 std::mt19937 gen(base_seed + static_cast<unsigned int>(task_id));
171
172 // 可选:记录任务开始(可能很详细) / Optional: Log task start (can be
173 // verbose) LOG_TRACE_S << "Task " << task_id << ": Generating points
174 // [" << start_idx << ", " << end_idx << ")";
175
176 // --- 为这个块生成点 / Generate points for this chunk ---
177 for (size_t k = start_idx; k < end_idx; ++k) {
178 // 直接赋值到预分配的向量元素 / Direct assignment to the
179 // pre-allocated vector element
180 points[k] = point_t<T>(dist_x(gen), dist_y(gen), dist_z(gen));
181 }
182 }));
183 start_idx = end_idx; // 移动到下一个块的开始 / Move to the next chunk start
184 }
185
186 // 等待所有任务完成并处理潜在的异常 / Wait for all tasks to complete and
187 // handle potential exceptions
188 try {
189 for (auto& fut : futures) {
190 fut.get(); // `.get()`等待并重新抛出任务中发生的异常 / `.get()` waits and
191 // rethrows exceptions if any occurred in the task
192 }
193 } catch (const std::exception& e) {
194 LOG_ERROR_S << "Exception during parallel point generation: " << e.what();
195 // 根据错误处理策略,可以清除点、重新抛出等 / Depending on error handling
196 // strategy, could clear points, rethrow, etc. 重新抛出通常是合适的 /
197 // Rethrowing is often appropriate
198 throw;
199 } catch (...) {
200 LOG_ERROR_S << "Unknown exception during parallel point generation.";
201 throw;
202 }
203
204 LOG_DEBUG_S << "Finished parallel generation of " << points.size()
205 << " points.";
206 return points;
207}
208
228template<typename T>
229CPP_TOOLBOX_EXPORT auto transform_point_cloud(
230 const point_cloud_t<T>& cloud,
231 const Eigen::Matrix<T, 4, 4>& transform) -> point_cloud_t<T>
232{
233 point_cloud_t<T> transformed;
234 transformed.points.reserve(cloud.size());
235
236 // 提取旋转和平移部分 / Extract rotation and translation parts
237 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
238 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
239
240 for (const auto& pt : cloud.points) {
241 Eigen::Matrix<T, 3, 1> src_vec(pt.x, pt.y, pt.z);
242 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
243 transformed.points.emplace_back(
244 transformed_vec[0], transformed_vec[1], transformed_vec[2]);
245 }
246
247 return transformed;
248}
249
268template<typename T>
269CPP_TOOLBOX_EXPORT auto transform_point_cloud_parallel(
270 const point_cloud_t<T>& cloud,
271 const Eigen::Matrix<T, 4, 4>& transform) -> point_cloud_t<T>
272{
273 if (cloud.empty()) {
274 return point_cloud_t<T>{};
275 }
276
277 LOG_DEBUG_S << "Transforming " << cloud.size() << " points in parallel.";
278
279 // 预分配输出向量 / Pre-allocate output vector
280 point_cloud_t<T> transformed;
281 transformed.points.resize(cloud.size());
282
283 // 提取旋转和平移部分 / Extract rotation and translation parts
284 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
285 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
286
287 // 使用线程池并行处理 / Process in parallel using thread pool
289 const size_t num_threads = pool.get_thread_count();
290 const size_t hardware_threads = std::max(1u, std::thread::hardware_concurrency());
291
292 // 定义分块策略 / Define chunking strategy
293 const size_t min_chunk_size = 1024; // 每个任务的最小点数 / Minimum points per task
294 const size_t max_tasks = std::max(static_cast<size_t>(1),
295 std::max(num_threads, hardware_threads) * 4);
296 size_t chunk_size = std::max(min_chunk_size,
297 static_cast<size_t>(std::ceil(
298 static_cast<double>(cloud.size()) / max_tasks)));
299 size_t num_tasks = static_cast<size_t>(
300 std::ceil(static_cast<double>(cloud.size()) / chunk_size));
301
302 if (num_tasks == 0 && cloud.size() > 0) {
303 num_tasks = 1;
304 }
305
306 std::vector<std::future<void>> futures;
307 futures.reserve(num_tasks);
308
309 LOG_DEBUG_S << "Parallel transformation using " << num_tasks
310 << " tasks with chunk size ~" << chunk_size;
311
312 size_t start_idx = 0;
313 for (size_t i = 0; i < num_tasks; ++i) {
314 size_t remaining_size = cloud.size() - start_idx;
315 size_t current_chunk_size = std::min(chunk_size, remaining_size);
316 if (current_chunk_size == 0) break;
317 size_t end_idx = start_idx + current_chunk_size;
318
319 // 提交任务到线程池 / Submit task to thread pool
320 futures.emplace_back(pool.submit(
321 [start_idx, end_idx, &cloud, &transformed, &rotation, &translation]() {
322 for (size_t k = start_idx; k < end_idx; ++k) {
323 const auto& src_pt = cloud.points[k];
324 Eigen::Matrix<T, 3, 1> src_vec(src_pt.x, src_pt.y, src_pt.z);
325 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
326 transformed.points[k] = point_t<T>(
327 transformed_vec[0], transformed_vec[1], transformed_vec[2]);
328 }
329 }));
330
331 start_idx = end_idx;
332 }
333
334 // 等待所有任务完成 / Wait for all tasks to complete
335 try {
336 for (auto& fut : futures) {
337 fut.get();
338 }
339 } catch (const std::exception& e) {
340 LOG_ERROR_S << "Exception during parallel point cloud transformation: " << e.what();
341 throw;
342 } catch (...) {
343 LOG_ERROR_S << "Unknown exception during parallel point cloud transformation.";
344 throw;
345 }
346
347 LOG_DEBUG_S << "Finished parallel transformation of " << transformed.size() << " points.";
348 return transformed;
349}
350
366template<typename T>
367CPP_TOOLBOX_EXPORT void transform_point_cloud_inplace(
368 point_cloud_t<T>& cloud,
369 const Eigen::Matrix<T, 4, 4>& transform)
370{
371 // 提取旋转和平移部分 / Extract rotation and translation parts
372 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
373 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
374
375 for (auto& pt : cloud.points) {
376 Eigen::Matrix<T, 3, 1> src_vec(pt.x, pt.y, pt.z);
377 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
378 pt.x = transformed_vec[0];
379 pt.y = transformed_vec[1];
380 pt.z = transformed_vec[2];
381 }
382}
383
399template<typename T>
401 point_cloud_t<T>& cloud,
402 const Eigen::Matrix<T, 4, 4>& transform)
403{
404 if (cloud.empty()) {
405 return;
406 }
407
408 // 提取旋转和平移部分 / Extract rotation and translation parts
409 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
410 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
411
412 // 使用 parallel_for_each 简化实现 / Use parallel_for_each to simplify implementation
414 cloud.points.begin(), cloud.points.end(),
415 [&rotation, &translation](point_t<T>& pt) {
416 Eigen::Matrix<T, 3, 1> src_vec(pt.x, pt.y, pt.z);
417 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
418 pt.x = transformed_vec[0];
419 pt.y = transformed_vec[1];
420 pt.z = transformed_vec[2];
421 });
422}
423
424} // namespace toolbox::types
包含点和相关数据的点云类 / A point cloud class containing points and associated data
Definition point.hpp:268
std::vector< point_t< T > > points
点坐标 / Point coordinates
Definition point.hpp:270
auto size() const -> std::size_t
获取点云中的点数 / Get number of points in cloud
Definition point_impl.hpp:293
auto empty() const -> bool
检查点云是否为空 / Check if cloud is empty
Definition point_impl.hpp:299
#define LOG_DEBUG_S
DEBUG级别流式日志的宏 / Macro for DEBUG level stream logging.
Definition thread_logger.hpp:1329
#define LOG_ERROR_S
ERROR级别流式日志的宏 / Macro for ERROR level stream logging.
Definition thread_logger.hpp:1332
void parallel_for_each(Iterator begin, Iterator end, Function func)
使用TBB并行对范围[begin, end)中的每个元素应用函数
Definition parallel_raw.hpp:21
base::thread_pool_singleton_t & default_pool()
获取默认线程池实例/Get the default thread pool instance
Definition parallel.hpp:22
Definition minmax_impl.hpp:21
CPP_TOOLBOX_EXPORT auto generate_random_points_parallel(const std::size_t &num_points, const minmax_t< point_t< T > > &minmax) -> std::vector< point_t< T > >
在给定边界内并行生成随机点 / Generates random points within given bounds in parallel
Definition point_utils.hpp:96
CPP_TOOLBOX_EXPORT auto transform_point_cloud_parallel(const point_cloud_t< T > &cloud, const Eigen::Matrix< T, 4, 4 > &transform) -> point_cloud_t< T >
对点云应用变换矩阵(并行版本)/ Apply transformation matrix to point cloud (parallel version)
Definition point_utils.hpp:269
CPP_TOOLBOX_EXPORT auto generate_random_points(const std::size_t &num_points, const minmax_t< point_t< T > > &minmax) -> std::vector< point_t< T > >
在给定边界内顺序生成随机点 / Generates random points within given bounds sequentially
Definition point_utils.hpp:46
CPP_TOOLBOX_EXPORT void transform_point_cloud_inplace(point_cloud_t< T > &cloud, const Eigen::Matrix< T, 4, 4 > &transform)
原地变换点云(顺序版本)/ Transform point cloud in-place (sequential version)
Definition point_utils.hpp:367
CPP_TOOLBOX_EXPORT void transform_point_cloud_inplace_parallel(point_cloud_t< T > &cloud, const Eigen::Matrix< T, 4, 4 > &transform)
原地变换点云(并行版本)/ Transform point cloud in-place (parallel version)
Definition point_utils.hpp:400
存储和计算最小最大值的主模板类 / Primary template class for storing and calculating minimum and maximum values
Definition minmax.hpp:92
3D点/向量模板类 / A 3D point/vector template class
Definition point.hpp:48