Python Turtle unit of measurement - python

When we instantiate a turtle object, we can draw a circle. I wonder about the radius parameter of the circle() method.
import turtle
myTurtle = turtle.Turtle()
myTurtle.circle(50)
What is the unit of measurement of this parameter?
Does the radius equal to 50 pixels or 50 inches?

the documentation for turtle.setup indicates that size parameters, if expressed as integers, are pixels, if expressed as floats, are fractions of the screen.

As you can see from the first few lines from the documentation, the forward method uses the unit pixel and since there is no other unit used in the documentation, you can conclude the all methods use pixel.
Edit: After looking at the source code form turtle, I'm on 100% sure that it is using pixel as unit, since it is adding the distance to the position directly.

It depends on whether we're measuring the image on the screen, or a printed PostScript image obtained through the underlying tkinter canvas.
My Dell display has a pixel pitch of 0.282mm so I expect to see 90 dots per inch. If turtle draws a circle with a radius of 45 pixels, what I measure on my screen is a circle with a 1" diameter.
However, if I print that image, and turn off any printing scaling, I won't get a 1" printed circle, but something larger. To achieve a properly printed circle, turtle needs to draw with a radius of 36, as the underlying measure for PostScript conversion seems to be based on points (# 72 per inch):
from turtle import Turtle, Screen
screen = Screen()
screen.setup(400, 600)
tortoise = Turtle()
tortoise.circle(36)
canvas = screen.getcanvas()
canvas.postscript(file="circle.ps")
screen.exitonclick()
Although this circle measures around 3/4" on my screen, the PostScript output on the printer is 1". (Make sure to turn off any automatic scaling features and print # 100%)
The actual size of the image on your monitor depends on its pixel pitch. Although tkinter can work in fixed size points for both display and print, Python turtle only works in variable size pixels for display. Once your determine your monitor's pixel pitch, you can use your own scaling factor, or:
turtle.setworldcoordinates(llx, lly, urx, ury)
to configure your own scaling:
from turtle import Turtle, Screen
PIXEL_PITCH = 0.282 # mm
MM_PER_INCH = 25.4
DOTS_PER_INCH = int(1 / (PIXEL_PITCH / MM_PER_INCH))
screen = Screen()
screen.setup(4 * DOTS_PER_INCH, 5 * DOTS_PER_INCH)
screen.setworldcoordinates(-2, -2.5, 2, 2.5) # convert to inches
tortoise = Turtle()
tortoise.circle(0.5) # 1/2" radius, one inch diameter on my screen
screen.exitonclick()
Which should be reasonably accurate on the screen but not print correctly without extra work to switch units during PostScript conversion or use the correct scaling factor in your print dialog.

Usage of the circle() function:
circle(radius, extent=None, steps=None)
See more here: https://docs.python.org/2/library/turtle.html#turtle.circle
So yes, it is the radius as pixels, the first parameter of the function.

Related

Pygame Rotation size issues

I am trying to rotate an image so it is facing the mouse at all times and I am noticing that the image size is changing. I am trying to troubleshoot but am having no luck. I would love some advice.
Here is what I am using:
ang = 360 - math.atan2(mousey - 540, mousex - 960) * 180 / math.pi
rotcircle = pygame.transform.scale(pygame.transform.rotate(redcircle,ang), [100, 100])
rect = rotcircle.get_rect(center=(960,540))
screen.blit(rotcircle,rect)
Just think about it. If you rotated an image 45 degrees, for example, the surface would naturally have to be larger in order to accommodate the corners, which would otherwise stick out of the original surface's bounds. So, if you rotate the image, it's going to be larger, just as the documentation says:
Unless rotating by 90 degree increments, the image will be padded larger to hold the new size. If the image has pixel alphas, the padded area will be transparent. Otherwise pygame will pick a color that matches the Surface colorkey or the topleft pixel value.
You're explicitly forcing the surface to be 100x100, meaning that the closer the image gets to being rotated by 45 degrees (again, for example), the smaller it'll appear. The easy solution is to stop resizing the image, or use another surface that's large enough to hold the rotated image and then blit the rotated image onto it.

Turtle. Set the initial app window position

I am trying to set the starting window for my first turtle script, but after some searching it seems that there is no clean way to do it.
after some searching it seems that there is no clean way to do it
What do you mean by clean? You can set the initial size and starting position of the turtle window using the setup() method:
>>> import turtle
>>> help(turtle.setup)
Help on function setup in module turtle:
setup(width=0.5, height=0.75, startx=None, starty=None)
Set the size and position of the main window.
Arguments:
width: as integer a size in pixels, as float a fraction of the
Default is 50% of
height: as integer the height in pixels, as float a fraction of the
Default is 75% of
startx: if positive, starting position in pixels from the left
edge of the screen, if negative from the right edge
Default, startx=None is to center window horizontally.
starty: if positive, starting position in pixels from the top
edge of the screen, if negative from the bottom edge
Default, starty=None is to center window vertically.
For example:
from turtle import Screen, Turtle
screen = Screen()
screen.setup(300, 300, startx=100, starty=200)
turtle = Turtle()
turtle.dot(100)
screen.mainloop()

How to put the figure inside a circle using turtle?

I got a simple figure using turtle. But the problem is I dunno how to put that figure inside circle.
Code:
import turtle
painter = turtle.Turtle()
painter.pencolor("blue")
for i in range(50):
painter.forward(100)
painter.left(123*2)
painter.circle(70)
turtle.done()
A bit of trigonometry in my head and I figured the angle. Not sure if I got the radius correct though. Ideally figure out the coordinates of the center instead, but a quick and dirty solution is:
import turtle
painter = turtle.Turtle()
painter.pencolor("blue")
for i in range(50):
painter.forward(100)
painter.left(123*2)
painter.right(123)
painter.right(90)
painter.penup()
painter.forward(10)
painter.left(90)
painter.pendown()
painter.circle(70)
turtle.done()
You will need to move the turtle to the correct starting position. NOTE that's not the circle's center! It starts drawing the circle from its rightmost position - i.e., if you want a circle with radius 70 around (0,0), then move to (70,0), e.g.:
painter.penup()
painter.goto(70,0)
painter.pendown()
painter.circle(70)
FYI: I can't immediately figure out where the center of your drawing is, but I suspect it is NOT at (0,0). In all cases, you should place the turtle to the right of your shape's center, offset by the circle's radius, to make the circle go around it.
Another approach would be to average the positions of your arbitrary image and then use that average as the center of the surrounding circle:
from turtle import Screen, Turtle, Vec2D
CIRCLE_RADIUS = 70
POLYGON_LENGTH = 100
POINTS = 50
screen = Screen()
painter = Turtle()
painter.speed('fastest')
painter.pencolor("blue")
total = Vec2D(0, 0)
for _ in range(POINTS):
painter.forward(POLYGON_LENGTH)
total += painter.position()
painter.left(246)
x, y = total * (1.0 / POINTS) # Vec2D can multiply by scalar but not divide
painter.penup()
painter.goto(x, y - CIRCLE_RADIUS)
painter.setheading(0)
painter.pendown()
painter.circle(CIRCLE_RADIUS)
screen.exitonclick()

Is it possible to change turtle's pen stroke?

I need to draw a bar graph using Python's turtle graphics and I figured it would be easier to simply make the pen a thick square so I could draw the bars like that and not have to worry about making dozens of rectangles and filling them in.
When I set the turtle shape using turtle.shape('square') though, it only changes the appearance of the pen but has no effect on the actual drawing:
Is there a way to make turtle actually draw a rectangular stroke, whether that be through built-in methods or through modifying the turtle file?
I DON'T want rounded edges, like this:
To answer the question asked in the title: No, it is not possible to change the pen stroke directly (see cdlane's answer for a possible way to do it by modifying the hardcoded values from tkinter).
I did find a workaround for the use case presented in the question body, however.
A custom pen shape (in this case, representing the exact shape and size of the bar) can be registered like this:
screen.register_shape("bar", ((width / 2, 0), (-width / 2, 0), (-width / 2, height), (width / 2, height)))`
We can then simply loop through each bar, update the pen shape with the new values, and use turtle.stamp to stamp the completed bars onto the graph, no drawing required.
It looks like changing the shape of the pen stroke itself isn't possible. turtle.shape('square') only changes the shape of the turtle, not the pen stroke. I suggest lowering the pen size, and creating a function to draw a rectangle. You could use this do draw the bars.
I've two solutions to this problem that I've used in various programs.
The first is a variation on your stamp solution. Rather than use screen.register_shape() to register a custom polygon for each line, use a square turtle and for each line turtle.turtlesize() it into the rectangle you want to stamp:
from turtle import Turtle, Screen
STAMP_SIZE = 20 # size of the square turtle shape
WIDTH, LENGTH = 25, 125
yertle = Turtle(shape="square")
yertle.penup()
yertle.turtlesize(WIDTH / STAMP_SIZE, LENGTH / STAMP_SIZE)
yertle.goto(100 + LENGTH//2, 100) # stamps are centered, so adjust X
yertle.stamp()
screen = Screen()
screen.exitonclick()
My other solution, when I need to draw instead of stamp, is to reach into turtle's tkinter underpinning and modify turtle's hardcoded line end shape itself:
from turtle import Turtle, Screen
import tkinter as _
_.ROUND = _.BUTT
WIDTH, LENGTH = 25, 125
yertle = Turtle()
yertle.width(WIDTH)
yertle.penup()
yertle.goto(100, 100)
yertle.pendown()
yertle.forward(LENGTH)
screen = Screen()
screen.exitonclick()
Use multiple stamps like so:
import turtle
turtle.shape("square")
for count in range(x):
turtle.stamp()
turtle.forward(1)

Negative coordinates in pygame

What would be the best way to use negative coordinates in pygame?
At the moment I have a surface that is 1.5 times the original surface then everything that needs to be drawn is shifted up by a certain amount (to ensure the negative coordinates become positive) and drawn.
Is there an easier/alternate way of doing this?
A simple solution is to write a linear mapping function from world coordinates to pygame screen coordinates
def coord(x,y):
"Convert world coordinates to pixel coordinates."
return 320+170*x, 400-170*y
and use it when drawing all world objects. Have a look here for a complete example.
There is no way to move the origin of a surface from 0,0.
Implement your own drawing class which transforms all the coordinates passed in into the space of the surface.
If it's similar to an RPG map situation, where you have world coordinates and screen coordinates:
use a function that translates world to local, and vice versa.
But I wasn't sure I'd you were looking for Rect's properties?
rect.bottomright = (width, height) # bottom right at window corner
If you want to use center coordinates to blit, vs top left being (0,0)
ship.rect.center = (20, 30) # don't need to translate by adding w/2 to topleft
See also: Rect.move_ip()

Categories