Java实现通过经纬度求两个任意地点在球面上的距离

我们在实际开发中会获取对应的经纬度,可以使用ES大数据搜索引擎进行计算对应区域的数据,那我们在如何根据两个经纬度获取对应的球面距离,就是在地球上从一个地点到另一个地点的直线距离

工具类如下:

public class GeoUtils {
    // 地球半径(单位:米)
    private static final double EARTH_RADIUS = 6371000.0;

    /**
     * 使用Haversine公式计算两点之间的球面距离
     *
     * @param lat1 latitude 纬度
     * @param lon1 longitude 经度
     * @param lat2 纬度
     * @param lon2 经度
     * @return 球面距离
     */
    public static double haversineDistance(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return EARTH_RADIUS * c;
    }

    /**
     * 使用Vincenty公式计算两点之间的球面距离
     *
     * @param lat1 latitude 纬度
     * @param lon1 longitude 经度
     * @param lat2 纬度
     * @param lon2 经度
     * @return 球面距离
     */
    public static double vincentyDistance(double lat1, double lon1, double lat2, double lon2) {
        double a = EARTH_RADIUS;
        double f = 1.0 / 298.257223563; // WGS-84 ellipsoid parameters
        double b = a * (1.0 - f);
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);

        double L = lon2Rad - lon1Rad;
        double U1 = Math.atan((1.0 - f) * Math.tan(lat1Rad));
        double U2 = Math.atan((1.0 - f) * Math.tan(lat2Rad));
        double sinU1 = Math.sin(U1);
        double cosU1 = Math.cos(U1);
        double sinU2 = Math.sin(U2);
        double cosU2 = Math.cos(U2);

        double lambda = L;
        double lambdaP;
        int iterLimit = 100;
        double cosSigma, sinSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM;
        do {
            double sinLambda = Math.sin(lambda);
            double cosLambda = Math.cos(lambda);
            sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) +
                    (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) *
                            (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
            if (sinSigma == 0) {
                return 0.0;
            }
            cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
            sigma = Math.atan2(sinSigma, cosSigma);
            sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
            cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
            cos2SigmaM = cosSigma - 2.0 * sinU1 * sinU2 / cosSqAlpha;
            if (Double.isNaN(cos2SigmaM)) {
                cos2SigmaM = 0.0;
            }
            double C = f / 16.0 * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha));
            lambdaP = lambda;
            lambda = L + (1.0 - C) * f * sinAlpha *
                    (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM)));
        } while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0);

        if (iterLimit == 0) {
            return Double.NaN; // Formula failed to converge
        }

        double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
        double A = 1 + uSq / 16384.0 * (4096.0 + uSq * (-768 + uSq * (320 - 175 * uSq)));
        double B = uSq / 1024.0 * (256.0 + uSq * (-128.0 + uSq * (74.0 - 47 * uSq)));
        double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4.0 * (cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM) -
                B / 6.0 * cos2SigmaM * (-3.0 + 4.0 * sinSigma * sinSigma) *
                        (-3.0 + 4.0 * cos2SigmaM * cos2SigmaM)));
        return b * A * (sigma - deltaSigma);
    }

    /**
     * 使用球面三角法计算两点之间的球面距离
     *
     * @param lat1 latitude 纬度
     * @param lon1 longitude 经度
     * @param lat2 纬度
     * @param lon2 经度
     * @return 球面距离
     */
    public static double sphericalLawOfCosinesDistance(double lat1, double lon1, double lat2, double lon2) {
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
        return Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(dLon)) * EARTH_RADIUS;
    }

    /**
     * 将米转换成公里
     *
     * @param meters
     * @return
     */
    public static double metersToKilometers(double meters) {
        return meters / 1000.0;
    }

}

测试从纽约到伦敦的距离

  public static void main(String[] args) {
        double newYorkLat = 40.7128; // 纽约的纬度
        double newYorkLon = -74.0060; // 纽约的经度
        double londonLat = 51.5074; // 伦敦的纬度
        double londonLon = -0.1278; // 伦敦的经度
        double distance1 = GeoUtils.haversineDistance(newYorkLat, newYorkLon, londonLat, londonLon);
        System.out.println("从纽约到伦敦的球面距离:" + distance1 + " 米 ," + metersToKilometers(distance1) + " 公里");
        double distance2 = GeoUtils.vincentyDistance(newYorkLat, newYorkLon, londonLat, londonLon);
        System.out.println("从纽约到伦敦的球面距离:" + distance2 + " 米 ," + metersToKilometers(distance2) + " 公里");
        double distance3 = GeoUtils.sphericalLawOfCosinesDistance(newYorkLat, newYorkLon, londonLat, londonLon);
        System.out.println("从纽约到伦敦的球面距离:" + distance3 + " 米 ," + metersToKilometers(distance3) + " 公里");
    }

这样子就可以求出地球上两点之间的距离了 

8f249501609b491f9a24e4de5c1524e7.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/201613.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centos7中通过kubeadmin安装k8s集群

k8s部署官方提供了kind、minikube、kubeadmin等多种安装方式。 其中minikube安装在之前的文章中已经介绍过,部署比较简单。下面介绍通过kubeadmin部署k8s集群。 生产中提供了多种高可用方案: k8s官方文档 本文安装的是1.28.0版本。 建议去认真阅读一下…

Linux常用命令----cp 命令

文章目录 1. 基本用法2. 保留文件属性3. 递归复制4. 仅复制更新的文件5. 交互式复制6. 创建符号链接而非复制7. 复制并备份目标文件8. 指定备份后缀9. 详细输出总结 Linux操作系统中,cp 命令是一个非常基础且强大的工具,用于复制文件或目录。本文将详细介…

[Java]JUC并发编程

JUC并发编程 一、什么是JUC 使用到 java.util 工具包、包、分类 二、线程和进程 进程:一个正在运行的程序,QQ.exe Music.exe 程序的集合; 一个进程往往可以包含多个线程,至少包含一个! Java默认有两个线程&#x…

动态规划学习——斐波那契数列

目录 最长的斐波那契数列子序列的长度 1.题目 2.题目接口 3.解题思路及其代码 最长的斐波那契数列子序列的长度 1.题目 如果序列x_1&#xff0c;X_2&#xff0c;...&#xff0c;x_n 满足下列条件&#xff0c;就说它是斐波那契式的: 1.n > 3 2.对于所有i2 <n&a…

Java面向对象(高级)-- 接口(interface)

文章目录 一、概念&#xff08;1&#xff09;引入&#xff08;2&#xff09;类比&#xff08;3&#xff09;举例1. 举例12. 举例23. 举例34. 举例4 &#xff08;4&#xff09; 定义格式及重点举例1. 接口的声明格式2. 接口的成员说明3. 接口内部结构的说明4. 举例4.1 举例1--接…

【算法挨揍日记】day33——1027. 最长等差数列、446. 等差数列划分 II - 子序列

1027. 最长等差数列 1027. 最长等差数列 题目描述&#xff1a; 给你一个整数数组 nums&#xff0c;返回 nums 中最长等差子序列的长度。 回想一下&#xff0c;nums 的子序列是一个列表 nums[i1], nums[i2], ..., nums[ik] &#xff0c;且 0 < i1 < i2 < ... < …

Go GORM简介

GORM&#xff08;Go Object-Relational Mapping&#xff09;是一个用于Go语言的ORM库&#xff0c;它提供了一种简单、优雅的方式来操作数据库。GORM支持多种数据库&#xff0c;包括MySQL、PostgreSQL、SQLite和SQL Server。以下是GORM的一些主要特性 全功能ORM&#xff1a;GORM…

MyBatis-plus-Generate 自动生成代码结构实践

一、新建一个springboot项目&#xff0c;并引入依赖 关注mybatis-plus-boot-starter <properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding…

PyQt基础_007_ 按钮类控件QCombox

import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class ComboxDemo(QWidget):def __init__(self, parentNone):super(ComboxDemo, self).__init__(parent)self.setWindowTitle("combox 例子") self.resize(300, 90) …

【测试开发】web自动化测试框架需求设计 !

1、实现目的 基于BS架构&#xff0c;模拟用户&#xff08;鼠标、键盘&#xff09;操作&#xff0c;达到快速、重复执行测试用例&#xff1b; 便于回归测试&#xff0c;快速覆盖主线用例或功能&#xff1b; 线上或线下巡检测试&#xff0c;结合持续集成&#xff0c;及时发现运…

一起学docker系列之十二什么是dockerfile

目录 1 基本概念2 语法规则3 Dockerfile构建步骤4 Dockerfile、Docker镜像和Docker容器的关系5 保留字介绍5.1 FROM5.2 MAINTAINER5.3 RUN5.4 EXPOSE5.5 WORKDIR5.6 USER5.7 ENV5.8 ADD5.9 COPY5.10 VOLUME5.11 CMD5.12 ENTRYPOINT 6 总结7 参考地址 1 基本概念 Dockerfile是一…

【接口技术】实验3:可编程并行接口8255

实验3 可编程并行接口8255实验 一、实验目的 1&#xff1a;了解8255芯片结构及编程方法。 2&#xff1a;了解8255输入/输出实验方法。 3&#xff1a;掌握8255控制键盘及显示电路的基本功能及编程方法。 4&#xff1a;掌握一般键盘和显示电路的工作原理。 二、实验内容 1&…

JAVA - 阻塞队列

一、什么是堵塞队列 堵塞队列&#xff08;Blocking Queue&#xff09;是一种特殊类型的队列&#xff0c;它具有一些特定的行为和限制。在堵塞队列中&#xff0c;当队列为空时&#xff0c;尝试从队列中取出元素的操作将会被阻塞&#xff0c;直到队列中有可用元素&#xff1b;当…

java el表达式解析

使用Java EL表达式解析 在Java开发中&#xff0c;我们经常需要对表达式进行解析和计算。EL&#xff08;Expression Language&#xff09;表达式是一种用于在Java应用程序中计算和输出动态值的简单语言。它可以用于实现动态的条件判断、数学计算、字符串合并等功能。本文将教你…

《第一行代码:Android》第三版-3.4.4体验Activity的生命周期

本文的代码是在主Activity中&#xff0c;重载了几个生命周期函数&#xff0c;在日志中打印出对应的日志信息&#xff0c;有两个按钮&#xff0c;负责启动另外的Activity&#xff0c;并回到主Activity 由此查看日志&#xff0c;来体会生命周期。 MainActivity.kt 文件如下 pac…

SAP_MM_ABAP_物料视图维护监控报表(自定义开发)

SAP ABAP 顾问&#xff08;开发工程师&#xff09;能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读458次。目标&#xff1a;基于对SAP abap 顾问能力模型的梳理&#xff0c;给一年左右经验的abaper 快速成长为三年经验提供超级燃料&#xff01;https://blog.csdn.net/j…

Java零基础——Nginx篇

1.【熟悉】服务器概述 1.1 目前常见的web服务器 1&#xff0c;Apache(http://httpd.apache.org) 它是世界上用的最多的web服务器&#xff0c;市场占有率达60%左右&#xff0c;模块非常丰富&#xff0c;系统非常稳定&#xff0c;可移植性好&#xff0c;但是比较消耗资源 2&…

Javaweb之Vue组件库Element案例的详细解析

4.4 案例 4.4.1 案例需求 参考 资料/页面原型/tlias智能学习辅助系统/首页.html 文件&#xff0c;浏览器打开&#xff0c;点击页面中的左侧栏的员工管理&#xff0c;如下所示&#xff1a; 需求说明&#xff1a; 制作类似格式的页面 即上面是标题&#xff0c;左侧栏是导航&…

E. Kolya and Movie Theatre

https://codeforces.com/contest/1862/problem/E 容易发现就是维护一个长度至多为m的序列和 减去 i*d&#xff08;i为最后选择看电影的是哪一天&#xff09; 一开始没有把第0天的p是0用上&#xff0c;没想出来 维护非负序列和这里可以用一个set&#xff0c;有点类似于滑动窗口&…

示波器高压探头的操作说明及使用注意事项

操作说明&#xff1a; 连接探头衰减端的地线(鳄鱼夹)到好的接地点或可靠的接地测试端。连接BNC头到示波器的BNC输入端口。选择示波器要求的量程范围。 注意&#xff1a;请务必在连接测试前把高压电源关闭。 注意事项&#xff1a; 请勿将测试设备的接地线从地面接线柱上移开。…