Rescaling on the fly

Hello,

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

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 :frowning:

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

function PhysicsDebugDraw:addBody(body)
    table.insert(self.bodies,body)
end

function PhysicsDebugDraw:addJoint(joint)
    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)
            line(0,0,body.radius-3,0)            
            ellipse(0,0,body.radius*2)
        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?

!(https://dl.dropboxusercontent.com/u/73950/IMG_1888.PNG)

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 :slight_smile: