均匀与准均匀 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=0∑nPiFi,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} t0≤t1≤⋯≤tn+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=n−k,b−k−1,⋯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(1−t)3=(−t3+3t2−3t+1)F1,3(t)=61(3t3−6t2+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(p2−p0)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)=p0−2p1+p2=2(2p0+p2−p)=2(pm−p1)p′′(1)=p1−2p2+p3=2(2p1+p3−p2)=2(pn−p2)

#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();
}

相关文章:
均匀与准均匀 B样条算法
B 样条曲线的定义 p ( t ) ∑ i 0 n P i F i , k ( t ) p(t) \sum_{i0}{n} P_i F_{i, k}(t) p(t)i0∑nPiFi,k(t) 方程中 n 1 n1 n1 个控制点, P i P_i Pi, i 0 , 1 , ⋯ n i0, 1, \cdots n i0,1,⋯n 要用到 n 1 n1 n1 个 k k k 次 B 样条基函数 …...
2023年12 月电子学会Python等级考试试卷(一级)答案解析
青少年软件编程(Python)等级考试试卷(一级) 分数:100 题数:37 一、单选题(共25题,共50分) 1. 下列程序运行的结果是?( ) print(hello) print(world) A. helloworld...
启发式算法解决TSP、0/1背包和电路板问题
1. Las Vegas 题目 设计一个 Las Vegas 随机算法,求解电路板布线问题。将该算法与分支限界算法结合,观察求解效率。 代码 python代码如下: # -*- coding: utf-8 -*- """ Date : 2024/1/4 Time : 16:21 Author : …...
阿里云新用户的定义与权益
随着云计算的普及,阿里云作为国内领先的云计算服务提供商,吸引了越来越多的用户。对于新用户来说,了解阿里云新用户的定义和相关权益非常重要,因为它关系到用户能否享受到更多的优惠和服务。 一、阿里云新用户的定义 阿里云新用户…...
go语言多线程操作
目录 引言 一、如何实现多线程 1. 线程的创建与管理: 2. 共享资源与同步: 3. 线程间通信: 4. 线程的生命周期管理: 5. 线程安全: 6. 考虑并发问题: 7. 性能与资源利用: 8. 特定语言或框架的工具和库: 二、go语言多线程 Goroutine 1. 轻量级: 2. 动态栈: 3. 调度:…...
GreatSQL社区2023全年技术文章总结
GreatSQL社区自成立以来一直致力于为广大的数据库爱好者提供一个交流与学习的平台。在2023年,我们见证了社区的蓬勃发展,见证了众多技术文章的诞生与分享。 此篇总结呈现GreatSQL社区2023年社区技术文章在CSDN发布的全部。这些文章涵盖了GreatSQL、MGR、…...
【论文阅读笔记】Stable View Synthesis 和 Enhanced Stable View Synthesis
目录 Stable View Synthesis摘要引言 Enhanced Stable View Synthesis 从Mip-NeRF360的对比实验中找到的两篇文献,使用了卷积神经网络进行渲染和新视角合成,特此记录一下 ToDo Stable View Synthesis paper:https://readpaper.com/pdf-ann…...
网络报文分析程序的设计与实现(2024)
1.题目描述 在上一题的基础上,参照教材中各层报文的头部结构,结合使用 wireshark 软件(下载地址 https://www.wireshark.org/download.html#releases)观察网络各层报文捕获,解析和分析的过程(如下 图所示&a…...
贯穿设计模式-享元模式思考
写享元模式的时候,会想使用ConcurrentHashMap来保证并发,没有使用双重锁会不会有问题?但是在synchronize代码块里面需要尽量避免throw异常,希望有经验的同学能够给出解答? 1月6号补充:没有使用双重锁会有问…...
牛客刷题:BC45 小乐乐改数字(中等)
自我介绍:一个脑子不好的大一学生,c语言接触还没到半年,若涉及到效率等问题,各位都可以在评论区提出见解,谢谢啦。 该账号介绍:此帐号会发布游戏(目前还只会简单小游戏),…...
设计模式学习2
代理模式:Proxy 动机 “增加一层间接层”是软件系统中对许多复杂问题的一种常见解决方案。在面向对象系统中,直接食用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常见手段。 2.伪代码: class ISubject{ pu…...
Rust:如何判断位置结构的JSON串的成员的数据类型
如何判断位置结构的JSON串的成员的数据类型,给一个Rust的例子,其中包含对数组的判断? 在Rust中,你可以使用serde_json库来处理JSON数据,并通过serde_json::Value类型的方法来判断JSON串中成员的数据类型。以下是一个示…...
Kafka(五)生产者
目录 Kafka生产者1 配置生产者bootstrap.serverskey.serializervalue.serializerclient.id""acksallbuffer.memory33554432(32MB)compression.typenonebatch.size16384(16KB)max.in.flight.requests.per.connection5max.request.size1048576(1MB)receive.buffer.byte…...
【Leetcode】242.有效的字母异位词
一、题目 1、题目描述 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 示例1: 输入: s = "anagram", t = "nagaram" 输出: true示例2: 输入: …...
【数据库原理】(16)关系数据理论的函数依赖
一.函数依赖的概念 函数依赖是关系数据库中核心的概念,它指的是在属性集之间存在的一种特定的关系。这种关系表明,一个属性集的值可以唯一确定另一个属性集的值。 属性子集:在关系模式中,X和Y可以是单个属性,也可以是…...
脆弱的SSL加密算法漏洞原理以及修复方法
漏洞名称:弱加密算法、脆弱的加密算法、脆弱的SSL加密算法、openssl的FREAK Attack漏洞 漏洞描述:脆弱的SSL加密算法,是一种常见的漏洞,且至今仍有大量软件支持低强度的加密协议,包括部分版本的openssl。其实…...
SVN迁移至GitLab,并附带历史提交记录(二)
与《SVN迁移至GitLab,并附带历史提交记录》用的 git svn clone不同,本文使用svn2git来迁移项目代码。 一、准备工作 安装Git环境,配置本地git账户信息: git config --global user.name "XXX" git config --global us…...
如何创建容器搭建节点
1.注册Discord账号 https://discord.com/这是登录网址: https://discord.com/ 2.点击startnow注册,用discord注册或者邮箱注册都可,然后登录tickhosting Tick Hosting这是登录网址:Tick Hosting 3.创建servers 4.点击你创建的servers,按照图中步骤进行...
微众区块链观察节点的架构和原理 | 科普时间
践行区块链公共精神,实现更好的公众开放与监督!2023年12月,微众区块链观察节点正式面向公众开放接入功能。从开放日起,陆续有多个观察节点在各地运行,同步区块链数据,运行区块链浏览器观察检视数据…...
React Admin 前端脚手架之ant-design-pro
文章目录 一、React Admin 前端脚手架选型二、React Admin 前端脚手架之ant-design-pro三、ant-design-pro使用步骤四、调试主题五、常用总结(持续更新)EditableProTable组件 常用组件EditableProTable组件 编辑某行后,保存时候触发发送请求EditableProTable组件,添加记录提…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
