/rust/registry/src/index.crates.io-1949cf8c6b5b557f/geo-0.32.0/src/utils.rs
Line | Count | Source |
1 | | //! Internal utility functions, types, and data structures. |
2 | | |
3 | | use geo_types::{Coord, CoordFloat, CoordNum}; |
4 | | use num_traits::FromPrimitive; |
5 | | |
6 | | /// Partition a mutable slice in-place so that it contains all elements for |
7 | | /// which `predicate(e)` is `true`, followed by all elements for which |
8 | | /// `predicate(e)` is `false`. Returns sub-slices to all predicated and |
9 | | /// non-predicated elements, respectively. |
10 | | /// |
11 | | /// https://github.com/llogiq/partition/blob/master/src/lib.rs |
12 | 0 | pub fn partition_slice<T, P>(data: &mut [T], predicate: P) -> (&mut [T], &mut [T]) |
13 | 0 | where |
14 | 0 | P: Fn(&T) -> bool, |
15 | | { |
16 | 0 | let len = data.len(); |
17 | 0 | if len == 0 { |
18 | 0 | return (&mut [], &mut []); |
19 | 0 | } |
20 | 0 | let (mut l, mut r) = (0, len - 1); |
21 | | loop { |
22 | 0 | while l < len && predicate(&data[l]) { |
23 | 0 | l += 1; |
24 | 0 | } |
25 | 0 | while r > 0 && !predicate(&data[r]) { |
26 | 0 | r -= 1; |
27 | 0 | } |
28 | 0 | if l >= r { |
29 | 0 | return data.split_at_mut(l); |
30 | 0 | } |
31 | 0 | data.swap(l, r); |
32 | | } |
33 | 0 | } |
34 | | |
35 | | pub enum EitherIter<I1, I2> { |
36 | | A(I1), |
37 | | B(I2), |
38 | | } |
39 | | |
40 | | impl<I1, I2> ExactSizeIterator for EitherIter<I1, I2> |
41 | | where |
42 | | I1: ExactSizeIterator, |
43 | | I2: ExactSizeIterator<Item = I1::Item>, |
44 | | { |
45 | | #[inline] |
46 | 0 | fn len(&self) -> usize { |
47 | 0 | match self { |
48 | 0 | EitherIter::A(i1) => i1.len(), |
49 | 0 | EitherIter::B(i2) => i2.len(), |
50 | | } |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl<T, I1, I2> Iterator for EitherIter<I1, I2> |
55 | | where |
56 | | I1: Iterator<Item = T>, |
57 | | I2: Iterator<Item = T>, |
58 | | { |
59 | | type Item = T; |
60 | | |
61 | | #[inline] |
62 | 0 | fn next(&mut self) -> Option<Self::Item> { |
63 | 0 | match self { |
64 | 0 | EitherIter::A(iter) => iter.next(), |
65 | 0 | EitherIter::B(iter) => iter.next(), |
66 | | } |
67 | 0 | } |
68 | | |
69 | | #[inline] |
70 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
71 | 0 | match self { |
72 | 0 | EitherIter::A(iter) => iter.size_hint(), |
73 | 0 | EitherIter::B(iter) => iter.size_hint(), |
74 | | } |
75 | 0 | } |
76 | | } |
77 | | |
78 | | // The Rust standard library has `max` for `Ord`, but not for `PartialOrd` |
79 | 0 | pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T { |
80 | 0 | if a > b { a } else { b } |
81 | 0 | } |
82 | | |
83 | | // The Rust standard library has `min` for `Ord`, but not for `PartialOrd` |
84 | 0 | pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T { |
85 | 0 | if a < b { a } else { b } |
86 | 0 | } |
87 | | |
88 | | use std::cmp::Ordering; |
89 | | |
90 | | /// Compare two coordinates lexicographically: first by the |
91 | | /// x coordinate, and break ties with the y coordinate. |
92 | | /// Expects none of coordinates to be uncomparable (eg. nan) |
93 | | #[inline] |
94 | 0 | pub fn lex_cmp<T: CoordNum>(p: &Coord<T>, q: &Coord<T>) -> Ordering { |
95 | 0 | p.x.partial_cmp(&q.x) |
96 | 0 | .unwrap() |
97 | 0 | .then(p.y.partial_cmp(&q.y).unwrap()) |
98 | 0 | } Unexecuted instantiation: geo::utils::lex_cmp::<f64> Unexecuted instantiation: geo::utils::lex_cmp::<_> |
99 | | |
100 | | /// Compute index of the least point in slice. Comparison is |
101 | | /// done using [`lex_cmp`]. |
102 | | /// |
103 | | /// Should only be called on a non-empty slice with no `nan` |
104 | | /// coordinates. |
105 | 0 | pub fn least_index<T: CoordNum>(pts: &[Coord<T>]) -> usize { |
106 | 0 | pts.iter() |
107 | 0 | .enumerate() |
108 | 0 | .min_by(|(_, p), (_, q)| lex_cmp(p, q)) Unexecuted instantiation: geo::utils::least_index::<f64>::{closure#0}Unexecuted instantiation: geo::utils::least_index::<_>::{closure#0} |
109 | 0 | .unwrap() |
110 | | .0 |
111 | 0 | } Unexecuted instantiation: geo::utils::least_index::<f64> Unexecuted instantiation: geo::utils::least_index::<_> |
112 | | |
113 | | /// Compute index of the lexicographically least _and_ the |
114 | | /// greatest coordinate in one pass. |
115 | | /// |
116 | | /// Should only be called on a non-empty slice with no `nan` |
117 | | /// coordinates. |
118 | 0 | pub fn least_and_greatest_index<T: CoordNum>(pts: &[Coord<T>]) -> (usize, usize) { |
119 | 0 | assert_ne!(pts.len(), 0); |
120 | 0 | let (min, max) = pts |
121 | 0 | .iter() |
122 | 0 | .enumerate() |
123 | 0 | .fold((None, None), |(min, max), (idx, p)| { |
124 | | ( |
125 | 0 | if let Some((midx, min)) = min { |
126 | 0 | if lex_cmp(p, min) == Ordering::Less { |
127 | 0 | Some((idx, p)) |
128 | | } else { |
129 | 0 | Some((midx, min)) |
130 | | } |
131 | | } else { |
132 | 0 | Some((idx, p)) |
133 | | }, |
134 | 0 | if let Some((midx, max)) = max { |
135 | 0 | if lex_cmp(p, max) == Ordering::Greater { |
136 | 0 | Some((idx, p)) |
137 | | } else { |
138 | 0 | Some((midx, max)) |
139 | | } |
140 | | } else { |
141 | 0 | Some((idx, p)) |
142 | | }, |
143 | | ) |
144 | 0 | }); |
145 | 0 | (min.unwrap().0, max.unwrap().0) |
146 | 0 | } |
147 | | |
148 | | /// Normalize a longitude to coordinate to ensure it's within [-180,180] |
149 | 0 | pub fn normalize_longitude<T: CoordFloat + FromPrimitive>(coord: T) -> T { |
150 | 0 | let one_eighty = T::from(180.0f64).unwrap(); |
151 | 0 | let three_sixty = T::from(360.0f64).unwrap(); |
152 | 0 | let five_forty = T::from(540.0f64).unwrap(); |
153 | | |
154 | 0 | ((coord + five_forty) % three_sixty) - one_eighty |
155 | 0 | } |
156 | | |
157 | | #[cfg(test)] |
158 | | mod test { |
159 | | use super::{partial_max, partial_min}; |
160 | | |
161 | | #[test] |
162 | | fn test_partial_max() { |
163 | | assert_eq!(5, partial_max(5, 4)); |
164 | | assert_eq!(5, partial_max(5, 5)); |
165 | | } |
166 | | |
167 | | #[test] |
168 | | fn test_partial_min() { |
169 | | assert_eq!(4, partial_min(5, 4)); |
170 | | assert_eq!(4, partial_min(4, 4)); |
171 | | } |
172 | | } |