java - 如何在Java中基于两个纬度+经度点测量距离并创建边界框?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/120283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:30:05  来源:igfitidea点击:

How can I measure distance and create a bounding box based on two latitude+longitude points in Java?

javageocodinglatitude-longitude

提问by will

I am wanting to find the distance between two different points. This I know can be accomplished with the great circle distance. http://www.meridianworlddata.com/Distance-calculation.asp

我想找到两个不同点之间的距离。我知道这可以通过大圆距离来完成。 http://www.meridianworlddata.com/Distance-calculation.asp

Once done, with a point and distance I would like to find the point that distance north, and that distance east in order to create a box around the point.

完成后,通过一个点和距离,我想找到距离北方和东方距离的点,以便在该点周围创建一个框。

采纳答案by Brendan Cashman

We've had some success using OpenMapto plot a lot of positional data. There's a LatLonPointclass that has some basic functionality, including distance.

我们在使用OpenMap绘制大量位置数据方面取得了一些成功。有一个LatLonPoint类具有一些基本功能,包括距离。

回答by Sean

Here is a Java implementation of Haversineformula. I use this in a project to calculate distance in miles between lat/longs.

这是Haversine公式的Java实现。我在一个项目中使用它来计算纬度/经度之间的距离(以英里为单位)。

public static double distFrom(double lat1, double lng1, double lat2, double lng2) {
    double earthRadius = 3958.75; // miles (or 6371.0 kilometers)
    double dLat = Math.toRadians(lat2-lat1);
    double dLng = Math.toRadians(lng2-lng1);
    double sindLat = Math.sin(dLat / 2);
    double sindLng = Math.sin(dLng / 2);
    double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
            * Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double dist = earthRadius * c;

    return dist;
    }

回答by JavadocMD

Or you could use SimpleLatLng. Apache 2.0 licensed and used in one production system that I know of: mine.

或者你可以使用SimpleLatLng。Apache 2.0 在我所知道的一个生产系统中获得许可和使用:我的。

Short story:

短篇故事:

I was searching for a simple geo library and couldn't find one to fit my needs. And who wants to write and test and debug these little geo tools over and over again in every application? There's got to be a better way!

我正在寻找一个简单的地理图书馆,但找不到适合我的需求。谁愿意在每个应用程序中一遍又一遍地编写、测试和调试这些小地理工具?必须有更好的方法!

So SimpleLatLng was born as a way to store latitude-longitude data, do distance calculations, and create shaped boundaries.

所以 SimpleLatLng 的诞生是为了存储经纬度数据、进行距离计算和创建形状边界。

I know I'm two years too late to help the original poster, but my aim is to help the people like me who find this question in a search. I would love to have some people use it and contribute to the testing and vision of this little lightweight utility.

我知道我已经晚了两年无法帮助原始海报,但我的目标是帮助像我这样在搜索中找到这个问题的人。我希望有人使用它并为这个小型轻量级实用程序的测试和愿景做出贡献。

回答by Oscar Salguero

You can use the Java Geodesy Library for GPS, it uses the Vincenty's formulaewhich takes account of the earths surface curvature.

您可以使用用于 GPSJava Geodesy 库,它使用Vincenty 公式,该公式考虑了地球表面曲率。

Implementation goes like this:

实现是这样的:

import org.gavaghan.geodesy.*;
...
GeodeticCalculator geoCalc = new GeodeticCalculator();
Ellipsoid reference = Ellipsoid.WGS84;
GlobalPosition pointA = new GlobalPosition(latitude, longitude, 0.0);
GlobalPosition userPos = new GlobalPosition(userLat, userLon, 0.0);
double distance = geoCalc.calculateGeodeticCurve(reference, userPos, pointA).getEllipsoidalDistance();

The resulting distance is in meters.

结果距离以米为单位。

回答by Victor P.

For a more accurate distance (0.5mm) you can also use the Vincenty approximation:

要获得更准确的距离 (0.5mm),您还可以使用 Vincenty 近似值:

/**
 * Calculates geodetic distance between two points specified by latitude/longitude using Vincenty inverse formula
 * for ellipsoids
 * 
 * @param lat1
 *            first point latitude in decimal degrees
 * @param lon1
 *            first point longitude in decimal degrees
 * @param lat2
 *            second point latitude in decimal degrees
 * @param lon2
 *            second point longitude in decimal degrees
 * @returns distance in meters between points with 5.10<sup>-4</sup> precision
 * @see <a href="http://www.movable-type.co.uk/scripts/latlong-vincenty.html">Originally posted here</a>
 */
public static double distVincenty(double lat1, double lon1, double lat2, double lon2) {
    double a = 6378137, b = 6356752.314245, f = 1 / 298.257223563; // WGS-84 ellipsoid params
    double L = Math.toRadians(lon2 - lon1);
    double U1 = Math.atan((1 - f) * Math.tan(Math.toRadians(lat1)));
    double U2 = Math.atan((1 - f) * Math.tan(Math.toRadians(lat2)));
    double sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
    double sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);

    double sinLambda, cosLambda, sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM;
    double lambda = L, lambdaP, iterLimit = 100;
    do {
        sinLambda = Math.sin(lambda);
        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; // co-incident points
        cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
        sigma = Math.atan2(sinSigma, cosSigma);
        sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
        cosSqAlpha = 1 - sinAlpha * sinAlpha;
        cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
        if (Double.isNaN(cos2SigmaM))
            cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6)
        double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
        lambdaP = lambda;
        lambda = L + (1 - C) * f * sinAlpha
                * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * 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 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
    double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
    double deltaSigma = B
            * sinSigma
            * (cos2SigmaM + B
                    / 4
                    * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM
                            * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
    double dist = b * A * (sigma - deltaSigma);

    return dist;
}

This code was freely adapted from http://www.movable-type.co.uk/scripts/latlong-vincenty.html

此代码是从http://www.movable-type.co.uk/scripts/latlong-vincenty.html免费改编的

回答by Matthew Hager

Corrected Haversine Distance formula....

修正Haversine距离公式....

public static double HaverSineDistance(double lat1, double lng1, double lat2, double lng2) 
{
    // mHager 08-12-2012
    // http://en.wikipedia.org/wiki/Haversine_formula
    // Implementation

    // convert to radians
    lat1 = Math.toRadians(lat1);
    lng1 = Math.toRadians(lng1);
    lat2 = Math.toRadians(lat2);
    lng2 = Math.toRadians(lng2);

    double dlon = lng2 - lng1;
    double dlat = lat2 - lat1;

    double a = Math.pow((Math.sin(dlat/2)),2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2),2);

    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    return EARTH_RADIUS * c;
}   

回答by Chetan Rawal

I typically use MATLAB with the Mapping Toolbox, and then use the code in my Java using MATLAB Builder JA.It makes my life a lot simpler. Given most schools have it for free student access, you can try it out (or get the trial version to get over your work).

我通常将 MATLAB 与Mapping Toolbox 一起使用,然后使用MATLAB Builder JA在我的 Java 中使用代码它让我的生活变得简单了很多。鉴于大多数学校都提供免费的学生访问权限,您可以尝试一下(或获取试用版来完成您的工作)。

回答by Rija Ramampiandra

http://www.movable-type.co.uk/scripts/latlong.html

http://www.movable-type.co.uk/scripts/latlong.html

public static Double distanceBetweenTwoLocationsInKm(Double latitudeOne, Double longitudeOne, Double latitudeTwo, Double longitudeTwo) {
        if (latitudeOne == null || latitudeTwo == null || longitudeOne == null || longitudeTwo == null) {
            return null;
        }

        Double earthRadius = 6371.0;
        Double diffBetweenLatitudeRadians = Math.toRadians(latitudeTwo - latitudeOne);
        Double diffBetweenLongitudeRadians = Math.toRadians(longitudeTwo - longitudeOne);
        Double latitudeOneInRadians = Math.toRadians(latitudeOne);
        Double latitudeTwoInRadians = Math.toRadians(latitudeTwo);
        Double a = Math.sin(diffBetweenLatitudeRadians / 2) * Math.sin(diffBetweenLatitudeRadians / 2) + Math.cos(latitudeOneInRadians) * Math.cos(latitudeTwoInRadians) * Math.sin(diffBetweenLongitudeRadians / 2)
                * Math.sin(diffBetweenLongitudeRadians / 2);
        Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return (earthRadius * c);
    }

回答by mikeho

I know that there are many answers, but in doing some research on this topic, I found that most answers here use the Haversine formula, but the Vincenty formula is actually more accurate. There was one post that adapted the calculation from a Javascript version, but it's very unwieldy. I found a version that is superior because:

我知道有很多答案,但是在对这个主题进行一些研究时,我发现这里的大多数答案都使用Haversine公式,但Vincenty公式实际上更准确。有一篇文章改编了 Javascript 版本的计算,但它非常笨拙。我发现了一个更好的版本,因为:

  1. It also has an open license.
  2. It uses OOP principles.
  3. It has greater flexibility to choose the ellipsoid you want to use.
  4. It has more methods to allow for different calculations in the future.
  5. It is well documented.
  1. 它也有一个开放的许可证。
  2. 它使用 OOP 原则。
  3. 选择要使用的椭球具有更大的灵活性。
  4. 它有更多的方法来允许将来进行不同的计算。
  5. 这是有据可查的。

VincentyDistanceCalculator

Vincenty 距离计算器

回答by Ad Infinitum

This method would help you find the distance between to geographic location in km.

此方法将帮助您找到以公里为单位的地理位置之间的距离。

private double getDist(double lat1, double lon1, double lat2, double lon2)
{
    int R = 6373; // radius of the earth in kilometres
    double lat1rad = Math.toRadians(lat1);
    double lat2rad = Math.toRadians(lat2);
    double deltaLat = Math.toRadians(lat2-lat1);
    double deltaLon = Math.toRadians(lon2-lon1);

    double a = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
            Math.cos(lat1rad) * Math.cos(lat2rad) *
            Math.sin(deltaLon/2) * Math.sin(deltaLon/2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    double d = R * c;
    return d;
}