153 lines
5.3 KiB
Lua
153 lines
5.3 KiB
Lua
local slickmath = require("slick.util.slickmath")
|
|
|
|
--- Represents a transform.
|
|
--- @class slick.geometry.transform
|
|
--- @field private immutable boolean
|
|
--- @field x number
|
|
--- @field y number
|
|
--- @field rotation number
|
|
--- @field private rotationCos number
|
|
--- @field private rotationSin number
|
|
--- @field scaleX number
|
|
--- @field scaleY number
|
|
--- @field offsetX number
|
|
--- @field offsetY number
|
|
local transform = {}
|
|
local metatable = { __index = transform }
|
|
|
|
--- Constructs a new transform.
|
|
--- @param x number? translation on the x axis (defaults to 0)
|
|
--- @param y number? translation on the y axis (defaults to 0)
|
|
--- @param rotation number? rotation in radians (defaults to 0)
|
|
--- @param scaleX number? scale along the x axis (defaults to 1)
|
|
--- @param scaleY number? scale along the y axis (defaults to 1)
|
|
--- @param offsetX number? offset along the x axis (defaults to 0)
|
|
--- @param offsetY number? offsete along the y axis (defaults to 0)
|
|
function transform.new(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
local result = setmetatable({}, metatable)
|
|
result:setTransform(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
result.immutable = false
|
|
|
|
return result
|
|
end
|
|
|
|
--- @package
|
|
--- @param x number? translation on the x axis (defaults to 0)
|
|
--- @param y number? translation on the y axis (defaults to 0)
|
|
--- @param rotation number? rotation in radians (defaults to 0)
|
|
--- @param scaleX number? scale along the x axis (defaults to 1)
|
|
--- @param scaleY number? scale along the y axis (defaults to 1)
|
|
--- @param offsetX number? offset along the x axis (defaults to 0)
|
|
--- @param offsetY number? offsete along the y axis (defaults to 0)
|
|
function transform._newImmutable(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
local result = setmetatable({}, metatable)
|
|
result:setTransform(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
result.immutable = true
|
|
|
|
return result
|
|
end
|
|
|
|
--- Same as setTransform.
|
|
--- @param x number? translation on the x axis
|
|
--- @param y number? translation on the y axis
|
|
--- @param rotation number? rotation in radians
|
|
--- @param scaleX number? scale along the x axis
|
|
--- @param scaleY number? scale along the y axis
|
|
--- @param offsetX number? offset along the x axis
|
|
--- @param offsetY number? offsete along the y axis
|
|
--- @see slick.geometry.transform.setTransform
|
|
function transform:init(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
self:setTransform(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
end
|
|
|
|
--- Constructs a transform.
|
|
--- @param x number? translation on the x axis
|
|
--- @param y number? translation on the y axis
|
|
--- @param rotation number? rotation in radians
|
|
--- @param scaleX number? scale along the x axis
|
|
--- @param scaleY number? scale along the y axis
|
|
--- @param offsetX number? offset along the x axis
|
|
--- @param offsetY number? offsete along the y axis
|
|
function transform:setTransform(x, y, rotation, scaleX, scaleY, offsetX, offsetY)
|
|
self.x = x or self.x or 0
|
|
self.y = y or self.y or 0
|
|
self.rotation = rotation or self.rotation or 0
|
|
self.rotationCos = math.cos(self.rotation)
|
|
self.rotationSin = math.sin(self.rotation)
|
|
self.scaleX = scaleX or self.scaleX or 1
|
|
self.scaleY = scaleY or self.scaleY or 1
|
|
self.offsetX = offsetX or self.offsetX or 0
|
|
self.offsetY = offsetY or self.offsetY or 0
|
|
end
|
|
|
|
--- Transforms (x, y) by the transform and returns the transformed coordinates.
|
|
--- @param x number
|
|
--- @param y number
|
|
--- @return number x
|
|
--- @return number y
|
|
function transform:transformPoint(x, y)
|
|
local ox = x - self.offsetX
|
|
local oy = y - self.offsetY
|
|
local rx = ox * self.rotationCos - oy * self.rotationSin
|
|
local ry = ox * self.rotationSin + oy * self.rotationCos
|
|
local sx = rx * self.scaleX
|
|
local sy = ry * self.scaleY
|
|
local resultX = sx + self.x
|
|
local resultY = sy + self.y
|
|
|
|
return resultX, resultY
|
|
end
|
|
|
|
--- Transforms the normal (x, y) by this transform.
|
|
--- This is essentially the inverse-transpose of just the rotation and scale components.
|
|
--- @param x number
|
|
--- @param y number
|
|
--- @return number x
|
|
--- @return number y
|
|
function transform:transformNormal(x, y)
|
|
local sx = x / self.scaleX
|
|
local sy = y / self.scaleY
|
|
local resultX = sx * self.rotationCos - sy * self.rotationSin
|
|
local resultY = sx * self.rotationSin + sy * self.rotationCos
|
|
|
|
return resultX, resultY
|
|
end
|
|
|
|
--- Transforms (x, y) by the inverse of the transform and returns the inverse transformed coordinates.
|
|
--- @param x number
|
|
--- @param y number
|
|
--- @return number x
|
|
--- @return number y
|
|
function transform:inverseTransformPoint(x, y)
|
|
local tx = x - self.x
|
|
local ty = y - self.y
|
|
local sx = tx / self.scaleX
|
|
local sy = ty / self.scaleY
|
|
local rx = sx * self.rotationCos + sy * self.rotationSin
|
|
local ry = sy * self.rotationCos - sx * self.rotationSin
|
|
local resultX = rx + self.offsetX
|
|
local resultY = ry + self.offsetY
|
|
|
|
return resultX, resultY
|
|
end
|
|
|
|
--- Copies this transform to `other`.
|
|
--- @param other slick.geometry.transform
|
|
function transform:copy(other)
|
|
assert(not other.immutable)
|
|
|
|
other.x = self.x
|
|
other.y = self.y
|
|
other.rotation = self.rotation
|
|
other.rotationCos = self.rotationCos
|
|
other.rotationSin = self.rotationSin
|
|
other.scaleX = self.scaleX
|
|
other.scaleY = self.scaleY
|
|
other.offsetX = self.offsetX
|
|
other.offsetY = self.offsetY
|
|
end
|
|
|
|
transform.IDENTITY = transform._newImmutable()
|
|
|
|
return transform
|