1. 定义

给定 n + 1 n+1 n+1个点的位置矢量 P i ( i = 0 , 1 , … , n ) P_i(i=0,1,\dots,n) Pi​(i=0,1,…,n),则Bezier曲线可以定义为
P ( t ) = ∑ i = 0 n P i B i , n ( t ) , t ∈ [ 0 , 1 ] P(t)=\sum_{i=0}^nP_iB_{i,n}(t),\quad t \in [0,1] P(t)=i=0∑n​Pi​Bi,n​(t),t∈[0,1]
其中 P i P_i Pi​(i=0,1,\dots,n)构成该Bezier曲线的特征多边形, B i , n ( t ) B_{i,n}(t) Bi,n​(t)是 n n n次Bernstein基函数
B i , n ( t ) = C n i t i ( 1 − t ) n − i = n ! i ! ( n − i ) ! t i ⋅ ( 1 − t ) n − i , ( i = 0 , 1 , … , n ) B_{i,n}(t) = C_n^it^i(1-t)^{n-i}=\frac{n!}{i!(n-i)!}t^i\cdot (1-t)^{n-i},\quad (i=0,1,\dots,n) Bi,n​(t)=Cni​ti(1−t)n−i=i!(n−i)!n!​ti⋅(1−t)n−i,(i=0,1,…,n)
其中 0 0 = 1 , 0 ! = 1 0^0=1,0!=1 00=1,0!=1。

2. Bezier曲线的递推算法

  计算Bez曲线上的点,可用Bezier曲线方程直接计算,但使用de Casteljau提出的递推算法则简单得多。
  由 n + 1 n+1 n+1个控制点 P i ( i = 0 , 1 , … , n ) P_i(i=0,1,\dots,n) Pi​(i=0,1,…,n)定义的 n n n次Bezier曲线 P 0 n P_0^n P0n​可被定义为分别由前、后 n n n个控制点定义的两条 n − 1 n-1 n−1次Bezier曲线 P 0 n − 1 P_0^{n-1} P0n−1​与 P 1 n − 1 P_1^{n-1} P1n−1​的线性组合
P 0 n = ( 1 − t ) P 0 n − 1 + t P 1 n − 1 , t ∈ [ 0 , 1 ] P_0^n = (1-t)P_0^{n-1}+tP_1^{n-1},\quad t \in[0,1] P0n​=(1−t)P0n−1​+tP1n−1​,t∈[0,1]
由此得到Bezier曲线的递推计算公式为
P i k = { P i , k = 0 ( 1 − t ) P i k − 1 + t P i + 1 k − 1 , k = 1 , 2 , … , n , i = 0 , 1 , … , n − k P_i^k= \begin{cases} P_i, & k=0 \\ (1-t)P_i^{k-1}+tP_{i+1}^{k-1}, & k=1,2,\dots,n,i=0,1,\dots,n-k \end{cases} Pik​={Pi​,(1−t)Pik−1​+tPi+1k−1​,​k=0k=1,2,…,n,i=0,1,…,n−k​

3. 代码实现(python)

如果直接采用递归的方法会有大量的重复计算,这样的求解和斐波那契数列的递归方法类似,参考网上做法,可以使用三个for循环可以简化该方法。

# -*- coding: UTF-8 -*-
import numpy as np
from scipy.special import comb, perm
from matplotlib import pyplot as pltclass MyBezier:def __init__(self, line):self.line = lineself.index_02 = None  # 保存拖动的这个点的索引self.press = None     # 状态标识,1为按下,None为没按下self.pick = None      # 状态标识,1为选中点并按下,None为没选中self.motion = None    # 状态标识,1为进入拖动,None为不拖动self.xs = list()      # 保存点的x坐标self.ys = list()      # 保存点的y坐标self.cidpress = line.figure.canvas.mpl_connect('button_press_event', self.on_press)        # 鼠标按下事件self.cidrelease = line.figure.canvas.mpl_connect('button_release_event', self.on_release)  # 鼠标放开事件self.cidmotion = line.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)     # 鼠标拖动事件self.cidpick = line.figure.canvas.mpl_connect('pick_event', self.on_picker)                # 鼠标选中事件def on_press(self, event): # 鼠标按下调用if event.inaxes!=self.line.axes: returnself.press = 1def on_motion(self, event): # 鼠标拖动调用if event.inaxes!=self.line.axes: returnif self.press is None: returnif self.pick is None: returnif self.motion is None: # 整个if获取鼠标选中的点是哪个点self.motion = 1x = self.xsxdata = event.xdataydata = event.ydataindex_01 = 0for i in x:if abs(i - xdata) < 0.02: # 0.02 为点的半径if abs(self.ys[index_01] - ydata) < 0.02:breakindex_01 = index_01 + 1self.index_02 = index_01if self.index_02 is None: returnself.xs[self.index_02] = event.xdata # 鼠标的坐标覆盖选中的点的坐标self.ys[self.index_02] = event.ydataself.draw_01()def on_release(self, event): # 鼠标放开调用if event.inaxes!=self.line.axes: returnif self.pick == None: # 如果不是选中点,那就添加点self.xs.append(event.xdata)self.ys.append(event.ydata)if self.pick == 1 and self.motion != 1: # 如果是选中点,但不是拖动点,那就降阶x = self.xsxdata = event.xdataydata = event.ydataindex_01 = 0for i in x:if abs(i - xdata) < 0.02:if abs(self.ys[index_01] - ydata) < 0.02:breakindex_01 = index_01 + 1self.xs.pop(index_01)self.ys.pop(index_01)self.draw_01()self.pick = None # 所有状态恢复,鼠标按下到释放为一个周期self.motion = Noneself.press = Noneself.index_02 = Nonedef on_picker(self, event): # 选中调用self.pick = 1def draw_01(self): # 绘图函数self.line.clear()            # 不清除的话会保留原有的图self.line.axis([0,1,0,1])   # x和y范围0到1self.bezier(self.xs,self.ys) # Bezier曲线self.line.scatter(self.xs, self.ys,color='b',s=200, marker="o",picker=5) # 画点self.line.plot(self.xs, self.ys,color='r') # 画线self.line.figure.canvas.draw() # 重构子图def bezier(self,*args): # Bezier曲线公式转换,获取x和yn = len(args[0])  # 点的个数xarray,yarray = [],[]x,y = [],[]index = 0for t in np.linspace(0,1):for i in range(1,n):for j in range(0,n-i):if i == 1:xarray.insert(j,args[0][j]*(1-t) + args[0][j+1]*t)yarray.insert(j,args[1][j]*(1-t) + args[1][j+1]*t)continue# i != 1时,通过上一次迭代的结果计算xarray[j] = xarray[j]*(1 - t) + xarray[j+1]*tyarray[j] = yarray[j]*(1 - t) + yarray[j+1]*tif n == 1:x.insert(index,args[0][0])y.insert(index,args[1][0])else:x.insert(index,xarray[0])y.insert(index,yarray[0])xarray = []yarray = []index = index+1self.line.plot(x,y)fig = plt.figure(2,figsize=(12,6)) #创建第2个绘图对象,1200*600像素
ax = fig.add_subplot(111) #一行一列第一个子图
ax.set_title('My Bezier')
myBezier = MyBezier(ax)
plt.xlabel('X')
plt.ylabel('Y')
plt.show()

结果演示:

参考博客:
https://www.cnblogs.com/GH-123/p/7898774.html
https://blog.csdn.net/lafengxiaoyu/article/details/51296411
https://blog.csdn.net/lafengxiaoyu/article/details/56294678

Bezier曲线——de Casteljau递推算法实现相关推荐

  1. B样条曲线——de Boor递推算法实现

    B样条曲线--de Boor递推算法实现 1. 定义   为保留Bezier方法的优点,B样条曲线的方程定义为 P(t)=∑i=0nPiNi,k(t)P(t)=\sum_{i=0}^n P_i N_{ ...

  2. 递推算法-五种典型的递推关系

    递推算法 递推法是一种重要的数学方法,在数学的各个领域中都有广泛的运用,也是计算机用于数值计算的一个重要算法.这种算法特点是:一个问题的求解需一系列的计算,在已知条件和所求问题之间总存在着某种相互联系 ...

  3. 微课|中学生可以这样学Python(8.3节):递推算法例题讲解

    适用教材: 董付国,应根球.<中学生可以这样学Python>.清华大学出版社,2017. 第8章  常用算法的Python实现 8.3  递推算法案例分析 京东购买链接:https://i ...

  4. 递推算法与递推套路(手撕算法篇)

    联系我们:有道技术团队助手:ydtech01 / 邮箱:[ydtech@rd.netease.com] 之前学习基础知识的时候也说了,递推和动态规划有这暧昧不清的关系,可以说,动态规划就是多了一个决策 ...

  5. 递推算法(以数字三角形为例)

    递推算法(以数字三角形为例) 数字三角形.如下所示为一个数字三角形.请编一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字总和最大.只要求输出总和. 1. 一步可沿左斜线向下或右斜线向下走: ...

  6. 递推算法与递推套路(算法基础篇)

    联系我们:有道技术团队助手:ydtech01 / 邮箱:[ydtech@rd.netease.com] 相信了解算法同学经常会说动态规划太难了,看到题目完全不知从何下手,或者是说"一看题解就 ...

  7. C语言经典递推算法之杨辉三角展开(详解)

    文章目录 一.递推算法 二.杨辉三角展开 一.递推算法 这是一种比较简单的算法,即通过已知条件,利用特定关系得到中间结论,然后得到最后结果的算法.递推算法可以分为顺推和逆推两种. 二.杨辉三角展开 1 ...

  8. c语言递推算法微课,最小二乘参数估计的递推算法及其C语言实现 精品.pdf

    2009年4月 焦作大学学报 №.2 第2期 JoURNALOFJIAOZUOUNIVERSITY Apr.2009 最小二乘参数估计的递推算法及其C语言实现 胡 沙 (河南理工大学电气工程与自动化学 ...

  9. java递推_Java算法-递推算法思想

    递推算法是常用的算法思想,在数学计算等方面有着广泛的应用.递推算法适合有着明显公式的规律场合. 一.递推算法基本思想 递推算法是一种理性思维模式的代表,其根据已有的数据和关系,逐步推导而得到结果.递推 ...

最新文章

  1. 在Ubuntu 14.04和CentOS上安装boost1.55二进制包
  2. 关于UIView的autoresizingMask属性的研究
  3. java缺_java – 缺少主类
  4. 最大限度地降低多线程 C# 代码的复杂性
  5. mysql 存储二进制数据_为什么在MySQL中存储二进制数据?
  6. 可视化流程设计器 Activiti Designer
  7. shell获取命令结果返回行数(行个数)
  8. Windows Live Writer 2012离线发布WP文章教程
  9. linux 审计工具auditd日志audit.log时间戳转换查看
  10. HTML文本样式标签
  11. 递归法 最大公倍数 斐波那契数列 数组插入排序改递归
  12. 5G应用前景广泛 不止是下电影更快,还能做这些事……
  13. csv转vcf格式网页工具-快速导入手机通讯录
  14. 8086CPU标志位
  15. re匹配中文格式的字符
  16. 2022款联想小新air15和联想小新pro14哪个好
  17. 在线html 生成链接,网址链接生成器
  18. 计算机怎样发现路由器上u盘,路由器上USB插口的4大功能,估计你连一个都没用过...
  19. CSDN【精品专栏】 第一期
  20. java面向对象三大特性理解

热门文章

  1. 第五人格亚服服务器不稳定,第五人格外服玩家“翻脸”?3个原因,让他们不太接受新屠夫...
  2. 本地服务器域名位置,怎么查看本地服务器域名服务器地址
  3. Java求8+88+888+8888········的前二十项和
  4. 网站在交换友情链接时7大注意事项
  5. AT91sam9260ek修改nandflash大小调试笔记
  6. 解决会声会影2018升级后的弹窗乱码的问题(15034:1:43)
  7. CSS+JS动态时钟(获取当前时间)
  8. virtualbox搭建一个局域网
  9. CTR预测经典模型GBDT+LR
  10. java比较两个list是否相同_Java判断两个List是否相同