matrix_2d 0.1.0

A matrix implementation that mimics what the canvas matrix functions do on html5 canvas.
Documentation

#[derive(Copy, Clone, Debug)]
pub struct Matrix2D {
  pub a: f64,
  pub b: f64,
  pub c: f64,
  pub d: f64,
  pub e: f64,
  pub f: f64,
}

pub enum Matrix2DTransformError {
  DeterminantIsZero,
}

impl Matrix2D {
  pub fn new() -> Matrix2D {
    Matrix2D {
      a: 1f64,
      b: 0f64,
      c: 0f64,
      d: 1f64,
      e: 0f64,
      f: 0f64,
    }
  }

  pub fn between(from: &Matrix2D, to: &Matrix2D, ratio: f64) -> Matrix2D {
    Matrix2D {
      a: from.a + (to.a - from.a) * ratio,
      b: from.b + (to.b - from.b) * ratio,
      c: from.c + (to.c - from.c) * ratio,
      d: from.d + (to.d - from.d) * ratio,
      e: from.e + (to.e - from.e) * ratio,
      f: from.f + (to.f - from.f) * ratio,
    }
  }

  pub fn translate_mut(&mut self, x: f64, y: f64) {
    self.e += self.a * x + self.c * y;
    self.f += self.b * x + self.d * y;
  }

  pub fn translate(mut self, x: f64, y: f64) -> Matrix2D {
    self.translate_mut(x, y);
    self
  }

  pub fn scale_mut(&mut self, x: f64, y: f64) {
    self.a *= x;
    self.b *= x;
    self.c *= y;
    self.d *= y;
  }

  pub fn scale(mut self, x: f64, y: f64) -> Matrix2D {
    self.scale_mut(x, y);
    self
  }

  pub fn rotate_mut(&mut self, angle: f64) {
    let cos = angle.cos();
    let sin = angle.sin();
    let Matrix2D { a, b, c, d, .. } = *self;
    self.a = a * cos + c * sin;
    self.b = b * cos + d * sin;
    self.c = c * cos - a * sin;
    self.d =  d * cos - b * sin;
  }

  pub fn rotate(mut self, angle: f64) -> Matrix2D {
    self.rotate_mut(angle);
    self
  }

  pub fn skew_x_mut(&mut self, angle: f64) {
    let tan = angle.tan();
    self.c += self.a * tan;
    self.d += self.b * tan;
  }

  pub fn skew_x(mut self, angle: f64) -> Matrix2D {
    self.skew_x_mut(angle);
    self
  }

  pub fn skew_y_mut(&mut self, angle: f64) {
    let tan = angle.tan();
    self.a += self.c * tan;
    self.b += self.d * tan;
  }

  pub fn skew_y(mut self, angle: f64) -> Matrix2D {
    self.skew_y_mut(angle);
    self
  }

  pub fn transform_mut(&mut self, matrix: &Matrix2D) {
    self.transform_values_mut(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f);
  }

  pub fn transform_values_mut(&mut self, pa: f64, pb: f64, pc: f64, pd: f64, pe: f64, pf: f64) {
    let a = self.a;
    let b = self.b;
    let c = self.c;
    let d = self.d;
    self.a = a * pa + c * pb;
    self.b = b * pa + d * pb;
    self.c = a * pc + c * pd;
    self.d = b * pc + d * pd;
    self.e += a * pe + c * pf;
    self.f += b * pe + d * pf;
  }

  pub fn transform(mut self, matrix: &Matrix2D) -> Matrix2D {
    self.transform_mut(matrix);
    self
  }

  pub fn transform_values(mut self, pa: f64, pb: f64, pc: f64, pd: f64, pe: f64, pf: f64) -> Matrix2D {
    self.transform_values_mut(pa, pb, pc, pd, pe, pf);
    self
  }

  pub fn reset_mut(&mut self) {
    self.set_mut(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
  }

  pub fn set_mut(&mut self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
    self.a = a;
    self.b = b;
    self.c = c;
    self.d = d;
    self.e = e;
    self.f = f;
  }

  pub fn det(&self) -> f64 {
    self.a * self.d - self.b * self.c
  }

  pub fn inverse_mut(&mut self) -> Result<(), Matrix2DTransformError> {
    let mut det = self.det();
    if det == 0f64 {
      return Err(Matrix2DTransformError::DeterminantIsZero);
    }
    det = 1f64 / det;
    let a = self.d * det;
    let b = -self.b * det;
    let c = -self.c * det;
    let d = self.a * det;
    let e = (self.c * self.f - self.e * self.d) * det;
    let f = (self.e * self.b - self.a * self.f) * det;
    self.a = a;
    self.b = b;
    self.c = c;
    self.d = d;
    self.e = e;
    self.f = f;
    Ok(())
  }

  pub fn inverse(mut self) -> Result<Matrix2D, Matrix2DTransformError> {
    self.inverse_mut()?;
    Ok(self)
  }
}