///|
/// A compact two-by-two matrix for projected tolerance transforms.
pub struct Matrix2 {
m11 : Double
m12 : Double
m21 : Double
m22 : Double
} derive(Debug, Eq)
///|
/// Construct a matrix from row-major entries.
pub fn Matrix2::new(
m11 : Double,
m12 : Double,
m21 : Double,
m22 : Double,
) -> Matrix2 {
{ m11, m12, m21, m22 }
}
///|
/// Construct the identity matrix.
pub fn Matrix2::identity() -> Matrix2 {
{ m11: 1.0, m12: 0.0, m21: 0.0, m22: 1.0 }
}
///|
/// Construct a two-dimensional rotation matrix.
pub fn Matrix2::rotation(angle_radians : Double) -> Matrix2 {
let cosine = @math.cos(angle_radians)
let sine = @math.sin(angle_radians)
{ m11: cosine, m12: -sine, m21: sine, m22: cosine }
}
///|
/// Construct a diagonal scale matrix.
pub fn Matrix2::scale(x : Double, y : Double) -> Matrix2 {
{ m11: x, m12: 0.0, m21: 0.0, m22: y }
}
///|
/// Apply the matrix to a vector.
pub fn Matrix2::apply(self : Matrix2, vector : Vector2) -> Vector2 {
Vector2::new(
self.m11 * vector.x + self.m12 * vector.y,
self.m21 * vector.x + self.m22 * vector.y,
)
}
///|
/// Multiply two matrices.
pub fn Matrix2::multiply(self : Matrix2, other : Matrix2) -> Matrix2 {
{
m11: self.m11 * other.m11 + self.m12 * other.m21,
m12: self.m11 * other.m12 + self.m12 * other.m22,
m21: self.m21 * other.m11 + self.m22 * other.m21,
m22: self.m21 * other.m12 + self.m22 * other.m22,
}
}
///|
/// Return the transpose.
pub fn Matrix2::transpose(self : Matrix2) -> Matrix2 {
{ m11: self.m11, m12: self.m21, m21: self.m12, m22: self.m22 }
}
///|
/// Return the determinant.
pub fn Matrix2::determinant(self : Matrix2) -> Double {
self.m11 * self.m22 - self.m12 * self.m21
}
///|
/// Return the inverse, if the determinant is non-zero.
pub fn Matrix2::inverse(self : Matrix2) -> Matrix2? {
let determinant = self.determinant()
if determinant == 0.0 {
None
} else {
Some({
m11: self.m22 / determinant,
m12: -self.m12 / determinant,
m21: -self.m21 / determinant,
m22: self.m11 / determinant,
})
}
}
///|
/// Return the matrix as an orthonormal transform within tolerance.
pub fn Matrix2::is_orthonormal(self : Matrix2) -> Bool {
let product = self.transpose().multiply(self)
product.m11.is_close(1.0, absolute_tolerance=0.000000001) &&
product.m22.is_close(1.0, absolute_tolerance=0.000000001) &&
product.m12.is_close(0.0, absolute_tolerance=0.000000001) &&
product.m21.is_close(0.0, absolute_tolerance=0.000000001)
}
///|
/// A rigid or affine two-dimensional transform.
pub struct Transform2 {
linear : Matrix2
translation : Vector2
} derive(Debug, Eq)
///|
/// Construct a transform from a linear matrix and translation.
pub fn Transform2::new(linear : Matrix2, translation : Vector2) -> Transform2 {
{ linear, translation }
}
///|
/// Apply a transform to a point.
pub fn Transform2::apply(self : Transform2, point : Vector2) -> Vector2 {
self.linear.apply(point).add(self.translation)
}
///|
/// Compose this transform after another transform.
pub fn Transform2::compose(self : Transform2, other : Transform2) -> Transform2 {
{
linear: self.linear.multiply(other.linear),
translation: self.linear.apply(other.translation).add(self.translation),
}
}
///|
/// Return the inverse transform when its linear part is invertible.
pub fn Transform2::inverse(self : Transform2) -> Transform2? {
match self.linear.inverse() {
None => None
Some(linear) =>
Some({ linear, translation: linear.apply(self.translation.scale(-1.0)) })
}
}