///|
/// Matrix decomposition for interactive editors and animation systems.
pub(all) struct MatrixDecomposition {
translation : Vec2
rotation : Double
scale : Vec2
determinant : Double
} derive(Eq, Debug, ToJson)
///|
pub fn Matrix2D::determinant(self : Matrix2D) -> Double {
self.a * self.d - self.b * self.c
}
///|
pub fn Matrix2D::is_identity(
self : Matrix2D,
epsilon? : Double = 0.000000001,
) -> Bool {
(self.a - 1.0).abs() <= epsilon &&
self.b.abs() <= epsilon &&
self.c.abs() <= epsilon &&
(self.d - 1.0).abs() <= epsilon &&
self.tx.abs() <= epsilon &&
self.ty.abs() <= epsilon
}
///|
pub fn Matrix2D::inverse(self : Matrix2D) -> Matrix2D? {
let det = self.determinant()
if det.abs() <= 0.000000000001 {
None
} else {
let inverse_det = 1.0 / det
Some({
a: self.d * inverse_det,
b: -self.b * inverse_det,
c: -self.c * inverse_det,
d: self.a * inverse_det,
tx: (self.c * self.ty - self.d * self.tx) * inverse_det,
ty: (self.b * self.tx - self.a * self.ty) * inverse_det,
})
}
}
///|
pub fn Matrix2D::decompose(self : Matrix2D) -> MatrixDecomposition {
let scale_x = Vec2::new(self.a, self.b).length()
let determinant = self.determinant()
let scale_y = if scale_x == 0.0 { 0.0 } else { determinant / scale_x }
{
translation: Vec2::new(self.tx, self.ty),
rotation: @math.atan2(self.b, self.a),
scale: Vec2::new(scale_x, scale_y),
determinant,
}
}
///|
pub fn Matrix2D::around(self : Matrix2D, center : Vec2) -> Matrix2D {
Matrix2D::translate(center.x, center.y)
.multiply(self)
.multiply(Matrix2D::translate(-center.x, -center.y))
}
///|
pub fn Matrix2D::map_rect(self : Matrix2D, rect : Rect) -> Rect {
let corners = [
Vec2::new(rect.x, rect.y),
Vec2::new(rect.right(), rect.y),
Vec2::new(rect.right(), rect.bottom()),
Vec2::new(rect.x, rect.bottom()),
]
let transformed = []
for corner in corners {
let (x, y) = self.transform_point(corner.x, corner.y)
transformed.push(Vec2::new(x, y))
}
bounds_of_points(transformed)
}
///|
pub fn interpolate_matrix(
start : Matrix2D,
end : Matrix2D,
amount : Double,
) -> Matrix2D {
let t = if amount < 0.0 { 0.0 } else if amount > 1.0 { 1.0 } else { amount }
{
a: start.a + (end.a - start.a) * t,
b: start.b + (end.b - start.b) * t,
c: start.c + (end.c - start.c) * t,
d: start.d + (end.d - start.d) * t,
tx: start.tx + (end.tx - start.tx) * t,
ty: start.ty + (end.ty - start.ty) * t,
}
}