第4章 案例研究:接口设计
练习 4-5 用函数画阿基米德螺旋
在百度百科阅读关于螺旋线(spiral)的信息,接着编写一段程序来画出阿基米德螺旋(或者其他某种螺旋线)。
【求解】
Step.1 确认组件
由于《Think Python》到本章为止并没有介绍笛卡尔坐标用法,所以本人不会使用笛卡尔坐标来绘制阿基米德螺旋,本解法基于已经出现过的 polyline
函数实现(绝不超纲)。
#多边线
def polyline(t, n, length, angle):
for i in range(n):
t.fd(length)
t.lt(angle)
Step.2 抽象问题
这里提一下 导数 概念:
当函数
y
=
f
(
x
)
y=f(x)
y=f(x) 的自变量
x
x
x 在一点
x
0
x_0
x0上产生一个增量
Δ
x
Δx
Δx 时,函数输出值的增量
Δ
y
Δy
Δy 与自变量增量
Δ
x
Δx
Δx 的比值在
Δ
x
Δx
Δx 趋于
0
0
0 时的极限
a
a
a 如果存在,
a
a
a 即为在
x
0
x_0
x0 处的导数,记作
f
′
(
x
0
)
f'(x_0)
f′(x0) 或
d
f
(
x
)
d
x
∣
x
=
x
0
\frac{df(x)}{dx}|_{x=x_0}
dxdf(x)∣x=x0。
函数 polyline(t, n, length, angle)
在模拟曲线时,实际上就是画的一小段一小段很短的切线,将精度调整到肉眼看不大出来的时候,画出来就是“曲线”了(实际上,如你所见《Think Python》练习 4-2:用函数画花朵 中的花朵也坑坑洼洼的)。
而我们现在要做的就是:确认一个微小变量(乌龟每次转过的微小角度),根据阿基米德螺旋公式,计算出在这个微小变量下的短小线段的 长度( l l l )。
Step.3 问题求解
已知阿基米德螺公式:
r
=
a
+
b
θ
r=a+bθ
r=a+bθ
希望乌龟从画布的中间开始画,这样好看点,故去掉起点至画布中心的距离,将阿基米德螺线公式简化为:
r
=
a
θ
r=aθ
r=aθ
由阿基米德曲线公式
r
=
a
θ
r=aθ
r=aθ 可知,当角度增加
Δ
θ
Δθ
Δθ,半径从
a
θ
aθ
aθ 变为
a
(
θ
+
Δ
θ
)
a(θ+Δθ)
a(θ+Δθ),即:
r
1
=
a
θ
r_1=aθ
r1=aθ
r
2
=
a
(
θ
+
Δ
θ
)
r_2=a(θ+Δθ)
r2=a(θ+Δθ)
已知:三角形两边
r
1
r_1
r1、
r
2
r_2
r2 及夹角
Δ
θ
Δθ
Δθ
求:三角形对边
l
l
l
解:
求高:
h
=
s
i
n
Δ
θ
⋅
r
′
=
s
i
n
Δ
θ
⋅
a
(
θ
+
Δ
θ
)
h=sinΔθ·r'=sinΔθ·a(θ+Δθ)
h=sinΔθ⋅r′=sinΔθ⋅a(θ+Δθ)
求顶点到高的距离与
r
1
r_1
r1 的差:
m
=
c
o
s
Δ
θ
⋅
r
′
−
r
=
c
o
s
Δ
θ
⋅
a
(
θ
+
Δ
θ
)
−
a
θ
m =cosΔθ·r'-r=cosΔθ·a(θ+Δθ)-aθ
m=cosΔθ⋅r′−r=cosΔθ⋅a(θ+Δθ)−aθ
勾股定理求对边
l
l
l:
l
=
m
2
+
h
2
l=\sqrt{m^2+h^2}
l=m2+h2
Step.4 完成代码
"""
《Think Python》练习 4-5:用函数画阿基米德螺旋(蚊香线)
r = aθ
由于用乌龟画,从中间开始旋转比较好看,故没有考虑起点与坐标原点的距离
绘图精度(乌龟每次转过的微小角度):Δθ = π/30 = 6°
绘制的阿基米德螺旋线圈数 (不可能让乌龟无限的画下去):n
theta:阿基米德螺旋角度 θ,从0开始
m:短线条数,根据精度 Δθ 与圈数 n 计算
length:短线长度
angle:短线间的夹角,即精度 Δθ = π/30 = 6°
"""
#引入数学模块、乌龟模块
import math
import turtle
#调用乌龟画图、提高画弧速度
bob = turtle.Turtle()
bob.delya = 0.01
#阿基米德螺旋
def spiral(t, a, n):
theta = 0
m = int(n * 60)
for i in range(m):
length = math.sqrt( ( math.cos(math.pi/30) * a * ( theta + math.pi/30 ) - a * theta )**2 + ( math.sin(math.pi/30) * a * ( theta + math.pi/30 ) )**2 )
angle = 6
t.fd(length)
t.lt(angle)
theta = theta + math.pi / 30
spiral(bob, 10, 3.25)
turtle.mainloop()
附草稿: