Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

L-System drawing

edited February 2012 in Code Sharing Posts: 118

L-System drawing program.

-- L-System
-- Herwig Van Marck

function setup()
    print("L-System\nWhile title is red the next level is calculated.")
    print("Change timeStep to slow down or speed up time to next level.")
    print("Double tap to restart")
    iparameter("timeStep",0,30,10)
    iparameter("example",1,9,9)
    time=0
    curExample=example
    lsys=initExample(curExample)
    zoom=Zoom(WIDTH/2,HEIGHT/2)
    strokeWidth(2)
    noSmooth()
end

function touched(touch)
    if (touch.state==BEGAN and touch.tapCount==2) then
        lsys=initExample(curExample)
        zoom:touched(touch)
    else
        zoom:touched(touch)
    end
end

function draw()
    if example~=curExample then
        curExample=example
        lsys=initExample(curExample)
        zoom:clear()
    end
    if (time>=600) then
        time=0
        if (lsys.level<lsys.maxlevel) then
            lsys:transform()
        end
    else
        time = time + timeStep
    end
    background(0, 0, 0, 255)
    lsys:drawTitle()
    zoom:draw()
    lsys:draw()
end

function initExample()
    if (example==1) then
        return LSystem("Plant",40,"NSL",
        {
            A=Step(Step.LINE,500),
            B=Step(Step.LINE,100),
            C=Step(Step.LINE,200),
            D=Step(Step.LINE,300),
            E=Step(Step.LINE,400),
            L=Step(Step.LINE,200),
            P=Step(Step.ROT,25),
            M=Step(Step.ROT,-29),
            U=Step(Step.PUSH),
            O=Step(Step.POP),
            N=Step(Step.TRANS,-250,0),
            S=Step(Step.SCALE,0.875)
        },
        {
            Rule("AB","AC"),
            Rule("AC","AD"),
            Rule("AD","AE"),
            Rule("AE","AA"),
            Rule("A","AB"),
            Rule("BL","CL"),
            Rule("CL","DL"),
            Rule("DL","EL"),
            Rule("L","BL"),
            Rule("EL","AUPLOML"),
            Rule("NS","NSS")
        })
    elseif example==2 then
        return LSystem("Dragon",14,"NABFX",
        {
            A=Step(Step.ROT,-45),
            B=Step(Step.SCALE,0.75),
            N=Step(Step.TRANS,-50,50),
            F=Step(Step.LINE,200),
            X=Step(Step.NOP),
            Y=Step(Step.NOP),
            P=Step(Step.ROT,90),
            M=Step(Step.ROT,-90)
        },
        {
            Rule("X","XPYF"),
            Rule("Y","FXMY"),
            Rule("NAB","NABAB")
        })
    elseif example==3 then
        return LSystem("Cantor Dust",8,"NSA",
        {
            N=Step(Step.TRANS,-250,0),
            A=Step(Step.LINE,1500),
            B=Step(Step.TRANS,1500,0),
            S=Step(Step.SCALE,1/3.0)
        },
        {
            Rule("NS","NSS"),
            Rule("A","ABA"),
            Rule("B","BBB")
        }
        )
    elseif example==4 then
        return LSystem("Koch curve",7,"NSA",
        {
            N=Step(Step.TRANS,-300,0),
            S=Step(Step.SCALE,1/3.0),
            A=Step(Step.LINE,1500),
            P=Step(Step.ROT,60),
            M=Step(Step.ROT,-120)
        },
        {
            Rule("NS","NSS"),
            Rule("A","APAMAPA")
        }
        )
    elseif example==5 then
        return LSystem("Right angle Koch curve",6,"NSA",
        {
            N=Step(Step.TRANS,-300,0),
            S=Step(Step.SCALE,1/3.0),
            A=Step(Step.LINE,1500),
            P=Step(Step.ROT,90),
            M=Step(Step.ROT,-90)
        },
        {
            Rule("NS","NSS"),
            Rule("A","APAMAMAPA")
        }
        )
    elseif example==6 then
        return LSystem("Sierpinsky Triangle",9,"NSQA",
        {
            N=Step(Step.TRANS,-200,-200),
            S=Step(Step.SCALE,0.5),
            Q=Step(Step.NOP),
            R=Step(Step.ROT,60),
            A=Step(Step.LINE,800),
            B=Step(Step.LINE,800),
            P=Step(Step.ROT,60),
            M=Step(Step.ROT,-60)
        },
        {
            Rule("NS","NSS"),
            Rule("A","BMAMB"),
            Rule("B","APBPA"),
            Rule("Q","R"),
            Rule("R","Q")
        }
        )
    elseif example==7 then
        return LSystem("Fractal Plant",7,"NSX",
        {
            N=Step(Step.TRANS,-300,0),
            S=Step(Step.SCALE,0.5),
            X=Step(Step.NOP),
            F=Step(Step.LINE,500),
            M=Step(Step.ROT,-25),
            P=Step(Step.ROT,25),
            U=Step(Step.PUSH),
            O=Step(Step.POP)
            
        },
        {
            Rule("NS","NSS"),
            Rule("X","FMUUXOPXOPFUPFXOMX"),
            Rule("F","FF")
        }
        )
    elseif example==8 then
        return LSystem("Hilbert curve",7,"NSA",
        {
            N=Step(Step.TRANS,-200,-200),
            Q=Step(Step.TRANS,-100,-100),
            S=Step(Step.SCALE,0.5),
            A=Step(Step.NOP),
            B=Step(Step.NOP),
            M=Step(Step.ROT,-90),
            P=Step(Step.ROT,90),
            F=Step(Step.LINE,800)
        },
        {
            Rule("NS","QSNS"),
            Rule("A","PBFMAFAMFBP"),
            Rule("B","MAFPBFBPFAM")
        }
        )
    elseif example==9 then
        return LSystem("Penrose Tiling",6,"NSUBOPPUBOPPUBOPPUBOPPUBO",
        {
            N=Step(Step.NOP),
            S=Step(Step.SCALE,2.0/3.0),
            A=Step(Step.NOP),
            B=Step(Step.NOP),
            C=Step(Step.NOP),
            D=Step(Step.NOP),
            F=Step(Step.LINE,200),
            U=Step(Step.PUSH),
            O=Step(Step.POP),
            M=Step(Step.ROT,-36),
            P=Step(Step.ROT,36)
        },
        {
            Rule("NS","NSS"),
            Rule("A","CFPPDFMMMMBFUMCFMMMMAFOPP"),
            Rule("B","PCFMMDFUMMMAFMMBFOP"),
            Rule("C","MAFPPBFUPPPCFPPDFOM"),
            Rule("D","MMCFPPPPAFUPDFPPPPBFOMMBF"),
            Rule("F",""),
            Rule("PPPMMM",""),
            Rule("MMMPPP",""),
            Rule("PPMM",""),
            Rule("MMPP",""),
            Rule("PM",""),
            Rule("MP","")
        }
        )
    else -- placeholder to copy and paste from
        return LSystem("",1,"N",
        {
            N=Step(Step.NOP)
        },
        {
            Rule("N","N")
        }
        )
    end
end

Comments

  • Posts: 118

    L-System class

    LSystem = class()
    
    function LSystem:init(name,maxlevel,start,steps,rules)
        self.name = name
        self.maxlevel = maxlevel
        self.level = 1
        self.str = start
        self.steps = steps
        self.rules = rules
        self:updateCount()
    end
    
    function LSystem:drawTitle()
        textMode(CENTER)
        font("ArialRoundedMTBold")
        fontSize(50)
        if self.level<self.maxlevel then
            fill(255, 0, 0, 255)
        else
            fill(0, 1, 255, 255)
        end
        text(self.name.." ("..self.level..")",WIDTH/2,HEIGHT -75)
    end
    
    function LSystem:draw()
        local cnt=0
        for i=1,string.len(self.str) do
            stroke(255*(1-cnt/self.count),0,255*cnt/self.count,255)
            local step=self.steps[string.sub(self.str,i,i)]
            step:draw()
            if (step.type==Step.LINE) then
                cnt = cnt + 1
            end
        end
    end
    
    function LSystem:updateCount()
        local cnt=0
        for k=1,#self.str do
            if self.steps[string.sub(self.str,k,k)].type==Step.LINE then
                cnt = cnt + 1
            end
        end
        self.count=cnt
    end
    
    function LSystem:transform()
        local i=1
        local res=""
        local cnt=0
        while (i<=string.len(self.str)) do
            local flg=true
            for j=1,#self.rules do
                local stri=self.rules[j].stri
                local stro=self.rules[j].stro
                if (string.sub(self.str,i,i+string.len(stri)-1)==stri) then
                    i = i + string.len(stri)
                    res = res .. stro
                    flg=false
                    break
                end
            end
            if flg then
                res = res .. string.sub(self.str,i,i)
                i = i + 1
            end
        end
        --print(string.len(res))
        self.str=res
        self.level = self.level + 1
        self:updateCount()
    end
    
    Rule = class()
    
    function Rule:init(stri,stro)
        self.stri = stri
        self.stro = stro
    end
    
    Step = class()
    
    Step.NOP=0
    Step.TRANS=1
    Step.ROT=2
    Step.PUSH=3
    Step.POP=4
    Step.SCALE=5
    
    function Step:init(type,val,val2)
        self.type = type
        self.val = val
        self.val2 = val2
    end
    
    function Step:draw()
        -- Codea does not automatically call this method
        if (self.type==Step.TRANS) then
            translate(self.val,self.val2)
        elseif (self.type==Step.LINE) then
            line(0,0,self.val,0)
            translate(self.val,0)
        elseif (self.type==Step.ROT) then
            rotate(self.val)
        elseif (self.type==Step.PUSH) then
            pushMatrix()
        elseif (self.type==Step.POP) then
            popMatrix()
        elseif (self.type==Step.SCALE) then
            scale(self.val)
        end
    end
    
    
  • Posts: 118

    Zoom class

    -- Zoom library v1.1
    -- Herwig Van Marck
    -- usage:
    --[[
    function setup()
        zoom=Zoom(WIDTH/2,HEIGHT/2)
    end
    function touched(touch)
        zoom:touched(touch)
    end
    function draw()
        zoom:draw()
    end
    ]]--
    
    Zoom = class()
    
    function Zoom:init(x,y)
        -- you can accept and set parameters here
        self.touches = {}
        self.initx=x or 0;
        self.inity=y or 0;
        self:clear()
        print("Tap and drag to move\nPinch to zoom\nDouble tap to reset zoom")
    end
    
    function Zoom:clear()
        self.lastPinchDist = 0
        self.pinchDelta = 1.0
        self.center = vec2(self.initx,self.inity)
        self.offset = vec2(0,0)
        self.zoom = 1
        self.started = false
        self.started2 = false
    end
    
    function Zoom:touched(touch)
        -- Codea does not automatically call this method
        if touch.state == ENDED then
            self.touches[touch.id] = nil
        else
            self.touches[touch.id] = touch
            if (touch.tapCount==2) then
                self:clear()
            end
        end
    end
    
    function Zoom:processTouches()
        local touchArr = {}
        for k,touch in pairs(self.touches) do
            -- push touches into array
            table.insert(touchArr,touch)
        end
    
        if #touchArr == 2 then
            self.started = false
            local t1 = vec2(touchArr[1].x,touchArr[1].y)
            local t2 = vec2(touchArr[2].x,touchArr[2].y)
    
            local dist = t1:dist(t2)
            if self.started2 then
            --if self.lastPinchDist > 0 then 
                self.pinchDelta = dist/self.lastPinchDist          
            else
                self.offset= self.offset + ((t1 + t2)/2-self.center)/self.zoom
                self.started2 = true
            end
            self.center = (t1 + t2)/2
            self.lastPinchDist = dist
        elseif (#touchArr == 1) then
            self.started2 = false
            local t1 = vec2(touchArr[1].x,touchArr[1].y)
            self.pinchDelta = 1.0
            self.lastPinchDist = 0
            if not(self.started) then
                self.offset = self.offset + (t1-self.center)/self.zoom
                self.started = true
            end
            self.center=t1
        else
            self.pinchDelta = 1.0
            self.lastPinchDist = 0
            self.started = false
            self.started2 = false
        end
    end
    
    function Zoom:clip(x,y,w,h)
        clip(x*self.zoom+self.center.x- self.offset.x*self.zoom,
            y*self.zoom+self.center.y- self.offset.y*self.zoom,
            w*self.zoom+1,h*self.zoom+1)
    end
    
    function Zoom:text(str,x,y)
        local fSz = fontSize()
        local xt=x*self.zoom+self.center.x- self.offset.x*self.zoom
        local yt=y*self.zoom+self.center.y- self.offset.y*self.zoom
        fontSize(fSz*self.zoom)
        local xtsz,ytsz=textSize(str)
        tsz=xtsz
        if tsz<ytsz then tsz=ytsz end
        if (tsz>2048) then
            local eZoom= tsz/2048.0
            fontSize(fSz*self.zoom/eZoom)
            pushMatrix()
            resetMatrix()
            translate(xt,yt)
            scale(eZoom)
            text(str,0,0)
            popMatrix()
            fontSize(fSz)
        else
            pushMatrix()
            resetMatrix()
            fontSize(fSz*self.zoom)
            text(str,xt,yt)
            popMatrix()
            fontSize(fSz)
        end
    end
    
    function Zoom:draw()
        -- compute pinch delta
        self:processTouches()
        -- scale by pinch delta
        self.zoom = math.max( self.zoom*self.pinchDelta, 0.2 )
    
        translate(self.center.x- self.offset.x*self.zoom,
            self.center.y- self.offset.y*self.zoom)
        
        scale(self.zoom,self.zoom)
    
        self.pinchDelta = 1.0
    end
    
    function Zoom:getWorldPoint(pt)
        return vec2(self.offset.x-(self.center.x- pt.x)/self.zoom,
            self.offset.y-(self.center.y- pt.y)/self.zoom)
    end
    
    function Zoom:getLocalPoint(pt)
        return vec2(pt.x*self.zoom+self.center.x- self.offset.x*self.zoom,
            pt.y*self.zoom+self.center.y- self.offset.y*self.zoom)
    end
    
  • Posts: 20

    Very cool. Amazing what some simple rules can end up doing with this type of system. Wasn't even aware of L-systems, after reading through the wikipedia article and looking at your code Ive got a lot better understanding.

  • Posts: 2,820

    Awsome

  • @Herwig: do you have a good source for Lindenmayer alike "functions", means axioms and rules? I wrote my own set of functions, but slowly running out of examples ...

  • Posts: 118

    @CrazyEd I took most of my examples from http://www.nahee.com/spanky/www/fractint/lsys/tutor.html

    To update the examples first change the parameter line in the setup() with

    iparameter("example",1,15,15)
    

    and update the initExample function with


        elseif example==10 then         return LSystem("Triangular Grid",7,"NSX",         {             N=Step(Step.TRANS,-300,0),             S=Step(Step.SCALE,0.5),             X=Step(Step.NOP),             Y=Step(Step.NOP),             F=Step(Step.LINE,1200),             M=Step(Step.ROT,-60),             P=Step(Step.ROT,60),             U=Step(Step.PUSH),             O=Step(Step.POP)         },         {             Rule("NS","NSS"),             Rule("X","FYUPFYOUMMFYOFY"),             Rule("Y","FXUPPFXOUMFXOFX"),             Rule("F","")         }         )     elseif example==11 then         return LSystem("Hexagonal",7,"NSF",         {             N=Step(Step.TRANS,-150,0),             S=Step(Step.SCALE,0.5),             F=Step(Step.LINE,600),             G=Step(Step.TRANS,1200,0),             M=Step(Step.ROT,-60),             P=Step(Step.ROT,60),             U=Step(Step.PUSH),             O=Step(Step.POP)         },         {             Rule("NS","NSS"),             Rule("F","UMFPFOGPUPFPFOM"),             Rule("G","GG")         }         )     elseif example==12 then         return LSystem("Terdragon",9,"NSF",         {             N=Step(Step.TRANS,-250,0),             S=Step(Step.SCALE,0.577735),             R=Step(Step.ROT,-30),             F=Step(Step.LINE,800),             M=Step(Step.ROT,-120),             P=Step(Step.ROT,120)         },         {             Rule("NS","NSRS"),             Rule("F","FPFMF")         }         )     elseif example==13 then         return LSystem("Cross",6,"NSFX",         {             N=Step(Step.TRANS,-170,0),             S=Step(Step.SCALE,0.425),             R=Step(Step.ROT,-117),             X=Step(Step.NOP),             Y=Step(Step.NOP),             F=Step(Step.LINE,1100),             M=Step(Step.ROT,-90),             P=Step(Step.ROT,90)         },         {             Rule("NS","NSRS"),             Rule("X","FXPFXPFXFYMFYM"),             Rule("Y","PFXPFXFYMFYMFY"),             Rule("F","")         }         )     elseif example==14 then         return LSystem("Pentigree",5,"NSFMFMFMFMF",         {             N=Step(Step.TRANS,-100,100),             S=Step(Step.SCALE,0.37),             R=Step(Step.ROT,-36),             F=Step(Step.LINE,800),             M=Step(Step.ROT,-72),             P=Step(Step.ROT,72)         },         {             Rule("NS","NSRS"),             Rule("F","FMFPPFPFMFMF")         }         )     elseif example==15 then         return LSystem("XmasTree",9,"NSPPA",         {             N=Step(Step.TRANS,-100,-200),             S=Step(Step.SCALE,0.6),             R=Step(Step.ROT,0),             F=Step(Step.LINE,800),             A=Step(Step.NOP),             B=Step(Step.NOP),             C=Step(Step.NOP),             D=Step(Step.NOP),             E=Step(Step.NOP),             G=Step(Step.NOP),             M=Step(Step.ROT,-36),             P=Step(Step.ROT,36)         },         {             Rule("NS","NSRS"),             Rule("A","MMFCPPPPFDMMFG"),             Rule("B","FEPPFCMMMMFDPP"),             Rule("C","PPFAMMMMFBPPFE"),             Rule("D","FGMMFAPPPPFBMM"),             Rule("E","PFGMMFAP"),             Rule("G","MFBPPFEM"),             Rule("F","")         }         )    
Sign In or Register to comment.