该类可以将百度,腾讯,高德地图坐标进行转换,即bd09,gcj02坐标转换。由于百度,腾讯等公司的坐标偏移算法是内部保密的,故该坐标转换类只能大致转换,具有一定偏差,请考虑实际情况使用。
核心代码
<?php // +---------------------------------------------------------------------- // | Author: 贝莉卡 <beilika.com> // +---------------------------------------------------------------------- /** * 坐标转换类 */ class CoordinateTransformation { /** * bd09转gcj02 * @param float $lat 百度坐标系的纬度 * @param float $lng 百度坐标系的经度 * @return array 转换后的gcj02坐标(高德坐标系)。格式array('lat'=>lat, 'lng'=>lng) */ public static function bd09_to_gcj02($lat = 0, $lng = 0){ $x = $lng - 0.0065; $y = $lat - 0.006; $z = sqrt($x*$x+$y*$y) - 0.00002 * sin($y * (M_PI * 3000.0 / 180.0)); $theta = atan2($y, $x) - 0.000003 * cos($x * (M_PI * 3000.0 / 180.0)); return array( 'lat' => $z * sin($theta), 'lng' => $z * cos($theta), ); } /** * gcj02转bd09 * @param float $lat gcj02坐标的纬度 * @param float $lng gcj02坐标的经度 * @return array 转换后的百度坐标系。格式array('lat'=>lat, 'lng'=>lng) */ public static function gcj02_to_bd09($lat = 0, $lng = 0){ $z = sqrt($lng * $lng + $lat * $lat) + 0.00002 * sin($lat * (M_PI * 3000.0 / 180.0)); $theta = atan2($lat, $lng) + 0.000003 * cos($lng * (M_PI * 3000.0 / 180.0)); return array( 'lat' => $z * sin($theta) + 0.006, 'lng' => $z * cos($theta) + 0.0065, ); } /** * wgs84转gcj02 * @param float $lat wgs84坐标的纬度 * @param float $lng wgs84坐标的经度 * @return array 转换后的gcj02坐标系。格式array('lat'=>lat, 'lng'=>lng) */ public static function wgs84_to_gcj02($lat = 0, $lng = 0) { if (self::abroad($lat, $lng)) { return array( 'lat' => $lat, 'lng' => $lng, ); } $res = self::delta($lat, $lng); return array( 'lat' => $lat + $res['lat'], 'lng' => $lng + $res['lng'], ); } /** * gcj02转wgs84 * @param float $lat gcj02坐标的纬度 * @param float $lng gcj02坐标的经度 * @return array 转换后的wgs84坐标系。格式array('lat'=>lat, 'lng'=>lng) */ public static function gcj02_to_wgs84($lat = 0, $lng = 0) { if (self::abroad($lat, $lng)) { return array( 'lat' => $lat, 'lng' => $lng, ); } $res = self::delta($lat, $lng); return array( 'lat' => $lat - $res['lat'], 'lng' => $lng - $res['lng'], ); } /** * wgs84转墨卡托投影 * @param float $lat wgs84坐标的纬度 * @param float $lng wgs84坐标的经度 */ public static function wgs84_to_mercator($lat = 0, $lng = 0) { $x = $lng * 20037508.34 / 180.; $y = log(tan((90.0 + $lat) * M_PI / 360.0)) / (M_PI / 180.0); $y = $y * 20037508.34 / 180.0; return array( 'lat' => $y, 'lng' => $x, ); /* if ((abs($lng) > 180 || abs($lat) > 90)){ return null; } $x = 6378137.0 * $lng * 0.017453292519943295; $a = $lat * 0.017453292519943295; $y = 3189068.5 * log((1.0 + sin($a)) / (1.0 - sin($a))); return array( 'lat' => $y, 'lng' => $x, ); */ } /** * 墨卡托投影转wgs84 * @param float $lat 墨卡托投影的纬度 * @param float $lng 墨卡托投影的经度 */ public static function mercator_to_wgs84($lat = 0, $lng = 0) { $x = $lng / 20037508.34 * 180.0; $y = $lat / 20037508.34 * 180.0; $y = 180 / M_PI * (2 * atan(exp($y * M_PI / 180.0)) - M_PI / 2); return array( 'lat' => $y, 'lng' => $x, ); /* if (abs($lng) < 180 && abs($lat) < 90){ return null; } if ((abs($lng) > 20037508.3427892) || (abs($lat) > 20037508.3427892)){ return null; } $a = $lng / 6378137.0 * 57.295779513082323; $x = $a - (floor((($a + 180.0) / 360.0)) * 360.0); $y = (1.5707963267948966 - (2.0 * atan(exp((-1.0 * $lat) / 6378137.0)))) * 57.295779513082323; return array( 'lat' => $y, 'lng' => $x, ); */ } /** * 获取两个坐标的距离 * @param float $lat_a 坐标a的lat * @param float $lng_a 坐标a的lng * @param float $lat_b 坐标b的lat * @param float $lng_b 坐标a的lng * @return float */ public static function distance($lat_a = 0, $lng_a = 0, $lat_b = 0, $lng_b = 0) { $earthR = 6371000.0; $x = cos($lat_a * M_PI / 180.0) * cos($lat_b * M_PI / 180.0) * cos(($lng_a - $lng_b) * M_PI / 180); $y = sin($lat_a * M_PI / 180.0) * sin($lat_b * M_PI / 180.0); $s = $x + $y; if ($s > 1) { $s = 1; } if ($s < -1) { $s = -1; } $alpha = acos($s); $distance = $alpha * $earthR; return $distance; } private static function delta($lat = 0, $lng = 0) { //a: 卫星椭球坐标投影到平面地图坐标系的投影因子。 $a = 6378245.0; //ee: 椭球的偏心率。 $ee = 0.00669342162296594323; $dLat = self::transformLat($lng - 105.0, $lat - 35.0); $dlng = self::transformlng($lng - 105.0, $lat - 35.0); $radLat = $lat / 180.0 * M_PI; $magic = sin($radLat); $magic = 1 - $ee * $magic * $magic; $sqrtMagic = sqrt($magic); $dLat = ($dLat * 180.0) / (($a * (1 - $ee)) / ($magic * $sqrtMagic) * M_PI); $dlng = ($dlng * 180.0) / ($a / $sqrtMagic * cos($radLat) * M_PI); return array( 'lat' => $dLat, 'lng' => $dlng, ); } /** * 判断坐标是否在国外 * @param float $lat * @param float $lng * @return boolen */ private static function abroad($lat = 0, $lng = 0) { if ($lng < 72.004 || $lng > 137.8347){ return true; } if ($lat < 0.8293 || $lat > 55.8271){ return true; } return false; } private static 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 * M_PI) + 20.0 * sin(2.0 * $x * M_PI)) * 2.0 / 3.0; $ret += (20.0 * sin($y * M_PI) + 40.0 * sin($y / 3.0 * M_PI)) * 2.0 / 3.0; $ret += (160.0 * sin($y / 12.0 * M_PI) + 320 * sin($y * M_PI / 30.0)) * 2.0 / 3.0; return $ret; } private static function transformlng($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 * M_PI) + 20.0 * sin(2.0 * $x * M_PI)) * 2.0 / 3.0; $ret += (20.0 * sin($x * M_PI) + 40.0 * sin($x / 3.0 * M_PI)) * 2.0 / 3.0; $ret += (150.0 * sin($x / 12.0 * M_PI) + 300.0 * sin($x / 30.0 * M_PI)) * 2.0 / 3.0; return $ret; } }
使用方法
$coordinate = new CoordinateTransformation(); //将百度坐标转为腾讯坐标或高德坐标 $coordinate->bd09_to_gcj02($lat, $lng); //将腾讯坐标或高德坐标转为百度坐标 $coordinate->gcj02_to_bd09($lat, $lng); //将国际坐标转为腾讯坐标或高德坐标 $coordinate->wgs84_to_gcj02($lat, $lng); //将腾讯坐标或高德坐标转为国际坐标 $coordinate->gcj02_to_wgs84($lat, $lng); //计算两个坐标之间的距离 $coordinate->distance($lat_a = 0, $lng_a = 0, $lat_b = 0, $lng_b = 0);
GItHub地址:https://github.com/beilika/coordinatetransformation