Files
ViewDesignEngine/include/vde/curves/bspline_curve.h
T
茂之钳 4c9ee4f760
CI / Build & Test (push) Failing after 29s
CI / Release Build (push) Failing after 38s
docs: doxygen annotations for curves + mesh + sketch
2026-07-24 11:04:04 +00:00

123 lines
4.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "vde/core/point.h"
#include <vector>
namespace vde::curves {
using core::Point3D;
using core::Vector3D;
/**
* @brief B 样条曲线(非有理、均匀/非均匀节点)
*
* 由 n+1 个控制点、m+1 个节点向量和阶次 p 定义。
* 节点向量必须满足 m = n + p + 1。
* 参数域为 [knots[p], knots[n+1]],由前 p 个和后 p 个节点修剪。
*
* 与 Bézier 的主要区别:
* - 局部控制:修改单个控制点仅影响 [t_i, t_{i+p+1}] 区间
* - 节点插入可引入更多控制点而不改变形状
* - 通过多重节点可达 C^{p-k} 连续性
*
* @ingroup curves
*/
class BSplineCurve {
public:
/**
* @brief 构造 B 样条曲线
* @param control_points n+1 个控制点
* @param knots 节点向量,必须为非递减序列
* @param degree 阶次 p
* @note 节点数量 = 控制点数 + 阶次 + 1;clamped 端点多重度为 p+1
* @code{.cpp}
* // 三次 B 样条,7 个控制点
* BSplineCurve curve(cps, {0,0,0,0, 0.25,0.5,0.75, 1,1,1,1}, 3);
* @endcode
*/
BSplineCurve(std::vector<Point3D> control_points,
std::vector<double> knots, int degree);
/**
* @brief 在参数 t 处求值曲线点
* @param t 参数值,必须在 domain() 范围内
* @return 曲线上对应 t 的点坐标
* @note 使用 de BoorCox-de Boor)递推算法
*/
[[nodiscard]] Point3D evaluate(double t) const;
/**
* @brief 在参数 t 处求导数
* @param t 参数值
* @param order 导数阶数,1 = 一切向量
* @return 导数向量
* @note B 样条导数公式:
* P^{(k)}(t) = Σ P_i^{(k)} N_{i,p-k}(t),其中
* P_i^{(0)} = P_i
* P_i^{(k)} = p·(P_i^{(k-1)} - P_{i-1}^{(k-1)}) / (t_{i+p-k+1} - t_i)
*/
[[nodiscard]] Vector3D derivative(double t, int order = 1) const;
/**
* @brief 曲线阶次
* @return 阶次 p
*/
[[nodiscard]] int degree() const { return degree_; }
/**
* @brief 参数定义域
* @return 有效参数范围 [knots[p], knots[n+1]]
*/
[[nodiscard]] std::pair<double, double> domain() const;
/**
* @brief 控制点访问
* @return 控制点数组只读引用
*/
[[nodiscard]] const std::vector<Point3D>& control_points() const { return cp_; }
/**
* @brief 节点向量访问
* @return 节点向量只读引用
*/
[[nodiscard]] const std::vector<double>& knots() const { return knots_; }
/**
* @brief 查找 t 所在的节点区间
* @param t 参数值
* @return 节点区间索引 i 满足 knots[i] ≤ t < knots[i+1]
* @note 使用二分查找,O(log n);求值和基函数的前置步骤
* @code{.cpp}
* int span = curve.find_span(0.5);
* auto N = curve.basis_functions(0.5, span);
* @endcode
*/
[[nodiscard]] int find_span(double t) const;
/**
* @brief 在 t 处求非零基函数值
* @param t 参数值
* @param span 节点区间索引,-1 表示自动查找
* @return N_{span-p}(t), ..., N_{span}(t) 共 p+1 个值
* @note 仅返回 p+1 个非零基函数;用于端点求值及插值
* @see find_span
*/
[[nodiscard]] std::vector<double> basis_functions(double t, int span = -1) const;
/**
* @brief 在 t 处求非零基函数的一阶导数
* @param t 参数值
* @param span 节点区间索引,-1 表示自动查找
* @return dN_{span-p}/du, ..., dN_{span}/du 共 p+1 个值
* @note B 样条基函数导数递推:
* N'_{i,p} = p/(t_{i+p}-t_i)·N_{i,p-1} - p/(t_{i+p+1}-t_{i+1})·N_{i+1,p-1}
* @see basis_functions
*/
[[nodiscard]] std::vector<double> basis_derivatives(double t, int span = -1) const;
private:
std::vector<Point3D> cp_; ///< 控制点序列
std::vector<double> knots_; ///< 节点向量(非递减)
int degree_; ///< 曲线阶次
};
} // namespace vde::curves