我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐

目录

前言

一、根据坐标经纬度计算两点距离(5种方法)

1.方法一

2.方法二

3.方法三

4.方法四

5.方法五

5.1 POM引入第三方依赖

5.2 代码

6.测试结果对比

二、校验经纬度是否在制定区域内

1.判断一个坐标是否在圆形区域内

2.判断一个坐标是否在一个多边形区域内

3.结果

总结


前言

        在开发项目中会用到根据两点坐标计算之间距离的算法,网上也找了很多的方法,多多少少会存在一些问题的。以下方法已经在我本地运行通过,利用百度地图拾取坐标系统和百度地图测距工具进行测试,现将其整理了一下。以供大家参考:


一、根据坐标经纬度计算两点距离

1.方法一

package com.test.java.util;public class PositionUtil {        private static final double EQUATOR_RADIUS = 6378137;        public static double getDistance1(double longitude1, double latitude1, double longitude2, double latitude2) {        // 纬度        double lat1 = Math.toRadians(latitude1);        double lat2 = Math.toRadians(latitude2);        // 经度        double lon1 = Math.toRadians(longitude1);        double lon2 = Math.toRadians(longitude2);        // 纬度之差        double a = lat1 - lat2;        // 经度之差        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;public class PositionUtil {        private static final double EARTH_AVG_RADIUS = 6371000;            public static double getDistance3(double longitude1, double latitude1, double longitude2, double latitude2) {        // 经纬度(角度)转弧度。弧度作为作参数,用以调用Math.cos和Math.sin        // A经弧度        double radiansAX = Math.toRadians(longitude1);        // A纬弧度        double radiansAY = Math.toRadians(latitude1);        // B经弧度        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]        // 最终结果        return EARTH_AVG_RADIUS * acos;    }}

3.方法三

基于谷歌地图的计算公式计算距离

package com.test.java.util;public class PositionUtil {        private static final double EARTH_AVG_RADIUS = 6371000;        private static double rad(double d) {        return d * Math.PI / 180.0;    }        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 {        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;        // 结果四舍五入 保留2位小数        //return new BigDecimal(distance).setScale(2, RoundingMode.HALF_UP).doubleValue();    }}

5.方法五

该方法是利用第三方jar包计算

5.1 POM引入第三方依赖

                org.gavaghan        geodesy        1.1.3    

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;public class PositionUtil {        public static double getDistance4(double longitude1, double latitude1, double longitude2, double latitude2, Ellipsoid ellipsoid) {        // 创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离        GlobalCoordinates firstPoint = new GlobalCoordinates(latitude1, longitude1);        GlobalCoordinates secondPoint = new GlobalCoordinates(latitude2, longitude2);        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, firstPoint, secondPoint);        return geoCurve.getEllipsoidalDistance();    }}

6.测试结果对比

这里我直接一起调用者4种方法,这样看结果也更加直观些。

    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方法中提供的测试数据也是我自身的真实数据,结合百度地图的测距工具进行的测试。有需要的小伙伴,可以自行选择合适的方法。

二、校验经纬度是否在制定区域内

怎么样判断一个坐标点在指定的区域内?其中区域又会分为:圆,多边形和不规则的多边形。

1.判断一个坐标是否在圆形区域内

计算这个坐标点和圆心之间的距离,然后跟圆的半径进行比较,如果比半径大,就不在圆形区域内,如果小于等于圆的半径,则该坐标点在圆形区域内。

package com.test.java.util;import org.apache.commons.lang3.StringUtils;public class PositionUtil {        private static final double EQUATOR_RADIUS = 6378137;        public static double getDistance1(double longitude1, double latitude1, double longitude2, double latitude2) {        // 纬度        double lat1 = Math.toRadians(latitude1);        double lat2 = Math.toRadians(latitude2);        // 经度        double lon1 = Math.toRadians(longitude1);        double lon2 = Math.toRadians(longitude2);        // 纬度之差        double a = lat1 - lat2;        // 经度之差        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;    }        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.判断一个坐标是否在一个多边形区域内

这里用到JAVA的一个类GeneralPath(由直线和二次和三次(B?zier)曲线构成的几何路径。 它可以包含多个子路径)使用这个类,结合传入的各顶点参数,画一个几何图形,并通过它自身的contains方法,判断该点是否在这个几何图形内。

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 {        public static boolean isInPolygon(double pointLon, double pointLat, double[] lon, double[] lat) {        // 将要判断的横纵坐标组成一个点        Point2D.Double point = new Point2D.Double(pointLon, pointLat);        // 将区域各顶点的横纵坐标放到一个点集合里面        List 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);    }        private static boolean check(Point2D.Double point, List polygon) {        GeneralPath generalPath = new GeneralPath();        Point2D.Double first = polygon.get(0);        // 通过移动到指定坐标(以双精度指定),将一个点添加到路径中        generalPath.moveTo(first.x, first.y);        polygon.remove(0);        for (Point2D.Double d : polygon) {            // 通过绘制一条从当前坐标到新指定坐标(以双精度指定)的直线,将一个点添加到路径中。            generalPath.lineTo(d.x, d.y);        }        // 将几何多边形封闭        generalPath.lineTo(first.x, first.y);        generalPath.closePath();        // 测试指定的 Point2D 是否在 Shape 的边界内。        return generalPath.contains(point);    }}

3.结果

    public static void main(String[] args) {        double distance1 = PositionUtil.getDistance1(longitude1, latitude1, longitude2, latitude2);        System.out.println("坐标与圆心的距离:" + distance1);        String radius1 = "10000";        boolean inCircle1 = PositionUtil.isInCircle(longitude1, latitude1, longitude2, latitude2, radius1);        System.out.println("校验坐标是否在圆形范围内:" + inCircle1);        String radius = "15000";        boolean inCircle2 = PositionUtil.isInCircle(longitude1, latitude1, longitude2, latitude2, radius);        System.out.println("校验坐标是否在圆形范围内:" + inCircle2);        double pointLon = 117.274984;        double pointLat = 31.790718;        // 坐标在多边形范围内的参数:        double[] lon = {117.272559, 117.276224, 117.278649, 117.273924};        double[] lat = {31.791247, 31.792812, 31.78982, 31.788539};        // 坐标在多边形范围外的参数:        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("校验坐标是否在多边形范围内:" + a);        System.out.println("校验坐标是否在多边形范围内:" + b);    }

 


总结

        这样的计算方式得到的距离并非是真实的距离,可以说是逻辑距离(直线距离),但其距离也已经很准确。不过毕竟是通过逻辑计算得到的距离,若要求高准确性的距离信息的话,还是借助第三方的地图api接口获取比较合适。

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。

来源地址:https://blog.csdn.net/weixin_42555014/article/details/132088436

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录