1pub use crate::transform::lonlat_to_merc;
9use std::f64::consts;
10
11#[derive(PartialEq, Clone, Debug)]
13pub struct Extent {
14 pub minx: f64,
15 pub miny: f64,
16 pub maxx: f64,
17 pub maxy: f64,
18}
19
20#[derive(PartialEq, Clone, Debug)]
22pub struct ExtentInt {
23 pub minx: u32,
24 pub miny: u32,
25 pub maxx: u32,
26 pub maxy: u32,
27}
28
29type CellIndex = (u32, u32);
31
32#[derive(PartialEq, Clone, Debug)]
34pub enum Origin {
35 TopLeft,
36 BottomLeft, }
38
39#[derive(PartialEq, Clone, Debug)]
41pub enum Unit {
42 Meters,
43 Degrees,
44 Feet,
45}
46
47#[derive(Clone, Debug)]
49pub struct Grid {
50 width: u16,
52 height: u16,
54 pub extent: Extent,
60 pub srid: i32,
62 pub units: Unit,
64 resolutions: Vec<f64>,
71 level_max: Vec<CellIndex>,
73 pub origin: Origin,
75}
76
77impl Grid {
78 pub fn wgs84() -> Grid {
80 Grid::new(
81 256,
82 256,
83 Extent {
84 minx: -180.0,
85 miny: -90.0,
86 maxx: 180.0,
87 maxy: 90.0,
88 },
89 4326,
90 Unit::Degrees,
91 vec![
92 0.703125000000000,
93 0.351562500000000,
94 0.175781250000000,
95 8.78906250000000e-2,
96 4.39453125000000e-2,
97 2.19726562500000e-2,
98 1.09863281250000e-2,
99 5.49316406250000e-3,
100 2.74658203125000e-3,
101 1.37329101562500e-3,
102 6.86645507812500e-4,
103 3.43322753906250e-4,
104 1.71661376953125e-4,
105 8.58306884765625e-5,
106 4.29153442382812e-5,
107 2.14576721191406e-5,
108 1.07288360595703e-5,
109 5.36441802978516e-6,
110 ],
111 Origin::BottomLeft,
112 )
113 }
114
115 #[allow(clippy::excessive_precision)]
117 pub fn web_mercator() -> Grid {
118 Grid::new(
119 256,
120 256,
121 Extent {
122 minx: -20037508.3427892480,
123 miny: -20037508.3427892480,
124 maxx: 20037508.3427892480,
125 maxy: 20037508.3427892480,
126 },
127 3857,
128 Unit::Meters,
129 vec![
131 156543.0339280410,
132 78271.5169640205,
133 39135.75848201025,
134 19567.879241005125,
135 9783.939620502562,
136 4891.969810251281,
137 2445.9849051256406,
138 1222.9924525628203,
139 611.4962262814101,
140 305.7481131407051,
141 152.87405657035254,
142 76.43702828517627,
143 38.218514142588134,
144 19.109257071294067,
145 9.554628535647034,
146 4.777314267823517,
147 2.3886571339117584,
148 1.1943285669558792,
149 0.5971642834779396,
150 0.2985821417389698,
151 0.1492910708694849,
152 0.07464553543474245,
153 0.037322767717371225,
154 ],
155 Origin::BottomLeft,
156 )
157 }
158
159 pub fn new(
160 width: u16,
161 height: u16,
162 extent: Extent,
163 srid: i32,
164 units: Unit,
165 resolutions: Vec<f64>,
166 origin: Origin,
167 ) -> Grid {
168 let mut grid = Grid {
169 width,
170 height,
171 extent,
172 srid,
173 units,
174 resolutions,
175 origin,
176 level_max: Vec::new(),
177 };
178 grid.level_max = grid.level_max();
179 grid
180 }
181 pub fn nlevels(&self) -> u8 {
182 self.resolutions.len() as u8
183 }
184 pub fn maxzoom(&self) -> u8 {
185 self.nlevels() - 1
186 }
187 pub fn pixel_width(&self, zoom: u8) -> f64 {
189 const METERS_PER_DEGREE: f64 = 6378137.0 * 2.0 * consts::PI / 360.0;
190 match self.units {
191 Unit::Meters => self.resolutions[zoom as usize],
192 Unit::Degrees => self.resolutions[zoom as usize] * METERS_PER_DEGREE,
193 Unit::Feet => self.resolutions[zoom as usize] * 0.3048,
194 }
195 }
196 pub fn scale_denominator(&self, zoom: u8) -> f64 {
198 const PIXEL_SCREEN_WIDTH: f64 = 0.00028;
200 self.pixel_width(zoom) / PIXEL_SCREEN_WIDTH
201 }
202 pub fn tile_extent(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
204 let res = self.resolutions[zoom as usize];
206 let tile_sx = self.width as f64;
207 let tile_sy = self.height as f64;
208 match self.origin {
209 Origin::BottomLeft => Extent {
210 minx: self.extent.minx + (res * xtile as f64 * tile_sx),
211 miny: self.extent.miny + (res * ytile as f64 * tile_sy),
212 maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
213 maxy: self.extent.miny + (res * (ytile + 1) as f64 * tile_sy),
214 },
215 Origin::TopLeft => Extent {
216 minx: self.extent.minx + (res * xtile as f64 * tile_sx),
217 miny: self.extent.maxy - (res * (ytile + 1) as f64 * tile_sy),
218 maxx: self.extent.minx + (res * (xtile + 1) as f64 * tile_sx),
219 maxy: self.extent.maxy - (res * ytile as f64 * tile_sy),
220 },
221 }
222 }
223 pub fn ytile_from_xyz(&self, ytile: u32, zoom: u8) -> u32 {
225 let maxy = self.level_max[zoom as usize].1;
227
228 maxy.saturating_sub(ytile).saturating_sub(1)
229 }
230 pub fn tile_extent_xyz(&self, xtile: u32, ytile: u32, zoom: u8) -> Extent {
232 let y = self.ytile_from_xyz(ytile, zoom);
233 self.tile_extent(xtile, y, zoom)
234 }
235 pub(crate) fn level_limit(&self, zoom: u8) -> CellIndex {
237 let res = self.resolutions[zoom as usize];
238 let unitheight = self.height as f64 * res;
239 let unitwidth = self.width as f64 * res;
240
241 let maxy =
242 ((self.extent.maxy - self.extent.miny - 0.01 * unitheight) / unitheight).ceil() as u32;
243 let maxx =
244 ((self.extent.maxx - self.extent.minx - 0.01 * unitwidth) / unitwidth).ceil() as u32;
245 (maxx, maxy)
246 }
247 fn level_max(&self) -> Vec<CellIndex> {
249 (0..self.nlevels())
250 .map(|zoom| self.level_limit(zoom))
251 .collect()
252 }
253 pub fn tile_limits(&self, extent: Extent, tolerance: i32) -> Vec<ExtentInt> {
255 const EPSILON: f64 = 0.0000001;
257 (0..self.nlevels())
258 .map(|i| {
259 let res = self.resolutions[i as usize];
260 let unitheight = self.height as f64 * res;
261 let unitwidth = self.width as f64 * res;
262 let (level_maxx, level_maxy) = self.level_max[i as usize];
263
264 let (mut minx, mut maxx, mut miny, mut maxy) = match self.origin {
265 Origin::BottomLeft => (
266 (((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as i32)
267 - tolerance,
268 (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as i32)
269 + tolerance,
270 (((extent.miny - self.extent.miny) / unitheight + EPSILON).floor() as i32)
271 - tolerance,
272 (((extent.maxy - self.extent.miny) / unitheight - EPSILON).ceil() as i32)
273 + tolerance,
274 ),
275 Origin::TopLeft => (
276 (((extent.minx - self.extent.minx) / unitwidth + EPSILON).floor() as i32)
277 - tolerance,
278 (((extent.maxx - self.extent.minx) / unitwidth - EPSILON).ceil() as i32)
279 + tolerance,
280 (((self.extent.maxy - extent.maxy) / unitheight + EPSILON).floor() as i32)
281 - tolerance,
282 (((self.extent.maxy - extent.miny) / unitheight - EPSILON).ceil() as i32)
283 + tolerance,
284 ),
285 };
286
287 if minx < 0 {
289 minx = 0;
290 }
291 if maxx > level_maxx as i32 {
292 maxx = level_maxx as i32
293 };
294 if miny < 0 {
295 miny = 0
296 };
297 if maxy > level_maxy as i32 {
298 maxy = level_maxy as i32
299 };
300
301 ExtentInt {
302 minx: minx as u32,
303 maxx: maxx as u32,
304 miny: miny as u32,
305 maxy: maxy as u32,
306 }
307 })
308 .collect()
309 }
310}
311
312pub fn extent_wgs84_to_merc(extent: &Extent) -> Extent {
314 let (minx, miny) = lonlat_to_merc(extent.minx, extent.miny);
315 let (maxx, maxy) = lonlat_to_merc(extent.maxx, extent.maxy);
316 Extent {
317 minx,
318 miny,
319 maxx,
320 maxy,
321 }
322}