patternpythonMinor
Drawing an Archimedean spiral using Pillow
Viewed 0 times
archimedeanpillowdrawingusingspiral
Problem
From Rosetta Code:
The Archimedean spiral is a spiral named after the Greek mathematician Archimedes. It can be described by the equation:
$$r=a+b\theta$$
with real numbers \$a\$ and \$b\$.
Here is my attempt to draw it in Python (using Pillow):
The program outputs this image:
The Archimedean spiral is a spiral named after the Greek mathematician Archimedes. It can be described by the equation:
$$r=a+b\theta$$
with real numbers \$a\$ and \$b\$.
Here is my attempt to draw it in Python (using Pillow):
"""This module creates an Archimdean Spiral."""
from math import cos, sin, pi
from PIL import Image, ImageDraw
def translate(point, screen_size):
"""
Takes a point and converts it to the appropriate coordinate system.
Note that PIL uses upper left as 0, we want the center.
Args:
point (real, real): A point in space.
screen_size (int): Size of an N x N screen.
Returns:
(real, real): Translated point for Pillow coordinate system.
"""
return point[0] + screen_size / 2, point[1] + screen_size / 2
def draw_spiral(a, b, img, step=0.5, loops=5):
"""
Draw the Archimdean spiral defined by:
r = a + b*theta
Args:
a (real): First parameter
b (real): Second parameter
img (Image): Image to write spiral to.
step (real): How much theta should increment by. (default: 0.5)
loops (int): How many times theta should loop around. (default: 5)
"""
draw = ImageDraw.Draw(img)
theta = 0.0
r = a
prev_x = int(r*cos(theta))
prev_y = int(r*sin(theta))
while theta < 2 * loops * pi:
theta += step
r = a + b*theta
# Draw pixels, but remember to convert to Cartesian:
x = int(r*cos(theta))
y = int(r*sin(theta))
draw.line(translate((prev_x, prev_y), img.size[0]) +
translate((x, y), img.size[0]), fill=1)
prev_x = x
prev_y = y
if __name__ == '__main__':
IMAGE_SIZE = 300, 300
img = Image.new('1', IMAGE_SIZE)
draw_spiral(1, 2, img)
img.save('spiral.png')The program outputs this image:
Solution
With the default values, the spiral does not look very smooth: it's easy to see that it's been drawn using a series of straight-line segments. That's because the step in \$\theta\$ is quite large — 0.5 radians is more than 28°. Setting
But you can still see deviations from smoothness in various places. The problem here is that the step in \$\theta\$ is constant, but as \$r\$ gets bigger this becomes a bigger step in actual distance. What we would like is a (roughly) constant step in terms of distance along the curve, which we get by replacing
with
This makes
step=0.1 and loops=10 is an improvement:But you can still see deviations from smoothness in various places. The problem here is that the step in \$\theta\$ is constant, but as \$r\$ gets bigger this becomes a bigger step in actual distance. What we would like is a (roughly) constant step in terms of distance along the curve, which we get by replacing
theta += stepwith
theta += step / rThis makes
step into an approximate distance along the curve in pixels (rather than a change in angle, as in the original code). Now, with step=1 and loops=10, we get this spiral:Code Snippets
theta += steptheta += step / rContext
StackExchange Code Review Q#144073, answer score: 7
Revisions (0)
No revisions yet.