vg/
geometry.rs

1use std::hash::{
2    Hash,
3    Hasher,
4};
5use std::ops::{
6    Index,
7    IndexMut,
8};
9
10use fnv::FnvHasher;
11
12pub fn quantize(a: f32, d: f32) -> f32 {
13    (a / d + 0.5).trunc() * d
14}
15
16pub fn pt_equals(x1: f32, y1: f32, x2: f32, y2: f32, tol: f32) -> bool {
17    let dx = x2 - x1;
18    let dy = y2 - y1;
19
20    dx * dx + dy * dy < tol * tol
21}
22
23pub fn cross(dx0: f32, dy0: f32, dx1: f32, dy1: f32) -> f32 {
24    dx1 * dy0 - dx0 * dy1
25}
26
27pub fn dist_pt_segment(x: f32, y: f32, px: f32, py: f32, qx: f32, qy: f32) -> f32 {
28    let pqx = qx - px;
29    let pqy = qy - py;
30    let dx = x - px;
31    let dy = y - py;
32    let d = pqx * pqx + pqy * pqy;
33    let mut t = pqx * dx + pqy * dy;
34
35    if d > 0.0 {
36        t /= d;
37    }
38
39    if t < 0.0 {
40        t = 0.0;
41    } else if t > 1.0 {
42        t = 1.0;
43    }
44
45    let dx = px + t * pqx - x;
46    let dy = py + t * pqy - y;
47
48    dx * dx + dy * dy
49}
50
51// TODO: fix this.. move it to point
52pub fn normalize(x: &mut f32, y: &mut f32) -> f32 {
53    let d = ((*x) * (*x) + (*y) * (*y)).sqrt();
54
55    if d > 1e-6 {
56        let id = 1.0 / d;
57        *x *= id;
58        *y *= id;
59    }
60
61    d
62}
63
64/// 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations.
65///
66/// It can represent transformations such as translation, rotation, or scaling.
67#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
68#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
69pub struct Transform2D(pub [f32; 6]);
70
71// TODO: Implement std::ops::* on this
72impl Transform2D {
73    /// Creates an identity transformation with no translation, rotation or scaling applied.
74    pub fn identity() -> Self {
75        Self([1.0, 0.0, 0.0, 1.0, 0.0, 0.0])
76    }
77
78    /// Creates transformation with translation
79    pub fn new_translation(x: f32, y: f32) -> Self {
80        let mut new = Self::identity();
81        new.translate(x, y);
82        new
83    }
84
85    /// Translate transformation
86    pub fn translate(&mut self, tx: f32, ty: f32) {
87        // self[0] = 1.0; self[1] = 0.0;
88        // self[2] = 0.0; self[3] = 1.0;
89        self[4] = tx;
90        self[5] = ty;
91    }
92
93    /// Scale transformation
94    pub fn scale(&mut self, sx: f32, sy: f32) {
95        self[0] = sx;
96        self[1] = 0.0;
97        self[2] = 0.0;
98        self[3] = sy;
99        self[4] = 0.0;
100        self[5] = 0.0;
101    }
102
103    /// Rotate transformation
104    pub fn rotate(&mut self, a: f32) {
105        let cs = a.cos();
106        let sn = a.sin();
107
108        self[0] = cs;
109        self[1] = sn;
110        self[2] = -sn;
111        self[3] = cs;
112        self[4] = 0.0;
113        self[5] = 0.0;
114    }
115
116    /// Skew transformation with x
117    pub fn skew_x(&mut self, a: f32) {
118        self[0] = 1.0;
119        self[1] = 0.0;
120        self[2] = a.tan();
121        self[3] = 1.0;
122        self[4] = 0.0;
123        self[5] = 0.0;
124    }
125
126    /// Skew transformation with y
127    pub fn skew_y(&mut self, a: f32) {
128        self[0] = 1.0;
129        self[1] = a.tan();
130        self[2] = 0.0;
131        self[3] = 1.0;
132        self[4] = 0.0;
133        self[5] = 0.0;
134    }
135
136    /// Multiply transformation
137    pub fn multiply(&mut self, other: &Self) {
138        let t0 = self[0] * other[0] + self[1] * other[2];
139        let t2 = self[2] * other[0] + self[3] * other[2];
140        let t4 = self[4] * other[0] + self[5] * other[2] + other[4];
141        self[1] = self[0] * other[1] + self[1] * other[3];
142        self[3] = self[2] * other[1] + self[3] * other[3];
143        self[5] = self[4] * other[1] + self[5] * other[3] + other[5];
144        self[0] = t0;
145        self[2] = t2;
146        self[4] = t4;
147    }
148
149    /// PreMultiply transformation
150    pub fn premultiply(&mut self, other: &Self) {
151        let mut other = *other;
152        other.multiply(self);
153        *self = other;
154    }
155
156    /// Invert transformation
157    pub fn inverse(&mut self) {
158        let t = *self;
159        let det = t[0] as f64 * t[3] as f64 - t[2] as f64 * t[1] as f64;
160
161        if det > -1e-6 && det < 1e-6 {
162            *self = Self::identity();
163        }
164
165        let invdet = 1.0 / det;
166
167        self[0] = (t[3] as f64 * invdet) as f32;
168        self[2] = (-t[2] as f64 * invdet) as f32;
169        self[4] = ((t[2] as f64 * t[5] as f64 - t[3] as f64 * t[4] as f64) * invdet) as f32;
170        self[1] = (-t[1] as f64 * invdet) as f32;
171        self[3] = (t[0] as f64 * invdet) as f32;
172        self[5] = ((t[1] as f64 * t[4] as f64 - t[0] as f64 * t[5] as f64) * invdet) as f32;
173    }
174
175    /// Invert transformation and chain
176    pub fn inversed(&self) -> Self {
177        let mut inv = *self;
178        inv.inverse();
179        inv
180    }
181
182    /// Transfor point with transformation
183    pub fn transform_point(&self, sx: f32, sy: f32) -> (f32, f32) {
184        let dx = sx * self[0] + sy * self[2] + self[4];
185        let dy = sx * self[1] + sy * self[3] + self[5];
186        (dx, dy)
187    }
188
189    /// Retrieve average scale
190    pub fn average_scale(&self) -> f32 {
191        let sx = (self[0] * self[0] + self[2] * self[2]).sqrt();
192        let sy = (self[1] * self[1] + self[3] * self[3]).sqrt();
193
194        (sx + sy) * 0.5
195    }
196
197    /// Convert transformation to matrix
198    pub fn to_mat3x4(self) -> [f32; 12] {
199        [
200            self[0], self[1], 0.0, 0.0, self[2], self[3], 0.0, 0.0, self[4], self[5], 1.0, 0.0,
201        ]
202    }
203
204    /// Retrieve hash
205    pub fn cache_key(&self) -> u64 {
206        let mut hasher = FnvHasher::default();
207
208        for i in 0..6 {
209            self.0[i].to_bits().hash(&mut hasher);
210        }
211
212        hasher.finish()
213    }
214}
215
216impl Default for Transform2D {
217    fn default() -> Self {
218        Self::identity()
219    }
220}
221
222impl Index<usize> for Transform2D {
223    type Output = f32;
224
225    fn index(&self, index: usize) -> &Self::Output {
226        &self.0[index]
227    }
228}
229
230impl IndexMut<usize> for Transform2D {
231    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
232        &mut self.0[index]
233    }
234}
235
236#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd)]
237pub struct Rect {
238    pub x: f32,
239    pub y: f32,
240    pub w: f32,
241    pub h: f32,
242}
243
244impl Rect {
245    pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
246        Self { x, y, w, h }
247    }
248
249    pub fn intersect(&self, other: Rect) -> Rect {
250        let minx = self.x.max(other.x);
251        let miny = self.y.max(other.y);
252        let maxx = (self.x + self.w).min(other.x + other.w);
253        let maxy = (self.y + self.h).min(other.y + other.h);
254
255        Rect::new(minx, miny, 0.0f32.max(maxx - minx), 0.0f32.max(maxy - miny))
256    }
257}
258
259#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
260pub struct Bounds {
261    pub minx: f32,
262    pub miny: f32,
263    pub maxx: f32,
264    pub maxy: f32,
265}
266
267impl Default for Bounds {
268    fn default() -> Self {
269        Self {
270            minx: 1e6,
271            miny: 1e6,
272            maxx: -1e6,
273            maxy: -1e6,
274        }
275    }
276}