先上代码,用js实现的纠偏算法:
var pi = 3.14159265358979324;
//
// Krasovsky 1940
//
// a = 6378245.0, 1/f = 298.3
// b = a * (1 - f)
// ee = (a^2 - b^2) / a^2;
var a = 6378245.0;
var ee = 0.00669342162296594323;
function outOfChina(lat, lon){
if (lon < 72.004 || lon > 137.8347)
return 1;
if (lat < 0.8293 || lat > 55.8271)
return 1;
return 0;
}
function transformLat(x,y){
var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(x > 0 ? x:-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;
}
function transformLon(x,y){
var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(x > 0 ? x:-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;
}
function transformFromWGSToGCJ(wgLoc)
{
var mgLoc ={};
mgLoc.lat = 0;
mgLoc.lng = 0;
if (outOfChina(wgLoc.lat, wgLoc.lng))
{
mgLoc = wgLoc;
return mgLoc;
}
var dLat = transformLat(wgLoc.lng - 105.0, wgLoc.lat - 35.0);
var dLon = transformLon(wgLoc.lng - 105.0, wgLoc.lat - 35.0);
var radLat = wgLoc.lat / 180.0 * pi;
var magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
var sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
mgLoc.lat = wgLoc.lat + dLat;
mgLoc.lng = wgLoc.lng + dLon;
return mgLoc;
}
参考文章1:http://blog.csdn.net/coolypf/article/details/8686588
WGS-84 到 GCJ-02 的转换(即 GPS 加偏)算法是一个普通青年轻易无法接触到的“公开”的秘密。这个算法的代码在互联网上是公开的,详情请使用 Google 搜索 "wgtochina_lb" 。
整理后的算法代码请参考 https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936 。知道了这个算法之后,就可以离线进行 Google 地图偏移校正,不必像之前那么麻烦。
至于 GCJ-02 到 WGS-84 的转换(即 GPS 纠偏),可以使用二分法。
参考文章2:http://www.zuidaima.com/code/file/1665077235663872.htm?dir=/correct_lat_lon/src/com/hgq/correct/MapFix.java package com.hgq.correct; |
003 |
004 |
005 | /** |
006 | * 经纬度纠偏工具类 |
007 | * [一句话功能简述]<p> |
008 | * [功能详细描述]<p> |
009 | * @author PeiYu |
010 | * @version 1.0, 2012-8-24 |
011 | * @see |
012 | * @since gframe-v100 |
013 | */ |
014 | public class MapFix |
015 | { |
016 | private double casm_f = 0.0 ; |
017 |
018 | private double casm_rr = 0.0 ; |
019 |
020 | private double casm_t1 = 0.0 ; |
021 |
022 | private double casm_t2 = 0.0 ; |
023 |
024 | private double casm_x1 = 0.0 ; |
025 |
026 | private double casm_x2 = 0.0 ; |
027 |
028 | private double casm_y1 = 0.0 ; |
029 |
030 | private double casm_y2 = 0.0 ; |
031 |
032 | private MapFix() |
033 | { |
034 | casm_rr = 0.0 ; |
035 | casm_t1 = 0.0 ; |
036 | casm_t2 = 0.0 ; |
037 | casm_x1 = 0.0 ; |
038 | casm_y1 = 0.0 ; |
039 | casm_x2 = 0.0 ; |
040 | casm_y2 = 0.0 ; |
041 | casm_f = 0.0 ; |
042 | } |
043 |
044 | private static MapFix instance; |
045 |
046 | public static MapFix getInstance() |
047 | { |
048 | if (instance == null ) |
049 | { |
050 | instance = new MapFix(); |
051 | } |
052 | return instance; |
053 | } |
054 |
055 | /** |
056 | * 纠偏 |
057 | * @param x 经度 |
058 | * @param y 纬度 |
059 | * @return [0]纠偏后经度 [1]纠偏后纬度 |
060 | */ |
061 | public double [] fix( double x , double y) |
062 | { |
063 | double [] res = new double [ 2 ]; |
064 | try |
065 | { |
066 | double num = x * 3686400.0 ; |
067 | double num2 = y * 3686400.0 ; |
068 | double num3 = 0.0 ; |
069 | double num4 = 0.0 ; |
070 | double num5 = 0.0 ; |
071 | MapPoint point = wgtochina_lb( 1 , ( int ) num, ( int ) num2, ( int ) num5, ( int ) num3, ( int ) num4); |
072 | double num6 = point.getX(); |
073 | double num7 = point.getY(); |
074 | num6 /= 3686400.0 ; |
075 | num7 /= 3686400.0 ; |
076 | res[ 0 ] = num6; |
077 | res[ 1 ] = num7; |
078 | } |
079 | catch (Exception ex) |
080 | { |
081 | System.out.println(ex); |
082 | } |
083 | return res; |
084 | } |
085 |
086 | private void IniCasm( double w_time , double w_lng , double w_lat) |
087 | { |
088 | casm_t1 = w_time; |
089 | casm_t2 = w_time; |
090 | double num = ( int ) (w_time / 0.357 ); |
091 | casm_rr = w_time - (num * 0.357 ); |
092 | if (w_time == 0.0 ) |
093 | { |
094 | casm_rr = 0.3 ; |
095 | } |
096 | casm_x1 = w_lng; |
097 | casm_y1 = w_lat; |
098 | casm_x2 = w_lng; |
099 | casm_y2 = w_lat; |
100 | casm_f = 3.0 ; |
101 | } |
102 |
103 | private double random_yj() |
104 | { |
105 | double num = 314159269.0 ; |
106 | double num2 = 453806245.0 ; |
107 | casm_rr = (num * casm_rr) + num2; |
108 | double num3 = ( int ) (casm_rr / 2.0 ); |
109 | casm_rr -= num3 * 2.0 ; |
110 | casm_rr /= 2.0 ; |
111 | return casm_rr; |
112 | } |
113 |
114 | private double Transform_jy5( double x , double xx) |
115 | { |
116 | double num = 6378245.0 ; |
117 | double num2 = 0.00669342 ; |
118 | double num3 = Math.sqrt( 1.0 - ((num2 * yj_sin2(x * 0.0174532925199433 )) * yj_sin2(x * 0.0174532925199433 ))); |
119 | return ((xx * 180.0 ) / (((num / num3) * Math.cos(x * 0.0174532925199433 )) * 3.1415926 )); |
120 | } |
121 |
122 | private double Transform_jyj5( double x , double yy) |
123 | { |
124 | double num = 6378245.0 ; |
125 | double num2 = 0.00669342 ; |
126 | double d = 1.0 - ((num2 * yj_sin2(x * 0.0174532925199433 )) * yj_sin2(x * 0.0174532925199433 )); |
127 | double num4 = (num * ( 1.0 - num2)) / (d * Math.sqrt(d)); |
128 | return ((yy * 180.0 ) / (num4 * 3.1415926 )); |
129 | } |
130 |
131 | private double Transform_yj5( double x , double y) |
132 | { |
133 | double num = (((( 300.0 + ( 1.0 * x)) + ( 2.0 * y)) + (( 0.1 * x) * x)) + (( 0.1 * x) * y)) |
134 | + ( 0.1 * Math.sqrt(Math.sqrt(x * x))); |
135 | num += (( 20.0 * yj_sin2( 18.849555921538762 * x)) + ( 20.0 * yj_sin2( 6.283185307179588 * x))) * 0.6667 ; |
136 | num += (( 20.0 * yj_sin2( 3.141592653589794 * x)) + ( 40.0 * yj_sin2( 1.0471975511965981 * x))) * 0.6667 ; |
137 | return (num + ((( 150.0 * yj_sin2( 0.26179938779914952 * x)) + ( 300.0 * yj_sin2( 0.10471975511965979 * x))) * 0.6667 )); |
138 | } |
139 |
140 | private double Transform_yjy5( double x , double y) |
141 | { |
142 | double num = ((((- 100.0 + ( 2.0 * x)) + ( 3.0 * y)) + (( 0.2 * y) * y)) + (( 0.1 * x) * y)) |
143 | + ( 0.2 * Math.sqrt(Math.sqrt(x * x))); |
144 | num += (( 20.0 * yj_sin2( 18.849555921538762 * x)) + ( 20.0 * yj_sin2( 6.283185307179588 * x))) * 0.6667 ; |
145 | num += (( 20.0 * yj_sin2( 3.141592653589794 * y)) + ( 40.0 * yj_sin2( 1.0471975511965981 * y))) * 0.6667 ; |
146 | return (num + ((( 160.0 * yj_sin2( 0.26179938779914952 * y)) + ( 320.0 * yj_sin2( 0.10471975511965979 * y))) * 0.6667 )); |
147 | } |
148 |
149 | private MapPoint wgtochina_lb( int wg_flag , int wg_lng , int wg_lat , int wg_heit , int wg_week , int wg_time) |
150 | { |
151 | MapPoint point = null ; |
152 | if (wg_heit <= 0x1388 ) |
153 | { |
154 | double num = wg_lng; |
155 | num /= 3686400.0 ; |
156 | double x = wg_lat; |
157 | x /= 3686400.0 ; |
158 | if (num < 72.004 ) |
159 | { |
160 | return point; |
161 | } |
162 | if (num > 137.8347 ) |
163 | { |
164 | return point; |
165 | } |
166 | if (x < 0.8293 ) |
167 | { |
168 | return point; |
169 | } |
170 | if (x > 55.8271 ) |
171 | { |
172 | return point; |
173 | } |
174 | if (wg_flag == 0 ) |
175 | { |
176 | IniCasm(( double ) wg_time, ( double ) wg_lng, ( double ) wg_lat); |
177 | point = new MapPoint(); |
178 | point.setLatitude(( double ) wg_lng); |
179 | point.setLongitude(( double ) wg_lat); |
180 | return point; |
181 | } |
182 | casm_t2 = wg_time; |
183 | double num3 = (casm_t2 - casm_t1) / 1000.0 ; |
184 | if (num3 <= 0.0 ) |
185 | { |
186 | casm_t1 = casm_t2; |
187 | casm_f++; |
188 | casm_x1 = casm_x2; |
189 | casm_f++; |
190 | casm_y1 = casm_y2; |
191 | casm_f++; |
192 | } |
193 | else if (num3 > 120.0 ) |
194 | { |
195 | if (casm_f == 3.0 ) |
196 | { |
197 | casm_f = 0.0 ; |
198 | casm_x2 = wg_lng; |
199 | casm_y2 = wg_lat; |
200 | double num4 = casm_x2 - casm_x1; |
201 | double num5 = casm_y2 - casm_y1; |
202 | double num6 = Math.sqrt((num4 * num4) + (num5 * num5)) / num3; |
203 | if (num6 > 3185.0 ) |
204 | { |
205 | return point; |
206 | } |
207 | } |
208 | casm_t1 = casm_t2; |
209 | casm_f++; |
210 | casm_x1 = casm_x2; |
211 | casm_f++; |
212 | casm_y1 = casm_y2; |
213 | casm_f++; |
214 | } |
215 | double xx = Transform_yj5(num - 105.0 , x - 35.0 ); |
216 | double yy = Transform_yjy5(num - 105.0 , x - 35.0 ); |
217 | double num9 = wg_heit; |
218 | xx = ((xx + (num9 * 0.001 )) + yj_sin2(wg_time * 0.0174532925199433 )) + random_yj(); |
219 | yy = ((yy + (num9 * 0.001 )) + yj_sin2(wg_time * 0.0174532925199433 )) + random_yj(); |
220 | point = new MapPoint(); |
221 | point.setX((num + Transform_jy5(x, xx)) * 3686400.0 ); |
222 | point.setY((x + Transform_jyj5(x, yy)) * 3686400.0 ); |
223 | } |
224 | return point; |
225 | } |
226 |
227 | private double yj_sin2( double x) |
228 | { |
229 | double num = 0.0 ; |
230 | if (x < 0.0 ) |
231 | { |
232 | x = -x; |
233 | num = 1.0 ; |
234 | } |
235 | int num2 = ( int ) (x / 6.28318530717959 ); |
236 | double num3 = x - (num2 * 6.28318530717959 ); |
237 | if (num3 > 3.1415926535897931 ) |
238 | { |
239 | num3 -= 3.1415926535897931 ; |
240 | if (num == 1.0 ) |
241 | { |
242 | num = 0.0 ; |
243 | } |
244 | else if (num == 0.0 ) |
245 | { |
246 | num = 1.0 ; |
247 | } |
248 | } |
249 | x = num3; |
250 | double num4 = x; |
251 | double num5 = x; |
252 | num3 *= num3; |
253 | num5 *= num3; |
254 | num4 -= num5 * 0.166666666666667 ; |
255 | num5 *= num3; |
256 | num4 += num5 * 0.00833333333333333 ; |
257 | num5 *= num3; |
258 | num4 -= num5 * 0.000198412698412698 ; |
259 | num5 *= num3; |
260 | num4 += num5 * 2 .75573192239859E- 06 ; |
261 | num5 *= num3; |
262 | num4 -= num5 * 2 .50521083854417E- 08 ; |
263 | if (num == 1.0 ) |
264 | { |
265 | num4 = -num4; |
266 | } |
267 | return num4; |
268 | } |
269 | } |
270 |