#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Point {
pub x: f64,
pub y: f64,
}
impl Point {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
pub fn distance(&self, other: &Self) -> f64 {
((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Size {
pub width: f64,
pub height: f64,
}
impl Size {
pub fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rect {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
impl Rect {
pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
Self {
x,
y,
width,
height,
}
}
pub fn from_points(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
Self {
x: x1.min(x2),
y: y1.min(y2),
width: (x2 - x1).abs(),
height: (y2 - y1).abs(),
}
}
pub fn contains(&self, px: f64, py: f64) -> bool {
px >= self.x && px <= self.x + self.width && py >= self.y && py <= self.y + self.height
}
pub fn intersects(&self, other: &Self) -> bool {
self.x < other.x + other.width
&& self.x + self.width > other.x
&& self.y < other.y + other.height
&& self.y + self.height > other.y
}
pub fn union(&self, other: &Self) -> Self {
let x = self.x.min(other.x);
let y = self.y.min(other.y);
let max_x = (self.x + self.width).max(other.x + other.width);
let max_y = (self.y + self.height).max(other.y + other.height);
Self {
x,
y,
width: max_x - x,
height: max_y - y,
}
}
pub fn intersection(&self, other: &Self) -> Option<Self> {
let x = self.x.max(other.x);
let y = self.y.max(other.y);
let max_x = (self.x + self.width).min(other.x + other.width);
let max_y = (self.y + self.height).min(other.y + other.height);
if max_x > x && max_y > y {
Some(Self {
x,
y,
width: max_x - x,
height: max_y - y,
})
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Matrix {
pub a: f64,
pub b: f64,
pub c: f64,
pub d: f64,
pub e: f64,
pub f: f64,
}
impl Matrix {
pub fn identity() -> Self {
Self {
a: 1.0,
b: 0.0,
c: 0.0,
d: 1.0,
e: 0.0,
f: 0.0,
}
}
pub fn translate(tx: f64, ty: f64) -> Self {
Self {
a: 1.0,
b: 0.0,
c: 0.0,
d: 1.0,
e: tx,
f: ty,
}
}
pub fn scale(sx: f64, sy: f64) -> Self {
Self {
a: sx,
b: 0.0,
c: 0.0,
d: sy,
e: 0.0,
f: 0.0,
}
}
pub fn rotate(angle: f64) -> Self {
let cos = angle.to_radians().cos();
let sin = angle.to_radians().sin();
Self {
a: cos,
b: sin,
c: -sin,
d: cos,
e: 0.0,
f: 0.0,
}
}
pub fn combine(&self, other: &Self) -> Self {
Self {
a: self.a * other.a + self.b * other.c,
b: self.a * other.b + self.b * other.d,
c: self.c * other.a + self.d * other.c,
d: self.c * other.b + self.d * other.d,
e: self.e * other.a + self.f * other.c + other.e,
f: self.e * other.b + self.f * other.d + other.f,
}
}
pub fn transform_point(&self, x: f64, y: f64) -> (f64, f64) {
(
self.a * x + self.c * y + self.e,
self.b * x + self.d * y + self.f,
)
}
}
pub type Transform = Matrix;