use std::collections::HashMap;
use std::convert::From;
#[derive(Debug, Clone, Copy)]
pub struct Affine {
pub x_scale: f64,
pub x_skew: f64,
pub x_origin: f64,
pub y_skew: f64,
pub y_scale: f64,
pub y_origin: f64,
}
impl Affine {
pub fn xy(&self, row: i32, col: i32) -> (f64, f64) {
let col_f = (col as f64) + 0.5;
let row_f = (row as f64) + 0.5;
let x = self.x_scale * col_f + self.x_skew * row_f + self.x_origin;
let y = self.y_skew * col_f + self.y_scale * row_f + self.y_origin;
(x, y)
}
pub fn col_row(&self, x: f64, y: f64) -> (f64, f64) {
let det = self.x_scale * self.y_scale - self.x_skew * self.y_skew;
let dx = x - self.x_origin;
let dy = y - self.y_origin;
let col = (self.y_scale * dx - self.x_skew * dy) / det;
let row = (-self.y_skew * dx + self.x_scale * dy) / det;
(col, row)
}
}
impl From<(f64, f64, f64, f64, f64, f64)> for Affine {
fn from(t: (f64, f64, f64, f64, f64, f64)) -> Self {
Self {
x_scale: t.0,
x_skew: t.1,
x_origin: t.2,
y_skew: t.3,
y_scale: t.4,
y_origin: t.5,
}
}
}
pub fn level_transforms(
base: impl Into<Affine>,
levels: &[usize],
offsets: (usize, usize),
) -> HashMap<i32, Affine> {
let Affine { x_scale: a, x_skew: b, x_origin: c, y_skew: d, y_scale: e, y_origin: f } = base.into();
levels
.iter()
.map(|&level| {
let l = level as f64;
let (sa, sb, sd, se) = (a * l + b * 0.0, a * 0.0 + b * l, d * l + e * 0.0, d * 0.0 + e * l);
let (tc, tr) = ((offsets.1 / level) as f64, (offsets.0 / level) as f64);
let t = (sa, sb, sa * tc + sb * tr + c, sd, se, sd * tc + se * tr + f);
(level as i32, Affine::from(t))
})
.collect()
}