Matrix in mojo2

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
I have problems understanding matrix handling in Cerberus. I've tried to read the documentation for a few weeks and painstainkinlgy converted the mojo1 example. It's behaving very strange. Any help would be much appreciated!

This is the mojo1 example:
Code:
Import mojo

Function Main()
    New TransformMapApp
End

Class TransformMapApp Extends App

    Field mx#,my#
    Field tmx#,tmy#
    Field omx#,omy#
    Field mapMatrix#[]

    Method OnCreate()
        ' Vertical blanking
        SetSwapInterval 1 ; SetUpdateRate 0
        PushMatrix
            Scale DeviceWidth()/400.0, DeviceHeight()/300.0
            mapMatrix = GetMatrix()
        PopMatrix
    End
 
    Method OnUpdate()
        Local coords#[]
        mx = MouseX() ; my = MouseY()
        PushMatrix
            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
            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 OnRender()
        Cls
        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

this is mojo2 version that I tried to create, the zoom seem to be stronger at the start and it behaves not the same for some reason
some commands have a very different syntax in mojo2 and this makes me very uncertain what is actually wrong, I tried to find every mojo2 command that does the same as the mojo1.

Everything seems to work fine except the coordinates seem to be x2 zoom, I don't knoe how to put it.
Have a look here what I've got so far:
Code:
Import mojo2

Function Main()
    New TransformMapApp
End

Class TransformMapApp Extends App
 
    Field canvas:Canvas
    Field mx#,my#
    Field tmx#,tmy#
    Field omx#,omy#
    Field mapMatrix#[]
    Field gesturing:Bool
 
    Method OnCreate()
           canvas = New Canvas()
        SetUpdateRate 0
        canvas.PushMatrix
        canvas.Scale DeviceWidth()/400.0, DeviceHeight()/300.0
        canvas.GetMatrix(mapMatrix)
        canvas.PopMatrix
    End
 
    Method OnUpdate()
            Local coords#[]
            Local coordsin#[]
            mx = TouchX(0) ; my = TouchY(0)
            canvas.PushMatrix
        
            canvas.Translate mx,my
            canvas.Rotate (KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT))*1.5
            Local s# = 1+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN))*.01
            canvas.Scale s,s
            canvas.Translate -mx,-my
            canvas.Transform mapMatrix[0],mapMatrix[1],mapMatrix[2],mapMatrix[3],mapMatrix[4],mapMatrix[5]

  '         coords = InvTransform([mx,my])            ' MOJO1
              coordsin[0] = mx ; coordsin[1] = my         ' MOJO2
           canvas.TransformCoords(coordsin,coords)  ' MOJO2

            tmx = coords[0] ; tmy = coords[1]
            If TouchDown(0) Then canvas.Translate tmx-omx, tmy-omy       
            canvas.GetMatrix(mapMatrix)
        
   '         coords = InvTransform([mx,my])             ' MOJO1
             coordsin[0] = mx ; coordsin[1] = my        ' MOJO2
             canvas.TransformCoords(coordsin,coords)  ' MOJO2
      
            omx = coords[0] ; omy = coords[1]
              canvas.PopMatrix
    End

    Method OnRender()
        canvas.Clear
        canvas.PushMatrix
        canvas.Transform mapMatrix[0],mapMatrix[1],mapMatrix[2],mapMatrix[3],mapMatrix[4],mapMatrix[5]
        drawMap
        canvas.DrawText Int(omx)+","+Int(omy),omx,omy-16

        Local bitsin#[]
        Local bits#[]   
 '       bits = InvTransform([mx,my])          ' MOJO1 
         bitsin[0] = mx ; bitsin[1] = my        ' MOJO2
          canvas.TransformCoords(bitsin,bits)  ' MOJO2
        canvas.DrawText Int(bits[0])+","+Int(bits[1]),omx,omy-16
    
        canvas.PopMatrix
        canvas.Flush
    End
 
    Method drawMap()
        For Local x=0 To 400 Step 100
            canvas.DrawLine x,0,x,300
        Next
        For Local y=0 To 300 Step 100
            canvas.DrawLine 0,y,400,y
        Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2
                canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
End
 
Last edited:

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
3,281
Ya I hear ya. Matrix stuff is over my head as well. Not sure but my 2D in 3D tutorial might help.

Also maybe looking at the Vortex2 source code. Or any OpenGL tutorial about matrixes?
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Thanks for the idea! This is what I've got now.
Not a perfect replica but most functions are there except the possibility to move using mouse instead of keys and a fixed originpoint set to 100,100.

Code:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=False

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field myRect : Rectangle
    Field origin : Point
    Field canvas : Canvas

    Method OnCreate()
        canvas = New Canvas

        SetSwapInterval 1 ; SetUpdateRate 0  
        myMatrix = New Matrix()
        myPoint = New Point()
        myRect = New Rectangle(-100,-100,200,200)
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
    End Method
   
    Method OnUpdate()
        canvas.Clear 0,0,0  
       
        ' Translate matrix
        If KeyDown(KEY_UP) Then myMatrix.translateBy(0,-1)
        If KeyDown(KEY_DOWN) THen myMatrix.translateBy(0,1)  
        If KeyDown(KEY_LEFT) Then myMatrix.translateBy(-1,0)
        If KeyDown(KEY_RIGHT) Then myMatrix.translateBy(1,0)

        ' Scale matrix
        If KeyDown(KEY_N) Then myMatrix.scaleBy(1.01,1.01)
        If KeyDown(KEY_M) Then myMatrix.scaleBy(0.99,0.99)

        ' Rotate matrix
        If KeyDown(KEY_Z) Then myMatrix.rotateBy(-1)
        If KeyDown(KEY_X) Then myMatrix.rotateBy(1)  

    End Method
   
    Method OnRender()
        canvas.Clear 0,0,0
        canvas.PushMatrix
        origin.mX = 100 ; origin.mY = 100
       
        canvas.Translate origin.mX,origin.mY
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy
        canvas.Translate  -origin.mX,-origin.mY
       
        canvas.DrawRect origin.mX + myRect.mX,origin.mY + myRect.mY,myRect.mWidth,myRect.mHeight
   
        canvas.SetColor 1,1,1
        drawMap()
       
        canvas.PopMatrix

        myPoint.mX = TouchX() - origin.mX
        myPoint.mY = TouchY() - origin.mY
       
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
               
        ' Transforms point
        Local testPoint : Point = invMatrix.transformPoint(myPoint) ' Make the point into the transformed world
       
        ' Simple rectangle check as the point has been transformed
        If myRect.containsPoint(testPoint) Then canvas.SetColor 1,0,0 Else canvas.SetColor 1,1,1
       
        canvas.DrawText "100,100 is current the set origin marked with a dot above. Scroll using cursor",0,400
        canvas.DrawText "scale using n & m         rotate using z & x",0,420
        canvas.DrawText "Square sprite collision will be shown in red",0,440
        canvas.DrawRect origin.mX,origin.mY,1,1
        canvas.DrawText String(origin.mX+Int(testPoint.mX)), 20,10
        canvas.DrawText String(origin.mY+Int(testPoint.mY)), 180,10
       
        canvas.Flush
    End Method

    Method drawMap()
        For Local x=0 To 400 Step 100
            canvas.DrawLine x,0,x,300
        Next
        For Local y=0 To 300 Step 100
            canvas.DrawLine 0,y,400,y
        Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2
                canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
   
End Class

Class Point

    Field mX : Float
    Field mY : Float

    Method New(x : Float,y : Float)
        Self.mX = x
        Self.mY = y
    End Method

End Class

Class Rectangle

    Field mX : Float
    Field mY : Float
    Field mWidth : Float
    Field mHeight : Float

    Method New()
        Self.mX = 0
        Self.mY = 0
        Self.mWidth = 0
        Self.mHeight = 0
    End Method
   
    Method New(x : Float,y : Float,width : Float,height : Float)
        Self.mX = x
        Self.mY = y
        Self.mWidth = width
        Self.mHeight = height
    End Method
   
    Method containsXY : Bool(x : Float,y : Float)
        Return (x >= mX) And (y >= mY) And (x <= mX + mWidth) And (y <= mY + mHeight)
    End Method
   
    Method containsPoint : Bool(point : Point)
        Return Self.containsXY(point.mX,point.mY)
    End Method
   
End Class

Class Matrix

     Field mA : Float
    Field mB : Float
    Field mC : Float
    Field mD : Float
     Field mTx : Float
    Field mTy : Float

    Method New()
        Self.mA = 1.0
        Self.mB = 0.0
        Self.mC = 0.0
        Self.mD = 1.0
        Self.mTx = 0.0
        Self.mTy = 0.0      
    End Method
   
    Method New(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        Self.mA = a
        Self.mB = b
        Self.mC = c
        Self.mD = d
        Self.mTx = tx
        Self.mTy = ty
    End Method
   
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a
        matrix.mB = b
        matrix.mC = c
        matrix.mD = d
        matrix.mTx = tx
        matrix.mTy = ty
    End Function
 
    Method clone : Matrix()
        Return New Matrix(Self.mA,Self.mB,Self.mC,Self.mD,Self.mTx,Self.mTy)
    End Method
   
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        Self.mA = a
        Self.mB = b
        Self.mC = c
        Self.mD = d
        Self.mTx = tx
        Self.mTy = ty
    End Method

    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * Self.mA  + matrix.mC * Self.mB
        Local b : Float = matrix.mB * Self.mA  + matrix.mD * Self.mB
        Local c : Float = matrix.mA * Self.mC  + matrix.mC * Self.mD
        Local d : Float = matrix.mB * Self.mC  + matrix.mD * Self.mD
        Local tx : Float = matrix.mA * Self.mTx + matrix.mC * Self.mTy + matrix.mTx
        Local ty : Float = matrix.mB * Self.mTx + matrix.mD * Self.mTy + matrix.mTy
        Self.setValues(a,b,c,d,tx,ty)
    End Method
        '
    Method determinant : Float()
            Return (Self.mA * Self.mD) - (Self.mC * Self.mB)
    End Method

    Method translateBy : Void(dx : Float,dy : Float)
        Self.mTx = Self.mTx + dx
        Self.mTy = Self.mTy + dy
    End Method
   
    Method scaleBy : Void(sx : Float,sy : Float)
        Self.mA = Self.mA * sx
        Self.mB = Self.mB * sy
        Self.mC = Self.mC * sx
        Self.mD = Self.mD * sy
        Self.mTx = Self.mTx * sx
        Self.mTy = Self.mTy * sy
    End Method

    Method scaleBy : Void(scale : Float)
        Self.scaleBy(scale,scale)
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        Self.concatMatrix(rotMatrix)
    End Method
   
    Method identity : Void()
        Self.setValues(1.0,0.0,0.0,1.0,0.0,0.0)
    End Method
   
    Method invert : Void()
        Local det : Float = Self.determinant()
        Local a : Float = Self.mD / det
        Local b : Float = -Self.mB / det
        Local c : Float = -Self.mC / det
        Local d : Float = Self.mA / det
        Local tx : Float = ((Self.mC * Self.mTy) - (Self.mD * Self.mTx)) / det
        Local ty : Float = ((Self.mB * Self.mTx) - (Self.mA * Self.mTy)) / det
        Self.setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (Self.mA * point.mX) + (Self.mC * point.mY) + Self.mTx
        Local y : Float = (Self.mB * point.mX) + (Self.mD * point.mY) + Self.mTy
        Return New Point(x,y)
    End Method
   
End Class
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Slimmed it down abit and starts to look good but what is still missing is to be able to use the mouse to move it around instead of cursorkeys, and to have the mousepointer to double as the originpoint.


screenshot.png


Code:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=False

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field origin : Point
    Field canvas : Canvas

    Method OnCreate()
        canvas = New Canvas
        SetSwapInterval 1 ; SetUpdateRate 0 
        myMatrix = New Matrix()
        myPoint = New Point()       
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
    End Method
  
    Method OnUpdate()
    
        ' Translate matrix
        If KeyDown(KEY_UP) Then myMatrix.translateBy(0,-1)
        If KeyDown(KEY_DOWN) THen myMatrix.translateBy(0,1) 
        If KeyDown(KEY_LEFT) Then myMatrix.translateBy(-1,0)
        If KeyDown(KEY_RIGHT) Then myMatrix.translateBy(1,0)

        ' Scale matrix
        If KeyDown(KEY_N) Then myMatrix.scaleBy(1.01,1.01)
        If KeyDown(KEY_M) Then myMatrix.scaleBy(0.99,0.99)

        ' Rotate matrix
        If KeyDown(KEY_Z) Then myMatrix.rotateBy(-1)
        If KeyDown(KEY_X) Then myMatrix.rotateBy(1)
        
    End Method
  
    Method OnRender()
        canvas.Clear 0,0,1
        canvas.PushMatrix
      '  origin.mX = 100 ; origin.mY = 100       
        canvas.Translate origin.mX,origin.mY
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy
        canvas.Translate -origin.mX,-origin.mY
        
        drawMap()
        canvas.PopMatrix
        
        myPoint.mX = TouchX() - origin.mX
        myPoint.mY = TouchY() - origin.mY
      
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
              
        ' Make the point into the transformed world
        Local testPoint : Point = invMatrix.transformPoint(myPoint)
        canvas.DrawRect origin.mX,origin.mY,1,1
        canvas.DrawText String(origin.mX+Int(testPoint.mX)), 20,10
        canvas.DrawText String(origin.mY+Int(testPoint.mY)), 180,10
      
        canvas.Flush
    End Method

    Method drawMap()
        For Local x=0 To 400 Step 100
            canvas.DrawLine x,0,x,300
        Next
        For Local y=0 To 300 Step 100
            canvas.DrawLine 0,y,400,y
        Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2
                canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
  
End Class

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x
       mY = y
    End Method

End Class

Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float

    Method New()
        mA = 1.0
        mB = 0.0
        mC = 0.0
        mD = 1.0
        mTx = 0.0
        mTy = 0.0     
    End Method
  
    Method New(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a
        mB = b
        mC = c
        mD = d
        mTx = tx
        mTy = ty
    End Method
  
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a
        matrix.mB = b
        matrix.mC = c
        matrix.mD = d
        matrix.mTx = tx
        matrix.mTy = ty
    End Function
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
  
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a
        mB = b
        mC = c
        mD = d
        mTx = tx
        mTy = ty
    End Method

    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * mA  + matrix.mC * mB
        Local b : Float = matrix.mB * mA  + matrix.mD * mB
        Local c : Float = matrix.mA * mC  + matrix.mC * mD
        Local d : Float = matrix.mB * mC  + matrix.mD * mD
        Local tx : Float = matrix.mA * mTx + matrix.mC * mTy + matrix.mTx
        Local ty : Float = matrix.mB * mTx + matrix.mD * mTy + matrix.mTy
        setValues(a,b,c,d,tx,ty)
    End Method
        '
    Method determinant : Float()
            Return (mA * mD) - (mC * mB)
    End Method

    Method translateBy : Void(dx : Float,dy : Float)
        mTx = mTx + dx
        mTy = mTy + dy
    End Method
  
    Method scaleBy : Void(sx : Float,sy : Float)
        mA = mA * sx
        mB = mB * sy
        mC = mC * sx
        mD = mD * sy
        mTx = mTx * sx
        mTy = mTy * sy
    End Method

    Method scaleBy : Void(scale : Float)
        scaleBy(scale,scale)
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        concatMatrix(rotMatrix)
    End Method
  
    Method identity : Void()
        setValues(1.0,0.0,0.0,1.0,0.0,0.0)
    End Method
  
    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det
        Local b : Float = -mB / det
        Local c : Float = -mC / det
        Local d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det
        Local ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx
        Local y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method
  
End Class
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Added draggability :D

Not sure how to make mouse to the origin?

EDIT
Added the possiblity to read the current canvas matrix hardware command into the math version.



[
Code:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=Fals

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field origin : Point
    Field canvas : Canvas
    Field ox:Int
    Field oy:Int
    Field x:Int
    Field y:Int
    Field d:Int
    Field mapMatrix:Float[6]
        
    Method OnCreate()
        canvas = New Canvas
        SetSwapInterval 1 ; SetUpdateRate 0
        myMatrix = New Matrix()
        myPoint = New Point()
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
      
       ' canvas.Scale DeviceWidth()/400.0, DeviceHeight()/300.0
    
         ' To be used later (just reading the default initial canvas value for now)
         ' Read the current canvas hardware matrix into numbers
        canvas.GetMatrix(mapMatrix)
        myMatrix.mA = mapMatrix[0]
        myMatrix.mB = mapMatrix[1]
        myMatrix.mC = mapMatrix[2]
        myMatrix.mD = mapMatrix[3]
        myMatrix.mTx = mapMatrix[4]
        myMatrix.mTy = mapMatrix[5]
 
    End Method
 
    Method OnUpdate()
      
            ox = x ; oy = y
            x = TouchX() ; y = TouchY()
            d = TouchDown(0)
          
            ' Add mouse/touch drag
            If d Then myMatrix.translateBy(x-ox,y-oy)
          
        ' Translate matrix
        If KeyDown(KEY_UP) Then myMatrix.translateBy(0,-1)
        If KeyDown(KEY_DOWN) THen myMatrix.translateBy(0,1)
        If KeyDown(KEY_LEFT) Then myMatrix.translateBy(-1,0)
        If KeyDown(KEY_RIGHT) Then myMatrix.translateBy(1,0)

        ' s matrix
        If KeyDown(KEY_N) Then myMatrix.sBy(1.01)
        If KeyDown(KEY_M) Then myMatrix.sBy(0.99)

        ' Rotate matrix
        If KeyDown(KEY_Z) Then myMatrix.rotateBy(-1)
        If KeyDown(KEY_X) Then myMatrix.rotateBy(1)
      
    End Method
 
    Method OnRender()
    

        canvas.Clear 0,0,1
        
        
        
        canvas.PushMatrix
        ' origin.mX = 100 ; origin.mY = 100
 
 ' MATH IS DONE!
 
 
     ' if right mousebutton then read current canvas matrix status and overwrite all math numbers before USIGN THEM IN ACTUAL MATRIXSETTINGS
     ' If MouseDown(1) Then canvas.GetMatrix(mapMatrix) ; myMatrix.mA = mapMatrix[0] ; myMatrix.mB = mapMatrix[1] ; myMatrix.mC = mapMatrix[2] ; myMatrix.mD = mapMatrix[3] ; myMatrix.mTx = mapMatrix[4] ; myMatrix.mTy = mapMatrix[5]
    canvas.DrawText String(myMatrix.mA),0,0
    canvas.DrawText String(myMatrix.mB),0,10
    canvas.DrawText String(myMatrix.mC),0,20
    canvas.DrawText String(myMatrix.mD),0,30
    canvas.DrawText String(myMatrix.mTx),0,40
    canvas.DrawText String(myMatrix.mTy),0,50


    ' Does not seem to work? It just says 1 0 0 1 0 0 when you move around the matrix?


      ' NOW SET HARDWARE AND PUT THE NUMBERS INTO ACTION
        canvas.Translate origin.mX,origin.mY
        ' Multiply matrix
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy
        canvas.Translate -origin.mX,-origin.mY   

    ' Here you can read matrix
    canvas.GetMatrix(mapMatrix)

        drawMap()
        canvas.PopMatrix
        myPoint.mX = x - origin.mX
        myPoint.mY = y - origin.mY
    
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
            
        ' Make the point into the transformed world
        Local testPoint : Point = invMatrix.transformPoint(myPoint)
        canvas.DrawRect origin.mX,origin.mY,1,1
        canvas.DrawText String(origin.mX+Int(testPoint.mX)), 20,10
        canvas.DrawText String(origin.mY+Int(testPoint.mY)), 180,10
    
   '     canvas.DrawText String(mapMatrix[0]),0,0
   ' canvas.DrawText String(mapMatrix[1]),0,10
'    canvas.DrawText String(mapMatrix[2]),0,20
'    canvas.DrawText String(mapMatrix[3]),0,30
'    canvas.DrawText String(mapMatrix[4]),0,40
'    canvas.DrawText String(mapMatrix[5]),0,50
    
        canvas.Flush
    End Method

    Method drawMap()
        For Local x=0 To 400 Step 100
            canvas.DrawLine x,0,x,300
        Next
        For Local y=0 To 300 Step 100
            canvas.DrawLine 0,y,400,y
        Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2
                canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
 
End Class

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class

Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float

    Method New()
        mA = 1.0 ; mB = 0.0 ; mC = 0.0 ; mD = 1.0 ; mTx = 0.0 ; mTy = 0.0   
    End Method
 
    Method New(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a ; matrix.mB = b ; matrix.mC = c ; matrix.mD = d ; matrix.mTx = tx ; matrix.mTy = ty
    End Function
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method

    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * mA  + matrix.mC * mB
        Local b : Float = matrix.mB * mA  + matrix.mD * mB
        Local c : Float = matrix.mA * mC  + matrix.mC * mD
        Local d : Float = matrix.mB * mC  + matrix.mD * mD
        Local tx : Float = matrix.mA * mTx + matrix.mC * mTy + matrix.mTx
        Local ty : Float = matrix.mB * mTx + matrix.mD * mTy + matrix.mTy
        setValues(a,b,c,d,tx,ty)
    End Method
 
    Method determinant : Float()
            Return (mA * mD) - (mC * mB)
    End Method

    Method translateBy : Void(dx : Float,dy : Float)
        mTx = mTx + dx ; mTy = mTy + dy
    End Method

    Method sBy : Void(s : Float)
        mA = mA * s ; mB = mB * s ; mC = mC * s ; mD = mD * s ; mTx = mTx * s ;  mTy = mTy * s
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        concatMatrix(rotMatrix)
    End Method
 
    Method identity : Void()
        setValues(1.0,0.0,0.0,1.0,0.0,0.0)
    End Method
 
    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det
        Local b : Float = -mB / det
        Local c : Float = -mC / det
        Local d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det
        Local ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx
        Local y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method
 
End Class
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Digging deeper into matrix commands, now trying to read the current canvas matrix, which is done successfully.

Still need to come up with a practical way to set the origin using mouse, without messing about.

EDIT
Got the idea to use GetMatrix/SetMatrix as this let you do things like matrix multiply and then read the multiplied parameters back, this might be useful if concatMatrix is not enough.


Code:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=False

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field origin : Point
    Field canvas : Canvas
    Field ox:Int
    Field oy:Int
    Field x:Int
    Field y:Int
    Field d:Int
    Field mapMatrix:Float[6]
        
    Method OnCreate()
        canvas = New Canvas
        SetSwapInterval 1 ; SetUpdateRate 0
        myMatrix = New Matrix()
        myPoint = New Point()
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
        ' canvas.Scale DeviceWidth()/400.0, DeviceHeight()/300.0
         ' To be used later (just reading the default initial canvas value for now)
         ' Read the current canvas hardware matrix into numbers
        canvas.GetMatrix(mapMatrix)
        myMatrix.mA = mapMatrix[0]
        myMatrix.mB = mapMatrix[1]
        myMatrix.mC = mapMatrix[2]
        myMatrix.mD = mapMatrix[3]
        myMatrix.mTx = mapMatrix[4]
        myMatrix.mTy = mapMatrix[5]
    End Method
 
    Method OnUpdate()
            ox = x ; oy = y
            x = TouchX() ; y = TouchY()
            d = TouchDown(0)
          
           ' Translate matrix
            If d Then myMatrix.translateBy(x-ox,y-oy)
            
           ' Scale matrix
           If KeyDown(KEY_UP) Then myMatrix.sBy(1.01)
           If KeyDown(KEY_DOWN) Then myMatrix.sBy(0.99)
 
           ' Rotate matrix
           If KeyDown(KEY_LEFT) Then myMatrix.rotateBy(-1)
           If KeyDown(KEY_RIGHT) Then myMatrix.rotateBy(1)
    End Method
 
    Method OnRender()
        canvas.Clear       
        canvas.PushMatrix
        ' origin.mX = 100 ; origin.mY = 100
       ' MATH IS DONE! NOW SET HARDWARE AND PUT THE NUMBERS INTO ACTION!
      
        canvas.Translate origin.mX,origin.mY
        ' Multiply matrix (might need to mathematically multiply instead for later inverse multiplication)
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy     
        canvas.Translate -origin.mX,-origin.mY   
    ' ----------------------------------------------------------------------
    ' Here you can read the current matrix
    canvas.GetMatrix(mapMatrix)
    
    ' Fails if you try (they are something you multiply, if you read here they become absolute)
    ' myMatrix.mA = mapMatrix[0] ; myMatrix.mB = mapMatrix[1] ; myMatrix.mC = mapMatrix[2] ; myMatrix.mD = mapMatrix[3] ; myMatrix.mTx = mapMatrix[4] ; myMatrix.mTy = mapMatrix[5]
    
    ' Set matrix
    canvas.SetMatrix mapMatrix[0], mapMatrix[1], mapMatrix[2], mapMatrix[3], mapMatrix[4], mapMatrix[5]
    ' canvas.SetMatrix myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD, myMatrix.mTx,myMatrix.mTy
    '
    ' Reset matrix so nothing can move
    ' canvas.SetMatrix 1, 0, 0, 1, 0, 0
    ' ----------------------------------------------------------------------
        drawMap()
        canvas.PopMatrix
        myPoint.mX = x - origin.mX
        myPoint.mY = y - origin.mY
    
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
            
        ' Make the point into the transformed world
        Local testPoint : Point = invMatrix.transformPoint(myPoint)
        canvas.DrawRect origin.mX,origin.mY,1,1
        canvas.DrawText String(origin.mX+Int(testPoint.mX)), 420,0
        canvas.DrawText String(origin.mY+Int(testPoint.mY)), 460,0
    
      canvas.DrawText String(mapMatrix[0]),0,0
     canvas.DrawText String(mapMatrix[1]),0,10
    canvas.DrawText String(mapMatrix[2]),0,20
    canvas.DrawText String(mapMatrix[3]),0,30
    canvas.DrawText String(mapMatrix[4]),0,40
    canvas.DrawText String(mapMatrix[5]),0,50
    
    canvas.Flush
    End Method

    Method drawMap()
        For Local x=0 To 400 Step 100
            canvas.DrawLine x,0,x,300
        Next
        For Local y=0 To 300 Step 100
            canvas.DrawLine 0,y,400,y
        Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2
                canvas.DrawText x+","+y,x-27,y+8
            Next
        Next
    End
 
End Class

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class

Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float

    Method New()
        mA = 1.0 ; mB = 0.0 ; mC = 0.0 ; mD = 1.0 ; mTx = 0.0 ; mTy = 0.0   
    End Method
 
    Method New(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a ; matrix.mB = b ; matrix.mC = c ; matrix.mD = d ; matrix.mTx = tx ; matrix.mTy = ty
    End Function
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method

    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * mA  + matrix.mC * mB
        Local b : Float = matrix.mB * mA  + matrix.mD * mB
        Local c : Float = matrix.mA * mC  + matrix.mC * mD
        Local d : Float = matrix.mB * mC  + matrix.mD * mD
        Local tx : Float = matrix.mA * mTx + matrix.mC * mTy + matrix.mTx
        Local ty : Float = matrix.mB * mTx + matrix.mD * mTy + matrix.mTy
        setValues(a,b,c,d,tx,ty)
    End Method
 
    Method determinant : Float()
            Return (mA * mD) - (mC * mB)
    End Method

    Method translateBy : Void(dx : Float,dy : Float)
        mTx = mTx + dx ; mTy = mTy + dy
    End Method

    Method sBy : Void(s : Float)
        mA = mA * s ; mB = mB * s ; mC = mC * s ; mD = mD * s ; mTx = mTx * s ;  mTy = mTy * s
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        concatMatrix(rotMatrix)
    End Method
 
    Method identity : Void()
        setValues(1.0,0.0,0.0,1.0,0.0,0.0)
    End Method
 
    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det
        Local b : Float = -mB / det
        Local c : Float = -mC / det
        Local d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det
        Local ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx
        Local y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method
 
End Class
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Checked the sourcecode for transform to define a multiply matrix operation, tested

Code:
        Method multiplyMatrix:Void(matrix:Matrix)     
        Local ix:Float = matrix.mA
       Local iy:Float = matrix.mB
       Local jx:Float = matrix.mC
       Local jy:Float = matrix.mD
       Local tx:Float = matrix.mTx
       Local ty:Float = matrix.mTy
        Local ix2:=ix*mA+iy*mC,iy2:=ix*mB+iy*mD
        Local jx2:=jx*mA+jy*mC,jy2:=jx*mB+jy*mD
        Local tx2:=tx*mA+ty*mC+mTx,ty2:=tx*mB+ty*mD+mTy
        setValues ix2,iy2,jx2,jy2,tx2,ty2
    End

Multiply tested using identity matrix etc
Code:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=False

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field origin : Point
    Field canvas : Canvas
    Field ox:Int
    Field oy:Int
    Field x:Int
    Field y:Int
    Field d:Int
    Field mapMatrix:Float[6]
        
    Method OnCreate()
        canvas = New Canvas
        SetSwapInterval 1 ; SetUpdateRate 0
        myMatrix = New Matrix()
        myPoint = New Point()
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
        canvas.GetMatrix(mapMatrix)
        myMatrix.mA = mapMatrix[0]
        myMatrix.mB = mapMatrix[1]
        myMatrix.mC = mapMatrix[2]
        myMatrix.mD = mapMatrix[3]
        myMatrix.mTx = mapMatrix[4]
        myMatrix.mTy = mapMatrix[5]
        
        Local myMatrix2 : Matrix = New Matrix()
        myMatrix.multiplyMatrix(myMatrix2)

    End Method
 
    Method OnUpdate()
            ox = x ; oy = y
            x = TouchX() ; y = TouchY() ; d = TouchDown(0)         
           ' Translate matrix
           If d Then myMatrix.translateBy(x-ox,y-oy)         
           ' scale matrix
           If KeyDown(KEY_UP) Then myMatrix.scaleBy(1.01)
           If KeyDown(KEY_DOWN) Then myMatrix.scaleBy(0.99)
           ' Rotate matrix
           If KeyDown(KEY_LEFT) Then myMatrix.rotateBy(-1)
           If KeyDown(KEY_RIGHT) Then myMatrix.rotateBy(1)
    End Method
 
    Method OnRender()
        canvas.Clear 
        canvas.PushMatrix
        ' origin.mX = 100 ; origin.mY = 100
        canvas.Translate origin.mX,origin.mY
        ' Multiply matrix (might need to mathematically multiply instead for later inverse multiplication)
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy     
        canvas.Translate -origin.mX,-origin.mY   
    ' ----------------------------------------------------------------------
    ' Here you can read the current matrix
    canvas.GetMatrix(mapMatrix)
    '
    ' Fails if you try (they are something you multiply, if you read here they become absolute)
    ' myMatrix.mA = mapMatrix[0] ; myMatrix.mB = mapMatrix[1] ; myMatrix.mC = mapMatrix[2] ; myMatrix.mD = mapMatrix[3] ; myMatrix.mTx = mapMatrix[4] ; myMatrix.mTy = mapMatrix[5]
    '
    ' Set matrix
    canvas.SetMatrix mapMatrix[0], mapMatrix[1], mapMatrix[2], mapMatrix[3], mapMatrix[4], mapMatrix[5]
    ' canvas.SetMatrix myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD, myMatrix.mTx,myMatrix.mTy
    '
    ' Reset matrix so nothing can move
    ' canvas.SetMatrix 1, 0, 0, 1, 0, 0
    
    ' Multiply using math, use identity matrix to proove nothing happens
    Local testMatrix : Matrix = New Matrix(1,0,0,1,0,0)
    myMatrix.multiplyMatrix(testMatrix)

    ' ----------------------------------------------------------------------
        drawMap()
        canvas.PopMatrix
        myPoint.mX = x - origin.mX
        myPoint.mY = y - origin.mY
    
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
            
        ' Make the point into the transformed world
        Local testPoint : Point = invMatrix.transformPoint(myPoint)
        canvas.DrawRect origin.mX,origin.mY,1,1
        canvas.DrawText String(origin.mX+Int(testPoint.mX)), 420,0
        canvas.DrawText String(origin.mY+Int(testPoint.mY)), 460,0
    
      canvas.DrawText String(mapMatrix[0]),0,0
     canvas.DrawText String(mapMatrix[1]),0,10
    canvas.DrawText String(mapMatrix[2]),0,20
    canvas.DrawText String(mapMatrix[3]),0,30
    canvas.DrawText String(mapMatrix[4]),0,40
    canvas.DrawText String(mapMatrix[5]),0,50
    
    canvas.Flush
    End Method

    Method drawMap()
        For Local x=0 To 400 Step 100
            canvas.DrawLine x,0,x,300
        Next
        For Local y=0 To 300 Step 100
            canvas.DrawLine 0,y,400,y ; Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2 ; canvas.DrawText x+","+y,x-27,y+8
            Next
        Next
    End
 
End Class

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class

Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float

    Method New()
        mA = 1.0 ; mB = 0.0 ; mC = 0.0 ; mD = 1.0 ; mTx = 0.0 ; mTy = 0.0   
    End Method
 
    Method New(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a ; matrix.mB = b ; matrix.mC = c ; matrix.mD = d ; matrix.mTx = tx ; matrix.mTy = ty
    End Function
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method

    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * mA  + matrix.mC * mB
        Local b : Float = matrix.mB * mA  + matrix.mD * mB
        Local c : Float = matrix.mA * mC  + matrix.mC * mD
        Local d : Float = matrix.mB * mC  + matrix.mD * mD
        Local tx : Float = matrix.mA * mTx + matrix.mC * mTy + matrix.mTx
        Local ty : Float = matrix.mB * mTx + matrix.mD * mTy + matrix.mTy
        setValues(a,b,c,d,tx,ty)
    End Method
    
        Method multiplyMatrix:Void(matrix:Matrix)     
        Local ix:Float = matrix.mA
       Local iy:Float = matrix.mB
       Local jx:Float = matrix.mC
       Local jy:Float = matrix.mD
       Local tx:Float = matrix.mTx
       Local ty:Float = matrix.mTy
        Local ix2:=ix*mA+iy*mC,iy2:=ix*mB+iy*mD
        Local jx2:=jx*mA+jy*mC,jy2:=jx*mB+jy*mD
        Local tx2:=tx*mA+ty*mC+mTx,ty2:=tx*mB+ty*mD+mTy
        setValues ix2,iy2,jx2,jy2,tx2,ty2
    End

    Method determinant : Float()
            Return (mA * mD) - (mC * mB)
    End Method

    Method translateBy : Void(dx : Float,dy : Float)
        mTx = mTx + dx ; mTy = mTy + dy
    End Method

    Method scaleBy : Void(s : Float)
        mA = mA * s ; mB = mB * s ; mC = mC * s ; mD = mD * s ; mTx = mTx * s ;  mTy = mTy * s
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        concatMatrix(rotMatrix)
    End Method
 
    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det
        Local b : Float = -mB / det
        Local c : Float = -mC / det
        Local d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det
        Local ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx
        Local y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method
 
End Class
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
This allows origin point using right mouseclick, but jerks once while you do it, if you've zoomed or rotated already (If this is anywhere close to JS in how it works this is probably because not all matrix actions is not commutative).

EDIT Cleaned it up a bit
All the needed hardware-matrix commands mathematically implemented in 199 LOC Cerberus code.


Code:
Import mojo2
#MOJO_AUTO_SUSPEND_ENABLED=False
#HTML5_CONSOLE_SHOW = False

Function Main()
    New MyApp
End Function

Class MyApp Extends App

    Field myMatrix : Matrix
    Field myPoint : Point
    Field origin : Point
    Field canvas : Canvas
    Field ox:Int, oy:Int, x:Int, y:Int, d:Int
    Field mapMatrix:Float[6]
       
    Method OnCreate()
        canvas = New Canvas
        SetSwapInterval 1 ; SetUpdateRate 0
        myMatrix = New Matrix()
        myPoint = New Point()
        origin = New Point(DeviceWidth() / 2.0,DeviceHeight() / 2.0)
        canvas.GetMatrix(mapMatrix)
       
        myMatrix.mA = mapMatrix[0] ; myMatrix.mB = mapMatrix[1]
        myMatrix.mC = mapMatrix[2] ; myMatrix.mD = mapMatrix[3]
        myMatrix.mTx = mapMatrix[4] ; myMatrix.mTy = mapMatrix[5]
        Local myMatrix2 : Matrix = New Matrix()
        myMatrix.multiplyMatrix(myMatrix2)
    End Method
 
    Method OnUpdate()
   
        ox = x ; oy = y ; x = TouchX() ; y = TouchY() ; d = TouchDown(0)
     
        ' Translate matrix
        If d Then myMatrix.translateBy(x-ox,y-oy)        

        ' Scale matrix
        If KeyDown(KEY_UP) Then myMatrix.scaleBy(1.01)
        If KeyDown(KEY_DOWN) Then myMatrix.scaleBy(0.99)
       
        ' Rotate matrix
        If KeyDown(KEY_LEFT) Then myMatrix.rotateBy(-1)
        If KeyDown(KEY_RIGHT) Then myMatrix.rotateBy(1)
       
        ' ---------------------------------------------------------------------
        ' Rightclick to set origin on SCREEN not OBJECT
        If Not d And MouseDown(1) Then origin.mX = x ; origin.mY = y
        '
        ' Rightclick to set origin on OBJECT not SCREEN
        '
        ' ---------------------------------------------------------------------
       
    End Method
 
    Method OnRender()
        canvas.Clear
        canvas.PushMatrix
        canvas.Translate origin.mX,origin.mY
        canvas.Transform myMatrix.mA,myMatrix.mB,myMatrix.mC,myMatrix.mD,myMatrix.mTx,myMatrix.mTy ' Multiply matrix using canvas command
        canvas.Translate -origin.mX,-origin.mY
         
        ' ----------------------------------------------------------------------
        ' Read current hardware matrix
        canvas.GetMatrix(mapMatrix)
        ' myMatrix.mA = mapMatrix[0] ; myMatrix.mB = mapMatrix[1] ; myMatrix.mC = mapMatrix[2]
        ' myMatrix.mD = mapMatrix[3] ; myMatrix.mTx = mapMatrix[4] ; myMatrix.mTy = mapMatrix[5]
       
        ' Set matrix (here to the absolute value from the read above, just to prove nothing happens, Matrix stays to whatever it is)
        canvas.SetMatrix mapMatrix[0], mapMatrix[1], mapMatrix[2], mapMatrix[3], mapMatrix[4], mapMatrix[5]

        ' Multiply Matrix (here using identity matrix just to prove nothing happens, Matrix stays to whatever it is)
        Local testMatrix : Matrix = New Matrix(1,0,0,1,0,0) ' Create a matrix to multiply myMatrix with
        myMatrix.multiplyMatrix(testMatrix)
        ' ----------------------------------------------------------------------
       
        drawMap()
        canvas.PopMatrix
       
        ' ----------------------------------------------------------------------
        ' READ COORDINATE USING MULTIPLICATION OF INVERSE AKA NEGATIVE MATRIX
        myPoint.mX = x - origin.mX ; myPoint.mY = y - origin.mY
   
        ' Inverse matrix
        Local invMatrix : Matrix = myMatrix.clone()
        invMatrix.invert()
           
        ' Make the point into the transformed world
        Local testPoint : Point = invMatrix.transformPoint(myPoint)
        canvas.DrawText String(origin.mX+Int(testPoint.mX)), 420,0
        canvas.DrawText String(origin.mY+Int(testPoint.mY)), 460,0
        ' ----------------------------------------------------------------------
       
        canvas.DrawRect origin.mX,origin.mY,1,1
        canvas.DrawText String(mapMatrix[0]),0,0
        canvas.DrawText String(mapMatrix[1]),0,10
        canvas.DrawText String(mapMatrix[2]),0,20
        canvas.DrawText String(mapMatrix[3]),0,30
        canvas.DrawText String(mapMatrix[4]),0,40
        canvas.DrawText String(mapMatrix[5]),0,50
        canvas.Flush
    End Method

    Method drawMap()
        For Local x=0 To 400 Step 100 ; canvas.DrawLine x,0,x,300 ; Next ' Draw a grid, horisontal..
        For Local y=0 To 300 Step 100 ; canvas.DrawLine 0,y,400,y ; Next ' ..and vertical lines
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2 ; canvas.DrawText x+","+y,x-27,y+8
            Next
        Next
    End

End Class

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class

Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float
 
    Method New(a : Float = 1.0 ,b : Float = 0.0,c : Float = 0.0,d : Float = 1.0,tx : Float = 0.0,ty : Float = 0.0) ' default = identity matrix
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Function setValues(matrix : Matrix,a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        matrix.mA = a ; matrix.mB = b ; matrix.mC = c ; matrix.mD = d ; matrix.mTx = tx ; matrix.mTy = ty
    End Function
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method

    Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * mA  + matrix.mC * mB
        Local b : Float = matrix.mB * mA  + matrix.mD * mB
        Local c : Float = matrix.mA * mC  + matrix.mC * mD
        Local d : Float = matrix.mB * mC  + matrix.mD * mD
        Local tx : Float = matrix.mA * mTx + matrix.mC * mTy + matrix.mTx
        Local ty : Float = matrix.mB * mTx + matrix.mD * mTy + matrix.mTy
        setValues(a,b,c,d,tx,ty)
    End Method
   
    Method multiplyMatrix:Void(matrix:Matrix)    
        Local ix:Float = matrix.mA,iy:Float = matrix.mB,jx:Float = matrix.mC
        Local jy:Float = matrix.mD,tx:Float = matrix.mTx, ty:Float = matrix.mTy
        Local ix2:=ix*mA+iy*mC,iy2:=ix*mB+iy*mD
        Local jx2:=jx*mA+jy*mC,jy2:=jx*mB+jy*mD
        Local tx2:=tx*mA+ty*mC+mTx,ty2:=tx*mB+ty*mD+mTy
        setValues ix2,iy2,jx2,jy2,tx2,ty2
    End

    Method determinant : Float()
        Return (mA * mD) - (mC * mB)
    End Method

    Method translateBy : Void(dx : Float,dy : Float)
        mTx = mTx + dx ; mTy = mTy + dy
    End Method

    Method scaleBy : Void(s : Float)
        mA = mA * s ; mB = mB * s ; mC = mC * s ; mD = mD * s ; mTx = mTx * s ;  mTy = mTy * s
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        concatMatrix(rotMatrix)
    End Method
 
    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det, b : Float = -mB / det
        Local c : Float = -mC / det, d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det
        Local ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx
        Local y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method

End Class
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Here's a working conversion of Mojo2!

EDIT Added Mousewheel zooming
EDIT commented out Mousewheel as WIP (Mousewheel appearently outputs garbage when you do other things with the touchpad so it's a small project to handle that neatly).


Code:
Import mojo2

Function Main()
    New TransformMapApp
End

Class TransformMapApp Extends App

    Field mx#,my#
    Field tmx#,tmy#
    Field omx#,omy#
    Field mapMatrix:Matrix
    Field canvas:Canvas
    Field agetmatrix:Float[6]
 
    Method OnCreate()
        SetUpdateRate 0
        canvas = New Canvas()
        mapMatrix = New Matrix()
  
        ' Read current matrix, and becuase there's two types currently in use, there's an ugly conversion between 6floatarray to matrix-type
        canvas.PushMatrix
        canvas.Scale DeviceWidth()/400.0, DeviceHeight()/300.0
        canvas.GetMatrix(agetmatrix)
        canvas.PopMatrix
        mapMatrix.mA = agetmatrix[0] ; mapMatrix.mB = agetmatrix[1]
        mapMatrix.mC = agetmatrix[2] ; mapMatrix.mD = agetmatrix[3]
        mapMatrix.mTx = agetmatrix[4] ; mapMatrix.mTy = agetmatrix[5]
    End
 
    Method OnUpdate()
        Local coords:Point
        mx = MouseX() ; my = MouseY()
        canvas.PushMatrix
        canvas.Translate mx,my
        canvas.Rotate (KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT))*1.5
        Local s# = 1+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN))*.01
    
  '   s = s + MouseZ() * .03

        canvas.Scale s,s
        canvas.Translate -mx,-my

        canvas.Transform mapMatrix.mA,mapMatrix.mB,mapMatrix.mC,mapMatrix.mD,mapMatrix.mTx,mapMatrix.mTy   
      
            Local invMatrix : Matrix = mapMatrix.clone() ; invMatrix.invert()
            coords = invMatrix.transformPoint(New Point(mx,my))
            tmx = coords.mX ; tmy = coords.mY
 
            If TouchDown(0) Then canvas.Translate tmx-omx, tmy-omy
            canvas.GetMatrix(agetmatrix)
            mapMatrix.mA = agetmatrix[0]
            mapMatrix.mB = agetmatrix[1]
            mapMatrix.mC = agetmatrix[2]
            mapMatrix.mD = agetmatrix[3]
            mapMatrix.mTx = agetmatrix[4]
            mapMatrix.mTy = agetmatrix[5]
      
            invMatrix = mapMatrix.clone() ; invMatrix.invert()
            coords = invMatrix.transformPoint(New Point(mx,my))
            omx = coords.mX ; omy = coords.mY
  
            canvas.PopMatrix
    End
 
    Method OnRender()
        canvas.Clear
        canvas.SetColor 1,1,1
        canvas.PushMatrix
  
        canvas.Transform mapMatrix.mA,mapMatrix.mB,mapMatrix.mC,mapMatrix.mD,mapMatrix.mTx,mapMatrix.mTy

        drawMap
        canvas.DrawText Int(omx)+","+Int(omy),omx,omy-12
 
       canvas.PopMatrix 
        canvas.Flush
    End

    Method drawMap()
        For Local x=0 To 400 Step 100 ; canvas.DrawLine x,0,x,300 ; Next
        For Local y=0 To 300 Step 100 ; canvas.DrawLine 0,y,400,y ; Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2 ; canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
End

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class
 
Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float
 
    Method New(a : Float = 1.0 ,b : Float = 0.0,c : Float = 0.0,d : Float = 1.0,tx : Float = 0.0,ty : Float = 0.0)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
        Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * Self.mA  + matrix.mC * Self.mB
        Local b : Float = matrix.mB * Self.mA  + matrix.mD * Self.mB
        Local c : Float = matrix.mA * Self.mC  + matrix.mC * Self.mD
        Local d : Float = matrix.mB * Self.mC  + matrix.mD * Self.mD
        Local tx : Float = matrix.mA * Self.mTx + matrix.mC * Self.mTy + matrix.mTx
        Local ty : Float = matrix.mB * Self.mTx + matrix.mD * Self.mTy + matrix.mTy
        Self.setValues(a,b,c,d,tx,ty)
    End Method
 
    Method multiplyMatrix:Void(matrix:Matrix)
        Local ix:Float = matrix.mA,iy:Float = matrix.mB,jx:Float = matrix.mC
        Local jy:Float = matrix.mD,tx:Float = matrix.mTx, ty:Float = matrix.mTy
        Local ix2:=ix*mA+iy*mC,iy2:=ix*mB+iy*mD,jx2:=jx*mA+jy*mC,jy2:=jx*mB+jy*mD,tx2:=tx*mA+ty*mC+mTx,ty2:=tx*mB+ty*mD+mTy
        setValues ix2,iy2,jx2,jy2,tx2,ty2
    End

    Method determinant : Float()
        Return (mA * mD) - (mC * mB)
    End Method
 
    Method translateBy : Void(dx : Float,dy : Float)
        Self.mTx = Self.mTx + dx
        Self.mTy = Self.mTy + dy
    End Method

    Method scaleBy : Void(sx : Float,sy : Float)
        Self.mA = Self.mA * sx
        Self.mB = Self.mB * sy
        Self.mC = Self.mC * sx
        Self.mD = Self.mD * sy
        Self.mTx = Self.mTx * sx
        Self.mTy = Self.mTy * sy
    End Method

    Method scaleBy : Void(scale : Float)
        Self.scaleBy(scale,scale)
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        Self.concatMatrix(rotMatrix)
    End Method

    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det, b : Float = -mB / det, c : Float = -mC / det, d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det, ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx, y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method

End Class
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Comparing the speed of Cerberus Matrix handling wiith lots of other languages, including Wonkey. Cerberus actually is over 16msec faster so basically one frame ahead. I'm so happy to be able to do a reaction mini-game finally.

I just don't like how this example was written in a mix of OnUpdate and OnRender, both containing PushMatrix PopMatrix etc. It makes the code hard to follow in a way so amm thinking of rewriting it to use only OnRender and put all inputs in variables using OnUpdate, would that be a good idea? OnUpdate for inputs, OnRender for outputs, so to speak? Anyways, it's working fine.
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Here's the final one with input and rendering separated sucessfully.

The scale var was initially 0. You can't rely on that onUpdate will run before onRender and set the variable to be used in OnRender so I had to preset the variable to scale to 1 just in case OnRender runs before any inputs is loaded into it.

Code:
Import mojo2

Function Main()
    New TransformMapApp
End

Class TransformMapApp Extends App

    Field mx#,my#
    Field tmx#,tmy#
    Field omx#,omy#
    Field mapMatrix:Matrix
    Field canvas:Canvas
    Field agetmatrix:Float[6]
    Field s:Float = 1
    Field r:Float = 0
    Field d:Float
    
    Method OnCreate()
        SetUpdateRate 0
        canvas = New Canvas()
        mapMatrix = New Matrix()
 
        ' Read current matrix, and becuase there's two types currently in use, there's an ugly conversion between 6floatarray to matrix-type
        canvas.PushMatrix
        canvas.Scale DeviceWidth()/400.0, DeviceHeight()/300.0
        canvas.GetMatrix(agetmatrix)
        canvas.PopMatrix
        mapMatrix.mA = agetmatrix[0] ; mapMatrix.mB = agetmatrix[1]
        mapMatrix.mC = agetmatrix[2] ; mapMatrix.mD = agetmatrix[3]
        mapMatrix.mTx = agetmatrix[4] ; mapMatrix.mTy = agetmatrix[5]
    End
 
    Method OnUpdate()
        d = TouchDown(0)
        mx = TouchX(0) ; my = TouchY(0)
        r = (KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT))*1.5
        s = 1+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN))*.01
        ' s = s + MouseZ() * .03
    End
 
    Method OnRender()
        canvas.Clear
  
        canvas.PushMatrix
        canvas.Translate mx,my
       canvas.Rotate r
        canvas.Scale s,s
        canvas.Translate -mx,-my
        canvas.Transform mapMatrix.mA,mapMatrix.mB,mapMatrix.mC,mapMatrix.mD,mapMatrix.mTx,mapMatrix.mTy                   
        Local invMatrix : Matrix = mapMatrix.clone() ; invMatrix.invert()
        Local coords:Point = invMatrix.transformPoint(New Point(mx,my))
        tmx = coords.mX ; tmy = coords.mY
        If d Then canvas.Translate tmx-omx, tmy-omy
        canvas.GetMatrix(agetmatrix)
        mapMatrix.mA = agetmatrix[0]
        mapMatrix.mB = agetmatrix[1]
        mapMatrix.mC = agetmatrix[2]
        mapMatrix.mD = agetmatrix[3]
        mapMatrix.mTx = agetmatrix[4]
        mapMatrix.mTy = agetmatrix[5]
        invMatrix = mapMatrix.clone() ; invMatrix.invert()
        coords = invMatrix.transformPoint(New Point(mx,my))
        omx = coords.mX ; omy = coords.mY
        canvas.PopMatrix
        
        canvas.PushMatrix
        canvas.Transform mapMatrix.mA,mapMatrix.mB,mapMatrix.mC,mapMatrix.mD,mapMatrix.mTx,mapMatrix.mTy
        drawMap
        canvas.DrawText Int(omx)+","+Int(omy),omx,omy-12
        canvas.PopMatrix
        canvas.Flush
    End

    Method drawMap()
        For Local x=0 To 400 Step 100 ; canvas.DrawLine x,0,x,300 ; Next
        For Local y=0 To 300 Step 100 ; canvas.DrawLine 0,y,400,y ; Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2 ; canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
End

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class
 
Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float
 
    Method New(a : Float = 1.0 ,b : Float = 0.0,c : Float = 0.0,d : Float = 1.0,tx : Float = 0.0,ty : Float = 0.0)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
        Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * Self.mA  + matrix.mC * Self.mB
        Local b : Float = matrix.mB * Self.mA  + matrix.mD * Self.mB
        Local c : Float = matrix.mA * Self.mC  + matrix.mC * Self.mD
        Local d : Float = matrix.mB * Self.mC  + matrix.mD * Self.mD
        Local tx : Float = matrix.mA * Self.mTx + matrix.mC * Self.mTy + matrix.mTx
        Local ty : Float = matrix.mB * Self.mTx + matrix.mD * Self.mTy + matrix.mTy
        Self.setValues(a,b,c,d,tx,ty)
    End Method
 
    Method multiplyMatrix:Void(matrix:Matrix)
        Local ix:Float = matrix.mA,iy:Float = matrix.mB,jx:Float = matrix.mC
        Local jy:Float = matrix.mD,tx:Float = matrix.mTx, ty:Float = matrix.mTy
        Local ix2:=ix*mA+iy*mC,iy2:=ix*mB+iy*mD,jx2:=jx*mA+jy*mC,jy2:=jx*mB+jy*mD,tx2:=tx*mA+ty*mC+mTx,ty2:=tx*mB+ty*mD+mTy
        setValues ix2,iy2,jx2,jy2,tx2,ty2
    End

    Method determinant : Float()
        Return (mA * mD) - (mC * mB)
    End Method
 
    Method translateBy : Void(dx : Float,dy : Float)
        Self.mTx = Self.mTx + dx
        Self.mTy = Self.mTy + dy
    End Method

    Method scaleBy : Void(sx : Float,sy : Float)
        Self.mA = Self.mA * sx
        Self.mB = Self.mB * sy
        Self.mC = Self.mC * sx
        Self.mD = Self.mD * sy
        Self.mTx = Self.mTx * sx
        Self.mTy = Self.mTy * sy
    End Method

    Method scaleBy : Void(scale : Float)
        Self.scaleBy(scale,scale)
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        Self.concatMatrix(rotMatrix)
    End Method

    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det, b : Float = -mB / det, c : Float = -mC / det, d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det, ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx, y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method

End Class
 
Last edited:

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
If you want to take a 2d Matrix and extract scale from it this is how you do it.

Code:
Import mojo2

Function Main()
    New TransformMapApp
End

Class TransformMapApp Extends App

    Field mx#,my#
    Field tmx#,tmy#
    Field omx#,omy#
    Field mapMatrix:Matrix
    Field canvas:Canvas
    Field agetmatrix:Float[6]
    Field s:Float = 1
    Field r:Float = 0
    Field d:Float
    
    Method OnCreate()
        SetUpdateRate 0
        canvas = New Canvas()
        mapMatrix = New Matrix()
 
        ' Read current matrix, and becuase there's two types currently in use, there's an ugly conversion between 6floatarray to matrix-type
        canvas.PushMatrix
        canvas.Scale DeviceWidth()/400.0, DeviceHeight()/300.0
        canvas.GetMatrix(agetmatrix)
        canvas.PopMatrix
        mapMatrix.mA = agetmatrix[0] ; mapMatrix.mB = agetmatrix[1]
        mapMatrix.mC = agetmatrix[2] ; mapMatrix.mD = agetmatrix[3]
        mapMatrix.mTx = agetmatrix[4] ; mapMatrix.mTy = agetmatrix[5]
    End
 
    Method OnUpdate()
        d = TouchDown(0)
        mx = TouchX(0) ; my = TouchY(0)
        r = (KeyDown(KEY_LEFT)-KeyDown(KEY_RIGHT))*1.5
        s = 1+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN))*.01
        ' s = s + MouseZ() * .03
    End
 
    Method OnRender()
        canvas.Clear
    
        canvas.PushMatrix
        canvas.Translate mx,my
       canvas.Rotate r   ' relative change that are stored
        canvas.Scale s,s  ' relative change that are stored
        canvas.Translate -mx,-my
        canvas.Transform mapMatrix.mA,mapMatrix.mB,mapMatrix.mC,mapMatrix.mD,mapMatrix.mTx,mapMatrix.mTy                   
        Local invMatrix : Matrix = mapMatrix.clone() ; invMatrix.invert()
        Local coords:Point = invMatrix.transformPoint(New Point(mx,my))
        tmx = coords.mX ; tmy = coords.mY
        If d Then canvas.Translate tmx-omx, tmy-omy
        canvas.GetMatrix(agetmatrix)
        mapMatrix.mA = agetmatrix[0]
        mapMatrix.mB = agetmatrix[1]
        mapMatrix.mC = agetmatrix[2]
        mapMatrix.mD = agetmatrix[3]
        mapMatrix.mTx = agetmatrix[4]
        mapMatrix.mTy = agetmatrix[5]
        invMatrix = mapMatrix.clone() ; invMatrix.invert()
        coords = invMatrix.transformPoint(New Point(mx,my))
        omx = coords.mX ; omy = coords.mY
        canvas.PopMatrix
        
        canvas.PushMatrix
        canvas.Transform mapMatrix.mA,mapMatrix.mB,mapMatrix.mC,mapMatrix.mD,mapMatrix.mTx,mapMatrix.mTy
    
      ' How to set Matrix in an absolute way using only math and a final SetMatrix hardware command:
       ' If MouseDown(1)
       ' ' How set position and scale
       ' Local tempmatrix : Matrix = New Matrix() ' Identity matrix is the default new matrix when no parameters given
       ' tempmatrix.translateBy 100,100    ' x & y
       ' tempmatrix.scaleBy 3.2,3.2        ' Scale
       ' canvas.SetMatrix tempmatrix.mA,tempmatrix.mB,tempmatrix.mC,tempmatrix.mD,tempmatrix.mTx,tempmatrix.mTy 
      ' Endif
      
        drawMap
        canvas.DrawText Int(omx)+","+Int(omy),omx,omy-12
        canvas.PopMatrix
        
        ' Extract scale & rotation from matric and print them
        canvas.DrawText "SCALE = " + (getScaleX(mapMatrix)),0,0 ' any will do as both are the same here
     '   canvas.DrawText "ROTATION = " + (getRotation(mapMatrix)),0,20
        canvas.Flush
    End
    
    Method getScaleX:Float(m:Matrix)
        Return Sqrt((m.mA * m.mA) + (m.mC * m.mC))
        ' Return Sqrt(Pow(m.mA + m.mB, 2))
    End

    Method getScaleY:Float(m:Matrix)
        ' Return Sqrt(Pow(m.mC + m.mD, 2))
        Return Sqrt((m.mB * m.mB) + (m.mD * m.mD))
    End   
    
    'Method getRotation:Float(m:Matrix)
    '    Return (m.mA / getScaleX(m) )
    '    ' Return m.mD / getScaleY(m)
        
    #REM HOW EXTRACT ROTATION
                scaleX = Sqrt((a * a) + (c * c))
                scaleY = Sqrt((b * b) + (d * d))
                sign = Atan(-c / a);
                rad  = Acos(a / scaleX)
                deg  = rad * degree
                if (deg > 90 And sign > 0)
                    rotation = (360 - deg) * radian
                elseif (deg < 90 And sign < 0)
                    rotation = (360 - deg) * radian
                else
                    rotation = rad
                EndIf
                 rotationInDegree = rotation * degree
               ' EndIf
            return dmat
                 End
    #END

    
    Method drawMap()
        For Local x=0 To 400 Step 100 ; canvas.DrawLine x,0,x,300 ; Next
        For Local y=0 To 300 Step 100 ; canvas.DrawLine 0,y,400,y ; Next
        For Local x=50 To 400 Step 100
            For Local y=50 To 300 Step 100
                canvas.DrawCircle x,y,2 ; canvas.DrawText x+","+y,x+2,y+2
            Next
        Next
    End
End

Class Point

    Field mX : Float, mY : Float

    Method New(x : Float,y : Float)
        mX = x ; mY = y
    End Method

End Class
 
Class Matrix

    Field mA : Float, mB : Float, mC : Float, mD : Float, mTx : Float, mTy : Float
 
    Method New(a : Float = 1.0 ,b : Float = 0.0,c : Float = 0.0,d : Float = 1.0,tx : Float = 0.0,ty : Float = 0.0)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
    Method clone : Matrix()
        Return New Matrix(mA,mB,mC,mD,mTx,mTy)
    End Method
 
    Method setValues(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
        mA = a ; mB = b ; mC = c ; mD = d ; mTx = tx ; mTy = ty
    End Method
 
        Method concatMatrix : Void(matrix : Matrix)
        Local a : Float = matrix.mA * Self.mA  + matrix.mC * Self.mB
        Local b : Float = matrix.mB * Self.mA  + matrix.mD * Self.mB
        Local c : Float = matrix.mA * Self.mC  + matrix.mC * Self.mD
        Local d : Float = matrix.mB * Self.mC  + matrix.mD * Self.mD
        Local tx : Float = matrix.mA * Self.mTx + matrix.mC * Self.mTy + matrix.mTx
        Local ty : Float = matrix.mB * Self.mTx + matrix.mD * Self.mTy + matrix.mTy
        Self.setValues(a,b,c,d,tx,ty)
    End Method
 
    Method multiplyMatrix:Void(matrix:Matrix)
        Local ix:Float = matrix.mA,iy:Float = matrix.mB,jx:Float = matrix.mC
        Local jy:Float = matrix.mD,tx:Float = matrix.mTx, ty:Float = matrix.mTy
        Local ix2:=ix*mA+iy*mC,iy2:=ix*mB+iy*mD,jx2:=jx*mA+jy*mC,jy2:=jx*mB+jy*mD,tx2:=tx*mA+ty*mC+mTx,ty2:=tx*mB+ty*mD+mTy
        setValues ix2,iy2,jx2,jy2,tx2,ty2
    End

    Method determinant : Float()
        Return (mA * mD) - (mC * mB)
    End Method
 
    Method translateBy : Void(dx : Float,dy : Float)
        Self.mTx = Self.mTx + dx
        Self.mTy = Self.mTy + dy
    End Method

    Method scaleBy : Void(sx : Float,sy : Float)
        Self.mA = Self.mA * sx
        Self.mB = Self.mB * sy
        Self.mC = Self.mC * sx
        Self.mD = Self.mD * sy
        Self.mTx = Self.mTx * sx
        Self.mTy = Self.mTy * sy
    End Method

    Method scaleBy : Void(scale : Float)
        Self.scaleBy(scale,scale)
    End Method

    Method rotateBy : Void(angle : Float)
        Local rotMatrix : Matrix = New Matrix(Cos(angle),Sin(angle),-Sin(angle),Cos(angle),0,0)
        Self.concatMatrix(rotMatrix)
    End Method

    Method invert : Void()
        Local det : Float = determinant()
        Local a : Float = mD / det, b : Float = -mB / det, c : Float = -mC / det, d : Float = mA / det
        Local tx : Float = ((mC * mTy) - (mD * mTx)) / det, ty : Float = ((mB * mTx) - (mA * mTy)) / det
        setValues(a,b,c,d,tx,ty)
    End Method

    Method transformPoint : Point(point : Point)
        Local x : Float = (mA * point.mX) + (mC * point.mY) + mTx, y : Float = (mB * point.mX) + (mD * point.mY) + mTy
        Return New Point(x,y)
    End Method

End Class
 
Last edited:
Top Bottom