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 ;
     }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值