Python绘制bezier曲线

Python matplotlib绘制Bezier曲线

给定控制点的数量num和各控制点的坐标,动态绘制Bezier曲线。

思路:递归
1)当num=3时,已知三个控制点P0,P1,P2的坐标,连接P0P1,P1P2,给定一个0到1之间的数t,分别在P0P1和P1P2中寻找点T0和T1,使得满足:
P0T0 = tP0P1,P1T1 = tP1P2
然后在直线T0T1上寻找点Q0,使得 T0Q0 = t*T0T1,此时Q0即为Bezier曲线上一点。
Python绘制bezier曲线
2)当num=4时,连接四个控制点,给定一个0到1之间的数t,在三条线段上分别找T0,T1,T2三点,使得满足:
PiTi = t * PiPi+1,例如:P0T0 = t * P0P1
连接T0T1T2,此时可以转换成三个控制点T0,T1,T2的情况,利用1)过程得到Q0.
Python绘制bezier曲线
3)当num>4时,反复利用2)过程,直到控制点减少到3个时,利用1)过程得到Q0点。

4)过程1)到过程3)实际上只得到了Bezier曲线上的一个点,这时候只需要遍历在0到1范围内的所有实数t,就会得到无数个点Q,所有点连接即得Bezier曲线。

函数介绍:

def getValue(x1,x2,t):
    return x1+(x2-x1)*t

t是0到1之间的数,用于计算直线上某一位置的点的坐标,x1与x2分别是线段起点和终点的x/y坐标值,可得到实数为t时,所求得的点的坐标值。

def Input(x,y):
    pointNum = int(input("请输入控制点的个数:"))
    for i in range(pointNum):
        x.append(int(input("请输入第" + str(i + 1) + "个控制点的x值:")))
        y.append(int(input("请输入第" + str(i + 1) + "个控制点的y值:")))
    return

1)x,y为所有控制点的坐标值。比如x=[x0,x1,x2,…],为所有控制点的x值组成的数组(列表)。
2) x.append()向数组x从后插入一个数,这里为xi。

def PointTest():
    for i in range(len(x)):
        plt.text(x[i], y[i], 'P' + str(i))
    return

在图像上显示所有控制点的标号,即P0,P1…

def BezierPoint():
    for i in range(len(xLast)):
        plt.plot(xLast[i],yLast[i],'*')
    return

在图像上显示已得到的Bezier曲线上的点。其中xLast数组存放Bezier曲线上的点的x值。

def Draw(x,y,num):
    if num==3:
        x0 = getValue(x[0], x[1], i / cnt)
        y0 = getValue(y[0], y[1], i / cnt)
        x1 = getValue(x[1], x[2], i / cnt)
        y1 = getValue(y[1], y[2], i / cnt)
        plt.plot([x0, x1], [y0, y1])
        #绘制端点为(x0,y0)和(x1,y1)的线段
        xLast.append(getValue(x0, x1, i / cnt))
        yLast.append(getValue(y0, y1, i / cnt))
        plt.plot(xLast[i], yLast[i], '*')
        #在(xLast[i], yLast[i])处绘制一点
        plt.pause(0.2)#在此处暂停0.2秒
    else:
        xNext=[]
        yNext=[]
        #存放num=num-1时的控制点坐标值
        for j in range(num-1):
            xNext.append(getValue(x[j], x[j + 1], i / cnt))
            yNext.append(getValue(y[j], y[j + 1], i / cnt))
        plt.plot(xNext,yNext)
        #依次连接数组中的所有点
        plt.pause(0.2)
        Draw(xNext,yNext,num-1)#递归调用
    return

1)num为当前控制点的个数,该函数会递归调用Draw()函数,直到num=3。
2)将0到1平分成cnt份,此时 t = i / cnt(i是0到cnt之间的整数)。

def Show():
    plt.grid(True)
    plt.plot(x, y)
    PointTest()
    BezierPoint()
    return

显示函数。

以下为完整代码:

import matplotlib.pyplot as plt

def getValue(x1,x2,t):
    return x1+(x2-x1)*t

def Input(x,y):
    pointNum = int(input("请输入控制点的个数:"))
    for i in range(pointNum):
        x.append(int(input("请输入第" + str(i + 1) + "个控制点的x值:")))
        y.append(int(input("请输入第" + str(i + 1) + "个控制点的y值:")))
    return

def PointTest():
    for i in range(len(x)):
        plt.text(x[i], y[i], 'P' + str(i))
    return
def BezierPoint():
    for i in range(len(xLast)):
        plt.plot(xLast[i],yLast[i],'*')
    return
def Draw(x,y,num):
    if num==3:
        x0 = getValue(x[0], x[1], i / cnt)
        y0 = getValue(y[0], y[1], i / cnt)
        x1 = getValue(x[1], x[2], i / cnt)
        y1 = getValue(y[1], y[2], i / cnt)
        plt.plot([x0, x1], [y0, y1])
        xLast.append(getValue(x0, x1, i / cnt))
        yLast.append(getValue(y0, y1, i / cnt))
        plt.plot(xLast[i], yLast[i], '*')
        plt.pause(0.2)
    else:
        xNext=[]
        yNext=[]
        for j in range(num-1):
            xNext.append(getValue(x[j], x[j + 1], i / cnt))
            yNext.append(getValue(y[j], y[j + 1], i / cnt))
        plt.plot(xNext,yNext)
        plt.pause(0.2)
        Draw(xNext,yNext,num-1)
    return

def Show():
    plt.grid(True)
    plt.plot(x, y)
    PointTest()
    BezierPoint()
    return

#主函数
x=[]
y=[]
xLast=[]
yLast=[]
cnt = 10
Input(x,y)
fig = plt.figure()
ax = fig.add_subplot(111)
Show()
for i in range(cnt+1):
    Draw(x,y,len(x))
    plt.pause(1)
    plt.cla()
    Show()
plt.cla()
Show()
plt.plot(xLast,yLast)
plt.show()

结果展示:

请输入控制点的个数:3
请输入第1个控制点的x值:1
请输入第1个控制点的y值:1
请输入第2个控制点的x值:2
请输入第2个控制点的y值:5
请输入第3个控制点的x值:3
请输入第3个控制点的y值:1

Python绘制bezier曲线

请输入控制点的个数:4
请输入第1个控制点的x值:0
请输入第1个控制点的y值:0
请输入第2个控制点的x值:1
请输入第2个控制点的y值:5
请输入第3个控制点的x值:2
请输入第3个控制点的y值:7
请输入第4个控制点的x值:3
请输入第4个控制点的y值:4

Python绘制bezier曲线

上一篇:吞吐量(TPS)、QPS、并发数、响应时间(RT)概念


下一篇:大咖专访:Conflux公链研究总监“杨光”现场解决实际技术问题