1use crate::{
2 Coord, CoordNum, Line, LineString, MultiLineString, MultiPolygon, Polygon, Rect, Triangle,
3};
4use core::slice;
5use std::fmt::Debug;
6use std::iter;
7
8pub trait LinesIter<'a> {
10 type Scalar: CoordNum;
11 type Iter: Iterator<Item = Line<Self::Scalar>>;
12
13 fn lines_iter(&'a self) -> Self::Iter;
46}
47
48impl<'a, T: CoordNum + 'a> LinesIter<'a> for Line<T> {
49 type Scalar = T;
50 type Iter = iter::Copied<iter::Once<&'a Line<Self::Scalar>>>;
51
52 fn lines_iter(&'a self) -> Self::Iter {
53 iter::once(self).copied()
54 }
55}
56
57impl<'a, T: CoordNum + 'a> LinesIter<'a> for LineString<T> {
58 type Scalar = T;
59 type Iter = LineStringIter<'a, Self::Scalar>;
60
61 fn lines_iter(&'a self) -> Self::Iter {
62 LineStringIter::new(self)
63 }
64}
65
66#[derive(Debug)]
68pub struct LineStringIter<'a, T: CoordNum>(slice::Windows<'a, Coord<T>>);
69
70impl<'a, T: CoordNum> LineStringIter<'a, T> {
71 fn new(line_string: &'a LineString<T>) -> Self {
72 Self(line_string.0.windows(2))
73 }
74}
75
76impl<'a, T: CoordNum> Iterator for LineStringIter<'a, T> {
77 type Item = Line<T>;
78
79 fn next(&mut self) -> Option<Self::Item> {
80 self.0.next().map(|w| {
85 unsafe { Line::new(*w.get_unchecked(0), *w.get_unchecked(1)) }
87 })
88 }
89}
90
91type MultiLineStringIter<'a, T> =
92 iter::Flatten<MapLinesIter<'a, slice::Iter<'a, LineString<T>>, LineString<T>>>;
93
94impl<'a, T: CoordNum + 'a> LinesIter<'a> for MultiLineString<T> {
95 type Scalar = T;
96 type Iter = MultiLineStringIter<'a, Self::Scalar>;
97
98 fn lines_iter(&'a self) -> Self::Iter {
99 MapLinesIter(self.0.iter()).flatten()
100 }
101}
102
103type PolygonIter<'a, T> = iter::Chain<
104 LineStringIter<'a, T>,
105 iter::Flatten<MapLinesIter<'a, slice::Iter<'a, LineString<T>>, LineString<T>>>,
106>;
107
108impl<'a, T: CoordNum + 'a> LinesIter<'a> for Polygon<T> {
109 type Scalar = T;
110 type Iter = PolygonIter<'a, Self::Scalar>;
111
112 fn lines_iter(&'a self) -> Self::Iter {
113 self.exterior()
114 .lines_iter()
115 .chain(MapLinesIter(self.interiors().iter()).flatten())
116 }
117}
118
119type MultiPolygonIter<'a, T> =
120 iter::Flatten<MapLinesIter<'a, slice::Iter<'a, Polygon<T>>, Polygon<T>>>;
121
122impl<'a, T: CoordNum + 'a> LinesIter<'a> for MultiPolygon<T> {
123 type Scalar = T;
124 type Iter = MultiPolygonIter<'a, Self::Scalar>;
125
126 fn lines_iter(&'a self) -> Self::Iter {
127 MapLinesIter(self.0.iter()).flatten()
128 }
129}
130
131impl<'a, T: CoordNum + 'a> LinesIter<'a> for Rect<T> {
132 type Scalar = T;
133 type Iter = <[Line<Self::Scalar>; 4] as IntoIterator>::IntoIter;
134
135 fn lines_iter(&'a self) -> Self::Iter {
136 self.to_lines().into_iter()
137 }
138}
139
140impl<'a, T: CoordNum + 'a> LinesIter<'a> for Triangle<T> {
141 type Scalar = T;
142 type Iter = <[Line<Self::Scalar>; 3] as IntoIterator>::IntoIter;
143
144 fn lines_iter(&'a self) -> Self::Iter {
145 self.to_lines().into_iter()
146 }
147}
148
149#[derive(Debug)]
151pub struct MapLinesIter<'a, Iter1: Iterator<Item = &'a Iter2>, Iter2: 'a + LinesIter<'a>>(Iter1);
152
153impl<'a, Iter1: Iterator<Item = &'a Iter2>, Iter2: LinesIter<'a>> Iterator
154 for MapLinesIter<'a, Iter1, Iter2>
155{
156 type Item = Iter2::Iter;
157
158 fn next(&mut self) -> Option<Self::Item> {
159 self.0.next().map(|g| g.lines_iter())
160 }
161}
162
163#[cfg(test)]
164mod test {
165
166 use super::LinesIter;
167 use crate::{
168 coord, line_string, polygon, Line, LineString, MultiLineString, MultiPolygon, Rect,
169 Triangle,
170 };
171
172 #[test]
173 fn test_line() {
174 let line = Line::new(coord! { x: 0., y: 0. }, coord! { x: 5., y: 10. });
175 let want = vec![Line::new(coord! { x: 0., y: 0. }, coord! { x: 5., y: 10. })];
176 assert_eq!(want, line.lines_iter().collect::<Vec<_>>());
177 }
178
179 #[test]
180 fn test_empty_line_string() {
181 let ls: LineString = line_string![];
182 assert_eq!(Vec::<Line>::new(), ls.lines_iter().collect::<Vec<_>>());
183 }
184
185 #[test]
186 fn test_open_line_string() {
187 let ls = line_string![(x: 0., y: 0.), (x: 1., y: 1.), (x:2., y: 2.)];
188 let want = vec![
189 Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. }),
190 Line::new(coord! { x: 1., y: 1. }, coord! { x: 2., y: 2. }),
191 ];
192 assert_eq!(want, ls.lines_iter().collect::<Vec<_>>());
193 }
194
195 #[test]
196 fn test_closed_line_string() {
197 let mut ls = line_string![(x: 0., y: 0.), (x: 1., y: 1.), (x:2., y: 2.)];
198 ls.close();
199 let want = vec![
200 Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. }),
201 Line::new(coord! { x: 1., y: 1. }, coord! { x: 2., y: 2. }),
202 Line::new(coord! { x: 2., y: 2. }, coord! { x: 0., y: 0. }),
203 ];
204 assert_eq!(want, ls.lines_iter().collect::<Vec<_>>());
205 }
206
207 #[test]
208 fn test_multi_line_string() {
209 let mls = MultiLineString::new(vec![
210 line_string![],
211 line_string![(x: 0., y: 0.), (x: 1., y: 1.)],
212 line_string![(x: 0., y: 0.), (x: 1., y: 1.), (x:2., y: 2.)],
213 ]);
214 let want = vec![
215 Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. }),
216 Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. }),
217 Line::new(coord! { x: 1., y: 1. }, coord! { x: 2., y: 2. }),
218 ];
219 assert_eq!(want, mls.lines_iter().collect::<Vec<_>>());
220 }
221
222 #[test]
223 fn test_polygon() {
224 let p = polygon!(
225 exterior: [(x: 0., y: 0.), (x: 0., y: 10.), (x: 10., y: 10.), (x: 10., y: 0.)],
226 interiors: [
227 [(x: 1., y: 1.), (x: 1., y: 2.), (x: 2., y: 2.), (x: 2., y: 1.)],
228 [(x: 3., y: 3.), (x: 5., y: 3.), (x: 5., y: 5.), (x: 3., y: 5.)],
229 ],
230 );
231 let want = vec![
232 Line::new(coord! { x: 0., y: 0. }, coord! { x: 0., y: 10. }),
234 Line::new(coord! { x: 0., y: 10. }, coord! { x: 10., y: 10. }),
235 Line::new(coord! { x: 10., y: 10. }, coord! { x: 10., y: 0. }),
236 Line::new(coord! { x: 10., y: 0. }, coord! { x: 0., y: 0. }),
237 Line::new(coord! { x: 1., y: 1. }, coord! { x: 1., y: 2. }),
239 Line::new(coord! { x: 1., y: 2. }, coord! { x: 2., y: 2. }),
240 Line::new(coord! { x: 2., y: 2. }, coord! { x: 2., y: 1. }),
241 Line::new(coord! { x: 2., y: 1. }, coord! { x: 1., y: 1. }),
242 Line::new(coord! { x: 3., y: 3. }, coord! { x: 5., y: 3. }),
244 Line::new(coord! { x: 5., y: 3. }, coord! { x: 5., y: 5. }),
245 Line::new(coord! { x: 5., y: 5. }, coord! { x: 3., y: 5. }),
246 Line::new(coord! { x: 3., y: 5. }, coord! { x: 3., y: 3. }),
247 ];
248 assert_eq!(want, p.lines_iter().collect::<Vec<_>>());
249 }
250
251 #[test]
252 fn test_multi_polygon() {
253 let mp = MultiPolygon::new(vec![
254 polygon!(
255 exterior: [(x: 0., y: 0.), (x: 0., y: 10.), (x: 10., y: 10.), (x: 10., y: 0.)],
256 interiors: [[(x: 1., y: 1.), (x: 1., y: 2.), (x: 2., y: 2.), (x: 2., y: 1.)]],
257 ),
258 polygon!(
259 exterior: [(x: 3., y: 3.), (x: 5., y: 3.), (x: 5., y: 5.), (x: 3., y: 5.)],
260 interiors: [],
261 ),
262 ]);
263 let want = vec![
264 Line::new(coord! { x: 0., y: 0. }, coord! { x: 0., y: 10. }),
266 Line::new(coord! { x: 0., y: 10. }, coord! { x: 10., y: 10. }),
267 Line::new(coord! { x: 10., y: 10. }, coord! { x: 10., y: 0. }),
268 Line::new(coord! { x: 10., y: 0. }, coord! { x: 0., y: 0. }),
269 Line::new(coord! { x: 1., y: 1. }, coord! { x: 1., y: 2. }),
271 Line::new(coord! { x: 1., y: 2. }, coord! { x: 2., y: 2. }),
272 Line::new(coord! { x: 2., y: 2. }, coord! { x: 2., y: 1. }),
273 Line::new(coord! { x: 2., y: 1. }, coord! { x: 1., y: 1. }),
274 Line::new(coord! { x: 3., y: 3. }, coord! { x: 5., y: 3. }),
276 Line::new(coord! { x: 5., y: 3. }, coord! { x: 5., y: 5. }),
277 Line::new(coord! { x: 5., y: 5. }, coord! { x: 3., y: 5. }),
278 Line::new(coord! { x: 3., y: 5. }, coord! { x: 3., y: 3. }),
279 ];
280 assert_eq!(want, mp.lines_iter().collect::<Vec<_>>());
281 }
282
283 #[test]
284 fn test_rect() {
285 let rect = Rect::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 2. });
286 let want = rect.to_polygon().lines_iter().collect::<Vec<_>>();
287 assert_eq!(want, rect.lines_iter().collect::<Vec<_>>());
288 }
289
290 #[test]
291 fn test_triangle() {
292 let triangle = Triangle::new(
293 coord! { x: 0., y: 0. },
294 coord! { x: 1., y: 2. },
295 coord! { x: 2., y: 3. },
296 );
297 let want = triangle.to_polygon().lines_iter().collect::<Vec<_>>();
298 assert_eq!(want, triangle.lines_iter().collect::<Vec<_>>());
299 }
300}