如何修改CGAL定义的Cartesian Point_2坐标以限制精度?
解决CGAL Point_2派生类无法修改坐标的问题
问题背景
你通过继承CGAL的Point_2实现了业务类TPoint,需要将坐标精度限制到毫米级,但发现基类的base成员是私有,无法直接修改坐标值。
可行解决方案
1. 优先采用组合而非继承(推荐)
CGAL的几何类设计为值类型,更适合用组合方式封装,而非继承。将CGALPoint作为TPoint的私有成员,通过创建新的CGALPoint来更新坐标:
typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_2 CGALPoint; double RoundPrecision(double number, int precision) { double decimals = std::pow(10, precision); return (std::round(number * decimals)) / decimals; } class TPoint { private: CGALPoint m_point; public: // 支持多种构造方式 TPoint() = default; TPoint(double x, double y) : m_point(x, y) {} TPoint(const CGALPoint& p) : m_point(p) {} // 暴露坐标读取接口 double x() const { return m_point.x(); } double y() const { return m_point.y(); } void RoundTo(int precision) { if (precision >= 0) { double lX = RoundPrecision(x(), precision); double lY = RoundPrecision(y(), precision); // 直接创建新的CGAL点替换内部成员 m_point = CGALPoint(lX, lY); } } // 提供访问内部CGAL点的方法,兼容CGAL其他算法 const CGALPoint& get_cgal_point() const { return m_point; } };
2. 若必须继承:通过赋值替换当前对象
如果因为业务限制必须继承CGALPoint,可以利用Point_2的赋值运算符,创建四舍五入后的新点并赋值给当前对象:
typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_2 CGALPoint; double RoundPrecision(double number, int precision) { double decimals = std::pow(10, precision); return (std::round(number * decimals)) / decimals; } class TPoint : public CGALPoint { public: // 继承基类所有构造函数 using CGALPoint::CGALPoint; void RoundTo(int precision) { if (precision >= 0) { double lX = RoundPrecision(x(), precision); double lY = RoundPrecision(y(), precision); // 用新点覆盖当前对象 *this = CGALPoint(lX, lY); } } };
这个方法绕开了私有成员的限制,本质是用新的Point_2实例替换当前对象的内容,符合CGAL值类型的设计逻辑。
3. 不推荐的方案:强制访问私有成员
不要尝试用reinterpret_cast直接访问基类的base成员,也不要修改CGAL源码添加友元——这些操作会破坏封装,依赖CGAL的内部实现细节,版本更新后必然失效,风险极高。
为什么不推荐继承CGAL几何类?
CGAL的核心几何类(如Point_2)设计为不可变值类型,没有提供修改坐标的接口,目的是保证几何计算的一致性和线程安全。继承这类值类型容易引发对象切片、行为不一致等问题,组合是更安全、更符合设计意图的选择。
内容的提问来源于stack exchange,提问作者huckfinn




