# Matrix useful for physics, collision and loads more

#### Jimmy

##### Active Member
3rd Party Module Dev
Tutorial Author
Cerberus X:
``````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 debugOn : Bool = False
Field canvas : Canvas

Method OnCreate()
canvas = New Canvas
' Vertical blanking
SetSwapInterval 1 ; SetUpdateRate 0
' Creates a new identity matrix
myMatrix = New Matrix()
' Creates a new point
myPoint = New Point()
' Creates a rectangle
myRect = New Rectangle(-100,-100,200,200)
' Stores origin
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)

' Scale matrix (free dimensions)
If KeyDown(KEY_W) Then myMatrix.scaleBy(1,1.1)
If KeyDown(KEY_S) Then myMatrix.scaleBy(1,0.9)
If KeyDown(KEY_A) Then myMatrix.scaleBy(1.1,1)
If KeyDown(KEY_D) Then myMatrix.scaleBy(0.9,1)

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

' Shear matrix
If KeyDown(KEY_1) Then myMatrix.shearBy(0.1,0)
If KeyDown(KEY_2) Then myMatrix.shearBy(-0.1,0)
If KeyDown(KEY_3) Then myMatrix.shearBy(0,0.1)
If KeyDown(KEY_4) Then myMatrix.shearBy(0,-0.1)

End Method

Method OnRender()
canvas.Clear 0,0,0
canvas.PushMatrix
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.SetColor 1,1,1
canvas.DrawRect origin.mX + myRect.mX,origin.mY + myRect.mY,myRect.mWidth,myRect.mHeight
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)

' Draws debug stuff
If debugOn = True

' Draws original outline rectangle shape
canvas.SetColor 0,0,1
canvas.DrawLine origin.mX + myRect.mX,origin.mY + myRect.mY,origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mY
canvas.DrawLine origin.mX + myRect.mX,origin.mY + myRect.mHeight / 2.0,origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mHeight / 2.0
canvas.DrawLine origin.mX + myRect.mX,origin.mY + myRect.mY,origin.mX + myRect.mX,origin.mY + myRect.mHeight / 2.0
canvas.DrawLine origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mY,origin.mX + myRect.mWidth / 2.0,origin.mY + myRect.mHeight / 2.0
canvas.SetColor 1,1,1
canvas.DrawText testPoint.mX + "," + testPoint.mY,0,0

' Draws test marker
canvas.SetColor 1,0,0
canvas.DrawOval origin.mX + testPoint.mX - 4,origin.mY + testPoint.mY - 4,8,8
Endif

' Checks if touching inside the shape
If TouchDown(0)
' Simple rectangle check as the point has been transformed
If myRect.containsPoint(testPoint) Then canvas.SetColor 1,0,0 ; canvas.DrawText "Point Inside Rect!",origin.mX,50,0.5,0.5
Endif
canvas.Flush
End Method

End Class

' The Point Class describes a two dimensional point Or vector.

Class Point

Field mX : Float
Field mY : Float

' Initializes a point with its x And y components. _Designated Initializer_.
Method New(x : Float,y : Float)
Self.mX = x
Self.mY = y
End Method

Function pointWithPolarLength : Point(length : Float,angle : Float)
Return New Point(Cos(angle) * length,Sin(angle) * length)
End Function

Function pointWithXY : Point(x : Float,y : Float)
Return New Point(x,y)
End Function

Function pointZero : Point()
Return New Point(0,0)
End Function

' Calculates the distance between two points.
Function distanceFromPoint : Float(p1 : Point,p2 : Point)
Local diff : Point = p1.subtractPoint(p2)
Return Sqr((diff.mX * diff.mX) + (diff.mY * diff.mY))
End Function

' Determines a point between two specified points. `ratio = 0 -> p1,ratio = 1 -> p2
Function interpolateFromPoint : Point(p1 : Point,p2 : Point,ratio : Float)
Local invRation = 1.0 - ratio
Local x : Float = (invRatio * p1.mX) + (ratio * p2.mX)
Local y : Float = (invRatio * p1.mY) + (ratio * p2.mY)
Return New Point(x,y)
End Function

' Clones point
Method clone : Point()
Return New Point(Self.mX,Self.mY)
End Method

' Length of vector
Method length : Float()
Return Sqr((Self.mX * Self.mX) + (Self.mY * Self.mY))
End Method

' Angle of vector
Method angle : Float()
Return ATan2(Self.mY,Self.mX)
End Method

' Adds a point To the current point And returns the resulting point.
Method addPoint : Point(point : Point)
Return New Point(point.mX + Self.mY,point.mY + Self.mY)
End Method

' Substracts a point from the current point And returns the resulting point.
Method subtractPoint : Point(point : Point)
Return New Point(point.mX - Self.mX,point.mY - Self.mY)
End Method

' Scales the point by a certain factor And returns the resulting point.
Method scaleBy : Point(scalar : Float)
Return New Point(Self.mX * scalar,Self.mY * scalar)
End Method

' Scales the line segment between the origin And the current point To one.
Method normalize : Point()
If Self.mX = 0 And Self.mY = 0
Error("Cannot mormalize a point in the origin")
Else
Local inverseLength : Float = 1.0 / Self.length()
Return New Point(Self.mX * inverseLength,Self.mY * inverseLength)
Endif
End Method

' Compares two points.
Method isEqual : Bool(other : Point)
If other = Self Then Return True
Return (Self.mX = point.mX) And (Self.mY = point.mY)
End Method

' Calculates the distance between two points.
Method distanceFromPoint : Float(point : Point)
Local diff : Point = Self.subtractPoint(point)
Return Sqr((diff.mX * diff.mX) + (diff.mY * diff.mY))
End Method

' Determines a point between two specified points. `ratio = 0 -> self,ratio = 1 -> point
Method interpolateFromPoint : Point(point : Point,ratio : Float)
Local invRation = 1.0 - ratio
Local x : Float = (invRatio * Self.mX) + (ratio * point.mX)
Local y : Float = (invRatio * Self.mY) + (ratio * point.mY)
Return New Point(x,y)
End Method

' Returns a string containing the components of the point
Method description : String()
Return "(x: " + Self.mX + ",y: " + Self.mY + ")"
End Method

End Class

' The Rectangle Class describes a rectangle by its top-left corner point (x,y) And by its width And height.

Class Rectangle

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

' Initializes a rectangle
Method New()
Self.mX = 0
Self.mY = 0
Self.mWidth = 0
Self.mHeight = 0
End Method

' Initializes a rectangle with the specified components
Method New(x : Float,y : Float,width : Float,height : Float)
Self.mX = x
Self.mY = y
Self.mWidth = width
Self.mHeight = height
End Method

Function rectangleWithValues : Rectangle(x : Float,y : Float,width : Float,height : Float)
Return New Rectangle(x,y,width,height)
End Function

' Clone rectangle
Method clone : Rectangle()
Return New Rectangle(Self.mX,Self.mY,Self.mWidth,Self.mHeight)
End Method

' Determines If a point is within the rectangle.
Method containsXY : Bool(x : Float,y : Float)
Return (x >= mX) And (y >= mY) And (x <= mX + mWidth) And (y <= mY + mHeight)
End Method

' Determines If a point is within the rectangle.
Method containsPoint : Bool(point : Point)
Return Self.containsXY(point.mX,point.mY)
End Method

' Determines If another rectangle is within the rectangle.
Method containsRectangle : Bool(rectangle : Rectangle)
Local rX : Float = rectangle.mX
Local rY : Float = rectangle.mY
Local rWidth : Float = rectangle.mWidth
Local rHeight : Float = rectangle.mHeight
Return (rX >= Self.mX) And (rX + rWidth <= mX + mWidth) And (rY >= mY) And (rY + rHeight <= mY + mHeight)
End Method

' Determines If another rectangle contains Or intersects the rectangle.
Method intersectsRectangle:Bool(rectangle : Rectangle)
Local rX : Float = rectangle.mX
Local rY : Float = rectangle.mY
Local rWidth : Float = rectangle.mWidth
Local rHeight : Float = rectangle.mHeight
Local outside : Bool = (rX <= Self.mX And rX + rWidth <= Self.mX) Or (rX >= Self.mX + Self.mWidth And rX + rWidth >= Self.mX + Self.mWidth) Or (rY <= Self.mY And rY + rHeight <= Self.mY) Or (rY >= Self.mY + Self.mHeight And rY + rHeight >= Self.mY + Self.mHeight)
Return Not outside
End Method

' If the specified rectangle intersects with the rectangle,returns the area of intersection.
Method intersectionWithRectangle : Rectangle(rectangle : Rectangle)
Local left : Float = Max(Self.mX,rectangle.mX)
Local right : Float = Min(Self.mX + Self.mWidth,rectangle.mX + rectangle.mWidth)
Local top : Float = Max(Self.mY,rectangle.mY)
Local bottom : Float = Min(Self.mY + Self.mHeight,rectangle.mY + rectangle.mHeight)
If (left > right Or top > bottom)
Return New Rectangle(0,0,0,0)
Else
Return New Rectangle(left,top,right - left,bottom - top)
Endif
End Method

' Adds two rectangles together To create a New Rectangle Object (by filling in the space between the two rectangles).
Method uniteWithRectangle : Rectangle(rectangle : Rectangle)
Local left : Float = Min(Self.mX,rectangle.mX)
Local right : Float = Max(Self.mX + Self.mWidth,rectangle.mX + rectangle.mWidth)
Local top : Float = Min(Self.mY,rectangle.mY)
Local bottom : Float = Max(Self.mY + Self.mHeight,rectangle.mY + rectangle.mHeight)
Return New Rectangle(left,top,right - left,bottom - top)
End Method

' Sets x,y,width And height components To zero.
Method setEmpty()
Self.mX = 0
Self.mY = 0
Self.mWidth = 0
Self.mHeight = 0
End Method

' Checks if width or height components are zero.
Method isEmpty : Bool()
Return (Self.mWidth = 0) Or (Self.mHeight = 0)
End Method

' Checks if two rectangles are equal
Method isEqual : Bool(rectangle : Rectangle)
If rectangle = Self Then Return True
Return (Self.mX = rectangle.mX) And (Self.mY = rectangle.mY) And (Self.mWidth = rectangle.mWidth) And (Self.mHeight = rectangle.mHeight)
End Method

' Returns a string containing the components of the rectangle
Method description : String()
Return "(x: " + Self.mX + ",y: " + Self.mY + " width: " + Self.mWidth + " height: " + Self.mHeight + ")"
End Method

End Class

' ------------------------------------------------------------------------------------------------
'  The Matrix Class describes an affine 2D transformation Matrix. It provides methods To
'  manipulate the matrix in convenient ways, and can be used To transform points.
'
'  The matrix has the following form:
'      |a c tx|
'      |b d ty|
'      |0 0  1|
' -------------------------------------------------------------------------------------------------

Class Matrix

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

' Initializes an identity matrix.
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

' Initializes a matrix with the specified components.
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 matrixWithValues : Matrix(a : Float,b : Float,c : Float,d : Float,tx : Float,ty : Float)
Return New Matrix(a,b,c,d,tx,ty)
End Function

Function matrixWithIdentity : Matrix()
Return New Matrix()
End Function

' Setter
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

' Compares two matrices.
Method isEqual : Bool(other : Matrix)
If other = Self Then Return True
Return (other.mA = Self.mA) And (other.mB = Self.mB) And (other.mC = Self.mC) And (other.mD = Self.mD) And (other.mTx = Self.mTx) And (other.mTy = Self.mTy)
End Method

' Clone matrix
Method clone : Matrix()
Return New Matrix(Self.mA,Self.mB,Self.mC,Self.mD,Self.mTx,Self.mTy)
End Method

' Sets a matrix with the with the specified components
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

' Concatenates a matrix with the current matrix,combining the geometric effects of the two.
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

' Determinate of matrix
Method determinant : Float()
Return (Self.mA * Self.mD) - (Self.mC * Self.mB)
End Method

' Translates the matrix along the x And y axes.
Method translateBy : Void(dx : Float,dy : Float)
Self.mTx = Self.mTx + dx
Self.mTy = Self.mTy + dy
End Method

' Applies a scaling transformation To the matrix.
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

' Applies a uniform scaling transformation To the matrix.
Method scaleBy : Void(scale : Float)
Self.scaleBy(scale,scale)
End Method

' Applies a rotation on the matrix.
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

' Applies a shearing transformation To the matrix.
Method shearBy : Void(sx : Float,sy : Float)
Self.mC = Self.mC + sx
Self.mB = Self.mB + sy
End Method

' Applies a uniform shearing transformation To the matrix.
Method shearBy : Void(shear : Float)
Self.mC = Self.mC * shear
Self.mB = Self.mB * shear
End Method

' Sets each matrix Property To a value that causes a Null transformation.
Method identity : Void()
Self.setValues(1.0,0.0,0.0,1.0,0.0,0.0)
End Method

' Performs the opposite transformation of the matrix.
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

' Applies the geometric transformation represented by the matrix To the specified point.
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

' Returns a string containing the components of the matrix
Method description : String()
Return "(a = " + Self.mA + "," + "b = " + Self.mB + "," + "c = " + Self.mC + "," + "d = " + Self.mD + "," + "tx = " + Self.mTx + "," + "ty = " + Self.mTy + ")"
End Method

End Class``````

Last edited: