首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 計算百度地圖 GPS 坐標距離與百度坐標系轉 WGS84 完整實作

     編輯:PHP 相關知識

PHP 計算百度地圖 GPS 坐標距離與百度坐標系轉 WGS84 完整實作

在 LBS(位置服務)應用中,計算兩點距離、坐標系轉換是核心基礎功能。本文提供兩個實用 PHP 函數:distanceBetween() 基於 Haversine 公式計算球面距離(米),BD09LLtoWGS84() 呼叫百度 API 將百度加密坐標(BD-09)轉為標準 GPS(WGS-84),並說明適用場景與注意事項。

一、球面距離計算:distanceBetween()

採用 Haversine 公式,以地球半徑 6378137 米計算兩經緯度點間的球面最短距離,精度滿足多數應用需求。

<?php
/**
 * 計算兩 GPS 坐標間距離(米)
 *
 * @param float $lat1 起點緯度
 * @param float $lon1 起點經度
 * @param float $lat2 終點緯度
 * @param float $lon2 終點經度
 * @return int 距離(米),四捨五入整數
 */
function distanceBetween(float $lat1, float $lon1, float $lat2, float $lon2): int {
    $earthRadius = 6378137; // 地球半徑(米),WGS-84 長半軸

    // 角度轉弧度
    $lat1 = deg2rad($lat1);
    $lon1 = deg2rad($lon1);
    $lat2 = deg2rad($lat2);
    $lon2 = deg2rad($lon2);

    // 緯度差、經度差
    $dLat = $lat2 - $lat1;
    $dLon = $lon2 - $lon1;

    // Haversine 公式
    $a = sin($dLat/2)**2 + cos($lat1) * cos($lat2) * sin($dLon/2)**2;
    $c = 2 * asin(sqrt($a));

    return (int)round($earthRadius * $c);
}

// 使用範例:天安門到北京西站
$dist = distanceBetween(39.9087, 116.3975, 39.8955, 116.3212);
echo "距離: $dist 米 (" . round($dist/1000, 2) . " 公里)\n";
// 輸出:距離: 6800 米 (6.8 公里)
?>

二、百度坐標系 (BD-09) 轉 WGS-84:BD09LLtoWGS84()

百度地圖使用加密坐標系 BD-09(在 GCJ-02 火星坐標基礎上再次加密)。若需與 GPS 原始資料、Google Maps、OpenStreetMap 互通,必須轉換為 WGS-84。

<?php
/**
 * 百度坐標 (BD-09) 轉標準 GPS (WGS-84)
 * 呼叫百度官方轉換 API:https://api.map.baidu.com/ag/coord/convert
 *
 * @param float $bdLon 百度經度
 * @param float $bdLat 百度緯度
 * @return string "經度,緯度" (WGS-84) 或原值(轉換失敗)
 */
function BD09LLtoWGS84(float $bdLon, float $bdLat): string {
    $url = "https://api.map.baidu.com/ag/coord/convert?from=0&to=4&x={$bdLon}&y={$bdLat}";
    
    $result = @file_get_contents($url);
    if ($result === false) {
        return "$bdLon,$bdLat"; // 網路失敗返回原值
    }
    
    $json = json_decode($result, true);
    if (!isset($json['error']) || $json['error'] !== 0) {
        return "$bdLon,$bdLat"; // API 錯誤返回原值
    }
    
    // 百度返回的 x, y 為 base64 編碼的加密偏移量
    $bx = base64_decode($json['x']);
    $by = base64_decode($json['y']);
    
    // 反推公式:WGS = 2*BD - 解密偏移
    $wgsLon = 2 * $bdLon - $bx;
    $wgsLat = 2 * $bdLat - $by;
    
    return "$wgsLon,$wgsLat";
}

// 使用範例
$bdCoord = "116.404,39.915"; // 百度坐標
$wgsCoord = BD09LLtoWGS84(...explode(',', $bdCoord));
echo "WGS-84: $wgsCoord\n";
?>

三、關鍵注意事項

項目說明
坐標順序慣例為「經度,緯度」(lng, lat),百度 API 參數 x=經度, y=緯度,請勿顛倒。
API 限制百度轉換 API 有配額限制(免費額度),高頻場景請申請 AK 或使用離線轉換庫(如 phayes/geoPHP、wandercn/coord-transform)。
精度Haversine 忽略地球扁率,誤差約 0.5%;高精度需求可用 Vincenty 公式或地理庫。
批次轉換避免迴圈中逐筆呼叫 HTTP API,應批次收集後單次請求或使用離線庫。
HTTPS生產環境請改用 https://api.map.baidu.com/... 並攜帶 AK 參數。

四、離線轉換替代方案(推薦生產環境)

不依賴外部 API、無網路延遲、無配額限制:

# Composer 安裝
composer require wandercn/coord-transform

# 使用
use Wander\CoordTransform\CoordTransform;

$wgs = CoordTransform::bd09ToWgs84($bdLon, $bdLat);
// 返回 ['lng' => ..., 'lat' => ...]

該庫實現純 PHP 端坐標系轉換(WGS84 ⇄ GCJ02 ⇄ BD09),效能極高,適合高併發服務。

總結

  • distanceBetween():純 PHP 實現 Haversine 公式,零依賴、高效能,適合即時距離計算。
  • BD09LLtoWGS84():呼叫百度官方 API,適合低頻、原型開發;生產環境強烈建議改用離線庫 wandercn/coord-transform。
  • 坐標系混用是 LBS 開發常見 Bug 來源,務必統一內部儲存為 WGS-84,僅在百度地圖顯示時轉 BD-09。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved