Turtle Graphics "if touching colour" - python

I am trying to make a program in Turtle that draws a Christmas Tree and then some baubles, which I want to be placed randomly on the tree. However because a Christmas Tree is an irregular shape I am not able to place the baubles by randomly choosing x and y co-ordinates. Is there a way to randomly place the baubles on the tree?
I was considering an "turtle.pendown()" and then "if turtle.pen touching "green"" but I am not sure how to code this.
Any help would be greatly appreciated.

One simple, graphic, approach is to:
Find a Python module that has a routine for performing the "point
in polygon"
inclusion
test
Use turtle's begin_poly(), end_poly(), and get_poly() to capture the
vertices that your code generates when drawing the tree
Randomly generate ornaments within the bounding box of the tree but
also apply the crossing number test to see if their centers are on
the tree
Here's an example implementation using an (exceptionally) abstract tree and ornaments:
from turtle import Turtle, Screen
from random import randrange, choice
from point_in_polygon import cn_PnPoly
screen = Screen()
WINDOW_WIDTH, WINDOW_HEIGHT = screen.window_width(), screen.window_height()
COLORS = ["red", "yellow", "gold", "blue", "white", "pink"]
def draw_abstract_tree(turtle):
width = WINDOW_WIDTH//4
turtle.penup()
turtle.goto(0, -WINDOW_HEIGHT//4)
turtle.pendown()
for _ in range(8):
turtle.forward(width)
turtle.left(150)
turtle.forward(1.156 * width)
turtle.right(150)
width *= 0.9
turtle.left(210)
for _ in range(8):
turtle.forward(1.156 * width)
turtle.left(150)
turtle.forward(width)
turtle.right(150)
width /= 0.9
turtle.goto(0, -WINDOW_HEIGHT//4)
turtle.setheading(0)
def decorate_tree(turtle, polygon):
turtle.penup()
for _ in range(1000):
x = randrange(-WINDOW_WIDTH/4, WINDOW_WIDTH/4)
y = randrange(-WINDOW_HEIGHT/4, WINDOW_HEIGHT)
diameter = randrange(1, 12)
if cn_PnPoly((x, y), polygon):
turtle.goto(x, y)
turtle.color(choice(COLORS))
turtle.dot(diameter)
yertle = Turtle(visible=False)
yertle.speed("fastest")
yertle.color("darkgreen")
yertle.begin_poly()
draw_abstract_tree(yertle)
yertle.end_poly()
polygon = yertle.get_poly()
yertle.begin_fill()
draw_abstract_tree(yertle)
yertle.end_fill()
decorate_tree(yertle, polygon)
screen.exitonclick()
OUTPUT

I think turtle doesn't have method to check color.
But turtle uses Canvas from tkinter which have function find_overlaping(rectangle) to check if some objects overlaps this rectangle. Maybe it could works. Maybe you could check if there is tree in some small rectange in random place.
turtle.getcanvas()
tkinter: Canvas.find_overlapping()

Related

Turtle drawing a hexagon and hexagon grid

current code
#import the turtle modules
import turtle
#Start a work Screen
ws=turtle.Screen()
#Define a Turtle Instance
geekyTurtle=turtle.Turtle()
#executing loop 6 times for 6 sides
for i in range(6):
#Move forward by 90 units
geekyTurtle.forward(90)
#Turn left the turtle by 300 degrees
geekyTurtle.left(300)
My goal is to make a hexagon grid pattern and I am failing to do it properly. My first issue is if you run the code you get a hexagon but the top is flat, I can't get it to get the pointy corners to get on top. Second I tried to make the grid and it failed and I am not sure why I am unable to copy the same hexagon and clone it next to the other. I will or should have a file of the image that I am going for below.
The output I am getting:
The output I am trying to get:
Before going into loop, turn 30 degrees.
geekyTurtle.right(30)
In order to have its clone beside, just put the turtle to the new place and draw the shape again:
for i in range(6):
geekyTurtle.forward(90)
geekyTurtle.left(300)
geekyTurtle.up()
geekyTurtle.goto(90 * 3 ** .5, 0)
geekyTurtle.down()
for i in range(6):
geekyTurtle.forward(90)
geekyTurtle.left(300)
Put it in a loop to have it for more than two times
You can use the idea of .up() and .goto(x, y) and .down() to draw grids.
It seems like this is a problem that recursion could simplify in a fractal-like way. Each side of the initial hexagon is itself a hexagon, and so forth, filling the available space:
from turtle import Screen, Turtle
SIDE = 75 # pixels
def hexagon(side, depth):
if depth > 0:
for _ in range(6):
turtle.forward(side)
turtle.right(60)
hexagon(side, depth - 1)
turtle.left(120)
screen = Screen()
screen.tracer(False) # because I have no patience
turtle = Turtle()
turtle.penup()
turtle.width(2)
turtle.sety(-SIDE) # center hexagons on window
turtle.pendown()
turtle.left(30) # optional, orient hexagons
hexagon(SIDE, depth=6) # depth depends on coverage area
turtle.hideturtle()
screen.tracer(True)
screen.exitonclick()

Recursive rainbow-colored circles around each other

I'm trying to change the color and # of circles shown on the screen. So far, I've figured out how to make all of them different colors in a recursive pattern, but I need help finding out how to add more. Attached is what I have versus what I need to achieve.
my code
import turtle
import colorsys
def draw_circle(x,y,r,color):
turtle.seth(0)
turtle.up()
turtle.goto(x,y-r)
turtle.down()
turtle.fillcolor(color)
turtle.begin_fill()
turtle.circle(r)
turtle.end_fill()
def draw_recursive_circles(x,y,r,color,n):
if n == 0:
return
draw_circle(x,y,r,color)
colors = ['red','orange','yellow','green','blue','purple']
i = 0
for angle in range(30,360,60):
turtle.up()
turtle.goto(x,y)
turtle.seth(angle)
turtle.fd(r*2)
draw_recursive_circles(turtle.xcor(),turtle.ycor(),r/3,colors[i],n-1)
i += 1
turtle.tracer(0)
turtle.hideturtle()
turtle.speed(0)
draw_recursive_circles(0,0,100,'red',5)
turtle.update()
What I need to achieve
What I have so far
You import colorsys but never use it -- this is a clue that you're supposed to generate colors based on angles and not a fixed list of colors. The reason for the import is that turtle's RGB-based colors are the wrong model for our needs, so we want a more appropriate model, like HSV (where we only really care about H/hue), and have it convert those values to RGB.
The number of satellites is determined by your range call:
for angle in range(30,360,60):
Which for this drawing should be more like:
for angle in range(0, 360, 30):
As there are twelve satellites and 360 / 30 is 12. Finally, we need to do proper accounting such that whenever we change a position or heading, in order to do recursive drawing, we need to restore the original values on exit. Below is my simplified example solution to this problem:
from turtle import Screen, Turtle
from colorsys import hsv_to_rgb
def draw_circle(radius):
y = turtle.ycor() # save position & heading
heading = turtle.heading()
turtle.fillcolor(hsv_to_rgb(heading / 360, 1.0, 1.0))
turtle.sety(y - radius)
turtle.setheading(0)
turtle.begin_fill()
turtle.circle(radius)
turtle.end_fill()
turtle.sety(y) # restore position & heading
turtle.setheading(heading)
def draw_recursive_circles(radius, n):
if n == 0:
return
draw_circle(radius)
if n > 1:
heading = turtle.heading() # save heading
for angle in range(0, 360, 30):
turtle.setheading(angle)
turtle.forward(radius * 2)
draw_recursive_circles(radius / 5, n - 1)
turtle.backward(radius * 2)
turtle.setheading(heading) # restore heading
screen = Screen()
screen.tracer(False)
turtle = Turtle(visible=False)
turtle.penup()
draw_recursive_circles(150, 4)
screen.update()
screen.tracer(True)
screen.exitonclick()
I've intentionally kept the pen up to simplifiy my example so only filled portions of the circles are shown. Putting back the surrounding outlines I leave as an exercise for you.
The center circle is not the right color. Fixing this is a simple matter of setting the turtle's heading prior to the initial call to draw_recursive_circles()

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()

Python Turtle: Draw concentric circles using circle() method

I was showing a grandson patterns drawn with Python's Turtle module,
and he asked to see concentric circles.
I thought it would be faster to use the turtle's circle() to draw them
than to write my own code for generating a circle. Ha! I am stuck.
I see that the circle produced begins its circumference at the turtle's
current location and its direction of drawing depends on turtle's current
direction of motion, but I can't figure out what I need to do to get
concentric circles.
I am not at this point interested in an efficient way of producing
concentric circles: I want to see what I have to do to get
this way to work:
def turtle_pos(art,posxy,lift):
if lift:
art.penup()
art.setposition(posxy)
art.pendown()
def drawit(tshape,tcolor,pen_color,pen_thick,scolor,radius,mv):
window=turtle.Screen() #Request a screen
window.bgcolor(scolor) #Set its color
#...code that defines the turtle trl
for j in range(1,11):
turtle_pos(trl,[trl.xcor()+mv,trl.ycor()-mv],1)
trl.circle(j*radius)
drawit("turtle","purple","green",4,"black",20,30)
You can do it like this:
import turtle
turtle.penup()
for i in range(1, 500, 50):
turtle.right(90) # Face South
turtle.forward(i) # Move one radius
turtle.right(270) # Back to start heading
turtle.pendown() # Put the pen back down
turtle.circle(i) # Draw a circle
turtle.penup() # Pen up while we go home
turtle.home() # Head back to the start pos
Which creates the picture below:
Basically it moves the turtle down one radius lenght to keep the center point for all the circles in the same spot.
From the documentation:
The center is radius units left of the turtle.
So wherever the turtle is when you start to draw a circle, the center of that circle is some distance to the right. After each circle, just move left or right some number of pixels and draw another circle whose radius is adjusted for the distance the turtle moved. For example, if you draw a circle with a radius of 50 pixels, then move right 10 pixels, you would draw another circle with a radius of 40, and the two circles should be concentric.
I am not at this point interested in an efficient way of producing
concentric circles: I want to see what I have to do to get this way to
work
To address the OP's question, the change to their original code to make it work is trivial:
turtle_pos(trl, [trl.xcor() + mv, trl.ycor() - mv], 1)
trl.circle(j * radius)
becomes:
turtle_pos(trl, [trl.xcor(), trl.ycor() - mv], 1)
trl.circle(j * mv + radius)
The complete code with the above fix and some style changes:
import turtle
def turtle_pos(art, posxy, lift):
if lift:
art.penup()
art.setposition(posxy)
art.pendown()
def drawit(tshape, tcolor, pen_color, pen_thick, scolor, radius, mv):
window = turtle.Screen() # Request a screen
window.bgcolor(scolor) # Set its color
#...code that defines the turtle trl
trl = turtle.Turtle(tshape)
trl.pencolor(pen_color)
trl.fillcolor(tcolor) # not filling but makes body of turtle this color
trl.width(pen_thick)
for j in range(10):
turtle_pos(trl, (trl.xcor(), trl.ycor() - mv), True)
trl.circle(j * mv + radius)
window.mainloop()
drawit("turtle", "purple", "green", 4, "black", 20, 30)
So now i am giving you the exact code that can draw concentric circles.
import turtle
t=turtle.Turtle()
for i in range(5):
t.circle(i*10)
t.penup()
t.setposition(0,-(i*10))
t.pendown()
turtle.done()

How to create a color wheel using turtle graphics?

I am trying to create somewhat of a color wheel using the turtle module in Python. Let's say I have a list of colors:
colors = ["#880000","#884400","#888800","#008800","#008888","#000088",
"#440088","#880088"]
I am aiming to go around a circle with a radius of 250px plotting in the colors:
def drawColors():
for color in colors:
turtle.color(dark)
for i in range(len(colors)):
turtle.begin_fill
turtle.circle(150)
turtle.end_fill()
turtle.done()
You can do it by dividing the circle up into multiple circular sectors (aka pie slices) and drawing each one in a different color. The tricky part doing it with turtle graphics is setting the initial position and heading (or direction) of the turtle to be at the start of the arc of each one. Also, unlike with the case with a full circle, you need to manually close the figure before filling it by drawing the final line segment from the end of the arc back to the center of the circle.
While this could be calculated mathematically, doing that is avoided in the following code by remembering, for all but the first sector, where the previous one left off and using that as the starting position and heading for the next. Fortunately for the initial one, these values are relatively simple to compute: the position is set to the (circle_center x value + radius, circle_center y value) with a due North heading of 90°.
import turtle
colors = ['#880000','#884400','#888800','#008800',
'#008888','#000088','#440088','#880088']
def draw_color_wheel(colors, radius, center=(0, 0)):
slice_angle = 360 / len(colors)
heading, position = 90, (center[0] + radius, center[1])
for color in colors:
turtle.color(color, color)
turtle.penup()
turtle.goto(position)
turtle.setheading(heading)
turtle.pendown()
turtle.begin_fill()
turtle.circle(radius, extent=slice_angle)
heading, position = turtle.heading(), turtle.position()
turtle.penup()
turtle.goto(center)
turtle.end_fill()
draw_color_wheel(colors, 150, center=(25, 50))
turtle.hideturtle()
print('done - press any key to exit')
turtle.onkeypress(exit)
turtle.listen()
turtle.done()
Result
Since this question has become active again, let's solve it using stamping rather than drawing:
from turtle import Turtle, Screen
colors = ['#880000', '#884400', '#888800', '#008800',
'#008888', '#000088', '#440088', '#880088']
def draw_color_wheel(colors, radius, center=(0, 0)):
slice_angle = 360 / len(colors)
yertle = Turtle(visible=False)
yertle.penup()
yertle.begin_poly()
yertle.sety(radius)
yertle.circle(-radius, extent=slice_angle)
yertle.home()
yertle.end_poly()
screen.register_shape('slice', yertle.get_poly())
yertle.shape('slice')
yertle.setposition(center)
for color in colors:
yertle.color(color)
yertle.stamp()
yertle.left(slice_angle)
screen = Screen()
draw_color_wheel(colors, 250, center=(25, 50))
screen.exitonclick()
OUTPUT
This approach takes slightly less code and produces noticeably faster output.

Categories