最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java根據(jù)坐標(biāo)經(jīng)緯度計算兩點距離5種方法及校驗經(jīng)緯度是否在圓/多邊形區(qū)域內(nèi)的算法推薦

 更新時間:2023年12月15日 08:53:40   作者:Javaの甘乃迪  
在項目開發(fā)過程中需要根據(jù)兩地經(jīng)緯度坐標(biāo)計算兩地間距離,下面這篇文章主要給大家介紹了關(guān)于Java根據(jù)坐標(biāo)經(jīng)緯度計算兩點距離5種方法以及校驗經(jīng)緯度是否在圓/多邊形區(qū)域內(nèi)的算法推薦,需要的朋友可以參考下

前言

在開發(fā)項目中會用到根據(jù)兩點坐標(biāo)計算之間距離的算法,網(wǎng)上也找了很多的方法,多多少少會存在一些問題的。以下方法已經(jīng)在我本地運行通過,利用百度地圖拾取坐標(biāo)系統(tǒng)和百度地圖測距工具進行測試,現(xiàn)將其整理了一下。以供大家參考:

一、根據(jù)坐標(biāo)經(jīng)緯度計算兩點距離

1.方法一

package com.test.java.util;

/**
 * 坐標(biāo)位置相關(guān)util
 */
public class PositionUtil {

    /**
     * 赤道半徑(單位:米)
     */
    private static final double EQUATOR_RADIUS = 6378137;

    /**
     * 方法一:(反余弦計算方式)
     *
     * @param longitude1 第一個點的經(jīng)度
     * @param latitude1  第一個點的緯度
     * @param longitude2 第二個點的經(jīng)度
     * @param latitude2  第二個點的緯度
     * @return 返回距離,單位m
     */
    public static double getDistance1(double longitude1, double latitude1, double longitude2, double latitude2) {
        // 緯度
        double lat1 = Math.toRadians(latitude1);
        double lat2 = Math.toRadians(latitude2);
        // 經(jīng)度
        double lon1 = Math.toRadians(longitude1);
        double lon2 = Math.toRadians(longitude2);
        // 緯度之差
        double a = lat1 - lat2;
        // 經(jīng)度之差
        double b = lon1 - lon2;
        // 計算兩點距離的公式
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
        // 弧長乘赤道半徑, 返回單位: 米
        s = s * EQUATOR_RADIUS;
        return s;
    }

}

2.方法二

package com.test.java.util;

/**
 * 坐標(biāo)位置相關(guān)util
 */
public class PositionUtil {

    /**
     * 地球平均半徑(單位:米)
     */
    private static final double EARTH_AVG_RADIUS = 6371000;
    
    /**
     * 方法二:(反余弦計算方式)
     *
     * @param longitude1 第一點的經(jīng)度
     * @param latitude1  第一點的緯度
     * @param longitude2 第二點的經(jīng)度
     * @param latitude2  第二點的緯度
     * @return 返回的距離,單位m
     */
    public static double getDistance3(double longitude1, double latitude1, double longitude2, double latitude2) {
        // 經(jīng)緯度(角度)轉(zhuǎn)弧度?;《茸鳛樽鲄?shù),用以調(diào)用Math.cos和Math.sin
        // A經(jīng)弧度
        double radiansAX = Math.toRadians(longitude1);
        // A緯弧度
        double radiansAY = Math.toRadians(latitude1);
        // B經(jīng)弧度
        double radiansBX = Math.toRadians(longitude2);
        // B緯弧度
        double radiansBY = Math.toRadians(latitude2);

        // 公式中“cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2”的部分,得到∠AOB的cos值
        double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX) + Math.sin(radiansAY) * Math.sin(radiansBY);
        // System.out.println("cos = " + cos); // 值域[-1,1]

        // 反余弦值
        double acos = Math.acos(cos);
        // System.out.println("acos = " + acos); // 值域[0,π]
        // System.out.println("∠AOB = " + Math.toDegrees(acos)); // 球心角 值域[0,180]

        // 最終結(jié)果
        return EARTH_AVG_RADIUS * acos;
    }
}

3.方法三

基于谷歌地圖的計算公式計算距離

package com.test.java.util;

/**
 * 坐標(biāo)位置相關(guān)util
 */
public class PositionUtil {

    /**
     * 地球平均半徑(單位:米)
     */
    private static final double EARTH_AVG_RADIUS = 6371000;

    /**
     * 經(jīng)緯度轉(zhuǎn)化為弧度(rad)
     *
     * @param d 經(jīng)度/緯度
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * 方法三:(基于googleMap中的算法得到兩經(jīng)緯度之間的距離,計算精度與谷歌地圖的距離精度差不多。)
     *
     * @param longitude1 第一點的經(jīng)度
     * @param latitude1  第一點的緯度
     * @param longitude2 第二點的經(jīng)度
     * @param latitude2  第二點的緯度
     * @return 返回的距離,單位m
     */
    public static double getDistance2(double longitude1, double latitude1, double longitude2, double latitude2) {
        double radLat1 = rad(latitude1);
        double radLat2 = rad(latitude2);
        double a = radLat1 - radLat2;
        double b = rad(longitude1) - rad(longitude2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_AVG_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        return s;
    }

}

4.方法四

基于高德地圖

package com.test.java.util;
/**
 * 計算距離
 */
public class PositionUtil {
    /**
     * 方法四:(高德地圖計算方法)
     *
     * @param longitude1 第一點的經(jīng)度
     * @param latitude1  第一點的緯度
     * @param longitude2 第二點的經(jīng)度
     * @param latitude2  第二點的緯度
     * @return 返回的距離,單位m
     */
    public static Double getDistance4(double longitude1, double latitude1, double longitude2, double latitude2) {
        if (longitude1 == 0 || latitude1 == 0 || latitude2 == 0 || longitude2 == 0) {
            return -1.0;
        }
        longitude1 *= 0.01745329251994329;
        latitude1 *= 0.01745329251994329;
        longitude2 *= 0.01745329251994329;
        latitude2 *= 0.01745329251994329;
        double var1 = Math.sin(longitude1);
        double var2 = Math.sin(latitude1);
        double var3 = Math.cos(longitude1);
        double var4 = Math.cos(latitude1);
        double var5 = Math.sin(longitude2);
        double var6 = Math.sin(latitude2);
        double var7 = Math.cos(longitude2);
        double var8 = Math.cos(latitude2);
        double[] var10 = new double[3];
        double[] var20 = new double[3];
        var10[0] = var4 * var3;
        var10[1] = var4 * var1;
        var10[2] = var2;
        var20[0] = var8 * var7;
        var20[1] = var8 * var5;
        var20[2] = var6;
        return Math.asin(Math.sqrt((var10[0] - var20[0]) * (var10[0] - var20[0]) + (var10[1] - var20[1]) * (var10[1] - var20[1]) + (var10[2] - var20[2]) * (var10[2] - var20[2])) / 2.0) * 1.27420015798544E7;
        // 結(jié)果四舍五入 保留2位小數(shù)
        //return new BigDecimal(distance).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
}

5.方法五

該方法是利用第三方j(luò)ar包計算

5.1 POM引入第三方依賴

    <!--用于計算兩點之間的距離-->
    <dependency>
        <groupId>org.gavaghan</groupId>
        <artifactId>geodesy</artifactId>
        <version>1.1.3</version>
    </dependency>

5.2 代碼

package com.test.java.util;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
/**
 * 坐標(biāo)位置相關(guān)util
 */
public class PositionUtil {
    /**
     * 方法四:(利用第三方j(luò)ar包計算)
     * 計算兩個經(jīng)緯度之間的距離
     *
     * @param longitude1 第一點的經(jīng)度
     * @param latitude1  第一點的緯度
     * @param longitude2 第二點的經(jīng)度
     * @param latitude2  第二點的緯度
     * @param ellipsoid  計算方式
     * @return 返回的距離,單位m
     */
    public static double getDistance4(double longitude1, double latitude1, double longitude2, double latitude2, Ellipsoid ellipsoid) {
        // 創(chuàng)建GeodeticCalculator,調(diào)用計算方法,傳入坐標(biāo)系、經(jīng)緯度用于計算距離
        GlobalCoordinates firstPoint = new GlobalCoordinates(latitude1, longitude1);
        GlobalCoordinates secondPoint = new GlobalCoordinates(latitude2, longitude2);
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, firstPoint, secondPoint);
        return geoCurve.getEllipsoidalDistance();
    }
}

6.測試結(jié)果對比

這里我直接一起調(diào)用者4種方法,這樣看結(jié)果也更加直觀些。

    public static void main(String[] args) {
        double longitude1 = 117.344733;
        double latitude1 = 31.912334;
        double longitude2 = 117.272186;
        double latitude2 = 31.79422;
        double distance1 = PositionUtil.getDistance1(longitude1, latitude1, longitude2, latitude2);
        double distance2 = PositionUtil.getDistance2(longitude1, latitude1, longitude2, latitude2);
        double distance3 = PositionUtil.getDistance3(longitude1, latitude1, longitude2, latitude2);
        double distance4 = PositionUtil.getDistance4(longitude1, latitude1, longitude2, latitude2);
        double distance5 = PositionUtil.getDistance4(longitude1, latitude1, longitude2, latitude2, Ellipsoid.Sphere);
        double distance6 = PositionUtil.getDistance4(longitude1, latitude1, longitude2, latitude2, Ellipsoid.WGS84);
        System.out.println("方法1算出的距離:" + distance1);
        System.out.println("方法2算出的距離:" + distance2);
        System.out.println("方法3算出的距離:" + distance3);
        System.out.println("方法4算出的距離:" + distance4);
        System.out.println("方法4-Sphere算出的距離:" + distance5);
        System.out.println("方法4-WGS84算出的距離:" + distance6);
    }

可以看出,這幾個方法算出的距離誤差相對較小。而且main方法中提供的測試數(shù)據(jù)也是我自身的真實數(shù)據(jù),結(jié)合百度地圖的測距工具進行的測試。有需要的小伙伴,可以自行選擇合適的方法。

二、校驗經(jīng)緯度是否在制定區(qū)域內(nèi)

怎么樣判斷一個坐標(biāo)點在指定的區(qū)域內(nèi)?其中區(qū)域又會分為:圓,多邊形和不規(guī)則的多邊形。

1.判斷一個坐標(biāo)是否在圓形區(qū)域內(nèi)

計算這個坐標(biāo)點和圓心之間的距離,然后跟圓的半徑進行比較,如果比半徑大,就不在圓形區(qū)域內(nèi),如果小于等于圓的半徑,則該坐標(biāo)點在圓形區(qū)域內(nèi)。

package com.test.java.util;
import org.apache.commons.lang3.StringUtils;
/**
 * 計算距離
 */
public class PositionUtil {
    /**
     * 赤道半徑(單位:米)
     */
    private static final double EQUATOR_RADIUS = 6378137;
    /**
     * 方法一:(反余弦計算方式)
     *
     * @param longitude1 第一個點的經(jīng)度
     * @param latitude1  第一個點的緯度
     * @param longitude2 第二個點的經(jīng)度
     * @param latitude2  第二個點的緯度
     * @return 返回距離,單位m
     */
    public static double getDistance1(double longitude1, double latitude1, double longitude2, double latitude2) {
        // 緯度
        double lat1 = Math.toRadians(latitude1);
        double lat2 = Math.toRadians(latitude2);
        // 經(jīng)度
        double lon1 = Math.toRadians(longitude1);
        double lon2 = Math.toRadians(longitude2);
        // 緯度之差
        double a = lat1 - lat2;
        // 經(jīng)度之差
        double b = lon1 - lon2;
        // 計算兩點距離的公式
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
        // 弧長乘赤道半徑, 返回單位: 米
        s = s * EQUATOR_RADIUS;
        return s;
    }
    /**
     * 判斷坐標(biāo)點是否在圓形區(qū)域內(nèi)
     * 計算這個坐標(biāo)點和圓心點之間的距離,然后跟圓的半徑進行比較,如果比半徑大,就不在圓形區(qū)域內(nèi),如果小于等于圓的半徑,則該坐標(biāo)點在圓形區(qū)域內(nèi)
     *
     * @param longitude1 第一點的經(jīng)度
     * @param latitude1  第一點的緯度
     * @param longitude2 第二點的經(jīng)度
     * @param latitude2  第二點的緯度
     * @param radius     圓形范圍半徑(單位:米)
     * @return true:不在區(qū)域內(nèi); false:在區(qū)域內(nèi)
     */
    public static boolean isInCircle(double longitude1, double latitude1, double longitude2, double latitude2, String radius) {
        if (StringUtils.isBlank(radius)) {
            throw new RuntimeException("請輸入范圍半徑");
        }
        return getDistance1(longitude1, latitude1, longitude2, latitude2) > Double.parseDouble(radius);
    }
}

2.判斷一個坐標(biāo)是否在一個多邊形區(qū)域內(nèi)

這里用到JAVA的一個類GeneralPath(由直線和二次和三次(B?zier)曲線構(gòu)成的幾何路徑。 它可以包含多個子路徑)使用這個類,結(jié)合傳入的各頂點參數(shù),畫一個幾何圖形,并通過它自身的contains方法,判斷該點是否在這個幾何圖形內(nèi)。

package com.test.java.util;
import org.apache.commons.lang3.StringUtils;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
/**
 * 計算距離
 */
public class PositionUtil {
    /**
     * 判斷坐標(biāo)點是否在多邊形區(qū)域內(nèi)
     *
     * @param pointLon 要判斷的點的經(jīng)度
     * @param pointLat 要判斷的點的緯度
     * @param lon      區(qū)域各頂點的經(jīng)度數(shù)組
     * @param lat      區(qū)域各頂點的緯度數(shù)組
     * @return true:范圍內(nèi); false:范圍外
     */
    public static boolean isInPolygon(double pointLon, double pointLat, double[] lon, double[] lat) {
        // 將要判斷的橫縱坐標(biāo)組成一個點
        Point2D.Double point = new Point2D.Double(pointLon, pointLat);
        // 將區(qū)域各頂點的橫縱坐標(biāo)放到一個點集合里面
        List<Point2D.Double> pointList = new ArrayList<>();
        double polygonPointToX;
        double polygonPointToY;
        for (int i = 0; i < lon.length; i++) {
            polygonPointToX = lon[i];
            polygonPointToY = lat[i];
            Point2D.Double polygonPoint = new Point2D.Double(polygonPointToX, polygonPointToY);
            pointList.add(polygonPoint);
        }
        return check(point, pointList);
    }
    /**
     * 坐標(biāo)點是否在多邊形內(nèi)
     *
     * @param point   要判斷的點的橫縱坐標(biāo)
     * @param polygon 組成的頂點坐標(biāo)集合
     */
    private static boolean check(Point2D.Double point, List<Point2D.Double> polygon) {
        GeneralPath generalPath = new GeneralPath();
        Point2D.Double first = polygon.get(0);
        // 通過移動到指定坐標(biāo)(以雙精度指定),將一個點添加到路徑中
        generalPath.moveTo(first.x, first.y);
        polygon.remove(0);
        for (Point2D.Double d : polygon) {
            // 通過繪制一條從當(dāng)前坐標(biāo)到新指定坐標(biāo)(以雙精度指定)的直線,將一個點添加到路徑中。
            generalPath.lineTo(d.x, d.y);
        }
        // 將幾何多邊形封閉
        generalPath.lineTo(first.x, first.y);
        generalPath.closePath();
        // 測試指定的 Point2D 是否在 Shape 的邊界內(nèi)。
        return generalPath.contains(point);
    }
}

3.結(jié)果

    public static void main(String[] args) {
        double distance1 = PositionUtil.getDistance1(longitude1, latitude1, longitude2, latitude2);
        System.out.println("坐標(biāo)與圓心的距離:" + distance1);
        String radius1 = "10000";
        boolean inCircle1 = PositionUtil.isInCircle(longitude1, latitude1, longitude2, latitude2, radius1);
        System.out.println("校驗坐標(biāo)是否在圓形范圍內(nèi):" + inCircle1);
        String radius = "15000";
        boolean inCircle2 = PositionUtil.isInCircle(longitude1, latitude1, longitude2, latitude2, radius);
        System.out.println("校驗坐標(biāo)是否在圓形范圍內(nèi):" + inCircle2);
        double pointLon = 117.274984;
        double pointLat = 31.790718;
        // 坐標(biāo)在多邊形范圍內(nèi)的參數(shù):
        double[] lon = {117.272559, 117.276224, 117.278649, 117.273924};
        double[] lat = {31.791247, 31.792812, 31.78982, 31.788539};
        // 坐標(biāo)在多邊形范圍外的參數(shù):
        double[] lon1 = {117.291001, 117.299705, 117.298035, 117.291216};
        double[] lat1 = {31.806576, 31.806814, 31.802319, 31.802196};
        boolean a = PositionUtil.isInPolygon(pointLon, pointLat, lon, lat);
        boolean b = PositionUtil.isInPolygon(pointLon, pointLat, lon1, lat1);
        System.out.println("校驗坐標(biāo)是否在多邊形范圍內(nèi):" + a);
        System.out.println("校驗坐標(biāo)是否在多邊形范圍內(nèi):" + b);
    }

總結(jié)

這樣的計算方式得到的距離并非是真實的距離,可以說是邏輯距離(直線距離),但其距離也已經(jīng)很準(zhǔn)確。不過畢竟是通過邏輯計算得到的距離,若要求高準(zhǔn)確性的距離信息的話,還是借助第三方的地圖api接口獲取比較合適。

到此這篇關(guān)于Java根據(jù)坐標(biāo)經(jīng)緯度計算兩點距離5種方法及校驗經(jīng)緯度是否在圓/多邊形區(qū)域內(nèi)的算法推薦的文章就介紹到這了,更多相關(guān)Java根據(jù)坐標(biāo)經(jīng)緯度計算兩點距離內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java.lang.OutOfMemoryError: GC overhead limit exceeded錯誤的解決

    Java.lang.OutOfMemoryError: GC overhead limit

    本文主要介紹了Java.lang.OutOfMemoryError: GC overhead limit exceeded錯誤的解決,錯誤是由于堆空間不足導(dǎo)致GC頻繁運行,從而引起的,下面就來介紹一下解決方法
    2025-03-03
  • mybatis-plus更新字段為null的處理方式

    mybatis-plus更新字段為null的處理方式

    這篇文章主要介紹了mybatis-plus更新字段為null的處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • MyBatis-Plus常見面試題和答案大全

    MyBatis-Plus常見面試題和答案大全

    Mybatis-Plus是一個基于Mybatis的增強工具,它簡化了Mybatis的開發(fā)流程,提供了許多實用的功能,如自動生成代碼、分頁查詢、條件構(gòu)造器、性能分析等,這篇文章主要給大家介紹了關(guān)于MyBatis-Plus常見面試題和答案的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • Spring Boot中WebSocket常用使用方法詳解

    Spring Boot中WebSocket常用使用方法詳解

    本文從WebSocket的基礎(chǔ)概念出發(fā),詳細介紹了Spring Boot集成WebSocket的步驟,并重點講解了常用的使用方法,包括簡單消息收發(fā)、點對點消息發(fā)送、消息攔截與認證,以及不使用接口而是基于注解的WebSocket實現(xiàn)方式,感興趣的朋友一起看看吧
    2025-07-07
  • IDEA?2022.1.4用前注意事項

    IDEA?2022.1.4用前注意事項

    這篇文章主要介紹了IDEA?2022.1.4用前注意事項,本文通過圖文并茂的形式給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • Java中由substring方法引發(fā)的內(nèi)存泄漏詳解

    Java中由substring方法引發(fā)的內(nèi)存泄漏詳解

    這篇文章主要介紹了Java中由substring方法引發(fā)的內(nèi)存泄漏詳解,涉及substring方法引發(fā)的內(nèi)存泄漏簡介,substring的作用和實現(xiàn)原理等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下
    2017-12-12
  • RabbitMQ消息隊列實現(xiàn)延遲任務(wù)示例

    RabbitMQ消息隊列實現(xiàn)延遲任務(wù)示例

    這篇文章主要為大家介紹了RabbitMQ消息隊列實現(xiàn)延遲任務(wù)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • nodejs與JAVA應(yīng)對高并發(fā)的對比方式

    nodejs與JAVA應(yīng)對高并發(fā)的對比方式

    這篇文章主要介紹了nodejs與JAVA應(yīng)對高并發(fā)的對比方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 解決Maven項目pom.xml導(dǎo)入了Junit包還是用不了@Test注解問題

    解決Maven項目pom.xml導(dǎo)入了Junit包還是用不了@Test注解問題

    在Maven項目中,如果在非test目錄下使用@Test注解,可能會因為pom.xml中<scope>test</scope>的設(shè)置而無法使用,正確做法是將測試代碼放在src/test/java目錄下,或去除<scope>test</scope>限制,這樣可以確保Junit依賴正確加載并應(yīng)用于適當(dāng)?shù)拇a部分
    2024-10-10
  • 使用Guava?Cache原理及最佳實踐

    使用Guava?Cache原理及最佳實踐

    文章介紹了GuavaCache,這是一種支持高并發(fā)的本地緩存,它支持多種回收策略,如基于容量、時間和引用的回收,并提供了自動加載、定時刷新和顯式清除緩存的功能,文章還討論了GuavaCache的適用場景和使用方法,并通過代碼示例和源碼分析,幫助讀者更好地理解和使用GuavaCache
    2025-02-02

最新評論

江都市| 和林格尔县| 科尔| 宜宾县| 阆中市| 盐池县| 黄山市| 桓台县| 鄂托克前旗| 资兴市| 阿坝县| 红原县| 桐庐县| 黄骅市| 晋中市| 长阳| 会理县| 平度市| 寿阳县| 峨眉山市| 永安市| 尼勒克县| 河北省| 革吉县| 隆安县| 罗城| 齐河县| 苗栗市| 自治县| 临清市| 永德县| 鄂尔多斯市| 塔河县| 华容县| 阿荣旗| 康定县| 岫岩| 嵊州市| 会理县| 邮箱| 沂水县|