#### 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?

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)

• Mod
Posts: 7,611

@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: 430

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#
• Mod
Posts: 7,611

@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()
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)

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

``````
• Mod
edited August 2018 Posts: 7,611

@xThomas I added rotation to my above code.

``````displayMode(FULLSCREEN)

function setup()
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
``````