diff --git a/hyphae.py b/hyphae.py new file mode 100755 index 0000000..7e7fd5f --- /dev/null +++ b/hyphae.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +import cairo +import math +import random +from utils import circle_fill +from utils import random_color + +WIDTH, HEIGHT = 1000, 1000 +ANGLE_RANDOM_MIN = -0.8 +ANGLE_RANDOM_MAX = 0.8 +# how much to shrink each consecutive circle +SHRINK = 0.0002 + +class Branch(): + def __init__(self, idx, ctx, x, y, r, ang): + self.nodes = [Node(ctx, x, y, r, ang)] + self.idx = idx + self.ctx = ctx + self.ended = False + def _last_node(self): + return self.nodes[-1] + def place_next(self, branches): + if not self.ended: + last = self._last_node() + 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 + # did we hit canvas edge? + if next_x + next_r > 1 or next_x - next_r < 0: + self.ended = True + return + if next_y + next_r > 1 or next_y - next_r < 0: + self.ended = True + return + last_nodes = self.nodes[-2:] + # did we hit another circle? + for branch in branches: + for node in branch.nodes: + 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 + + 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)) + + +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): + self.x = x + self.y = y + self.r = r + self.ang = ang + 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 main(): + + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT) + ctx = cairo.Context(surface) + + ctx.scale(WIDTH, HEIGHT) # Normalizing the canvas + + + 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 branch in branches: + branch.place_next(branches) + + + surface.write_to_png("out/hyphae.png") # Output to PNG + +if __name__ == '__main__': + main() diff --git a/utils.py b/utils.py index 1207694..48dca58 100644 --- a/utils.py +++ b/utils.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 import random - +import math def circle(ctx,x,y,r): - ctx.arc(x,y,r,0,pi*2.) + ctx.arc(x,y,r,0,math.pi*2.) ctx.stroke() -def circle_fill(self,x,y,r): - self.ctx.arc(x,y,r,0,pi*2.) - self.ctx.fill() +def circle_fill(ctx,x,y,r): + ctx.arc(x,y,r,0,math.pi*2.) + ctx.fill() def random_color():