I'm continuing my experiment in procedural generation by "exploring" a fascinating algorithm for generating procedural trees. The rapidly-exploring random tree algorithm, or RRT for short, is a Monte-Carlo method traditionally used for autonomous navigation. However, before I dive into the code, let me show you this algorithm's result in an image.
It's a fractal! A stochastic fractal, to be precise.And so began my journey to replicate this algorithm, not for robotic navigation, but for artistic purposes. I decided to write the code for my implementation with Python since the PIL library makes it easy to quickly generate images.
import random import math from PIL import Image, ImageDraw WIDTH = 500 HEIGHT = 500 RECURSIONS = 125 class Node: def __init__(self, x, y): self.x = x self.y = y self.parent = None def __repr__(self): return (self.x, self.y) def distance(self, other): return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2) def get_nearest(self, nodes, rnd): dlist = [(node.distance(rnd), node) for node in nodes] dlist.sort() return dlist[0][1] def turn(self, to, extend_length=10.0): d, theta = self.distance(to), math.atan2(to.y - self.y, to.x - self.x) if d > extend_length: to = Node(self.x + extend_length * math.cos(theta), self.y + extend_length * math.sin(theta)) to.parent = self return to def generate_path(self, path): path.append((self.x, self.y)) if self.parent is not None: self.parent.generate_path(path) img = Image.new('RGB', (WIDTH, HEIGHT), (255, 255, 255)) draw = ImageDraw.Draw(img) nodes = [] nodes.append(Node(random.randint(0, WIDTH), random.randint(0, HEIGHT))) for i in range(RECURSIONS): rnd = Node(random.randint(0, WIDTH), random.randint(0, HEIGHT)) nearest_node = nodes[0].get_nearest(nodes, rnd) new_node = nearest_node.turn(rnd) nodes.append(new_node) draw.line((nearest_node.x, nearest_node.y, new_node.x, new_node.y), fill=(0, 0, 0)) try: img.show() #save image img.save('rrt.png') except(TypeError): pass
Comments
Post a Comment