均匀与准均匀 B样条算法

B 样条曲线的定义

p ( t ) = ∑ i = 0 n P i F i , k ( t ) p(t) = \sum_{i=0}{n} P_i F_{i, k}(t) p(t)=i=0nPiFi,k(t)

方程中 n + 1 n+1 n+1 个控制点, P i P_i Pi, i = 0 , 1 , ⋯ n i=0, 1, \cdots n i=0,1,n 要用到 n + 1 n+1 n+1 k k k 次 B 样条基函数 F i , k F_{i, k} Fi,k, i = 0 , 1 , ⋯ , n i=0, 1, \cdots, n i=0,1,,n, 节点矢量为 T = [ t 0 , t 1 , ⋯ , t n + k + 1 ] T = [t_0, t_1, \cdots, t_{n+k+1}] T=[t0,t1,,tn+k+1] F i , k ( t ) F_{i, k}(t) Fi,k(t) 是由一个称为节点矢量的非递减的参数 t t t 的序列, t 0 ≤ t 1 ≤ ⋯ ≤ t n + k + 1 t_0 \leq t_1 \leq \cdots \leq t_{n+k+1} t0t1tn+k+1所决定的 k k k 次分段多项式。

B 样条曲线划分为四种类型,均匀 B 样条曲线,准均匀B 样条曲线,分段 Bezier 曲线和非均匀 B 样条曲线。

定义域

给定 n + 1 n+1 n+1 个控制点, P i P_i Pi, i = 0 , 1 , ⋯ n i=0, 1, \cdots n i=0,1,n, 相应地要求 n + 1 n+1 n+1 个 B 样条基函数 F i , k ( t ) F_{i, k}(t) Fi,k(t) 定义一个 k k k 次 B 样条曲线,这 n + 1 n+1 n+1 k k k 次 B 样条由节点矢量 T = [ t 0 , t 1 , ⋯ t n + k + 1 ] T = [t_0, t_1, \cdots t_{n+k+1}] T=[t0,t1,tn+k+1] 所决定。
并非这个些节点矢量所包含的 n + k + 1 n+k +1 n+k+1 个区间都在该曲线的定义域,其中两端的各 k k k 个几点区间,不能作为 B 样条曲线的定义区间。
这是因为 n + 1 n+1 n+1 个控制点中最前的 n + 1 n+1 n+1 个顶点 P i P_i Pi, i = 0 , 1 , ⋯ k i=0,1, \cdots k i=0,1,k 定义了 B 样条曲线的首段,其定义区间为 t ∈ [ t k , t k + 1 ] t\in [t_k, t_{k+1}] t[tk,tk+1] 往后移动一个顶点 P i P_i Pi i = 1 , 2 , ⋯ k + 1 i=1, 2, \cdots k+1 i=1,2,k+1 定义第二段,其定义区间为 t ∈ [ t k + , t k + 2 ] t \in [t_{k+}, t_{k+2}] t[tk+,tk+2] 依次类推,最后 k + 1 k+1 k+1 个顶点, P i P_i Pi, i = n − k , b − k − 1 , ⋯ n i=n-k, b-k-1, \cdots n i=nk,bk1,n 定义最后一段,其定义区间为 t ∈ [ t n , t n + 1 ] t\in[t_n, t_{n+1}] t[tn,tn+1], 因此,高于零次的 k k k 次B 样条曲线的定义域为

t ∈ [ t k , t n + 1 ] t \in [t_k, t_{n+1}] t[tk,tn+1]

三次均匀 B 样条曲线

{ F 0 , 3 ( t ) = 1 6 ( 1 − t ) 3 = ( − t 3 + 3 t 2 − 3 t + 1 ) F 1 , 3 ( t ) = 1 6 ( 3 t 3 − 6 t 2 + 4 ) F 2 , 3 ( t ) = 1 6 ( − 3 t 3 + 3 t 2 + 3 t + 1 ) F 3 , 3 ( t ) = 1 6 t 3 \begin{cases} F_{0,3}(t) = \frac{1}{6} (1-t)^3 = (-t^3 + 3t^2 -3t+1)\\ F_{1,3}(t) = \frac{1}{6} (3t^3 - 6t^2 +4)\\ F_{2,3}(t) = \frac{1}{6} (-3t^3 + 3t^2 + 3t +1) \\ F_{3,3}(t) = \frac{1}{6} t^3\\ \end{cases} F0,3(t)=61(1t)3=(t3+3t23t+1)F1,3(t)=61(3t36t2+4)F2,3(t)=61(3t3+3t2+3t+1)F3,3(t)=61t3

在这里插入图片描述

三次 B 样条的几何性质

{ p ( 0 ) = 1 6 ( p 0 + 4 p 1 + p 2 ) = 1 3 ( p 0 + p 2 2 ) + 2 3 p 1 = 1 3 p m + 2 3 p 1 p ( 1 ) = 1 6 ( p 1 + 4 p 2 + p 3 ) = 1 3 ( p 1 + p 3 2 ) + 2 3 p 2 = 1 3 p n + 2 3 p 2 \begin{cases} p(0) = \frac{1}{6}(p_0 + 4 p_1 + p_2) = \frac{1}{3} (\frac{p_0 + p_2}{2}) + \frac{2}{3}p_1 = \frac{1}{3}p_m + \frac{2}{3}p_1\\ p(1) = \frac{1}{6}(p_1 + 4 p_2 + p_3) = \frac{1}{3} (\frac{p_1 + p_3}{2}) + \frac{2}{3}p_2 = \frac{1}{3}p_n + \frac{2}{3}p_2\\ \end{cases} {p(0)=61(p0+4p1+p2)=31(2p0+p2)+32p1=31pm+32p1p(1)=61(p1+4p2+p3)=31(2p1+p3)+32p2=31pn+32p2

{ p ′ ( 0 ) = 1 2 ( p 2 − p 0 ) p ′ ( 1 ) = 1 2 ( p 3 + p 1 ) \begin{cases} p'(0) = \frac{1}{2}(p_2 - p_0) \\ p'(1) = \frac{1}{2}(p_3 + p_1) \\ \end{cases} {p(0)=21(p2p0)p(1)=21(p3+p1)

{ p ′ ′ ( 0 ) = p 0 − 2 p 1 + p 2 = 2 ( p 0 + p 2 2 − p ) = 2 ( p m − p 1 ) p ′ ′ ( 1 ) = p 1 − 2 p 2 + p 3 = 2 ( p 1 + p 3 2 − p 2 ) = 2 ( p n − p 2 ) \begin{cases} p''(0) = p_0 - 2p_1 + p_2 = 2(\frac{p_0 + p_2}{2} -p)= 2(p_m - p_1) \\ p''(1) = p_1 - 2p_2 + p_3 = 2(\frac{p_1 + p_3}{2} -p_2)= 2(p_n - p_2) \\ \end{cases} {p′′(0)=p02p1+p2=2(2p0+p2p)=2(pmp1)p′′(1)=p12p2+p3=2(2p1+p3p2)=2(pnp2)

在这里插入图片描述

#include <QWidget>
#include <QApplication>
#include <QPainter>
#include <QPointF>
#include <QPainterPath>const double knot[13] = {-3/6.0, -2/6.0, -1/6.0, 0.0, 1 / 6.0, 2 / 6.0, 3 / 6.0, 4 / 6.0, 5 / 6.0, 1.0, 7/ 6.0, 8/ 6.0, 9/6.0};double BasisFunctionValue(double t, int i, int k)
{double val1, val2, val;if (k == 0){if ((t >= knot[i]) && t < knot[i + 1]){return 1.0;}else{	// 其它return 0.0;}}if (k > 0){if (t < knot[i] || t > knot[i + k + 1]) {return 0.0;		// 其它}else{double coffcient1, coffcient2;	// 凸组合系数1 凸组合系数 2double denominator = 0.0;		// 分母denominator = knot[i + k] - knot[i];if (denominator == 0.0){// 约定 0/0 = 0coffcient1 = 0.0;}else{coffcient1 = (t - knot[i]) / denominator;	// 计算的第一项}denominator = knot[i + k + 1] - knot[i + 1];	// 递推公式第二项分母if (denominator == 0.0){// 约定 0/0 = 0coffcient2 = 0.0;}else{coffcient2 = (knot[i + k + 1] - t) / denominator;	// 递推公式第二项}val1 = coffcient1 * BasisFunctionValue(t, i, k - 1);	// 递推公式第一项的只val2 = coffcient2 * BasisFunctionValue(t, i+1, k - 1);	// 递推公式第二项的只val = val1 + val2;	// 基函数的值}}return val;
}void drawBSplineCure(QPainter* painter, const std::vector<QPointF>& P)
{// Set line colorQColor lineColor(0, 0, 255);// Set point colorQColor pointColor(255, 0, 0);QPainterPath bezierPath;QPen pen(lineColor);pen.setWidth(2);  // Set the line width as neededpainter->setPen(pen);QPointF center(900, 600);  // Center coordinatesint k = 3;  // Degree of the B-spline curvefor (int i = k; i <= P.size() - k; ++i){double tStep = 0.01;for (double t = 0.0; t <= 1.0; t += tStep){QPointF p(0, 0);  // Discrete pointfor (int j = 0; j < P.size(); ++j){double BValue = BasisFunctionValue(t, j, k);p += P[j] * BValue;}if (t == 0.0){bezierPath.moveTo(p + center);}else{bezierPath.lineTo(p + center);}painter->setPen(pointColor);painter->setBrush(Qt::NoBrush);painter->drawEllipse(p + center, 5, 5);}}painter->drawPath(bezierPath);
}void drawControlPolygon(QPainter* painter, std::vector<QPointF> P)
{QColor lineColor(0, 0, 0);QColor pointColor(0, 0, 255);  // Blue color for pointsQPen polyLinePen(lineColor);painter->setPen(polyLinePen);QBrush pointBrush(pointColor);painter->setBrush(pointBrush);QPointF center(900, 600);QVector<QPointF> shiftedPoints;std::transform(P.begin(), P.end(), std::back_inserter(shiftedPoints),[center](const QPointF& point) { return point + center; });painter->drawPolyline(shiftedPoints.data(), shiftedPoints.size());for (const QPointF& point : shiftedPoints){painter->drawEllipse(point, 5, 5);}}std::vector<QPointF> getControlPoints(){std::vector<QPointF> controlPoints = {QPointF(-600, -50),QPointF(-500, 200),  // 控制点QPointF(-160, 250),QPointF(-250, -300),QPointF(160, -200),  // 控制点QPointF(200, 200),QPointF(600, 180),QPointF(700, -60),   // 控制点QPointF(500, -200)};return controlPoints;
}class MyWidget : public QWidget {
public:MyWidget(QWidget* parent = nullptr) : QWidget(parent) {setFixedSize(1800, 1200);}protected:void paintEvent(QPaintEvent* event) override {Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);std::vector<QPointF> controlPoints = getControlPoints();drawBSplineCure(&painter, controlPoints);drawControlPolygon(&painter, controlPoints);}public:int n = 8;int k = 3;};int main(int argc, char* argv[]) {QApplication app(argc, argv);MyWidget widget;widget.show();return app.exec();
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DeepPurpose 生物化学深度学习库;蛋白靶点小分子药物对接亲和力预测虚拟筛选

参考: https://blog.csdn.net/c9Yv2cf9I06K2A9E/article/details/107649770 https://github.com/kexinhuang12345/DeepPurpose ##安装 pip install DeepPurpose rdkitDeepPurpose包括: 数据: 关联TDC库下载,是同一作者开发的 https://blog.csdn.net/weixin_42357472/artic…

认识Git

&#x1f30e;初识Git 初识Git 什么是Git Git的安装       Centos平台安装Git       Ubuntu平台安装Git Git的基本操作       创建远程仓库       配置Git 认识工作区、暂存区与版本库       添加文件到暂存区       将暂存区文件提交至本…

web期末个人引导页透明版

效果图 代码 css代码 * {box-sizing: border-box; }body {color: #2b2c48;font-family: "Jost", sans-serif;background-image: url(../img/bg.jpg);background-repeat: no-repeat;background-size: cover;background-position: center;background-attachment: fix…

在 PyCharm 中使用 Copilot

GitHub Copilot 由 OpenAI Codex 提供支持&#xff0c;可帮助用户在编辑器中实时工作。 它使用强大的 GPT-3 模型版本&#xff0c;该模型在大量开源代码上进行训练。 此外&#xff0c;GitHub Copilot 可在不同的 IDE&#xff08;集成开发环境&#xff09;上使用&#xff0c;包…

【数据仓库与联机分析处理】数据仓库工具Hive

目录 一、Hive简介 &#xff08;一&#xff09;什么是Hive &#xff08;二&#xff09;优缺点 &#xff08;三&#xff09;Hive架构原理 &#xff08;四&#xff09;Hive 和数据库比较 二、MySQL的安装配置 三、Hive的安装配置 1、下载安装包 2、解压并改名 3、配置环…

力扣labuladong一刷day54天前缀树

力扣labuladong一刷day54天前缀树 文章目录 力扣labuladong一刷day54天前缀树一、208. 实现 Trie (前缀树)二、648. 单词替换三、211. 添加与搜索单词 - 数据结构设计四、1804. 实现 Trie &#xff08;前缀树&#xff09; II五、677. 键值映射 一、208. 实现 Trie (前缀树) 题…

Hive实战:网址去重

文章目录 一、实战概述二、提出任务三、完成任务&#xff08;一&#xff09;准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 &#xff08;二&#xff09;实现步骤1、启动Hive Metastore服务2、启动Hive客户端3、基于HDFS数据文件创建Hive外部表4、利用Hive SQL实…

【MySQL用户管理】

目录&#xff1a; 前言用户管理创建用户删除用户修改用户密码修改用户密码安全检测设置 用户权限添加权限回收权限 总结 前言 剑指offer&#xff1a;一年又13天 用户管理 mysql> show databases; -------------------- | Database | -------------------- | inf…

R304S 指纹识别模块功能实现示例

1 基本通信流程 1.1 UART 命令包的处理过程 1.2 UART 数据包的发送过程 UART 传输数据包前&#xff0c;首先要接收到传输数据包的指令包&#xff0c;做好传输准备后发送成功应答包&#xff0c;最后才开始传输数据包。数据包主要包括&#xff1a;包头、设备地址、包标识、包长…

Java:结束本机端口被占用进程

前言 在实际开发当中我们&#xff0c;往往在idea中将某个服务的启动给关闭了&#xff0c;但是在nacos的某个服务上&#xff0c;我们却可以看到本地别名服务还是在上面挂载着本地再次启动的时候就提示【端口被占用】&#xff0c;今天就说一下如何解决这个问题 操作 点击即可预…

嵌入式(七)看门狗 | 看门狗工作模式 寄存器 时钟系统

文章目录 1 看门狗原理2 功能3 看门狗工作模式4 看门狗控制寄存器5 时钟系统 及其寄存器 1 看门狗原理 看门狗(Watch Dog Timer&#xff0c; WDT)是一种专门用于监测单片机程序运行状态的芯片组件。其实质是一个计数器&#xff0c;一般给看门狗初始一个比较大的数&#xff0c;…

【数据结构—排序—交换排序】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、排序的概念及其运用 1、排序的概念 2、排序运用 3、 常见的排序算法 二、交换排序 1、冒泡排序 1.1算法讲解 1.2冒泡排序的实现&#xff1a; 1.2.1头文件的…