76 votes

Comment mesurer une distance et créer une boîte de délimitation à partir de deux points de latitude et de longitude en Java ?

Je veux trouver la distance entre deux points différents. Je sais que cela peut être accompli avec la distance orthodromique. http://www.meridianworlddata.com/Distance-calculation.asp

Une fois que c'est fait, avec un point et une distance, je voudrais trouver le point à cette distance au nord, et à cette distance à l'est afin de créer une boîte autour du point.

1 votes

156voto

Sean Points 3185

Voici une implémentation Java de Haversine formule. Je l'utilise dans un projet pour calculer la distance en miles entre des latitudes et des longitudes.

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

23 votes

Une remarque à ce sujet : la distance sera exprimée en miles (en raison du paramètre earthRadius). Pour d'autres unités, modifiez le rayon de la terre (cf. fr.wikipedia.org/wiki/Earth_radius pour en savoir plus)

0 votes

Y a-t-il une raison pour laquelle vous utilisez des flottants au lieu de doubles ? Si je comprends bien, vous pouvez augmenter la précision de vos résultats en changeant simplement les types de paramètres d'entrée.

0 votes

Il n'est pas non plus nécessaire de calculer deux fois le sinus de la moitié des deltas. Il suffit de le calculer une fois et de le multiplier par lui-même. Cela vaut vraiment la peine dans une boucle serrée.

45voto

JavadocMD Points 1624

Ou vous pouvez utiliser SimpleLatLng . Apache 2.0 sous licence et utilisé dans un seul système de production à ma connaissance : le mien.

Une histoire courte :

Je cherchais une géothèque simple et je n'en ai pas trouvé une qui réponde à mes besoins. Et qui veut écrire, tester et déboguer ces petits outils géographiques encore et encore dans chaque application ? Il doit y avoir une meilleure solution !

C'est ainsi qu'est né SimpleLatLng, un moyen de stocker des données de latitude et de longitude, de calculer des distances et de créer des limites de forme.

Je sais que j'arrive deux ans trop tard pour aider le posteur initial, mais mon objectif est d'aider les personnes qui, comme moi, trouvent cette question lors d'une recherche. J'aimerais que certaines personnes l'utilisent et contribuent aux tests et à la vision de ce petit utilitaire léger.

0 votes

Ceci pourrait m'aider ! L'avez-vous créé ? Utilisez-vous la formule Haversine pour le calcul de la distance ??? J'essaierai de participer si je trouve le temps !

0 votes

Correct, il utilise l'haversine pour les calculs de distance en mettant l'accent sur la rapidité (sans en être obsédé, il faut bien l'admettre) et en utilisant peu de mémoire. Je pense qu'il possède également d'autres propriétés intéressantes de manipulation des nombres, comme le fait de considérer comme égales des coordonnées qui sont "vraiment proches".

21voto

bcash Points 3224

Nous avons eu du succès en utilisant OpenMap pour tracer beaucoup de données positionnelles. Il y a un LatLonPoint qui possède quelques fonctionnalités de base, notamment la distance.

5 votes

Avertissement aux éventuels adoptants : Je viens de rencontrer un GROS problème avec OpenMap ; ils utilisent des flottants en interne pour les lat/lon décimaux, ce qui limite la précision en fonction de la proximité de l'équateur. Ils prévoient de supporter l'option pour les doubles avec leurs classes OMGraphic à partir de la version 4.7, mais la version stable actuelle n'est que 4.6.5 (en mars 2010). Source : openmap.bbn.com/mailArchives/openmap-users/2006-01/4522.html

0 votes

Notez également que l'actuel contrat de licence du logiciel OpenMap openmap.bbn.com/license.html a été jugé non libre. web.archiveorange.com/archive/v/XyE55YoXwS3lME936I0U Des discussions avec BBN ont eu lieu pour changer les licences mais rien n'a encore été fait.

3 votes

Cette réponse est maintenant périmée puisque les deux liens sont hors ligne.

11voto

Victor P. Points 337

Pour une distance plus précise (0,5 mm), vous pouvez également utiliser l'approximation de 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;
}

Ce code a été librement adapté de http://www.movable-type.co.uk/scripts/latlong-vincenty.html

7voto

Greg Hewgill Points 356191

Une recherche rapide sur Google donne GeoTools qui a probablement le type de fonctions que vous recherchez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X