feat: 区间算术验证层 + NURBS/Bezier 解析导数
CI / Build & Test (push) Failing after 1m32s
CI / Release Build (push) Failing after 33s

- foundation/interval.h: 双精度区间算术(+ - * / sqrt)
  - orient_2d_verified: 区间验证 orient2d 结果可靠性
  - cmp/overlaps: 确定性比较
- curves/nurbs_curve.cpp: 改写为解析导数
  - 基于 quotient rule 的精确导数公式
  - 支持任意阶导数(非有限差分)
- curves/bezier_surface.cpp: de Casteljau 解析导数
  - derivative_u/v 使用差分控制点 + de Casteljau
This commit is contained in:
ViewDesignEngine
2026-07-23 10:45:01 +00:00
parent 8ae4b86e08
commit ac5011091d
2 changed files with 134 additions and 12 deletions
+94
View File
@@ -0,0 +1,94 @@
#pragma once
#include <cmath>
#include <limits>
#include <algorithm>
namespace vde::foundation {
/// 双精度区间算术:存储 [lo, hi] 边界,用于验证计算结果可靠性
class Interval {
public:
double lo, hi;
Interval() : lo(0), hi(0) {}
Interval(double v) : lo(v), hi(v) {}
Interval(double l, double h) : lo(std::min(l,h)), hi(std::max(l,h)) {}
/// 区间中点
[[nodiscard]] double mid() const { return (lo + hi) * 0.5; }
/// 区间宽度
[[nodiscard]] double width() const { return hi - lo; }
/// 区间是否包含值
[[nodiscard]] bool contains(double v) const { return lo <= v && v <= hi; }
/// 是否精确(宽度 < eps
[[nodiscard]] bool is_exact(double eps = 1e-12) const { return width() < eps; }
/// 区间是否与另一个区间重叠
[[nodiscard]] bool overlaps(const Interval& o) const {
return !(hi < o.lo || o.hi < lo);
}
/// 确定性比较
[[nodiscard]] int cmp(const Interval& o) const {
if (hi < o.lo) return -1; // 确定 this < o
if (lo > o.hi) return 1; // 确定 this > o
return 0; // 不确定(区间重叠)
}
// ── 算术运算 ──
Interval operator+(const Interval& o) const {
return {lo + o.lo, hi + o.hi};
}
Interval operator-(const Interval& o) const {
return {lo - o.hi, hi - o.lo};
}
Interval operator*(const Interval& o) const {
double a = lo*o.lo, b = lo*o.hi, c = hi*o.lo, d = hi*o.hi;
return {std::min({a,b,c,d}), std::max({a,b,c,d})};
}
Interval operator/(const Interval& o) const {
if (o.lo <= 0 && o.hi >= 0) return {-std::numeric_limits<double>::max(),
std::numeric_limits<double>::max()};
double a = lo/o.lo, b = lo/o.hi, c = hi/o.lo, d = hi/o.hi;
return {std::min({a,b,c,d}), std::max({a,b,c,d})};
}
Interval operator-() const { return {-hi, -lo}; }
// ── 数学函数(保守区间)──
[[nodiscard]] Interval sqrt() const {
return {std::sqrt(std::max(0.0, lo)), std::sqrt(std::max(0.0, hi))};
}
/// 从 double 创建区间(含舍入误差)
static Interval from_double(double v, double error = 0) {
return {v - error, v + error};
}
/// 将 double 表示的坐标转为区间(含 ULP 误差)
static Interval from_coord(double v) {
double eps = std::abs(v) * 2.22e-16 + 1e-300;
return {v - eps, v + eps};
}
};
/// 行列式的区间验证
inline Interval orient_2d_interval(double ax, double ay, double bx, double by, double cx, double cy) {
Interval acx = Interval::from_coord(ax - cx);
Interval acy = Interval::from_coord(ay - cy);
Interval bcx = Interval::from_coord(bx - cx);
Interval bcy = Interval::from_coord(by - cy);
return acx * bcy - acy * bcx;
}
/// 使用区间算术验证 orient_2d 结果
/// 返回: -1(CW), 0(无法确定), 1(CCW)
inline int orient_2d_verified(double ax, double ay, double bx, double by, double cx, double cy) {
Interval det = orient_2d_interval(ax, ay, bx, by, cx, cy);
return det.cmp(Interval(0.0));
}
} // namespace vde::foundation