Recently I've been looking at Povray, pyprocessing, and cfdg (version 3.0) as tools for creating digital images. I have branched two separate blogs where I mainly explore jruby + processing and processing.py

Thursday, 13 January 2011

Penrose Tiling using lsystems and processing.py

Get processing.py here.

"""
penrose.py is a python script for use in processing.py. 
It avoids switch, because python does not include it in the language, in my view this
is big mistake switch is very easy on the eye, I dislike chains of if/elif, however the 
alternatives in python are either dodgy or equally ugly
"""

import math

# some globals
XPOS = 0
YPOS = 1
ANGLE = 2
DELTA = math.pi/5

RULES = {
'F' : '',
'W' : 'YBF2+ZRF4-XBF[-YBF4-WRF]2+',
'X' : '+YBF2-ZRF[3-WRF2-XBF]+',
'Y' : '-WRF2+XBF[3+YBF2+ZRF]-',
'Z' : '2-YBF4+WRF[+ZRF4+XBF]2-XBF' 
}

AXIOM = '[X]2+[X]2+[X]2+[X]2+[X]'


def __produce(axiom, rules):
    """
    private single pass rule substitution
    """
    output = ""
    for i in axiom:
        output += rules.get(i, i)    # second i is returned when no dict key found
    return output
    
 
def repeat(rpx, axiom, rules):
    """
    Repeat rule substitution in a recursive fashion rpx times
    """ 
    production = axiom
    for i in range(0, rpx):
        production = __produce(production, rules)
    return production
    

def render(production):        # avoiding switch and globals
    """
    Render evaluates the production string and calls draw_line
    """
    turtle = [0, 0, -DELTA]
    stack = []
    repeat = 1
    for val in production:
        if val == "F": 
            turtle = __drawLine(turtle, 20)
        elif val == "+": 
            turtle[ANGLE] += DELTA * repeat
            repeat = 1
        elif val == "-": 
            turtle[ANGLE] -= DELTA * repeat
            repeat = 1
        elif val == "[": 
            temp = [turtle[XPOS], turtle[YPOS], turtle[ANGLE]]
            stack.append(temp)
        elif val == "]": 
            turtle = stack.pop() 
        elif ((val == '2') or (val == '3') or (val == '4')):
            repeat = int(val)     
        else: 
            pass


def __drawLine(turtle, length):
    """
    private line draw uses processing 'line' function to draw a line
    to a heading from the turtle with distance = length returns a new
    turtle corresponding to end of the new line
    """
    new_xpos = turtle[XPOS] + length * math.cos(turtle[ANGLE])
    new_ypos = turtle[YPOS] - length * math.sin(turtle[ANGLE])
    line(turtle[XPOS], turtle[YPOS], new_xpos, new_ypos)
    return [new_xpos, new_ypos, turtle[ANGLE]]     


def setup():
    """
    The processing setup statement
    """
    size(500, 500)
    background(255)
    smooth()
    production = repeat(5, AXIOM, RULES)
    translate(width/2, height/2)
    strokeWeight(2)
    render(production)


def draw():
    """
    An empty processing draw statement seems to be required to prevent premature exit()?
    """
    pass 
 
 

No comments:

Post a Comment

Followers

Blog Archive

About Me

My photo
Pembrokeshire, United Kingdom
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2