1use std::f64::consts::PI;
2use std::str::FromStr;
3
4use num::cast::AsPrimitive;
5use num::Integer;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum ZoomLv {
16 Lv0,
17 Lv1,
18 Lv2,
19 Lv3,
20 Lv4,
21 Lv5,
22 Lv6,
23 Lv7,
24 Lv8,
25 Lv9,
26 Lv10,
27 Lv11,
28 Lv12,
29 Lv13,
30 Lv14,
31 Lv15,
32 Lv16,
33 Lv17,
34 Lv18,
35 Lv19,
36 Lv20,
37 Lv21,
38 Lv22,
39 Lv23,
40 Lv24,
41}
42
43impl ZoomLv {
44 pub fn parse<T: Integer + AsPrimitive<u8>>(num: T) -> Result<Self, ()> {
65 match num.as_() {
66 0 => Ok(Self::Lv0),
67 1 => Ok(Self::Lv1),
68 2 => Ok(Self::Lv2),
69 3 => Ok(Self::Lv3),
70 4 => Ok(Self::Lv4),
71 5 => Ok(Self::Lv5),
72 6 => Ok(Self::Lv6),
73 7 => Ok(Self::Lv7),
74 8 => Ok(Self::Lv8),
75 9 => Ok(Self::Lv9),
76 10 => Ok(Self::Lv10),
77 11 => Ok(Self::Lv11),
78 12 => Ok(Self::Lv12),
79 13 => Ok(Self::Lv13),
80 14 => Ok(Self::Lv14),
81 15 => Ok(Self::Lv15),
82 16 => Ok(Self::Lv16),
83 17 => Ok(Self::Lv17),
84 18 => Ok(Self::Lv18),
85 19 => Ok(Self::Lv19),
86 20 => Ok(Self::Lv20),
87 21 => Ok(Self::Lv21),
88 22 => Ok(Self::Lv22),
89 23 => Ok(Self::Lv23),
90 24 => Ok(Self::Lv24),
91 _ => Err(()),
92 }
93 }
94}
95
96impl TryFrom<u8> for ZoomLv
97{
98 type Error = ();
99
100 fn try_from(value: u8) -> Result<Self, Self::Error> {
101 Self::parse(value)
102 }
103}
104
105impl TryFrom<u16> for ZoomLv
106{
107 type Error = ();
108
109 fn try_from(value: u16) -> Result<Self, Self::Error> {
110 Self::parse(value)
111 }
112}
113
114impl TryFrom<u32> for ZoomLv
115{
116 type Error = ();
117
118 fn try_from(value: u32) -> Result<Self, Self::Error> {
119 Self::parse(value)
120 }
121}
122
123impl TryFrom<u64> for ZoomLv
124{
125 type Error = ();
126
127 fn try_from(value: u64) -> Result<Self, Self::Error> {
128 Self::parse(value)
129 }
130}
131
132impl TryFrom<usize> for ZoomLv
133{
134 type Error = ();
135
136 fn try_from(value: usize) -> Result<Self, Self::Error> {
137 Self::parse(value)
138 }
139}
140
141impl TryFrom<i8> for ZoomLv
142{
143 type Error = ();
144
145 fn try_from(value: i8) -> Result<Self, Self::Error> {
146 Self::parse(value)
147 }
148}
149
150impl TryFrom<i16> for ZoomLv
151{
152 type Error = ();
153
154 fn try_from(value: i16) -> Result<Self, Self::Error> {
155 Self::parse(value)
156 }
157}
158
159impl TryFrom<i32> for ZoomLv
160{
161 type Error = ();
162
163 fn try_from(value: i32) -> Result<Self, Self::Error> {
164 Self::parse(value)
165 }
166}
167
168impl TryFrom<i64> for ZoomLv
169{
170 type Error = ();
171
172 fn try_from(value: i64) -> Result<Self, Self::Error> {
173 Self::parse(value)
174 }
175}
176
177impl TryFrom<isize> for ZoomLv
178{
179 type Error = ();
180
181 fn try_from(value: isize) -> Result<Self, Self::Error> {
182 Self::parse(value)
183 }
184}
185
186impl FromStr for ZoomLv {
187 type Err = ();
188
189 fn from_str(s: &str) -> Result<Self, Self::Err> {
190 match s.parse::<u8>() {
191 Ok(num) => Self::parse(num),
192 Err(_) => Err(()),
193 }
194 }
195}
196
197pub fn ll2pixel(ll: (f64, f64), zoom: ZoomLv) -> (u32, u32) {
218 let (long, lat) = ll;
219 const L: f64 = 85.05112878;
220
221 let x = (2_f64.powf(zoom as i32 as f64 + 7.)) * (long / PI + 1.);
222 let y = (2_f64.powf(zoom as i32 as f64 + 7.) / PI)
223 * (-(lat.sin().atanh()) + (L * PI / 180.).sin().atanh());
224
225 (x as u32, y as u32)
226}
227
228pub fn pixel2ll(pixel: (u32, u32), zoom: ZoomLv) -> (f64, f64) {
246 let (x, y) = pixel;
247 const L: f64 = 85.05112878;
248
249 let long = PI * (x as f64 / 2_f64.powf(zoom as i32 as f64 + 7.) - 1.);
250 let lat = ((-PI * y as f64 / (2_f64.powf(zoom as i32 as f64 + 7.))
251 + (PI * L / 180.).sin().atanh())
252 .tanh())
253 .asin();
254
255 (long, lat)
256}
257
258pub fn pixel_resolution(lat: f64, zoom: ZoomLv) -> f64 {
273 156543.04 * lat.cos() / 2_f64.powf(zoom as i32 as f64)
274}
275
276pub fn pixel2tile(pixel: (u32, u32)) -> (u32, u32) {
292 let (x, y) = pixel;
293 (x / 256, y / 256)
294}
295
296#[cfg(test)]
297mod tests {
298 use close_to::assert_close_to;
299
300 use super::*;
301
302 #[test]
303 fn ll2pixel_works() {
304 let (x, y) = ll2pixel(
305 (139.7649308_f64.to_radians(), (35.6812405_f64).to_radians()),
306 ZoomLv::Lv21,
307 );
308
309 assert_eq!((x, y), (476868027, 211407949));
310 }
311
312 #[test]
313 fn pixel2ll_works() {
314 let (long, lat) = pixel2ll((476868027, 211407949), ZoomLv::Lv21);
315
316 println!("{}, {}", long.to_degrees(), lat.to_degrees());
317
318 assert_close_to(139.7649308_f64.to_radians(), long, 5);
319 assert_close_to(35.6812405_f64.to_radians(), lat, 5);
320 }
321
322 #[test]
323 fn pixel_resolution_works() {
324 let equator_length_m = 40075_f64 * 1000_f64;
325 let zoom_lv = ZoomLv::Lv17;
326 let resolution = pixel_resolution(0_f64.to_radians(), zoom_lv);
327
328 assert_close_to(
329 resolution,
330 equator_length_m / (2_f64.powf(zoom_lv as i32 as f64) * 256.),
331 5,
332 );
333 }
334}