几何内核开发-实现自己的NURBS曲线生成API

2024-06-24 05:20

本文主要是介绍几何内核开发-实现自己的NURBS曲线生成API,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我去年有一篇帖子,介绍了NURBS曲线生成与显示的实现代码。

https://blog.csdn.net/stonewu/article/details/133387469?spm=1001.2014.3001.5501文章浏览阅读323次,点赞4次,收藏2次。搞3D几何内核算法研究,必须学习NURBS样条曲线曲面。看《非均匀有理B样条 第2版》这本书,学习起来,事半功倍。在《插件化算法研究平台》上,做了一个样条曲线研究功能,可以分析Bezier曲线、BSpline、NURBS曲线的各种性质,有直观的体验,能更好地理解。https://blog.csdn.net/stonewu/article/details/133387469?spm=1001.2014.3001.5501

本贴子介绍如何在OGG几何内核上做个自己NURBS曲线API。

曲线代码框架参考示例如下:(具体实现代码,请参考我去年的帖子自行实现,或联系本人)

namespace stone
{using namespace std;
class Point3
{
public:float x, y, z;Point3(float x = 0, float y = 0, float z = 0) : x(x), y(y), z(z) {}double norm() { return sqrt(x * x + y * y + z * z); }Point3 operator*(double d) { return Point3(x * d, y * d, z * d); }Point3 operator+(const Point3& p) { return Point3(x + p.x, y + p.y, z + p.z); }
};
class BaseCurve
{
public:virtual ~BaseCurve() {}BaseCurve(double precision) { m_precision = precision; }bool finished = false; //完成控制点构成bool m_mousePressed = false;int  m_currentControlPointIndex = -1;double         m_precision = 0.01; //精度vector<Point3> controlPoints;vector<Point3> curvePoints;//nurbs参数vector<double> weights;    //权重vector<double> knots;      // 结点向量int            degree = 3; // 曲线次数virtual void clear(){//清空curvePoints.clear();//清空controlPoints.clear();finished = false;}virtual void curveInfo() = 0;virtual void createCurve() = 0;virtual void appendControlPoint(Point3 controlPoint) { controlPoints.push_back(controlPoint); }virtual void moveControlPoint(int index, Point3 controlPoint) { controlPoints[index] = controlPoint; }void initKnots(){。。。}void initWeights(){。。。}
};
class BezierCurve : public BaseCurve
{
public:BezierCurve(double precision = 0.01) : BaseCurve(precision){};public:void curveInfo() { debugx("BezierCurve!"); }// 生成N阶贝塞尔曲线点void createCurve(){curveInfo();if (controlPoints.size() <= 1)return;//清空curvePoints.clear();auto size = controlPoints.size();for (double t = 0; t < 1.0000; t += m_precision){ //根据精度绘制点。。。}}
};class BSplineCurve : public BaseCurve
{
public:void curveInfo() { debugx("BSplineCurve!"); }BSplineCurve(int aDegree, double precision) : BaseCurve(precision) { degree = aDegree; }BSplineCurve(vector<Point3> points, int k, double precision) : BaseCurve(precision){controlPoints = points;degree = k;// 初始化结点向量, m = n + 1+ k   ,m+1节点数量, n+1控制点数量 ,k 次数。。。}// 计算基函数值double basis(int i, int k, double u){
。。。return a * basis(i, k - 1, u) + b * basis(i + 1, k - 1, u);}// 计算样条曲线上的点virtual Point3 calculatePoint(double u){Point3 result;。。。return result;}void createCurve(){curveInfo();//清空curvePoints.clear();auto size = controlPoints.size();if (size < 2)return;//生成NURBS曲线上所有的点。。。}void moveControlPoint(int index, Point3 controlPoint){controlPoints[index] = controlPoint;if (controlPoints.size() < 2)return;createCurve();}
};class NURBSCurve : public BSplineCurve
{
public:void curveInfo() override { debugx("NURBSCurve!"); }NURBSCurve(int aDegree=3, double precision = 0.01) : BSplineCurve(aDegree, precision) {}// 计算样条曲线上的点Point3 calculatePoint(double u) override{。。。return result;}
};
} //namespace stonenamespace stone
{class CurveUtil
{
public:static BRepBuilderAPI_MakePolygon CreateBezierCurve(TColgp_Array1OfPnt Array1, double precision = 0.01){。。}static BRepBuilderAPI_MakePolygon CreateNURBSCurve(TColgp_Array1OfPnt Array1, int aDegree=3, double precision = 0.01){。。。return makePolygon;}
};} //namespace stone MakeAPI

调用代码参考示例:

主要功能Demo:

1、定义5个控制点,并在界面上显示出来。

2、调用自己的曲线算法API,生成BezierCurve,以此线条为路径,生成管道。并显示。

3、调用自己的曲线算法API,生成NURBSCurve,缺省权重为1,degree为3,节点向量自行生成。以此线条为路径,生成管道。并显示。

4、调用 OCCT几何内核的BSpline API。以此线条为路径,生成管道。并显示。

5、调用 OCCT几何内核的BSpline  API  NUBRS曲线。以此线条为路径,生成管道。并显示。

void myCurveDemo(OccView *view)
{gp_Ax2 ax2;ax2.SetLocation(gp_Pnt(0, 0, 0));TopoDS_Edge circleEdge = BRepBuilderAPI_MakeEdge(gp_Circ(ax2, 0.1));const int pointCount=5;TColgp_HArray1OfPnt points(1, pointCount);points.SetValue(1, gp_Pnt(0.1, 0, 0));points.SetValue(2, gp_Pnt(1.1, 1, 1));points.SetValue(3, gp_Pnt(2.1, 2, 0));points.SetValue(4, gp_Pnt(3.1, 1, -1));points.SetValue(5, gp_Pnt(5.1, 1, -3));// points.SetValue(6, gp_Pnt(5.1, 4, 5));// points.SetValue(7, gp_Pnt(6.1, 5, -3));// points.SetValue(8, gp_Pnt(8.1, 2, -5));//显示控制点for(int i=1;i<=pointCount;i++){auto p=points.Value(i);showPoint(view,p,QString::number(i).toStdString().c_str(),false);}//调用自己的曲线算法API,生成BezierCurveauto curve=stone::CurveUtil::CreateBezierCurve(points);if(curve.IsDone()){Handle(AIS_ColoredShape) ais = new AIS_ColoredShape(curve.Wire());view->Display(ais);}
//调用自己的曲线算法API,生成NURBSCurve,缺省权重为1,degree为3,节点向量自行生成curve=stone::CurveUtil::CreateNURBSCurve(points);if(curve.IsDone()){auto wire=curve.Wire();Handle(AIS_ColoredShape) ais = new AIS_ColoredShape(wire);ais->SetColor(Quantity_NOC_MAROON);view->Display(ais);{//扫掠TopoDS_Shape pipe=BRepOffsetAPI_MakePipe(wire,circleEdge);Handle(AIS_Shape) aisPipe = new AIS_Shape(pipe);aisPipe->SetColor(Quantity_NOC_MAROON);view->Display(aisPipe);}}
//调用 OCCT几何内核的BSpline API{// Make a BSpline curve from the points arrayHandle(Geom_BSplineCurve) aBSplineCurve = GeomAPI_PointsToBSpline(points).Curve();// Make an edge between two point on the BSpline curve.gp_Pnt aPntOnCurve1, aPntOnCurve2;aBSplineCurve->D0(0.75 * aBSplineCurve->FirstParameter()+ 0.25 * aBSplineCurve->LastParameter(),aPntOnCurve1);aBSplineCurve->D0(0.25 * aBSplineCurve->FirstParameter()+ 0.75 * aBSplineCurve->LastParameter(),aPntOnCurve2);TopoDS_Edge anEdgeBSpline = BRepBuilderAPI_MakeEdge(aBSplineCurve);Handle(AIS_ColoredShape) anAisEdgeBSpline = new AIS_ColoredShape(anEdgeBSpline);anAisEdgeBSpline->SetColor(Quantity_Color(Quantity_NOC_MAGENTA));view->Display(anAisEdgeBSpline);{//扫掠auto wire=BRepBuilderAPI_MakeWire(anEdgeBSpline).Wire();TopoDS_Shape pipe=BRepOffsetAPI_MakePipe(wire,circleEdge);Handle(AIS_Shape) aisPipe = new AIS_Shape(pipe);aisPipe->SetColor(Quantity_NOC_MAGENTA);view->Display(aisPipe);}}//调用 OCCT几何内核的BSpline  API  NUBRS曲线{/// 均匀B样条,节点向量中的节点值成等差排布/// 均匀B样条的基函数呈周期性,即所有的基函数有相同的形状/// 每个后续基函数仅仅市前面基函数在新位置上的重复Standard_Integer degree(2);Standard_Integer KNum = pointCount + degree + 1;TColStd_Array1OfReal knots(1,KNum);for(int i=0; i<KNum; ++i)knots.SetValue(i+1, i);TColStd_Array1OfInteger mults(1,KNum);for(int i=0; i<KNum; ++i)mults.SetValue(i+1, 1);Handle(Geom_BSplineCurve) curve = new Geom_BSplineCurve(points, knots, mults, degree);TopoDS_Edge ed1 = BRepBuilderAPI_MakeEdge(curve);TopoDS_Wire wr1 = BRepBuilderAPI_MakeWire(ed1);Handle(AIS_ColoredShape) ais = new AIS_ColoredShape(wr1);ais->SetColor(Quantity_NOC_SALMON);view->Display(ais);}{/// 准均匀B样条,节点向量中的节点值也是等差排布,但是起点和终点都有k-1的重复度,其中ke为曲线次数。Standard_Integer degree(2);Standard_Integer KNum = pointCount-1;TColStd_Array1OfReal knots(1,KNum);for(int i=0; i<KNum; ++i)knots.SetValue(i+1, i);TColStd_Array1OfInteger mults(1,KNum);for(int i=0; i<KNum; ++i)if(i == 0 || i == KNum-1)mults.SetValue(i+1, degree+1);elsemults.SetValue(i+1, 1);Handle(Geom_BSplineCurve) curve = new Geom_BSplineCurve(points, knots, mults, degree);TopoDS_Edge ed1 = BRepBuilderAPI_MakeEdge(curve);TopoDS_Wire wr1 = BRepBuilderAPI_MakeWire(ed1);Handle(AIS_ColoredShape) ais = new AIS_ColoredShape(wr1);ais->SetColor(Quantity_NOC_SIENNA);view->Display(ais);//扫掠圆,BSpline路径 BRepOffsetAPI_MakePipe{{TopoDS_Shape pipe=BRepOffsetAPI_MakePipe(wr1,circleEdge);Handle(AIS_Shape) aisPipe = new AIS_Shape(pipe);aisPipe->SetColor(Quantity_NOC_BISQUE);view->Display(aisPipe);}}}
}

运行效果:

从运行效果上来看,扫掠生成的管道,与曲线形状非常一致。

绿色的管道(粗线)和自定义算法生成的Bezier曲线路径,如下图:

绿色的管道(粗线)和自定义算法生成的NURBS曲线路径,如下图:

绿色的管道(粗线)和OCCT几何内核的NURBS曲线路径,如下图:

以上三个图中,黄色+处,是控制点位置。黄色+的右下边的数字1,2,3,4,5是控制点的顺序号。

这篇关于几何内核开发-实现自己的NURBS曲线生成API的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089274

相关文章

python实现svg图片转换为png和gif

《python实现svg图片转换为png和gif》这篇文章主要为大家详细介绍了python如何实现将svg图片格式转换为png和gif,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录python实现svg图片转换为png和gifpython实现图片格式之间的相互转换延展:基于Py

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Android实现在线预览office文档的示例详解

《Android实现在线预览office文档的示例详解》在移动端展示在线Office文档(如Word、Excel、PPT)是一项常见需求,这篇文章为大家重点介绍了两种方案的实现方法,希望对大家有一定的... 目录一、项目概述二、相关技术知识三、实现思路3.1 方案一:WebView + Office Onl

C# foreach 循环中获取索引的实现方式

《C#foreach循环中获取索引的实现方式》:本文主要介绍C#foreach循环中获取索引的实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、手动维护索引变量二、LINQ Select + 元组解构三、扩展方法封装索引四、使用 for 循环替代

Spring Security+JWT如何实现前后端分离权限控制

《SpringSecurity+JWT如何实现前后端分离权限控制》本篇将手把手教你用SpringSecurity+JWT搭建一套完整的登录认证与权限控制体系,具有很好的参考价值,希望对大家... 目录Spring Security+JWT实现前后端分离权限控制实战一、为什么要用 JWT?二、JWT 基本结构

Java实现优雅日期处理的方案详解

《Java实现优雅日期处理的方案详解》在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间,下面我们就来看看如何使用java处理这样的日期问题吧,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言一、日期的坑1.1 日期格式化陷阱1.2 时区转换二、优雅方案的进阶之路2.1 线程安全重构2

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络