web-dev-qa-db-ja.com

Javaで2つの緯度+経度ポイントに基づいて距離を測定し、境界ボックスを作成するにはどうすればよいですか?

2つの異なるポイント間の距離を見つけたいです。これは、大円距離で達成できることを知っています。 http://www.meridianworlddata.com/Distance-calculation.asp

一度行ったら、ポイントと距離を使用して、ポイントの周りにボックスを作成するために、その距離を北に、その距離を東に見つけたいと思います。

75
will

OpenMap を使用して多くの位置データをプロットすることに成功しました。 LatLonPoint クラスがあり、距離を含むいくつかの基本的な機能があります。

21
Brendan Cashman

Java Haversine 式の実装です。これをプロジェクトで使用して、緯度/経度間の距離をマイルで計算します。

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;
    }
147
Sean

または、 SimpleLatLng を使用できます。 Apache 2.0は、私の知っている1つの実稼働システムでライセンスされ、使用されています。

ショートストーリー:

シンプルなジオライブラリを探していましたが、自分のニーズに合ったライブラリを見つけることができませんでした。そして、これらの小さなジオツールをすべてのアプリケーションで何度も何度も作成、テスト、デバッグしたいのは誰ですか?もっと良い方法があるはずです!

そのため、SimpleLatLngは、緯度経度データを保存し、距離を計算し、形状の境界を作成する方法として生まれました。

私は元のポスターを手伝うには2年遅すぎることを知っていますが、私の目的は、この質問を検索で見つけた私のような人々を助けることです。一部の人々にそれを使用してもらい、この小さな軽量ユーティリティのテストとビジョンに貢献してもらいたいです。

44
JavadocMD

より正確な距離(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;
}

このコードは http://www.movable-type.co.uk/scripts/latlong-vincenty.html から自由に変更されました

11
Victor P.

Haversine Distanceの式を修正しました。

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;
}   
6
Matthew Hager

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);
    }
2

私は多くの答えがあることを知っていますが、このトピックに関するいくつかの研究を行うと、ほとんどの答えはHaversine式を使用しますが、Vincenty式は実際にはより正確であることがわかりました。 Javascriptバージョンからの計算を採用した記事が1つありましたが、非常に扱いにくいです。優れたバージョンを見つけました:

  1. また、オープンライセンスもあります。
  2. OOP原則を使用します。
  3. 使用する楕円体を選択する柔軟性が高くなっています。
  4. 将来的に異なる計算を可能にするためのメソッドが増えました。
  5. 十分に文書化されています。

VincentyDistanceCalculator

1
mikeho

この方法は、地理的な場所までの距離を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;
}
1
Ad Infinitum

GPS用Java Geodesy Library を使用できます。これは Vincentyの式 を使用し、地球表面の曲率を考慮します。

実装は次のようになります。

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();

結果の距離はメートル単位です。

1
Oscar S.

Androidには、簡単なアプローチがあります。

 public static float getDistanceInMeter(LatLng start, LatLng end) { 
    float[] results = new float[1];
    Location.distanceBetween(start.latitude, start.longitude, end.latitude, end.longitude, results);
    return results[0];

}

;

https://developer.Android.com/reference/Android/location/Location#distanceBetween(lat1、lng1、lat2、lng2、output [])

0
makata

通常、MATLABで Mapping Toolbox を使用してから、Java using MATLAB Builder JA。 を使用して、私の人生をほとんどの学校が無料で生徒にアクセスできるようになっているので、試してみることができます(または試用版を入手して仕事をやり直してください)。

0
Chetan Rawal

Haversine式のKotlinバージョン。返される結果はメートル単位です。テスト済み https://www.vcalc.com/wiki/vCalc/Haversine+-+Distance

const val EARTH_RADIUS_IN_METERS = 6371007.177356707

fun distance(lat1: Double, lng1: Double, lat2: Double, lng2: Double): Double {
    val latDiff = Math.toRadians(abs(lat2 - lat1))
    val lngDiff = Math.toRadians(abs(lng2 - lng1))
    val a = sin(latDiff / 2) * sin(latDiff / 2) +
        cos(Math.toRadians(lat1)) * cos(Math.toRadians(lat2)) *
        sin(lngDiff / 2) * sin(lngDiff / 2)
    val c = 2 * atan2(sqrt(a), sqrt(1 - a))
    return EARTH_RADIUS_IN_METERS * c
}
0
Binakot