Spring Boot整合 Geodesy講解

上善若泪發表於2024-06-09

目錄
  • 1 Geodesy
    • 1.1 什麼是geodesy
    • 1.2 操作實踐
      • 1.2.1 pom.xml
      • 1.2.2 數學公式計算類
      • 1.2.3 庫包呼叫
      • 1.2.4 測試

1 Geodesy

1.1 什麼是geodesy

浩瀚的宇宙中,地球是我們賴以生存的家園。自古以來,人類一直對星球上的位置和彼此的距離著迷。無論是航海探險、貿易往來還是科學研究,精確計算兩個地點之間的距離都是至關重要的。 Geodesy:大地測量學的神奇力量 Geodesy,又稱大地測量學,是一門研究地球形狀、大小及其重力場的學科。在地球距離計算中,它扮演著至關重要的角色。Geodesy 的原理基於球面幾何。 首先,Geodesy 將地球近似為一個光滑的球體。然後,根據經緯度座標,將兩個地點視為球面上的兩點。最後,使用球面距離公式:
$$
d = R * arccos(sin(φ1) * sin(φ2) + cos(φ1) * cos(φ2) * cos(λ1 - λ2))
$$

其中,R 是地球半徑,φ1φ2 分別是兩個地點的緯度,λ1λ2 是兩個地點的經度,d 是兩點之間的距離。 透過這個公式,Geodesy 能夠快速準確地計算出地球上兩個經緯度座標之間的距離。

1.2 操作實踐

1.2.1 pom.xml

<dependency>
    <groupId>org.gavaghan</groupId>
    <artifactId>geodesy</artifactId>
    <version>1.1.3</version>
</dependency>

1.2.2 數學公式計算類

package com.et.geodesy.util;

import lombok.experimental.UtilityClass;
import java.math.BigDecimal;

/**
 * <p>formula:S=R·arccos[cosβ1·cosβ·2cos(α1-α2)+sinβ1·sinβ2]
 */
@UtilityClass
public class MathDistanceUtil {

  private static final double EARTH_RADIUS = 6371393;

  private static final double DEGREES_TO_RADIANS = 0.017453292519943295;


  public static double getDistance(
      Double longitude1, Double latitude1, Double longitude2, Double latitude2) {
    double radiansLongitude1 = toRadians(longitude1);
    double radiansLatitude1 = toRadians(latitude1);
    double radiansLongitude2 = toRadians(longitude2);
    double radiansLatitude2 = Math.toRadians(latitude2);

    final double cos =
        BigDecimal.valueOf(Math.cos(radiansLatitude1))
            .multiply(BigDecimal.valueOf(Math.cos(radiansLatitude2)))
            .multiply(
                BigDecimal.valueOf(
                    Math.cos(
                        BigDecimal.valueOf(radiansLongitude1)
                            .subtract(BigDecimal.valueOf(radiansLongitude2))
                            .doubleValue())))
            .add(
                BigDecimal.valueOf(Math.sin(radiansLatitude1))
                    .multiply(BigDecimal.valueOf(Math.sin(radiansLatitude2))))
            .doubleValue();

    double acos = Math.acos(cos);
    return BigDecimal.valueOf(EARTH_RADIUS).multiply(BigDecimal.valueOf(acos)).doubleValue();
  }

 
  private static double toRadians(double value) {
    return BigDecimal.valueOf(value).multiply(BigDecimal.valueOf(DEGREES_TO_RADIANS)).doubleValue();
  }
}

1.2.3 庫包呼叫

底層原理也是基於公式計算,方便大家使用才封裝成包

package com.et.geodesy.util;

import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;

import java.math.BigDecimal;
import java.math.RoundingMode;


public class GeodsyDistanceUtils {

    public static double getDistance(Double lonA, Double latA, Double lonB, Double latB,int newScale) {
        GlobalCoordinates source = new GlobalCoordinates(latA, lonA);
        GlobalCoordinates target = new GlobalCoordinates(latB, lonB);
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.Sphere, source, target);
        double distance = geoCurve.getEllipsoidalDistance();
        BigDecimal distanceBig = new BigDecimal(distance).setScale(newScale, RoundingMode.UP);
        return distanceBig.doubleValue();
    }

}

以上只是一些關鍵程式碼,所有程式碼請參見下面程式碼倉庫

1.2.4 測試

編寫測試類

@Test
public void getDistance() {
    // source (113.324553,23.106414)
    // target (121.499718, 31.239703)
    double distance1 = GeodsyDistanceUtils.getDistance(113.324553,23.106414,
            121.499718, 31.239703,2);
    System.out.println("distant1(m):" + distance1);
    double distance2 = MathDistanceUtil.getDistance(113.324553, 23.106414, 121.499718, 31.239703);
    System.out.println("distant2(m):" + distance2);
}

執行單元測試,發現2種計算方式誤差不大
distant1(m):1212316.48
distant2(m):1212391.2574948743

相關文章