#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Point {
pub x: f32,
pub y: f32,
}
impl Point {
pub const fn new(x: f32, y: f32) -> Point {
Point { x, y }
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Size {
pub width: f32,
pub height: f32,
}
impl Size {
pub const fn new(width: f32, height: f32) -> Size {
Size { width, height }
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Rect {
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl Rect {
pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Rect {
Rect {
x,
y,
width,
height,
}
}
pub fn right(&self) -> f32 {
self.x + self.width
}
pub fn bottom(&self) -> f32 {
self.y + self.height
}
pub fn is_empty(&self) -> bool {
self.width <= 0.0 || self.height <= 0.0
}
pub fn contains(&self, point: Point) -> bool {
point.x >= self.x && point.x < self.right() && point.y >= self.y && point.y < self.bottom()
}
pub fn union(&self, other: Rect) -> Rect {
if other.is_empty() {
return *self;
}
if self.is_empty() {
return other;
}
let x = self.x.min(other.x);
let y = self.y.min(other.y);
Rect::new(
x,
y,
self.right().max(other.right()) - x,
self.bottom().max(other.bottom()) - y,
)
}
pub fn intersect(&self, other: Rect) -> Rect {
let x = self.x.max(other.x);
let y = self.y.max(other.y);
let right = self.right().min(other.right());
let bottom = self.bottom().min(other.bottom());
if right > x && bottom > y {
Rect::new(x, y, right - x, bottom - y)
} else {
Rect::default()
}
}
}
impl Rect {
pub(crate) fn outset(&self, by: f32) -> Rect {
if self.is_empty() {
return *self;
}
Rect::new(
self.x - by,
self.y - by,
self.width + 2.0 * by,
self.height + 2.0 * by,
)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Affine {
pub sx: f32,
pub ky: f32,
pub kx: f32,
pub sy: f32,
pub tx: f32,
pub ty: f32,
}
impl Affine {
pub(crate) fn map(&self, point: Point) -> Point {
Point::new(
self.sx * point.x + self.kx * point.y + self.tx,
self.ky * point.x + self.sy * point.y + self.ty,
)
}
pub(crate) fn map_rect(&self, rect: Rect) -> Rect {
let corners = [
Point::new(rect.x, rect.y),
Point::new(rect.right(), rect.y),
Point::new(rect.x, rect.bottom()),
Point::new(rect.right(), rect.bottom()),
]
.map(|corner| self.map(corner));
let (mut left, mut top) = (f32::INFINITY, f32::INFINITY);
let (mut right, mut bottom) = (f32::NEG_INFINITY, f32::NEG_INFINITY);
for corner in corners {
left = left.min(corner.x);
top = top.min(corner.y);
right = right.max(corner.x);
bottom = bottom.max(corner.y);
}
let mapped = Rect::new(left, top, right - left, bottom - top);
if [mapped.x, mapped.y, mapped.width, mapped.height]
.iter()
.all(|n| n.is_finite())
{
mapped
} else {
Rect::default()
}
}
pub(crate) fn invert(&self) -> Option<Affine> {
let det = self.sx * self.sy - self.kx * self.ky;
if det == 0.0 || !det.is_finite() {
return None;
}
let (sx, ky, kx, sy) = (self.sy / det, -self.ky / det, -self.kx / det, self.sx / det);
Some(Affine {
sx,
ky,
kx,
sy,
tx: -(sx * self.tx + kx * self.ty),
ty: -(ky * self.tx + sy * self.ty),
})
}
}
pub(crate) fn through(chain: &[Affine], rect: Rect) -> Rect {
chain.iter().rev().fold(rect, |rect, transform| {
if rect.is_empty() {
rect
} else {
transform.map_rect(rect.outset(1.0))
}
})
}