Help drawing recursive trees

Hi guys, I have the following code. I’m trying to get the branches to draw slowly through the draw function and not during one draw iteration but can’t figure it out given the recursion.

If anyone could help that would be great and if anyone knows how to edit this text to be in code that would be useful thanks!

import time

def setup():
size(1000, 1000);
background(0)
stroke(83,53,10)

def draw():

frameRate(1)

original_size = 120
translate(width/2,height)
first_branch_size = 120
left, right = get_direction(probability = 0.5)
first_thickness_size = 5
strokeWeight(first_thickness_size)
line(0,0,0,-original_size);
translate(0,-original_size);

branch(first_branch_size, left, right, threshold = 30, first_thickness_size = first_thickness_size);

#multiple_branch(first_branch_size, left, right, threshold = 30, first_thickness_size = first_thickness_size)

time.sleep(5)

def get_direction(probability = 0.1):
random_int = random(0,1)

left_probability = 1 - probability
left, right = False, False
if random_int  >= left_probability:
    left = True
elif random_int <= probability:
    left = True
else:
    left, right = True, True

return left, right

def draw_branch(theta, h, threshold, first_thickness_size):
first_thickness_size *= random(0.6, 0.9)
strokeWeight(first_thickness_size)
pushMatrix();
rotate(-theta);
line(0, 0, 0, -h);
# for i in range(100):
# y = lerp(0, 0, i/100)
# point(0, y)
translate(0, -h);
left, right = get_direction()
branch(h, left, right, threshold, first_thickness_size);
popMatrix();

def branch(h, left, right, threshold = 6, first_thickness_size = 3):

a = random(-30, 30)
steps = 10
theta = radians(a)

h *= random(0.7, 1);
if (h > threshold):
if right:
draw_branch(theta, h, threshold, first_thickness_size) # Whenever we get back here, we “pop” in order to restore the previous matrix state
if left:
draw_branch(-theta, h, threshold, first_thickness_size)
# Repeat the same thing, only branch off to the “left” this time!

else:
lights();
pushMatrix()
fill(random(30,45), random(45,90), random(1,39))
ellipse(0, 0, random(1,5), random(1,20))

  translate(0,-h)
  popMatrix()

def multiple_branch(first_branch_size, left, right, threshold, first_thickness_size = 10):
branch(first_branch_size, left, right, threshold = 30, first_thickness_size = first_thickness_size);
branch(first_branch_size, left, right, threshold = 20, first_thickness_size = first_thickness_size);
branch(first_branch_size, left, right, threshold = 10, first_thickness_size = first_thickness_size);

Hi @43zombiegit,

Please help us to help you and follow instructions here to format your code.

https://discourse.processing.org/faq#format-your-code

Cheers
— mnse

Adding a time.sleep() won’t help. Probably, moving the branch-drawing logic into your draw block would be best. Hopefully, this very simple example helps illustrate what I mean –

def setup():
    size(500, 500)
    frameRate(1)

def draw():
    right = random(0, 1)
    if right > 0.5:
        draw_branch('#FF0000', 'r')
    else:
        draw_branch('#0000FF', 'l')
        
def draw_branch(f, dir):
    stroke(f)
    strokeWeight(2)
    if dir == 'r':
        line(random(width/2), random(height), 250, 0)
    else:
        line(250 + random(width/2), random(height), 250, 0)

It just draws random lines on the left (blue) and right (red) halves of the display window, but hopefully that helps.

As the mnse has pointed out, you need to format your code (with the </> button) so we can see the indentation.

1 Like

… to add to what I wrote before …

Consider that these three code snippets produce the same result, counting from ten down to zero. First, a recursive function

r_limit = 10

def recurse():
    global r_limit
    print(r_limit)
    if r_limit > 0:
        r_limit -= 1
        recurse()
        delay(1000)

recurse()

Second, a while loop (which you use instead of a for loop when you don’t know ‘up front’ how many iterations you might require) –

r_limit = 10

while r_limit > 0:
    print(r_limit)
    r_limit -= 1
    delay(1000)

But you need to draw/render each frame. So here’s a third version that employs the draw() block as a loop. Note that the frameRate() effectively serves the purpose of the timing argument in the delay() functions above –

def setup():
    frameRate(1)

r_limit = 10

def draw():
    global r_limit
    print(r_limit)
    if r_limit > 0:
        r_limit -= 1
    else:
        noLoop()

Alternatively, you could use a draw() block with some noLoop();delay(1000);draw() sequence in it – but to me, that feels more clumsy than letting frameRate() do the job for you (unless you need some variable frame rate).