CGAL Min_sphere_of_spheres_d类:如何实现可变维度点的支持?
解决CGAL Min_sphere_of_spheres_d的可变维度需求
嘿,我懂你的痛点——CGAL的Min_sphere_of_spheres_d示例都是固定3维的,但你想要让用户自由选择维度,可CGAL默认的点类型都是编译时固定维度的,这确实卡壳了。不过有两个靠谱的解决方案,我给你捋清楚:
方案1:使用动态维度的点/球类型
CGAL提供了Dynamic_dimension_tag,可以让你在运行时指定维度,完美适配用户动态选择的场景。具体步骤如下:
1. 定义动态维度的类型
首先要替换掉固定维度的Point/Sphere,改用支持动态维度的版本:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Min_sphere_of_spheres_d.h> #include <CGAL/Point_d.h> #include <CGAL/Sphere_d.h> #include <vector> // 选择合适的Kernel,Epick支持动态维度 typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; // 动态维度的点类型 typedef CGAL::Point_d<Kernel, CGAL::Dynamic_dimension_tag> DynPoint; // 动态维度的球类型(对应Min_sphere_of_spheres_d的输入) typedef CGAL::Sphere_d<Kernel, CGAL::Dynamic_dimension_tag> DynSphere; // 动态维度的最小包围球计算类 typedef CGAL::Min_sphere_of_spheres_d<DynSphere> DynMinSphere;
2. 运行时构建球并计算
获取用户选择的维度后,就可以创建对应维度的点和球,再传给最小包围球计算类:
int user_selected_dim = 4; // 假设用户选择了4维 std::vector<DynSphere> spheres; // 创建第一个球(半径0,等价于点) std::vector<double> center1 = {0, 0, 0, 0}; DynPoint p1(user_selected_dim, center1.begin(), center1.end()); spheres.emplace_back(p1, 0.0); // 创建第二个球 std::vector<double> center2 = {1, 1, 1, 1}; DynPoint p2(user_selected_dim, center2.begin(), center2.end()); spheres.emplace_back(p2, 1.0); // 计算最小包围球 DynMinSphere ms(spheres.begin(), spheres.end()); // 验证计算结果有效性 assert(ms.is_valid()); // 获取结果球并输出 DynSphere result_sphere = ms.sphere(); std::cout << "最小包围球中心:" << result_sphere.center() << std::endl; std::cout << "最小包围球半径:" << result_sphere.radius() << std::endl;
注意事项
- 动态维度类型会有轻微的性能开销(因为要运行时检查维度一致性),但大部分场景下完全可以接受。
- 确保你的Kernel支持动态维度,
Exact_predicates_inexact_constructions_kernel(Epick)是没问题的。
方案2:编译时分支选择固定维度(性能优先)
如果你的应用对性能要求极高,且用户可选的维度是有限的几个值(比如2、3、4维),可以用编译时模板实例化的方式,兼顾性能和灵活性:
1. 编写模板化的计算函数
把计算逻辑封装成模板函数,维度作为模板参数:
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; template<int Dim> void compute_min_sphere(const std::vector<std::vector<double>>& input_data) { // 固定维度的点/球类型 typedef CGAL::Point_d<Kernel, CGAL::Fixed_dimension_tag<Dim>> FixedPoint; typedef CGAL::Sphere_d<Kernel, CGAL::Fixed_dimension_tag<Dim>> FixedSphere; typedef CGAL::Min_sphere_of_spheres_d<FixedSphere> FixedMinSphere; std::vector<FixedSphere> spheres; for (const auto& data : input_data) { // 每个输入元素:前Dim个是中心坐标,最后一个是半径 FixedPoint p(Dim, data.begin(), data.begin() + Dim); spheres.emplace_back(p, data[Dim]); } FixedMinSphere ms(spheres.begin(), spheres.end()); assert(ms.is_valid()); FixedSphere result = ms.sphere(); std::cout << Dim << "维最小包围球中心:" << result.center() << std::endl; std::cout << Dim << "维最小包围球半径:" << result.radius() << std::endl; }
2. 根据用户输入调用对应模板实例
在运行时根据用户选择的维度,调用对应的模板函数:
int user_dim = 3; // 用户选择的维度 std::vector<std::vector<double>> input = { {0,0,0, 0.0}, // 3维中心 + 半径 {1,1,1, 1.0} }; if (user_dim == 2) { compute_min_sphere<2>(input); } else if (user_dim == 3) { compute_min_sphere<3>(input); } else if (user_dim == 4) { compute_min_sphere<4>(input); } // 可以继续扩展更多维度选项
优势
- 完全复用固定维度类型的性能优势,没有动态维度的运行时开销。
- 代码逻辑清晰,每个维度的计算都是编译时优化过的。
总结
- 如果需要支持任意维度,优先选方案1的动态维度类型。
- 如果维度是有限固定选项且追求极致性能,选方案2的编译时模板分支。
内容的提问来源于stack exchange,提问作者vexrav
相关产品推荐
相关产品推荐

