كيف يمكنني قياس المسافة وإنشاء مربع محيط بناءً على نقطتي خط العرض + خط الطول في Java؟

StackOverflow https://stackoverflow.com/questions/120283

سؤال

أريد إيجاد المسافة بين نقطتين مختلفتين.أعلم أنه يمكن تحقيق ذلك من خلال مسافة الدائرة الكبيرة.http://www.meridianworlddata.com/Distance-calculation.asp

بمجرد الانتهاء من ذلك، بالنسبة للنقطة والمسافة، أود العثور على النقطة التي تبعد الشمال وتلك المسافة شرقًا من أجل إنشاء مربع حول النقطة.

هل كانت مفيدة؟

المحلول

لقد حققنا بعض النجاح في استخدام الخريطة المفتوحة لرسم الكثير من البيانات الموضعية.هناك لاتلون بوينت فئة تحتوي على بعض الوظائف الأساسية، بما في ذلك المسافة.

نصائح أخرى

هنا تطبيق 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;
    }

أو يمكنك استخدام SimpleLatLng.تم ترخيص Apache 2.0 واستخدامه في نظام إنتاج واحد أعرفه:مِلكِي.

قصة قصيرة:

كنت أبحث عن مكتبة جغرافية بسيطة ولم أتمكن من العثور على مكتبة تناسب احتياجاتي.ومن يريد كتابة واختبار وتصحيح هذه الأدوات الجغرافية الصغيرة مرارًا وتكرارًا في كل تطبيق؟يجب أن تكون هناك طريقة أفضل!

لذلك، وُلدت SimpleLatLng كوسيلة لتخزين بيانات خطوط الطول والعرض، وإجراء حسابات المسافة، وإنشاء حدود ذات أشكال.

أعلم أنني تأخرت عامين في مساعدة الملصق الأصلي، ولكن هدفي هو مساعدة الأشخاص مثلي الذين يجدون هذا السؤال في البحث.أرغب في أن يستخدمه بعض الأشخاص ويساهمون في اختبار ورؤية هذه الأداة الصغيرة خفيفة الوزن.

للحصول على مسافة أكثر دقة (0.5 مم)، يمكنك أيضًا استخدام تقريب فنسنتي:

/**
 * 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

تصحيح صيغة مسافة هافيرسين ....

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

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

يمكنك استخدام ال مكتبة جافا الجيوديسية لنظام تحديد المواقع, ، ويستخدم صيغ فنسنتي والذي يأخذ في الاعتبار انحناء سطح الأرض.

التنفيذ يسير على النحو التالي:

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. كما أن لديها ترخيصًا مفتوحًا.
  2. ويستخدم مبادئ OOP.
  3. يتمتع بمرونة أكبر لاختيار الشكل الناقص الذي تريد استخدامه.
  4. لديها المزيد من الأساليب للسماح بإجراء حسابات مختلفة في المستقبل.
  5. لقد تم توثيقه جيدًا.

VincentyDistanceCalculator

ستساعدك هذه الطريقة في العثور على المسافة بين الموقع الجغرافي بالكيلومترات.

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

عادةً ما أستخدم MATLAB مع ملف أدوات رسم الخرائط, ، ثم استخدم الكود الموجود في Java الخاص بي باستخدام ماتلاب منشئ JA. يجعل حياتي أسهل بكثير.نظرًا لأن معظم المدارس توفر الوصول المجاني للطلاب، فيمكنك تجربته (أو الحصول على الإصدار التجريبي لإكمال عملك).

بالنسبة لنظام 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[])

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top