使用Java計算兩個經緯度之間的距離

地球經度和緯度的距離在地球表面上並不是簡單的直線距離,而是大圓弧的長度。因此,計算兩個全球位置之間的距離需要使用數學公式。在Java中,有幾種方法可以準確地計算兩點之間的距離,幾乎可以支持全球任何位置。

一、Haversine公式

Haversine公式是一種常用的計算球面距離的方法。這個公式用來計算兩個地球表面上的點之間的距離。

public static double haversine(double startLat, double startLong, double endLat, double endLong) {
    final int earthRadius = 6371;
    double dLat = Math.toRadians(endLat - startLat);
    double dLong = Math.toRadians(endLong - startLong);

    startLat = Math.toRadians(startLat);
    endLat = Math.toRadians(endLat);

    double a = Math.pow(Math.sin(dLat / 2), 2) +
               Math.pow(Math.sin(dLong / 2), 2) *
               Math.cos(startLat) *
               Math.cos(endLat);
    double c = 2 * Math.asin(Math.sqrt(a));
    return earthRadius * c;
}

這段代碼用來計算兩個經緯度之間的距離,它將地球看做是一個球形,所以需要知道地球的半徑。在這個例子中,半徑設置為6371千米。函數參數startLat和startLong是第一個點的緯度和經度,endLat和endLong是第二個點的緯度和經度。這個函數返回兩個點之間的距離,以千米為單位。

二、Vincenty公式

Vincenty公式是另一種球面距離計算方法。這個演算法比Haversine演算法更準確,但也需要更多的計算。這個公式考慮了地球的橢球形狀以及海拔高度對距離的影響。

public static double vincenty(double startLat, double startLong, double endLat, double endLong) {
    final double earthRadius = 6371; // km

    double lat1 = Math.toRadians(startLat);
    double lat2 = Math.toRadians(endLat);
    double dLong = Math.toRadians(endLong - startLong);

    double y = Math.sin(dLong) * Math.cos(lat2);
    double x = Math.cos(lat1) * Math.sin(lat2) -
               Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLong);
    double bearing = Math.atan2(y, x);
    
    double phi1 = Math.atan2(Math.tan(lat1), Math.cos(bearing));
    double phi2 = Math.atan2(Math.tan(lat2), Math.cos(bearing));

    double a = Math.pow(Math.cos(phi2) * Math.sin(dLong), 2) +
               Math.pow(Math.cos(phi1) * Math.sin(phi2) -
                         Math.sin(phi1) * Math.cos(phi2) * Math.cos(dLong), 2);
    double b = Math.sin(phi1) * Math.sin(phi2) +
               Math.cos(phi1) * Math.cos(phi2) * Math.cos(dLong);
    double c = Math.atan2(Math.sqrt(a), b);
    return earthRadius * c;
}

這段代碼中的變數和參數與上面的函數類似,使用的是地球半徑6371千米。這裡的函數使用了發射角(bearing)的概念,它是第一點和第二點之間的連線與正北方向之間的角度。這個函數返回兩點之間的距離,以千米為單位。

三、不考慮海拔高度的計算

如果您不需要考慮海拔高度的影響,那麼可以使用簡單的勾股定理來計算兩點之間的距離。下面是一個示例函數:

public static double distance(double lat1, double lon1, double lat2, double lon2) {
    double theta = lon1 - lon2; 
    double dist = Math.sin(Math.toRadians(lat1)) * Math.sin(Math.toRadians(lat2)) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.cos(Math.toRadians(theta));
    dist = Math.acos(dist); 
    dist = Math.toDegrees(dist); 
    dist = dist * 60 * 1.1515; 
    dist = dist * 1.609344;
    return (dist);
}

這個函數返回兩點之間的距離,單位是千米。它使用的是經典的勾股定理,但是將地球的曲球面考慮在內。

四、代碼示例

public class DistanceCalculator {

    public static double haversine(double startLat, double startLong, double endLat, double endLong) {
        final int earthRadius = 6371;
        double dLat = Math.toRadians(endLat - startLat);
        double dLong = Math.toRadians(endLong - startLong);

        startLat = Math.toRadians(startLat);
        endLat = Math.toRadians(endLat);

        double a = Math.pow(Math.sin(dLat / 2), 2) +
                   Math.pow(Math.sin(dLong / 2), 2) *
                   Math.cos(startLat) *
                   Math.cos(endLat);
        double c = 2 * Math.asin(Math.sqrt(a));
        return earthRadius * c;
    }

    public static double vincenty(double startLat, double startLong, double endLat, double endLong) {
        final double earthRadius = 6371; // km

        double lat1 = Math.toRadians(startLat);
        double lat2 = Math.toRadians(endLat);
        double dLong = Math.toRadians(endLong - startLong);

        double y = Math.sin(dLong) * Math.cos(lat2);
        double x = Math.cos(lat1) * Math.sin(lat2) -
                   Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLong);
        double bearing = Math.atan2(y, x);

        double phi1 = Math.atan2(Math.tan(lat1), Math.cos(bearing));
        double phi2 = Math.atan2(Math.tan(lat2), Math.cos(bearing));

        double a = Math.pow(Math.cos(phi2) * Math.sin(dLong), 2) +
                   Math.pow(Math.cos(phi1) * Math.sin(phi2) -
                             Math.sin(phi1) * Math.cos(phi2) * Math.cos(dLong), 2);
        double b = Math.sin(phi1) * Math.sin(phi2) +
                   Math.cos(phi1) * Math.cos(phi2) * Math.cos(dLong);
        double c = Math.atan2(Math.sqrt(a), b);
        return earthRadius * c;
    }

    public static double distance(double lat1, double lon1, double lat2, double lon2) {
        double theta = lon1 - lon2; 
        double dist = Math.sin(Math.toRadians(lat1)) * Math.sin(Math.toRadians(lat2)) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.cos(Math.toRadians(theta));
        dist = Math.acos(dist); 
        dist = Math.toDegrees(dist); 
        dist = dist * 60 * 1.1515; 
        dist = dist * 1.609344;
        return (dist);
    }
}

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/291218.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-24 13:14
下一篇 2024-12-24 13:14

相關推薦

  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java Bean載入過程

    Java Bean載入過程涉及到類載入器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean載入的過程。 一、類載入器 類載入器是Java虛擬機…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • 利用Python實現兩個鏈表合併為一個有序鏈表

    對於開發工程師來說,實現兩個鏈表合併為一個有序鏈表是必須掌握的技能之一。Python語言在鏈表處理上非常便利,本文將從多個方面詳細闡述如何利用Python實現兩個鏈表合併為一個有序…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • VSCode為什麼無法運行Java

    解答:VSCode無法運行Java是因為默認情況下,VSCode並沒有集成Java運行環境,需要手動添加Java運行環境或安裝相關插件才能實現Java代碼的編寫、調試和運行。 一、…

    編程 2025-04-29
  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29

發表回復

登錄後才能評論