Howdy, Stranger!

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

How do you do zooming pinches?

in Questions Posts: 121
Pinching spreading is what I call zooming with two fingers in iOS

I’ve looked at jmv38’s sensor class and I think I understand it partially, but not entirely

When you have two touches. A zoom event occurs

When either touches moves, calculate a box between the two touches with width and height. Return those width and height values (in the example demo, jmv uses it to set the width and height of a rectangle)


But now I have my question. Go to safari on iOS, and pinch. And translate the touches of your fingers. The page moves along with them

What is going on?

Does it translate like a normal touch, or is there a different logic?

(To me it looks like it is translating like normal, one touch finger, but I’m not sure because of all the zooming in and out)

Comments

  • dave1707dave1707 Mod
    Posts: 7,058

    @xThomas When there’s 2 fingers on the screen and only one of them moves, you get a zoom. When both fingers move, you get a scroll. Also, if you touch the screen with one finger and move it up or down, the screen will scroll up or down but not side to side. If you touch the screen with one finger and move it side to side, the screen will scroll side to side but not up or down. You should be able to code that in Codea.

  • Posts: 419

    It is a different logic. Wirh two fingers, let a and b be their original places and c and d their current places. Then there is a unique combination of translation, rotation, and scaling that send a -> c and b -> d.

    It is given by the following:

    1. set b' = b-a and d' = d-c
    2. set b^ to be b' rotated by 90 and d^ similarly
    3. set B to be the 2x2 matrix [b', b^] and D similarly
    4. set A to be D B^{-1}, this has the property that Ab' = d'
    5. the transformation is then x |-> A(x-a) + c

    If you don't want rotation but only zoom and pan then the following is what to do. This keeps the centre of the touches fixed.

    1. set a# to be the average of a and b (so a# = (a+b)/2 ) and similarly c#
    2. let r be the distance between a and a#, and s between c and c#
    3. translate by - a#
    4. scale by s/r
    5. translate by c#
  • dave1707dave1707 Mod
    Posts: 7,058

    @xThomas Here a quick example of using one finger to move an image or using 2 fingers to move and/or zoom an image.

    displayMode(FULLSCREEN)
    
    function setup()
        img=readImage("Small World:Icon")
        size=img.width
        dx,dy=0,0
        fill(255)
        tab={}
    end
    
    function draw()
        background(0)
        sprite(img,WIDTH/2+dx,HEIGHT/2+dy,size)
    end
    
    function touched(t)
        if t.state==BEGAN then
            if #tab<2 then
                table.insert(tab,{id=t.id,x=t.x,y=t.y})
            end
            if #tab==2 then
                v1=vec2(tab[1].x,tab[1].y)
                startDist=v1:dist(vec2(tab[2].x,tab[2].y))
                startSize=size
            end
        elseif t.state==MOVING then
            for a,b in pairs(tab) do
                if b.id==t.id then
                    b.x=t.x
                    b.y=t.y
                end
            end
            if #tab==2 then
                v1=vec2(tab[1].x,tab[1].y)
                d=v1:dist(vec2(tab[2].x,tab[2].y))
                size=startSize*(d/startDist)
            end
            dx=dx+t.deltaX/#tab
            dy=dy+t.deltaY/#tab
        elseif t.state==ENDED then
            for a,b in pairs(tab) do
                if b.id==t.id then
                    table.remove(tab,a)
                end
            end
        end
    end
    
  • Posts: 121

    Ooh, nice.

    @LoopSpace I wasn’t able to get it working exactly, the scale logic works great but for translation i end up going with deltaXY (when i tried to implement translation earlier i couldnt get it to work)

    ill try rotation tomorrow

    for now here is the code i have
    (note that instead of a# c# i’d put ab or cd

    -- zoom pan
    
    -- Use this function to perform your initial setup
    function setup()
        print("Hello World!")
        trans=vec2(0,0)
        scalar=vec2(1,1)
    
    end
    
    -- This function gets called once every frame
    tick = 0
    function draw()
        -- This sets a dark background color 
        background(40, 40, 50)
    
        -- This sets the line thickness
        strokeWidth(5)
    
        -- Do your drawing here
        pushMatrix()
        scale(scalar.x,scalar.y)
        translate(trans.x,trans.y)
    
        sprite("Blocks:Brick Grey",0,0)
        popMatrix()
        textMode(CORNER)
        text(trans.x..','..trans.y, 50,700)
        text(scalar.x,50,650)
    
    
    end
    abtap = {}
    cdtap = {}
    -- prevtap = {}
    idtap = {}
    function began(t)
        if t.state == BEGAN then 
            local a,b = abtap.a,abtap.b
            if not a and not b then 
                -- print"creaate tap a"
                abtap.a = vec2(t.x,t.y)
                cdtap.c = vec2(t.x,t.y)
                -- prevtap.c = vec2(t.x,t.y)
                idtap.a = t.id
            elseif a and not b then 
                -- print"create tap b"
                abtap.b = vec2(t.x,t.y)
                cdtap.d = vec2(t.x,t.y)
                -- prevtap.d = vec2(t.x,t.y)
                idtap.b = t.id
            elseif b and not a then
                -- print"created tap à"
                abtap.a = vec2(t.x,t.y)
                cdtap.c = vec2(t.x,t.y)
                -- prevtap.c = vec2(t.x,t.y)
                idtap.a = t.id
            end
         end
    end
    
    
    function pan(t)
        if t.state == MOVING then
            local a,b = abtap.a,abtap.b
            if not (a and b) then return end
            local c,d = cdtap.c,cdtap.d
            if idtap.a==t.id then
                --abtap.a = vec2(t.prevX,t.prevY)
                -- prevtap.c = vec2(t.prevX,t.prevY)
                cdtap.c = vec2(t.x,t.y)
                dotap(t)
    
            elseif idtap.b==t.id then
                --abtap.b = vec2(t.prevX,t.prevY)
                -- prevtap.d = vec2(t.prevX,t.prevY)
                cdtap.d = vec2(t.x,t.y)
                dotap(t)
            end
        end
    
    end
    
    function dotap(t)
        local a,b = abtap.a,abtap.b
        local c,d = cdtap.c,cdtap.d
        -- local pc, pd = prevtap.c, prevtap.d
    
        local ab = (a+b)/2 --original touch center
        local cd = (c+d)/2 --current touch center
    
        --local pcd = (pc+pd)/2 --prev touch center
    
        local r = a:dist(ab)
        local s = c:dist(cd)
        local rs = s/r
        --trans = trans - ab
        --trans = trans - pcd
        scalar = vec2(rs,rs)
        --print(rs)
        --trans = trans * rs
        --trans = trans + vec2(cd.x,cd.y)
        --trans = trans + pcd
        trans = trans + vec2(t.deltaX,t.deltaY)
    end
    
    function touched(t)
        began(t)
        pan(t)
        ended(t)
    end
    
    function ended(t)
        if t.state == CANCELLED or t.state == ENDED then
            if idtap.a==t.id then
                -- print"delete tapp a"
                idtap.a = nil
                abtap.a = nil
                cdtap.c = nil
            elseif idtap.b==t.id then
                -- print"dellete tap b"
                idtap.b = nil
                abtap.b = nil
                cdtap.d = nil
            end
        end
    end
    
    
  • dave1707dave1707 Mod
    edited August 25 Posts: 7,058

    @xThomas I added rotation to my above code.

    displayMode(FULLSCREEN)
    
    function setup()
        img=readImage("Small World:Icon")
        size=img.width
        dx,dy=0,0
        tab={}
        calcAng,endAng=0,0
    end
    
    function draw()
        background(0)
        translate(WIDTH/2+dx,HEIGHT/2+dy)
        rotate(calcAng+endAng)  
        sprite(img,0,0,size)
    end
    
    function touched(t)
        if t.state==BEGAN then
            if #tab<2 then
                table.insert(tab,{id=t.id,x=t.x,y=t.y})
                if #tab==2 then
                    origAng=math.deg(math.atan((tab[2].y-tab[1].y),(tab[2].x-tab[1].x)))
                    startDist=vec2(tab[1].x,tab[1].y):dist(vec2(tab[2].x,tab[2].y))
                    startSize=size
                end
            end
        elseif t.state==MOVING then
            for a,b in pairs(tab) do
                if b.id==t.id then
                    b.x=t.x
                    b.y=t.y
                end
            end
            if #tab==2 then
                currAng=math.deg(math.atan((tab[2].y-tab[1].y),(tab[2].x-tab[1].x)))
                if currAng<0 then
                    currAng=currAng+360
                end
                calcAng=currAng-origAng
                d=vec2(tab[1].x,tab[1].y):dist(vec2(tab[2].x,tab[2].y))
                size=startSize*(d/startDist)
            end
            dx=dx+t.deltaX/#tab
            dy=dy+t.deltaY/#tab
        elseif t.state==ENDED then
            for a,b in pairs(tab) do
                if b.id==t.id then
                    if #tab==2 then
                        endAng=endAng+calcAng
                        calcAng,currAng=0,0
                    end
                    table.remove(tab,a)
                end
            end
        end
    end
    
Sign In or Register to comment.