1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//!
//! Ported from [elm-lang's Transform2D module]
//! (https://github.com/elm-lang/core/blob/62b22218c42fb8ccc996c86bea450a14991ab815/src/Transform2D.elm)
//!
//!
//! A library for performing 2D matrix transformations. It is used primarily with the
//! `group_transform` function from the `form` module and allows you to do things like rotation,
//! scaling, translation, shearing and reflection.
//!
//! Note that all the matrices in this library are 3*3 matrices of homogeneous coordinates, used
//! for affine transformations. Since the bottom row is always `0 0 1` in these matrices, it is
//! omitted in the diagrams below.
//!


use vecmath::{mat2x3_id, Matrix2x3, row_mat2x3_mul};

pub type Matrix2d = Matrix2x3<f64>;

/// Represents a 2D transform.
#[derive(Clone, Debug)]
pub struct Transform2D(pub Matrix2d);

impl Transform2D {

    /// Multiply two transforms together.
    ///
    ///   ma mb mx     na nb nx
    ///   mc md my  .  nc nd ny
    ///    0  0  1      0  0  1
    ///
    #[inline]
    pub fn multiply(self, other: Transform2D) -> Transform2D {
        let (Transform2D(m), Transform2D(n)) = (self, other);
        Transform2D(row_mat2x3_mul(m, n))
    }

}

/// Create an identity transform. Transforming by the identity does not change anything, but it can
/// come in handy as a default or base case.
///
///   1 0 0
///   0 1 0
///
#[inline]
pub fn identity() -> Transform2D {
    Transform2D(mat2x3_id())
}

/// Creates a transformation matrix. This lets you create transforms such as scales, shears,
/// reflections and translations.
///
///   a b x
///   c d y
///
#[inline]
pub fn matrix(a: f64, b: f64, c: f64, d: f64, x: f64, y: f64) -> Transform2D {
    Transform2D([ [a, b, x], [c, d, y] ])
}

/// Create a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix). Given an angle t, it
/// creates a counterclockwise rotation matrix.
///
///   cos t  -sin t  0
///   sin t   cos t  0
///
#[inline]
pub fn rotation(t: f64) -> Transform2D {
    Transform2D([ [t.cos(), -t.sin(), 0.0], [t.sin(), t.cos(), 0.0] ])
}

/// Creates a transformation matrix for translation.
///
///   1 0 x
///   0 1 y
///
#[inline]
pub fn translation(x: f64, y: f64) -> Transform2D {
    matrix(1.0, 0.0, 0.0, 1.0, x, y)
}

/// Creates a transformation matrix for scaling by all directions.
///
///   s 0 0
///   0 s 0
///
#[inline]
pub fn scale(s: f64) -> Transform2D {
    matrix(s, 0.0, 0.0, s, 0.0, 0.0)
}

/// Creates a transformation for horizontal scaling.
#[inline]
pub fn scale_x(s: f64) -> Transform2D {
    matrix(s, 0.0, 0.0, 1.0, 0.0, 0.0)
}

/// Creates a transformation for vertical scaling.
#[inline]
pub fn scale_y(s: f64) -> Transform2D {
    matrix(1.0, 0.0, 0.0, s, 0.0, 0.0)
}