""" Before the World Was II generation script. This code is not particularly elegant. It's based on the Generative Artistry tutorial: https://generativeartistry.com/tutorials/circle-packing/. """ #!/usr/bin/env python import math import random window_size = 600 half_size = window_size / 2 circles = [] min_r = 4.2 max_r = 6 step = 0.2 max_r2 = max_r * 2 border = 1 min_x = 0 - (max_r2) max_x = window_size + (max_r2) total_circles = 1600 attempts = 500 # Heavenly Parents parent_r = 50 parent_border = 12.5 circles.append({ 'x': half_size - parent_r, 'y': half_size, 'r': parent_r, 'border': parent_border, 'cls': 'parent', }) circles.append({ 'x': half_size + parent_r, 'y': half_size, 'r': parent_r, 'border': parent_border, 'cls': 'parent', }) def collision(c): """ Check if the circle has collided with either another circle or the outer wall (with some padding). """ for other in circles: if not other: continue x = c['x'] - other['x'] y = c['y'] - other['y'] a = c['r'] + c['border'] + other['r'] + other['border'] if a >= math.sqrt((x*x) + (y*y)): return True return False # big or small def new_circle(r, border): """ Creates a new circle dict. """ return { 'x': math.floor(random.random() * window_size), 'y': math.floor(random.random() * window_size), 'r': r, 'border': border, 'cls': 'child', } def create_circle(start_r, border): """ Create a new circle, checking for collisions. """ draw = False for _ in range(attempts): c = new_circle(start_r, border) if collision(c): continue draw = True break if not draw: return # See how big it can grow, this is kind of hacky while c['r'] <= max_r: c['r'] += step if collision(c): c['r'] -= step break return c def create_circles(): """ Create the circles, adding them to the hackily global circles list. """ for i in range(total_circles): c = create_circle(min_r, border) circles.append(c) # Progress bar if i % 10 == 0: print('.', end='', flush=True) # Give us a newline print() def to_svg(circles, filename): """ Takes a list of circles and spits out an SVG file. """ SVG_TEMPLATE = ''' ''' svg = '' for c in circles: if not c: continue x = c['x'] y = c['y'] r = c['r'] cls = c['cls'] svg += f'\t\n' with open(filename, 'w') as f: f.write(SVG_TEMPLATE.format(window_size=window_size, circles=svg)) if __name__ == '__main__': create_circles() to_svg(circles, 'output.svg') print(f'{len(circles)} circles generated, see output.svg')