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/core/export.hpp> // For CPP_TOOLBOX_EXPORT
13#include <iostream>
14
15// Algorithms report failures through their return values; keep diagnostics
16// available without coupling this low-level module to logging.
17#ifndef LOG_DEBUG_S
18# define LOG_DEBUG_S std::clog
19#endif
20#ifndef LOG_ERROR_S
21# define LOG_ERROR_S std::clog
22#endif
23#include <cpp-toolbox/geometry_algorithms/minmax.hpp> // Needs minmax_t definition (and includes parallel.hpp)
24#include <cpp-toolbox/geometry/point.hpp> // Needs point_t definition
25#include <cpp-toolbox/concurrency/parallel.hpp> // For parallel_for_each
26#include <Eigen/Core> // For Matrix operations
27
28namespace toolbox::types
29{
30
54template<typename T>
56 const std::size_t& num_points, const minmax_t<point_t<T>>& minmax)
57 -> std::vector<point_t<T>>
58{
59 std::vector<point_t<T>> points;
60 points.reserve(num_points);
61
62 std::random_device rd;
63 std::mt19937 gen(rd());
64
65 std::uniform_real_distribution<T> dist_x(minmax.min.x, minmax.max.x);
66 std::uniform_real_distribution<T> dist_y(minmax.min.y, minmax.max.y);
67 std::uniform_real_distribution<T> dist_z(minmax.min.z, minmax.max.z);
68
69 std::generate_n(
70 std::back_inserter(points),
71 num_points,
72 [&]() { return point_t<T>(dist_x(gen), dist_y(gen), dist_z(gen)); });
73
74 return points;
75}
76
104template<typename T>
106 const std::size_t& num_points, const minmax_t<point_t<T>>& minmax)
107 -> std::vector<point_t<T>>
108{
109 LOG_DEBUG_S << "Generating " << num_points << " points in parallel.";
110 if (num_points == 0) {
111 return {};
112 }
113
114 // 预分配整个向量以避免并行任务中的调整大小 / Pre-allocate the entire vector
115 // to avoid resizing in parallel tasks
116 std::vector<point_t<T>> points(num_points);
117
118 // --- 使用线程池的并行执行逻辑 / Parallel execution logic using thread pool
119 // ---
121 const size_t num_threads = pool.get_thread_count();
122 const size_t hardware_threads =
123 std::max(1u, std::thread::hardware_concurrency());
124
125 // 定义分块策略(根据性能测试调整参数) / Define chunking strategy (adjust
126 // parameters based on performance testing)
127 const size_t min_chunk_size =
128 1024; // 每个任务的最小点数 / Minimum points per task
129 const size_t max_tasks = std::max(
130 static_cast<size_t>(1), std::max(num_threads, hardware_threads) * 4);
131 size_t chunk_size =
132 std::max(min_chunk_size,
133 static_cast<size_t>(
134 std::ceil(static_cast<double>(num_points) / max_tasks)));
135 size_t num_tasks = static_cast<size_t>(
136 std::ceil(static_cast<double>(num_points) / chunk_size));
137 if (num_tasks == 0 && num_points > 0)
138 num_tasks = 1; // 如果num_points > 0,确保至少有一个任务 / Ensure at least
139 // one task if num_points > 0
140
141 std::vector<std::future<void>> futures;
142 futures.reserve(num_tasks);
143
144 std::random_device rd;
145 unsigned int base_seed =
146 rd(); // 生成基础种子以确保线程间的可重现性 / Generate a base seed for
147 // reproducibility across threads
148
149 LOG_DEBUG_S << "Parallel generation using " << num_tasks
150 << " tasks with chunk size ~" << chunk_size;
151
152 size_t start_idx = 0;
153 for (size_t i = 0; i < num_tasks; ++i) {
154 size_t remaining_size = num_points - start_idx;
155 size_t current_chunk_actual_size = std::min(chunk_size, remaining_size);
156 if (current_chunk_actual_size == 0)
157 break; // 如果逻辑正确则不应发生 / Should not happen if logic is correct
158 size_t end_idx = start_idx + current_chunk_actual_size;
159
160 // 向线程池提交任务 / Submit task to the thread pool
161 futures.emplace_back(pool.submit(
162 // 通过值/引用捕获必要的变量 / Capture necessary variables by
163 // value/reference 'points'通过引用捕获 - 由于预分配和索引访问是安全的 /
164 // 'points' is captured by reference - safe due to pre-allocation and
165 // indexed access 'minmax'通过引用捕获(const) / 'minmax' captured by
166 // reference (const)
167 [start_idx, end_idx, &points, &minmax, base_seed, task_id = i]()
168 {
169 // --- 线程本地设置 / Thread-local setup ---
170 // 必须为每个任务/线程创建分布,因为它们可能保持状态 / Distributions
171 // must be created per task/thread as they might hold state
172 std::uniform_real_distribution<T> dist_x(minmax.min.x, minmax.max.x);
173 std::uniform_real_distribution<T> dist_y(minmax.min.y, minmax.max.y);
174 std::uniform_real_distribution<T> dist_z(minmax.min.z, minmax.max.z);
175
176 // 每个任务/线程的随机数生成器使用唯一种子 / Per-task/thread random
177 // number generator seeded uniquely 组合基础种子和任务ID提供变化 /
178 // Combining base seed and task ID provides variation
179 std::mt19937 gen(base_seed + static_cast<unsigned int>(task_id));
180
181 // 可选:记录任务开始(可能很详细) / Optional: Log task start (can be
182 // verbose) LOG_TRACE_S << "Task " << task_id << ": Generating points
183 // [" << start_idx << ", " << end_idx << ")";
184
185 // --- 为这个块生成点 / Generate points for this chunk ---
186 for (size_t k = start_idx; k < end_idx; ++k) {
187 // 直接赋值到预分配的向量元素 / Direct assignment to the
188 // pre-allocated vector element
189 points[k] = point_t<T>(dist_x(gen), dist_y(gen), dist_z(gen));
190 }
191 }));
192 start_idx = end_idx; // 移动到下一个块的开始 / Move to the next chunk start
193 }
194
195 // 等待所有任务完成并处理潜在的异常 / Wait for all tasks to complete and
196 // handle potential exceptions
197 try {
198 for (auto& fut : futures) {
199 fut.get(); // `.get()`等待并重新抛出任务中发生的异常 / `.get()` waits and
200 // rethrows exceptions if any occurred in the task
201 }
202 } catch (const std::exception& e) {
203 LOG_ERROR_S << "Exception during parallel point generation: " << e.what();
204 // 根据错误处理策略,可以清除点、重新抛出等 / Depending on error handling
205 // strategy, could clear points, rethrow, etc. 重新抛出通常是合适的 /
206 // Rethrowing is often appropriate
207 throw;
208 } catch (...) {
209 LOG_ERROR_S << "Unknown exception during parallel point generation.";
210 throw;
211 }
212
213 LOG_DEBUG_S << "Finished parallel generation of " << points.size()
214 << " points.";
215 return points;
216}
217
237template<typename T>
239 const point_cloud_t<T>& cloud,
240 const Eigen::Matrix<T, 4, 4>& transform) -> point_cloud_t<T>
241{
242 point_cloud_t<T> transformed;
243 transformed.points.reserve(cloud.size());
244
245 // 提取旋转和平移部分 / Extract rotation and translation parts
246 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
247 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
248
249 for (const auto& pt : cloud.points) {
250 Eigen::Matrix<T, 3, 1> src_vec(pt.x, pt.y, pt.z);
251 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
252 transformed.points.emplace_back(
253 transformed_vec[0], transformed_vec[1], transformed_vec[2]);
254 }
255
256 return transformed;
257}
258
277template<typename T>
279 const point_cloud_t<T>& cloud,
280 const Eigen::Matrix<T, 4, 4>& transform) -> point_cloud_t<T>
281{
282 if (cloud.empty()) {
283 return point_cloud_t<T>{};
284 }
285
286 LOG_DEBUG_S << "Transforming " << cloud.size() << " points in parallel.";
287
288 // 预分配输出向量 / Pre-allocate output vector
289 point_cloud_t<T> transformed;
290 transformed.points.resize(cloud.size());
291
292 // 提取旋转和平移部分 / Extract rotation and translation parts
293 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
294 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
295
296 // 使用线程池并行处理 / Process in parallel using thread pool
298 const size_t num_threads = pool.get_thread_count();
299 const size_t hardware_threads = std::max(1u, std::thread::hardware_concurrency());
300
301 // 定义分块策略 / Define chunking strategy
302 const size_t min_chunk_size = 1024; // 每个任务的最小点数 / Minimum points per task
303 const size_t max_tasks = std::max(static_cast<size_t>(1),
304 std::max(num_threads, hardware_threads) * 4);
305 size_t chunk_size = std::max(min_chunk_size,
306 static_cast<size_t>(std::ceil(
307 static_cast<double>(cloud.size()) / max_tasks)));
308 size_t num_tasks = static_cast<size_t>(
309 std::ceil(static_cast<double>(cloud.size()) / chunk_size));
310
311 if (num_tasks == 0 && cloud.size() > 0) {
312 num_tasks = 1;
313 }
314
315 std::vector<std::future<void>> futures;
316 futures.reserve(num_tasks);
317
318 LOG_DEBUG_S << "Parallel transformation using " << num_tasks
319 << " tasks with chunk size ~" << chunk_size;
320
321 size_t start_idx = 0;
322 for (size_t i = 0; i < num_tasks; ++i) {
323 size_t remaining_size = cloud.size() - start_idx;
324 size_t current_chunk_size = std::min(chunk_size, remaining_size);
325 if (current_chunk_size == 0) break;
326 size_t end_idx = start_idx + current_chunk_size;
327
328 // 提交任务到线程池 / Submit task to thread pool
329 futures.emplace_back(pool.submit(
330 [start_idx, end_idx, &cloud, &transformed, &rotation, &translation]() {
331 for (size_t k = start_idx; k < end_idx; ++k) {
332 const auto& src_pt = cloud.points[k];
333 Eigen::Matrix<T, 3, 1> src_vec(src_pt.x, src_pt.y, src_pt.z);
334 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
335 transformed.points[k] = point_t<T>(
336 transformed_vec[0], transformed_vec[1], transformed_vec[2]);
337 }
338 }));
339
340 start_idx = end_idx;
341 }
342
343 // 等待所有任务完成 / Wait for all tasks to complete
344 try {
345 for (auto& fut : futures) {
346 fut.get();
347 }
348 } catch (const std::exception& e) {
349 LOG_ERROR_S << "Exception during parallel point cloud transformation: " << e.what();
350 throw;
351 } catch (...) {
352 LOG_ERROR_S << "Unknown exception during parallel point cloud transformation.";
353 throw;
354 }
355
356 LOG_DEBUG_S << "Finished parallel transformation of " << transformed.size() << " points.";
357 return transformed;
358}
359
375template<typename T>
377 point_cloud_t<T>& cloud,
378 const Eigen::Matrix<T, 4, 4>& transform)
379{
380 // 提取旋转和平移部分 / Extract rotation and translation parts
381 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
382 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
383
384 for (auto& pt : cloud.points) {
385 Eigen::Matrix<T, 3, 1> src_vec(pt.x, pt.y, pt.z);
386 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
387 pt.x = transformed_vec[0];
388 pt.y = transformed_vec[1];
389 pt.z = transformed_vec[2];
390 }
391}
392
408template<typename T>
410 point_cloud_t<T>& cloud,
411 const Eigen::Matrix<T, 4, 4>& transform)
412{
413 if (cloud.empty()) {
414 return;
415 }
416
417 // 提取旋转和平移部分 / Extract rotation and translation parts
418 Eigen::Matrix<T, 3, 3> rotation = transform.template block<3, 3>(0, 0);
419 Eigen::Matrix<T, 3, 1> translation = transform.template block<3, 1>(0, 3);
420
421 // 使用 parallel_for_each 简化实现 / Use parallel_for_each to simplify implementation
423 cloud.points.begin(), cloud.points.end(),
424 [&rotation, &translation](point_t<T>& pt) {
425 Eigen::Matrix<T, 3, 1> src_vec(pt.x, pt.y, pt.z);
426 Eigen::Matrix<T, 3, 1> transformed_vec = rotation * src_vec + translation;
427 pt.x = transformed_vec[0];
428 pt.y = transformed_vec[1];
429 pt.z = transformed_vec[2];
430 });
431}
432
433} // 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 CPP_TOOLBOX_EXPORT
Definition export.hpp:8
#define LOG_DEBUG_S
Definition memory_mapped_file.cpp:6
#define LOG_ERROR_S
Definition memory_mapped_file.cpp:4
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 point_impl.hpp:14
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:105
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:278
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:55
CPP_TOOLBOX_EXPORT auto transform_point_cloud(const point_cloud_t< T > &cloud, const Eigen::Matrix< T, 4, 4 > &transform) -> point_cloud_t< T >
对点云应用变换矩阵(顺序版本)/ Apply transformation matrix to point cloud (sequential version)
Definition point_utils.hpp:238
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:376
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:409
#define LOG_DEBUG_S
Definition point_utils.hpp:18
#define LOG_ERROR_S
Definition point_utils.hpp:21
存储和计算最小最大值的主模板类 / 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