You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优雅获取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;
}

关键改进点

  1. 精确类型保留:全程用K::FT(精确分数类型)计算,彻底避免浮点转换带来的精度损失
  2. 内置旋转变换:借助CGAL::Rotation_2直接构造旋转,无需手动计算三角函数
  3. 方向自动适配:根据圆弧的顺时针/逆时针方向调整角度差符号,保证插值方向与原圆弧一致
  4. 完整圆处理:自动识别起点终点重合的完整圆,直接使用2π作为角度差

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:48:20