当前位置: 首页 > ds >正文

Open CASCADE学习|B 样条曲线拟合优化

一、引言

B 样条曲线拟合在计算机辅助设计(CAD)、计算机图形学、工程建模等诸多领域有着关键作用。它可以帮助我们将离散的点集用连续平滑的曲线表示,以便后续进行各种分析与处理。本文将基于 OpenCASCADE 库,深入探讨 C++ 中的 B 样条曲线拟合优化,从原理到代码实现进行全面阐述。

二、B 样条曲线原理

(一)B 样条曲线定义

B 样条曲线(B - Spline Curve)是一种分段多项式曲线,它以控制点和基函数为基础进行构造。其数学表达式为:

C ( u ) = ∑ i = 0 n N i , p ( u ) P i \mathbf{C}(u) = \sum_{i=0}^{n} N_{i,p}(u) \mathbf{P}_i C(u)=i=0nNi,p(u)Pi

其中:

  • C ( u ) \mathbf{C}(u) C(u) 是曲线上的点, u u u 是参数,通常在区间 [ 0 , 1 ] [0,1] [0,1] 内变化。

  • N i , p ( u ) N_{i,p}(u) Ni,p(u) p p p 次的 B 样条基函数,通过递推公式计算得到。递推公式如下:

    • N i , 0 ( u ) = { 1 , u ∈ [ u i , u i + 1 ) 0 , otherwise N_{i,0}(u) = \begin{cases} 1, & u \in [u_i, u_{i+1}) \\ 0, & \text{otherwise} \end{cases} Ni,0(u)={1,0,u[ui,ui+1)otherwise
    • N i , p ( u ) = u − u i u i + p − u i N i , p − 1 ( u ) + u i + p + 1 − u u i + p + 1 − u i + 1 N i + 1 , p − 1 ( u ) N_{i,p}(u) = \frac{u - u_i}{u_{i+p} - u_i} N_{i,p-1}(u) + \frac{u_{i+p+1} - u}{u_{i+p+1} - u_{i+1}} N_{i+1,p-1}(u) Ni,p(u)=ui+puiuuiNi,p1(u)+ui+p+1ui+1ui+p+1uNi+1,p1(u)
  • P i \mathbf{P}_i Pi 是控制点,决定了曲线的大致形状走向。

  • k n o t knot knot 向量是一个非递减的实数序列: u 0 ≤ u 1 ≤ ⋯ ≤ u m u_0 \leq u_1 \leq \cdots \leq u_{m} u0u1um,它定义了基函数的作用范围,对曲线的连续性等性质有很大影响。

(二)B 样条曲线性质

  • 局部支撑性 :每个基函数 N i , p ( u ) N_{i,p}(u) Ni,p(u) 在区间 [ u i , u i + p + 1 ] [u_i, u_{i+p+1}] [ui,ui+p+1] 内非零,这意味着曲线在参数区间的一个局部区域内的形状只与部分控制点有关,改变一个控制点只会影响曲线的局部形状。
  • 连续性 :B 样条曲线具有 C p − k C^{p - k} Cpk 连续性,其中 k k k k n o t knot knot向量中重复的次数。例如,若在某个区间内 k n o t knot knot 向量的重复次数为 2,且基函数是 3 次的(即 p = 3 p = 3 p=3 ),则曲线在该处具有 C 1 C^{1} C1 连续性。
  • 凸包性 :曲线位于控制点的凸包之内,这使得可以通过控制点的大致分布来估计曲线的范围。

三、OpenCASCADE 中 B 样条曲线拟合

(一)OpenCASCADE 相关类介绍

  • GeomAPI_PointsToBSpline :这是 OpenCASCADE 提供的一个关键类,用于进行离散点集到 B 样条曲线的拟合。它可以处理不同的参数化方式以及拟合精度要求等。
  • Geom_BSplineCurve :代表 B 样条曲线对象的类,包含了曲线的相关信息,如控制点、基函数、 k n o t knot knot 向量等。

(二)代码实现步骤

  1. 读取点集文件

    • 通过 C++ 的文件输入输出操作,从指定路径读取存储离散点坐标的文件。
    • 文件中每行包含一个点的 x x x y y y 坐标,以逗号分隔。读取时,将每行数据解析为一个 gp_Pnt 对象(OpenCASCADE 中的点类),并存入一个 vector 容器中。
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>#include <TColgp_Array1OfPnt.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Standard_Handle.hxx>
#include <GeomAbs_Shape.hxx>
#include <Approx_ParametrizationType.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>int main() {// 1. 读取点集文件std::ifstream file("D:/pointsenvelope.txt");if (!file.is_open()) {std::cerr << "无法打开文件!" << std::endl;return 1;}std::vector<gp_Pnt> points;std::string line;while (std::getline(file, line)) {std::stringstream ss(line);double x, y;char comma;if (ss >> x >> comma >> y && comma == ',') {// 创建 gp_Pnt 对象,z 坐标默认为 0points.emplace_back(gp_Pnt(x, y, 0.0));}}file.close();
}
  1. 将点集转换为 OpenCASCADE 数组

    • vector 容器中的点数据转换为 OpenCASCADE 可用的 TColgp_Array1OfPnt 数组格式,以便后续调用 OpenCASCADE 的拟合函数。
// 2. 转换为 OpenCASCADE 数组
TColgp_Array1OfPnt occtPoints(1, points.size());
for (size_t i = 0; i < points.size(); ++i) {occtPoints.SetValue(i + 1, points[i]);
}

3. 拟合 B 样条曲线

参数化方式选择:

弦长参数化 :适用于非均匀分布的点集。它是根据相邻点之间的欧几里得距离来计算参数值,使得参数在曲线上的分布与点在空间中的分布相对应,能较好地反映点集的几何特征。

变分平滑参数化 :通过平衡曲线长度、曲率、挠率等因素,对曲线进行优化平滑处理。可以根据实际需求设置相关权重参数,如曲线长度权重(weightLength)、曲率平滑权重(weightCurvature)、扭转平滑权重(weightTorsion)等,以达到所需的平滑效果。

拟合精度控制:

设置拟合的次数(如 3 次)、最大允许次数(如 6 次)、连续性要求(如 GeomAbs_C2 表示二阶连续)以及误差容忍度(如 (1.0e-3) ),来控制拟合曲线的质量与精确度。

// 3. 拟合 B 样条曲线(使用弦长参数化与变分平滑)
GeomAPI_PointsToBSpline approximator;
try {// 方法一:使用弦长参数化(适用于非均匀分布点)// approximator.Init(occtPoints, Approx_ChordLength, 3, 6, GeomAbs_C2, 1.0e-3);// 方法二:变分平滑(平衡长度、曲率、挠率)const Standard_Real weightLength = 1.0;  // 曲线长度权重const Standard_Real weightCurvature = 0.1; // 曲率平滑权重const Standard_Real weightTorsion = 0.01;  // 扭转平滑权重approximator.Init(occtPoints, weightLength, weightCurvature, weightTorsion, 6, GeomAbs_C2, 1.0e-3);
}
catch (...) {std::cerr << "Error during curve approximation." << std::endl;return 1;
}if (!approximator.IsDone()) {std::cerr << "Error: Approximation failed." << std::endl;return 1;
}
  1. 获取结果曲线并可视化

    • 调用 approximator.Curve() 方法获取拟合得到的 B 样条曲线对象。
    • 利用 OpenCASCADE 的 BRepBuilderAPI_MakeEdge 类将曲线转换为边对象,以便在可视化组件(如自定义的 Viewer 类)中进行显示。
// 4. 获取结果曲线
Handle(Geom_BSplineCurve) curve = approximator.Curve();
std::cout << "B-Spline fitting successful. Degree: " << curve->Degree() << std::endl;
Viewer vout(50, 50, 500, 500);
vout << BRepBuilderAPI_MakeEdge(curve);
vout << BRepBuilderAPI_MakeEdge(gp_Pnt(0,0,0), gp_Pnt(0, 0.6,0));
vout.StartMessageLoop();
return 0;

四、完整代码

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>#include <TColgp_Array1OfPnt.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Standard_Handle.hxx>
#include <GeomAbs_Shape.hxx>
#include <Approx_ParametrizationType.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include "Viewer.h"int main() {// 1. 读取点集文件std::ifstream file("D:/pointsenvelope.txt");if (!file.is_open()) {std::cerr << "无法打开文件!" << std::endl;return 1;}std::vector<gp_Pnt> points;std::string line;while (std::getline(file, line)) {std::stringstream ss(line);double x, y;char comma;if (ss >> x >> comma >> y && comma == ',') {// 创建 gp_Pnt 对象,z 坐标默认为 0points.emplace_back(gp_Pnt(x, y, 0.0));}}file.close();// 2. 转换为 OpenCASCADE 数组TColgp_Array1OfPnt occtPoints(1, points.size());for (size_t i = 0; i < points.size(); ++i) {occtPoints.SetValue(i + 1, points[i]);}// 3. 拟合 B 样条曲线(使用弦长参数化与变分平滑)GeomAPI_PointsToBSpline approximator;try {// 方法一:使用弦长参数化(适用于非均匀分布点)// approximator.Init(occtPoints, Approx_ChordLength, 3, 6, GeomAbs_C2, 1.0e-3);// 方法二:变分平滑(平衡长度、曲率、挠率)const Standard_Real weightLength = 1.0;  // 曲线长度权重const Standard_Real weightCurvature = 0.1; // 曲率平滑权重const Standard_Real weightTorsion = 0.01;  // 扭转平滑权重approximator.Init(occtPoints, weightLength, weightCurvature, weightTorsion, 6, GeomAbs_C2, 1.0e-3);}catch (...) {std::cerr << "Error during curve approximation." << std::endl;return 1;}if (!approximator.IsDone()) {std::cerr << "Error: Approximation failed." << std::endl;return 1;}// 4. 获取结果曲线Handle(Geom_BSplineCurve) curve = approximator.Curve();std::cout << "B-Spline fitting successful. Degree: " << curve->Degree() << std::endl;Viewer vout(50, 50, 500, 500);vout << BRepBuilderAPI_MakeEdge(curve);vout << BRepBuilderAPI_MakeEdge(gp_Pnt(0,0,0), gp_Pnt(0, 0.6,0));vout.StartMessageLoop();return 0;
}

五、总结

本文详细介绍了 C++ 中基于 OpenCASCADE 的 B 样条曲线拟合优化过程。从 B 样条曲线的基本原理阐述开始,深入分析了 OpenCASCADE 中相关类的使用方法,并通过完整的代码示例展示了从点集读取、数据转换、曲线拟合到结果可视化等整个流程。这种基于 OpenCASCADE 的 B 样条曲线拟合优化技术,能够有效地将离散的点集转化为平滑连续的曲线,为后续的几何建模、分析与设计等应用提供了坚实的基础,具有广泛的实际应用价值。

http://www.xdnf.cn/news/5464.html

相关文章:

  • 探秘 Canva AI 图像生成器:重塑设计创作新范式
  • vs python“““标记注释报错,vs使用自带环境安装 python第三方库
  • 每日一题洛谷T534125 合数c++
  • C# 方法(ref局部变量和ref返回)
  • 测试一下多模态提取图片中文字的能力
  • STM32F103单片机在不需要使用 JTAG 调试接口的情况下,释放引脚给其他功能使用。
  • 电网拓扑分析:原理与应用
  • Crewai Community Version(四)——Crew
  • Qt QCheckBox 使用
  • 【Java ee初阶】网络编程 TCP
  • 深度学习篇---姿态检测实现
  • 软考错题集
  • Java 23种设计模式 - 行为型模式11种
  • PostgreSQL 的 pg_collation_actual_version 函数
  • 【深度学习-Day 8】让数据说话:Python 可视化双雄 Matplotlib 与 Seaborn 教程
  • Kimball
  • Python 基础语法与数据类型(七) - 函数的定义与调用 (def, return)
  • Ethercat转Profinet网关如何用“协议翻译术“打通自动化产线任督二脉
  • Looper死循环阻塞为什么没有ANR
  • 【大模型面试每日一题】Day 14:大模型训练中显存占用的主要来源有哪些?如何通过激活重计算降低显存?
  • 关于char字符的16进制打印
  • 408考研逐题详解:2009年第11题
  • PySide6 GUI 学习笔记——常用类及控件使用方法(常用类边距QMargins)
  • 数字信号处理|| 快速傅里叶变换(FFT)
  • 软考(信息系统运行管理员)
  • 猿人学第十七题—天杀的http2.0
  • SSH免密登录
  • Java注解之@PostConstruct
  • ts装饰器
  • IPM IMI111T-026H 高效风扇控制板