Created
December 15, 2017 12:57
-
-
Save DMRobertson/db3c55d969e30ea9395a14f61577f247 to your computer and use it in GitHub Desktop.
Blender Python API example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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