plottery_lib/geometry/
v2.rs

1use std::{f32::consts::PI, iter::Sum};
2
3use geo_types::Coord;
4use mint::Point2;
5use serde::{Deserialize, Serialize};
6
7use crate::{rand_range, Angle, Rect, Rotate, Rotate90, SampleSettings};
8
9use super::v2i::V2i;
10
11#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
12pub struct V2 {
13    pub x: f32,
14    pub y: f32,
15}
16
17impl V2 {
18    pub fn xy(x_and_y: f32) -> Self {
19        Self {
20            x: x_and_y,
21            y: x_and_y,
22        }
23    }
24
25    pub fn new(x: f32, y: f32) -> Self {
26        Self { x, y }
27    }
28    pub fn new_from_geo(geo_coord: &Coord<f32>) -> Self {
29        Self {
30            x: geo_coord.x,
31            y: geo_coord.y,
32        }
33    }
34    pub fn polar(angle: Angle, distance: f32) -> Self {
35        Self {
36            x: angle.to_rad().cos() * distance,
37            y: angle.to_rad().sin() * distance,
38        }
39    }
40    pub fn zero() -> Self {
41        Self { x: 0.0, y: 0.0 }
42    }
43    pub fn up() -> Self {
44        Self { x: 0.0, y: 1.0 }
45    }
46    pub fn right() -> Self {
47        Self { x: 1.0, y: 0.0 }
48    }
49    pub fn down() -> Self {
50        Self { x: 0.0, y: -1.0 }
51    }
52    pub fn left() -> Self {
53        Self { x: 0.0, y: -1.0 }
54    }
55
56    pub fn random_unit_circle() -> Self {
57        Self::polar(Angle::rand(), 1.0)
58    }
59    pub fn random_unit_disk() -> Self {
60        let angle = Angle::rand();
61        let radius = rand_range(0.0, 1.0).sqrt();
62        Self::polar(angle, radius)
63    }
64    pub fn random_in_rect(rect: &Rect) -> Self {
65        Self::new(
66            rand_range(rect.bl().x, rect.tr().x),
67            rand_range(rect.bl().y, rect.tr().y),
68        )
69    }
70
71    pub fn din_a(number: u8) -> Self {
72        match number {
73            0 => Self::a0(),
74            1 => Self::a1(),
75            2 => Self::a2(),
76            3 => Self::a3(),
77            4 => Self::a4(),
78            5 => Self::a5(),
79            6 => Self::a6(),
80            7 => Self::a7(),
81            8 => Self::a8(),
82            9 => Self::a9(),
83            10 => Self::a10(),
84            _ => panic!("DIN A number out of range."),
85        }
86    }
87    pub fn a0() -> Self {
88        Self { x: 84.1, y: 118.9 }
89    }
90    pub fn a1() -> Self {
91        Self { x: 59.4, y: 84.1 }
92    }
93    pub fn a2() -> Self {
94        Self { x: 42.0, y: 59.4 }
95    }
96    pub fn a3() -> Self {
97        Self { x: 29.7, y: 42.0 }
98    }
99    pub fn a4() -> Self {
100        Self { x: 21.0, y: 29.7 }
101    }
102    pub fn a5() -> Self {
103        Self { x: 14.8, y: 21.0 }
104    }
105    pub fn a6() -> Self {
106        Self { x: 10.5, y: 14.8 }
107    }
108    pub fn a7() -> Self {
109        Self { x: 7.4, y: 10.5 }
110    }
111    pub fn a8() -> Self {
112        Self { x: 5.2, y: 7.4 }
113    }
114    pub fn a9() -> Self {
115        Self { x: 3.7, y: 5.2 }
116    }
117    pub fn a10() -> Self {
118        Self { x: 2.6, y: 3.7 }
119    }
120
121    pub fn swap(&self) -> Self {
122        Self {
123            x: self.y,
124            y: self.x,
125        }
126    }
127
128    pub fn only_x(&self) -> Self {
129        Self { x: self.x, y: 0.0 }
130    }
131    pub fn only_y(&self) -> Self {
132        Self { x: 0.0, y: self.y }
133    }
134
135    pub fn as_geo_coord(&self) -> Coord<f32> {
136        Coord {
137            x: self.x,
138            y: self.y,
139        }
140    }
141    pub fn as_tuple(&self) -> (f32, f32) {
142        (self.x, self.y)
143    }
144    pub fn as_array(&self) -> [f32; 2] {
145        [self.x, self.y]
146    }
147    pub fn as_vec(&self) -> Vec<f32> {
148        vec![self.x, self.y]
149    }
150
151    pub fn round(&self) -> Self {
152        Self {
153            x: self.x.round(),
154            y: self.y.round(),
155        }
156    }
157    pub fn round_to_int(&self) -> V2i {
158        V2i::new(self.x.round() as i32, self.y.round() as i32)
159    }
160
161    pub fn ceil(&self) -> Self {
162        Self {
163            x: self.x.ceil(),
164            y: self.y.ceil(),
165        }
166    }
167    pub fn ceil_to_int(&self) -> V2i {
168        V2i::new(self.x.ceil() as i32, self.y.ceil() as i32)
169    }
170
171    pub fn floor(&self) -> Self {
172        Self {
173            x: self.x.floor(),
174            y: self.y.floor(),
175        }
176    }
177    pub fn floor_to_int(&self) -> V2i {
178        V2i::new(self.x.floor() as i32, self.y.floor() as i32)
179    }
180
181    pub fn dot(&self, other: &Self) -> f32 {
182        self.x * other.x + self.y * other.y
183    }
184
185    pub fn min(&self, other: &Self) -> Self {
186        V2::new(self.x.min(other.x), self.y.min(other.y))
187    }
188    pub fn min_axis(&self) -> f32 {
189        self.x.min(self.y)
190    }
191    pub fn max(&self, other: &Self) -> Self {
192        V2::new(self.x.max(other.x), self.y.max(other.y))
193    }
194    pub fn max_axis(&self) -> f32 {
195        self.x.max(self.y)
196    }
197
198    pub fn dist(&self, other: &Self) -> f32 {
199        ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
200    }
201    pub fn dist_squared(&self, other: &Self) -> f32 {
202        (self.x - other.x).powi(2) + (self.y - other.y).powi(2)
203    }
204    pub fn dist_manhattan(&self, other: &Self) -> f32 {
205        (self.x - other.x).abs() + (self.y - other.y).abs()
206    }
207
208    pub fn len(&self) -> f32 {
209        (self.x * self.x + self.y * self.y).sqrt()
210    }
211    pub fn len_squared(&self) -> f32 {
212        self.x * self.x + self.y * self.y
213    }
214
215    pub fn angle(&self) -> Angle {
216        let mut rad = self.y.atan2(self.x);
217        if rad < 0.0 {
218            rad += 2.0 * PI;
219        }
220        Angle::from_rad(rad)
221    }
222    pub fn angle_to(&self, other: &Self) -> Angle {
223        (other - self).angle()
224    }
225
226    pub fn normalize(&self) -> Self {
227        let len = self.len();
228        if len == 0.0 {
229            *self
230        } else {
231            *self / len
232        }
233    }
234    pub fn normalize_to(&self, len: f32) -> Self {
235        *self * len / self.len()
236    }
237
238    /// project a point onto the infinite line defined by the vector
239    pub fn project_onto(&self, other: &Self) -> Self {
240        let length_squared = other.len_squared();
241        let dot_product = self.dot(other);
242        V2::new(
243            (dot_product / length_squared) * other.x,
244            (dot_product / length_squared) * other.y,
245        )
246    }
247
248    pub fn clamp_len(&self, min_len: f32, max_len: f32) -> Self {
249        let len = self.len();
250        if len < min_len {
251            *self * (min_len / len)
252        } else if len > max_len {
253            *self * (max_len / len)
254        } else {
255            *self
256        }
257    }
258
259    pub fn map(&self, f: fn(f32) -> f32) -> Self {
260        V2::new(f(self.x), f(self.y))
261    }
262
263    pub fn sqrt(&self) -> Self {
264        V2::new(self.x.sqrt(), self.y.sqrt())
265    }
266
267    pub fn lerp(&self, other: &Self, t: f32) -> Self {
268        V2::new(
269            self.x + t * (other.x - self.x),
270            self.y + t * (other.y - self.y),
271        )
272    }
273    pub fn lerp_iter_fixed(&self, end: V2, steps: usize) -> V2Interpolator {
274        V2Interpolator::new(*self, end, steps)
275    }
276    pub fn lerp_iter(&self, end: V2, sample_settings: &SampleSettings) -> V2Interpolator {
277        let distance = self.dist(&end);
278        V2Interpolator::new(
279            *self,
280            end,
281            sample_settings.get_num_points_for_length(distance) as usize,
282        )
283    }
284}
285
286pub struct V2Interpolator {
287    start: V2,
288    end: V2,
289    steps: usize,
290    current_step: usize,
291}
292
293impl V2Interpolator {
294    pub fn new(start: V2, end: V2, steps: usize) -> Self {
295        Self {
296            start,
297            end,
298            steps,
299            current_step: 0,
300        }
301    }
302}
303
304impl Iterator for V2Interpolator {
305    type Item = V2;
306
307    fn next(&mut self) -> Option<Self::Item> {
308        if self.current_step > self.steps {
309            return None;
310        }
311        let t = self.current_step as f32 / self.steps as f32;
312        let interpolated = self.start.lerp(&self.end, t);
313        self.current_step += 1;
314        Some(interpolated)
315    }
316}
317
318impl Rotate for V2 {
319    fn rotate(&self, angle: &Angle) -> Self {
320        let angle = angle.to_rad();
321        let angle_sin = angle.sin();
322        let angle_cos = angle.cos();
323        Self::new(
324            self.x * angle_cos - self.y * angle_sin,
325            self.x * angle_sin + self.y * angle_cos,
326        )
327    }
328    fn rotate_mut(&mut self, angle: &Angle) {
329        *self = self.rotate(angle);
330    }
331
332    fn rotate_around(&self, pivot: &V2, angle: &Angle) -> Self {
333        let angle = angle.to_rad();
334        let angle_sin = angle.sin();
335        let angle_cos = angle.cos();
336
337        let x_offset = self.x - pivot.x;
338        let y_offset = self.y - pivot.y;
339
340        Self::new(
341            (x_offset * angle_cos - y_offset * angle_sin) + pivot.x,
342            (x_offset * angle_sin + y_offset * angle_cos) + pivot.y,
343        )
344    }
345    fn rotate_around_mut(&mut self, pivot: &V2, angle: &Angle) {
346        *self = self.rotate_around(pivot, angle);
347    }
348}
349
350impl Rotate90 for V2 {
351    fn rotate_90(&self) -> Self {
352        Self::new(-self.y, self.x)
353    }
354    fn rotate_90_mut(&mut self) {
355        *self = self.rotate_90();
356    }
357
358    fn rotate_180(&self) -> Self {
359        Self::new(-self.x, -self.y)
360    }
361    fn rotate_180_mut(&mut self) {
362        *self = self.rotate_180();
363    }
364
365    fn rotate_270(&self) -> Self {
366        Self::new(self.y, -self.x)
367    }
368    fn rotate_270_mut(&mut self) {
369        *self = self.rotate_270();
370    }
371
372    fn rotate_90_around(&self, pivot: &V2) -> Self {
373        Self::new(-self.y + pivot.y + pivot.x, self.x - pivot.x + pivot.y)
374    }
375    fn rotate_90_around_mut(&mut self, pivot: &V2) {
376        *self = self.rotate_90_around(pivot);
377    }
378
379    fn rotate_180_around(&self, pivot: &V2) -> Self {
380        Self::new(pivot.x * 2.0 - self.x, pivot.y * 2.0 - self.y)
381    }
382    fn rotate_180_around_mut(&mut self, pivot: &V2) {
383        *self = self.rotate_180_around(pivot);
384    }
385
386    fn rotate_270_around(&self, pivot: &V2) -> Self {
387        Self::new(self.y - pivot.y + pivot.x, -self.x + pivot.x + pivot.y)
388    }
389    fn rotate_270_around_mut(&mut self, pivot: &V2) {
390        *self = self.rotate_270_around(pivot);
391    }
392}
393
394impl Sum for V2 {
395    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
396        iter.fold(V2::zero(), |a, b| a + b)
397    }
398}
399
400impl From<Point2<f32>> for V2 {
401    fn from(point: Point2<f32>) -> Self {
402        Self::new(point.x, point.y)
403    }
404}
405
406impl From<V2> for Point2<f32> {
407    fn from(v2: V2) -> Self {
408        Point2 { x: v2.x, y: v2.y }
409    }
410}
411
412impl From<&V2> for Point2<f32> {
413    fn from(v2: &V2) -> Self {
414        Point2 { x: v2.x, y: v2.y }
415    }
416}
417
418impl From<&Point2<f32>> for V2 {
419    fn from(point: &Point2<f32>) -> Self {
420        Self::new(point.x, point.y)
421    }
422}