├── document ├── latlng_conv_online_wgs84_2_gcj02.txt ├── latlng_fetcher.txt └── latlng_convert_online_any_2_bd09.txt ├── README.md └── php_code ├── latlng_conv_sample_2_sample2.php ├── latlng_conv_bd09_2_gcj02.php ├── latlng_conv_gcj02_2_bd09.php └── latlng_conv_wgs84_2_gcj02.php /document/latlng_conv_online_wgs84_2_gcj02.txt: -------------------------------------------------------------------------------- 1 | 代码源: 2 | http://api.amap.com/URI/browser_guide 3 | 手机浏览器地图URI 调用说明 -> 地图标注 4 | 5 | 高德私有接口:将wgs84转换为gcj02 6 | 7 | http://api.amap.com:9090/coordinate/simple?sid=15001&xys=经度,纬度&resType=json&ia=1&rid=[绑定cookies的一个随机数](可能需要添加key=????,????为申请的apikey) -------------------------------------------------------------------------------- /document/latlng_fetcher.txt: -------------------------------------------------------------------------------- 1 | gcj02坐标(高德坐标)获取: 2 | http://api.amap.com/Javascript/example 3 | 地图工具 -> 单击地图获取地图坐标 4 | 5 | 6 | 百度坐标获取: 7 | http://api.map.baidu.com/lbsapi/getpoint/index.html 8 | 9 | 10 | wgs84坐标获取: 11 | 请使用http://www.openlayers.org/ 自行构造一个 12 | (demo:https://github.com/HorseLuke/satellite_map_viewer ) 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | latlng_conv_package 2 | =================== 3 | 4 | 地理坐标转换包php版本,集中解决国内的坐标偏移问题。 5 | 6 | 当前已实现的转换见php_code目录。 7 | 8 | 使用时,需要考虑php.ini中precision的设置值(默认值一般也能很好工作)。考虑到性能问题,没有采用bc库运算。 9 | 10 | 已完成的坐标转换集中为当前热门的地图资源,涉及的有: 11 | - WGS-84(GPS原始坐标) 12 | - GCJ-02(俗称的火星坐标,当前应用于高德地图、google地图国内区域等) 13 | - BD-09(百度坐标,火星坐标上再加一层偏移) 14 | 15 | 代码参考众多人的代码,在此致谢。参考来源请见注释。 16 | 17 | Licensed under the Apache License, Version 2.0 (the "License") 18 | 19 | 20 | 觉得好用?就用支付宝扫一扫来打赏和捐助吧! 21 | 22 | ![支付宝打赏捐助二维码](http://7xlz3z.com1.z0.glb.clouddn.com/img/git/apavqmok7au6ummhae.png) 23 | -------------------------------------------------------------------------------- /document/latlng_convert_online_any_2_bd09.txt: -------------------------------------------------------------------------------- 1 | 代码源:http://developer.baidu.com/map/jsdemo.htm#a5_1 2 | 地图示例->坐标换算 3 | 4 | 5 | url接口如下: 6 | http://api.map.baidu.com/ag/coord/convert?from=[@from]&to=4&x=[@lng]&y=[@lat]&callback=BMap.Convertor.[@callbackName]&mode=[@mode]&ie=utf-8&oue=1&res=api&fromproduct=jsapi 7 | 8 | from 和 to的含义值: 9 | 0:GPS坐标系类型 10 | 2:Google 坐标系类型(gcj-02) 11 | 4:Baidu 坐标系类型 12 | 13 | mode等于1时,为批量转换,貌似一次最多20个。x和y此时需以逗号分割,比如: 14 | http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x=100,101&y=3,10&callback=BMap.Convertor.cbk_7789&mode=1&ie=utf-8&oue=1&res=api 15 | 16 | fromproduct=jsapi为baidu map api参数 -------------------------------------------------------------------------------- /php_code/latlng_conv_sample_2_sample2.php: -------------------------------------------------------------------------------- 1 | lat, 'lng'=>lng) 7 | * - 返回格式必须为:array('lat'=>lat, 'lng'=>lng) 8 | * 9 | * @author hl 10 | * 11 | */ 12 | class latlng_conv_sample_2_sample2{ 13 | 14 | /** 15 | * 转换接口 16 | * @param float|array $lat 纬度、或者array('lat'=>lat, 'lng'=>lng) 17 | * @param float $lng 经度 18 | * @return array array('lat'=>lat, 'lng'=>lng) 19 | */ 20 | static public function conv($lat, $lng = 0){ 21 | if(is_array($lat)){ 22 | $lng = isset($lat['lng']) ? $lat['lng'] : 0; 23 | $lat = isset($lat['lat']) ? $lat['lat'] : 0; 24 | } 25 | 26 | return array('lat'=>$lat, 'lng'=>$lng); 27 | 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /php_code/latlng_conv_bd09_2_gcj02.php: -------------------------------------------------------------------------------- 1 | lat, 'lng'=>lng) 19 | * @param float $lng 百度坐标系的经度 20 | * @return array 转换后的gcj02坐标(高德坐标系)。格式array('lat'=>lat, 'lng'=>lng) 21 | */ 22 | static public function conv($lat, $lng = 0){ 23 | if(is_array($lat)){ 24 | $lng = isset($lat['lng']) ? $lat['lng'] : 0; 25 | $lat = isset($lat['lat']) ? $lat['lat'] : 0; 26 | } 27 | 28 | $x = $lng - 0.0065; 29 | $y = $lat - 0.006; 30 | $z = sqrt($x*$x+$y*$y) - 0.00002 * sin($y * self::const_x_pi()); 31 | $theta = atan2($y, $x) - 0.000003 * cos($x * self::const_x_pi()); 32 | return array( 33 | 'lat' => $z * sin($theta), 34 | 'lng' => $z * cos($theta), 35 | ); 36 | 37 | } 38 | 39 | /** 40 | * const_x_pi 41 | * @return float 42 | */ 43 | static public function const_x_pi(){ 44 | static $x_pi = 0; 45 | if(0 == $x_pi){ 46 | $x_pi = M_PI * 3000.0 / 180.0; 47 | } 48 | return $x_pi; 49 | } 50 | 51 | 52 | } 53 | 54 | 55 | //var_export(implode(',', latlng_conv_bd09_2_gcj02::conv(39.914903299421,116.40389993345))); -------------------------------------------------------------------------------- /php_code/latlng_conv_gcj02_2_bd09.php: -------------------------------------------------------------------------------- 1 | lat, 'lng'=>lng) 21 | * @param float $lng gcj02坐标的经度 22 | * @return array 转换后的百度坐标系。格式array('lat'=>lat, 'lng'=>lng) 23 | */ 24 | static public function conv($lat, $lng = 0){ 25 | if(is_array($lat)){ 26 | $lng = isset($lat['lng']) ? $lat['lng'] : 0; 27 | $lat = isset($lat['lat']) ? $lat['lat'] : 0; 28 | } 29 | 30 | $z = sqrt($lng * $lng + $lat * $lat) + 0.00002 * sin($lat * self::const_x_pi()); 31 | $theta = atan2($lat, $lng) + 0.000003 * cos($lng * self::const_x_pi()); 32 | 33 | return array( 34 | 'lat' => $z * sin($theta) + 0.006, 35 | 'lng' => $z * cos($theta) + 0.0065, 36 | ); 37 | 38 | } 39 | 40 | /** 41 | * const_x_pi 42 | * @return float 43 | */ 44 | static public function const_x_pi(){ 45 | static $x_pi = 0; 46 | if(0 == $x_pi){ 47 | $x_pi = M_PI * 3000.0 / 180.0; 48 | } 49 | return $x_pi; 50 | } 51 | 52 | 53 | } 54 | 55 | 56 | //var_export(implode(',', latlng_conv_gcj02_2_bd09::conv(39.914805,116.39137))); 57 | 58 | -------------------------------------------------------------------------------- /php_code/latlng_conv_wgs84_2_gcj02.php: -------------------------------------------------------------------------------- 1 | lat, 'lng'=>lng) 81 | * @param float $lng wgs84坐标系的经度 82 | * @param int $wg_heit wgs84坐标系的高度。缺省为0 83 | * @param int $random 输出的中间量需要random混淆?默认为0,表示跟随配置;-1表示强制禁用random混淆;其余数值表示强制启用random混淆 84 | * @return array 转换后的gcj02坐标(高德坐标系)。格式array('lat'=>lat, 'lng'=>lng) 85 | */ 86 | static public function conv($lat, $lng = 0, $wg_heit = 0, $random = 0){ 87 | if(is_array($lat)){ 88 | $lng = isset($lat['lng']) ? $lat['lng'] : 0; 89 | $lat = isset($lat['lat']) ? $lat['lat'] : 0; 90 | } 91 | 92 | if(!self::is_conv_range($lat, $lng, $wg_heit)){ 93 | return array( 94 | 'lat' => $lat, 95 | 'lng' => $lng, 96 | ); 97 | } 98 | 99 | $x_l = $lng; 100 | $y_l = $lat; 101 | 102 | //此处直入 103 | $x_add = self::Transform_yj5($x_l - 105, $y_l - 35) ; 104 | $y_add = self::Transform_yjy5($x_l - 105, $y_l - 35) ; 105 | $h_add = $wg_heit; 106 | 107 | //由于猜测$wg_time = 0(个人猜测,应该是全部等于0,否则数据迁移很难搞...),后面的计算可省略 108 | $x_add = $x_add + $h_add * 0.001 /* + self::yj_sin2($wg_time*self::pi_div(180)) */; 109 | $y_add = $y_add + $h_add * 0.001 /* + self::yj_sin2($wg_time*self::pi_div(180)) */; 110 | 111 | if(0 == $random){ 112 | if(false != self::$conf_random){ 113 | $x_add += self::random_yj(); 114 | $y_add += self::random_yj(); 115 | } 116 | }elseif($random != -1){ 117 | $x_add += self::random_yj(); 118 | $y_add += self::random_yj(); 119 | } 120 | 121 | return array( 122 | 'lat' => ($y_l + self::Transform_jyj5($y_l, $y_add)), 123 | 'lng' => ($x_l + self::Transform_jy5($y_l, $x_add)), 124 | ); 125 | 126 | } 127 | 128 | /** 129 | * 是在需要转换的范畴么? 130 | * @param float $lat 131 | * @param float $lng 132 | * @return bool 不需要转换时,返回false 133 | */ 134 | static public function is_conv_range($lat, $lng, $wg_heit = 0){ 135 | if($lng < 72.004 || $lng > 137.8347){ 136 | return false; 137 | } 138 | 139 | if($lat < 0.8293 || $lat > 55.8271){ 140 | return false; 141 | } 142 | 143 | if($wg_heit > 5000){ 144 | return false; 145 | } 146 | 147 | return true; 148 | 149 | } 150 | 151 | static public function Transform_yj5($x, $y){ 152 | $tt = 300 + $x + 2 * $y + 0.1 * pow($x, 2) + 0.1 * $x * $y + 0.1 * sqrt(abs($x)); 153 | 154 | $tt += (20 * self::yj_sin2(self::pi_mul(6) * $x) + 20 * self::yj_sin2(self::pi_mul(2) * $x))*2.0/3.0; 155 | $tt += (20 * self::yj_sin2(M_PI * $x) + 40 * self::yj_sin2(self::pi_div(3) * $x))*2.0/3.0; 156 | $tt += (150 * self::yj_sin2(self::pi_div(12) * $x) + 300 * self::yj_sin2(self::pi_div(30) * $x))*2.0/3.0; 157 | return $tt; 158 | } 159 | 160 | static public function Transform_yjy5($x , $y){ 161 | $tt = -100 + 2 * $x + 3 * $y + 0.2 * pow($y, 2) + 0.1 * $x * $y + 0.2 * sqrt(abs($x)); 162 | $tt = $tt + (20 * self::yj_sin2(self::pi_mul(6) * $x) + 20 * self::yj_sin2(self::pi_mul(2) * $x))*2.0/3.0; 163 | $tt = $tt + (20 * self::yj_sin2(M_PI * $y)+ 40 * self::yj_sin2(self::pi_div(3) * $y))*2.0/3.0; 164 | $tt = $tt + (160 * self::yj_sin2(self::pi_div(12) * $y) + 320 * self::yj_sin2(self::pi_div(30) * $y))*2.0/3.0; 165 | return $tt; 166 | } 167 | 168 | /** 169 | * 170 | * @param float $x 171 | * @return float 172 | */ 173 | static public function yj_sin2($x){ 174 | 175 | //另一种是直接返回sin($x) 176 | //return sin($x); 177 | 178 | $tt = $ss = $s2 = 0.0; 179 | $ff = 0; 180 | 181 | if($x < 0){ 182 | $x *= -1; 183 | $ff = 1; 184 | } 185 | 186 | $tt = $x - intval($x / self::pi_mul(2)) * self::pi_mul(2); //如果不考虑intval,$tt必定等于0 187 | 188 | if ($tt > M_PI){ 189 | $tt -= M_PI; 190 | if ($ff==1){ 191 | $ff=0; 192 | }elseif ($ff==0){ 193 | $ff=1; 194 | } 195 | } 196 | 197 | //中间量若为0,则所有后续运算全部归0 198 | if(0 == $tt){ 199 | return 0; 200 | } 201 | 202 | $x = $ss = $s2 = $tt; 203 | $tt=pow($tt, 2); 204 | 205 | //分别为3!,5!,7!,9!,11! 206 | foreach(array(6, 120, 5040, 362880, 39916800) as $index => $value){ 207 | $s2 *= $tt; 208 | if(0 == $index % 2){ 209 | $ss -= $s2 / $value; 210 | }else{ 211 | $ss += $s2 / $value; 212 | } 213 | } 214 | 215 | if ($ff==1){ 216 | $ss *= -1; 217 | } 218 | return $ss; 219 | 220 | } 221 | 222 | static public function random_yj(){ 223 | $casm_rr = self::$casm_rr; 224 | 225 | $casm_rr = 314159269 * $casm_rr + 453806245; 226 | $casm_rr = $casm_rr - intval($casm_rr / 2) * 2; 227 | $casm_rr = $casm_rr / 2 ; 228 | 229 | self::$casm_rr = $casm_rr; 230 | return $casm_rr; 231 | } 232 | 233 | static public function Transform_jyj5($x, $yy){ 234 | $mm = 1 - self::ELLIPSOID_PARAM_E2 * self::yj_sin2($x * self::pi_div(180)) * self::yj_sin2($x * self::pi_div(180)) ; 235 | $m = (self::ELLIPSOID_PARAM_A * (1 - self::ELLIPSOID_PARAM_E2)) / ($mm * sqrt($mm)); 236 | return ($yy * 180) / ($m * M_PI); 237 | } 238 | 239 | static public function Transform_jy5($x , $xx){ 240 | $n = sqrt (1 - self::ELLIPSOID_PARAM_E2 * self::yj_sin2($x * self::pi_div(180)) * self::yj_sin2($x * self::pi_div(180))); 241 | $n = ($xx * 180) /(self::ELLIPSOID_PARAM_A / $n * cos($x * self::pi_div(180)) * M_PI) ; 242 | return $n; 243 | } 244 | 245 | /** 246 | * pi除以 247 | * @param int $x 248 | */ 249 | static public function pi_div($x = 1){ 250 | if(!isset(self::$pi_div_result[$x])){ 251 | self::$pi_div_result[$x] = (1 == $x) ? M_PI : (M_PI / $x); 252 | } 253 | return self::$pi_div_result[$x]; 254 | } 255 | 256 | 257 | /** 258 | * pi乘以 259 | * @param int $x 260 | * @return float 261 | */ 262 | static public function pi_mul($x = 1){ 263 | if(!isset(self::$pi_mul_result[$x])){ 264 | self::$pi_mul_result[$x] = (1 == $x) ? M_PI : (M_PI * $x); 265 | } 266 | return self::$pi_mul_result[$x]; 267 | } 268 | 269 | /** 270 | * 获取或者设置conf_random的值 271 | * @param bool|null $val 为bool值时,表示要设置为对应值;其余情况下,返回当前设置值 272 | * @return bool 273 | */ 274 | static public function conf_random($val = null){ 275 | if(!is_bool($val)){ 276 | return self::$conf_random; 277 | } 278 | self::$conf_random = $val; 279 | return $val; 280 | } 281 | 282 | } 283 | --------------------------------------------------------------------------------