几何内核开发-实现自己的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 stone

namespace 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,生成BezierCurve
    auto 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 array
        Handle(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);
            else
                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_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是控制点的顺序号。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736335.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

板凳-------unix 网络编程 卷1-1简介

unix网络编程进程通信 unpipc.h https://blog.csdn.net/u010527630/article/details/33814377?spm1001.2014.3001.5502 订阅专栏 1>解压源码unpv22e.tar.gz。 $tar zxvf unpv22e.tar.gz //这样源码就被解压到当前的目录下了 2>运行configure脚本&#xff0c;以生成正确…

indexedDB---掌握浏览器内建数据库的基本用法

1.认识indexedDB IndexedDB 是一个浏览器内建的数据库&#xff0c;它可以存放对象格式的数据&#xff0c;类似本地存储localstore&#xff0c;但是相比localStore 10MB的存储量&#xff0c;indexedDB可存储的数据量远超过这个数值&#xff0c;具体是多少呢&#xff1f; 默认情…

前端初学java

目录 java术语 JDK Javac Java Jdb Jhat JVM JRE JAR JDK下载 运行java文件 字面量 隐式转换 强制转换 注意 运算符 &&、||、&、| Switch 程序入口 String[] args 数组 静态初始化 动态初始化 变量初始化 Java内存 方法 重载 Final 包 …

mac苹果窗口辅助工具:Magnet for mac 2.14.0中文免激活版

Magnet 是一款针对 MacOS 系统的窗口管理工具软件。它能够帮助用户更加高效地管理和组织桌面上的窗口&#xff0c;通过简单的快捷键操作&#xff0c;可以将窗口自动调整到指定的位置和大小&#xff0c;实现多窗口快速布局。Magnet 还支持多显示器环境下的窗口管理&#xff0c;可…

模拟算法讲解

模拟算法是一种基于实际情况模拟的算法&#xff0c;通过模拟现实世界中的系统或过程&#xff0c;来研究它们的性质和行为。模拟算法可以用于解决各种问题&#xff0c;包括物理模拟、经济模拟、社会模拟等。 模拟算法的基本步骤包括&#xff1a; 定义问题&#xff1a;明确需要模…

禁用/屏蔽 Chrome 默认快捷键

Chrome 有一些内置的快捷键&#xff0c;但是它并没有像其他软件一样提供管理快捷键的界面。在某些时候&#xff0c;当我们因为个人需求希望禁用 Chrome 某些快捷键时&#xff0c;又无从下手。 好在有开发者开发了 Chrome 插件&#xff0c;可以禁用 Chrome 快捷键的插件&#x…

Python中使用PyQT5库时报错:没有Qt平台插件可以初始化

一、发现问题&#xff1a;无限易pythonGo打开执行的时候报&#xff1a;“没有Qt平台插件可以初始化&#xff0c;请重新安装应用程序。”的错误&#xff0c;点击确定后无限易崩溃闪退。 二、解决问题&#xff1a; 1、重新安装依赖&#xff0c;打开CMD输入pip list&#xff0c;查…

用户态协议栈06-TCP三次握手

最近由于准备软件工程师职称考试&#xff0c;然后考完之后不小心生病了&#xff0c;都没写过DPDK的博客了。今天开始在上次架构优化的基础上增加TCP的协议栈流程。 什么是TCP 百度百科&#xff1a;TCP即传输控制协议&#xff08;Transmission Control Protocol&#xff09;是…

「动态规划」如何求环绕字符串中唯一的子字符串个数?

467. 环绕字符串中唯一的子字符串https://leetcode.cn/problems/unique-substrings-in-wraparound-string/description/ 定义字符串base为一个"abcdefghijklmnopqrstuvwxyz"无限环绕的字符串&#xff0c;所以base看起来是这样的&#xff1a;"...zabcdefghijklm…

浅谈红队攻防之道-office文件免杀

最完美的状态&#xff0c;不是你从不失误&#xff0c;而是你从没放弃成长。 ∙菜单栏&#xff1a;集成了Cobalt Strike的所有功能。 ∙快捷功能区&#xff1a;列出了常用功能。 ∙目标列表区&#xff1a;根据不同的显示模式&#xff0c;显示已获取权限的主机及目标主机。 ∙…

如何打包数据库文件

使用 mysqldump 命令&#xff1a; mysqldump -u username -p database_name > output_file.sql username 是数据库的用户名。database_name 是要导出的数据库名称。output_file.sql 是导出的 SQL 文件名&#xff0c;可以自定义。 示例&#xff1a; mysqldump -u root -p…

OS复习笔记ch12-2

辅存管理 文件分配问题 创建文件一次性分配最大空间吗&#xff1f;分配连续的分区空间&#xff0c;分区多大&#xff1f;用什么数据结构记录&#xff1f; &#xff08;1&#xff09;分配方式 类似于#ch8-3调页机制&#xff0c;文件分配也有预分配和动态分配的形式。 一般拷贝…

【database1】mysql:DDL/DML/DQL,外键约束/多表/子查询,事务/连接池

文章目录 1.mysql安装&#xff1a;存储&#xff1a;集合&#xff08;内存&#xff1a;临时&#xff09;&#xff0c;IO流&#xff08;硬盘&#xff1a;持久化&#xff09;1.1 服务端&#xff1a;双击mysql-installer-community-5.6.22.0.msi1.2 客户端&#xff1a;命令行输入my…

文华财经多空精准买卖点止损止盈数值主图指标公式源码

文华财经多空精准买卖点止损止盈数值主图指标公式源码&#xff1a; DD:EVERY(H>HV(H,20),1); KK:EVERY(L<LV(L,20),1); D:DD&&SUM(DD,BARSLAST(KK))1; K:KK&&SUM(KK,BARSLAST(DD))1; Y:1; DRAWCOLORKLINE(Y&&ISDOWN,COLORYELLOW,0); DRAW…

How to create a langchain doc from an str

问题背景&#xff1a; Ive searched all over langchain documentation on their official website but I didnt find how to create a langchain doc from a str variable in python so I searched in their GitHub code and I found this : 在 langchain 的官方文档中&#…

吴恩达机器学习 第二课 week4 决策树

目录 01 学习目标 02 实现工具 03 问题描述 04 构建决策树 05 总结 01 学习目标 &#xff08;1&#xff09;理解“熵”、“交叉熵&#xff08;信息增益&#xff09;”的概念 &#xff08;2&#xff09;掌握决策树的构建步骤与要点 02 实现工具 &#xff08;1&#xff09;…

视频讲解|【双层模型】分布式光伏储能系统的优化配置方法

1 主要内容 该讲解视频对应的程序链接为【双层模型】分布式光伏储能系统的优化配置方法&#xff0c;模型参考《分布式光伏储能系统的优化配置方法》&#xff0c;分为上下层求解方式&#xff0c;上层采用粒子群算法确定储能的选址和容量方案&#xff0c;以全年购电成本、网络损…

<router-view />标签的理解

< router-view />标签的理解 < router-view />用来承载当前级别下的子集路由的一个视图标签。显示当前路由级别下一级的页面。 App.vue是根组件&#xff0c;在它的标签里使用&#xff0c;而且配置好路由的情况下&#xff0c;就能在浏览器上显示子组件的效果。 如…

开启调试模式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 run()方法虽然适用于启动本地的开发服务器&#xff0c;但是每次修改代码后都要手动重启它。这样并不够方便&#xff0c;如果启用了调试支持&#xff…

中国真实婚恋相亲交友服务平台有哪些?全国靠谱恋爱脱单软件APP大全

终于成功脱单了&#xff01;在过去的这两年里&#xff0c;我动用了身边所有的资源&#xff0c;却始终未能找到理想的男朋友。无奈之下&#xff0c;只好将目光转向线上。经过长达半年的不懈坚持&#xff0c;终于寻觅到了心仪的对象&#xff01;接下来&#xff0c;我要把自己用过…