1 public static class MapConvertercs
2 {
3 //WGS-84原始坐标系
4 //GCJ-02:高德、Google
5 //BD-09:百度
6
7
8 /// <summary>
9 /// 圆周率
10 /// </summary>
11 private const double PI = 3.1415926535897932384626;
12 private const double X_PI = PI * 3000.0 / 180.0;
13
14 /// <summary>
15 /// 地理位置是否位于中国以外
16 /// </summary>
17 /// <param name="wgLat">WGS-84坐标纬度</param>
18 /// <param name="wgLon">WGS-84坐标经度</param>
19 /// <returns>
20 /// true:国外
21 /// false:国内
22 /// </returns>
23 public static bool OutOfChina(double wgLat, double wgLon)
24 {
25 if (wgLon < 72.004 || wgLon > 137.8347) return true;
26 if (wgLat < 0.8293 || wgLat > 55.8271) return true;
27
28 return false;
29 }
30
31 /// <summary>
32 /// WGS-84坐标系转火星坐标系 (GCJ-02)
33 /// </summary>
34 /// <param name="wgLat">WGS-84坐标纬度</param>
35 /// <param name="wgLon">WGS-84坐标经度</param>
36 /// <param name="mgLat">输出:GCJ-02坐标纬度</param>
37 /// <param name="mgLon">输出:GCJ-02坐标经度</param>
38 public static void WGS84ToGCJ02(double wgLat, double wgLon, out double mgLat, out double mgLon)
39 {
40 if (OutOfChina(wgLat, wgLon))
41 {
42 mgLat = wgLat;
43 mgLon = wgLon;
44 }
45 else
46 {
47 double dLat;
48 double dLon;
49 Delta(wgLat, wgLon, out dLat, out dLon);
50 mgLat = wgLat + dLat;
51 mgLon = wgLon + dLon;
52 }
53 }
54
55 /// <summary>
56 /// 火星坐标系 (GCJ-02)转WGS-84坐标系
57 /// </summary>
58 /// <param name="mgLat">GCJ-02坐标纬度</param>
59 /// <param name="mgLon">GCJ-02坐标经度</param>
60 /// <param name="wgLat">输出:WGS-84坐标纬度</param>
61 /// <param name="wgLon">输出:WGS-84坐标经度</param>
62 public static void GCJ02ToWGS84(double mgLat, double mgLon, out double wgLat, out double wgLon)
63 {
64 if (OutOfChina(mgLat, mgLon))
65 {
66 wgLat = mgLat;
67 wgLon = mgLon;
68 }
69 else
70 {
71 double dLat;
72 double dLon;
73 Delta(mgLat, mgLon, out dLat, out dLon);
74 wgLat = mgLat - dLat;
75 wgLon = mgLon - dLon;
76 }
77 }
78
79 /// <summary>
80 /// 火星坐标系 (GCJ-02)转WGS-84坐标系
81 /// </summary>
82 /// <param name="mgLat">GCJ-02坐标纬度</param>
83 /// <param name="mgLon">GCJ-02坐标经度</param>
84 /// <param name="wgLat">输出:WGS-84坐标纬度</param>
85 /// <param name="wgLon">输出:WGS-84坐标经度</param>
86 public static void GCJ02ToWGS84Exact(double mgLat, double mgLon, out double wgLat, out double wgLon)
87 {
88 const double InitDelta = 0.01;
89 const double Threshold = 0.000001;
90
91 double dLat = InitDelta;
92 double dLon = InitDelta;
93 double mLat = mgLat - dLat;
94 double mLon = mgLon - dLon;
95 double pLat = mgLat + dLat;
96 double pLon = mgLon + dLon;
97
98 double nLat;
99 double nLon;
100
101 int i = 0;
102 do
103 {
104 wgLat = (mLat + pLat) / 2;
105 wgLon = (mLon + pLon) / 2;
106
107 WGS84ToGCJ02(wgLat, wgLon, out nLat, out nLon);
108
109 dLat = nLat - mgLat;
110 dLon = nLon - mgLon;
111 if ((Math.Abs(dLat) < Threshold) && (Math.Abs(dLon) < Threshold)) break;
112
113 if (dLat > 0) pLat = wgLat; else mLat = wgLat;
114 if (dLon > 0) pLon = wgLon; else mLon = wgLon;
115 } while (++i <= 30);
116 }
117
118 /// <summary>
119 /// 百度坐标系 (BD-09)转火星坐标系 (GCJ-02)
120 /// </summary>
121 /// <param name="bdLat">百度坐标系纬度</param>
122 /// <param name="bdLon">百度坐标系经度</param>
123 /// <param name="mgLat">输出:GCJ-02坐标纬度</param>
124 /// <param name="mgLon">输出:GCJ-02坐标经度</param>
125 public static void BD09ToGCJ02(double bdLat, double bdLon, out double mgLat, out double mgLon)
126 {
127 double x = bdLon - 0.0065;
128 double y = bdLat - 0.006;
129 double z = Math.Sqrt(x * x + y * y) - 0.00002 * Math.Sin(y * X_PI);
130 double theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * X_PI);
131 mgLat = z * Math.Sin(theta);
132 mgLon = z * Math.Cos(theta);
133 }
134
135 /// <summary>
136 /// 火星坐标系 (GCJ-02)转百度坐标系 (BD-09)
137 /// </summary>
138 /// <param name="mgLat">GCJ-02坐标纬度</param>
139 /// <param name="mgLon">GCJ-02坐标经度</param>
140 /// <param name="bdLat">输出:百度坐标系纬度</param>
141 /// <param name="bdLon">输出:百度坐标系经度</param>
142 public static void GCJ02ToBD09(double mgLat, double mgLon, out double bdLat, out double bdLon)
143 {
144 double x = mgLon;
145 double y = mgLat;
146 double z = Math.Sqrt(x * x + y * y) + 0.00002 * Math.Sin(y * X_PI);
147 double theta = Math.Atan2(y, x) + 0.000003 * Math.Cos(x * X_PI);
148 bdLat = z * Math.Sin(theta) + 0.006;
149 bdLon = z * Math.Cos(theta) + 0.0065;
150 }
151
152 /// <summary>
153 /// WGS-84坐标系转百度坐标系 (BD-09)
154 /// </summary>
155 /// <param name="wgLat">WGS-84坐标纬度</param>
156 /// <param name="wgLon">WGS-84坐标经度</param>
157 /// <param name="bdLat">输出:百度坐标系纬度</param>
158 /// <param name="bdLon">输出:百度坐标系经度</param>
159 public static void WGS84ToBD09(double wgLat, double wgLon, out double bdLat, out double bdLon)
160 {
161 double mgLat;
162 double mgLon;
163
164 WGS84ToGCJ02(wgLat, wgLon, out mgLat, out mgLon);
165 GCJ02ToBD09(mgLat, mgLon, out bdLat, out bdLon);
166 }
167
168 /// <summary>
169 /// 百度坐标系 (BD-09)转WGS-84坐标系
170 /// </summary>
171 /// <param name="bdLat">百度坐标系纬度</param>
172 /// <param name="bdLon">百度坐标系经度</param>
173 /// <param name="wgLat">输出:WGS-84坐标纬度</param>
174 /// <param name="wgLon">输出:WGS-84坐标经度</param>
175 public static void BD09ToWGS84(double bdLat, double bdLon, out double wgLat, out double wgLon)
176 {
177 double mgLat;
178 double mgLon;
179
180 BD09ToGCJ02(bdLat, bdLon, out mgLat, out mgLon);
181 GCJ02ToWGS84(mgLat, mgLon, out wgLat, out wgLon);
182 }
183
184 public static double Distance(double LatA, double LonA, double LatB, double LonB)
185 {
186 const double EarthR = 6371000.0;
187
188 double x = Math.Cos(LatA * PI / 180.0) * Math.Cos(LatB * PI / 180.0) * Math.Cos((LonA - LonB) * PI / 180);
189 double y = Math.Sin(LatA * PI / 180.0) * Math.Sin(LatB * PI / 180.0);
190 double s = x + y;
191 if (s > 1) s = 1;
192 if (s < -1) s = -1;
193
194 return Math.Acos(s) * EarthR;
195 }
196
197 private static void Delta(double Lat, double Lon, out double dLat, out double dLon)
198 {
199 const double AXIS = 6378245.0;
200 const double EE = 0.00669342162296594323;
201
202 dLat = TransformLat(Lon - 105.0, Lat - 35.0);
203 dLon = TransformLon(Lon - 105.0, Lat - 35.0);
204 double radLat = Lat / 180.0 * PI;
205 double magic = Math.Sin(radLat);
206 magic = 1 - EE * magic * magic;
207 double sqrtMagic = Math.Sqrt(magic);
208 dLat = (dLat * 180.0) / ((AXIS * (1 - EE)) / (magic * sqrtMagic) * PI);
209 dLon = (dLon * 180.0) / (AXIS / sqrtMagic * Math.Cos(radLat) * PI);
210 }
211
212 private static double TransformLat(double x, double y)
213 {
214 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));
215 ret += (20.0 * Math.Sin(6.0 * x * PI) + 20.0 * Math.Sin(2.0 * x * PI)) * 2.0 / 3.0;
216 ret += (20.0 * Math.Sin(y * PI) + 40.0 * Math.Sin(y / 3.0 * PI)) * 2.0 / 3.0;
217 ret += (160.0 * Math.Sin(y / 12.0 * PI) + 320 * Math.Sin(y * PI / 30.0)) * 2.0 / 3.0;
218 return ret;
219 }
220
221 private static double TransformLon(double x, double y)
222 {
223 double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.Sqrt(Math.Abs(x));
224 ret += (20.0 * Math.Sin(6.0 * x * PI) + 20.0 * Math.Sin(2.0 * x * PI)) * 2.0 / 3.0;
225 ret += (20.0 * Math.Sin(x * PI) + 40.0 * Math.Sin(x / 3.0 * PI)) * 2.0 / 3.0;
226 ret += (150.0 * Math.Sin(x / 12.0 * PI) + 300.0 * Math.Sin(x / 30.0 * PI)) * 2.0 / 3.0;
227 return ret;
228 }
229 }