Skip to content

Instantly share code, notes, and snippets.

@DMRobertson
Created December 15, 2017 12:57
Show Gist options
  • Save DMRobertson/db3c55d969e30ea9395a14f61577f247 to your computer and use it in GitHub Desktop.
Save DMRobertson/db3c55d969e30ea9395a14f61577f247 to your computer and use it in GitHub Desktop.
Blender Python API example
"""A script to build a model representing the Cayley graph of F_3 in Blender. I threw this together in a morning so it's quite hacky and quite dirty."""
import bpy
from itertools import product
from math import sqrt
def make_alphabet(letters):
"""Group/monoid elements are represented in memory as numbers, but we should be able to list them as human-readable strings. We use an asterisk to denote inverse, so that (e.g.) xx* = 1."""
symbols = {}
for i, char in enumerate(letters):
symbols[i] = char
symbols[i] = char + '*'
return symbols
symbols = make_alphabet('xyz')
alphabet = list(symbols)
def free_monoid_on(alphabet, max_len=float('inf'), skip_empty=False):
length = 1 if skip_empty else 0
while length <= max_len:
yield from product(alphabet, repeat=length)
length += 1
def free_group_on(alphabet, max_len=float('inf'), skip_empty=False):
for x in free_monoid_on(alphabet, max_len, skip_empty):
if is_reduced(x):
yield x
def format(word):
if len(word) == 0:
return '<empty>'
return ''.join(symbols[i] for i in word)
def is_reduced(word):
#Doesn't need to know about the alphabet as it's only looking at numbers here
return all( word[i] != -word[i+1] for i in range(len(word)-1))
def coord(word):
c = [0, 0, 0]
depth = 0
for char in word:
sign = 1 if char > 0 else -1
c[index(char)] += sign * 2 ** -depth
depth += 1
return c
def index(char):
return abs(char) - 1
def midpoint(x, y, weight=1/2):
return [weight*x[i] + (1-weight)*y[i] for i in range(len(x))]
def dist(x, y):
return sqrt( sum( x[i]**2 + y[i]**2 for i in range(len(x)) ) )
def add_cube(x):
tail = x[:-1]
t_loc = coord(tail)
h_loc = coord(x)
depth = len(x)
loc = midpoint(h_loc, t_loc, 3/4)
thickness = 2**-depth
scale_factor = (dist(loc, h_loc) + thickness)/thickness
resize_vec = [1, 1, 1]
try:
resize_vec[index(x[-1])] = 2
except IndexError: #empty word doesn't need resizing
pass
bpy.ops.mesh.primitive_cube_add(location=loc, radius=thickness/2,)
for obj in bpy.context.selected_objects:
obj.name = format(x)
bpy.ops.transform.resize(value=resize_vec)
if __name__ == "__main__":
#For use when debugging
#bpy.ops.object.select_all(action='SELECT')
#bpy.ops.object.delete()
count = 0
for word in free_group_on(alphabet, max_len=4):
count += 1
if count % 100 == 0: print(count)
add_cube(word)
bpy.ops.object.select_all(action='DESELECT')
print('Done!')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment