How can I fill each petal separately using begin_fill()? - python

I have the following code that generates a petal pattern for a flower I'm trying to build. However, the problem is the fill part.
What should happen is each petal to be filled individually:
Instead, what happens is this:
import turtle
import math
wn = turtle.Screen()
wn.bgcolor("white")
def draw_leaf(turtle, side, theta = 0):
angle = 2
turtle.color("#67bd3c")
for x in range(-180,180):
y = math.sin(math.radians(angle))
angle += 1
y = y * side
x_axis = (x % 180) * math.cos(math.radians(theta)) + y * math.sin(math.radians(theta))
y_axis = (x % 180) * (-1 * (math.sin(math.radians(theta)))) + y * math.cos(math.radians(theta))
turtle.goto(-1 * x_axis, -1 * y_axis)
return
def draw_flower(turtle, petals):
for x in range(petals):
theta = 180/(petals - 1)
turtle.pendown()
turtle.begin_fill()
draw_leaf(turtle, 35, theta * x)
turtle.end_fill()
turtle.penup()
turtle.left(theta)
return
draw_flower(turtle,4)
wn.exitonclick()

It looks like each draw_leaf call begins when the turtle is at the far end of the leaf that it just previously drew. So the polygon that is filled during the current draw_leaf includes that end point. This is more apparent if you draw each leaf with a different color.
One possible solution is to goto the center of the flower after your penup, before you draw the next leaf.
def draw_flower(turtle, petals):
start = turtle.pos()
for x in range(petals):
theta = 180/(petals - 1)
turtle.pendown()
turtle.begin_fill()
draw_leaf(turtle, 35, theta * x)
turtle.end_fill()
turtle.penup()
turtle.goto(*start)
turtle.left(theta)
return

Related

Perlin Noise in Ursina

Is there a way to incorporate Perlin Noise into the Ursina game engine in Python to give it a Minecraft feeling? I think I may be onto something, but for some reason, the y value is not varying. Do you mind helping me out?
The code that I have so far:
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
from perlin_noise import PerlinNoise;
app = Ursina()
noise = PerlinNoise(octaves=10, seed=1)
# Define a Voxel class.
# By setting the parent to scene and the model to 'cube' it becomes a 3d button.
class Voxel(Button):
def __init__(self, position=(0,0,0)):
super().__init__(
parent = scene,
position = position,
model = 'cube',
origin_y = .5,
texture = 'white_cube',
color = color.color(0, 0, random.uniform(.9, 1.0)),
highlight_color = color.lime,
)
def input(self, key):
if self.hovered:
if key == 'left mouse down':
voxel = Voxel(position=self.position + mouse.normal)
if key == 'right mouse down':
destroy(self)
for z in range(8):
for x in range(8):
y = .25 + noise([x, z])
voxel = Voxel(position=(x, y,z))
player = FirstPersonController()
app.run()
As shown in the usage examples, you'll have to scale the noise value with an additional division:
for z in range(8):
for x in range(8):
y = .25 + noise([x/8, z/8])
voxel = Voxel(position=(x, y,z))
You'll probably want to replace that magic number with a constant.
You can use this:
seed=random.randint(1,1000000)
noise = PerlinNoise(octaves=3,seed=seed)
for z in range(8):
for x in range(8):
y = noise([x * 0.02,z * 0.02])
y = math.floor(y * 7.5)
voxel = Voxel(position=(x,y,z))
First, you did not say "Perlin Noise" correctly, so remove the semi-colon, then you'll use this code:
noise = PerlinNoise(octaves=intgeer,seed=0)
for z in range(8):
for x in range(8):
y = 0. 25 noise([x * 0.02,z * 0.02])
voxel = Voxel(position=(x,y,z))
It sounds like Voxel(...) places a voxel at the specified position, right? If so, then you would need to loop over the whole column to place the blocks into.
And if your noise library doesn't handle frequency and amplitude scaling internally, then you need to do that externally. Multiply the input coordinates by fractions, and multiply the output value by larger values.
min_height = 4.0
max_height = 16.0
for z in range(8):
for x in range(8):
height = # some noise formula
# if noise() range is 0 to 1: min_height + noise([x * 0.05, z * 0.05]) * (max_height - min_height)
# if noise() range is -1 to 1: min_height + (noise([x * 0.05, z * 0.05]) * 0.5 + 0.5) * (max_height - min_height)
for y in range(height): # might need to convert height to an integer
voxel = Voxel(position=(x,y,z))
Also please keep in mind the problems of Perlin for noise in its unmitigated form. The algorithm's popularity by name far outweighs its canonical form's true merit in light of its square alignment issues and the broader space of options we have now, and in spite of the overwhelming amount of content that still teaches it in a vacuum. See the final paragraph from my last answer for more info: https://stackoverflow.com/a/73348943
I would suggest this: https://pypi.org/project/pyfastnoiselite/
from pyfastnoiselite.pyfastnoiselite import (
FastNoiseLite, NoiseType, FractalType,
)
min_height = 4.0
max_height = 16.0
noise = FastNoiseLite(0)
noise.noise_type = NoiseType.NoiseType_OpenSimplex2
noise.fractal_type = FractalType.FractalType_FBm
noise.fractal_octaves = 4
noise.frequency = 0.03
for z in range(8):
for x in range(8):
height = min_height + (noise.get_noise(x, z) * 0.5 + 0.5) * (max_height - min_height)
for y in range(height): # might need to convert height to an integer
Voxel(position=(x,y,z))
or for 3D noise to enable overhangs, you vary that heightmap within Y as well:
from pyfastnoiselite.pyfastnoiselite import (
FastNoiseLite, NoiseType, FractalType,
)
min_height = 4.0
max_height = 16.0
noise = FastNoiseLite(0)
noise.noise_type = NoiseType.NoiseType_OpenSimplex2
noise.fractal_type = FractalType.FractalType_FBm
noise.fractal_octaves = 4
noise.frequency = 0.03
for z in range(8):
for x in range(8):
for y in range(min_height): # might need to convert bounds to integers
Voxel(position=(x,y,z))
for y in range(min_height, max_height): # might need to convert bounds to integers
effective_height = min_height + (noise.get_noise(x, y, z) * 0.5 + 0.5) * (max_height - min_height)
if effective_height > y:
Voxel(position=(x,y,z))
Examples untested. There may be some changes to parameters or even syntax to get these working! Feel free to make the needed edits to this answer to get it working properly.
Also min_height + (noise.get_noise(x, y, z) * 0.5 + 0.5) * (max_height - min_height) can be simplified down to noise.get_noise(x, y, z) * factor + offset, where
factor = 0.5 * (max_height - min_height)
offset = factor + min_height

Having trouble making the Sierpinski Carpet using recursion only and python turtle

import turtle
window = turtle.Screen()
window.screensize(1920,1080)
window.setup(width=1.0, height=1.0, startx=None, starty=None)
# T is a global variable
T = turtle.Turtle()
T.shape('turtle')
T.speed(2)
def forward_and_rotate(distance, degree, t):
t.forward(distance)
t.left(degree)
def draw_square_recursion(distance, t, sides_left=4):
t.pendown()
if sides_left == 0:
return
else:
forward_and_rotate(distance, 90, t)
draw_square_recursion(distance, t, sides_left-1)
t.penup()
def draw_filled_square(t, side_len, color='black'):
current_color = T.pencolor()
t.pendown()
t.color(color)
t.begin_fill()
draw_square_recursion(side_len, t, 4)
t.end_fill()
t.penup()
T.color(current_color)
# Starter code
def sier_carp(t, l, n):
if n == 0:
home = t.pos()
t.goto(home + (l/3, l/3))
draw_filled_square(t, l/3)
t.goto(home)
else:
sier_carp(t, l/3, n - 1)
t.fd(l/3)
sier_carp(t, l/3, n -1)
t.fd(l/3)
sier_carp(t, l/3, n -1)
t.fd(l/3)
t.left(90)
t.fd(l/3)
sier_carp(t, l/3, n - 1)
t.fd(l/3)
sier_carp(t, l/3, n -1)
t.fd(l/3)
t.left(90)
t.fd(l/3)
sier_carp(t, l/3, n - 1)
t.fd(l/3)
sier_carp(t, l/3, n -1)
t.fd(l/3)
t.left(90)
t.fd(l/3)
sier_carp(t, l/3, n - 1)
t.fd(l/3)
sier_carp(t, l/3, n -1)
t.fd(l/3)
t.left(90)
t.fd(l/3)
# add more cases!
T.penup()
sl = 200
draw_square_recursion(sl, T, 4)
sier_carp(T, sl, 1)
I'm having a hard time drawing the Sierpinski carpet using recursion only and no loops. However after the first three squares are drawn and I try to rotate to the left and do the next 2 squares on the nest site, the squares go out of line. If you want you can try out this code and see how it looks like. Btw the color are inversed to white around and black inside and not the usual carpet version of black around and white square.
I'm going to do a simplied version of your code -- although repetitive, your starter code does achieve your goal of recursion only. However, I'm going to use stamping instead of drawing so we can focus on the recursive image and not the mechanics of drawing squares with turtles:
from turtle import Screen, Turtle
SIDE_LENGTH = 200
CURSOR_SIZE = 20
def draw_filled_square(t, side_len):
t.shapesize(side_len / CURSOR_SIZE)
t.stamp()
def sier_carp(t, l, n):
draw_filled_square(t, l)
if n < 1:
return
x, y = t.position()
t.setx(x + l)
sier_carp(t, l/3, n - 1)
t.sety(y + l)
sier_carp(t, l/3, n - 1)
t.setx(x)
sier_carp(t, l/3, n - 1)
t.setx(x - l)
sier_carp(t, l/3, n - 1)
t.sety(y)
sier_carp(t, l/3, n - 1)
t.sety(y - l)
sier_carp(t, l/3, n - 1)
t.setx(x)
sier_carp(t, l/3, n - 1)
t.setx(x + l)
sier_carp(t, l/3, n - 1)
t.goto(x, y)
screen = Screen()
screen.setup(width=1.0, height=1.0)
turtle = Turtle()
turtle.hideturtle()
turtle.shape('square')
turtle.penup()
sier_carp(turtle, SIDE_LENGTH, 4)
screen.exitonclick()
I intentionally avoided speeding things up with screen.tracer(False) as you should see how it's drawn in a counterclockwise pattern.
I believe the problem is simpler than you're making it. It's important in this sort of drawing that your recursive function return the turtle to where it was when the function started. This allows the caller to make valid assumptions about its position.
Here are the concepts I've noted before starting:
Define a function that takes in a coordinate and a square size, and return the 8 surrounding coordinates.
Define a function that takes in a coordinate and a square size, and draw a square with the given size as its length, and the given coordinate as its center point.
Define the main function that will take in a coordinate, a size and the number of recursions. The coordinate will be the center of the Sierpinski Carpet and the size will be the size of the finished Sierpinski Carpet.
With the above notes in mind, let's begin to construct our program:
Import the turtle module, turn off tracer (optional) for efficiency and hide the turtle cursor:
import turtle
turtle.tracer(0)
turtle.hideturtle()
Define the function that takes in coordinate and a unit, and return a list of all 8 coordinates surrounding the given coordinate:
def surrounding(cor, size):
x, y = cor
return [(x - size, y + size),
(x + size, y + size),
(x - size, y - size),
(x + size, y - size),
(x - size, y),
(x + size, y),
(x, y + size),
(x, y - size)]
Define a recursive function that will take in a coordinate, size and a count. It will draw a square with its center at the given coordinate and its size one third of the given size, so that the sides of the finished carpet will end up the given size. The count is there to tell the function when to stop recursing; when the count reaches 0:
def draw_square(cor, size, count):
size /= 3
count -= 1
turtle.penup()
turtle.goto(cor[0] - size / 2, cor[1] + size / 2)
turtle.pendown()
turtle.begin_fill()
turtle.forward(size)
turtle.right(90)
turtle.forward(size)
turtle.right(90)
turtle.forward(size)
turtle.right(90)
turtle.forward(size)
turtle.right(90)
turtle.end_fill()
if count:
func(surrounding(cor, size), size, count)
Define a recursive function that takes in a coordinate and a size. It will use the surroundings function defined earlier to convert that coordinate into a list of surround coordinates. Then, it will use the draw_square function defined earlier to draw a square at each of the surrounding coordinates:
def func(cors, size, count):
if len(cors) == 2:
draw_square(cors, size, count)
else:
draw_square(cors[0], size, count)
draw_square(cors[1], size, count)
draw_square(cors[2], size, count)
draw_square(cors[3], size, count)
draw_square(cors[4], size, count)
draw_square(cors[5], size, count)
draw_square(cors[6], size, count)
draw_square(cors[7], size, count)
Finally, call the main function, func, and update the turtle screen (if tracer was set to 0).
func((0, 0), 600, 5)
turtle.update()
Altogether:
import turtle
turtle.tracer(0)
turtle.hideturtle()
def surrounding(cor, size):
x, y = cor
return [(x - size, y + size),
(x + size, y + size),
(x - size, y - size),
(x + size, y - size),
(x - size, y),
(x + size, y),
(x, y + size),
(x, y - size)]
def draw_square(cor, size, count):
size /= 3
count -= 1
turtle.penup()
turtle.goto(cor[0] - size / 2, cor[1] + size / 2)
turtle.pendown()
turtle.begin_fill()
turtle.forward(size)
turtle.right(90)
turtle.forward(size)
turtle.right(90)
turtle.forward(size)
turtle.right(90)
turtle.forward(size)
turtle.right(90)
turtle.end_fill()
if count:
func(surrounding(cor, size), size, count)
def func(cors, size, count):
if len(cors) == 2:
draw_square(cors, size, count)
else:
draw_square(cors[0], size, count)
draw_square(cors[1], size, count)
draw_square(cors[2], size, count)
draw_square(cors[3], size, count)
draw_square(cors[4], size, count)
draw_square(cors[5], size, count)
draw_square(cors[6], size, count)
draw_square(cors[7], size, count)
func((0, 0), 600, 5)
turtle.update()
Output:

Drawing radiating circular trapezoid pattern with Turtle

I was just wondering how to draw some trapezoids in my turtle code.
I want my output to be like this:
What my output is right now:
Here's the code I've written so far:
import turtle as trtl
num_sides = 6
side_length = 15
circumradius = side_length
trtl.pencolor((245, 176, 66))
trtl.pensize(8)
for move_turtle in range(1):
trtl.penup()
trtl.sety(-circumradius)
trtl.pendown()
trtl.circle(circumradius, steps = num_sides)
circumradius *= 2
side_length = side_length + 8
trtl.pensize(12)
for move_turtle in range(1):
trtl.pencolor((255, 83, 71))
trtl.penup()
trtl.sety(-circumradius)
trtl.pendown()
trtl.circle(circumradius, steps = num_sides)
circumradius *= 2
for move_turtle in range(1):
trtl.pencolor((247, 220, 67))
trtl.penup()
trtl.sety(-circumradius)
trtl.pendown()
trtl.circle(circumradius, steps = num_sides)
circumradius *= 2
trtl.hideturtle()
What techniques can I use to get the desired output?
The approach I often take when given patterns like this is to think about a slight-of-hand trick that can produce the result with less trouble than figuring out how to draw something potentially fussy like a trapezoid.
In this case, if you remove the white spaces, we have a "pie"-shaped circle of different solid colors radiating from the middle. If we can manage to solve that simpler problem, then we can draw white lines on top and wind up with the desired result.
The only trig we need is the angle-to-coordinates formula:
x = cos(radians(angle)) * radius
y = sin(radians(angle)) * radius
Using this, we can iterate over n points (with some rotational offset) along the circumference of a circle with a loop and fill in the colors to make a pie:
import math
import turtle
def draw_pie(t, r, n, colors, rot_offset=0.5):
for i in range(n + 1):
a = 360 / n * (i + rot_offset)
t.color(colors[i%len(colors)])
t.begin_fill()
t.goto(0, 0)
x = math.cos(math.radians(a)) * r
y = math.sin(math.radians(a)) * r
t.goto(x, y)
t.end_fill()
if __name__ == "__main__":
t = turtle.Turtle()
t.screen.setup(540, 540)
t.penup()
t.speed("fastest")
sides = 6
draw_pie(t, 450, sides, ["#dd2", "orange", "#d02"])
t.ht()
turtle.exitonclick()
Next, we need to draw a bunch of thick white lines with square corners. Unfortunately, turtle draws rounded edges by default which aren't suitable for our needs. There are many tricks for making square edges (stamping is a reasonable method). The approach I used here was writing a custom rectangle drawing function that takes advantage of turtle.distance and turtle.setheading(turtle.towards(x, y)) which lets me point to the next point along the circumference of the circle. The rest is just loops to compute angles and picking the right values.
Here's the code:
import math
import turtle
def draw_rect(t, x, y, xx, yy, width):
t.goto(x, y)
t.setheading(t.towards(xx, yy))
t.begin_fill()
for d in [t.distance(xx, yy), width] * 2:
t.forward(d)
t.left(90)
t.end_fill()
def draw_pie(t, r, n, colors, rot_offset=0.5):
for i in range(n + 1):
a = 360 / n * (i + rot_offset)
t.color(colors[i%len(colors)])
t.begin_fill()
t.goto(0, 0)
x = math.cos(math.radians(a)) * r
y = math.sin(math.radians(a)) * r
t.goto(x, y)
t.end_fill()
def draw_reg_polygon(t, r, n, thickness, rot_offset=0.5):
for i in range(n):
a = 360 / n * (i + rot_offset)
x = math.cos(math.radians(a)) * r
y = math.sin(math.radians(a)) * r
a = 360 / n * (1 + i + rot_offset)
xx = math.cos(math.radians(a)) * r
yy = math.sin(math.radians(a)) * r
draw_rect(t, x, y, xx, yy, thickness)
if __name__ == "__main__":
t = turtle.Turtle()
t.screen.setup(540, 540)
t.penup()
t.speed("fastest")
sides = 6
draw_pie(t, 450, sides, ["#dd2", "orange", "#d02"])
t.color("white")
for r in range(50, 500, 100):
draw_reg_polygon(t, r, sides, 45)
t.ht()
turtle.exitonclick()

Draw Checkerboard on Python

I want to draw a checkerboard on Python, but I only get one black square.
Can you help me fix this program?
import turtle
def filled_square(size, color, x, y):
turtle.setpos(x, y)
turtle.color(color)
turtle.begin_fill()
for i in range(4):
angle = 90
turtle.fd(size)
turtle.lt(angle)
turtle.end_fill()
turtle.up()
import sys
n = int(sys.argv[1])
s = int(sys.argv[2])
square_size = s//n
y=0
for i in range(n):
x = 0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
x+=square_size
turtle.down()
turtle.done()
y=0
for i in range(n):
x = 0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
x+=square_size
Couple problems here.
There's not much point in increasing the value of x when you reset it right back to zero in the next iteration, so the initial assignment should be above the for loop.
you never update the value of y.
x = 0
for i in range(n):
y=0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
y+=square_size
x+=square_size
Now you should get the checkerboard shape you want.
Alternate solution: you can avoid the problem of bookkeeping the values of x and y by not having those values at all. You can derive the coordinates of the squares straight from i and j.
for i in range(n):
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", i*square_size, j*square_size)
else:
filled_square(square_size, "black", i*square_size, j*square_size)
It might also be nice to consolidate the common logic in your if and else blocks, and only differentiate the values that actually change (namely, the color)
for i in range(n):
for j in range(n):
if (i+j)%2==0:
color = "red"
else:
color = "black"
filled_square(square_size, color, i*square_size, j*square_size)
You need to increment both x and y. Also note that x should be incremented in the inner loop. Here is the working code,
import turtle
def filled_square(size, color, x, y):
turtle.setpos(x, y)
turtle.color(color)
turtle.begin_fill()
for i in range(4):
angle = 90
turtle.fd(size)
turtle.lt(angle)
turtle.end_fill()
turtle.up()
import sys
n = int(sys.argv[1])
s = int(sys.argv[2])
square_size = s//n
y=0
for i in range(n):
x = 0
for j in range(n):
if (i+j)%2==0:
filled_square(square_size, "red", x, y)
else:
filled_square(square_size, "black", x, y)
x+=square_size
y+=square_size
turtle.down()
turtle.done()
I recommend using functional programming like this for board/game work. It'll make everything easier to maintain and make implementing new features easier.
import turtle
def filled_square(size, color, x, y):
turtle.up()
turtle.setpos(x, y)
turtle.color(color)
turtle.begin_fill()
for i in range(4):
angle = 90
turtle.fd(size)
turtle.lt(angle)
turtle.end_fill()
def board(length, size, x_pos=0, y_pos=0):
for y in range(length):
for x in range(length):
if (x+y)%2==0:
filled_square(
size, "red", (x * square_size) - x_pos, (y * square_size) - y_pos)
else:
filled_square(
size, "black", (x * square_size) - x_pos, (y * square_size) - y_pos)
turtle.done()
Keyword arguments are great too. If you decided you wanted to add more colors, it is as easy as adding an two parameters,
def board(length, size, x_pos=0, y_pos=0, color1="red", color2="black"):
for y in range(length):
for x in range(length):
if (x+y)%2==0:
filled_square(
size, color1, (x * square_size) - x_pos, (y * square_size) - y_pos)
else:
filled_square(
size, color2, (x * square_size) - x_pos, (y * square_size) - y_pos)

Python: draw tangent graph using math & turtle libraries

I was stuck on this task for several days. Although, the solution should be simple. I apply math and turtle libraries for drawing 3 graphs: sine, cosine and tangent with amplitude 200. The problem is I cant build the tangent graph as It should be drawn.
This is what I should do:
This is what I got:
As you see, my turtle goes up and doesn't come back anymore.
Pls, don't suggest me to use numpy. It's out of my task.
Thank you for advance!
import math
import turtle
ws = turtle.Screen()
ws.bgcolor("white")
t = turtle.Turtle()
for i in [(0,250), (0,0), (0,-250), (0,0), (400,0), (0,0)]:
t.goto(i, None)
t.write(i, font=("Arial", 12))
t.color("red")
for angle in range(360):
y = math.sin(math.radians(angle))
t.goto(angle, y * 200)
t.penup()
t.setpos(0,200)
t.goto(0,200)
t.pendown()
t.color("blue")
for angle in range(360):
y = math.cos(math.radians(angle))
t.goto(angle, y * 200)
t.penup()
t.setpos(0,0)
t.goto(0,0)
t.pendown()
t.color("green")
for angle in range(360):
y = math.tan(math.radians(angle))
t.goto(angle, y * 200)
ws.exitonclick()
To show that it should work, below is my minimalist implementation of plotting sine, cosine and tangent using turtle graphics:
import math
from turtle import Turtle, Screen
RESOLUTION = 0.1
def plot(x_points, y_points):
for i, y in enumerate(y_points):
if abs(y) <= 2.0:
yertle.goto(x_points[i], y)
yertle.pendown()
else:
yertle.penup()
yertle.penup()
screen = Screen()
screen.setworldcoordinates(0, -1.5, 2 * math.pi / RESOLUTION, 1.5)
yertle = Turtle()
yertle.penup()
x = range(int(2 * math.pi / RESOLUTION))
yertle.color("blue")
plot(x, (math.cos(n * RESOLUTION) for n in x))
yertle.color("red")
plot(x, (math.sin(n * RESOLUTION) for n in x))
yertle.color("dark green")
plot(x, (math.tan(n * RESOLUTION) for n in x))
screen.exitonclick()
OUTPUT
My guess is you're not waiting long enough for tangent to plot, i.e. it's slowly plotting lots of points off the window and will eventually reappear on-screen. My code works around that issue.
try about this. Near to work for me, no time to get better:
for angle in range(360):
y=0
y = math.tan(math.radians(angle))
if y<1 and y>-1:
t.goto(angle, y * 200)
With asipmtotas
for angle in range(360):
t.penup()
y = math.tan(math.radians(angle))
if y<1 and y>-1:
t.pendown()
t.goto(angle, y * 200)
else:
t.penup()
#t.pendown()
t.goto(angle, 200)

Categories