MATLAB绘制B样条曲线[通俗易懂]

MATLAB绘制B样条曲线[通俗易懂]1B样条曲线1.1B样条曲线定义B样条方法具有表示与设计自由型曲线曲面的强大功能,是形状数学描述的主流方法之一,另外B样条方法是目前工业产品几何定义国际标准——有理B样条方法(NURBS)的基础。B样条方法兼备了Bezier方法的一切优点,包括几何不变性,仿射不变性等等,同时克服了Bezier方法中由于整体表示带来不具有局部性质的缺点(移动一个控制顶点将会影响整个曲线)。B样条曲线方程可写为

大家好,又见面了,我是你们的朋友全栈君。

1 B样条曲线

1.1 B样条曲线定义

B样条方法具有表示与设计自由型曲线曲面的强大功能,是形状数学描述的主流方法之一,另外B样条方法是目前工业产品几何定义国际标准——有理B样条方法(NURBS)的基础。B样条方法兼备了Bezier方法的一切优点,包括几何不变性,仿射不变性等等,同时克服了Bezier方法中由于整体表示带来不具有局部性质的缺点(移动一个控制顶点将会影响整个曲线)。B样条曲线方程可写为:

p(u)=i=0ndiNi,k(u)



其中,

di(i=0,1…n)
为控制顶点(坐标),

Ni,k(i=0,1…n)


k
次规范B样条基函数,最高次数是



k

。基函数是由一个称为节点矢量的非递减参数

u
的序列



U



u0u1...un+k+1
所决定的

k
次分段多项式。

B样条的基函数通常采用Cox-deBoor递推公式:




Ni,0(u)={1,  if  uiuui+10,  othersNi,k=uuiui+kuiNi,k1(u)+ui+k+1uui+k+1ui+1Ni+1,k1(u)define  00=0



式中

i
为节点序号,



k

是基函数的次数,共有

n+1
个控制顶点。
注意区分节点和控制顶点,节点是在节点矢量 U 中取得,控制顶点则是坐标点,决定B样条的控制多边形。Cox-deBoor递推公式是B样条曲线的定义的核心,该部分在程序中实现可采用递归的方式:

% BaseFunction.m文件
function Nik_u = BaseFunction(i, k , u, NodeVector)
% 计算基函数Ni,k(u),NodeVector为节点向量

if k == 0       % 0次B样条
    if (u >= NodeVector(i+1)) && (u < NodeVector(i+2))
        Nik_u = 1.0;
    else
        Nik_u = 0.0;
    end
else
    Length1 = NodeVector(i+k+1) - NodeVector(i+1);
    Length2 = NodeVector(i+k+2) - NodeVector(i+2);      % 支撑区间的长度
    if Length1 == 0.0       % 规定0/0 = 0
        Length1 = 1.0;
    end
    if Length2 == 0.0
        Length2 = 1.0;
    end
    Nik_u = (u - NodeVector(i+1)) / Length1 * BaseFunction(i, k-1, u, NodeVector) ...
        + (NodeVector(i+k+2) - u) / Length2 * BaseFunction(i+1, k-1, u, NodeVector);
end

所给程序可用于计算基函数

Ni,k(u)
的值,程序中对不同类型的B样条曲线区别在于节点矢量 NodeVector 的取值不同。

1.2 B样条曲线的分类

根据节点矢量中节点的分布情况不同,可以划分4中类型的B样条曲线:
1. 均匀B样条曲线
节点矢量中节点为沿参数轴均匀或等距分布。
2. 准均匀B样条曲线
其节点矢量中两端节点具有重复度 k+1 ,即 u0=u1=...=uk un+1=un+2=...=un+k+1 ,所有的内节点均匀分布,具有重复度1。
3. 分段Bezier曲线
其节点矢量中两端节点的重复度与类型2相同,为 k+1 。不同的是内节点重复度为 k 。该类型有限制条件,控制顶点数减1必须等于次数的正整数倍,即

nk=

4. 一般非均匀B样条曲线
对任意分布的节点矢量 U=[u0,u1...un+k+1] ,只要在数学上成立都可选取。

2 B样条曲线的绘制

2.1 节点矢量的确定

不同类型的B样条曲线区别主要在于节点矢量,对于具有 n+1 个控制顶点 (P0,P1,...,Pn) k 次B样条曲线,无论是哪种类型都具有

n+k+2
个节点 ([u0,u1...un+k+1])

$n=4,k=2时不同类型的节点矢量$

根据图示,三种类型的B样条曲线对应的节点矢量分别为:

[01727374757671]

[0 0 013231 1 1]

[0 0 012121 1 1]

需要注意的是分段Bezier曲线必须满足 nk=

这里给出准均匀B样条和分段Bezier曲线的生成节点矢量的代码,均匀B样条的很简单就不列出了。假设共n+1个控制顶点,k次B样条,输入参数为 n, k ,输出节点矢量NodeVector。


准均匀B样条曲线的节点矢量生成:

% U_quasi_uniform.m文件
function NodeVector = U_quasi_uniform(n, k)
% 准均匀B样条的节点向量计算,共n+1个控制顶点,k次B样条
NodeVector = zeros(1, n+k+2);
piecewise = n - k + 1;       % 曲线的段数
if piecewise == 1       % 只有一段曲线时,n = k
    for i = n+2 : n+k+2
        NodeVector(1, i) = 1;
    end
else
    flag = 1;       % 不止一段曲线时
    while flag ~= piecewise
        NodeVector(1, k+1+flag) = NodeVector(1, k + flag) + 1/piecewise;
        flag = flag + 1;
    end
    NodeVector(1, n+2 : n+k+2) = 1;
end

分段Bezier曲线的节点矢量生成:

% U_piecewise_Bezier.m文件
function NodeVector = U_piecewise_Bezier(n, k)
% 分段Bezier曲线的节点向量计算,共n+1个控制顶点,k次B样条
% 分段Bezier端节点重复度为k+1,内间节点重复度为k,且满足n/k为正整数

if ~mod(n, k) && (~mod(k, 1) && k>=1)   % 满足n是k的整数倍且k为正整数
    NodeVector = zeros(1, n+k+2);   % 节点矢量长度为n+k+2
    NodeVector(1, n+2 : n+k+2) = ones(1, k+1);  % 右端节点置1

    piecewise = n / k;      % 设定内节点的值
    Flg = 0;
    if piecewise > 1
        for i = 2 : piecewise
            for j = 1 : k
                NodeVector(1, k+1 + Flg*k+j) = (i-1)/piecewise;
            end
            Flg = Flg + 1;
        end
    end

else
    fprintf('error!\n');
end

2.2 B样条曲线的绘制

根据B样条曲线的定义公式,曲线上任一点坐标值是参数变量 u 的函数,用矩阵形式表示



p(u)=(d0d1dn)N0,k(u)N1,k(u)Nn,k(u)

只需要确定控制顶点 di 、曲线的次数 k 以及基函数

Ni,k(u)
,就完全确定了曲线。


B样条曲线的绘制函数:

% DrawSpline.m文件
function DrawSpline(n, k, P, NodeVector)
% B样条的绘图函数
% 已知n+1个控制顶点P(i), k次B样条,P是2*(n+1)矩阵存控制顶点坐标, 节点向量NodeVector
plot(P(1, 1:n+1), P(2, 1:n+1),...
                    'o','LineWidth',1,...
                    'MarkerEdgeColor','k',...
                    'MarkerFaceColor','g',...
                    'MarkerSize',6);
line(P(1, 1:n+1), P(2, 1:n+1));
Nik = zeros(n+1, 1);
for u = 0 : 0.005 : 1-0.005
    for i = 0 : 1 : n
        Nik(i+1, 1) = BaseFunction(i, k , u, NodeVector);
    end
    p_u = P * Nik;
    if u == 0
        tempx = p_u(1,1);
        tempy = p_u(2,1);
        line([tempx p_u(1,1)], [tempy p_u(2,1)],...
            'Marker','.','LineStyle','-', 'Color',[.3 .6 .9], 'LineWidth',3);
    else
        line([tempx p_u(1,1)], [tempy p_u(2,1)],...
            'Marker','.','LineStyle','-', 'Color',[.3 .6 .9], 'LineWidth',3);
        tempx = p_u(1,1);
        tempy = p_u(2,1);
    end
end

调用 DrawSpline(n, k, P, NodeVector) 函数就能绘制曲线,注意输入变量要正确。


下面给出绘制三种不同B样条曲线的命令流,可以参考比较每种类型之间的区别。

% 绘制三种类型的B样条曲线,需要前面所给的所有.m文件
clear all;
%控制顶点
P = [9.036145, 21.084337, 37.607573, 51.893287, 61.187608;
    51.779661, 70.084746, 50.254237, 69.745763, 49.576271];

n = 4; k = 2;

flag = 2;
% flag = 1,绘制均匀B样条曲线
% flag = 2, 绘制准均匀B样条曲线
% flag = 3, 绘制分段Bezier曲线

switch flag
    case 1
        NodeVector = linspace(0, 1, n+k+2); % 均匀B样条的节点矢量

        % 绘制样条曲线
        plot(P(1, 1:n+1), P(2, 1:n+1),...
                        'o','LineWidth',1,...
                        'MarkerEdgeColor','k',...
                        'MarkerFaceColor','g',...
                        'MarkerSize',6);
        line(P(1, 1:n+1), P(2, 1:n+1));
        Nik = zeros(n+1, 1);
        for u = k/(n+k+1) : 0.001 : (n+1)/(n+k+1)
            % for u = 0 : 0.005 : 1
            for i = 0 : 1 : n
                Nik(i+1, 1) = BaseFunction(i, k , u, NodeVector);
            end
        p_u = P * Nik;
        line(p_u(1,1), p_u(2,1), 'Marker','.','LineStyle','-', 'Color',[.3 .6 .9]);
        end
    case 2
        NodeVector = U_quasi_uniform(n, k); % 准均匀B样条的节点矢量
        DrawSpline(n, k, P, NodeVector);
    case 3
        NodeVector = U_piecewise_Bezier(n, k);  % 分段Bezier曲线的节点矢量
        DrawSpline(n, k, P, NodeVector);
    otherwise
        fprintf('error!\n');
end

三种类型的B样条曲线:
1. 均匀B样条曲线
均匀B样条曲线
2. 准均匀B样条曲线
准均匀B样条曲线
3. 分段Bezier曲线
分段Bezier曲线

参考文献:

[1] 施法中. 计算机辅助几何设计与非均匀有理B样条(修订版)[M]. 北京: 高等教育出版社, 2013 : 217-248.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/150361.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)
blank

相关推荐

  • 一周第四次课(3月22日)1.13 单用户模式 1.14 救援模式 1.15 克隆虚拟机 1.16 Linux机器相互登录…

    一周第四次课(3月22日)1.13 单用户模式 1.14 救援模式 1.15 克隆虚拟机 1.16 Linux机器相互登录…

  • 算法时间复杂度分析(一)

    算法时间复杂度分析(一)金庸武侠中描述一种武功招式的时候,经常会用到“快、准、狠”这3个字眼。同样,在计算机中我们衡量一种算法的执行效率的时候也会考量3个方面:“快、省、稳”。具体点来讲就是我们在实现某一种算法的时候,最终目的就是要求计算机(CPU)在最短的时间内,用最少的内存稳定的输出正确的结果。这一章节主要来理解“快”,至于“省”和“稳”,我会在后续章节进行讲解。那如何来判断某一段代码运行的是否足够快呢…

  • 什么是MVC三层架构?「建议收藏」

    什么是MVC三层架构?「建议收藏」1.1、什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。 是将业务逻辑、数据、显示分离的方法来组织代码。 MVC主要作用是降低了视图与业务逻辑间的双向偶合。 MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。 Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:ValueObj

  • java中list,set,map集合的区别,及面试要点[通俗易懂]

    java中list,set,map集合的区别,及面试要点[通俗易懂](图一)1.面试题:你说说collection里面有什么子类。(其实面试的时候听到这个问题的时候,你要知道,面试官是想考察List,Set)正如图一,list和set是实现了collection接口的。(…

  • 【QGIS入门实战精品教程】2.1:初识QGIS软件[通俗易懂]

    【QGIS入门实战精品教程】2.1:初识QGIS软件[通俗易懂]从今天开始,我们一起来学习一款免费开源、对机器要求低、功能强大的GIS软件:QGIS!一、QGIS简介QGIS(原称QuantumGIS)是一个自由软件的桌面GIS软件。它提供数据的显示、编辑和分析功能。QGIS是一个用户界面友好的桌面地理信息系统,可运行在Linux、Unix、MacOSX和Windows等平台之上。QGIS是基于Qt,使用C++开发的一个用户界面友好、跨平台的免费开源版桌面地理信息系统。二、QGIS软件的主要特点支持多种GIS数据文件格式。通过GDAL..

  • Java对象数组

    Java对象数组所谓的对象数组,就是指包含了一组相关的对象,但是在对象数组的使用中一定要清楚一点:数组一定要先开辟空间,但是因为其是引用数据类型,所以数组里面的每一个对象都是null值,则在使用的时候数组中的每一个对象必须分别进行实例化操作。 对象数组的声明先定义,再开辟空间类名称对象数组名[]=null;对象数组名=new类名称[长度]; 定义并开辟数组类名称对象数…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号