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 {// 平均半径,单位:mprivate 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.9652Point2D 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
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
