1use geometry_model::{Linestring, MultiLinestring, MultiPoint, MultiPolygon, Point, Polygon, Ring};
11use geometry_trait::{
12 Closure, Linestring as LinestringTrait, MultiPoint as MultiPointTrait, Polygon as PolygonTrait,
13 Ring as RingTrait,
14};
15
16pub fn for_each_point<G, F>(g: &G, mut f: F)
23where
24 G: ForEachPoint,
25 F: FnMut(&G::Point),
26{
27 g.for_each_point(&mut f);
28}
29
30#[doc(hidden)]
32pub trait ForEachPoint {
33 type Point: geometry_trait::Point;
34 fn for_each_point<F: FnMut(&Self::Point)>(&self, f: &mut F);
35}
36
37impl<T, const D: usize, Cs> ForEachPoint for Point<T, D, Cs>
38where
39 T: geometry_coords::CoordinateScalar,
40 Cs: geometry_cs::CoordinateSystem,
41{
42 type Point = Self;
43 fn for_each_point<F: FnMut(&Self::Point)>(&self, f: &mut F) {
44 f(self);
45 }
46}
47
48impl<P: geometry_trait::Point> ForEachPoint for Linestring<P> {
49 type Point = P;
50 fn for_each_point<F: FnMut(&P)>(&self, f: &mut F) {
51 for p in self.points() {
52 f(p);
53 }
54 }
55}
56
57impl<P: geometry_trait::Point, const CW: bool, const CL: bool> ForEachPoint for Ring<P, CW, CL> {
58 type Point = P;
59 fn for_each_point<F: FnMut(&P)>(&self, f: &mut F) {
60 for p in self.points() {
61 f(p);
62 }
63 }
64}
65
66impl<P: geometry_trait::Point, const CW: bool, const CL: bool> ForEachPoint for Polygon<P, CW, CL> {
67 type Point = P;
68 fn for_each_point<F: FnMut(&P)>(&self, f: &mut F) {
69 self.exterior().for_each_point(f);
70 for inner in self.interiors() {
71 inner.for_each_point(f);
72 }
73 }
74}
75
76impl<P: geometry_trait::Point> ForEachPoint for MultiPoint<P> {
77 type Point = P;
78 fn for_each_point<F: FnMut(&P)>(&self, f: &mut F) {
79 for p in self.points() {
80 f(p);
81 }
82 }
83}
84
85impl<L> ForEachPoint for MultiLinestring<L>
86where
87 L: LinestringTrait + ForEachPoint<Point = <L as geometry_trait::Geometry>::Point>,
88{
89 type Point = <L as geometry_trait::Geometry>::Point;
90 fn for_each_point<F: FnMut(&Self::Point)>(&self, f: &mut F) {
91 for l in &self.0 {
92 l.for_each_point(f);
93 }
94 }
95}
96
97impl<Pg> ForEachPoint for MultiPolygon<Pg>
98where
99 Pg: PolygonTrait + ForEachPoint<Point = <Pg as geometry_trait::Geometry>::Point>,
100{
101 type Point = <Pg as geometry_trait::Geometry>::Point;
102 fn for_each_point<F: FnMut(&Self::Point)>(&self, f: &mut F) {
103 for p in &self.0 {
104 p.for_each_point(f);
105 }
106 }
107}
108
109pub fn for_each_segment<G, F>(g: &G, mut f: F)
117where
118 G: ForEachSegment,
119 F: FnMut(&G::Point, &G::Point),
120{
121 g.for_each_segment(&mut f);
122}
123
124#[doc(hidden)]
126pub trait ForEachSegment {
127 type Point: geometry_trait::Point;
128 fn for_each_segment<F: FnMut(&Self::Point, &Self::Point)>(&self, f: &mut F);
129}
130
131impl<P: geometry_trait::Point> ForEachSegment for Linestring<P> {
132 type Point = P;
133 fn for_each_segment<F: FnMut(&P, &P)>(&self, f: &mut F) {
134 let pts: alloc::vec::Vec<&P> = self.points().collect();
135 for w in pts.windows(2) {
136 f(w[0], w[1]);
137 }
138 }
139}
140
141impl<P: geometry_trait::Point, const CW: bool, const CL: bool> ForEachSegment for Ring<P, CW, CL> {
142 type Point = P;
143 fn for_each_segment<F: FnMut(&P, &P)>(&self, f: &mut F) {
144 let pts: alloc::vec::Vec<&P> = self.points().collect();
145 if pts.len() < 2 {
146 return;
147 }
148 for w in pts.windows(2) {
149 f(w[0], w[1]);
150 }
151 if matches!(self.closure(), Closure::Open) {
155 f(pts[pts.len() - 1], pts[0]);
156 }
157 }
158}
159
160impl<P: geometry_trait::Point, const CW: bool, const CL: bool> ForEachSegment
161 for Polygon<P, CW, CL>
162{
163 type Point = P;
164 fn for_each_segment<F: FnMut(&P, &P)>(&self, f: &mut F) {
165 self.exterior().for_each_segment(f);
166 for inner in self.interiors() {
167 inner.for_each_segment(f);
168 }
169 }
170}
171
172impl<L> ForEachSegment for MultiLinestring<L>
173where
174 L: LinestringTrait + ForEachSegment<Point = <L as geometry_trait::Geometry>::Point>,
175{
176 type Point = <L as geometry_trait::Geometry>::Point;
177 fn for_each_segment<F: FnMut(&Self::Point, &Self::Point)>(&self, f: &mut F) {
178 for l in &self.0 {
179 l.for_each_segment(f);
180 }
181 }
182}
183
184impl<Pg> ForEachSegment for MultiPolygon<Pg>
185where
186 Pg: PolygonTrait + ForEachSegment<Point = <Pg as geometry_trait::Geometry>::Point>,
187{
188 type Point = <Pg as geometry_trait::Geometry>::Point;
189 fn for_each_segment<F: FnMut(&Self::Point, &Self::Point)>(&self, f: &mut F) {
190 for p in &self.0 {
191 p.for_each_segment(f);
192 }
193 }
194}
195
196#[cfg(test)]
197#[allow(clippy::float_cmp, reason = "Visited coordinates are exact literals.")]
198mod tests {
199 use super::{for_each_point, for_each_segment};
202 use geometry_cs::Cartesian;
203 use geometry_model::{Linestring, MultiPoint, Point2D, Polygon, linestring, polygon};
204 use geometry_trait::Point as _;
205
206 type Pt = Point2D<f64, Cartesian>;
207
208 #[test]
209 fn point_visits_once() {
210 let p = Pt::new(3.0, 4.0);
211 let mut sum = 0.0;
212 for_each_point(&p, |q| sum += q.get::<0>() + q.get::<1>());
213 assert_eq!(sum, 7.0);
214 }
215
216 #[test]
217 fn linestring_visits_in_order() {
218 let ls: Linestring<Pt> = linestring![(0.0, 0.0), (3.0, 4.0), (4.0, 3.0)];
219 let mut xs = alloc::vec::Vec::new();
220 for_each_point(&ls, |p| xs.push(p.get::<0>()));
221 assert_eq!(xs, vec![0.0, 3.0, 4.0]);
222 }
223
224 #[test]
225 fn polygon_visits_outer_then_inner() {
226 let pg: Polygon<Pt> = polygon![
227 [(0.0, 0.0), (5.0, 0.0), (5.0, 5.0), (0.0, 5.0), (0.0, 0.0)],
228 [(1.0, 1.0), (2.0, 1.0), (2.0, 2.0), (1.0, 1.0)]
229 ];
230 let mut count = 0;
231 for_each_point(&pg, |_| count += 1);
232 assert_eq!(count, 5 + 4); }
234
235 #[test]
236 fn multipoint_visits_each() {
237 let mp = MultiPoint(vec![Pt::new(0.0, 0.0), Pt::new(1.0, 1.0)]);
238 let mut count = 0;
239 for_each_point(&mp, |_| count += 1);
240 assert_eq!(count, 2);
241 }
242
243 #[test]
244 fn linestring_segments_are_consecutive_pairs() {
245 let ls: Linestring<Pt> = linestring![(0.0, 0.0), (3.0, 0.0), (3.0, 4.0)];
246 let mut edges = alloc::vec::Vec::new();
247 for_each_segment(&ls, |a, b| edges.push((a.get::<0>(), b.get::<0>())));
248 assert_eq!(edges, vec![(0.0, 3.0), (3.0, 3.0)]);
249 }
250
251 #[test]
252 fn closed_ring_segment_count_equals_edges() {
253 let pg: Polygon<Pt> =
256 polygon![[(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)]];
257 let mut count = 0;
258 for_each_segment(&pg, |_, _| count += 1);
259 assert_eq!(count, 4);
260 }
261
262 use geometry_model::{MultiLinestring, MultiPolygon, Ring};
263
264 #[test]
266 fn multilinestring_visits_all_member_points() {
267 let mls: MultiLinestring<Linestring<Pt>> = MultiLinestring(vec![
268 linestring![(0.0, 0.0), (1.0, 1.0)],
269 linestring![(2.0, 2.0), (3.0, 3.0), (4.0, 4.0)],
270 ]);
271 let mut xs = alloc::vec::Vec::new();
272 for_each_point(&mls, |p| xs.push(p.get::<0>()));
273 assert_eq!(xs, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
274 }
275
276 #[test]
278 fn multipolygon_visits_all_member_points() {
279 let member: Polygon<Pt> = polygon![[(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]];
280 let mpg: MultiPolygon<Polygon<Pt>> = MultiPolygon(vec![member.clone(), member]);
281 let mut count = 0;
282 for_each_point(&mpg, |_| count += 1);
283 assert_eq!(count, 8); }
285
286 #[test]
289 fn open_ring_emits_implicit_closing_edge() {
290 let ring: Ring<Pt, true, false> = Ring::from_vec(vec![
293 Pt::new(0.0, 0.0),
294 Pt::new(2.0, 0.0),
295 Pt::new(2.0, 2.0),
296 Pt::new(0.0, 2.0),
297 ]);
298 let mut edges = alloc::vec::Vec::new();
299 for_each_segment(&ring, |a, b| {
300 edges.push(((a.get::<0>(), a.get::<1>()), (b.get::<0>(), b.get::<1>())));
301 });
302 assert_eq!(edges.len(), 4);
303 assert_eq!(*edges.last().unwrap(), ((0.0, 2.0), (0.0, 0.0)));
305 }
306
307 #[test]
310 fn degenerate_ring_emits_no_segments() {
311 let ring: Ring<Pt, true, false> = Ring::from_vec(vec![Pt::new(1.0, 1.0)]);
312 let mut count = 0;
313 for_each_segment(&ring, |_, _| count += 1);
314 assert_eq!(count, 0);
315 }
316
317 #[test]
319 fn multilinestring_visits_all_member_segments() {
320 let mls: MultiLinestring<Linestring<Pt>> = MultiLinestring(vec![
321 linestring![(0.0, 0.0), (1.0, 1.0)], linestring![(2.0, 2.0), (3.0, 3.0), (4.0, 4.0)], ]);
324 let mut count = 0;
325 for_each_segment(&mls, |_, _| count += 1);
326 assert_eq!(count, 3);
327 }
328
329 #[test]
331 fn multipolygon_visits_all_member_segments() {
332 let member: Polygon<Pt> =
333 polygon![[(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)]]; let mpg: MultiPolygon<Polygon<Pt>> = MultiPolygon(vec![member.clone(), member]);
335 let mut count = 0;
336 for_each_segment(&mpg, |_, _| count += 1);
337 assert_eq!(count, 8); }
339}