use serde_derive::{Deserialize, Serialize};
use crate::units::Pt;
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", tag = "type", content = "data")]
pub enum CurTransMat {
Translate(Pt, Pt),
Rotate(f32),
TranslateRotate(Pt, Pt, f32),
Scale(f32, f32),
Raw([f32; 6]),
Identity,
}
impl PartialEq for CurTransMat {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl CurTransMat {
pub fn as_css_val(&self) -> String {
let m = self.as_array();
format!(
"matrix({} {} {} {} {} {})",
m[0], m[1], m[2], m[3], m[4], m[5]
)
}
pub fn combine_matrix(a: [f32; 6], b: [f32; 6]) -> [f32; 6] {
let a = [
[a[0], a[1], 0.0, 0.0],
[a[2], a[3], 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[a[4], a[5], 0.0, 1.0],
];
let b = [
[b[0], b[1], 0.0, 0.0],
[b[2], b[3], 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[b[4], b[5], 0.0, 1.0],
];
let result = [
[
mul_add(
a[0][0],
b[0][0],
mul_add(
a[0][1],
b[1][0],
mul_add(a[0][2], b[2][0], a[0][3] * b[3][0]),
),
),
mul_add(
a[0][0],
b[0][1],
mul_add(
a[0][1],
b[1][1],
mul_add(a[0][2], b[2][1], a[0][3] * b[3][1]),
),
),
mul_add(
a[0][0],
b[0][2],
mul_add(
a[0][1],
b[1][2],
mul_add(a[0][2], b[2][2], a[0][3] * b[3][2]),
),
),
mul_add(
a[0][0],
b[0][3],
mul_add(
a[0][1],
b[1][3],
mul_add(a[0][2], b[2][3], a[0][3] * b[3][3]),
),
),
],
[
mul_add(
a[1][0],
b[0][0],
mul_add(
a[1][1],
b[1][0],
mul_add(a[1][2], b[2][0], a[1][3] * b[3][0]),
),
),
mul_add(
a[1][0],
b[0][1],
mul_add(
a[1][1],
b[1][1],
mul_add(a[1][2], b[2][1], a[1][3] * b[3][1]),
),
),
mul_add(
a[1][0],
b[0][2],
mul_add(
a[1][1],
b[1][2],
mul_add(a[1][2], b[2][2], a[1][3] * b[3][2]),
),
),
mul_add(
a[1][0],
b[0][3],
mul_add(
a[1][1],
b[1][3],
mul_add(a[1][2], b[2][3], a[1][3] * b[3][3]),
),
),
],
[
mul_add(
a[2][0],
b[0][0],
mul_add(
a[2][1],
b[1][0],
mul_add(a[2][2], b[2][0], a[2][3] * b[3][0]),
),
),
mul_add(
a[2][0],
b[0][1],
mul_add(
a[2][1],
b[1][1],
mul_add(a[2][2], b[2][1], a[2][3] * b[3][1]),
),
),
mul_add(
a[2][0],
b[0][2],
mul_add(
a[2][1],
b[1][2],
mul_add(a[2][2], b[2][2], a[2][3] * b[3][2]),
),
),
mul_add(
a[2][0],
b[0][3],
mul_add(
a[2][1],
b[1][3],
mul_add(a[2][2], b[2][3], a[2][3] * b[3][3]),
),
),
],
[
mul_add(
a[3][0],
b[0][0],
mul_add(
a[3][1],
b[1][0],
mul_add(a[3][2], b[2][0], a[3][3] * b[3][0]),
),
),
mul_add(
a[3][0],
b[0][1],
mul_add(
a[3][1],
b[1][1],
mul_add(a[3][2], b[2][1], a[3][3] * b[3][1]),
),
),
mul_add(
a[3][0],
b[0][2],
mul_add(
a[3][1],
b[1][2],
mul_add(a[3][2], b[2][2], a[3][3] * b[3][2]),
),
),
mul_add(
a[3][0],
b[0][3],
mul_add(
a[3][1],
b[1][3],
mul_add(a[3][2], b[2][3], a[3][3] * b[3][3]),
),
),
],
];
[
result[0][0],
result[0][1],
result[1][0],
result[1][1],
result[3][0],
result[3][1],
]
}
}
#[inline(always)]
fn mul_add(a: f32, b: f32, c: f32) -> f32 {
if cfg!(all(
target_arch = "arm",
target_os = "linux",
target_env = "gnu"
)) {
(a * b) + c
} else {
a.mul_add(b, c)
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum TextMatrix {
Translate(Pt, Pt),
TranslateRotate(Pt, Pt, f32),
Raw([f32; 6]),
}
impl PartialEq for TextMatrix {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl TextMatrix {
pub fn as_css_val(&self, invert_y: bool) -> String {
let m = self.as_array();
let factor = if invert_y { -1.0 } else { 1.0 };
format!(
"matrix({} {} {} {} {} {})",
m[0],
m[1],
m[2],
m[3],
m[4],
m[5] * factor
)
}
pub fn as_array(&self) -> [f32; 6] {
use self::TextMatrix::*;
match self {
Translate(x, y) => {
[1.0, 0.0, 0.0, 1.0, x.0, y.0]
}
Raw(r) => *r,
TranslateRotate(x, y, rot) => {
let rad = (360.0 - rot).to_radians();
[rad.cos(), -rad.sin(), rad.sin(), rad.cos(), x.0, y.0]
}
}
}
}
impl CurTransMat {
pub fn as_array(&self) -> [f32; 6] {
use self::CurTransMat::*;
match self {
Translate(x, y) => {
[1.0, 0.0, 0.0, 1.0, x.0, y.0]
}
TranslateRotate(x, y, rot) => {
let rad = (360.0 - rot).to_radians();
[rad.cos(), -rad.sin(), rad.sin(), rad.cos(), x.0, y.0]
}
Rotate(rot) => {
let rad = (360.0 - rot).to_radians();
[rad.cos(), -rad.sin(), rad.sin(), rad.cos(), 0.0, 0.0]
}
Raw(r) => *r,
Scale(x, y) => {
[*x, 0.0, 0.0, *y, 0.0, 0.0]
}
Identity => [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
}
}
}
#[test]
fn test_ctm_translate() {
use self::*;
let ctm_trans = CurTransMat::Translate(Pt(150.0), Pt(50.0));
let ctm_trans_arr: [f32; 6] = ctm_trans.as_array();
assert_eq!([1.0_f32, 0.0, 0.0, 1.0, 150.0, 50.0], ctm_trans_arr);
let ctm_scale = CurTransMat::Scale(2.0, 4.0);
let ctm_scale_arr: [f32; 6] = ctm_scale.as_array();
assert_eq!([2.0_f32, 0.0, 0.0, 4.0, 0.0, 0.0], ctm_scale_arr);
let ctm_rot = CurTransMat::Rotate(30.0);
let ctm_rot_arr: [f32; 6] = ctm_rot.as_array();
assert_eq!(
[0.8660253, 0.5000002, -0.5000002, 0.8660253, 0.0, 0.0],
ctm_rot_arr
);
}