GPS坐标互转:WGS-84(GPS)、GCJ-02(Google地图)、BD-09(百度地图)

 

WGS-84:是国际标准,GPS坐标(Google Earth使用、或者GPS模块)
GCJ-02:中国坐标偏移标准,Google Map、高德、腾讯使用
BD-09:百度坐标偏移标准,Baidu Map使用

//WGS-84 to GCJ-02
GPS.gcj_encrypt();

//GCJ-02 to WGS-84 粗略
GPS.gcj_decrypt();

//GCJ-02 to WGS-84 精确(二分极限法)
// var threshold = 0.000000001; 目前设置的是精确到小数点后9位,这个值越小,越精确,但是javascript中,浮点运算本身就不太精确,九位在GPS里也偏差不大了
GSP.gcj_decrypt_exact();

//GCJ-02 to BD-09
GPS.bd_encrypt();

//BD-09 to GCJ-02
GPS.bd_decrypt();

//求距离
GPS.distance();

示例:
document.write("GPS: 39.933676862706776,116.35608315379092<br />");
var arr2 = GPS.gcj_encrypt(39.933676862706776, 116.35608315379092);
document.write("中国:" + arr2['lat']+","+arr2['lon']+'<br />');
var arr3 = GPS.gcj_decrypt_exact(arr2['lat'], arr2['lon']);
document.write('逆算:' + arr3['lat']+","+arr3['lon']+' 需要和第一行相似(目前是小数点后9位相等)');

 

1. [代码][JavaScript]代码     

?
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
var  GPS = {
     PI : 3.14159265358979324,
     x_pi : 3.14159265358979324 * 3000.0 / 180.0,
     delta :  function  (lat, lon) {
         // Krasovsky 1940
         //
         // a = 6378245.0, 1/f = 298.3
         // b = a * (1 - f)
         // ee = (a^2 - b^2) / a^2;
         var  a = 6378245.0;  //  a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
         var  ee = 0.00669342162296594323;  //  ee: 椭球的偏心率。
         var  dLat =  this .transformLat(lon - 105.0, lat - 35.0);
         var  dLon =  this .transformLon(lon - 105.0, lat - 35.0);
         var  radLat = lat / 180.0 *  this .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) *  this .PI);
         dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) *  this .PI);
         return  { 'lat' : dLat,  'lon' : dLon};
     },
     
     //WGS-84 to GCJ-02
     gcj_encrypt :  function  (wgsLat, wgsLon) {
         if  ( this .outOfChina(wgsLat, wgsLon))
             return  { 'lat' : wgsLat,  'lon' : wgsLon};
 
         var  d =  this .delta(wgsLat, wgsLon);
         return  { 'lat'  : wgsLat + d.lat, 'lon'  : wgsLon + d.lon};
     },
     //GCJ-02 to WGS-84
     gcj_decrypt :  function  (gcjLat, gcjLon) {
         if  ( this .outOfChina(gcjLat, gcjLon))
             return  { 'lat' : gcjLat,  'lon' : gcjLon};
         
         var  d =  this .delta(gcjLat, gcjLon);
         return  { 'lat' : gcjLat - d.lat,  'lon' : gcjLon - d.lon};
     },
     //GCJ-02 to WGS-84 exactly
     gcj_decrypt_exact :  function  (gcjLat, gcjLon) {
         var  initDelta = 0.01;
         var  threshold = 0.000000001;
         var  dLat = initDelta, dLon = initDelta;
         var  mLat = gcjLat - dLat, mLon = gcjLon - dLon;
         var  pLat = gcjLat + dLat, pLon = gcjLon + dLon;
         var  wgsLat, wgsLon, i = 0;
         while  (1) {
             wgsLat = (mLat + pLat) / 2;
             wgsLon = (mLon + pLon) / 2;
             var  tmp =  this .gcj_encrypt(wgsLat, wgsLon)
             dLat = tmp.lat - gcjLat;
             dLon = tmp.lon - gcjLon;
             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 > 10000)  break ;
         }
         //console.log(i);
         return  { 'lat' : wgsLat,  'lon' : wgsLon};
     },
     //GCJ-02 to BD-09
     bd_encrypt :  function  (gcjLat, gcjLon) {
         var  x = gcjLon, y = gcjLat; 
         var  z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y *  this .x_pi); 
         var  theta = Math.atan2(y, x) + 0.000003 * Math.cos(x *  this .x_pi); 
         bdLon = z * Math.cos(theta) + 0.0065; 
         bdLat = z * Math.sin(theta) + 0.006;
         return  { 'lat'  : bdLat, 'lon'  : bdLon};
     },
     //BD-09 to GCJ-02
     bd_decrypt :  function  (bdLat, bdLon) {
         var  x = bdLon - 0.0065, y = bdLat - 0.006; 
         var  z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y *  this .x_pi); 
         var  theta = Math.atan2(y, x) - 0.000003 * Math.cos(x *  this .x_pi); 
         var  gcjLon = z * Math.cos(theta); 
         var  gcjLat = z * Math.sin(theta);
         return  { 'lat'  : gcjLat,  'lon'  : gcjLon};
     },
     //WGS-84 to Web mercator
     //mercatorLat -> y mercatorLon -> x
     mercator_encrypt :  function (wgsLat, wgsLon) {
         var  x = wgsLon * 20037508.34 / 180.;
         var  y = Math.log(Math.tan((90. + wgsLat) *  this .PI / 360.)) / ( this .PI / 180.);
         y = y * 20037508.34 / 180.;
         return  { 'lat'  : y,  'lon'  : x};
         /*
         if ((Math.abs(wgsLon) > 180 || Math.abs(wgsLat) > 90))
             return null;
         var x = 6378137.0 * wgsLon * 0.017453292519943295;
         var a = wgsLat * 0.017453292519943295;
         var y = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
         return {'lat' : y, 'lon' : x};
         //*/
     },
     // Web mercator to WGS-84
     // mercatorLat -> y mercatorLon -> x
     mercator_decrypt :  function (mercatorLat, mercatorLon) {
         var  x = mercatorLon / 20037508.34 * 180.;
         var  y = mercatorLat / 20037508.34 * 180.;
         y = 180 /  this .PI * (2 * Math.atan(Math.exp(y *  this .PI / 180.)) -  this .PI / 2);
         return  { 'lat'  : y,  'lon'  : x};
         /*
         if (Math.abs(mercatorLon) < 180 && Math.abs(mercatorLat) < 90)
             return null;
         if ((Math.abs(mercatorLon) > 20037508.3427892) || (Math.abs(mercatorLat) > 20037508.3427892))
             return null;
         var a = mercatorLon / 6378137.0 * 57.295779513082323;
         var x = a - (Math.floor(((a + 180.0) / 360.0)) * 360.0);
         var y = (1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * mercatorLat) / 6378137.0)))) * 57.295779513082323;
         return {'lat' : y, 'lon' : x};
         //*/
     },
     // two point's distance
     distance :  function  (latA, lonA, latB, lonB) {
         var  earthR = 6371000.;
         var  x = Math.cos(latA *  this .PI / 180.) * Math.cos(latB *  this .PI / 180.) * Math.cos((lonA - lonB) *  this .PI / 180);
         var  y = Math.sin(latA *  this .PI / 180.) * Math.sin(latB *  this .PI / 180.);
         var  s = x + y;
         if  (s > 1) s = 1;
         if  (s < -1) s = -1;
         var  alpha = Math.acos(s);
         var  distance = alpha * earthR;
         return  distance;
     },
     outOfChina :  function  (lat, lon) {
         if  (lon < 72.004 || lon > 137.8347)
             return  true ;
         if  (lat < 0.8293 || lat > 55.8271)
             return  true ;
         return  false ;
     },
     transformLat :  function  (x, y) {
         var  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 *  this .PI) + 20.0 * Math.sin(2.0 * x *  this .PI)) * 2.0 / 3.0;
         ret += (20.0 * Math.sin(y *  this .PI) + 40.0 * Math.sin(y / 3.0 *  this .PI)) * 2.0 / 3.0;
         ret += (160.0 * Math.sin(y / 12.0 *  this .PI) + 320 * Math.sin(y *  this .PI / 30.0)) * 2.0 / 3.0;
         return  ret;
     },
     transformLon :  function  (x, y) {
         var  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 *  this .PI) + 20.0 * Math.sin(2.0 * x *  this .PI)) * 2.0 / 3.0;
         ret += (20.0 * Math.sin(x *  this .PI) + 40.0 * Math.sin(x / 3.0 *  this .PI)) * 2.0 / 3.0;
         ret += (150.0 * Math.sin(x / 12.0 *  this .PI) + 300.0 * Math.sin(x / 30.0 *  this .PI)) * 2.0 / 3.0;
         return  ret;
     }
};

2. [代码][PHP]代码     

?
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
<?php
class  GPS {
     private  $PI  = 3.14159265358979324;
     private  $x_pi  = 0;
 
     public  function  __construct()
     {
         $this ->x_pi = 3.14159265358979324 * 3000.0 / 180.0;
     }
     //WGS-84 to GCJ-02
     public  function  gcj_encrypt( $wgsLat $wgsLon ) {
         if  ( $this ->outOfChina( $wgsLat $wgsLon ))
             return  array ( 'lat'  =>  $wgsLat 'lon'  =>  $wgsLon );
 
         $d  $this ->delta( $wgsLat $wgsLon );
         return  array ( 'lat'  =>  $wgsLat  $d [ 'lat' ], 'lon'  =>  $wgsLon  $d [ 'lon' ]);
     }
     //GCJ-02 to WGS-84
     public  function  gcj_decrypt( $gcjLat $gcjLon ) {
         if  ( $this ->outOfChina( $gcjLat $gcjLon ))
             return  array ( 'lat'  =>  $gcjLat 'lon'  =>  $gcjLon );
         
         $d  $this ->delta( $gcjLat $gcjLon );
         return  array ( 'lat'  =>  $gcjLat  $d [ 'lat' ],  'lon'  =>  $gcjLon  $d [ 'lon' ]);
     }
     //GCJ-02 to WGS-84 exactly
     public  function  gcj_decrypt_exact( $gcjLat $gcjLon ) {
         $initDelta  = 0.01;
         $threshold  = 0.000000001;
         $dLat  $initDelta $dLon  $initDelta ;
         $mLat  $gcjLat  $dLat $mLon  $gcjLon  $dLon ;
         $pLat  $gcjLat  $dLat $pLon  $gcjLon  $dLon ;
         $wgsLat  = 0;  $wgsLon  = 0;  $i  = 0;
         while  (TRUE) {
             $wgsLat  = ( $mLat  $pLat ) / 2;
             $wgsLon  = ( $mLon  $pLon ) / 2;
             $tmp  $this ->gcj_encrypt( $wgsLat $wgsLon );
             $dLat  $tmp [ 'lat' ] -  $gcjLat ;
             $dLon  $tmp [ 'lon' ] -  $gcjLon ;
             if  (( abs ( $dLat ) <  $threshold ) && ( abs ( $dLon ) <  $threshold ))
                 break ;
 
             if  ( $dLat  > 0)  $pLat  $wgsLat else  $mLat  $wgsLat ;
             if  ( $dLon  > 0)  $pLon  $wgsLon else  $mLon  $wgsLon ;
 
             if  (++ $i  > 10000)  break ;
         }
         //console.log(i);
         return  array ( 'lat'  =>  $wgsLat 'lon' =>  $wgsLon );
     }
     //GCJ-02 to BD-09
     public  function  bd_encrypt( $gcjLat $gcjLon ) {
         $x  $gcjLon $y  $gcjLat
         $z  = sqrt( $x  $x  $y  $y ) + 0.00002 * sin( $y  $this ->x_pi); 
         $theta  atan2 ( $y $x ) + 0.000003 *  cos ( $x  $this ->x_pi); 
         $bdLon  $z  cos ( $theta ) + 0.0065; 
         $bdLat  $z  * sin( $theta ) + 0.006;
         return  array ( 'lat'  =>  $bdLat , 'lon'  =>  $bdLon );
     }
     //BD-09 to GCJ-02
     public  function  bd_decrypt( $bdLat $bdLon )
     {
         $x  $bdLon  - 0.0065;  $y  $bdLat  - 0.006; 
         $z  = sqrt( $x  $x  $y  $y ) - 0.00002 * sin( $y  $this ->x_pi); 
         $theta  atan2 ( $y $x ) - 0.000003 *  cos ( $x  $this ->x_pi); 
         $ $gcjLon  $z  cos ( $theta ); 
         $gcjLat  $z  * sin( $theta );
         return  array ( 'lat'  =>  $gcjLat 'lon'  =>  $gcjLon );
     }
     //WGS-84 to Web mercator
     //$mercatorLat -> y $mercatorLon -> x
     public  function  mercator_encrypt( $wgsLat $wgsLon )
     {
         $x  $wgsLon  * 20037508.34 / 180.;
         $y  = log(tan((90. +  $wgsLat ) *  $this ->PI / 360.)) / ( $this ->PI / 180.);
         $y  $y  * 20037508.34 / 180.;
         return  array ( 'lat'  =>  $y 'lon'  =>  $x );
         /*
         if ((abs($wgsLon) > 180 || abs($wgsLat) > 90))
             return NULL;
         $x = 6378137.0 * $wgsLon * 0.017453292519943295;
         $a = $wgsLat * 0.017453292519943295;
         $y = 3189068.5 * log((1.0 + sin($a)) / (1.0 - sin($a)));
         return array('lat' => $y, 'lon' => $x);
         //*/
     }
     // Web mercator to WGS-84
     // $mercatorLat -> y $mercatorLon -> x
     public  function  mercator_decrypt( $mercatorLat $mercatorLon )
     {
         $x  $mercatorLon  / 20037508.34 * 180.;
         $y  $mercatorLat  / 20037508.34 * 180.;
         $y  = 180 /  $this ->PI * (2 *  atan ( exp ( $y  $this ->PI / 180.)) -  $this ->PI / 2);
         return  array ( 'lat'  =>  $y 'lon'  =>  $x );
         /*
         if (abs($mercatorLon) < 180 && abs($mercatorLat) < 90)
             return NULL;
         if ((abs($mercatorLon) > 20037508.3427892) || (abs($mercatorLat) > 20037508.3427892))
             return NULL;
         $a = $mercatorLon / 6378137.0 * 57.295779513082323;
         $x = $a - (floor((($a + 180.0) / 360.0)) * 360.0);
         $y = (1.5707963267948966 - (2.0 * atan(exp((-1.0 * $mercatorLat) / 6378137.0)))) * 57.295779513082323;
         return array('lat' => $y, 'lon' => $x);
         //*/
     }
     // two point's distance
     public  function  distance( $latA $lonA $latB $lonB )
     {
         $earthR  = 6371000.;
         $x  cos ( $latA  $this ->PI / 180.) *  cos ( $latB  $this ->PI / 180.) *  cos (( $lonA  $lonB ) *  $this ->PI / 180);
         $y  = sin( $latA  $this ->PI / 180.) * sin( $latB  $this ->PI / 180.);
         $s  $x  $y ;
         if  ( $s  > 1)  $s  = 1;
         if  ( $s  < -1)  $s  = -1;
         $alpha  acos ( $s );
         $distance  $alpha  $earthR ;
         return  $distance ;
     }
 
     private  function  delta( $lat $lon )
     {
         // Krasovsky 1940
         //
         // a = 6378245.0, 1/f = 298.3
         // b = a * (1 - f)
         // ee = (a^2 - b^2) / a^2;
         $a  = 6378245.0; //  a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
         $ee  = 0.00669342162296594323; //  ee: 椭球的偏心率。
         $dLat  $this ->transformLat( $lon  - 105.0,  $lat  - 35.0);
         $dLon  $this ->transformLon( $lon  - 105.0,  $lat  - 35.0);
         $radLat  $lat  / 180.0 *  $this ->PI;
         $magic  = sin( $radLat );
         $magic  = 1 -  $ee  $magic  $magic ;
         $sqrtMagic  = sqrt( $magic );
         $dLat  = ( $dLat  * 180.0) / (( $a  * (1 -  $ee )) / ( $magic  $sqrtMagic ) *  $this ->PI);
         $dLon  = ( $dLon  * 180.0) / ( $a  $sqrtMagic  cos ( $radLat ) *  $this ->PI);
         return  array ( 'lat'  =>  $dLat 'lon'  =>  $dLon );
     }
 
     private  function  outOfChina( $lat $lon )
     {
         if  ( $lon  < 72.004 ||  $lon  > 137.8347)
             return  TRUE;
         if  ( $lat  < 0.8293 ||  $lat  > 55.8271)
             return  TRUE;
         return  FALSE;
     }
 
     private  function  transformLat( $x $y ) {
         $ret  = -100.0 + 2.0 *  $x  + 3.0 *  $y  + 0.2 *  $y  $y  + 0.1 *  $x  $y  + 0.2 * sqrt( abs ( $x ));
         $ret  += (20.0 * sin(6.0 *  $x  $this ->PI) + 20.0 * sin(2.0 *  $x  $this ->PI)) * 2.0 / 3.0;
         $ret  += (20.0 * sin( $y  $this ->PI) + 40.0 * sin( $y  / 3.0 *  $this ->PI)) * 2.0 / 3.0;
         $ret  += (160.0 * sin( $y  / 12.0 *  $this ->PI) + 320 * sin( $y  $this ->PI / 30.0)) * 2.0 / 3.0;
         return  $ret ;
     }
 
     private  function  transformLon( $x $y ) {
         $ret  = 300.0 +  $x  + 2.0 *  $y  + 0.1 *  $x  $x  + 0.1 *  $x  $y  + 0.1 * sqrt( abs ( $x ));
         $ret  += (20.0 * sin(6.0 *  $x  $this ->PI) + 20.0 * sin(2.0 *  $x  $this ->PI)) * 2.0 / 3.0;
         $ret  += (20.0 * sin( $x  $this ->PI) + 40.0 * sin( $x  / 3.0 *  $this ->PI)) * 2.0 / 3.0;
         $ret  += (150.0 * sin( $x  / 12.0 *  $this ->PI) + 300.0 * sin( $x  / 30.0 *  $this ->PI)) * 2.0 / 3.0;
         return  $ret ;
     }
}

 

 

转载地址:http://www.oschina.net/code/snippet_260395_39205

 

你可能感兴趣的:(google地图)