一、为什么要使用贝塞尔曲线?

在参数方程中,参数不都是有明显几何意义的

参数方程可以表示空间中的曲线,也可以表示空间中的曲面。如半径长为r、圆心在(a,b)的平面圆,其参数方程为:

{x=a+rcos⁡θy=b+rsin⁡θ(1.1)\left\{ \begin{aligned} &x = a + r\cos\theta\\ &y = b + r\sin\theta \end{aligned} \right. \tag{1.1} {​x=a+rcosθy=b+rsinθ​(1.1)
其中:θ∈[0,2π)\theta\in[0,2\pi)θ∈[0,2π)。θ\thetaθ则为直观的角度,θ\thetaθ从0变化到2π2\pi2π,直线顺时针变化。

又如球面,球心在坐标原点,半径为R的球面。参数方程:
{x=Rsinϕcos⁡θy=Rsinϕsin⁡θz=Rcosϕ(1.2)\left\{ \begin{aligned} &x = Rsin\phi\cos\theta\\ &y = Rsin\phi\sin\theta\\ &z=Rcos\phi \end{aligned} \right. \tag{1.2} ⎩⎪⎨⎪⎧​​x=Rsinϕcosθy=Rsinϕsinθz=Rcosϕ​(1.2)
对于球面,如果我们改变θ\thetaθ,那么曲面上的点的变化方向是什么?如果同时修改θ\thetaθ和ϕ\phiϕ又是如何变化的?显然我们几乎不可能预测形状变化,因此我们说几何意义不明显。更重要的是,在工程、设计领域上不是所有人都关心方程式,人们更加关心如何去设计其产品、完成其生产任务。贝塞尔曲线就是这样一种方法,具有很多优点如:几何直观、灵活(控制点操纵)、统一(与形状无关)和平移、旋转不变等优点,还具有数值稳定性

二、定义

2.1 数值定义

给定n+1个空间上的点P0,P1,P2…,PnP_0,P_1,P_2\dots,P_nP0​,P1​,P2​…,Pn​,贝塞尔曲线的计算公式为:
C(u)=∑i=0nBn,i(u)Pi(1.3)C(u)=\sum^n_{i=0}B_{n,i}(u)P_i\tag{1.3}C(u)=i=0∑n​Bn,i​(u)Pi​(1.3)

其中参数为u的权重系数Bn,i(u)B_{n,i}(u)Bn,i​(u)计算方法如下:
Bn,i=n!i!(n−i)!ui(1−u)n−i(1.4)B_{n,i}=\frac{n!}{i!(n-i)!}u^i(1-u)^{n-i}\tag{1.4}Bn,i​=i!(n−i)!n!​ui(1−u)n−i(1.4)

由表达式(1.3)可以看出,最终生成的点C(u)与每个点P0,P1,P2…,PnP_0,P_1,P_2\dots,P_nP0​,P1​,P2​…,Pn​均有关系,这些点“控制”了曲线的最终走向,因此也称为控制点,贝塞尔阶数为n,由n+1个控制点控制。

给出以下性质:

  • u∈[0,1]u\in[0,1]u∈[0,1],当u=0时位于起点,u=1时终点;
  • 给定参数u基函数和为1。观察可知表达式是二项展开式(u+(1−u))n=1(u+(1-u))^n=1(u+(1−u))n=1,下图是四阶贝塞尔基函数随着u变化的图像;
  • 凸包性。曲线在凸包之内,可预测曲线行进方向;

2.2 德卡斯特里奥(DeCasteljau)算法

德卡斯特里奥(DeCasteljau)算法是一个数值稳定的方法,而(2.1)节提到的方法是一种数值不稳定的方法。对于一个已经存在的算法,若输入数据的误差在计算过程中迅速增长而得不到控制,则称该算法是不稳定的,否则是数值稳定的[1]。尤其是计算基函数时需要用到u的n次幂函数,计算机存储精度影响下,数值就变得更不稳定了。

算法的原理也比较直观,依次连接每个控制点,形成多个线段,每个线段在比例u:1-u处获取新控制点,在新的控制点基础上再进行划分,当控制点数仅剩一个时,该点就是系数u对应的C(u)。如果还不理解的话,可以去这个地方感受一下https://zh.javascript.info/bezier-curve。

三、python的实现

import matplotlib.pyplot as plt
import numpy as np
import mathclass Bezier:# 输入控制点,Points是一个array,num是控制点间的插补个数def __init__(self,Points,InterpolationNum):self.demension=Points.shape[1]   # 点的维度self.order=Points.shape[0]-1     # 贝塞尔阶数=控制点个数-1self.num=InterpolationNum        # 相邻控制点的插补个数self.pointsNum=Points.shape[0]   # 控制点的个数self.Points=Points# 获取Bezeir所有插补点def getBezierPoints(self,method):if method==0:return self.DigitalAlgo()if method==1:return self.DeCasteljauAlgo()# 数值解法def DigitalAlgo(self):PB=np.zeros((self.pointsNum,self.demension)) # 求和前各项pis =[]                                      # 插补点for u in np.arange(0,1+1/self.num,1/self.num):for i in range(0,self.pointsNum):PB[i]=(math.factorial(self.order)/(math.factorial(i)*math.factorial(self.order-i)))*(u**i)*(1-u)**(self.order-i)*self.Points[i]pi=sum(PB).tolist()                      #求和得到一个插补点pis.append(pi)            return np.array(pis)# 德卡斯特里奥解法def DeCasteljauAlgo(self):pis =[]                          # 插补点for u in np.arange(0,1+1/self.num,1/self.num):Att=self.Pointsfor i in np.arange(0,self.order):for j in np.arange(0,self.order-i):Att[j]=(1.0-u)*Att[j]+u*Att[j+1]pis.append(Att[0].tolist())return np.array(pis)class Line:def __init__(self,Points,InterpolationNum):self.demension=Points.shape[1]    # 点的维数self.segmentNum=InterpolationNum-1 # 段数self.num=InterpolationNum         # 单段插补(点)数self.pointsNum=Points.shape[0]   # 点的个数self.Points=Points                # 所有点信息def getLinePoints(self):# 每一段的插补点pis=np.array(self.Points[0])# i是当前段for i in range(0,self.pointsNum-1):sp=self.Points[i]ep=self.Points[i+1]dp=(ep-sp)/(self.segmentNum)# 当前段每个维度最小位移for i in range(1,self.num):pi=sp+i*dppis=np.vstack((pis,pi))         return pis# points=np.array([
#     [1,3,0],
#     [1.5,1,0],
#     [4,2,0],
#     [4,3,4],
#     [2,3,11],
#     [5,5,9]
#     ])
points=np.array([[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0],])if points.shape[1]==3:fig=plt.figure()ax = fig.gca(projection='3d')# 标记控制点for i in range(0,points.shape[0]):ax.scatter(points[i][0],points[i][1],points[i][2],marker='o',color='r')ax.text(points[i][0],points[i][1],points[i][2],i,size=12)# 直线连接控制点l=Line(points,1000)pl=l.getLinePoints()ax.plot3D(pl[:,0],pl[:,1],pl[:,2],color='k')# 贝塞尔曲线连接控制点bz=Bezier(points,1000)matpi=bz.getBezierPoints(0)ax.plot3D(matpi[:,0],matpi[:,1],matpi[:,2],color='r')plt.show()
if points.shape[1]==2:  # 标记控制点for i in range(0,points.shape[0]):plt.scatter(points[i][0],points[i][1],marker='o',color='r')plt.text(points[i][0],points[i][1],i,size=12)# 直线连接控制点l=Line(points,1000)pl=l.getLinePoints()plt.plot(pl[:,0],pl[:,1],color='k')# 贝塞尔曲线连接控制点bz=Bezier(points,1000)matpi=bz.getBezierPoints(1)plt.plot(matpi[:,0],matpi[:,1],color='r')plt.show()

下面是实现的效果:

[1] 曲线篇: 贝塞尔曲线

20201021:重写数值解求贝塞尔曲线的方法;
20201022:增加德卡斯特里奥(DeCasteljau)方法,该方法在求解贝塞尔曲线具有数值稳定性;
20201023:重新整理文字部分说明;
20201223:控制点控制着曲线的形状,连成的段数等于贝塞尔阶数。就好像给定n个点(控制点)其段数为n-1(阶数),NUBRS学习的对比有感。

(一)轨迹规划:贝塞尔曲线的python实现相关推荐

  1. 轨迹规划-贝塞尔曲线

    1. 简介 贝塞尔曲线于 1962 年,由法国工程师皮埃尔·贝济埃(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计,贝塞尔曲线最初由保尔·德·卡斯特里奥于1959年运用 ...

  2. 【CAD算法】【计算机图形学】Bezier贝塞尔曲线生成程序(python/numpy实现)[1]

    整个项目,从Bezier曲线的创建,到Coons Patch曲面的实现,再到网格的实现和优化,还有最后对表面的光顺,链接如下: [CAD算法][计算机图形学]Bezier贝塞尔曲线生成程序(pytho ...

  3. 轨迹规划——Bezier曲线与B样条曲线

    一.Bezier曲线 1.Bezier曲线的背景 给定n+1个数据点,p0~pn,生成一条曲线,使得该曲线与这些点描述的形状相符. (如果要求曲线通过所有数据点,则属于插值问题:如果只要求曲线逼近这些 ...

  4. 自动驾驶路径轨迹规划(三阶曲线spline)

    对于给定的一连串waypoints我们需要对其进行平滑线处理,这里介绍一种三阶spline的平滑方法: call function: clc clear all% x = [-4 -2 0 2 4 6 ...

  5. 前端动画之贝塞尔曲线推导及应用

    hello,大家好,今天豆皮范儿给大家带来了贝塞尔曲线推导和应用,优美的贝塞尔曲线想起了大学时候老师在给我们讲如何实现,如何推导,如何实现和应用.本来也来详细介绍一下,纯纯的干货- 作者:lff 生活 ...

  6. 《考虑车辆运动约束的最优避障轨迹规划算法》论文解读二

    目录 1 贝塞尔曲线 1.1 公式推导 1.2 Bernstein基函数的性质 1.3 贝塞尔曲线的性质 1.4 曲线的连续性 2 贝塞尔曲线规划器 2.1 局部轨迹 2.2 约束 1 贝塞尔曲线 这 ...

  7. 六轴机械臂-正解+逆解+轨迹规划实现

    之前,写了一篇博客,从坐标系的说明 -> D-H参数表的建立 -> 正解和逆解的整个算法推导过程整理了一篇博客https://blog.csdn.net/ymj7150697/articl ...

  8. 【路径规划】局部路径规划算法——贝塞尔曲线法(含python实现 | c++实现)

    文章目录 参考资料 1. 算法简介 2. 公式原理及python实现 2.1 一阶贝塞尔曲线 2.2 二阶贝塞尔曲线 2.3 三阶贝塞尔曲线 2.4 n阶贝塞尔曲线 2.5 贝塞尔曲线性质 3. c+ ...

  9. 自动驾驶算法详解(5): 贝塞尔曲线进行路径规划的python实现

    一.理论知识 1.路径规划定义 路径规划智能物流.无人驾驶等智能领域中重要的组成部分.路径规划的目标是实现从目的地到终点之间寻找一条安全(无碰撞).高效(最短距离或 最短时间)的一条最优或接近最优的路 ...

  10. 轨迹规划之 贝塞尔曲线

    轨迹规划之 贝塞尔曲线 前言 贝塞尔曲线 低次贝塞尔曲线的表达式 贝塞尔曲线的切线 高次贝塞尔曲线 高次贝塞尔曲线表达式 贝塞尔曲线的递归性 贝塞尔曲线的连接 贝塞尔曲线的速度 代码示例1:普通贝塞尔 ...

最新文章

  1. Can't connect to MySQL server on '127.0.0.1' (10061) (code 2003)解决方法
  2. R构建lasso回归模型并获得最佳正则化系数
  3. 什么是C#编程语言明明白白学C#
  4. ASP.NET MVC+EF框架+EasyUI实现权限管理(附源码)
  5. mysql set语句_不得不注意!那些容易被忽视的MySQL字符集问题?
  6. mozilla js 引擎_Mozilla的内容拦截器,新JavaScript引擎以及更多开源新闻
  7. 【英语学习】【WOTD】doldrums 释义/词源/示例
  8. java 协议这个概念_java网络协议概念是什么?
  9. AndroidStudio_安卓原生开发_Json解析报错_要注意这点---Android原生开发工作笔记141
  10. matlab smooth 函数,matlab中smooth函数平滑处理数据实例
  11. gitlab创建分支上传文件_环境搭建:gitLab平台的搭建和简单使用
  12. 单细胞文章解读——用单细胞RNA测序技术分析与肿瘤转移相关的细胞间通讯
  13. ES系列:解决Cluster state has not been recovered yet, cannot write to the [null] index问题
  14. 《三国演义》与“项目管理”——从诸葛亮舌战群儒看商务谈判
  15. Java上传图片功能
  16. oracle maxidletime,ORA-02396:超过最大空闲时间,请再次连接
  17. 字节码是什么?字节码增强有哪些?
  18. ufo帧率测试网站_移动全平台性能测试分析工具:PerfDog性能狗
  19. 【CCF】ISBN号码
  20. JSP——标准标签库 (JSTL)

热门文章

  1. 计算广告丨《互联网广告算法和系统实践》读书笔记
  2. 数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现
  3. 蓝桥杯练习题之圆的面积
  4. 中国移动宽带服务器上的光信号,中国移动光猫设置方法(常见故障及解决方法)...
  5. Word里仅修改字母和数字的字体,不改变标点符号字体
  6. HTML+CSS系列教程(第1—20课)
  7. window10 重装后“未安装任何音频输出设备”
  8. 程序员要实现财富自由,“出海”这条路该怎么走?
  9. 超全!Python 处理日期与时间的全面总结!
  10. 新巴塞尔资本协议(中英文)