Function plotter

It’s my first Codea program. You can zoom and pan with your fingers. The grid can be deactivated. You can write your own functions in “function fn(x)”.


function fn(x)
    return math.sin(x*2) + math.sin(x)
end

function setup()
    center=vec2(WIDTH/2,HEIGHT/2)
    pos=vec2(0,0)
    size=100
    touches = {}
    lineCapMode(2)
    --noSmooth()
    iparameter("Grid",0,1,1)
    --watch("myW")
end

function draw()
    local fnI, prevI, prevFnI, move, dist

    left=fromScreen(vec2(0,0))
    right=fromScreen(vec2(WIDTH,0))
    top=fromScreen(vec2(0,HEIGHT))
    bottom=fromScreen(vec2(0,0))

    background(0, 0, 0, 255)
    
    drawAxis()
        
    --draw function
    stroke(101, 239, 18, 255)
    strokeWidth(4)
    prevI = nil
    for i = left.x, right.x, (right.x-left.x)/700 do
        fnI = fn(i)
        if (prevI~=nil) then myLine(vec2(i,fnI),vec2(prevI,prevFnI)) end
        prevI = i
        prevFnI = fnI
    end
    
    --zooming and moving
    n = nbTouches()
    if(n==1) then
        move = vec2(CurrentTouch.prevX-CurrentTouch.x,CurrentTouch.prevY-CurrentTouch.y)
        pos = pos - move/size
        zooming=false
    elseif(n==2) then
        if (zooming==true) then
            size=size0*distanceBetweenFingers()/dist0
            move = vec2(CurrentTouch.prevX-CurrentTouch.x,CurrentTouch.prevY-CurrentTouch.y)
            pos = pos - move/size
        else
            zooming=true
            dist0=distanceBetweenFingers()
            size0=size
        end
    else
        zooming=false    
    end
end

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

function nbTouches()
    local n
    n=0
    for i,j in pairs(touches) do
        n = n + 1
    end
    return n
end

function distanceBetweenFingers()
    local v, sign
    v=vec2(0,0)
    sign=1
    for i,j in pairs(touches) do
        v=v+vec2(j.x,j.y)*sign
        sign=-1
    end
    return v:len()
end

function toScreen(v)
    return center + (v + pos) * size
end

function fromScreen(v)
    return (v - center) / size - pos
end

function myLine(va,vb)
    local v1,v2
    v1 = toScreen(va)
    v2 = toScreen(vb)
    line(v1.x,v1.y,v2.x,v2.y)
end

function drawAxis()
    local v,i
    stroke(38, 0, 255, 255)
    strokeWidth(4)

    i=fromScreen(vec2(60,0)).x - fromScreen(vec2(0,0)).x
    i=nearestInterval(i)
    
    for x=math.floor(left.x/i)*i,right.x,i do
        v=toScreen(vec2(x,0))
        gridVerLine(v.x)
        line(v.x,v.y+5,v.x,v.y-5)
        text(x,v.x-15,v.y-10)
    end
    for y=math.floor(bottom.y/i)*i,top.y,i do
        v=toScreen(vec2(0,y))
        gridHorLine(v.y)
        line(v.x+5,v.y,v.x-5,v.y)
        text(y,v.x-15,v.y-10)
    end
    stroke(38, 0, 255, 255)
    strokeWidth(4)
    myLine(vec2(-1000000,0),vec2(1000000,0))
    myLine(vec2(0,-1000000),vec2(0,1000000))
end

function gridVerLine(x)
    if (Grid == 0) then return end
    pushStyle()
    stroke(92, 87, 99, 255)
    line(x,0,x,HEIGHT)
    popStyle()
end

function gridHorLine(y)
    if (Grid == 0) then return end
    pushStyle()
    stroke(92, 87, 99, 255)
    line(0,y,WIDTH,y)
    popStyle()
end

function nearestInterval(n)
    local i1, i2, i3
    i=1
    i2=2.5
    i3=5
    
    while true do
        if(n>i and n<i*10)then break
        elseif(n<i) then i=i/10
        else i=i*10
        end
    end
    if (n>i and n<i2*i) then return(i)
    elseif (n>i2*i and n<i3*i) then return(i2*i)
    else return(i3*i)
    end
end

BTW, how can I insert images in my posts?

I have a problem with my program. When I print the labels of the axis in intervals of 0.1 the maths of Codea don’t seem to work well. Look at this code:

    i=0.1
    x=-1
    for n=1,11 do
        x = x + i
        print(x)
    end

It should print:
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.1
0
0.1

Instead it prints:
-0.9
-0.8
-0.7
-0.6
-0.5
-0.4
-0.3
-0.2
-0.0999999
7.45058e-08
0.1

Any ideas?

Good work, nice Tool you made!

Your problem could have st. to do with the internal number type? Maybe theres a rounding function to solve this? Does’nt look like you’ve done something wrong…

Nice work, pepinganos. Thanks for sharing. I learn a lot from people like you posting code.

@pepinganos that’s one of the problems with floating point number representations. The binary form of 0.1 in floating point is an infinitely repeating sequence — so it gets rounded to the nearest decimal representation, which can become 0.0999999 due to rounding errors through multiple additions. (It’s not specific to Codea, it’s just how 32bit floating point works on most CPUs.)

Thank you for your answers. I’ve tried the same loop with these values with much worse errors when the x aproches zero:

    i=0.1
    x=-4
    for n=1,42 do
        x = x + i
        print(x)
    end

How can I include videos and pictures in posts?