简体   繁体   中英

Turtle graphics in Python 2.7: Drawing an arc

In Exercise 4.1(c) in Section 4.12 (Chapter 4) of Python for Software Design it is claimed that the following version of function arc() ,

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) + 1
    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
    lt(t, step_angle/2)
    polyline(t, n, step_length, step_angle)
    rt(t, step_angle/2)

is "better" than the original one from Section 4.7:

def arc(t, r, angle):
    arc_length = 2 * math.pi * r * angle / 360
    n = int(arc_length / 3) + 1
    step_length = arc_length / n
    step_angle = float(angle) / n
    polyline(t, n, step_length, step_angle)

(You can look up the code of subroutines, such as polyline() , here ).

I'm trying to understand why the former version is better, in particular, by which metric. How can we define the true circle we are approximating? Any ideas?

I could not explain it to myself also until I tried to sketch it. If you can imagine it, the turn of half a step angle helps to bisect the arc length approximately. By going in between, it is kind of a rough correction to both add and subtract the additional areas created.

Let's have a bake-off to compare. We'll use turtle.circle() as an arbitrary standard and then use the two arc() routines to draw 360 degree arcs (aka circles), one 3 pixels smaller radius, one 3 pixels larger radius than our standard:

import math
from turtle import Turtle, Screen

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 _ in range(n):
        t.fd(length)
        t.lt(angle)

def arc2(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) + 1
    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 arc1(t, r, angle):
    arc_length = 2 * math.pi * r * angle / 360
    n = int(arc_length / 3) + 1
    step_length = arc_length / n
    step_angle = float(angle) / n
    polyline(t, n, step_length, step_angle)

screen = Screen()
screen.setup(500, 500)
screen. setworldcoordinates(-250, -50, 250, 450)

thing0 = Turtle()
thing0.circle(200, steps=60)

thing1 = Turtle()
thing1.color("red")
thing1.penup()
thing1.goto(0, 3)
thing1.pendown()
arc1(thing1, 197, 360)

thing2 = Turtle()
thing2.color("green")
thing2.penup()
thing2.goto(0, -3)
thing2.pendown()
arc2(thing2, 203, 360)

screen.exitonclick()

Complete Circles

在此处输入图片说明

Detail #1

在此处输入图片说明

Detail #2

在此处输入图片说明

I would say that the Section 4.12 arc (green) looks better than the Section 4.7 arc (red) as the green arc has less jaggies and stays a consistent 3 pixels away from our standard circle whereas the red arc veers closer and further. What criteria do you consider important?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM