#pragma once #include "vde/core/point.h" #include namespace vde::curves { using core::Point3D; using core::Vector3D; /** * @brief 任意阶 Bézier 曲线 * * 通过 de Casteljau 递推算法定义的参数多项式曲线。 * 控制点 cp_ 的数量 = p+1(p 为次数)。 * 参数域 t ∈ [0, 1],端点插值首末控制点。 * * @ingroup curves */ class BezierCurve { public: /** * @brief 构造 Bézier 曲线 * @param control_points 控制点序列,点数 = degree + 1,最少 2 个 * @note 控制点数量决定了曲线阶次;点数越多,曲线越灵活但计算越昂贵 * @code{.cpp} * BezierCurve curve({p0, p1, p2, p3}); // 三次 Bézier * @endcode */ explicit BezierCurve(std::vector control_points); /** * @brief 在参数 t 处求值曲线点 * @param t 参数值,范围 [0, 1] * @return 曲线上对应 t 的点坐标 * @note 使用 de Casteljau 递推算法,O(n²) 复杂度 */ [[nodiscard]] Point3D evaluate(double t) const; /** * @brief 在参数 t 处求导数 * @param t 参数值,范围 [0, 1] * @param order 导数阶数,1 = 一阶(切向量),2 = 二阶(曲率相关) * @return 导数向量 * @note 高阶导数通过降阶 Bézier 曲线计算: * P^{(k)}(t) = n(n-1)...(n-k+1) Σ Δ^k P_i · B_i^{n-k}(t) */ [[nodiscard]] Vector3D derivative(double t, int order = 1) const; /** * @brief 曲线阶次 * @return 阶次 = 控制点数 - 1 */ [[nodiscard]] int degree() const { return static_cast(cp_.size()) - 1; } /** * @brief 参数定义域 * @return 固定为 [0, 1] */ [[nodiscard]] std::pair domain() const { return {0.0, 1.0}; } /** * @brief 控制点访问 * @return 控制点向量的只读引用 */ [[nodiscard]] const std::vector& control_points() const { return cp_; } /** * @brief 在 t 处将曲线一分为二 * @param t 分割参数,范围 [0, 1] * @return 左段 + 右段两条 Bézier 曲线 * @note 使用 de Casteljau 分割算法,分割点为三角阵的对角线 * @code{.cpp} * auto [left, right] = curve.split(0.5); * // left: 控制点 = [P0, b1, b2, P(t)] * // right: 控制点 = [P(t), b3, b4, P3] * @endcode */ [[nodiscard]] std::pair split(double t) const; /** * @brief 升阶操作 * @param times 升阶次数,≥ 1 * @return 升阶后的 Bézier 曲线(控制点数增加 times,形状不变) * @note 通过反复应用公式 P_i' = i/(n+1) P_{i-1} + (1 - i/(n+1)) P_i * 升阶不仅增加自由度,也用于不同阶曲线间的兼容操作 * @see split */ [[nodiscard]] BezierCurve degree_elevate(int times = 1) const; private: std::vector cp_; ///< 控制点序列 }; } // namespace vde::curves