1use crate::{MinMax, Xyz};
9
10pub trait TileIterator: Iterator<Item = Xyz> {}
11
12pub struct XyzIterator {
14 z: u8,
15 x: u64,
16 y: u64,
17 z_min: u8,
18 z_max: u8,
19 limits: Vec<MinMax>,
20 finished: bool,
21}
22
23impl XyzIterator {
24 pub(crate) fn new(z_min: u8, z_max: u8, limits: Vec<MinMax>) -> XyzIterator {
25 const EMPTY_ITER: XyzIterator = XyzIterator {
27 z: 0,
28 x: 0,
29 y: 0,
30 z_min: 0,
31 z_max: 0,
32 limits: Vec::new(),
33 finished: true,
34 };
35 if z_min <= z_max {
36 if let Some(limit) = &limits.first() {
37 let z_max = std::cmp::min(z_max, z_min + limits.len().saturating_sub(1) as u8);
38 XyzIterator {
39 z: z_min,
40 x: limit.x_min,
41 y: limit.y_min,
42 z_min,
43 z_max,
44 limits,
45 finished: false,
46 }
47 } else {
48 EMPTY_ITER
49 }
50 } else {
51 EMPTY_ITER
52 }
53 }
54}
55
56impl Iterator for XyzIterator {
57 type Item = Xyz;
58
59 fn next(&mut self) -> Option<Self::Item> {
60 if self.finished {
61 return None;
62 }
63 let current = Xyz::new(self.x, self.y, self.z);
64 let limit = &self.limits[(self.z - self.z_min) as usize];
65 if self.y < limit.y_max {
66 self.y += 1;
67 } else if self.x < limit.x_max {
68 self.x += 1;
69 self.y = limit.y_min;
70 } else if self.z < self.z_max {
71 self.z += 1;
72 let limit = &self.limits[(self.z - self.z_min) as usize];
73 self.x = limit.x_min;
74 self.y = limit.y_min;
75 } else {
76 self.finished = true;
77 }
78 Some(current)
79 }
80}
81
82impl TileIterator for XyzIterator {}
83
84#[cfg(test)]
85mod test {
86 use crate::{tms, Xyz};
87
88 #[test]
89 fn test_mercator_iter() {
90 let tms = tms().lookup("WebMercatorQuad").unwrap();
91 let griditer = tms.xyz_iterator(&tms.xy_bbox(), 0, 2);
92 let cells = griditer.collect::<Vec<_>>();
93 assert_eq!(
94 cells,
95 vec![
96 Xyz::new(0, 0, 0),
97 Xyz::new(0, 0, 1),
98 Xyz::new(0, 1, 1),
99 Xyz::new(1, 0, 1),
100 Xyz::new(1, 1, 1),
101 Xyz::new(0, 0, 2),
102 Xyz::new(0, 1, 2),
103 Xyz::new(0, 2, 2),
104 Xyz::new(0, 3, 2),
105 Xyz::new(1, 0, 2),
106 Xyz::new(1, 1, 2),
107 Xyz::new(1, 2, 2),
108 Xyz::new(1, 3, 2),
109 Xyz::new(2, 0, 2),
110 Xyz::new(2, 1, 2),
111 Xyz::new(2, 2, 2),
112 Xyz::new(2, 3, 2),
113 Xyz::new(3, 0, 2),
114 Xyz::new(3, 1, 2),
115 Xyz::new(3, 2, 2),
116 Xyz::new(3, 3, 2)
117 ]
118 );
119
120 let griditer = tms.xyz_iterator(&tms.xy_bbox(), 1, 2);
121 let cells = griditer.collect::<Vec<_>>();
122 assert_eq!(
123 cells,
124 vec![
125 Xyz::new(0, 0, 1),
126 Xyz::new(0, 1, 1),
127 Xyz::new(1, 0, 1),
128 Xyz::new(1, 1, 1),
129 Xyz::new(0, 0, 2),
130 Xyz::new(0, 1, 2),
131 Xyz::new(0, 2, 2),
132 Xyz::new(0, 3, 2),
133 Xyz::new(1, 0, 2),
134 Xyz::new(1, 1, 2),
135 Xyz::new(1, 2, 2),
136 Xyz::new(1, 3, 2),
137 Xyz::new(2, 0, 2),
138 Xyz::new(2, 1, 2),
139 Xyz::new(2, 2, 2),
140 Xyz::new(2, 3, 2),
141 Xyz::new(3, 0, 2),
142 Xyz::new(3, 1, 2),
143 Xyz::new(3, 2, 2),
144 Xyz::new(3, 3, 2)
145 ]
146 );
147
148 let griditer = tms.xyz_iterator(&tms.xy_bbox(), 0, 0);
149 let cells = griditer.collect::<Vec<_>>();
150 assert_eq!(cells, vec![Xyz::new(0, 0, 0)]);
151 }
152
153 #[test]
154 fn invalid_iters() {
155 let tms = tms().lookup("WebMercatorQuad").unwrap();
156
157 let griditer = tms.xyz_iterator(&tms.xy_bbox(), 3, 2);
158 assert_eq!(griditer.count(), 0);
159
160 let griditer = tms.xyz_iterator(&tms.xy_bbox(), 2, 3);
163 assert_eq!(griditer.count(), 80);
164 }
165}