coord_transform/
lib.rs

1use std::f64::consts::PI;
2// 定义常量
3const LL2MC: [[f64; 10]; 6] = [
4    [
5        -0.0015702102444,
6        111320.7020616939,
7        1704480524535203.0,
8        -10338987376042340.0,
9        26112667856603880.0,
10        -35149669176653700.0,
11        26595700718403920.0,
12        -10725012454188240.0,
13        1800819912950474.0,
14        82.5,
15    ],
16    [
17        0.0008277824516172526,
18        111320.7020463578,
19        647795574.6671607,
20        -4082003173.641316,
21        10774905663.51142,
22        -15171875531.51559,
23        12053065338.62167,
24        -5124939663.577472,
25        913311935.9512032,
26        67.5,
27    ],
28    [
29        0.00337398766765,
30        111320.7020202162,
31        4481351.045890365,
32        -23393751.19931662,
33        79682215.47186455,
34        -115964993.2797253,
35        97236711.15602145,
36        -43661946.33752821,
37        8477230.501135234,
38        52.5,
39    ],
40    [
41        0.00220636496208,
42        111320.7020209128,
43        51751.86112841131,
44        3796837.749470245,
45        992013.7397791013,
46        -1221952.21711287,
47        1340652.697009075,
48        -620943.6990984312,
49        144416.9293806241,
50        37.5,
51    ],
52    [
53        -0.0003441963504368392,
54        111320.7020576856,
55        278.2353980772752,
56        2485758.690035394,
57        6070.750963243378,
58        54821.18345352118,
59        9540.606633304236,
60        -2710.55326746645,
61        1405.483844121726,
62        22.5,
63    ],
64    [
65        -0.0003218135878613132,
66        111320.7020701615,
67        0.00369383431289,
68        823725.6402795718,
69        0.46104986909093,
70        2351.343141331292,
71        1.58060784298199,
72        8.77738589078284,
73        0.37238884252424,
74        7.45,
75    ],
76];
77
78const LLBAND: [f64; 6] = [75.0, 60.0, 45.0, 30.0, 15.0, 0.0];
79
80const MCBAND: [f64; 6] = [
81    12890594.86,
82    8362377.87,
83    5591021.0,
84    3481989.83,
85    1678043.12,
86    0.0,
87];
88const MC2LL: [[f64; 10]; 6] = [
89    [
90        1.410526172116255e-8,
91        0.00000898305509648872,
92        -1.9939833816331,
93        200.9824383106796,
94        -187.2403703815547,
95        91.6087516669843,
96        -23.38765649603339,
97        2.57121317296198,
98        -0.03801003308653,
99        17337981.2,
100    ],
101    [
102        -7.435856389565537e-9,
103        0.000008983055097726239,
104        -0.78625201886289,
105        96.32687599759846,
106        -1.85204757529826,
107        -59.36935905485877,
108        47.40033549296737,
109        -16.50741931063887,
110        2.28786674699375,
111        10260144.86,
112    ],
113    [
114        -3.030883460898826e-8,
115        0.00000898305509983578,
116        0.30071316287616,
117        59.74293618442277,
118        7.357984074871,
119        -25.38371002664745,
120        13.45380521110908,
121        -3.29883767235584,
122        0.32710905363475,
123        6856817.37,
124    ],
125    [
126        -1.981981304930552e-8,
127        0.000008983055099779535,
128        0.03278182852591,
129        40.31678527705744,
130        0.65659298677277,
131        -4.44255534477492,
132        0.85341911805263,
133        0.12923347998204,
134        -0.04625736007561,
135        4482777.06,
136    ],
137    [
138        3.09191371068437e-9,
139        0.000008983055096812155,
140        0.00006995724062,
141        23.10934304144901,
142        -0.00023663490511,
143        -0.6321817810242,
144        -0.00663494467273,
145        0.03430082397953,
146        -0.00466043876332,
147        2555164.4,
148    ],
149    [
150        2.890871144776878e-9,
151        0.000008983055095805407,
152        -3.068298e-8,
153        7.47137025468032,
154        -0.00000353937994,
155        -0.02145144861037,
156        -0.00001234426596,
157        0.00010322952773,
158        -0.00000323890364,
159        826088.5,
160    ],
161];
162
163/** `bd2gcj` 将百度坐标系 (BD-09) 转换至 火星坐标系 (GCJ-02)
164```
165    let (x, y) = coord_transform::bd2gcj((118.0, 32.0));
166    assert_eq!(x, 117.99349542486605);
167    assert_eq!(y, 31.994068010063465);
168```
169*/
170pub fn bd2gcj(bd: (f64, f64)) -> (f64, f64) {
171    // 解构元组
172    let (x, y) = bd;
173    let x_pi = PI * 3000.0 / 180.0;
174    let gcj_x = x - 0.0065;
175    let gcj_y = y - 0.006;
176    let z = (gcj_x.powi(2) + gcj_y.powi(2)).sqrt() - 0.00002 * ((gcj_y * x_pi).sin());
177    let theta = gcj_y.atan2(gcj_x) - (gcj_x * x_pi).cos() * 0.000003;
178    // 返回新元组
179    (theta.cos() * z, theta.sin() * z)
180}
181
182/** `gcj2bd` 将火星坐标系 (GCJ-02) 转换至 百度坐标系 (BD-09)
183```
184    let (x, y) = coord_transform::gcj2bd((118.0, 32.0));
185    assert_eq!(x, 118.00653128313961);
186    assert_eq!(y, 32.00581846664105);
187```
188*/
189pub fn gcj2bd(gcj: (f64, f64)) -> (f64, f64) {
190    // 解构元组
191    let (x, y) = gcj;
192    let x_pi = PI * 3000.0 / 180.0;
193    let z = (x.powi(2) + y.powi(2)).sqrt() + (y * x_pi).sin() * 0.00002;
194    let theta = y.atan2(x) + (x * x_pi).cos() * 0.000003;
195    // 返回新元组
196    (theta.cos() * z + 0.0065, theta.sin() * z + 0.006)
197}
198/** `wgs2gcj` 将WGS84无偏移坐标 转换至 火星坐标系 (GCJ-02)
199```
200    let (x, y) = coord_transform::wgs2gcj((118.0, 32.0));
201    assert_eq!(x, 118.00543101383846);
202    assert_eq!(y, 31.997964381055795);
203```
204*/
205pub fn wgs2gcj(wgs: (f64, f64)) -> (f64, f64) {
206    let (x, y) = wgs;
207    // 坐标在国外,直接返回
208    if x < 72.004 || x > 137.8347 || y < 0.8293 || y > 55.8271 {
209        return wgs;
210    }
211    let a = 6378245.0;
212    let ee = 0.00669342162296594323;
213    // 国内坐标
214    let delta_x = x - 105.0;
215    let delta_y = y - 35.0;
216
217    let mut d_lat = -100.0
218        + 2.0 * delta_x
219        + 3.0 * delta_y
220        + 0.2 * delta_y.powi(2)
221        + 0.1 * delta_x * delta_y
222        + 0.2 * (delta_x.abs().sqrt())
223        + (20.0 * ((6.0 * delta_x * PI).sin()) + 20.0 * ((2.0 * delta_x * PI).sin())) * 2.0 / 3.0
224        + (20.0 * ((delta_y * PI).sin()) + 40.0 * ((delta_y / 3.0 * PI).sin())) * 2.0 / 3.0
225        + (160.0 * ((delta_y / 12.0 * PI).sin()) + 320.0 * ((delta_y * PI / 30.0).sin())) * 2.0
226            / 3.0;
227
228    let mut d_lon = 300.0
229        + delta_x
230        + 2.0 * delta_y
231        + 0.1 * delta_x.powi(2)
232        + 0.1 * delta_x * delta_y
233        + 0.1 * delta_x.abs().sqrt()
234        + (20.0 * ((6.0 * delta_x * PI).sin()) + 20.0 * ((2.0 * delta_x * PI).sin())) * 2.0 / 3.0
235        + (20.0 * ((delta_x * PI).sin()) + 40.0 * ((delta_x / 3.0 * PI).sin())) * 2.0 / 3.0
236        + (150.0 * ((delta_x / 12.0 * PI).sin()) + 300.0 * ((delta_x / 30.0 * PI).sin())) * 2.0
237            / 3.0;
238
239    let rad_lat = y / 180.0 * PI;
240    let mut magic = rad_lat.sin();
241    magic = 1.0 - ee * magic * magic;
242    let magic_sqrt = magic.sqrt();
243
244    d_lon = (d_lon * 180.0) / (a / magic_sqrt * (rad_lat.cos()) * PI);
245    d_lat = (d_lat * 180.0) / ((a * (1.0 - ee)) / (magic * magic_sqrt) * PI);
246    (x + d_lon, y + d_lat)
247}
248/** `gcj2wgs` 将火星坐标系 (GCJ-02)  转换至 WGS84无偏移坐标
249```
250    let (x, y) = coord_transform::gcj2wgs((118.0, 32.0));
251    assert_eq!(x, 117.99456898616154);
252    assert_eq!(y, 32.002035618944205);
253```
254*/
255pub fn gcj2wgs(gcj: (f64, f64)) -> (f64, f64) {
256    let (gcj_x, gcj_y) = gcj;
257    let (x, y) = wgs2gcj(gcj);
258
259    let d_lon = x - gcj_x;
260    let d_lat = y - gcj_y;
261    (gcj_x - d_lon, gcj_y - d_lat)
262}
263
264/** `bd2wgs` 将百度经纬度坐标系 (BD-09)  转换至 WGS84无偏移坐标
265```
266    let (x, y) = coord_transform::bd2wgs((118.0, 32.0));
267    assert_eq!(x, 117.98808485929571);
268    assert_eq!(y, 31.996121973877745);
269```
270*/
271pub fn bd2wgs(bd: (f64, f64)) -> (f64, f64) {
272    //百度先转火星,火星转84
273    gcj2wgs(bd2gcj(bd))
274}
275/** `wgs2bd` 将WGS84无偏移坐标 转换至 百度经纬度坐标系 (BD-09)
276```
277    let (x, y) = coord_transform::wgs2bd((118.0, 32.0));
278    assert_eq!(x, 118.01198481069936);
279    assert_eq!(y, 32.00370423982076);
280```
281*/
282pub fn wgs2bd(wgs: (f64, f64)) -> (f64, f64) {
283    //百度先转火星,火星转84
284    gcj2bd(wgs2gcj(wgs))
285}
286
287fn get_loop(mut lon: f64, min_v: f64, max_v: f64) -> f64 {
288    while lon > max_v {
289        lon -= max_v - min_v;
290    }
291    while lon < min_v {
292        lon += max_v - min_v;
293    }
294    lon
295}
296fn get_range(mut lat: f64, min_v: f64, max_v: f64) -> f64 {
297    lat = lat.max(min_v);
298    lat = lat.min(max_v);
299    lat
300}
301/** `bd_wgs2mkt` 将百度经纬度坐标(BD-09) 转换至 百度墨卡托坐标
302```
303    let (x, y) = coord_transform::bd_wgs2mkt((118.0, 32.0));
304    assert_eq!(x, 13135842.840674074);
305    assert_eq!(y, 3740459.445338771);
306```
307*/
308pub fn bd_wgs2mkt(bdwgs: (f64, f64)) -> (f64, f64) {
309    let (mut x, mut y) = bdwgs;
310    x = get_loop(x, -180.0, 180.0);
311    y = get_range(y, -74.0, 74.0);
312    let mut cf: Option<[f64; 10]> = None;
313    let mut i: usize = 0;
314    for item in LLBAND {
315        if y >= item {
316            cf = Some(LL2MC[i]);
317            break;
318        }
319        i += 1;
320    }
321    // 不为空匹配
322    if let None = cf {
323        for item in LLBAND {
324            if y <= -item {
325                cf = Some(LL2MC[i]);
326                break;
327            }
328            i -= 1;
329        }
330    }
331    //  let number = if a > 0 { 1 } else { -1 }; 类似js里的三元选择符
332    match cf {
333        Some(_cf)=> {
334            x = _cf[0] + _cf[1] * x.abs();
335            let cc = y.abs() / _cf[9];
336            y = _cf[2]
337                + _cf[3] * cc
338                + _cf[4] * cc * cc
339                + _cf[5] * cc * cc * cc
340                + _cf[6] * cc * cc * cc * cc
341                + _cf[7] * cc * cc * cc * cc * cc
342                + _cf[8] * cc * cc * cc * cc * cc * cc;
343            return (x.abs(), y.abs());
344        }
345        _ => {
346            panic!("error occured");
347        }
348    }
349}
350/** `bd_mkt2wgs` 将百度墨卡托坐标 转换至 百度经纬度坐标(BD-09) 
351```
352    let (x, y) = coord_transform::bd_mkt2wgs((13135842.840674074,3740459.445338771));
353    assert_eq!(x, 117.99999999999993);
354    assert_eq!(y, 32.00000001036519);
355```
356*/
357pub fn bd_mkt2wgs(bdmkt: (f64, f64)) -> (f64, f64) {
358    let (mut x, mut y) = bdmkt;
359    x = x.abs();
360    y = y.abs();
361    let mut cf: Option<[f64; 10]> = None;
362    let mut i: usize = 0;
363    for item in MCBAND {
364        if y >= item {
365            cf = Some(MC2LL[i]);
366            break;
367        }
368        i += 1;
369    }
370    match cf {
371        Some(_cf) => {
372            x = _cf[0] + _cf[1] * (x.abs());
373            let cc = y.abs() / _cf[9];
374            y = _cf[2]
375                + _cf[3] * cc
376                + _cf[4] * cc * cc
377                + _cf[5] * cc * cc * cc
378                + _cf[6] * cc * cc * cc * cc
379                + _cf[7] * cc * cc * cc * cc * cc
380                + _cf[8] * cc * cc * cc * cc * cc * cc;
381            return (x.abs(), y.abs());
382        }
383        _ => {
384            panic!("error occured");
385        }
386    }
387}
388
389/** `wgs2bdmkt` 将无偏移的经纬度坐标 转换至 百度墨卡托坐标
390```
391    let (x, y) = coord_transform::wgs2bdmkt((118.0,32.0));
392    assert_eq!(x, 13137176.998214714);
393    assert_eq!(y, 3740943.32810748);
394```
395*/
396pub fn wgs2bdmkt(wgs:(f64, f64)) -> (f64, f64) {
397    bd_wgs2mkt(wgs2bd(wgs))
398}
399/** `bdmkt2wgs` 将百度墨卡托坐标 转换至 无偏移的经纬度坐标
400```
401    let (x, y) = coord_transform::bdmkt2wgs((13137176.998214714,3740943.32810748));
402    assert_eq!(x, 117.9999832373631);
403    assert_eq!(y, 31.999983711526742);
404```
405*/
406pub fn bdmkt2wgs(bdmkt:(f64, f64)) -> (f64, f64) {
407    bd2wgs(bd_mkt2wgs(bdmkt))
408}
409
410
411#[cfg(test)]
412mod tests {
413    use super::*;
414
415    #[test]
416    fn bd2gcj_test() {
417        let (x, y) = bd2gcj((118.0, 32.0));
418        assert_eq!(x, 117.99349542486605);
419        assert_eq!(y, 31.994068010063465);
420    }
421    #[test]
422    fn gcj2bd_test() {
423        let (x, y) = gcj2bd((118.0, 32.0));
424        assert_eq!(x, 118.00653128313961);
425        assert_eq!(y, 32.00581846664105);
426    }
427
428    #[test]
429    fn wgs2gcj_test() {
430        let (x, y) = wgs2gcj((118.0, 32.0));
431        assert_eq!(x, 118.00543101383846);
432        assert_eq!(y, 31.997964381055795);
433    }
434
435    #[test]
436    fn gcj2wgs_test() {
437        let (x, y) = gcj2wgs((118.0, 32.0));
438        assert_eq!(x, 117.99456898616154);
439        assert_eq!(y, 32.002035618944205);
440    }
441    #[test]
442    fn bd2wgs_test() {
443        let (x, y) = bd2wgs((118.0, 32.0));
444        assert_eq!(x, 117.98808485929571);
445        assert_eq!(y, 31.996121973877745);
446    }
447
448    #[test]
449    fn wgs2bd_test() {
450        let (x, y) = wgs2bd((118.0, 32.0));
451        assert_eq!(x, 118.01198481069936);
452        assert_eq!(y, 32.00370423982076);
453    }
454
455    #[test]
456    fn bd_wgs2mkt_test() {
457        let (x, y) = bd_wgs2mkt((118.0, 32.0));
458        assert_eq!(x, 13135842.840674074);
459        assert_eq!(y, 3740459.445338771);
460    }
461
462    #[test]
463    fn bd_mkt2wgs_test() {
464        let (x, y) = bd_mkt2wgs((13135842.840674074,3740459.445338771));
465        assert_eq!(x, 117.99999999999993);
466        assert_eq!(y, 32.00000001036519);
467    }
468
469    #[test]
470    fn wgs2bdmkt_test() {
471        let (x, y) = wgs2bdmkt((118.0,32.0));
472        assert_eq!(x, 13137176.998214714);
473        assert_eq!(y, 3740943.32810748);
474    }
475
476    #[test]
477    fn bdmkt2wgs_test() {
478        let (x, y) = bdmkt2wgs((13137176.998214714,3740943.32810748));
479        assert_eq!(x, 117.9999832373631);
480        assert_eq!(y, 31.999983711526742);
481    }
482}