1#[derive(Debug, Clone, Copy, PartialEq)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4pub struct Point {
5 pub x: f64,
6 pub y: f64,
7}
8
9impl Point {
10 pub fn new(x: f64, y: f64) -> Self {
11 Self { x, y }
12 }
13
14 pub fn distance(&self, other: &Self) -> f64 {
15 ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
16 }
17}
18
19#[derive(Debug, Clone, Copy, PartialEq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Size {
23 pub width: f64,
24 pub height: f64,
25}
26
27impl Size {
28 pub fn new(width: f64, height: f64) -> Self {
29 Self { width, height }
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct Rect {
37 pub x: f64,
38 pub y: f64,
39 pub width: f64,
40 pub height: f64,
41}
42
43impl Rect {
44 pub fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
45 Self {
46 x,
47 y,
48 width,
49 height,
50 }
51 }
52
53 pub fn from_points(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
54 Self {
55 x: x1.min(x2),
56 y: y1.min(y2),
57 width: (x2 - x1).abs(),
58 height: (y2 - y1).abs(),
59 }
60 }
61
62 pub fn contains(&self, px: f64, py: f64) -> bool {
63 px >= self.x && px <= self.x + self.width && py >= self.y && py <= self.y + self.height
64 }
65
66 pub fn intersects(&self, other: &Self) -> bool {
67 self.x < other.x + other.width
68 && self.x + self.width > other.x
69 && self.y < other.y + other.height
70 && self.y + self.height > other.y
71 }
72
73 pub fn union(&self, other: &Self) -> Self {
74 let x = self.x.min(other.x);
75 let y = self.y.min(other.y);
76 let max_x = (self.x + self.width).max(other.x + other.width);
77 let max_y = (self.y + self.height).max(other.y + other.height);
78 Self {
79 x,
80 y,
81 width: max_x - x,
82 height: max_y - y,
83 }
84 }
85
86 pub fn intersection(&self, other: &Self) -> Option<Self> {
87 let x = self.x.max(other.x);
88 let y = self.y.max(other.y);
89 let max_x = (self.x + self.width).min(other.x + other.width);
90 let max_y = (self.y + self.height).min(other.y + other.height);
91 if max_x > x && max_y > y {
92 Some(Self {
93 x,
94 y,
95 width: max_x - x,
96 height: max_y - y,
97 })
98 } else {
99 None
100 }
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub struct Matrix {
108 pub a: f64,
109 pub b: f64,
110 pub c: f64,
111 pub d: f64,
112 pub e: f64,
113 pub f: f64,
114}
115
116impl Matrix {
117 pub fn identity() -> Self {
118 Self {
119 a: 1.0,
120 b: 0.0,
121 c: 0.0,
122 d: 1.0,
123 e: 0.0,
124 f: 0.0,
125 }
126 }
127
128 pub fn translate(tx: f64, ty: f64) -> Self {
129 Self {
130 a: 1.0,
131 b: 0.0,
132 c: 0.0,
133 d: 1.0,
134 e: tx,
135 f: ty,
136 }
137 }
138
139 pub fn scale(sx: f64, sy: f64) -> Self {
140 Self {
141 a: sx,
142 b: 0.0,
143 c: 0.0,
144 d: sy,
145 e: 0.0,
146 f: 0.0,
147 }
148 }
149
150 pub fn rotate(angle: f64) -> Self {
151 let cos = angle.to_radians().cos();
152 let sin = angle.to_radians().sin();
153 Self {
154 a: cos,
155 b: sin,
156 c: -sin,
157 d: cos,
158 e: 0.0,
159 f: 0.0,
160 }
161 }
162
163 pub fn combine(&self, other: &Self) -> Self {
164 Self {
165 a: self.a * other.a + self.b * other.c,
166 b: self.a * other.b + self.b * other.d,
167 c: self.c * other.a + self.d * other.c,
168 d: self.c * other.b + self.d * other.d,
169 e: self.e * other.a + self.f * other.c + other.e,
170 f: self.e * other.b + self.f * other.d + other.f,
171 }
172 }
173
174 pub fn transform_point(&self, x: f64, y: f64) -> (f64, f64) {
175 (
176 self.a * x + self.c * y + self.e,
177 self.b * x + self.d * y + self.f,
178 )
179 }
180}
181
182pub type Transform = Matrix;