1. NodeBox 1
    1. Homepage
    2. NodeBox 3Node-based app for generative design and data visualization
    3. NodeBox OpenGLHardware-accelerated cross-platform graphics library
    4. NodeBox 1Generate 2D visuals using Python code (Mac OS X only)
  2. Gallery
  3. Documentation
  4. Forum
  5. Blog

Penrose Tiling

Posted by Mark M on Feb 23, 2008



This is a short script to generate the non-periodic penrose tiling. As mentioned under the L-system posting a while back this can be produced by means of a well-known l-system recipe. The L-system works beautifully but it is very difficult to see how it works. This script uses a contraction method of starting with one half of one of the tiles and recursively breaking it down into smaller units. One of the goals was to show the intense relationship between the tiling and the golden ratio and also to see if it could be done using nothing except Nodebox's transformations. Enjoy:

from math import sqrt
stroke(.9)
strokewidth(.35)
translate(-9, 466)
transform(CORNER)
colormode(HSB)
 
### Golden Ratio
phi = 1.61803399
sqrt2_phi = sqrt(2 + phi)
 
class thinRhomb():
    def __init__(self,l, type, draw=True):
        self.length = l
        self.type = type
        if draw:
            self.draw()
    def draw(self):
        fill(self.type/3.0+.25, .3, self.type/3.0+.5)
        l = self.length
        beginpath(0,0)
        lineto(sqrt2_phi/2 * l, l/(2*phi))
        lineto(sqrt2_phi*l,0)
        lineto(sqrt2_phi/2 * l, -l/(2*phi))
        return endpath()
    def contract(self, minLength, rule=None):
        L = self.length
        if L/phi < minLength:
            self.draw()
            return
        if self.type == 0:
            ## scale with negative number==reflection
            scale(x=1, y=-1)
        # One Thin Rhomb becomes one thick via rotation and one thin via rotation/translation
        push()
        rotate(-18)
        Rhomb = thickRhomb(L/phi, 0,  draw=False)
        Rhomb.contract(minLength)
        pop()
        push()
        translate(0,L/phi)
        rotate(108)
        translate(0,L)
        Rhomb = thinRhomb(L/phi, 1,  draw=False)
        Rhomb.contract(minLength)
        pop()
        
class thickRhomb():
    def __init__(self, l, type, draw=True):
        self.length = l
        self.type = type
        if draw:
            self.draw()
    def draw(self):
        fill((self.type+.6)/3.0, .25, (self.type+.3)/2.0)
        l = self.length
        beginpath(0,0)
        lineto(phi/2*l, -(phi-1)* sqrt2_phi/2*l)
        lineto(phi*l,0)
        lineto(phi/2*l, (phi-1)* sqrt2_phi/2*l)
        return endpath()
    def contract(self, minLength, rule=None):
        L = self.length
        if L/phi < minLength:
            self.draw()
            return
        if self.type == 1:
            scale(-1,1)
            translate(-L*phi,0)
        # One Thick Rhomb becomes one thick via translation and on thick via rotation/translation
        # one thin via translation/rotation
        push()
        translate(L/phi, 0)
        Rh = thickRhomb(L/phi,1, draw=False)
        Rh.contract(minLength)
        pop()
        push()
        rotate(216)
        translate(-L, -0)
        Rh = thickRhomb(L/phi, 0, draw=False)
        Rh.contract(minLength)
        pop()
        push()
        translate(L/phi, 0)
        rotate(54)
        Rh = thinRhomb(L/phi, 0,  draw=False)
        Rh.contract(minLength)
        pop()
        
 
initial_Length = 600
 
R = thickRhomb(initial_Length, 0, draw=False)
min_side_length = 20
R.contract(min_side_length)


 
Posted by Zach on Mar 21, 2008

Awesome!!



Posted by Leandro on Nov 29, 2008

Great, thank you! it's beautiful!



Posted by George on Oct 20, 2009

what is intended by the five "function calls" in lines 2 through 6?



Posted by Mark M on Oct 23, 2009

George, those are just basic nodebox functions to set up the state before it starts drawing. They are all described really well in the reference pages. The transform call is the only one that is critical because as the we rotate the tiles they need the corner transform or they'll all end up on top of each other. The others just move the canvas so the art is centered, set the stroke color and width so the tiles are outlined, etc.