///|
/// 2D affine transformation matrix
/// | a b tx |
/// | c d ty |
/// | 0 0 1 |
pub struct Transform {
a : Double
b : Double
c : Double
d : Double
tx : Double
ty : Double
} derive(Eq, Debug)
///|
pub extend Transform with Debug::{to_repr}
///|
pub extend Transform with Eq::{not_equal, equal}
///|
/// Create an identity transform
pub fn Transform::identity() -> Transform {
{ a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0, }
}
///|
/// Create an arbitrary affine transform.
pub fn Transform::affine(
a~ : Double,
b~ : Double,
c~ : Double,
d~ : Double,
tx~ : Double,
ty~ : Double,
) -> Transform {
{ a, b, c, d, tx, ty, }
}
///|
/// Create a translation transform
pub fn Transform::translate(tx~ : Double, ty~ : Double) -> Transform {
{ a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx, ty, }
}
///|
/// Create a scale transform
pub fn Transform::scale(sx~ : Double, sy~ : Double) -> Transform {
{ a: sx, b: 0.0, c: 0.0, d: sy, tx: 0.0, ty: 0.0, }
}
///|
/// Create a rotation transform (angle in radians)
pub fn Transform::rotate(angle : Double) -> Transform {
let cos_a = @math.cos(angle)
let sin_a = @math.sin(angle)
{ a: cos_a, b: -sin_a, c: sin_a, d: cos_a, tx: 0.0, ty: 0.0, }
}
///|
/// Apply transform to a point
pub fn Transform::apply(
self : Transform,
x : Double,
y : Double,
) -> (Double, Double) {
let new_x = self.a * x + self.b * y + self.tx
let new_y = self.c * x + self.d * y + self.ty
(new_x, new_y)
}
///|
/// Multiply two transforms
pub fn Transform::multiply(self : Transform, other : Transform) -> Transform {
{
a: self.a * other.a + self.b * other.c,
b: self.a * other.b + self.b * other.d,
c: self.c * other.a + self.d * other.c,
d: self.c * other.b + self.d * other.d,
tx: self.a * other.tx + self.b * other.ty + self.tx,
ty: self.c * other.tx + self.d * other.ty + self.ty,
}
}
///|
/// Return the inverse transform if this matrix is invertible.
pub fn Transform::inverse(self : Transform) -> Transform? {
let determinant = self.a * self.d - self.b * self.c
guard determinant.abs() > 0.000000001 else { return None }
Some({
a: self.d / determinant,
b: -self.b / determinant,
c: -self.c / determinant,
d: self.a / determinant,
tx: (self.b * self.ty - self.d * self.tx) / determinant,
ty: (self.c * self.tx - self.a * self.ty) / determinant,
})
}