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.