diff --git a/hyphae.py b/hyphae.py index 7e7fd5f..76877a1 100755 --- a/hyphae.py +++ b/hyphae.py @@ -7,17 +7,20 @@ from utils import circle_fill from utils import random_color WIDTH, HEIGHT = 1000, 1000 -ANGLE_RANDOM_MIN = -0.8 -ANGLE_RANDOM_MAX = 0.8 +ANGLE_RANDOM_MIN = -0.6 +ANGLE_RANDOM_MAX = 0.6 # how much to shrink each consecutive circle -SHRINK = 0.0002 +SHRINK = 0.00004 class Branch(): 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.ctx = ctx self.ended = False + def _last_node(self): return self.nodes[-1] def place_next(self, branches): @@ -26,13 +29,17 @@ class Branch(): next_x = last.r * math.sin(last.ang) + last.x next_y = last.r * math.cos(last.ang) + last.y next_r = last.r - SHRINK + # too small? + if next_r < 0.000000001: + self.ended = True + return False # did we hit canvas edge? if next_x + next_r > 1 or next_x - next_r < 0: self.ended = True - return + return False if next_y + next_r > 1 or next_y - next_r < 0: self.ended = True - return + return False last_nodes = self.nodes[-2:] # did we hit another circle? for branch in branches: @@ -40,33 +47,57 @@ class Branch(): if node not in last_nodes: #!= last and node != self.nodes[-2]: if circles_intersect(node.x, node.y, node.r, next_x, next_y, next_r): - print(f'intersect: {next_x},{next_y} r: {next_r} with {node}') self.ended = True - return + return False 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)) - + return True def circles_intersect(x1, y1, r1, x2, y2, r2): distance = math.sqrt(math.pow(abs(x2 - x1), 2) + math.pow(abs(y2 - y1), 2)) combined_r = r1 + r2 - print(f'd: {distance} r1 + r2: {combined_r}') return distance < combined_r class Node(): - def __init__(self, ctx, x, y, r, ang): + def __init__(self, ctx, x, y, r, ang, dry=False): self.x = x self.y = y self.r = r self.ang = ang - circle_fill(ctx, x, y, r) + if not dry: + circle_fill(ctx, x, y, r) def __ne__(self, other): 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(): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) @@ -74,20 +105,34 @@ def main(): ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas - + # place seeds branches = [] - for b in range(6): - start_x = random.uniform(0.3, 0.7) - start_y = random.uniform(0.3, 0.7) - start_r = 0.02 - start_angle = random.randint(0, 360) - branches.append(Branch(b, ctx, start_x, start_y, start_r, start_angle)) - for x in range(100): + #for b in range(6): + # start_x = random.uniform(0.2, 0.8) + # start_y = random.uniform(0.2, 0.8) + start_r = 0.015 + # start_angle = random.randint(0, 360) + # branches.append(Branch(b, ctx, start_x, start_y, start_r, start_angle)) + 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: branch.place_next(branches) - - - surface.write_to_png("out/hyphae.png") # Output to PNG + # 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 if __name__ == '__main__': main()