从Think Python了解示例代码如何像计算机科学家一样思考4.3 ex 5

时间:2019-04-06 17:55:09

标签: python

我很难理解这本书的作者为什么使用某些代码行:

import math
import turtle

bob = turtle.Turtle()

def polyline(t, n, length, angle):
    """Draws n line segments.

    t: Turtle object
    n: number of line segments
    length: length of each segment
    angle: degrees between segments
    """
    for i in range(n):
        t.fd(length)
        t.lt(angle)


def polygon(t, n, length):
    """Draws a polygon with n sides.

    t: Turtle
    n: number of sides
    length: length of each side.
    """
    angle = 360.0/n
    polyline(t, n, length, angle)


def arc(t, r, angle):
    """Draws an arc with the given radius and angle.

    t: Turtle
    r: radius
    angle: angle subtended by the arc, in degrees
    """
    arc_length = 2 * math.pi * r * abs(angle) / 360
    n = int(arc_length / 4) + 3
    step_length = arc_length / n
    step_angle = float(angle) / n

    # making a slight left turn before starting reduces
    # the error caused by the linear approximation of the arc
    t.lt(step_angle/2)
    polyline(t, n, step_length, step_angle)
    t.rt(step_angle/2)


def circle(t, r):
    """Draws a circle with the given radius.

    t: Turtle
    r: radius
    """
    arc(t, r, 90)

circle(bob, 100)

我在评论中强调了我的困惑。说明是为了使一般功能能够在Python中使用乌龟绘制圆。我正在使用Python 3.7,但我并不认为这有所作为。为什么作者在第一条评论中使用n?他从哪里得到那个公式?另外,其余注释代码背后的逻辑是什么?我理解其余的练习,如果我知道他是怎么得到方程式的,我也会理解的。

1 个答案:

答案 0 :(得分:1)

让我们逐行接弧功能:

arc_length = 2 * math.pi * r * abs(angle) / 360

2 * math.pi * r是圆周长的公式。 abs(angle) / 360告诉您您的路径将占圆周长的比例。将它们相乘,就可以得出乌龟描述该弧线所需的距离(假设它可以沿着弯曲的路径移动,而这只是我们的近似值)。

n = int(arc_length / 4) + 3

这是当我们近似由该圆的圆周描述的路径时,我们希望乌龟采取的步骤数。不一定是这个特定的值。其他实现使用int(arc_length / 3) + 1和其他值。 step_lengthstep_angle都按比例缩放,因此增加它会使每个步骤更小,并使单个步骤更小旋转。忽略浮点数学问题和应计的舍入误差,行进的总距离和总的旋转将保持不变。

step_length = arc_length / n
step_angle = float(angle) / n

我们的折线将为我们迈出n步。在每一步中,我们要移动1/n的{​​{1}} th并旋转圆弧描述的总角度的arc_length th。如果我们在这两行之前的行中将1/n设为更大的值,则nstep_length将相应地缩小。

其余的:

step_angle

这里的半转弯对我们近似的弧度有很小的改善。想想我们在这里描述的路径,例如沿着单位圆的90度弧线,从(1,0)开始,以(3,3)结束于(0,1)。下表是单位圆本身的位置(理想x,理想y和理想航向,其中理想航向是该点处圆的切线),原始x,原始y和原始航向以及通过在开始路径前向左转t.lt(step_angle/2) polyline(t, n, step_length, step_angle) # take a lot of little steps t.rt(step_angle/2) ,然后向后弯曲step_angle/2,将其取消,可以得到x,y和航向:

step_angle/2

请注意,调整后的值比原始值更接近理想值。在考虑折线的工作原理时,这具有直观的意义:折线朝着其面对的任何方向向前移动,然后左转。从未调整的航向开始时,您甚至在尝试转弯之前将 |ideal x|ideal y|ideal heading|raw x|raw y|raw heading|adj x|adj y|adj heading| ------------------------------------------------------------------------------------ Start|1 |0 |90 |1 |0 |90 |1 |0 |105 | Step1|0.86 |0.5 |120 |1 |0.52 |120 |0.86 |0.51 |135 | Step2|0.5 |0.86 |150 |0.74 |0.98 |150 |0.49 |0.88 |165 | Step3|0 |1 |180 |0.28 |1.24 |180 |-0.01|1.01 |195 | End |0 |1 |180 |0.28 |1.24 |180 |-0.01|1.01 |180 | 移至圆弧上方。您将始终位于圆弧的上方和右侧。首先向左转半个step_angle,您将在圆弧下花费每个step_length,并在圆弧上花费每个step_length。与严格位于弧外的弧相比,这将产生更好的弧近似值。

编辑

关于更新的circle方法的问题,它需要两个参数(turtle和圆的半径),然后相应地调用arc,现在您的实现是:

step_length

def circle(t, r): arc(t, r, 90) 的第三个参数是您要传播的弧的角度。要制作一个圆圈,您需要360度,而不是90度。