To measure the rotation speed of a rod, I need to make a dial with a large number of alternating dark / transparent segments arranged in a circle. The rotating dial will interrupt the light on a photosensor, and then I only need to measure the frequency of light pulses. Python turtle graphics seems like a good idea for drawing this dial.
I need to draw this image very large, so as to avoid the stair-step effect on the edges of the segments - I need smooth edges. But if I do turtle.setup(x, y) with either x or y bigger than the screen, the canvas is truncated to fit the screen. How to avoid that?
My code is included at the end. See here a screenshot with the truncated canvas for x = y = 1420
EDIT: Just to make it clear - getscreen() / getcanvas() at the end capture this truncated canvas image and save it as-is (truncated) into an EPS file. That's what bothers me. I need the whole circle captured in a high-resolution image file.
I am using python-2.7.4 on Ubuntu 13.04
This is the code:
#!/usr/bin/python
# set this to 1 to troubleshoot
debug = 0
import turtle
import math
# image file with the result
fname="dial.eps"
# number of lines
n = 100
# external radius
r2 = 700
# length of each line
l = round(r2 / 10)
r1 = r2 - l
# pen thickness
# tuned for 50% fill factor at the inner end of each line
# (dark stripe and transparent stripe have equal width there)
thick = 2 * math.pi * r1 / float(2 * n)
print "thickness =", thick
# setup screen size to contain the whole circle, plus a little extra
border = 20 + thick
turtle.setup(2 * r2 + border, 2 * r2 + border)
dot = turtle.Turtle()
dot.speed(0)
dot.hideturtle()
# draw crosshairs in the center
dot.setpos(l, 0)
dot.setpos(-l, 0)
dot.home()
dot.setpos(0, l)
dot.setpos(0, -l)
dot.penup()
# thickness of lines
dot.pensize(thick)
for step in range(0, n):
a = 360.0 * step / float(n)
arad = math.radians(a)
x1 = r1 * math.cos(arad)
y1 = r1 * math.sin(arad)
x2 = r2 * math.cos(arad)
y2 = r2 * math.sin(arad)
if debug == 1:
print "a =", a, "\t x1 =", x1, "\t y1 =", y1, "\t x2 =", x2, "\t y2 =", y2
dot.penup()
dot.setpos(x1, y1)
dot.pendown()
dot.setpos(x2, y2)
ts = turtle.getscreen()
ts.getcanvas().postscript(file=fname)
print "Saved image to: ", fname
print "All done. Click image to exit."
turtle.exitonclick()
getcanvas().postscript
is resolution-independent; you can print it at any size and it will still come out at your printer's native resolution.I modified your code to read the screen size and change the circle radius accordingly:
#!/usr/bin/python
# set this to 1 to troubleshoot
debug = 0
import turtle
import math
ts = turtle.getscreen()
max_size = 0
if ts.window_width > ts.window_height:
max_size = ts.window_height()
else:
max_size = ts.window_width()
# image file with the result
fname = 'dial.eps'
# number of lines
n = 100
# external radius
# r2 = 700
r2 = 0.8 * max_size / 2
# length of each line - changed from 'l', which looks too much like 1
line_length = round(r2 / 10)
r1 = r2 - line_length
# pen thickness
# tuned for 50% fill factor at the inner end of each line
# (dark stripe and transparent stripe have equal width there)
thick = 2 * math.pi * r1 / float(2 * n)
print 'thickness =', thick
# setup screen size to contain the whole circle, plus a little extra
border = 20 + thick
# turtle.setup(2 * r2 + border, 2 * r2 + border)
dot = turtle.Turtle()
dot.speed(0)
dot.hideturtle()
# draw crosshairs in the center
dot.setpos(line_length, 0)
dot.setpos(-line_length, 0)
dot.home()
dot.setpos(0, line_length)
dot.setpos(0, -line_length)
dot.penup()
# thickness of lines
dot.pensize(thick)
for step in range(0, n):
a = 360.0 * step / float(n)
arad = math.radians(a)
x1 = r1 * math.cos(arad)
y1 = r1 * math.sin(arad)
x2 = r2 * math.cos(arad)
y2 = r2 * math.sin(arad)
if debug == 1:
print 'a =', a, '\t x1 =', x1, '\t y1 =', y1, '\t x2 =', x2, \
'\t y2 =', y2
dot.penup()
dot.setpos(x1, y1)
dot.pendown()
dot.setpos(x2, y2)
ts.getcanvas().postscript(file=fname)
print 'Saved image to: ', fname
print 'All done. Click image to exit.'
turtle.exitonclick()
Zoomed in at 500%, there are no jaggies:
Oh, and please never use l
as a variable name; it looks too much like 1
. Bad programmer, no biscuit … ☺