geo/algorithm/
extremes.rs1use crate::CoordsIter;
2use crate::{Coord, CoordNum};
3
4pub trait Extremes<'a, T: CoordNum> {
28 fn extremes(&'a self) -> Option<Outcome<T>>;
29}
30
31#[derive(Debug, PartialEq, Eq)]
32pub struct Extreme<T: CoordNum> {
33 pub index: usize,
34 pub coord: Coord<T>,
35}
36
37#[derive(Debug, PartialEq, Eq)]
38pub struct Outcome<T: CoordNum> {
39 pub x_min: Extreme<T>,
40 pub y_min: Extreme<T>,
41 pub x_max: Extreme<T>,
42 pub y_max: Extreme<T>,
43}
44
45impl<'a, T, G> Extremes<'a, T> for G
46where
47 G: CoordsIter<'a, Scalar = T>,
48 T: CoordNum,
49{
50 fn extremes(&'a self) -> Option<Outcome<T>> {
51 let mut iter = self.exterior_coords_iter().enumerate();
52
53 let mut outcome = iter.next().map(|(index, coord)| Outcome {
54 x_min: Extreme { index, coord },
55 y_min: Extreme { index, coord },
56 x_max: Extreme { index, coord },
57 y_max: Extreme { index, coord },
58 })?;
59
60 for (index, coord) in iter {
61 if coord.x < outcome.x_min.coord.x {
62 outcome.x_min = Extreme { coord, index };
63 }
64
65 if coord.y < outcome.y_min.coord.y {
66 outcome.y_min = Extreme { coord, index };
67 }
68
69 if coord.x > outcome.x_max.coord.x {
70 outcome.x_max = Extreme { coord, index };
71 }
72
73 if coord.y > outcome.y_max.coord.y {
74 outcome.y_max = Extreme { coord, index };
75 }
76 }
77
78 Some(outcome)
79 }
80}
81
82#[cfg(test)]
83mod test {
84 use super::*;
85 use crate::{coord, polygon, MultiPoint};
86
87 #[test]
88 fn polygon() {
89 let polygon = polygon![
91 (x: 1.0, y: 0.0),
92 (x: 2.0, y: 1.0),
93 (x: 1.0, y: 2.0),
94 (x: 0.0, y: 1.0),
95 (x: 1.0, y: 0.0),
96 ];
97
98 let actual = polygon.extremes();
99
100 assert_eq!(
101 Some(Outcome {
102 x_min: Extreme {
103 index: 3,
104 coord: coord! { x: 0.0, y: 1.0 }
105 },
106 y_min: Extreme {
107 index: 0,
108 coord: coord! { x: 1.0, y: 0.0 }
109 },
110 x_max: Extreme {
111 index: 1,
112 coord: coord! { x: 2.0, y: 1.0 }
113 },
114 y_max: Extreme {
115 index: 2,
116 coord: coord! { x: 1.0, y: 2.0 }
117 }
118 }),
119 actual
120 );
121 }
122
123 #[test]
124 fn empty() {
125 let multi_point: MultiPoint<f32> = MultiPoint::new(vec![]);
126
127 let actual = multi_point.extremes();
128
129 assert!(actual.is_none());
130 }
131}