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

news2024/12/28 5:53:59

我去年有一篇帖子,介绍了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是控制点的顺序号。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

L56---226.翻转二叉树(广搜)---Java版

1.题目描述 2.思路和知识点 &#xff08;1&#xff09;按照每层来划分&#xff0c; 第一层是2^0&#xff08; 1&#xff09; 第二层是2^1&#xff08;2&#xff0c;3&#xff09; 第三层是2^2 &#xff08;4&#xff0c;5&#xff0c;6&#xff0c;7&#xff09; 第n层是2^(n-…

栅格数据重心迁移变化分析

目前网络上大多是针对矢量重心迁移进行计算&#xff0c;或把栅格转矢量在进行计算&#xff0c;可以不用怎么麻烦&#xff0c;可以直接利用栅格进行得出多期数据的重心&#xff0c;然后进行变化分析等方面的分析。 矢量数据可以通过下面方式进行重心计算&#xff1a; 使用ArcGIS…

谷歌学术内容爬取

最近面临导师灵魂拷问&#xff1a; “你怎么知道你提出的这个方法前人都没有提出过呢&#xff1f;” “你相比于之前的方法&#xff0c;创新点究竟在哪里&#xff1f;” 好吧&#xff0c;为了彻底杜绝这样的问题&#xff0c;开始学习使用谷歌学术。先来学习下关键词检索 哈哈…

qt基本窗口类(QWidget,QDialog,QMainWindow)

1.三个基本窗口类 1.1QWidget 所有窗口的基类 可以内嵌到其他窗口的内部&#xff0c;无边框 也可以作为独立窗口显示&#xff0c;有边框 1.2QDialog 继承于QWidget 对话框窗口类 不可以内嵌到其他窗口 有模态和非模态两种显示方式 1.3QMainWind 继承于QWidget 主窗口类 不可以…

前端Web开发HTML5+CSS3+移动web视频教程 Day1

链接 HTML 介绍 写代码的位置&#xff1a;VSCode 看效果的位置&#xff1a;谷歌浏览器 安装插件 open in browser&#xff1a; 接下来要保证每次用 open in browser 打开的是谷歌浏览器。只需要将谷歌浏览器变为默认的浏览器就可以了。 首先进入控制面板&#xff0c;找到默…

【会议征稿,ACM出版】2024年图像处理、智能控制与计算机工程国际学术会议(IPICE 2024,8月9-11)

2024年图像处理、智能控制与计算机工程国际学术会议&#xff08;IPICE 2024&#xff09;将于2024年8月9-11日在中国福州举行。本届会议由阳光学院、福建省空间信息感知与智能处理重点实验室、空间数据挖掘与应用福建省高校工程研究中心联合主办。 会议主要围绕图像处理、智能控…

QtCreator/VS中制作带有界面的静态库

1、可参考以下文章 QT中制作带有界面的动态库 2、相比动态库,静态库就更简单了,,, 1)创建静态库项目 2)直接右键创建同名窗口类进行覆盖 3)编译生成静态库 4)使用 3、上述都是基于QtCreator来制作的含有界面的静态库,下面基于VS2017来制作带有界面的静态库 …

Temu(拼多多跨境电商) API接口:获取商品详情

核心功能介绍——获取商品详情 在竞争激烈的电商市场中&#xff0c;快速、准确地获取商品数据详情对于电商业务的成功至关重要。此Temu接口的核心功能在于其能够实时、全面地获取平台上的商品数据详情。商家通过接入Temu接口&#xff0c;可以轻松获取商品的标题、价格、库存、…

Day6 —— 电商日志数据分析项目部署流程

项目二 _____&#xff08;电商日志数据分析项目&#xff09; 项目部署过程相关依赖运行结果截图统计页面浏览量日志的ETL操作统计各个省份的浏览量 项目部署过程 以IDEA 2023版本为例 步骤一&#xff1a;创建一个空项目&#xff0c;命名为demo_2&#xff0c;并指定语言类型和构…

oracle 主从库中,从库APPLIED为YES ,但是主库任然为NO

主库 从库 从库已经APPLIED但是主库为APPLIED&#xff0c; 主数据库和备用数据库之间的ARCH-RFS心跳Ping负责更新主数据库上v$archived_log的APPLICED列。 在主数据库上有一个指定的心跳ARCn进程来执行此Ping。如果此进程开始挂起&#xff0c;它将不再与远程RFS进程通信&#…

2024-06-23 编译原理实验4——中间代码生成

文章目录 一、实验要求二、实验设计三、实验结果四、附完整代码 补录与分享本科实验&#xff0c;以示纪念。 一、实验要求 在词法分析、语法分析和语义分析程序的基础上&#xff0c;将C−−源代码翻译为中间代码。 要求将中间代码输出成线性结构&#xff08;三地址代码&#…

STM32F103ZET6基于HAL库实现CAN回环测试和中断接收

简介 在野火STM32F103ZET6开发板上基于HAL库实现了CAN回环测试&#xff0c;并通过PCAN客户端工具和串口打印的方式&#xff0c;分别验证了CAN数据发送成功和CAN数据中断接收成功。 STM32F1开发板测试 STM32测试程序 发送函数 /** 函数名&#xff1a;CAN_SetMsg* 描述 &am…

Windows安全中心打开白屏的解决方法

Windows安全中心打开白屏的解决方法&#xff1a; 1. 复制以下内容&#xff0c;打开记事本粘贴并保存&#xff0c;同时将记事本文件的【txt后缀名改为reg】: Windows Registry Editor Version 5.00 &#xff3b;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defende…

RTA_OS基础功能讲解 2.10-调度表

RTA_OS基础功能讲解 2.10-调度表 文章目录 RTA_OS基础功能讲解 2.10-调度表一、调度表简介二、调度表配置2.1 同步三、到期点配置四、启动调度表4.1 绝对启动4.2 相对启动4.3 同步启动五、到期点处理六、停止调度表6.1 重新启动被停止的调度表七、切换调度表八、选择同步策略8.…

NSIS 入门教程 (三)

引言 在教程的第二部分中&#xff0c;我们为安装程序增加了一个卸载程序&#xff0c;并查看了一些其他的向导页面以及安装部分的选择。第三部分的目标是使安装程序的外观更加现代化。 更现代的外观 为了给安装程序一个更现代的外观&#xff0c;我们要启用现代用户界面。要提…

UnityShader——基础篇之UnityShader基础

UnityShader基础 UnityShader概述 材质和UnityShader 总的来说&#xff0c;在Unity中需要配合使用材质(Material)和 Unity Shader 才能达到需要的效果&#xff0c;常见流程为&#xff1a; 创建一个材质创建一个 Unity Shader&#xff0c;并把它赋给上一步中创建的材质把材质…

AcWing算法基础课笔记——求组合数4

求组合数Ⅳ 用来解决求 C a b C_a^b Cab​的问题&#xff08;没有模运算&#xff09; 解决办法&#xff1a;分解质因数&#xff0c;实现高精度乘法。 C a b a ! b ! ( a − b ) ! C_a^b \frac{a!}{b!(a - b)!} Cab​b!(a−b)!a!​ 其中 a ! a! a!可以用 p p p的倍数来表示…

自动驾驶仿真:Carsim转向传动比设置

文章目录 一、转向传动比概念二、设置转向传动比1、C factor概念2、Steer Kinematics概念3、传动比计算公式 三、转向传动比验证 一、转向传动比概念 转向传动比&#xff08;Steering Ratio&#xff09;表示方向盘转动角度与车轮转动角度之间的关系。公式如下&#xff1a; 转向…

计算机网络 动态路由OSPF

一、理论知识 1.OSPF基本概念 ①OSPF是一种链路状态路由协议&#xff0c;使用Dijkstra算法计算最短路径。 ②OSPF使用区域&#xff08;Area&#xff09;来组织网络&#xff0c;区域0&#xff08;Area 0&#xff09;是主干区域。 ③路由器通过通告直连网络加入OSPF域。 ④反…

QT中制作带有界面的静态库

1、可参考以下文章 QT中制作带有界面的动态库 2、相比动态库&#xff0c;静态库就更简单了&#xff0c;&#xff0c;&#xff0c; 1&#xff09;创建静态库项目 2&#xff09;直接右键创建同名窗口类进行覆盖 3&#xff09;编译生成静态库 4&#xff09;使用