matlab实践(十):贝塞尔曲线

1.贝塞尔曲线

贝塞尔曲线的原理是基于贝塞尔曲线的数学表达式和插值算法。

贝塞尔曲线的数学表达式可以通过控制点来定义。对于二次贝塞尔曲线,它由三个控制点P0、P1和P2组成,其中P0和P2是曲线的起点和终点,P1是曲线上的一个中间点。曲线上的每个点可以通过参数t在0到1之间的取值来计算,公式如下:

B(t) = (1-t)^2 * P0 + 2 * t * (1-t) * P1 + t^2 * P2

其中,B(t)表示曲线上的点,t表示参数值,(1-t)表示参数值的补数。

对于三次贝塞尔曲线,它由四个控制点P0、P1、P2和P3组成,其中P0和P3是曲线的起点和终点,P1和P2是曲线上的两个中间点。曲线上的每个点可以通过参数t在0到1之间的取值来计算,公式如下:

B(t) = (1-t)^3 * P0 + 3 * t * (1-t)^2 * P1 + 3 * t^2 * (1-t) * P2 +
t^3 * P3

贝塞尔曲线的插值算法可以通过递归的方式来计算。对于二次贝塞尔曲线,可以通过将两个二次贝塞尔曲线的控制点作为新的控制点,再次应用贝塞尔曲线的计算公式来得到更高阶的曲线。同样地,对于三次贝塞尔曲线,可以通过将两个三次贝塞尔曲线的控制点作为新的控制点,再次应用贝塞尔曲线的计算公式来得到更高阶的曲线。

贝塞尔曲线的优点是可以通过调整控制点的位置来改变曲线的形状,同时保持曲线的平滑性。这使得贝塞尔曲线在计算机图形学和计算机辅助设计中得到广泛应用,例如绘制曲线、路径动画、字体设计等。

2.代码

贝塞尔曲线本质上是一个递推公式。
p ( i , j ) = ( 1 − u ) × p ( i − 1 , j ) + u × p ( i − 1 , j − 1 ) \color{red}{p(i,j)=(1-u)\times p(i-1,j)+u\times p(i-1,j-1)} p(i,j)=(1u)×p(i1,j)+u×p(i1,j1)
上述递推公式中 , i 表示贝塞尔曲线的阶数 , j 表示贝塞尔曲线中的点个数 ( 包含起止点 + 控制点 ) , u 表示比例取值范围 0 ~ 1 ;

function points = computeCubicBezierCurve(controlPoints, numPoints)
    numControlPoints = size(controlPoints, 2);
    t = linspace(0, 1, numPoints); % 在0到1之间生成numPoints个等间距的参数值
    points = zeros(2, numPoints); % 存储曲线上的点坐标
    
    for i = 1:numPoints
        B = zeros(2, 1);
        for j = 1:numControlPoints
            B = B + nchoosek(numControlPoints-1, j-1) * t(i)^(j-1) * (1 - t(i))^(numControlPoints-j) * controlPoints(:, j);
        end
        points(:, i) = B; % 存储点坐标
    end
end

这是用彗星图画的

P=randi(100,2,60);
position=computeCubicBezierCurve(P,100);

X=position(1,:);
Y=position(2,:);
figure(1);
h=gca;
plot(P(1,:),P(2,:),'g.-','MarkerSize',40);
c={
   '起点'};
text(P(1,1),P(2,1),c,'HorizontalAlignment','left')
hold on

text(P(1,end),P(2,end),'终点','HorizontalAlignment','left')
hold on

mycomet(h,X,Y,0.8)

2.1总代码

clc;clear;
% fps = 40;
% myVideo = VideoWriter('test2.avi'); 
% myVideo.FrameRate = fps; 
% open(myVideo); 
% P0=[1,2];
% P1=[5,8];
% P2=[10,10];
% P=[P0;P1;P2];
% X=@(t)(1-t).^2.*P0(1)+2.*t.*(1-t)*P1(1)+t.^2*P2(1);
% Y=@(t)(1-t).^2.*P0(2)+2.*t.*(1-t)*P1(2)+t.^2*P2(2);
% x1=@(t)(1-t).*P0(1)+t.*P1(1);
% y1=@(t)(1-t).*P0(2)+t.*P1(2);
% x2=@(t)(1-t).*P1(1)+t.*P2(1);
% y2=@(t)(1-t).*P1(2)+t.*P2(2);
% t=0:0.01:1;
% X=X(t);
% Y=Y(t);
% x1=x1(t);
% y1=y1(t);
% x2=x2(t);
% y2=y2(t);
P=randi(100,2,6);
position=computeCubicBezierCurve(P,100);

X=position(1,:);
Y=position(2,:);
% figure(1);
% h=gca;
% plot(P(1,:),P(2,:),'g.-','MarkerSize',40);
% c={'起点'};
% text(P(1,1),P(2,1),c,'HorizontalAlignment','left')
% hold on
% 
% text(P(1,end),P(2,end),'终点','HorizontalAlignment','left')
% hold on
% 
% mycomet(h,X,Y,0.8)

% figure
% for k = 1:101
%     plot(P(1,:),P(2,:),'k.-','MarkerSize',40),hold on
%     plot(X(k),Y(k),'r.'),hold on
%     % plot(x1(k),y1(k),'g.'),hold on
%     % plot(x2(k),y2(k),'g.'),hold on
%     % plot([x2(k),x1(k)],[y2(k),y1(k)],'y-'),hold on
%     axis([min(P(1,:)),max(P(1,:)),min(P(2,:)),max(P(2,:))]),drawnow
%     frame = getframe(gcf);
%     im = frame2im(frame); 
%     writeVideo(myVideo,im); 
% end
% close(myVideo); 
plot(P(1,:),P(2,:),'g.-','MarkerSize',40),hold on
plot(X,Y)
hold on
p = plot(X(1),Y(1),'o','MarkerFaceColor','red');
hold off
axis manual
pic_num=1;
for k = 2:101
    p.XData = X(k);
    p.YData = Y(k);
    
    F=getframe(gcf);
    I=frame2im(F);
    [I,map]=rgb2ind(I,256);
    if pic_num==1
    imwrite(I,map,'test.gif','gif','Loopcount',inf,'DelayTime',0.2);
    elseif mod(pic_num,3)==1
    imwrite(I,map,'test.gif','gif','WriteMode','append','DelayTime',0.2);
    end
    pic_num = pic_num + 1;
 
    drawnow limitrate
end
function mycomet(varargin)
%COMET  Comet-like trajectory.
%   COMET(Y) displays an animated comet plot of the vector Y.
%   COMET(X,Y) displays an animated comet plot of vector Y vs. X.
%   COMET(X,Y,p) uses a comet of length p*length(Y).  Default is p = 0.10.
%
%   COMET(AX,...) plots into AX instead of GCA.
%
%   Example:
%       t = -pi:pi/200:pi;
%       comet(t,tan(sin(t))-sin(tan(t)))
%
%   See also COMET3.

%   Charles R. Denham, MathWorks, 1989.
%   Copyright 1984-2022 The MathWorks, Inc.

% Parse possible Axes input
nnn=0.05;

[ax,args,nargs] = axescheck(varargin{
   :});
if nargs < 1
    error(message('MATLAB:narginchk:notEnoughInputs'));
elseif nargs > 3
    error(message('MATLAB:narginchk:tooManyInputs'));
end

% Parse the rest of the inputs
bodyLengthProportion = 0.10;
if nargs < 2, x = args{
   1}; y = x; x = 1:length(y); end
if nargs == 2, [x,y] = deal(args{
   :}); end
if nargs == 3, [x,y,bodyLengthProportion] = deal(args{
   :}); end

if ~isscalar(bodyLengthProportion) || ~isreal(bodyLengthProportion) ||  bodyLengthProportion < 0 || bodyLengthProportion >= 1
    error(message('MATLAB:comet:InvalidP'));
end

x = matlab.graphics.chart.internal.datachk(x);
y = matlab.graphics.chart.internal.datachk(y);

if ~isvector(x) || ~isvector(y) || numel(x) ~= numel(y)
    error(message('MATLAB:comet:XYVectorsSameLength'));
end

ax = newplot(ax);

if ~strcmp(ax.NextPlot,'add')
    % If NextPlot is 'add', assume other objects are driving the limits.
    % Otherwise, set the limits so that the axes limits don't jump around
    % during animation.
    [minx,maxx] = minmax(x);
    [miny,maxy] = minmax(y);
    if ~isa(ax,'matlab.graphics.axis.GeographicAxes') && ~isa(ax,'map.graphics.axis.MapAxes')
        axis(ax,[minx maxx miny maxy])
    else
        % Latitudes are the first axis (x) and longitudes are the second
        % axis (y).
        latmin = minx;
        latmax = maxx;
        lonmin = miny;
        lonmax = maxy;
        
        % Buffer the limits for better display.
        bufferInPercent = 5;
        f = 1 + bufferInPercent / 100;
        half = f * (latmax - latmin)/2;
        latlim = [-half, half] + (latmin + latmax)/2;
        latlim(1) = max(latlim(1), -90);
        latlim(2) = min(latlim(2),  90);
        half = f * (lonmax - lonmin)/2;
        lonlim = [-half, half] + (lonmin + lonmax)/2;
        
        geolimits(ax,latlim,lonlim)
    end
end

totalLength = length(x);
bodyLength = round(bodyLengthProportion*totalLength);

head = line('Parent',ax,'SeriesIndex_I',0,'Marker','o','LineStyle','none', ...
            'XData',x(1),'YData',y(1),'Tag','head');
body = matlab.graphics.animation.AnimatedLine('SeriesIndex_I',0,...
    'Parent',ax,'MaximumNumPoints',max(1,bodyLength),'tag','body');
tail = matlab.graphics.animation.AnimatedLine('Parent',ax, 'SeriesIndex_I',0,...
    'LineStyle','-','MaximumNumPoints',1+totalLength,'tag','tail'); %Add 1 for any extra points

if isequal(body.Color,tail.Color) && isequal(body.LineStyle, tail.LineStyle)
    body.LineStyle='--';
end

if length(x) < 2000
    updateFcn = @()drawnow;
else
    updateFcn = @()drawnow('limitrate');
end

% Grow the body
for i = 1:bodyLength
    % Protect against deleted objects following the call to drawnow.
    if ~(isvalid(head) && isvalid(body))
        return
    end
    set(head,'xdata',x(i),'ydata',y(i));
    addpoints(body,x(i),y(i));
    updateFcn();
    pause(nnn)
end

% Add a drawnow to capture any events / callbacks
drawnow

% Initialize tail with first point. The next point will be added in the
% first iteration of the primary loop below, creating the first line
% segment of the tail.
addpoints(tail,x(1),y(1));

% Primary loop
for i = bodyLength+1:totalLength
    % Protect against deleted objects following the call to drawnow.
    if ~(isvalid(head) && isvalid(body) && isvalid(tail))
        return
    end
    set(head,'xdata',x(i),'ydata',y(i));
    addpoints(body,x(i),y(i));
    
    nextTailIndex = i-bodyLength+1;
    if(nextTailIndex<=totalLength)
        addpoints(tail,x(nextTailIndex),y(nextTailIndex));
    end
    updateFcn();
    pause(nnn)
end
drawnow

% Allow tail to continue on to the full length. The last point added to the 
% tail in the primary loop above was at index (totalLength-bodyLength+1), 
% so this loop starts at the following index. 
for i = totalLength-bodyLength+2:totalLength
    % Protect against deleted objects following the call to drawnow.
    if ~isvalid(tail)
        return
    end
    addpoints(tail,x(i),y(i));
    updateFcn();
    pause(nnn)
end
drawnow

end

function [minx,maxx] = minmax(x)
minx = min(x(isfinite(x)));
maxx = max(x(isfinite(x)));
if minx == maxx
    minx = maxx-1;
    maxx = maxx+1;
end
end
function points = computeCubicBezierCurve(controlPoints, numPoints)
    numControlPoints = size(controlPoints, 2);
    t = linspace(0, 1, numPoints); % 在0到1之间生成numPoints个等间距的参数值
    points = zeros(2, numPoints); % 存储曲线上的点坐标
    
    for i = 1:numPoints
        B = zeros(2, 1);
        for j = 1:numControlPoints
            B = B + nchoosek(numControlPoints-1, j-1) * t(i)^(j-1) * (1 - t(i))^(numControlPoints-j) * controlPoints(:, j);
        end
        points(:, i) = B; % 存储点坐标
    end
end

3.效果

三个点
在这里插入图片描述

四个点

在这里插入图片描述
五个点
在这里插入图片描述

六个点
在这里插入图片描述

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-07 13:16:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-07 13:16:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-07 13:16:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-07 13:16:04       20 阅读

热门阅读

  1. Windows11 和 MacOS 内存优化比较

    2023-12-07 13:16:04       41 阅读
  2. 2次MD5加密——用于分布式对话

    2023-12-07 13:16:04       34 阅读
  3. git: 修改commit的comment

    2023-12-07 13:16:04       26 阅读
  4. 大型语言模型在实体关系提取中的应用探索

    2023-12-07 13:16:04       41 阅读
  5. Linux-网络服务和端口

    2023-12-07 13:16:04       34 阅读
  6. 数据库——习题

    2023-12-07 13:16:04       32 阅读
  7. Mac下更新python

    2023-12-07 13:16:04       31 阅读
  8. C#编程题分享(5)

    2023-12-07 13:16:04       33 阅读
  9. CommonJs和ES6模块区别,项目中的运用差距

    2023-12-07 13:16:04       35 阅读
  10. Gitlab 安装手册

    2023-12-07 13:16:04       33 阅读