use std::ops::{Add, BitAnd, BitOr, Div, Index, IndexMut, Mul, Neg, Sub};
use super::ErrorKind;
use crate::error::Result;
const INFINITE_MIN: f64 = -2_147_483_648.0;
const INFINITE_MAX: f64 = 2_147_483_520.0;
const IRECT_LIMIT: f64 = 16_777_216.0;
fn outward_to_irect(x0: f64, y0: f64, x1: f64, y1: f64) -> IRect {
fn edge(value: f64, low: bool) -> i32 {
let rounded = if low { value.floor() } else { value.ceil() };
rounded.clamp(-IRECT_LIMIT, IRECT_LIMIT) as i32
}
IRect {
x0: edge(x0, true),
y0: edge(y0, true),
x1: edge(x1, false),
y1: edge(y1, false),
}
}
fn point_on_segment(p: Point, a: Point, b: Point) -> bool {
let cross = (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x);
if cross != 0.0 {
return false;
}
let (min_x, max_x) = if a.x < b.x { (a.x, b.x) } else { (b.x, a.x) };
let (min_y, max_y) = if a.y < b.y { (a.y, b.y) } else { (b.y, a.y) };
p.x >= min_x && p.x <= max_x && p.y >= min_y && p.y <= max_y
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Rect {
pub x0: f64,
pub y0: f64,
pub x1: f64,
pub y1: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IRect {
pub x0: i32,
pub y0: i32,
pub x1: i32,
pub y1: i32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Point {
pub x: f64,
pub y: f64,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Matrix {
pub a: f64,
pub b: f64,
pub c: f64,
pub d: f64,
pub e: f64,
pub f: f64,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Quad {
pub ul: Point,
pub ur: Point,
pub ll: Point,
pub lr: Point,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum AreaUnit {
Pixels,
Inches,
Millimetres,
Centimetres,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum CompareOp {
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
}
fn clamped_area(width: f64, height: f64) -> f64 {
if width <= 0.0 || height <= 0.0 {
0.0
} else {
width * height
}
}
fn area_in(area: f64, unit: AreaUnit) -> f64 {
match unit {
AreaUnit::Pixels => area,
AreaUnit::Inches => area / 5184.0,
AreaUnit::Millimetres => area / 5184.0 * 25.4 * 25.4,
AreaUnit::Centimetres => area / 5184.0 * 2.54 * 2.54,
}
}
impl Rect {
pub fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> Self {
Self { x0, y0, x1, y1 }
}
pub fn abs(&self) -> f64 {
clamped_area(self.x1 - self.x0, self.y1 - self.y0)
}
pub fn to_bool(&self) -> bool {
self.x0 != 0.0 || self.y0 != 0.0 || self.x1 != 0.0 || self.y1 != 0.0
}
pub fn contains_point(&self, point: Point) -> i32 {
i32::from(
point.x >= self.x0 && point.x <= self.x1 && point.y >= self.y0 && point.y <= self.y1,
)
}
pub fn len(&self) -> usize {
4
}
pub fn pos(&self) -> Self {
*self
}
pub fn bl(&self) -> Point {
Point {
x: self.x0,
y: self.y1,
}
}
pub fn bottom_left(&self) -> Point {
self.bl()
}
pub fn bottom_right(&self) -> Point {
Point {
x: self.x1,
y: self.y1,
}
}
pub fn br(&self) -> Point {
self.bottom_right()
}
pub fn contains_rect(&self, other: Rect) -> bool {
other.x0 >= self.x0 && other.y0 >= self.y0 && other.x1 <= self.x1 && other.y1 <= self.y1
}
pub fn get_area(&self) -> f64 {
self.abs()
}
pub fn height(&self) -> f64 {
self.y1 - self.y0
}
pub fn include_point(&mut self, point: Point) -> Rect {
self.x0 = self.x0.min(point.x);
self.y0 = self.y0.min(point.y);
self.x1 = self.x1.max(point.x);
self.y1 = self.y1.max(point.y);
*self
}
pub fn include_rect(&mut self, other: Rect) -> Rect {
self.x0 = self.x0.min(other.x0);
self.y0 = self.y0.min(other.y0);
self.x1 = self.x1.max(other.x1);
self.y1 = self.y1.max(other.y1);
*self
}
pub fn intersect(&mut self, other: Rect) -> Rect {
self.x0 = self.x0.max(other.x0);
self.y0 = self.y0.max(other.y0);
self.x1 = self.x1.min(other.x1);
self.y1 = self.y1.min(other.y1);
*self
}
pub fn intersects(&self, other: Rect) -> bool {
self.x0.max(other.x0) < self.x1.min(other.x1)
&& self.y0.max(other.y0) < self.y1.min(other.y1)
}
pub fn irect(&self) -> IRect {
outward_to_irect(self.x0, self.y0, self.x1, self.y1)
}
pub fn is_empty(&self) -> bool {
self.x0 >= self.x1 || self.y0 >= self.y1
}
pub fn is_infinite(&self) -> bool {
self.x0 == INFINITE_MIN
&& self.y0 == INFINITE_MIN
&& self.x1 == INFINITE_MAX
&& self.y1 == INFINITE_MAX
}
pub fn is_valid(&self) -> bool {
self.x0 <= self.x1 && self.y0 <= self.y1
}
pub fn morph(&self, point: Point, matrix: Matrix) -> Quad {
self.quad().morph(point, matrix)
}
pub fn norm(&self) -> f64 {
(self.x0 * self.x0 + self.y0 * self.y0 + self.x1 * self.x1 + self.y1 * self.y1).sqrt()
}
pub fn normalize(&mut self) -> Rect {
if self.x0 > self.x1 {
std::mem::swap(&mut self.x0, &mut self.x1);
}
if self.y0 > self.y1 {
std::mem::swap(&mut self.y0, &mut self.y1);
}
*self
}
pub fn quad(&self) -> Quad {
Quad {
ul: self.top_left(),
ur: self.top_right(),
ll: self.bottom_left(),
lr: self.bottom_right(),
}
}
pub fn round(&self) -> IRect {
self.irect()
}
pub fn tl(&self) -> Point {
Point {
x: self.x0,
y: self.y0,
}
}
pub fn top_left(&self) -> Point {
self.tl()
}
pub fn top_right(&self) -> Point {
Point {
x: self.x1,
y: self.y0,
}
}
pub fn torect(&self, target: Rect) -> Matrix {
let sx = (target.x1 - target.x0) / (self.x1 - self.x0);
let sy = (target.y1 - target.y0) / (self.y1 - self.y0);
Matrix {
a: sx,
b: 0.0,
c: 0.0,
d: sy,
e: target.x0 - self.x0 * sx,
f: target.y0 - self.y0 * sy,
}
}
pub fn tr(&self) -> Point {
self.top_right()
}
pub fn transform(&mut self, matrix: Matrix) -> Rect {
*self = *self * matrix;
*self
}
pub fn width(&self) -> f64 {
self.x1 - self.x0
}
pub fn contains_quad(&self, quad: Quad) -> bool {
self.contains_rect(quad.rect())
}
pub fn get_area_in(&self, unit: AreaUnit) -> f64 {
area_in(self.abs(), unit)
}
pub fn compare(&self, _other: &Self, _op: CompareOp) -> Result<bool> {
Err(ErrorKind::WrongType.to_error("rectangles have no ordering"))
}
}
impl IRect {
pub fn new(x0: i32, y0: i32, x1: i32, y1: i32) -> Self {
Self { x0, y0, x1, y1 }
}
pub fn contains_point(&self, point: Point) -> i32 {
let x0 = f64::from(self.x0);
let y0 = f64::from(self.y0);
let x1 = f64::from(self.x1);
let y1 = f64::from(self.y1);
i32::from(point.x >= x0 && point.x <= x1 && point.y >= y0 && point.y <= y1)
}
pub fn len(&self) -> usize {
4
}
pub fn pos(&self) -> Self {
*self
}
pub fn bl(&self) -> Point {
Point {
x: f64::from(self.x0),
y: f64::from(self.y1),
}
}
pub fn bottom_left(&self) -> Point {
self.bl()
}
pub fn bottom_right(&self) -> Point {
Point {
x: f64::from(self.x1),
y: f64::from(self.y1),
}
}
pub fn br(&self) -> Point {
self.bottom_right()
}
pub fn contains_rect(&self, other: IRect) -> bool {
other.x0 >= self.x0 && other.y0 >= self.y0 && other.x1 <= self.x1 && other.y1 <= self.y1
}
pub fn get_area(&self) -> f64 {
let width = (i64::from(self.x1) - i64::from(self.x0)).max(0) as f64;
let height = (i64::from(self.y1) - i64::from(self.y0)).max(0) as f64;
width * height
}
pub fn height(&self) -> i32 {
self.y1.saturating_sub(self.y0).max(0)
}
pub fn include_point(&mut self, point: Point) -> IRect {
let grown = outward_to_irect(point.x, point.y, point.x, point.y);
self.x0 = self.x0.min(grown.x0);
self.y0 = self.y0.min(grown.y0);
self.x1 = self.x1.max(grown.x1);
self.y1 = self.y1.max(grown.y1);
*self
}
pub fn include_rect(&mut self, other: IRect) -> IRect {
self.x0 = self.x0.min(other.x0);
self.y0 = self.y0.min(other.y0);
self.x1 = self.x1.max(other.x1);
self.y1 = self.y1.max(other.y1);
*self
}
pub fn intersect(&mut self, other: IRect) -> IRect {
self.x0 = self.x0.max(other.x0);
self.y0 = self.y0.max(other.y0);
self.x1 = self.x1.min(other.x1);
self.y1 = self.y1.min(other.y1);
*self
}
pub fn intersects(&self, other: IRect) -> bool {
self.x0.max(other.x0) < self.x1.min(other.x1)
&& self.y0.max(other.y0) < self.y1.min(other.y1)
}
pub fn is_empty(&self) -> bool {
self.x0 >= self.x1 || self.y0 >= self.y1
}
pub fn is_infinite(&self) -> bool {
self.x0 == i32::MIN
&& self.y0 == i32::MIN
&& self.x1 == 2_147_483_520
&& self.y1 == 2_147_483_520
}
pub fn is_valid(&self) -> bool {
self.x0 <= self.x1 && self.y0 <= self.y1
}
pub fn morph(&self, point: Point, matrix: Matrix) -> Quad {
self.quad().morph(point, matrix)
}
pub fn norm(&self) -> f64 {
let edge = |v: i32| {
let v = f64::from(v);
v * v
};
(edge(self.x0) + edge(self.y0) + edge(self.x1) + edge(self.y1)).sqrt()
}
pub fn normalize(&mut self) -> IRect {
if self.x0 > self.x1 {
std::mem::swap(&mut self.x0, &mut self.x1);
}
if self.y0 > self.y1 {
std::mem::swap(&mut self.y0, &mut self.y1);
}
*self
}
pub fn quad(&self) -> Quad {
Quad {
ul: self.top_left(),
ur: self.top_right(),
ll: self.bottom_left(),
lr: self.bottom_right(),
}
}
pub fn rect(&self) -> Rect {
Rect {
x0: f64::from(self.x0),
y0: f64::from(self.y0),
x1: f64::from(self.x1),
y1: f64::from(self.y1),
}
}
pub fn tl(&self) -> Point {
Point {
x: f64::from(self.x0),
y: f64::from(self.y0),
}
}
pub fn top_left(&self) -> Point {
self.tl()
}
pub fn top_right(&self) -> Point {
Point {
x: f64::from(self.x1),
y: f64::from(self.y0),
}
}
pub fn torect(&self, target: IRect) -> Matrix {
let sx = (f64::from(target.x1) - f64::from(target.x0))
/ (f64::from(self.x1) - f64::from(self.x0));
let sy = (f64::from(target.y1) - f64::from(target.y0))
/ (f64::from(self.y1) - f64::from(self.y0));
Matrix {
a: sx,
b: 0.0,
c: 0.0,
d: sy,
e: f64::from(target.x0) - f64::from(self.x0) * sx,
f: f64::from(target.y0) - f64::from(self.y0) * sy,
}
}
pub fn tr(&self) -> Point {
self.top_right()
}
pub fn transform(&mut self, matrix: Matrix) -> IRect {
*self = *self * matrix;
*self
}
pub fn width(&self) -> i32 {
self.x1.saturating_sub(self.x0).max(0)
}
pub fn get_area_in(&self, unit: AreaUnit) -> f64 {
area_in(self.get_area(), unit)
}
pub fn compare(&self, _other: &Self, _op: CompareOp) -> Result<bool> {
Err(ErrorKind::WrongType.to_error("integer rectangles have no ordering"))
}
}
impl Point {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
fn transformed(self, matrix: Matrix) -> Point {
Point {
x: self.x * matrix.a + self.y * matrix.c + matrix.e,
y: self.x * matrix.b + self.y * matrix.d + matrix.f,
}
}
pub fn abs(&self) -> f64 {
self.x.hypot(self.y)
}
pub fn to_bool(&self) -> bool {
self.x != 0.0 || self.y != 0.0
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
2
}
pub fn pos(&self) -> Self {
*self
}
pub fn abs_unit(&self) -> Point {
Point {
x: self.x.abs(),
y: self.y.abs(),
}
.unit()
}
pub fn distance_to(&self, other: Point) -> f64 {
(self.x - other.x).hypot(self.y - other.y)
}
pub fn norm(&self) -> f64 {
self.abs()
}
pub fn transform(&mut self, matrix: Matrix) -> Point {
*self = self.transformed(matrix);
*self
}
pub fn unit(&self) -> Point {
let length = self.abs();
if length == 0.0 {
*self
} else {
Point {
x: self.x / length,
y: self.y / length,
}
}
}
pub fn compare(&self, _other: &Self, _op: CompareOp) -> Result<bool> {
Err(ErrorKind::WrongType.to_error("points have no ordering"))
}
}
impl Matrix {
pub fn new(a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> Self {
Self { a, b, c, d, e, f }
}
fn determinant(self) -> f64 {
self.a * self.d - self.b * self.c
}
fn concat_of(one: Matrix, two: Matrix) -> Matrix {
Matrix {
a: one.a * two.a + one.b * two.c,
b: one.a * two.b + one.b * two.d,
c: one.c * two.a + one.d * two.c,
d: one.c * two.b + one.d * two.d,
e: one.e * two.a + one.f * two.c + two.e,
f: one.e * two.b + one.f * two.d + two.f,
}
}
pub fn abs(&self) -> f64 {
self.norm()
}
pub fn to_bool(&self) -> bool {
self.a != 0.0
|| self.b != 0.0
|| self.c != 0.0
|| self.d != 0.0
|| self.e != 0.0
|| self.f != 0.0
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
6
}
pub fn pos(&self) -> Self {
*self
}
pub fn concat(&mut self, one: Matrix, two: Matrix) -> Matrix {
*self = Self::concat_of(one, two);
*self
}
pub fn invert(&self, src: Option<Matrix>) -> Matrix {
let m = src.unwrap_or(*self);
let det = m.determinant();
if det == 0.0 {
return m;
}
Matrix {
a: m.d / det,
b: -m.b / det,
c: -m.c / det,
d: m.a / det,
e: (m.c * m.f - m.e * m.d) / det,
f: (m.e * m.b - m.a * m.f) / det,
}
}
pub fn is_rectilinear(&self) -> bool {
(self.b == 0.0 && self.c == 0.0) || (self.a == 0.0 && self.d == 0.0)
}
pub fn norm(&self) -> f64 {
(self.a * self.a
+ self.b * self.b
+ self.c * self.c
+ self.d * self.d
+ self.e * self.e
+ self.f * self.f)
.sqrt()
}
pub fn prerotate(&mut self, theta: f64) -> Matrix {
let angle = theta.to_radians();
let rotation = Matrix {
a: angle.cos(),
b: angle.sin(),
c: -angle.sin(),
d: angle.cos(),
e: 0.0,
f: 0.0,
};
*self = Self::concat_of(rotation, *self);
*self
}
pub fn prescale(&mut self, sx: f64, sy: f64) -> Matrix {
let scale = Matrix {
a: sx,
b: 0.0,
c: 0.0,
d: sy,
e: 0.0,
f: 0.0,
};
*self = Self::concat_of(scale, *self);
*self
}
pub fn preshear(&mut self, h: f64, v: f64) -> Matrix {
let shear = Matrix {
a: 1.0,
b: v,
c: h,
d: 1.0,
e: 0.0,
f: 0.0,
};
*self = Self::concat_of(shear, *self);
*self
}
pub fn pretranslate(&mut self, tx: f64, ty: f64) -> Matrix {
let shift = Matrix {
a: 1.0,
b: 0.0,
c: 0.0,
d: 1.0,
e: tx,
f: ty,
};
*self = Self::concat_of(shift, *self);
*self
}
pub fn compare(&self, _other: &Self, _op: CompareOp) -> Result<bool> {
Err(ErrorKind::WrongType.to_error("matrices have no ordering"))
}
}
impl Quad {
pub fn new(ul: Point, ur: Point, ll: Point, lr: Point) -> Self {
Self { ul, ur, ll, lr }
}
fn ring(&self) -> [Point; 4] {
[self.ul, self.ur, self.lr, self.ll]
}
pub fn abs(&self) -> f64 {
let ring = self.ring();
let mut sum = 0.0;
for i in 0..4 {
let p = ring[i];
let q = ring[(i + 1) % 4];
sum += p.x * q.y - q.x * p.y;
}
0.5 * sum.abs()
}
pub fn to_bool(&self) -> bool {
self.ul.to_bool() || self.ur.to_bool() || self.ll.to_bool() || self.lr.to_bool()
}
pub fn contains_point(&self, point: Point) -> bool {
let ring = self.ring();
for i in 0..4 {
if point_on_segment(point, ring[i], ring[(i + 1) % 4]) {
return true;
}
}
let mut inside = false;
for i in 0..4 {
let a = ring[i];
let b = ring[(i + 1) % 4];
if (a.y > point.y) != (b.y > point.y) {
let cross_x = a.x + (point.y - a.y) * (b.x - a.x) / (b.y - a.y);
if point.x < cross_x {
inside = !inside;
}
}
}
inside
}
pub fn len(&self) -> usize {
4
}
pub fn pos(&self) -> Self {
*self
}
pub fn height(&self) -> f64 {
(self.ll.x - self.ul.x).hypot(self.ll.y - self.ul.y)
}
pub fn is_convex(&self) -> bool {
let ring = self.ring();
let mut positive = false;
let mut negative = false;
for i in 0..4 {
let a = ring[i];
let b = ring[(i + 1) % 4];
let c = ring[(i + 2) % 4];
let cross = (b.x - a.x) * (c.y - b.y) - (b.y - a.y) * (c.x - b.x);
if cross > 0.0 {
positive = true;
} else if cross < 0.0 {
negative = true;
}
}
!(positive && negative)
}
pub fn is_empty(&self) -> bool {
self.rect().is_empty()
}
pub fn is_infinite(&self) -> bool {
self.rect().is_infinite()
}
pub fn is_rectangular(&self) -> bool {
!self.is_empty()
&& self.ul.x == self.ll.x
&& self.ur.x == self.lr.x
&& self.ul.y == self.ur.y
&& self.ll.y == self.lr.y
}
pub fn morph(&self, point: Point, matrix: Matrix) -> Quad {
let morph_corner = |corner: Point| {
let shifted = Point {
x: corner.x - point.x,
y: corner.y - point.y,
}
.transformed(matrix);
Point {
x: point.x + shifted.x,
y: point.y + shifted.y,
}
};
Quad {
ul: morph_corner(self.ul),
ur: morph_corner(self.ur),
ll: morph_corner(self.ll),
lr: morph_corner(self.lr),
}
}
pub fn rect(&self) -> Rect {
let xs = [self.ul.x, self.ur.x, self.ll.x, self.lr.x];
let ys = [self.ul.y, self.ur.y, self.ll.y, self.lr.y];
Rect {
x0: xs.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
y0: ys.iter().fold(f64::INFINITY, |a, &b| a.min(b)),
x1: xs.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)),
y1: ys.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)),
}
}
pub fn transform(&mut self, matrix: Matrix) -> Quad {
self.ul = self.ul.transformed(matrix);
self.ur = self.ur.transformed(matrix);
self.ll = self.ll.transformed(matrix);
self.lr = self.lr.transformed(matrix);
*self
}
pub fn width(&self) -> f64 {
(self.ur.x - self.ul.x).hypot(self.ur.y - self.ul.y)
}
pub fn compare(&self, _other: &Self, _op: CompareOp) -> Result<bool> {
Err(ErrorKind::WrongType.to_error("quadrilaterals have no ordering"))
}
}
impl Add<IRect> for IRect {
type Output = Self;
fn add(self, rhs: IRect) -> Self {
Self {
x0: self.x0.wrapping_add(rhs.x0),
y0: self.y0.wrapping_add(rhs.y0),
x1: self.x1.wrapping_add(rhs.x1),
y1: self.y1.wrapping_add(rhs.y1),
}
}
}
impl Add<i32> for IRect {
type Output = Self;
fn add(self, rhs: i32) -> Self {
Self {
x0: self.x0.wrapping_add(rhs),
y0: self.y0.wrapping_add(rhs),
x1: self.x1.wrapping_add(rhs),
y1: self.y1.wrapping_add(rhs),
}
}
}
impl Sub<IRect> for IRect {
type Output = Self;
fn sub(self, rhs: IRect) -> Self {
Self {
x0: self.x0.wrapping_sub(rhs.x0),
y0: self.y0.wrapping_sub(rhs.y0),
x1: self.x1.wrapping_sub(rhs.x1),
y1: self.y1.wrapping_sub(rhs.y1),
}
}
}
impl Sub<i32> for IRect {
type Output = Self;
fn sub(self, rhs: i32) -> Self {
Self {
x0: self.x0.wrapping_sub(rhs),
y0: self.y0.wrapping_sub(rhs),
x1: self.x1.wrapping_sub(rhs),
y1: self.y1.wrapping_sub(rhs),
}
}
}
impl Mul<Matrix> for IRect {
type Output = Self;
fn mul(self, rhs: Matrix) -> Self {
let moved = self.rect() * rhs;
outward_to_irect(moved.x0, moved.y0, moved.x1, moved.y1)
}
}
impl Mul<i32> for IRect {
type Output = Self;
fn mul(self, rhs: i32) -> Self {
Self {
x0: self.x0.wrapping_mul(rhs),
y0: self.y0.wrapping_mul(rhs),
x1: self.x1.wrapping_mul(rhs),
y1: self.y1.wrapping_mul(rhs),
}
}
}
impl Div<Matrix> for IRect {
type Output = Self;
fn div(self, rhs: Matrix) -> Self {
if rhs.determinant() == 0.0 {
self
} else {
self * rhs.invert(None)
}
}
}
impl Div<i32> for IRect {
type Output = Self;
fn div(self, rhs: i32) -> Self {
assert!(rhs != 0, "integer rectangle division by zero");
let divisor = f64::from(rhs);
let edge = |value: i32, low: bool| {
let quotient = f64::from(value) / divisor;
(if low {
quotient.floor()
} else {
quotient.ceil()
}) as i32
};
Self {
x0: edge(self.x0, true),
y0: edge(self.y0, true),
x1: edge(self.x1, false),
y1: edge(self.y1, false),
}
}
}
impl Neg for IRect {
type Output = Self;
fn neg(self) -> Self {
Self {
x0: self.x0.wrapping_neg(),
y0: self.y0.wrapping_neg(),
x1: self.x1.wrapping_neg(),
y1: self.y1.wrapping_neg(),
}
}
}
impl BitAnd<IRect> for IRect {
type Output = Self;
fn bitand(self, rhs: IRect) -> Self {
Self {
x0: self.x0.max(rhs.x0),
y0: self.y0.max(rhs.y0),
x1: self.x1.min(rhs.x1),
y1: self.y1.min(rhs.y1),
}
}
}
impl BitOr<IRect> for IRect {
type Output = Self;
fn bitor(self, rhs: IRect) -> Self {
Self {
x0: self.x0.min(rhs.x0),
y0: self.y0.min(rhs.y0),
x1: self.x1.max(rhs.x1),
y1: self.y1.max(rhs.y1),
}
}
}
impl Index<usize> for IRect {
type Output = i32;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x0,
1 => &self.y0,
2 => &self.x1,
3 => &self.y1,
_ => panic!("integer rectangle index out of range: {index}"),
}
}
}
impl IndexMut<usize> for IRect {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x0,
1 => &mut self.y0,
2 => &mut self.x1,
3 => &mut self.y1,
_ => panic!("integer rectangle index out of range: {index}"),
}
}
}
impl Add<Matrix> for Matrix {
type Output = Self;
fn add(self, rhs: Matrix) -> Self {
Self {
a: self.a + rhs.a,
b: self.b + rhs.b,
c: self.c + rhs.c,
d: self.d + rhs.d,
e: self.e + rhs.e,
f: self.f + rhs.f,
}
}
}
impl Add<f64> for Matrix {
type Output = Self;
fn add(self, rhs: f64) -> Self {
Self {
a: self.a + rhs,
b: self.b + rhs,
c: self.c + rhs,
d: self.d + rhs,
e: self.e + rhs,
f: self.f + rhs,
}
}
}
impl Sub<Matrix> for Matrix {
type Output = Self;
fn sub(self, rhs: Matrix) -> Self {
Self {
a: self.a - rhs.a,
b: self.b - rhs.b,
c: self.c - rhs.c,
d: self.d - rhs.d,
e: self.e - rhs.e,
f: self.f - rhs.f,
}
}
}
impl Sub<f64> for Matrix {
type Output = Self;
fn sub(self, rhs: f64) -> Self {
Self {
a: self.a - rhs,
b: self.b - rhs,
c: self.c - rhs,
d: self.d - rhs,
e: self.e - rhs,
f: self.f - rhs,
}
}
}
impl Mul<Matrix> for Matrix {
type Output = Self;
fn mul(self, rhs: Matrix) -> Self {
Self::concat_of(self, rhs)
}
}
impl Mul<f64> for Matrix {
type Output = Self;
fn mul(self, rhs: f64) -> Self {
Self {
a: self.a * rhs,
b: self.b * rhs,
c: self.c * rhs,
d: self.d * rhs,
e: self.e * rhs,
f: self.f * rhs,
}
}
}
impl Div<Matrix> for Matrix {
type Output = Self;
fn div(self, rhs: Matrix) -> Self {
if rhs.determinant() == 0.0 {
self
} else {
self * rhs.invert(None)
}
}
}
impl Div<f64> for Matrix {
type Output = Self;
fn div(self, rhs: f64) -> Self {
Self {
a: self.a / rhs,
b: self.b / rhs,
c: self.c / rhs,
d: self.d / rhs,
e: self.e / rhs,
f: self.f / rhs,
}
}
}
impl Neg for Matrix {
type Output = Self;
fn neg(self) -> Self {
Self {
a: -self.a,
b: -self.b,
c: -self.c,
d: -self.d,
e: -self.e,
f: -self.f,
}
}
}
impl Index<usize> for Matrix {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.a,
1 => &self.b,
2 => &self.c,
3 => &self.d,
4 => &self.e,
5 => &self.f,
_ => panic!("matrix index out of range: {index}"),
}
}
}
impl IndexMut<usize> for Matrix {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.a,
1 => &mut self.b,
2 => &mut self.c,
3 => &mut self.d,
4 => &mut self.e,
5 => &mut self.f,
_ => panic!("matrix index out of range: {index}"),
}
}
}
impl Add<Point> for Point {
type Output = Self;
fn add(self, rhs: Point) -> Self {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Add<f64> for Point {
type Output = Self;
fn add(self, rhs: f64) -> Self {
Self {
x: self.x + rhs,
y: self.y + rhs,
}
}
}
impl Sub<Point> for Point {
type Output = Self;
fn sub(self, rhs: Point) -> Self {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl Sub<f64> for Point {
type Output = Self;
fn sub(self, rhs: f64) -> Self {
Self {
x: self.x - rhs,
y: self.y - rhs,
}
}
}
impl Mul<Point> for Point {
type Output = f64;
fn mul(self, rhs: Point) -> f64 {
self.x * rhs.x + self.y * rhs.y
}
}
impl Mul<Matrix> for Point {
type Output = Self;
fn mul(self, rhs: Matrix) -> Self {
self.transformed(rhs)
}
}
impl Mul<f64> for Point {
type Output = Self;
fn mul(self, rhs: f64) -> Self {
Self {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl Div<Matrix> for Point {
type Output = Self;
fn div(self, rhs: Matrix) -> Self {
if rhs.determinant() == 0.0 {
self
} else {
self * rhs.invert(None)
}
}
}
impl Div<f64> for Point {
type Output = Self;
fn div(self, rhs: f64) -> Self {
Self {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl Neg for Point {
type Output = Self;
fn neg(self) -> Self {
Self {
x: -self.x,
y: -self.y,
}
}
}
impl Index<usize> for Point {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
_ => panic!("point index out of range: {index}"),
}
}
}
impl IndexMut<usize> for Point {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
_ => panic!("point index out of range: {index}"),
}
}
}
impl Add<Quad> for Quad {
type Output = Self;
fn add(self, rhs: Quad) -> Self {
Self {
ul: self.ul + rhs.ul,
ur: self.ur + rhs.ur,
ll: self.ll + rhs.ll,
lr: self.lr + rhs.lr,
}
}
}
impl Add<f64> for Quad {
type Output = Self;
fn add(self, rhs: f64) -> Self {
Self {
ul: self.ul + rhs,
ur: self.ur + rhs,
ll: self.ll + rhs,
lr: self.lr + rhs,
}
}
}
impl Sub<Quad> for Quad {
type Output = Self;
fn sub(self, rhs: Quad) -> Self {
Self {
ul: self.ul - rhs.ul,
ur: self.ur - rhs.ur,
ll: self.ll - rhs.ll,
lr: self.lr - rhs.lr,
}
}
}
impl Sub<f64> for Quad {
type Output = Self;
fn sub(self, rhs: f64) -> Self {
Self {
ul: self.ul - rhs,
ur: self.ur - rhs,
ll: self.ll - rhs,
lr: self.lr - rhs,
}
}
}
impl Mul<Matrix> for Quad {
type Output = Self;
fn mul(self, rhs: Matrix) -> Self {
Self {
ul: self.ul.transformed(rhs),
ur: self.ur.transformed(rhs),
ll: self.ll.transformed(rhs),
lr: self.lr.transformed(rhs),
}
}
}
impl Mul<f64> for Quad {
type Output = Self;
fn mul(self, rhs: f64) -> Self {
Self {
ul: self.ul * rhs,
ur: self.ur * rhs,
ll: self.ll * rhs,
lr: self.lr * rhs,
}
}
}
impl Div<Matrix> for Quad {
type Output = Self;
fn div(self, rhs: Matrix) -> Self {
if rhs.determinant() == 0.0 {
self
} else {
self * rhs.invert(None)
}
}
}
impl Div<f64> for Quad {
type Output = Self;
fn div(self, rhs: f64) -> Self {
Self {
ul: self.ul / rhs,
ur: self.ur / rhs,
ll: self.ll / rhs,
lr: self.lr / rhs,
}
}
}
impl Neg for Quad {
type Output = Self;
fn neg(self) -> Self {
Self {
ul: -self.ul,
ur: -self.ur,
ll: -self.ll,
lr: -self.lr,
}
}
}
impl Index<usize> for Quad {
type Output = Point;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.ul,
1 => &self.ur,
2 => &self.ll,
3 => &self.lr,
_ => panic!("quadrilateral index out of range: {index}"),
}
}
}
impl IndexMut<usize> for Quad {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.ul,
1 => &mut self.ur,
2 => &mut self.ll,
3 => &mut self.lr,
_ => panic!("quadrilateral index out of range: {index}"),
}
}
}
impl Add<Rect> for Rect {
type Output = Self;
fn add(self, rhs: Rect) -> Self {
Self {
x0: self.x0 + rhs.x0,
y0: self.y0 + rhs.y0,
x1: self.x1 + rhs.x1,
y1: self.y1 + rhs.y1,
}
}
}
impl Add<f64> for Rect {
type Output = Self;
fn add(self, rhs: f64) -> Self {
Self {
x0: self.x0 + rhs,
y0: self.y0 + rhs,
x1: self.x1 + rhs,
y1: self.y1 + rhs,
}
}
}
impl Sub<Rect> for Rect {
type Output = Self;
fn sub(self, rhs: Rect) -> Self {
Self {
x0: self.x0 - rhs.x0,
y0: self.y0 - rhs.y0,
x1: self.x1 - rhs.x1,
y1: self.y1 - rhs.y1,
}
}
}
impl Sub<f64> for Rect {
type Output = Self;
fn sub(self, rhs: f64) -> Self {
Self {
x0: self.x0 - rhs,
y0: self.y0 - rhs,
x1: self.x1 - rhs,
y1: self.y1 - rhs,
}
}
}
impl Mul<Matrix> for Rect {
type Output = Self;
fn mul(self, rhs: Matrix) -> Self {
let at = |x: f64, y: f64| Point::new(x, y).transformed(rhs);
let p0 = at(self.x0, self.y0);
let p1 = at(self.x1, self.y0);
let p2 = at(self.x0, self.y1);
let p3 = at(self.x1, self.y1);
Self {
x0: p0.x.min(p1.x).min(p2.x).min(p3.x),
y0: p0.y.min(p1.y).min(p2.y).min(p3.y),
x1: p0.x.max(p1.x).max(p2.x).max(p3.x),
y1: p0.y.max(p1.y).max(p2.y).max(p3.y),
}
}
}
impl Mul<f64> for Rect {
type Output = Self;
fn mul(self, rhs: f64) -> Self {
Self {
x0: self.x0 * rhs,
y0: self.y0 * rhs,
x1: self.x1 * rhs,
y1: self.y1 * rhs,
}
}
}
impl Div<Matrix> for Rect {
type Output = Self;
fn div(self, rhs: Matrix) -> Self {
if rhs.determinant() == 0.0 {
self
} else {
self * rhs.invert(None)
}
}
}
impl Div<f64> for Rect {
type Output = Self;
fn div(self, rhs: f64) -> Self {
Self {
x0: self.x0 / rhs,
y0: self.y0 / rhs,
x1: self.x1 / rhs,
y1: self.y1 / rhs,
}
}
}
impl Neg for Rect {
type Output = Self;
fn neg(self) -> Self {
Self {
x0: -self.x0,
y0: -self.y0,
x1: -self.x1,
y1: -self.y1,
}
}
}
impl BitAnd<Rect> for Rect {
type Output = Self;
fn bitand(self, rhs: Rect) -> Self {
Self {
x0: self.x0.max(rhs.x0),
y0: self.y0.max(rhs.y0),
x1: self.x1.min(rhs.x1),
y1: self.y1.min(rhs.y1),
}
}
}
impl BitOr<Rect> for Rect {
type Output = Self;
fn bitor(self, rhs: Rect) -> Self {
Self {
x0: self.x0.min(rhs.x0),
y0: self.y0.min(rhs.y0),
x1: self.x1.max(rhs.x1),
y1: self.y1.max(rhs.y1),
}
}
}
impl Index<usize> for Rect {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x0,
1 => &self.y0,
2 => &self.x1,
3 => &self.y1,
_ => panic!("rectangle index out of range: {index}"),
}
}
}
impl IndexMut<usize> for Rect {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x0,
1 => &mut self.y0,
2 => &mut self.x1,
3 => &mut self.y1,
_ => panic!("rectangle index out of range: {index}"),
}
}
}