- Joined
- Jan 2, 2020
- Messages
- 1,414
Cerberus:
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: