PHP项目距离计算如何两点经纬度算直线距离

wen PHP项目 28

本文目录导读:

PHP项目距离计算如何两点经纬度算直线距离

  1. Haversine公式(最常用,精度较高)
  2. 使用PHP的atan2版本(更精确)
  3. 返回多种单位的版本
  4. 批量计算距离(适合数据库查询)
  5. 使用geotools库(推荐用于复杂项目)
  6. 精度对比
  7. 注意事项

在PHP中计算两点经纬度之间的直线距离,最常用的方法是Haversine公式,以下是几种实现的示例:

Haversine公式(最常用,精度较高)

function haversineDistance($lat1, $lon1, $lat2, $lon2) {
    $earthRadius = 6371; // 地球半径,单位:公里
    // 如果希望得到英里,使用 3959
    // 将角度转换为弧度
    $latFrom = deg2rad($lat1);
    $lonFrom = deg2rad($lon1);
    $latTo = deg2rad($lat2);
    $lonTo = deg2rad($lon2);
    // 计算纬度和经度的差值
    $latDelta = $latTo - $latFrom;
    $lonDelta = $lonTo - $lonFrom;
    // Haversine公式
    $a = sin($latDelta / 2) * sin($latDelta / 2) +
         cos($latFrom) * cos($latTo) *
         sin($lonDelta / 2) * sin($lonDelta / 2);
    $c = 2 * asin(sqrt($a));
    // 最终距离
    $distance = $earthRadius * $c;
    return $distance;
}
// 使用示例
$lat1 = 39.9042; // 北京纬度
$lon1 = 116.4074; // 北京经度
$lat2 = 31.2304; // 上海纬度
$lon2 = 121.4737; // 上海经度
$distance = haversineDistance($lat1, $lon1, $lat2, $lon2);
echo "北京到上海的直线距离约为:" . round($distance, 2) . " 公里";

使用PHP的atan2版本(更精确)

function getDistance($lat1, $lon1, $lat2, $lon2) {
    $earthRadius = 6371; // 公里
    $latFrom = deg2rad($lat1);
    $lonFrom = deg2rad($lon1);
    $latTo = deg2rad($lat2);
    $lonTo = deg2rad($lon2);
    $lonDelta = $lonTo - $lonFrom;
    $a = pow(cos($latTo) * sin($lonDelta), 2) +
         pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
    $b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
    $angle = atan2(sqrt($a), $b);
    return $angle * $earthRadius;
}

返回多种单位的版本

function calculateDistance($lat1, $lon1, $lat2, $lon2, $unit = 'km') {
    $earthRadius = [
        'km' => 6371,
        'mi' => 3959,
        'm' => 6371000,
        'nm' => 3440.065 // 海里
    ];
    if (!isset($earthRadius[$unit])) {
        $unit = 'km';
    }
    $latFrom = deg2rad($lat1);
    $lonFrom = deg2rad($lon1);
    $latTo = deg2rad($lat2);
    $lonTo = deg2rad($lon2);
    $latDelta = $latTo - $latFrom;
    $lonDelta = $lonTo - $lonFrom;
    $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
        cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
    return $earthRadius[$unit] * $angle;
}
// 使用示例
echo calculateDistance(39.9042, 116.4074, 31.2304, 121.4737, 'km'); // 公里
echo calculateDistance(39.9042, 116.4074, 31.2304, 121.4737, 'mi'); // 英里

批量计算距离(适合数据库查询)

function getDistanceSQL($lat, $lng, $tableName = 'locations') {
    // 这个SQL可以用于MySQL数据库查询附近的地点
    $sql = "SELECT *, 
            (6371 * acos(
                cos(radians($lat)) * 
                cos(radians(latitude)) * 
                cos(radians(longitude) - radians($lng)) + 
                sin(radians($lat)) * 
                sin(radians(latitude))
            )) AS distance 
            FROM $tableName 
            HAVING distance < 50 
            ORDER BY distance";
    return $sql;
}

使用geotools库(推荐用于复杂项目)

如果项目需要更复杂的地理计算,可以使用Composer安装geotools:

composer require league/geotools
use League\Geotools\Coordinate\Coordinate;
use League\Geotools\Distance\Vincenty;
function geotoolsDistance($lat1, $lon1, $lat2, $lon2) {
    $coordA = new Coordinate([$lat1, $lon1]);
    $coordB = new Coordinate([$lat2, $lon2]);
    $calculator = new Vincenty();
    $distance = $calculator->setFrom($coordA)->setTo($coordB)->calculate();
    return $distance->get(); // 返回米
}

精度对比

  • Haversine公式:精度约0.5%,适合大多数应用场景
  • Vincenty公式:精度更高(<0.5mm),但计算更复杂
  • 球面余弦定律:适合短距离计算,对长距离精度会下降

注意事项

  1. 经纬度格式:确保使用十进制度数,而非度分秒格式
  2. 地球模型:上述计算假设地球是完美球体,实际为椭球体,但误差通常可接受
  3. 性能考虑:如果需要大量计算,建议在数据库层直接使用SQL计算

推荐在实际项目中使用第一种Haversine公式,兼顾了精度和性能。

抱歉,评论功能暂时关闭!