Howdy, Stranger!

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

Spirograph

edited January 2012 in Code Sharing Posts: 118

Wrote this small Spirograph program after I got frustrated with the real thing.

-- Use this function to perform your initial setup
function setup()
    print("Pinch to Zoom the view")
    print("Change Commit to 1 to make it permanent")
    touches = {}
    lastPinchDist = 0
    pinchDelta = 1.0
    pinchCenter = vec2(0,0)
    offset = vec2(0,0)
    zoom = 1
    parameter("step",1,10,5)
    parameter("r1",10,400,150)
    parameter("r2",10,400,50)
    iparameter("wheel",1,8,7)
    iparameter("rot",1,50,10)
    iparameter("R",0,255,0)
    iparameter("G",0,255,255)
    iparameter("B",0,255,0)
    iparameter("Commit",0,1,0)
    img=image(WIDTH,HEIGHT)
    spriteMode(CORNER)
    done=0
end

function drawSpirograph()
    --setContext(img)
    noSmooth()
    stroke(R,G,B, 255)
    strokeWidth(2)
    lineCapMode(PROJECT)
    if wheel==1 then
        nr=25
    elseif wheel==2 then
        nr=32
    elseif wheel==3 then
        nr=45
    elseif wheel==4 then
        nr=52
    elseif wheel==5 then
        nr=60
    elseif wheel==6 then
        nr=21
    elseif wheel==7 then
        nr=75
    elseif wheel==8 then
        nr=84
    end
    local x1,y1=WIDTH/2+r1+r2,HEIGHT/2
    for ang=0,360*rot,step do
        local x2,y2=WIDTH/2+r1*math.cos(ang*math.pi/90.0)+
                r2*math.cos((-ang*105.0/nr)*math.pi/90.0),
                HEIGHT/2+r1*math.sin(ang*math.pi/90.0)+
                r2*math.sin((-ang*105.0/nr)*math.pi/90.0)
        line(x1,y1,x2,y2)
        x1,y1=x2,y2
    end
    --setContext()
end

function touched(touch)
    if touch.state == ENDED then
        touches[touch.id] = nil
    else
        touches[touch.id] = touch
    end
end

function processTouches()
    touchArr = {}
    for k,touch in pairs(touches) do
        -- push touches into array
        table.insert(touchArr,touch)
    end

    if #touchArr == 2 then
        t1 = vec2(touchArr[1].x,touchArr[1].y)
        t2 = vec2(touchArr[2].x,touchArr[2].y)

        dist = t1:dist(t2)
        if lastPinchDist > 0 then 
            pinchDelta = dist/lastPinchDist
            
        else
            offset= offset + ((t1 + t2)/2-pinchCenter)/zoom
        end
        pinchCenter = (t1 + t2)/2
        lastPinchDist = dist
    else
        pinchDelta = 1.0
        lastPinchDist = 0
    end
end

function draw()
    
    -- This sets the background color to black
    background(0, 0, 0)
    sprite(img,0,0)
    if (Commit==1) then
        setContext(img)
    end
    -- compute pinch delta
    processTouches()
    -- scale by pinch delta
    zoom = math.max( zoom*pinchDelta, 0.2)

    translate(pinchCenter.x-offset.x*zoom,pinchCenter.y-offset.y*zoom)
    
    scale(zoom,zoom)
    
    --translate(pinchCenter.x,pinchCenter.y)

    pinchDelta = 1.0

    
    drawSpirograph()
    --sprite(img,WIDTH/2,HEIGHT/2)
    if (Commit==1) then
        setContext()
        Commit=0
    end
end
Tagged:

Comments

  • Posts: 118

    I noticed (when checking for characters that need to be escaped) the selecting the code above for copy and paste, that the selection stops before the ' #' character. Anyone knows how this can be avoided?

  • JohnJohn Admin Mod
    Posts: 629

    Seems to be detected as markup by the forum. I would try using --- before and after code (replace - with ~) for code blocks.

  • Posts: 118

    @John Indeed! I changed it now. Thanks!

  • Posts: 118

    Updated version using my Zoom library.

    -- Spirograph
    -- Herwig Van Marck
    
    function setup()
        print("Play with parameters to change the Spirograph\nSet commit to 1 to fix it\n"..
            "Change parameters again to add another one on top\n")
        zoom=Zoom(0,0)
        parameter("step",1,10,5)
        parameter("r1",10,400,150)
        parameter("r2",10,400,50)
        iparameter("wheel",1,8,7)
        iparameter("rot",1,50,10)
        iparameter("R",0,255,0)
        iparameter("G",0,255,255)
        iparameter("B",0,255,0)
        iparameter("Commit",0,1,0)
        img=image(WIDTH,HEIGHT)
        spriteMode(CORNER)
        done=0
    end
    
    function drawSpirograph()
        --setContext(img)
        noSmooth()
        stroke(R,G,B, 255)
        strokeWidth(2)
        lineCapMode(PROJECT)
        if wheel==1 then
            nr=25
        elseif wheel==2 then
            nr=32
        elseif wheel==3 then
            nr=45
        elseif wheel==4 then
            nr=52
        elseif wheel==5 then
            nr=60
        elseif wheel==6 then
            nr=21
        elseif wheel==7 then
            nr=75
        elseif wheel==8 then
            nr=84
        end
        local x1,y1=WIDTH/2+r1+r2,HEIGHT/2
        for ang=0,360*rot,step do
            local x2,y2=WIDTH/2+r1*math.cos(ang*math.pi/90.0)+
                    r2*math.cos((-ang*105.0/nr)*math.pi/90.0),
                    HEIGHT/2+r1*math.sin(ang*math.pi/90.0)+
                    r2*math.sin((-ang*105.0/nr)*math.pi/90.0)
            line(x1,y1,x2,y2)
            x1,y1=x2,y2
        end
        --setContext()
    end
    
    function touched(touch)
        zoom:touched(touch)
    end
    
    function draw()
        zoom:draw()
        -- This sets the background color to black
        background(0, 0, 0)
        sprite(img,0,0)
        if (Commit==1) then
            zoom:clear()
            resetMatrix()
            zoom:draw()
            setContext(img)
        end
    
        drawSpirograph()
        --sprite(img,WIDTH/2,HEIGHT/2)
        if (Commit==1) then
            setContext()
            Commit=0
        end
    end
    
    -- Zoom library
    -- 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")
    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
    
    
Sign In or Register to comment.