如何优雅获取CGAL中x_monotone_curve_2圆弧上的插值点?
在CGAL中优雅地对X_monotone_curve_2圆弧进行插值
你的实现里手动计算角度、转浮点的操作确实会引入精度损失,CGAL本身提供了基于精确几何构造的原生方案,完全不需要手动处理角度和三角函数,直接用旋转变换就能完成圆弧插值。
核心思路
利用CGAL的旋转变换和精确几何运算:
- 全程保留几何量的精确类型,避免
to_double这类精度丢失的转换 - 以圆弧起点相对于圆心的向量为基础,按参数
t的比例旋转到目标位置 - 自动识别并处理完整圆的特殊情况
修改后的实现代码
// Compile with: clang++ -DBOOST_ALL_NO_LIB -DCGAL_USE_GMPXX=1 -O2 -g -DNDEBUG -Wall -Wextra -pedantic -march=native -frounding-math main.cpp -lgmpxx -lmpfr -lgmp #include <CGAL/Arr_circle_segment_traits_2.h> #include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Gps_circle_segment_traits_2.h> #include <CGAL/Rotation_2.h> using K = CGAL::Exact_predicates_exact_constructions_kernel; using Point_2 = K::Point_2; using Circle_2 = K::Circle_2; using Vector_2 = K::Vector_2; using Traits_2 = CGAL::Gps_circle_segment_traits_2<K>; using X_monotone_curve_2 = Traits_2::X_monotone_curve_2; using FT = K::FT; using Rotation = CGAL::Rotation_2<K>; class CircularArcInterpolator { public: CircularArcInterpolator(const X_monotone_curve_2 &curve) : curve(curve) { if(!curve.is_circular()){ throw std::runtime_error("CircularArcInterpolator requires a circular curve!"); } circle = curve.supporting_circle(); start_point = curve.source(); end_point = curve.target(); start_vec = start_point - circle.center(); // 计算精确角度差 if (start_point == end_point) { // 完整圆,角度差为2π angle_diff = 2 * CGAL_PI; } else { Vector_2 end_vec = end_point - circle.center(); angle_diff = CGAL::angle(start_vec, end_vec); // 根据圆弧方向调整角度差符号 if (curve.orientation() == CGAL::CLOCKWISE) { angle_diff = -angle_diff; } } } // t ∈ [0,1],0对应起点,1对应终点 Point_2 operator()(const double t) const { FT t_ft(t); // 构造旋转变换:旋转角度为 angle_diff * t Rotation rot(CGAL::cos(angle_diff * t_ft), CGAL::sin(angle_diff * t_ft)); Vector_2 rotated_vec = rot(start_vec); return circle.center() + rotated_vec; } private: const X_monotone_curve_2 curve; Circle_2 circle; Point_2 start_point; Point_2 end_point; Vector_2 start_vec; FT angle_diff; }; int main(){ Point_2 center(0,0); Circle_2 supporting_circle(center, 1); Point_2 start_end(1, 0); X_monotone_curve_2 curve(supporting_circle, start_end, start_end, CGAL::COUNTERCLOCKWISE); CircularArcInterpolator cai(curve); const auto right = cai(0.00); // Point_2(1, 0) const auto up = cai(0.25); // Point_2(0, 1) const auto left = cai(0.50); // Point_2(-1, 0) const auto down = cai(0.75); // Point_2(0, -1) const auto end = cai(1.00); // Point_2(1, 0) std::cout << right << std::endl; std::cout << up << std::endl; std::cout << left << std::endl; std::cout << down << std::endl; std::cout << end << std::endl; return 0; }
关键改进点
- 精确类型保留:全程用
K::FT(精确分数类型)计算,彻底避免浮点转换带来的精度损失 - 内置旋转变换:借助
CGAL::Rotation_2直接构造旋转,无需手动计算三角函数 - 方向自动适配:根据圆弧的顺时针/逆时针方向调整角度差符号,保证插值方向与原圆弧一致
- 完整圆处理:自动识别起点终点重合的完整圆,直接使用2π作为角度差
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

