from pykludge3d import * from lsystem import * """ Note: I use the term 'face' a lot in this file. In this situation, 'face' is a synonym for 'polygon'. I use 'face' instead of 'polygon' because, when I say 'face', I'm also referring to the L-system action/symbol involving polygons. L-system action symbols: S scale the face M move the face along the face's normal E[...] extrude the face and branch the L-system. Each item in the comma-separated list between the brackets is a branch. The first branch is the branch for the original face (ie the face that, following the extrude, is facing in the same direction as the face that was extruded). The subsequent branches are for the N other faces resulting from the extrude. You do not need to specify an action for all N+1 of the branches; use 'T' for branches you don't care about. If there are more items in the list than faces resulting from the extrude, the extra items are ignored. If there are fewer items in the list than faces resulting from the extrude, the extra faces will not be acted on (the same as if 'T' were specified). After the extrude action itself has been performed, the branches will be executed in a depth-first manner, starting with the first branch (the one corresponding to the original face). Action symbols following the E and its braces will be executed after all symbols in the E have been acted upon. Note that the brackets are optional. If you do not wish to manipulate the new faces resulting from an extrude, simply use E by itself. T terminal. A no-op; no action is performed on the face. 0-9 digits are ignored """ def scale_face( currentFace, depth ): scaleFactor = 0.75 scale_verts( get_verts_in_polys( [currentFace] ), scaleFactor, scaleFactor, scaleFactor ) def move_face( currentFace, depth ): moveFactor = 1.0 normal = get_poly_normal( currentFace, None ) #print normal translate_verts( get_verts_in_polys( [currentFace] ), normal[0] * moveFactor, normal[1] * moveFactor, normal[2] * moveFactor ) def extrude_face( currentFace, depth ): return polys_extrude( [currentFace], 0 ) def get_bracketed_substring( string, startIndex ): if string[startIndex] != '[': return '' rbcount = 0 # right-bracket count i = startIndex+1 while rbcount != 1 and i < len(string): if string[i] == '[': rbcount -= 1 if string[i] == ']': rbcount += 1 i += 1 if rbcount != 1: return '' return string[startIndex+1 : i-1] # end get_bracketed_substring def interpret_branches( faces, branchString, depth ): i = 0 faceNum = 0 while i < len( branchString ): temp = '' while i < len( branchString ) and branchString[i] != ',': if branchString[i] == '[': temp += branchString[i] i += 1 # we want to skip over everything between the braces. # advance i until matching bracket is found rbcount = 0 # right-bracket count while rbcount != 1 and i < len(branchString): if branchString[i] == '[': rbcount -= 1 if branchString[i] == ']': rbcount += 1 temp += branchString[i] i += 1 else: temp += branchString[i] i += 1 if i < len( branchString ) and branchString[i] == ',': i += 1 #print '\t'*depth, 'temp is ', temp #print '\t'*depth, 'i is ', i interpret_action( temp, faces[faceNum], depth+1 ) faceNum += 1 # end interpret_branches def interpret_action( actionString, currentFace, depth=1 ): i = 0 while i < len(actionString): action = actionString[i] if action == 'T' or action.isdigit() or action.isspace(): print 'terminal/no-op' elif action == 'S': scale_face( currentFace, depth ) elif action == 'M': move_face( currentFace, depth ) elif action == 'E': # extrude faces = extrude_face( currentFace, depth ) # follow the branches branchString = get_bracketed_substring( actionString, i+1 ) interpret_branches( faces, branchString, depth ) elif action == '[': # we want to skip over everything between the braces. # advance i until matching bracket is found rbcount = 0 # right-bracket count while rbcount != 1 and i < len(actionString): if actionString[i] == '[': rbcount -= 1 if actionString[i] == ']': rbcount += 1 i += 1 else: print 'Unknown action', action i += 1 # end interpret_action def run_lsystem( axiom = '0', rules = [('0', 'EM0')], generations = 5 ): '''Runs an L-system (Lindenmeyer system), using the given initial string (the axiom) and the set of rules for string-substitution. Once the L-system has been run for the specified number of generations, the resulting string will be interpreted (see below). How to pass rules into the L-system: The 'rules' list is a list of tuples, each tuple being a rule for string substitution. Each rule tuple has two parts, a single character to look for, and a string to replace the character with. Here's an example: ('0', 'EM0') This rule means that every time '0' is encountered, it is replaced with the string 'EM0'. If our initial string is '0', and we apply this rule for, say, 5 generations, we end up with the following progression: 0 -> EM0 -> EMEM0 -> EMEMEM0 -> EMEMEMEM0 -> EMEMEMEMEM0 How the result strings are interpreted: A complete description of the symbols can be found in the doc string for this module, but here is a brief summary: S scale the face M move the face along the face's normal E[...] extrude the face and branch the L-system (definitely see the doc string for more info) T ignored 0-9 ignored (used to represent faces at the string-substitution stage, useless once string-substitution is complete) ''' polys = get_selected_polys() if len( polys ) < 1: print 'At least one polygon must be selected' return system = LSystem( axiom, rules ) while not system.done and system.generation < generations: system.step() interpret_action( system.string, polys[0] ) # end run_lsystem