# Rescaling on the fly

Hello,

I’m having a rescaling problem, that -I think- can be explained with the following example…

In the Physics lab example, in test 1, for instance, how to implement the following multi-touch UI functionality?

if one would pinch in or out, the drawings would be scaled accordingly, dragging object or creating them would still work as expected (the touch coordinates need to match the new scale).

Has anyone tried implementing this seemingly simple (but deceptively hard-ish, I believe) things before?

Here’s something I found in my stuff. Just move 2 fingers apart or together on the screen.

``````
displayMode(FULLSCREEN)

function setup()
tab={}
size=100
d1=0
d2=0
end

function draw()
background(40, 40, 50)
fill(207, 193, 47, 255)
ellipse(WIDTH/2,HEIGHT/2,size,size)
end

function touched(t)
if t.state==BEGAN then
d1=0
d2=0
table.insert(tab,vec3(t.x,t.y,t.id))
end
if t.state==MOVING and #tab == 2 then
for z=1,2 do
if t.id==tab[z].z then
tab[z].x=t.x
tab[z].y=t.y
end
end
d1=math.sqrt((tab[1].x-tab[2].x)^2+(tab[1].y-tab[2].y)^2)
if d2==0 then
d2=d1
end
size=size+(d1-d2)
if size<0 then
size=0
end
d2=d1
end
if t.state==ENDED then
for z=1,#tab do
if t.id==tab[z].z then
table.remove(tab,z)
return
end
end
end
end

``````

Cool, thanks! The heart of my question -which is admittedly not really clear- is how, while using the scale function, to register touches at coordinates where physics objects are? This is why I’m specifically giving Physics’ lab test1 exemple.

When I tried:

``````pushMatrix()
scale(.75)

--draw physics objects

popMatrix()
``````

I can’t touch and move objects anymore (like in Physics’ lab test1), since rescaling only changed what we see on the screen, and not the coordinate system per se

Thanks again!

divide the coordinates by the scale factor. If you’re zooming in, you probably need to translate too to keep the view centred.

So if you’re scaling and translating like this:

``````cent=vec2(WIDTH/2,HEIGHT/2)
cam = {zoom = 0.75, off = vec2(0,0)} --off = offset, for scrolling the screen
...

scale(cam.zoom)
translate ((cent.x/cam.zoom)-cam.off.x,(cent.y/cam.zoom)-cam.off.y)
``````

then screen-to-world conversion should look like this:

``````vec2( ((touch.x-cent.x)/cam.zoom)+cam.off.x, ((touch.y-cent.y)/cam.zoom)+cam.off.y)
``````

Ok, great, here it is in the physics lab example (look for the text “changes here”):

I’m scale at 50%.

• What works: scaling, touches are at the right coordinates when I move shapes.
• What doesn’t: the new scaled drawings are not centred, touches are not at the right coordinates when I create them.

What do you reckon I’m doing wrong here?

``````PhysicsDebugDraw = class()

function PhysicsDebugDraw:init()
self.bodies = {}
self.joints = {}
self.touchMap = {}
self.contacts = {}
end

table.insert(self.bodies,body)
end

table.insert(self.joints,joint)
end

function PhysicsDebugDraw:clear()
-- deactivate all bodies

for i,body in ipairs(self.bodies) do
body:destroy()
end

for i,joint in ipairs(self.joints) do
joint:destroy()
end

self.bodies = {}
self.joints = {}
self.contacts = {}
self.touchMap = {}
end

function PhysicsDebugDraw:draw()

-- changes here
pushMatrix()
cent = vec2(WIDTH/2,HEIGHT/2)
cam = {zoom = .5, off = vec2(0,0)}
scale(cam.zoom)
translate((cent.x/cam.zoom)-cam.off.x,(cent.y/cam.zoom)-cam.off.y)
-- end of changes

pushStyle()
smooth()
strokeWidth(5)
stroke(128,0,128)

local gain = 2.0
local damp = 0.5
for k,v in pairs(self.touchMap) do
local worldAnchor = v.body:getWorldPoint(v.anchor)
local touchPoint = v.tp
local diff = touchPoint - worldAnchor
local vel = v.body:getLinearVelocityFromWorldPoint(worldAnchor)
v.body:applyForce( (1/1) * diff * gain - vel * damp, worldAnchor)

line(touchPoint.x, touchPoint.y, worldAnchor.x, worldAnchor.y)
end

stroke(0,255,0,255)
strokeWidth(5)
for k,joint in pairs(self.joints) do
local a = joint.anchorA
local b = joint.anchorB
line(a.x,a.y,b.x,b.y)
end

stroke(255,255,255,255)
noFill()

for i,body in ipairs(self.bodies) do
pushMatrix()
translate(body.x, body.y)
rotate(body.angle)

if body.type == STATIC then
stroke(255,255,255,255)
elseif body.type == DYNAMIC then
stroke(150,255,150,255)
elseif body.type == KINEMATIC then
stroke(150,150,255,255)
end

if body.shapeType == POLYGON then
strokeWidth(3.0)
local points = body.points
for j = 1,#points do
a = points[j]
b = points[(j % #points)+1]
line(a.x, a.y, b.x, b.y)
end
elseif body.shapeType == CHAIN or body.shapeType == EDGE then
strokeWidth(3.0)
local points = body.points
for j = 1,#points-1 do
a = points[j]
b = points[j+1]
line(a.x, a.y, b.x, b.y)
end
elseif body.shapeType == CIRCLE then
strokeWidth(3.0)
end

popMatrix()
end

stroke(255, 0, 0, 255)
fill(255, 0, 0, 255)

for k,v in pairs(self.contacts) do
for m,n in ipairs(v.points) do
ellipse(n.x, n.y, 10, 10)
end
end

popStyle()
popMatrix()
end

function PhysicsDebugDraw:touched(touch)
--local touchPoint = vec2(touch.x, touch.y)

-- changes here
local touchPoint = vec2(((touch.x-cent.x)/cam.zoom)+cam.off.x, ((touch.y-cent.y)/cam.zoom)+cam.off.y)
-- end of changes

if touch.state == BEGAN then
for i,body in ipairs(self.bodies) do
if body.type == DYNAMIC and body:testPoint(touchPoint) then
self.touchMap[touch.id] = {tp = touchPoint, body = body, anchor = body:getLocalPoint(touchPoint)}
return true
end
end
elseif touch.state == MOVING and self.touchMap[touch.id] then
self.touchMap[touch.id].tp = touchPoint
return true
elseif touch.state == ENDED and self.touchMap[touch.id] then
self.touchMap[touch.id] = nil
return true;
end
return false
end

function PhysicsDebugDraw:collide(contact)
if contact.state == BEGAN then
self.contacts[contact.id] = contact
sound(SOUND_HIT, 2643)
elseif contact.state == MOVING then
self.contacts[contact.id] = contact
elseif contact.state == ENDED then
self.contacts[contact.id] = nil
end
end
``````

You’re only scaling the touch coords in `PhysicsDebugDraw:touched(touch)`: You also need to scale them anywhere else you’re touching the game world, ie in `Test1:touched(touch)` or wherever. Either apply the same scaling action in `Test1` or, what you should do, is do the scaling on a touchpos in `touched(touch)` in the `Main` tab, and then pass that through to whatever is using it, ie `currentTest:touched(touch, worldTouchPos)` or something, so that you avoid doing the same scaling operation (and typing the same operation) multiple times.

Also, in your code above, you don’t need to define `cent` and `cam` every cycle, those 2 lines should be outside the drawloop somewhere (particularly if you’re dynamically zooming in and out and scrolling around. At the moment you’re resetting them at the start of each click.)

cool, I’m trying now… as far as the scene not being centered, do you know what’s going on?

set the `off` variable to (a copy of) centre. `off = vec2(cent.x, cent.y)`. I’m assuming that if you’re zooming in, you’ll also want to pan around. That’s what `off` is for. `cent` is meant to be a constant, I got bored of writing `WIDTH*0.5` all the time.

Oh off course… Thanks for your patience