JAVA 根據經緯度獲取兩點之間的距離

前(fei)言(hua):

最近搞“考勤系統”其中有個“考勤打卡不能超過設置打卡地點多少m需求”,查詢帖子,參照相關帖子,做個筆記,方便以後使用。

 

先上測試結果吧:

比網上多數看不懂的算法要準確一些,雖然依然跟百度地圖上的測量結果稍有出入,不過已經足夠應付一般的需求了~

思路:

1. 地球本身是個不規則的球體,這裏將其看着一個規制球體

2. 半徑取平均值:6371.393千米

3. 計算公式採用“球面距離公式”:S=R·arccos[cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2]

4. 對公式的理解:設需要求距離的兩點爲A、B,球心爲O。可以分解成3步:

    ① cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2——求∠AOB的餘弦值,這裏是難點,得到這部分公式的推導過程比較複雜;

    ② arccos[∠AOB的餘弦值]——求∠AOB的反餘弦值,值域爲[0,π],本質是 ∠AOB角度 / 180° * π;

    ③ R·∠AOB的反餘弦值,等價於 R·∠AOB角度 / 180° * π,這裏集合弧長公式很好理解

注意:

1. 經緯度,在本質上是角度

2. Java中的Math類提供的sin和con方法的參數是弧度,而不是角度

3. 公式裏面的“arccos”是反餘弦算法,在Math類中爲acos()方法

package com.chinacoal.microservice.util.tool;

import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author sc
 * @version V1.0
 * @createTime 2020/6/26 17:21
 * @description
 */
public class LocationUtils {
    // 平均半徑,單位:m
    private static final double EARTH_RADIUS = 6371393;

    /**
     * 通過AB點經緯度獲取距離 整數
     * @param pointA A點(經,緯)
     * @param pointB B點(經,緯)
     * @return 距離(單位:米)
     */
    public static long getDistance(Point2D pointA, Point2D pointB) {
        // 經緯度(角度)轉弧度。弧度用作參數,以調用Math.cos和Math.sin
        // A經弧度
        double radiansAX = Math.toRadians(pointA.getX());
        // A緯弧度
        double radiansAY = Math.toRadians(pointA.getY());
        // B經弧度
        double radiansBX = Math.toRadians(pointB.getX());
        // B緯弧度
        double radiansBY = Math.toRadians(pointB.getY());
        // 公式中“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);
        // 反餘弦值
        double acos = Math.acos(cos);
        // 最終結果
        double h = EARTH_RADIUS * acos;

        //四捨五入
        long f1 = Math.round(h);
        //保留小數後兩位
       /* BigDecimal b = new BigDecimal(h);
        double f1 = b.setScale(2, RoundingMode.HALF_UP).doubleValue();*/
        return f1;
    }


    /**
     * 通過AB點經緯度獲取距離  真實距離
     * @param pointA A點(經,緯)
     * @param pointB B點(經,緯)
     * @return 距離(單位:米)
     */
    public static double  getDistanceDouble(Point2D pointA, Point2D pointB) {
        // 經緯度(角度)轉弧度。弧度用作參數,以調用Math.cos和Math.sin
        // A經弧度
        double radiansAX = Math.toRadians(pointA.getX());
        // A緯弧度
        double radiansAY = Math.toRadians(pointA.getY());
        // B經弧度
        double radiansBX = Math.toRadians(pointB.getX());
        // B緯弧度
        double radiansBY = Math.toRadians(pointB.getY());
        // 公式中“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);
        // 反餘弦值
        double acos = Math.acos(cos);
        // 最終結果
        double h = EARTH_RADIUS * acos;
        return h;
    }
    /**
     * 通過AB點經緯度獲取距離  小數後倆位
     * @param pointA A點(經,緯)
     * @param pointB B點(經,緯)
     * @return 距離(單位:米)
     */
    public static double  getDistanceDoubleBy2(Point2D pointA, Point2D pointB) {
        // 經緯度(角度)轉弧度。弧度用作參數,以調用Math.cos和Math.sin
        // A經弧度
        double radiansAX = Math.toRadians(pointA.getX());
        // A緯弧度
        double radiansAY = Math.toRadians(pointA.getY());
        // B經弧度
        double radiansBX = Math.toRadians(pointB.getX());
        // B緯弧度
        double radiansBY = Math.toRadians(pointB.getY());
        // 公式中“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);
        // 反餘弦值
        double acos = Math.acos(cos);
        // 最終結果
        double h = EARTH_RADIUS * acos;
        //保留小數後兩位
        BigDecimal b = new BigDecimal(h);
        double f1 = b.setScale(2, RoundingMode.HALF_UP).doubleValue();
        return f1;
    }

    public static void main(String[] args) {
        //中煤大廈西門
       // Point2D pointDD = new Point2D.Double( 116.414735,39.963634);
        // 北京 將宅口
        //Point2D pointDD = new Point2D.Double(116.414942,39.963859);
        // 北京  將宅十字路口
         //Point2D pointDD = new Point2D.Double(116.414775,39.965553);
         //北京 將宅十字路口東門116.417304,39.9652
         Point2D pointDD = new Point2D.Double(116.417304,39.9652);
        // 北京 將宅口
        Point2D pointXD = new Point2D.Double(116.414942,39.963859);

        double distanceDouble = getDistanceDouble(pointDD, pointXD);
        System.out.println(distanceDouble);
        System.out.println(distanceDouble<200);
        System.out.println();

        double distanceDouble2 = getDistanceDoubleBy2(pointDD, pointXD);
        System.out.println(distanceDouble2);
        System.out.println(distanceDouble2<200);
        System.out.println();

        Long distance = getDistance(pointDD, pointXD);
        System.out.println(distance);
        System.out.println(distance<200);
        System.out.println();



       /* // 北京 東單地鐵站
        Point2D pointDD = new Point2D.Double(116.425249, 39.914504);
        // 北京 西單地鐵站
        Point2D pointXD = new Point2D.Double(116.382001, 39.913329);
        System.out.println(getDistance(pointDD, pointXD));
        System.out.println();*/

      /*  // 北京 天安門
        Point2D pointTAM = new Point2D.Double(116.403882, 39.915139);
        // 廣州 越秀公園
        Point2D pointGZ = new Point2D.Double(113.272422, 23.147387);
        System.out.println(getDistance(pointTAM, pointGZ));
        System.out.println();*/

      /*  // 四川大學
        Point2D pointSCDX = new Point2D.Double(104.090539, 30.636951);
        // 成都南站
        Point2D pointCDNZ = new Point2D.Double(104.074238, 30.612572);
        System.out.println(getDistance(pointSCDX, pointCDNZ));
        System.out.println();*/
    }
}

測試代碼:附上百度地圖座標拾取系統,方便各位測試

下面爲 測試取的點

 

參照  感謝

https://blog.csdn.net/jk940438163/article/details/83147557?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.nonecase

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章