use std::f32::consts::PI;
use std::fmt::{self, Display};
use std::ops::Mul;
#[derive(Clone, Copy, Debug)]
pub enum JoinStyle {
Miter,
Round,
Bevel,
}
#[derive(Clone, Copy, Debug)]
pub enum CapStyle {
Butt,
Round,
ProjectingSquare,
}
#[derive(Clone, Copy, Debug)]
pub enum Color {
#[doc(hidden)]
RGB { red: u8, green: u8, blue: u8 },
#[doc(hidden)]
Gray { gray: u8 },
}
impl Color {
pub fn rgb(red: u8, green: u8, blue: u8) -> Self {
Color::RGB { red, green, blue }
}
pub fn gray(gray: u8) -> Self {
Color::Gray { gray }
}
}
pub struct Matrix {
v: [f32; 6],
}
impl Matrix {
pub fn translate(dx: f32, dy: f32) -> Self {
Matrix {
v: [1., 0., 0., 1., dx, dy],
}
}
pub fn rotate(a: f32) -> Self {
Matrix {
v: [a.cos(), a.sin(), -a.sin(), a.cos(), 0., 0.],
}
}
pub fn rotate_deg(a: f32) -> Self {
Self::rotate(a * PI / 180.)
}
pub fn scale(sx: f32, sy: f32) -> Self {
Matrix {
v: [sx, 0., 0., sy, 0., 0.],
}
}
pub fn uniform_scale(s: f32) -> Self {
Self::scale(s, s)
}
pub fn skew(a: f32, b: f32) -> Self {
Matrix {
v: [1., a.tan(), b.tan(), 1., 0., 0.],
}
}
}
impl Display for Matrix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let v = self.v;
write!(f, "{} {} {} {} {} {}", v[0], v[1], v[2], v[3], v[4], v[5])
}
}
impl Mul for Matrix {
type Output = Self;
fn mul(self, b: Self) -> Self {
let a = self.v;
let b = b.v;
Matrix {
v: [
a[0] * b[0] + a[1] * b[2],
a[0] * b[1] + a[1] * b[3],
a[2] * b[0] + a[3] * b[2],
a[2] * b[1] + a[3] * b[3],
a[4] * b[0] + a[5] * b[2] + b[4],
a[4] * b[1] + a[5] * b[3] + b[5],
],
}
}
}
#[cfg(test)]
mod tests {
use super::Matrix;
use std::f32::consts::PI;
#[test]
fn test_matrix_mul_a() {
assert_unit(Matrix::rotate_deg(45.) * Matrix::rotate_deg(-45.));
}
#[test]
fn test_matrix_mul_b() {
assert_unit(Matrix::uniform_scale(2.) * Matrix::uniform_scale(0.5));
}
#[test]
fn test_matrix_mul_c() {
assert_unit(Matrix::rotate(2. * PI));
}
#[test]
fn test_matrix_mul_d() {
assert_unit(Matrix::rotate(PI) * Matrix::uniform_scale(-1.));
}
fn assert_unit(m: Matrix) {
assert_eq!(None, diff(&[1., 0., 0., 1., 0., 0.], &m.v));
}
fn diff(a: &[f32; 6], b: &[f32; 6]) -> Option<String> {
let large_a = a.iter().fold(0f32, |x, &y| x.max(y));
let large_b = b.iter().fold(0f32, |x, &y| x.max(y));
let epsilon = 1e-6 * large_a.max(large_b);
for i in 0..6 {
if (a[i] - b[i]).abs() > epsilon {
return Some(format!("{:?} != {:?}", a, b));
}
}
None
}
}