问题
上一篇文章已经实现了样条曲线拟合,但是仍存在问题,Tolerance过大拟合成直线了,Tolerance过大头尾波浪形。

正确改进方案
1️⃣ 核心参数优化
通过调整以下参数控制曲线平滑度:
Standard_Integer DegMin = 3;    // 最低阶数(建议≥3)
Standard_Integer DegMax = 5;    // 最高阶数(过高易过拟合)
Standard_Real Tolerance = 1e-3;  // 容差(需根据点集坐标范围调整)
GeomAbs_Shape Continuity = GeomAbs_C2; // 连续性(C2更平滑)
2️⃣ 构造拟合器时直接指定参数
// 使用构造函数直接传递参数(正确方法)
Geom2dAPI_PointsToBSpline approximator(pointsArray,    // 点集DegMin,         // 最小阶数DegMax,         // 最大阶数Continuity,     // 连续性Tolerance       // 容差
);
3️⃣ 抑制波浪形的替代方法
-  增大容差 ( Tolerance)
 逐步增加Tolerance值,允许曲线偏离原始点,强制忽略高频波动(头尾噪声)。例如,若点集分布在 [0, 100] 范围内,可将Tolerance设为点集总范围的 2-5%(如 2.0~5.0)。
-  提高连续性 ( Continuity)
 使用GeomAbs_C2连续性(二阶连续),强制曲线在连接处更平滑,抑制局部抖动。
-  限制曲线阶数 ( DegMax)
 将DegMax设为较低值(如 5),避免高阶曲线过度拟合噪声。
分段控制替代方案
若需隐式控制分段数,可通过以下方法间接实现:
// 通过容差和连续性间接影响分段数
approximator.Init(pointsArray, DegMin, DegMax, Continuity, Tolerance);
// 注:Init() 方法允许重新初始化参数
数据预处理(关键步骤)
对波动较大的头尾数据进行滤波处理:
#include <algorithm>
#include <vector>// 滑动平均滤波函数(窗口大小=3)
std::vector<gp_Pnt2d> SmoothPoints(const std::vector<gp_Pnt2d>& input, int windowSize = 3) {std::vector<gp_Pnt2d> output;for (size_t i = 0; i < input.size(); ++i) {double sumX = 0.0, sumY = 0.0;int count = 0;int start = std::max(0, (int)i - windowSize/2);int end = std::min((int)input.size()-1, (int)i + windowSize/2);for (int j = start; j <= end; ++j) {sumX += input[j].X();sumY += input[j].Y();count++;}output.emplace_back(sumX/count, sumY/count);}return output;
}// 使用平滑后的点集
std::vector<gp_Pnt2d> smoothPoints = SmoothPoints(pointsVec, 3);
完整代码修正
#include <Geom2dAPI_PointsToBSpline.hxx>
#include <TColgp_Array1OfPnt2d.hxx>Handle(Geom2d_BSplineCurve) FitCurve2D(const std::vector<gp_Pnt2d>& pointsVec) {if (pointsVec.size() < 2) return nullptr;// 转换为OpenCASCADE数组(索引从1开始)TColgp_Array1OfPnt2d pointsArray(1, pointsVec.size());for (int i = 0; i < pointsVec.size(); ++i) {pointsArray.SetValue(i + 1, pointsVec[i]);}// 设置拟合参数Standard_Integer DegMin = 3;Standard_Integer DegMax = 5;Standard_Real Tolerance = 2.0;  // 根据点集范围调整GeomAbs_Shape Continuity = GeomAbs_C2;// 创建拟合器Geom2dAPI_PointsToBSpline approximator(pointsArray, DegMin, DegMax, Continuity, Tolerance);if (approximator.IsDone()) {return approximator.Curve();}return nullptr;
}
参数调整建议
| 现象 | 解决方案 | 参数调整方向 | 
|---|---|---|
| 头尾波浪形严重 | 增大容差,降低曲线自由度 | Tolerance ↑,DegMax ↓ | 
| 曲线过于僵硬 | 减小容差,允许更多细节 | Tolerance ↓,DegMax ↑ | 
| 连接处不光滑 | 提高连续性要求 | Continuity → GeomAbs_C2 | 
验证方法
- 可视化检查:将拟合曲线与原始点绘制在同一坐标系,观察趋势是否符合。
- 误差分析:计算曲线到点的最大偏差:Standard_Real maxError = approximator.MaxError(); std::cout << "Max fitting error: " << maxError << std::endl;
- 参数迭代:若误差远小于 Tolerance,说明容差设置过大,可适当减小。
调整前的结果:

调整后的结果:

通过以上方法,有效抑制头尾波浪形,使曲线贴合整体趋势。