管灌系统巡查员智能手机App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package com.dayu.pipirrapp.utils;
 
 
/**
 * author: zuo
 * Date: 2023/12/20
 * Time: 11:01
 * wgs84 84年提出,大地坐标,也是原始坐标。
 * gcj02 02年提出,火星坐标,经过加密算法。大多数非百度中国地图厂商基本都是使用的火星坐标:高德,腾讯,谷歌中国cn
 * bd09  09年提出,百度坐标,经过火星坐标再次加密,相当于对大地坐标经过了二次加密。百度自己使用
 * 一般的算法,没有直接bd09->wgs84或者wgs84->bd09,都需要借助wgs84->gcj02或者gcj02->wgs84算法推导。
 * <p>
 * 备注:坐标系转换
 */
public class MapUtils {
 
    //π的定义
    public static double pi = 3.1415926535897932384626;
    //椭球长半径,依据克拉索索夫斯基椭球系数计算
    public static double a = 6378245.0;
    //第一偏心率的平方
    public static double ee = 0.00669342162296594323;
 
    public static double transformLat(double x, double y) {
        double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
                + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }
 
    public static double transformLon(double x, double y) {
        double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
                * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
                * pi)) * 2.0 / 3.0;
        return ret;
    }
 
    /***
     * 判断是否在中国范围之内
     * @param lat
     * @param lon
     * @return
     */
    public static boolean outOfChina(double lat, double lon) {
        if (lon < 72.004 || lon > 137.8347) {
            return true;
        }
        if (lat < 0.8293 || lat > 55.8271) {
            return true;
        }
        return false;
    }
 
    /***
     * 把公式部分抽取出来
     * @param lat
     * @param lon
     * @return
     */
    public static Gps transform(double lat, double lon) {
        if (outOfChina(lat, lon)) {
            return new Gps(lat, lon);
        }
        double dLat = transformLat(lon - 105.0, lat - 35.0);
        double dLon = transformLon(lon - 105.0, lat - 35.0);
        double radLat = lat / 180.0 * pi;
        double magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
        double mgLat = lat + dLat;
        double mgLon = lon + dLon;
        return new Gps(mgLat, mgLon);
    }
 
    /***
     * wgs84到gcj02转换
     * @param lat
     * @param lon
     * @return
     */
    public static Gps wgs84_To_Gcj02(double lat, double lon) {
        return transform(lat, lon);
    }
 
    /***
     * 简单的gcj02到wgs84坐标类型转换,只做了一次迭代
     */
    public static Gps gcj02_To_Wgs84(double lat, double lon) {
        Gps gps = transform(lat, lon);
        double lontitude = lon * 2 - gps.lon;
        double latitude = lat * 2 - gps.lat;
        return new Gps(latitude, lontitude);
    }
 
    /***
     * 稍微精确一点的gcj02到wgs84转换
     * @param lat
     * @param lon
     * @return
     */
    public static Gps gcj02_To_Wgs84_exact(double lat, double lon) {
        if (outOfChina(lat, lon)) {
            return gcj02_To_Wgs84(lat, lon);
        }
        double initDelta = 0.01;
        double threshold = 0.000001;
        double dLat = initDelta;
        double dLon = initDelta;
        double mLat = lat - dLat;
        double mLon = lon - dLon;
        double pLat = lat + dLat;
        double pLon = lon + dLon;
        double wgsLat = 0;
        double wgsLon = 0;
        int i = 0;
        while (true) {
            wgsLat = (mLat + pLat) / 2;
            wgsLon = (mLon + pLon) / 2;
            Gps tmp = wgs84_To_Gcj02(wgsLat, wgsLon);
            dLat = tmp.lat - lat;
            dLon = tmp.lon - lon;
            if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold)) {
                break;
            }
            if (dLat > 0) {
                pLat = wgsLat;
            } else {
                mLat = wgsLat;
            }
            if (dLon > 0) {
                pLon = wgsLon;
            } else {
                mLon = wgsLon;
            }
 
            if (++i > 1000) break;
        }
 
        return new Gps(wgsLat, wgsLon);
    }
 
    /***
     * 百度坐标是在火星坐标基础上做的二次加密
     * @param gg_lat
     * @param gg_lon
     * @return
     */
    public static Gps gcj02_To_Bd09(double gg_lat, double gg_lon) {
        double x = gg_lon, y = gg_lat;
        double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);
        double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);
        double bd_lon = z * Math.cos(theta) + 0.0065;
        double bd_lat = z * Math.sin(theta) + 0.006;
        return new Gps(bd_lat, bd_lon);
    }
 
    /***
     * 百度坐标与火星坐标逆向转换
     * @param bd_lat
     * @param bd_lon
     * @return
     */
    public static Gps bd09_To_Gcj02(double bd_lat, double bd_lon) {
        double x = bd_lon - 0.0065, y = bd_lat - 0.006;
        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi);
        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi);
        double gg_lon = z * Math.cos(theta);
        double gg_lat = z * Math.sin(theta);
        return new Gps(gg_lat, gg_lon);
    }
 
    public static void main(String[] args) {
        Gps gps = new Gps(39.9072885060602, 116.39123343289631);
        System.out.println(gps);//{39.9072885060602,116.39123343289631}
        Gps gps2 = wgs84_To_Gcj02(gps.lat, gps.lon);
        System.out.println(gps2);//{39.9086897410389,116.39747455259267}
        Gps gps3 = gcj02_To_Wgs84(gps2.lat, gps2.lon);
        System.out.println(gps3);//{39.907286247736586,116.39123098626051}
        Gps gps4 = gcj02_To_Wgs84_exact(gps2.lat, gps2.lon);
        System.out.println(gps4);//{39.907288984202964,116.3912337078661} 相对一次迭代是精确了,但是好像也不是完全还原
    }
 
}
 
class Gps {
    double lat, lon;
 
    public Gps() {
    }
 
    public Gps(double lat, double lon) {
        this.lat = lat;
        this.lon = lon;
    }
 
    @Override
    public String toString() {
        return "{" + lat + "," + lon + "}";
    }
 
}