2008-09-23 1 views
74

Я хочу найти расстояние между двумя разными точками. Это, как я знаю, может быть достигнуто с большой дистанцией круга. http://www.meridianworlddata.com/Distance-calculation.aspКак измерить расстояние и создать ограничивающий прямоугольник на основе двух точек широты + долготы в Java?

После того, как сделано, с точкой и расстоянием, я хотел бы найти точку, расположенную на север, и это расстояние на восток, чтобы создать коробку вокруг точки.

+1

относятся к этому блогу http://xebee.xebia.in/2010/10/28/working-with-geolocations/ – Robin 2010-11-01 10:29:13

ответ

20

У нас был некоторый успех, используя OpenMap, чтобы построить много позиционных данных. Существует класс LatLonPoint, который имеет некоторые базовые функции, включая расстояние.

+5

Предупреждение о возможных усыновителей: Я просто столкнулся с большой проблемой с OpenMap; они используют внутренние поплавки для decimal lat/lon, что ограничивает точность, зависящую от того, насколько близка к экватору. Они планируют поддержать вариант удвоения с их классами OMGraphic, начиная с версии 4.7, но текущая стабильная версия - только 4.6.5 (по состоянию на март 2010 года). Источник: http://openmap.bbn.com/mailArchives/openmap-users/2006-01/4522.html – Marc 2010-03-30 18:13:31

+0

Также обратите внимание, что действующее Лицензионное соглашение на программное обеспечение OpenMap http://openmap.bbn.com/license.html были признаны несвободными. http://web.archiveorange.com/archive/v/XyE55YoXwS3lME936I0U Некоторые обсуждения с BBN произошли, чтобы сменить лицензии, но ничего еще не произошло. – 2011-04-07 13:51:59

+0

Ссылка LatLonPoint не работает – Petriborg 2012-04-26 20:14:31

7

Быстрый поиск Google включает GeoTools, который, вероятно, имеет вид функций, которые вы ищете.

140

Вот реализация 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; 
    } 
43

Или вы можете использовать SimpleLatLng. Apache 2.0 лицензирован и используется в одной производственной системе, о которой я знаю: мой.

Краткая история:

Я искал простую библиотеку гео и не мог найти, чтобы соответствовать моим потребностям. И кто хочет писать и тестировать и отлаживать эти небольшие гео-инструменты снова и снова в каждом приложении? Там должен быть лучший способ!

So SimpleLatLng родился как способ хранения данных долготы широты, выполнения расчетов расстояний и создания фасонных границ.

Я знаю, что я слишком поздно, чтобы помочь оригинальному плакату, но моя цель - помочь таким людям, как я, которые находят этот вопрос в поиске. Я хотел бы, чтобы некоторые люди использовали его и способствовали тестированию и видению этой небольшой облегченной утилиты.

1

Вы можете использовать Java Geodesy Library for GPS, он использует Vincenty's formulae, который учитывает кривизну поверхности земли.

Реализация выглядит следующим образом:

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

Полученное расстояние в метрах.

11

Для более точного расстояния (0.5мм), вы можете также использовать приближение 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

6

Исправленная формула 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; 
} 
0

Я обычно использую MATLAB с Mapping Toolbox, а затем использовать код в моей Java с помощью MATLAB Builder JA. Это делает мою жизнь намного проще. Учитывая, что в большинстве школ есть бесплатный доступ для студентов, вы можете попробовать (или получить пробную версию, чтобы получить доступ к вашей работе).

2

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

Я знаю, что есть много ответов, но при этом некоторые исследования по этой теме, я обнаружил, что большинство ответов здесь используют формулу Haversine, но формула Vincenty на самом деле более точным. Было одно сообщение, которое адаптировало расчет из версии Javascript, но это очень громоздко. Я нашел версию, которая превосходит, потому что:

  1. У этого также есть открытая лицензия.
  2. В нем используются принципы ООП.
  3. Он обладает большей гибкостью для выбора эллипсоида, который вы хотите использовать.
  4. У этого есть больше методов, позволяющих в будущем проводить различные вычисления.
  5. Это хорошо документировано.

VincentyDistanceCalculator

1

Этот метод поможет вам найти расстояние между географическим положением в км.

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; 
} 
Смежные вопросы