takes some time lul

gui
Felix Pankratz 3 years ago
parent 0b5db0c3f5
commit eedf8e7ac5

@ -7,17 +7,20 @@ from utils import circle_fill
from utils import random_color from utils import random_color
WIDTH, HEIGHT = 1000, 1000 WIDTH, HEIGHT = 1000, 1000
ANGLE_RANDOM_MIN = -0.8 ANGLE_RANDOM_MIN = -0.6
ANGLE_RANDOM_MAX = 0.8 ANGLE_RANDOM_MAX = 0.6
# how much to shrink each consecutive circle # how much to shrink each consecutive circle
SHRINK = 0.0002 SHRINK = 0.00004
class Branch(): class Branch():
def __init__(self, idx, ctx, x, y, r, ang): def __init__(self, idx, ctx, x, y, r, ang):
self.nodes = [Node(ctx, x, y, r, ang)] ctx.set_source_rgb(255, 0, 0)
self.nodes = [Node(ctx, x, y, r, ang, dry=True)]
ctx.set_source_rgb(0,0, 0)
self.idx = idx self.idx = idx
self.ctx = ctx self.ctx = ctx
self.ended = False self.ended = False
def _last_node(self): def _last_node(self):
return self.nodes[-1] return self.nodes[-1]
def place_next(self, branches): def place_next(self, branches):
@ -26,13 +29,17 @@ class Branch():
next_x = last.r * math.sin(last.ang) + last.x next_x = last.r * math.sin(last.ang) + last.x
next_y = last.r * math.cos(last.ang) + last.y next_y = last.r * math.cos(last.ang) + last.y
next_r = last.r - SHRINK next_r = last.r - SHRINK
# too small?
if next_r < 0.000000001:
self.ended = True
return False
# did we hit canvas edge? # did we hit canvas edge?
if next_x + next_r > 1 or next_x - next_r < 0: if next_x + next_r > 1 or next_x - next_r < 0:
self.ended = True self.ended = True
return return False
if next_y + next_r > 1 or next_y - next_r < 0: if next_y + next_r > 1 or next_y - next_r < 0:
self.ended = True self.ended = True
return return False
last_nodes = self.nodes[-2:] last_nodes = self.nodes[-2:]
# did we hit another circle? # did we hit another circle?
for branch in branches: for branch in branches:
@ -40,33 +47,57 @@ class Branch():
if node not in last_nodes: #!= last and node != self.nodes[-2]: if node not in last_nodes: #!= last and node != self.nodes[-2]:
if circles_intersect(node.x, node.y, node.r, if circles_intersect(node.x, node.y, node.r,
next_x, next_y, next_r): next_x, next_y, next_r):
print(f'intersect: {next_x},{next_y} r: {next_r} with {node}')
self.ended = True self.ended = True
return return False
next_ang = last.ang + random.uniform(ANGLE_RANDOM_MIN, ANGLE_RANDOM_MAX) next_ang = last.ang + random.uniform(ANGLE_RANDOM_MIN, ANGLE_RANDOM_MAX)
print(f'next circle: {next_x},{next_y} r: {next_r} a: {next_ang}')
self.nodes.append(Node(self.ctx, next_x, next_y, next_r, next_ang)) self.nodes.append(Node(self.ctx, next_x, next_y, next_r, next_ang))
return True
def circles_intersect(x1, y1, r1, x2, y2, r2): def circles_intersect(x1, y1, r1, x2, y2, r2):
distance = math.sqrt(math.pow(abs(x2 - x1), 2) + math.pow(abs(y2 - y1), 2)) distance = math.sqrt(math.pow(abs(x2 - x1), 2) + math.pow(abs(y2 - y1), 2))
combined_r = r1 + r2 combined_r = r1 + r2
print(f'd: {distance} r1 + r2: {combined_r}')
return distance < combined_r return distance < combined_r
class Node(): class Node():
def __init__(self, ctx, x, y, r, ang): def __init__(self, ctx, x, y, r, ang, dry=False):
self.x = x self.x = x
self.y = y self.y = y
self.r = r self.r = r
self.ang = ang self.ang = ang
if not dry:
circle_fill(ctx, x, y, r) circle_fill(ctx, x, y, r)
def __ne__(self, other): def __ne__(self, other):
return self.x != other.x or self.y != other.y or self.r != other.r or self.ang != other.ang return self.x != other.x or self.y != other.y or self.r != other.r or self.ang != other.ang
def grow_subs(ctx, subs, branches):
new_subs = []
created = False
for branch in subs:
# create a sub branch based on length
sub_branches = len(branch.nodes) // 10
if sub_branches > 1:
created = True
for i in range(sub_branches):
for n in range(15): # attempts at growing branches
start_node = random.choice(branch.nodes)
# start perpendicular to our last angle
start_angle = start_node.ang + random.choice([90, -90]) + random.uniform(-5, 5)
start_x = start_node.r * math.sin(start_angle) + start_node.x
start_y = start_node.r * math.cos(start_angle) + start_node.y
start_r = start_node.r - 0.002
new_branch = Branch(i, ctx, start_x, start_y, start_r, start_angle)
if new_branch.place_next(branches):
break
branches.append(new_branch)
new_subs.append(new_branch)
if not created:
return
while not all([branch.ended for branch in new_subs]):
for branch in new_subs:
branch.place_next(branches)
return new_subs
def main(): def main():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
@ -74,19 +105,33 @@ def main():
ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas
# place seeds
branches = [] branches = []
for b in range(6): #for b in range(6):
start_x = random.uniform(0.3, 0.7) # start_x = random.uniform(0.2, 0.8)
start_y = random.uniform(0.3, 0.7) # start_y = random.uniform(0.2, 0.8)
start_r = 0.02 start_r = 0.015
start_angle = random.randint(0, 360) # start_angle = random.randint(0, 360)
branches.append(Branch(b, ctx, start_x, start_y, start_r, start_angle)) # branches.append(Branch(b, ctx, start_x, start_y, start_r, start_angle))
for x in range(100): branches.append(Branch(0, ctx, 0.5, 0.4, start_r, 180))
branches.append(Branch(1, ctx, 0.4, 0.5, start_r, 270))
branches.append(Branch(2, ctx, 0.6, 0.5, start_r, 90))
branches.append(Branch(3, ctx, 0.5, 0.6, start_r, 0))
# grow initial branches
while not all([b.ended for b in branches]):
for branch in branches: for branch in branches:
branch.place_next(branches) branch.place_next(branches)
# start branching off
#subs = []
subs = branches
try:
for x in range(8):
if subs == None:
return
subs = grow_subs(ctx, subs, branches)
surface.write_to_png("out/hyphae.png") # Output to PNG
input('next')
finally:
surface.write_to_png("out/hyphae.png") # Output to PNG surface.write_to_png("out/hyphae.png") # Output to PNG
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save