Pinch zoom + pan

Monkey Forums/Monkey Programming/Pinch zoom + pan

JIM(Posted 2011) [#1]
Has anyone successfully implemented something like this? Pinch to zoom + drag to pan.

I've been pulling my hair out for 3 days (for a few hours each day, but still...) and I can't get it right.

I've got this far (pseudocode):

offset -= O
offset *= newZoom
offset += beginO + pan

O = origin
newZoom = distance between points over distance between the original points (eg.: 2 if your fingers are twice as far apart as they were when starting the zoom)
beginO = origin when zoom/pan was started
pan = difference between the current points and the original points

I've been circling around the idea that I have to invert the current transformation (object.x = O.x + position.x * zoom) and then apply the new one, but I just can't get it right and my head hurts :(


Indiepath(Posted 2011) [#2]
There are gesture events that do a lot of this for you - they are just not implemented into Monkey yet.

In javascript you are looking at something like:


As you can clearly see, scale and rotation are calculated for you - same for native iOS, not sure about andriod but I suspect it's native.


Warpy(Posted 2011) [#3]
my 'transform' example in the bananas directory show how to do the transformations. You just need to pick your pan, zoom and rotate values.


Skn3(Posted 2011) [#4]
Something like this code should let you do pan with finger:
If drag = False 
	If TouchHit(0)
		drag = True
		dragStartX = TouchX(0)
		dragStartY = TouchY(0)
		
		dragScrollX = scrollX
		dragScrollY = scrollY
	EndIf
Else
	If TouchDown(0) = False
		drag = False
	Else
		dragCurrentX = TouchX(0)
		dragCurrentY = TouchY(0)
	EndIf
	
	dragAmountX = dragCurrentX - dragStartX
	dragAmountY = dragCurrentY - dragStartY
	
	scrollX = dragScrollX + dragAmountX
	scrollY = dragScrollY + dragAmountY
EndIf


You just need to offset/transform your drawing with scrollX/scrollY


JIM(Posted 2011) [#5]
Thanks for the help guys.

My original problem wasn't that I can't zoom or pan. I nailed those really quick. The problem was that if I zoomed while panning, my objects would move all over the place. Also, I couldn't get the zooming to be properly centered between my fingers.

I got to a point that's satisfying for now, but it's still not perfect. (might be precision problems, but I doubt it)


Global ZoomPan1Begin:Float[2]
Global ZoomPan2Begin:Float[2]
Global ZoomPanDO:Float[2]
Global ZoomPanZoom:Float

if (Not TouchDown(1))
		ZoomPanning = false
	End
	
	If (TouchDown(0) and TouchHit(1))
		ZoomPan1Begin[0] = TouchX(0)
		ZoomPan1Begin[1] = TouchY(0)
		
		ZoomPan2Begin[0] = TouchX(1)
		ZoomPan2Begin[1] = TouchY(1)
		
		ZoomPanDO[0] = DOX
		ZoomPanDO[1] = DOY
		
		ZoomPanZoom = GetZoom()
		
		ZoomPanning = True
	End
	
	If (ZoomPanning)
		Local oldDist# = Dist2DSq(ZoomPan1Begin[0], ZoomPan1Begin[1], ZoomPan2Begin[0], ZoomPan2Begin[1])
		Local crtDist# = Dist2DSq(TouchX(0), TouchY(0), TouchX(1), TouchY(1))
		
		Local newZoom# = crtDist / oldDist

		SetZoom(ZoomPanZoom * newZoom)
	
		Local newP:Float[2]
		newP[0] = (TouchX(0) + TouchX(1)) / 2.0
		newP[1] = (TouchY(0) + TouchY(1)) / 2.0
		
		Local oldP:Float[2]
		oldP[0] = (ZoomPan1Begin[0] + ZoomPan2Begin[0]) / 2.0
		oldP[1] = (ZoomPan1Begin[1] + ZoomPan2Begin[1]) / 2.0
		
		Local newOff:Float[2]
		newOff[0] = -newP[0] * (newZoom - 1.0) + newP[0] - oldP[0]
		newOff[1] = -newP[1] * (newZoom - 1.0) + newP[1] - oldP[1]
	
		DOX = ZoomPanDO[0] + newOff[0]
		DOY = ZoomPanDO[1] + newOff[1]
	End


@Indiepath Until monkey has native support for gestures, I'd like to code them myself (besides learning stuff, I avoid hacking stuff for each target) :)

@Warpy I saw the example and I know how to play with those. I guess I'm trying to solve it without matrices because I started this way. I'll probably end up with matrices in the end though.

@Skn3 Thanks for the code, but I already had that :)


JIM(Posted 2011) [#6]
Thanks for the help guys.

My original problem wasn't that I can't zoom or pan. I nailed those really quick. The problem was that if I zoomed while panning, my objects would move all over the place. Also, I couldn't get the zooming to be properly centered between my fingers.

I got to a point that's satisfying for now, but it's still not perfect. (might be precision problems, but I doubt it)


Global ZoomPan1Begin:Float[2]
Global ZoomPan2Begin:Float[2]
Global ZoomPanDO:Float[2]
Global ZoomPanZoom:Float

if (Not TouchDown(1))
		ZoomPanning = false
	End
	
	If (TouchDown(0) and TouchHit(1))
		ZoomPan1Begin[0] = TouchX(0)
		ZoomPan1Begin[1] = TouchY(0)
		
		ZoomPan2Begin[0] = TouchX(1)
		ZoomPan2Begin[1] = TouchY(1)
		
		ZoomPanDO[0] = DOX
		ZoomPanDO[1] = DOY
		
		ZoomPanZoom = GetZoom()
		
		ZoomPanning = True
	End
	
	If (ZoomPanning)
		Local oldDist# = Dist2DSq(ZoomPan1Begin[0], ZoomPan1Begin[1], ZoomPan2Begin[0], ZoomPan2Begin[1])
		Local crtDist# = Dist2DSq(TouchX(0), TouchY(0), TouchX(1), TouchY(1))
		
		Local newZoom# = crtDist / oldDist

		SetZoom(ZoomPanZoom * newZoom)
	
		Local newP:Float[2]
		newP[0] = (TouchX(0) + TouchX(1)) / 2.0
		newP[1] = (TouchY(0) + TouchY(1)) / 2.0
		
		Local oldP:Float[2]
		oldP[0] = (ZoomPan1Begin[0] + ZoomPan2Begin[0]) / 2.0
		oldP[1] = (ZoomPan1Begin[1] + ZoomPan2Begin[1]) / 2.0
		
		Local newOff:Float[2]
		newOff[0] = -newP[0] * (newZoom - 1.0) + newP[0] - oldP[0]
		newOff[1] = -newP[1] * (newZoom - 1.0) + newP[1] - oldP[1]
	
		DOX = ZoomPanDO[0] + newOff[0]
		DOY = ZoomPanDO[1] + newOff[1]
	End


@Indiepath Until monkey has native support for gestures, I'd like to code them myself (besides learning stuff, I avoid hacking stuff for each target) :)

@Warpy I saw the example and I know how to play with those. I guess I'm trying to solve it without matrices because I started this way. I'll probably end up with matrices in the end though.

@Skn3 Thanks for the code, but I already had that :)