murrelet_common/
polyline.rs

1//! A way to represent a shape from line segments.
2//! I'm not sure if I'll keep going down this route for
3//! shapes in general.
4use glam::{vec2, Mat4, Vec2};
5use itertools::Itertools;
6
7use crate::{geometry::SpotOnCurve, transform::TransformVec2};
8
9#[derive(Debug, Clone)]
10pub struct Polyline {
11    v: Vec<Vec2>,
12}
13impl Polyline {
14    pub fn new(v: Vec<Vec2>) -> Self {
15        Self { v }
16    }
17
18    pub fn empty() -> Self {
19        Self { v: vec![] }
20    }
21
22    pub fn is_empty(&self) -> bool {
23        self.v.is_empty()
24    }
25
26    pub fn reverse(&mut self) {
27        self.v.reverse()
28    }
29
30    pub fn first(&self) -> Option<&Vec2> {
31        self.v.first()
32    }
33
34    pub fn last(&self) -> Option<&Vec2> {
35        self.v.last()
36    }
37
38    pub fn len(&self) -> usize {
39        self.v.len()
40    }
41
42    pub fn vertices(&self) -> &[Vec2] {
43        &self.v
44    }
45
46    pub fn apply_transform(self, transform: Mat4) -> Self {
47        let vs = self
48            .into_iter_vec2()
49            .map(|x| {
50                let p = transform.transform_vec2(x);
51                vec2(p.x, p.y)
52            })
53            .collect_vec();
54        Polyline::new(vs)
55    }
56
57    pub fn transform_with<T: TransformVec2>(&self, t: &T) -> Self {
58        t.transform_many_vec2(self)
59    }
60
61    pub fn add_pt_to_end(&mut self, pt: Vec2) {
62        self.v.push(pt)
63    }
64}
65
66// IsPolyline traits
67
68pub trait IsPolyline {
69    fn into_iter_vec2<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = Vec2> + 'a>;
70    fn as_polyline(self) -> Polyline;
71    fn into_vec(self) -> Vec<Vec2>;
72    fn clone_to_vec(&self) -> Vec<Vec2>;
73}
74
75impl IsPolyline for Polyline {
76    fn into_iter_vec2<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = Vec2> + 'a> {
77        Box::new(self.v.iter().cloned())
78    }
79
80    fn as_polyline(self) -> Polyline {
81        self
82    }
83
84    fn into_vec(self) -> Vec<Vec2> {
85        self.v
86    }
87
88    fn clone_to_vec(&self) -> Vec<Vec2> {
89        self.v.clone()
90    }
91}
92
93impl IsPolyline for &[Vec2] {
94    fn into_iter_vec2<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = Vec2> + 'a> {
95        Box::new(self.iter().cloned())
96    }
97
98    fn as_polyline(self) -> Polyline {
99        Polyline { v: self.to_vec() }
100    }
101
102    fn into_vec(self) -> Vec<Vec2> {
103        self.to_vec()
104    }
105
106    fn clone_to_vec(&self) -> Vec<Vec2> {
107        self.to_vec()
108    }
109}
110
111impl IsPolyline for Vec<Vec2> {
112    fn into_iter_vec2<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = Vec2> + 'a> {
113        Box::new(self.iter().cloned())
114    }
115
116    fn as_polyline(self) -> Polyline {
117        Polyline { v: self }
118    }
119
120    fn into_vec(self) -> Vec<Vec2> {
121        self
122    }
123
124    fn clone_to_vec(&self) -> Vec<Vec2> {
125        self.clone()
126    }
127}
128
129// ANGLED POLYLINE
130// like polyline, but uses SpotOnCurve
131
132#[derive(Debug, Clone)]
133pub struct AngledPolyline {
134    v: Vec<SpotOnCurve>,
135}
136
137impl AngledPolyline {
138    pub fn new(v: Vec<SpotOnCurve>) -> Self {
139        Self { v }
140    }
141
142    pub fn empty() -> Self {
143        Self { v: vec![] }
144    }
145
146    pub fn is_empty(&self) -> bool {
147        self.v.is_empty()
148    }
149
150    pub fn reverse(&mut self) {
151        self.v.reverse()
152    }
153
154    pub fn first(&self) -> Option<&SpotOnCurve> {
155        self.v.first()
156    }
157
158    pub fn last(&self) -> Option<&SpotOnCurve> {
159        self.v.last()
160    }
161
162    pub fn len(&self) -> usize {
163        self.v.len()
164    }
165
166    pub fn vertices(&self) -> &[SpotOnCurve] {
167        &self.v
168    }
169}
170
171impl IsPolyline for AngledPolyline {
172    fn into_iter_vec2<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = Vec2> + 'a> {
173        Box::new(self.v.iter().map(|x| x.loc()))
174    }
175
176    fn as_polyline(self) -> Polyline {
177        // actually cloning...
178        self.into_iter_vec2().collect_vec().as_polyline()
179    }
180
181    // actually cloning...
182    fn into_vec(self) -> Vec<Vec2> {
183        self.into_iter_vec2().collect_vec()
184    }
185
186    fn clone_to_vec(&self) -> Vec<Vec2> {
187        self.into_iter_vec2().collect_vec()
188    }
189}
190
191pub trait IsAngledPolyline {
192    fn into_iter_spot<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = SpotOnCurve> + 'a>;
193    fn as_angled_polyline(self) -> AngledPolyline;
194    fn into_vec(self) -> Vec<SpotOnCurve>;
195    fn clone_to_spot_vec(&self) -> Vec<SpotOnCurve> {
196        self.into_iter_spot().collect_vec()
197    }
198}
199
200impl IsAngledPolyline for &[SpotOnCurve] {
201    fn into_iter_spot<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = SpotOnCurve> + 'a> {
202        Box::new(self.iter().cloned())
203    }
204
205    fn as_angled_polyline(self) -> AngledPolyline {
206        AngledPolyline { v: self.to_vec() }
207    }
208
209    fn into_vec(self) -> Vec<SpotOnCurve> {
210        self.to_vec()
211    }
212}
213
214impl IsAngledPolyline for Vec<SpotOnCurve> {
215    fn into_iter_spot<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = SpotOnCurve> + 'a> {
216        Box::new(self.iter().cloned())
217    }
218
219    fn as_angled_polyline(self) -> AngledPolyline {
220        AngledPolyline { v: self.to_vec() }
221    }
222
223    fn into_vec(self) -> Vec<SpotOnCurve> {
224        self.to_vec()
225    }
226}
227
228impl IsAngledPolyline for AngledPolyline {
229    fn into_iter_spot<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = SpotOnCurve> + 'a> {
230        Box::new(self.v.iter().cloned())
231    }
232
233    fn as_angled_polyline(self) -> AngledPolyline {
234        self
235    }
236
237    fn into_vec(self) -> Vec<SpotOnCurve> {
238        self.v
239    }
240}