文章目录
- 一、 低阶贝塞尔曲线
- 1.一阶贝塞尔曲线
- 2. 二阶贝塞尔曲线
- 3. 三阶贝塞尔曲线
一、 低阶贝塞尔曲线
1.一阶贝塞尔曲线
如下图所示,
P
0
P_0
P0,
P
1
P_1
P1 是平面中的两点,则
B
(
t
)
B ( t )
B(t) 代表平面中的一段线段。
考虑这样一条曲线方程
B
(
t
)
=
P
0
+
(
P
1
−
P
0
)
t
=
(
1
−
t
)
P
0
+
t
P
1
\begin{align} B(t)=P_0+(P_1−P_0)t=(1−t)P_0+tP_1 \end{align}
B(t)=P0+(P1−P0)t=(1−t)P0+tP1
一阶曲线很好理解, 就是根据
t
t
t来的线性插值,
t
t
t的取值范围为
[
0
,
1
]
[ 0 , 1 ]
[0,1]。
python实现
# 保存动图时用,pip install celluloid
from celluloid import Camera
import numpy as np
import matplotlib.pyplot as plt
P0=np.array([0,0])
P1=np.array([1,1])
fig=plt.figure(1)
camera = Camera(fig)
x =[]
y=[]
for t in np.arange(0,1,0.01):
plt.plot([P0[0],P1[0]],[P0[1],P1[1]],'r')
p1_t=(1-t)*P0+t*P1
x.append(p1_t[0])
y.append(p1_t[1])
# plt.plot(x,y,c='b')
plt.scatter(x,y,c='b')
# plt.pause(0.001)
camera.snap()
animation = camera.animate()
animation.save('一阶贝塞尔.gif')
matlab实现
from celluloid import Camera # 保存动图时用,pip install celluloid
import numpy as np
import matplotlib.pyplot as plt
P0=np.array([0,0])
P1=np.array([1,1])
fig=plt.figure(1)
camera = Camera(fig)
x =[]
y=[]
for t in np.arange(0,1,0.01):
plt.plot([P0[0],P1[0]],[P0[1],P1[1]],'r')
p1_t=(1-t)*P0+t*P1
x.append(p1_t[0])
y.append(p1_t[1])
# plt.plot(x,y,c='b')
plt.scatter(x,y,c='b')
# plt.pause(0.001)
camera.snap()
animation = camera.animate()
animation.save('一阶贝塞尔.gif')
2. 二阶贝塞尔曲线
对于二阶贝塞尔曲线,需要3个控制点,假设分别为
P
0
P_0
P0,
P
1
P_1
P1,
P
2
P_2
P2。
P
0
P_0
P0 和
P
1
P_1
P1 构成一阶
P
1
,
1
(
t
)
P_{1,1}(t)
P1,1(t),
P
1
P_1
P1和
P
2
P_2
P2也构成一阶
P
1
,
2
(
t
)
P_{1,2}(t)
P1,2(t),即:
{
P
1
,
1
(
t
)
=
(
1
−
t
)
P
0
+
t
P
1
P
1
,
2
(
t
)
=
(
1
−
t
)
P
1
+
t
P
2
\begin{equation} \left\{ \begin{array}{} P_{1,1}(t)=(1−t)P_0+tP_1 \\ P_{1,2}(t)=(1−t)P_1+tP_2 \\ \end{array} \right. \end{equation}
{P1,1(t)=(1−t)P0+tP1P1,2(t)=(1−t)P1+tP2
在生成的两个一阶点
P
1
,
1
(
t
)
P_{1,1}(t)
P1,1(t),
P
1
,
2
(
t
)
P_{1,2}(t)
P1,2(t)基础上,可以生成二阶贝塞尔点
P
2
(
t
)
P_2(t)
P2(t):
P
2
(
t
)
=
(
1
−
t
)
P
1
,
1
+
t
P
1
,
2
=
(
1
−
t
)
2
P
0
+
2
t
(
1
−
t
)
P
1
+
t
2
P
2
\begin{align} P_2(t)=(1−t)P_{1,1}+tP_{1,2}=(1−t)^2P_0+2t(1−t)P_1+t^2P_2 \end{align}
P2(t)=(1−t)P1,1+tP1,2=(1−t)2P0+2t(1−t)P1+t2P2
python实现
from celluloid import Camera # 保存动图时用,pip install celluloid
import numpy as np
import matplotlib.pyplot as plt
P0 = np.array([0, 0])
P1 = np.array([1,1])
P2 = np.array([2, 1])
fig = plt.figure(2)
camera = Camera(fig)
x_2 = []
y_2 = []
for t in np.arange(0, 1, 0.01):
plt.cla()
plt.plot([P0[0], P1[0]], [P0[1], P1[1]], 'k')
plt.plot([P1[0], P2[0]], [P1[1], P2[1]], 'k')
p11_t = (1-t)*P0+t*P1
p12_t = (1-t)*P1+t*P2
p2_t = (1-t)*p11_t+t*p12_t
x_2.append(p2_t[0])
y_2.append(p2_t[1])
plt.scatter(x_2, y_2, c='r')
plt.plot([p11_t[0],p12_t[0]],[p11_t[1],p12_t[1]],'g')
plt.title("t="+str(t))
plt.pause(0.001)
# camera.snap()
# animation = camera.animate()
# animation.save('2阶贝塞尔.gif')
matlab实现
clc;
clear;
close all;
%% 二次贝塞尔曲线
P0=[0,0];
P1=[1,1];
P2=[2,1];
P=[P0;
P1;
P2];
figure(2);
plot(P(:,1),P(:,2),'k');
MakeGif('二次贝塞尔曲线.gif',1);
hold on
scatter(P(:,1),P(:,2),200,'.b');
for t=0:0.01:1
P_t_1=(1-t) * P0 + t * P1;
P_t_2=(1-t) * P1 + t * P2;
P_t_3=(1-t) * P_t_1 + t * P_t_2;
m1=scatter(P_t_1(1),P_t_1(2),300,'g');
m2=scatter(P_t_2(1),P_t_2(2),300,'g');
m3=plot([P_t_1(1),P_t_2(1)],[P_t_1(2),P_t_2(2)],'g','linewidth',2);
scatter(P_t_3(1),P_t_3(2),300,'.r');
stringName = "二次贝塞尔曲线:t="+num2str(t);
title(stringName);
MakeGif('二次贝塞尔曲线.gif',t*100+1);
delete(m1);
delete(m2);
delete(m3);
end
3. 三阶贝塞尔曲线
三阶贝塞尔曲线有4个控制点,假设分别为
P
0
P_0
P0,
P
1
P_1
P1,
P
2
P_2
P2,
P
3
P_3
P3。
P
0
P_0
P0 和
P
1
P_1
P1,
P
1
P_1
P1 和
P
2
P_2
P2 ,
P
2
P_2
P2 和
P
3
P_3
P3 分别构成一阶
P
1
,
1
(
t
)
P_{1,1}(t)
P1,1(t),
P
1
,
2
(
t
)
P_{1,2}(t)
P1,2(t),
P
1
,
3
(
t
)
P_{1,3}(t)
P1,3(t),即:
{
P
1
,
1
(
t
)
=
(
1
−
t
)
P
0
+
t
P
1
P
1
,
2
(
t
)
=
(
1
−
t
)
P
1
+
t
P
2
P
1
,
3
(
t
)
=
(
1
−
t
)
P
2
+
t
P
3
\begin{equation} \left\{ \begin{array}{} P_{1,1}(t)=(1−t)P_0+tP_1 \\ P_{1,2}(t)=(1−t)P_1+tP_2 \\ P_{1,3}(t)=(1−t)P_2+tP_3 \\ \end{array} \right. \end{equation}
⎩
⎨
⎧P1,1(t)=(1−t)P0+tP1P1,2(t)=(1−t)P1+tP2P1,3(t)=(1−t)P2+tP3
在生成的三个一阶点
P
1
,
1
(
t
)
P_{1,1}(t)
P1,1(t),
P
1
,
2
(
t
)
P_{1,2}(t)
P1,2(t),
P
1
,
3
(
t
)
P_{1,3}(t)
P1,3(t)基础上,可以生成两个二阶贝塞尔点
P
2
,
1
(
t
)
P_{2,1}(t)
P2,1(t),
P
2
,
2
(
t
)
P_{2,2}(t)
P2,2(t):
{
P
2
,
1
(
t
)
=
(
1
−
t
)
P
1
,
1
+
t
P
1
,
2
P
2
,
2
(
t
)
=
(
1
−
t
)
P
1
,
2
+
t
P
1
,
3
\begin{equation} \left\{ \begin{array}{} P_{2,1}(t)=(1−t)P_{1,1}+tP_{1,2} \\ P_{2,2}(t)=(1−t)P_{1,2}+tP_{1,3}\\ \end{array} \right. \end{equation}
{P2,1(t)=(1−t)P1,1+tP1,2P2,2(t)=(1−t)P1,2+tP1,3
在生成的两个二阶点
P
2
,
1
(
t
)
P_{2,1}(t)
P2,1(t),
P
2
,
2
(
t
)
P_{2,2}(t)
P2,2(t)基础上,可以生成三阶贝塞尔点
P
3
(
t
)
P_3(t)
P3(t):
P
3
(
t
)
=
(
1
−
t
)
P
2
,
1
+
t
P
2
,
2
=
(
1
−
t
)
3
P
0
+
3
t
(
1
−
t
)
2
P
1
+
3
t
2
(
1
−
t
)
P
2
+
t
3
P
3
\begin{align} P_3(t)=(1−t)P_{2,1}+tP_{2,2}=(1−t)^3P_0+3t(1−t)^2P_1+3t^2(1-t)P_2+t^3P_3 \end{align}
P3(t)=(1−t)P2,1+tP2,2=(1−t)3P0+3t(1−t)2P1+3t2(1−t)P2+t3P3
python实现
from celluloid import Camera # 保存动图时用,pip install celluloid
import numpy as np
import matplotlib.pyplot as plt
P0 = np.array([0, 0])
P1 = np.array([1, 1])
P2 = np.array([2, 1])
P3 = np.array([3, 0])
fig = plt.figure(3)
camera = Camera(fig)
x_2 = []
y_2 = []
for t in np.arange(0, 1, 0.01):
plt.cla()
plt.plot([P0[0], P1[0]], [P0[1], P1[1]], 'k')
plt.plot([P1[0], P2[0]], [P1[1], P2[1]], 'k')
plt.plot([P2[0], P3[0]], [P2[1], P3[1]], 'k')
p11_t = (1-t)*P0+t*P1
p12_t = (1-t)*P1+t*P2
p13_t = (1-t)*P2+t*P3
p21_t = (1-t)*p11_t+t*p12_t
p22_t = (1-t)*p12_t+t*p13_t
p3_t = (1-t)*p21_t+t*p22_t
x_2.append(p3_t[0])
y_2.append(p3_t[1])
plt.scatter(x_2, y_2, c='r')
plt.plot([p11_t[0], p12_t[0]], [p11_t[1], p12_t[1]], 'b')
plt.plot([p12_t[0], p13_t[0]], [p12_t[1], p13_t[1]], 'b')
plt.plot([p21_t[0], p22_t[0]], [p21_t[1], p22_t[1]], 'r')
plt.title("t="+str(t))
plt.pause(0.001)
# camera.snap()
# animation = camera.animate()
# animation.save('3阶贝塞尔.gif')
matlab实现
clc;
clear;
close all;
P0=[0,0];
P1=[1,1];
P2=[2,1];
P3=[3,0];
P=[P0;
P1;
P2;
P3];
figure(3);
plot(P(:,1),P(:,2),'k');
MakeGif('三次贝塞尔曲线.gif',1);
hold on
scatter(P(:,1),P(:,2),200,'.b');
for t=0:0.01:1
P_t_1=(1-t) * P0 + t * P1;
P_t_2=(1-t) * P1 + t * P2;
P_t_3=(1-t) * P2 + t * P3;
ss
P_t_4=(1-t) * P_t_1 + t * P_t_2;
P_t_5=(1-t) * P_t_2 + t * P_t_3;
P_t_6=(1-t) * P_t_4 + t * P_t_5;
m1=scatter(P_t_1(1),P_t_1(2),300,'g');
m2=scatter(P_t_2(1),P_t_2(2),300,'g');
m3=scatter(P_t_3(1),P_t_3(2),300,'g');
m4=scatter(P_t_4(1),P_t_4(2),300,'m');
m5=scatter(P_t_5(1),P_t_5(2),300,'m');
m6=plot([P_t_1(1),P_t_2(1),P_t_3(1)],[P_t_1(2),P_t_2(2),P_t_3(2)],'g','linewidth',2);
m7=plot([P_t_4(1),P_t_5(1)],[P_t_4(2),P_t_5(2)],'m','linewidth',2);
scatter(P_t_6(1),P_t_6(2),300,'.r');
stringName = "三次贝塞尔曲线:t="+num2str(t);
title(stringName);
MakeGif('三次贝塞尔曲线.gif',t*100+1);
delete(m1);
delete(m2);
delete(m3);
delete(m4);
delete(m5);
delete(m6);
delete(m7);
end