RaspberryDJ
Member
- Joined
- Jun 3, 2019
I'm looking for a way in Cerberus to create a pinch pan & zoom, any ideas how to go about doing that?
' Map panning, rotating and zooming all using easy matrices
' by Christian Perfect
' By saving a transformation matrix and using the Translate, Rotate and Scale operations on it,
' we can manipulate the player's view of a map very easily.
' The InvTransform command allows you to do the transformation backwards, converting screen
' co-ordinates to map co-ordinates
Import mojo
Class TransformMapApp Extends App
Field mx#,my# 'current screen co-ordinates of mouse
Field tmx#,tmy# 'current map co-ordinates of mouse
Field omx#,omy# 'previous map co-ordinates of mouse
Field mapMatrix#[] 'the transformation matrix applied to the map
Method OnCreate()
SetUpdateRate 0
'I want the map to be size 400x300 and to fill the entire screen when the program starts.
'So, the first step is to Scale the screen and grab the resulting transformation matrix
PushMatrix
Scale DeviceWidth()/400.0, DeviceHeight()/300.0
mapMatrix = GetMatrix()
PopMatrix
'The Push/PopMatrix isn't strictly necessary here since the matrix gets reset when the program first renders, but it's good to get in the habit of using it
End
Method OnUpdate()
Local coords#[]
mx = MouseX() ; my = MouseY()
'We're going to do some transformations on the mapMatrix, and they need to be undone so they don't affect drawing, so we need a Push/PopMatrix round all this code
PushMatrix
'Translate to the mouse's screen co-ords. This way, the rotation and scaling are centred on the mouse.
Translate mx,my
Rotate (KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT))*1.5
Local s# = 1+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN))*.01
Scale s,s
'Now move back. While other points on the map might have been transformed, the mouse's position remains unchanged.
Translate -mx,-my
'Apply the last saved mapMatrix, that is, all rotations, scalings and translations applied since the program started
Transform mapMatrix[0],mapMatrix[1],mapMatrix[2],mapMatrix[3],mapMatrix[4],mapMatrix[5]
'Work out what map co-ordinate the mouse is pointing at by doing the matrix transformation backwards.
coords = InvTransform([mx,my])
tmx = coords[0]
tmy = coords[1]
If TouchDown(0)
'Pan the map based on how far the mouse has moved since last frame
Translate tmx-omx, tmy-omy
Endif
mapMatrix = GetMatrix() 'Save the new map transformation matrix, preserving all the transformations we've just done.
'Work out the mouse's map co-ordinates based on the new matrix.
coords = InvTransform([mx,my])
omx = coords[0]
omy = coords[1]
PopMatrix
End
Method OnRender()
Cls
SetColor 255,255,255
SetFont Null
PushMatrix
'apply the saved map transformation matrix
Transform mapMatrix[0],mapMatrix[1],mapMatrix[2],mapMatrix[3],mapMatrix[4],mapMatrix[5]
drawMap
'Draw the mouse's map co-ordinates above the cursor
DrawText Int(omx)+","+Int(omy),omx,omy-TextHeight()
Local bits#[] = InvTransform([mx,my])
DrawText Int(bits[0])+","+Int(bits[1]),omx,omy-TextHeight()*2
PopMatrix
DrawText "Click and drag to move",0,0
DrawText "Arrow keys to rotate and zoom",0,TextHeight()
End
Method drawMap()
For Local x=0 To 400 Step 100
DrawLine x,0,x,300
Next
For Local y=0 To 300 Step 100
DrawLine 0,y,400,y
Next
For Local x=50 To 400 Step 100
For Local y=50 To 300 Step 100
DrawCircle x,y,2
DrawText x+","+y,x+2,y+2
Next
Next
End
End
Function Main()
New TransformMapApp
End
Import mojo
Class TransformMapApp Extends App
Field mx#,my#
Field tmx#,tmy#
Field omx#,omy#
Field mapMatrix#[]
Field gesturing:Bool
Field g0#[] ' ?
Field g1:AffineMat3f = New AffineMat3f
Field gmatrix:AffineMat3f = New AffineMat3f
Method OnCreate()
SetUpdateRate 0
PushMatrix
Scale DeviceWidth()/400.0, DeviceHeight()/300.0
mapMatrix = GetMatrix()
PopMatrix
End
Method OnUpdate()
Local coords#[]
mx = TouchX(0) ; my = TouchY(0)
PushMatrix
' ORIGINAL------------------------------------------------------------
Translate mx,my
Rotate (KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT))*1.5
Local s# = 1+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN))*.01
Scale s,s
Translate -mx,-my
' TOUCH---------------------------------------------------------
If Not gesturing
If TouchDown(0) And TouchDown(1)
' If g1 Then g0 = g1 * GestureMatrix(TouchXY(0),TouchXY(1))
' If Not g1 Then g0 = GestureMatrix(TouchXY(0),TouchXY(1))
gesturing=True
Endif
Endif
If gesturing
If TouchDown(0) And TouchDown(1)
' gmatrix = -g0 * GestureMatrix(TouchXY(0),TouchXY(1))
Else
' g1 = -gmatrix ; gesturing = False
Endif
Endif
' -------------------------------------------------------------
Transform mapMatrix[0],mapMatrix[1],mapMatrix[2],mapMatrix[3],mapMatrix[4],mapMatrix[5]
coords = InvTransform([mx,my])
tmx = coords[0] ; tmy = coords[1]
If TouchDown(0) Then Translate tmx-omx, tmy-omy
mapMatrix = GetMatrix()
coords = InvTransform([mx,my])
omx = coords[0] ; omy = coords[1]
PopMatrix
End
Method GestureMatrix:AffineMat3f(p0:Vec2f,p1:Vec2f)
Local d = p1-p0,r = -ATan2(d.y,d.x),s = d.Length
Local center = (p0-p1) / 2.0 + p1
Return New AffineMat3f().Translate(p0).Rotate(r).Scale(s,s)
End
Method OnRender()
Cls
SetColor 255,255,255
SetFont Null
PushMatrix
Transform mapMatrix[0],mapMatrix[1],mapMatrix[2],mapMatrix[3],mapMatrix[4],mapMatrix[5]
drawMap
DrawText Int(omx)+","+Int(omy),omx,omy-TextHeight()
Local bits#[] = InvTransform([mx,my])
DrawText Int(bits[0])+","+Int(bits[1]),omx,omy-TextHeight()*2
PopMatrix
End
Method drawMap()
For Local x=0 To 400 Step 100
DrawLine x,0,x,300
Next
For Local y=0 To 300 Step 100
DrawLine 0,y,400,y
Next
For Local x=50 To 400 Step 100
For Local y=50 To 300 Step 100
DrawCircle x,y,2
DrawText x+","+y,x+2,y+2
Next
Next
End
End
Function Main()
New TransformMapApp
End
Yup, in my framework fantomCX I have something like that already and it could easily be integrated into the next CX version.BTW @MikeHart Do we have functions for vector calculation in cx. Maybe this is a good starting point for enhancement.
vector functions -> easy to use functions/classes for swipe, pinch, and collisions
def estimate translation scaling rotation(X,Y):
N=min(len(X),len(Y))
a1 = b1 = c1 = d1 = 0
a2 = b2 = ac = ad = bc = bd = 0
for i in range(1,N):
a = X[ i ] [ 0 ]
b = X[ i ] [ 1 ]
c = Y[ i ] [ 0 ]
d = Y[ 1 ] [ 1 ]
a1 += a
b1 += b
c1 += c
d1 += d
a2 += a * a
b2 += b * b
ac += a * c
ad += a * d
bc += b ∗ c
bd += b ∗ d
g = N ∗ a2 + N ∗ b2 − a1 ∗ a1 − b1 ∗ b1
if g < epsilon:
if N == 0 :
return 1,0,0,0
return 1,0,(c1 − a1) / N,(d1 − b1) / N
acbd = ac + bd
adbc = ad − bc
s = (N ∗ acbd − a1 ∗ c1 − b1 ∗ d1) / g
r = (N ∗ adbc + b1 ∗ c1 − a1 ∗ d1) / g
t1 = (−a1 ∗ acbd + b1 ∗ adbc + a2 ∗ c1 + b2 ∗ c1) / g
t2 = (−b1 ∗ acbd − a1 ∗ adbc + a2 ∗ d1 + b2 ∗ d1) / g
return s,r,t1,t2