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}