Skip to content

Instantly share code, notes, and snippets.

@zeffii
Created December 16, 2015 20:52
Show Gist options
  • Save zeffii/a651fbae53236d94b589 to your computer and use it in GitHub Desktop.
Save zeffii/a651fbae53236d94b589 to your computer and use it in GitHub Desktop.
"""
lifted from: http://www.4dsolutions.net/ocn/lsystems.html
"F": Move forward a step of length d. A line segment between
points (X,Y,Z) and (X',Y',Z') is drawn.
"["
and
"]": bracket - push and pop the current state, in this project
it is used to generate the tree branches
"+": Turn left by angle Delta, Using rotation matrix R_U(Delta)
"-": Turn right by angle Delta, Using rotation matrix R_U(-Delta)
"&": Pitch down by angle Delta, Using rotation matrix R_L(Delta)
"+": Pitch up by angle Delta, Using rotation matrix R_L(-Delta)
"<": Roll left by angle Delta, Using rotation matrix R_H(Delta)
">": Roll right by angle Delta, Using rotation matrix R_H(-Delta)
"|": Turn around, Using rotation matrix R_H(180)
"""
import math
from math import radians
import random
from random import randint
import bpy
import bmesh
from mathutils import Vector, Euler
Xvec = Vector((1, 0, 0))
Yvec = Vector((0, 1, 0))
Zvec = Vector((0, 0, 1))
def produce(axiom, rules):
output = ""
for i in axiom:
output = output + rules.get(i, i)
return output
def iterate(n, axiom, rules):
# print(axiom)
if n > 0:
axiom = produce(axiom, rules)
return iterate(n - 1, axiom, rules)
return axiom
class Lturtle:
# looking down on YX axis. Z is vertical.
stackstate = [] # remembers saved state
vHeading = Vector((0, 0, 1))
delta = 0.2 # angle of rotation
length = 0.5 # full length of turtle move
thickness = 0.02 # default thickness of cylinder
instrudict = {
'+': 'turnleft',
'-': 'turnright',
'&': 'pitchdown',
'^': 'pitchup',
'<': 'leftroll',
'>': 'rightroll',
'[': 'storeloc_rot',
']': 'restoreloc_rot',
'%': 'roll180',
'$': 'rollhoriz',
'x': 'randturn',
't': 'gravity',
'F': 'fdraw',
'f': 'fnodraw',
'Z': 'halfdraw',
'z': 'halfnodraw',
'g': 'Fnorecord',
'.': 'Nomove'
}
verts = []
edges = []
def __init__(self, vPos=Vector((0, 0, 0)), vH=Xvec, vL=Yvec, vU=Zvec):
self.vPos, self.vH, self.vL, self.vU = vPos, vH, vL, vU
def chomp(self, instructions):
getparam = 0
checkparam = 0
param = ""
for item in instructions:
if getparam:
if item == ")":
getparam = 0 # done getting
command = command + "(" + param + ")"
eval(command)
continue
else:
param = param + item # building parameter
continue
if checkparam: # checking for parameter?
checkparam = 0
if item == "(":
param = ""
getparam = 1 # parameter exists
continue
else:
command = command + "()" # no parameter
eval(command)
# initializing command string
command = "self." + self.instrudict.get(item, 'notHandled')
checkparam = 1 # set flag
else: # dealing with last item
if checkparam:
command = command + "()" # no parameter
eval(command)
if self.edges and self.verts:
mesh = bpy.data.meshes.new("Base_Data")
mesh.from_pydata(self.verts, self.edges, [])
mesh.update()
obj = bpy.data.objects.new("Base_Object", mesh)
scene = bpy.context.scene
scene.objects.link(obj)
def add_edge(self):
i = len(self.verts)
self.edges.append([i - 2, i - 1])
def add_verts(self, amp=1):
self.verts.append(self.vPos[:])
self.vPos = self.vPos + (self.vHeading * self.length * amp)
self.verts.append(self.vPos[:])
def fnodraw(self, n=""):
self.vPos = self.vPos + self.vHeading * self.length
print("Forward %s (no draw)" % n)
def halfnodraw(self, n=""):
self.vPos = self.vPos + (self.vHeading * self.length * 0.5)
print("half no draw %s" % n)
def fdraw(self, n=""):
self.add_verts()
self.add_edge()
print("fdraw %s" % n)
def halfdraw(self, n=""):
self.add_verts(amp=0.5)
self.add_edge()
print("half draw %s" % n)
# Turning, Pitch, Roll
def storeloc_rot(self, n=""):
print("Store rotation and location %s" % n)
def restoreloc_rot(self, n=""):
print("Restore rotation and location %s" % n)
def do_rotation(self, axis, sign, n=""):
""" axis 0=x, 1=y, z=2 """
if n:
self.delta = float(n)
components = [0, 0, 0]
components[axis] = sign * radians(self.delta)
myEul = Euler(components, 'XYZ')
self.vHeading.rotate(myEul)
def turnleft(self, n=""):
self.do_rotation(1, 2, n)
print("Turn Left around Z axis %s" % n)
def turnright(self, n=""):
self.do_rotation(-1, 2, n)
print("Turn Right around Z axis %s" % n)
def pitchdown(self, n=""):
self.do_rotation(1, 1, n)
print("Pitch down %s" % n)
def pitchup(self, n=""):
self.do_rotation(-1, 1, n)
print("Pitch up %s" % n)
def leftroll(self, n=""):
self.do_rotation(1, 0, n)
print("left roll %s" % n)
def rightroll(self, n=""):
self.do_rotation(-1, 0, n)
print("right roll %s" % n)
def turn180(self, n=""):
self.do_rotation(-1, 2, 180)
print("turn180 %s" % n)
def roll180(self, n=""):
self.do_rotation(1, 0, 180)
print("roll180 %s" % n)
def rollhoriz(self, n=""):
# not exactly sure what this command was intended to do but how
# about resetting to vertical.
self.vHeading = Vector((0, 0, 1))
print("roll horiz %s" % n)
def randturn(self, n=""):
ax_x = radians(randint(0, 360))
ax_y = radians(randint(0, 360))
ax_z = radians(randint(0, 360))
myEul = Euler((ax_x, ax_y, ax_z), 'XYZ')
self.vHeading.rotate(myEul)
print("randturn %s" % n)
def gravity(self, n=""):
print("not handled yet")
print("gravity %s" % n)
def Fnorecord(self, n=""):
print("Fnorecord %s" % n)
def Nomove(self, n=""):
print("No move %s" % n)
def notHandled(self, n=""):
print("Not handled %s" % n)
rules = {}
rules['I'] = '+(40)ffHccI'
rules['H'] = '[+ffFG]c[-fffG]c[^fffG]c[&fffG]G'
rules['G'] = '[dS]e[d]e[d]e[d]e[d]e[d]e[d]e[d]'
rules['e'] = '+(90)f-(90)>(-45)'
rules['d'] = '[f+(90)f+(90)f+(90)f>(+38)-(105)ff-(151)ff][f&(38)+(15)ff+(151)ff]'
axiom = 'I'
m = iterate(3, axiom, rules)
poonjab = Lturtle()
poonjab.chomp(m)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment