كيف يمكنني العثور على Lat / Long هو X KM شمالا من Lat / Lax المعطى؟

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

  •  13-09-2019
  •  | 
  •  

سؤال

لدي بعض رمز C # الذي يولد خرائط جوجل. يبدو أن هذه الرموز في جميع النقاط التي أحتاج إليها على الخريطة، ثم أعمل حدود المستطيل لتضمين تلك النقاط. ثم يمر هذه الحدود إلى Google Maps API لتعيين مستوى التكبير بشكل مناسب لإظهار جميع النقاط على الخريطة.

هذا الرمز يعمل بشكل جيد ولكن لدي شرط جديد.

قد يكون لأحد النقاط دقيقة مرتبطة به. إذا كان هذا هو الحال، فأرسم دائرة حول النقطة مع تعيين دائرة نصف قطرها إلى القيمة الدقة. مرة أخرى، يعمل هذا بشكل جيد ولكن التحقق من حدودي لا يفعل الآن ما أريده القيام به. أريد أن يكون مربع التحديد تشمل الدائرة كاملة.

يتطلب ذلك خوارزمية أن تأخذ نقطة س وحساب النقطة Y التي ستكون Z متر شمال X وكذلك Z متر جنوب X.

هل لدى أي شخص هذه الخوارزمية، ويفضل أن يكون ذلك في C #. لقد وجدت خوارزمية عامة هنا ولكن يبدو أنني لم تنفذ هذا بشكل صحيح كما الإجابات التي أحصل عليها هي 1000s من KMFF.

هذا هو المثال العام

Lat/lon given radial and distance

A point {lat,lon} is a distance d out on the tc radial from point 1 if:

     lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
     IF (cos(lat)=0)
        lon=lon1      // endpoint a pole
     ELSE
        lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
     ENDIF

وهذا هو بلدي الترجمة C #.

  // Extend a Point North/South by the specified distance
    public static Point ExtendPoint(Point _pt, int _distance, int _bearing )
    {
        Decimal lat = 0.0;
        Decimal lng = 0.0;

        lat = Math.Asin(Math.Sin(_pt.Lat) * Math.Cos(_distance) + Math.Cos(_pt.Lat) * 
            Math.Sin(_distance) * Math.Cos(_bearing));

         if (Math.Cos(lat) == 0)
         {
            lng = _pt.Lng;      // endpoint a pole
         }
         else 
         {
             lng = (
                 (_pt.Lng - Math.Asin(Math.Sin(_bearing) * Math.Sin(_distance) / Math.Cos(lat)) 
                 + Math.PI) % (2 * Math.PI)) - Math.PI;
         }

         ret = new Point(lat,lng);
         return ret;
    }

أنا أدعو هذه الوظيفة إلى تحمل 0 لحساب الموضع الشمالي الجديد وقيمة 180 لحساب الموضع الجنوبي الجديد.

هل يمكن لأي شخص أن يرى ما فعلته خطأ أو ربما توفير خوارزمية عمل معروفة؟

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

المحلول

إذا كان لديك خطوط خطوط وطويلة معينة، فيمكنك حساب خط الطول والعرض الصحيح لتغيير X كم في خط العرض مثل ذلك:

new-lat = ((old-km-north + x-km-change)/40,075) * 360)
           ^ is the ratio of the                  ^ times the ratio of the circle
           of the earth the change                by 360 to get the total ratio 
           covers.                                covered in degrees.

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

new-long = ((old-km-east + x-km-change)/40,075) * 360)
           ^ is the ratio of the                  ^ times the ratio of the circle
           of the earth the change                by 360 to get the total ratio 
           covers.                                covered in degrees.

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

تحرير: كما هو مطلوب من قبل Skizz 40،075 يحتاج إلى تعديل على محيط الأرض في أي خطوط خط عرضية معينة باستخدام 2.pi.r.cos (lat) أو 40074.cos (lat)

نصائح أخرى

لدي جزء مشابه جدا من التعليمات البرمجية. لقد حصلت لي نتائج دقيقة جدا بالمقارنة مع تنفيذ آخر.

أعتقد أن المشكلة فيك هي أنك تستخدم "المسافة" كما المسافة الخطية بالأمتار بدلا من المسافة الزاوية في الراديان.

/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static LatLonAlt CalculateDerivedPosition(LatLonAlt source, double range, double bearing)
{
    double latA = source.Latitude * UnitConstants.DegreesToRadians;
    double lonA = source.Longitude * UnitConstants.DegreesToRadians;
    double angularDistance = range / GeospatialConstants.EarthRadius;
    double trueCourse = bearing * UnitConstants.DegreesToRadians;

    double lat = Math.Asin(
        Math.Sin(latA) * Math.Cos(angularDistance) + 
        Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));

    double dlon = Math.Atan2(
        Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA), 
        Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));

    double lon = ((lonA + dlon + Math.PI) % UnitConstants.TwoPi) - Math.PI;

    return new LatLonAlt(
        lat * UnitConstants.RadiansToDegrees, 
        lon * UnitConstants.RadiansToDegrees, 
        source.Altitude);
}

أين

public const double EarthRadius = 6378137.0;   //  WGS-84 ellipsoid parameters

واللاللونالت في درجات / متر (يحدث التحويل داخليا). ضبط حسب الحاجة.

أفترض أنه يمكنك معرفة ما قيمة UnitConstants.DegreesToRadians هو :)

للأشخاص الكسول، (مثلي؛)) حلا للنسخ معجون، إصدار إيريتش ميرابال مع تغييرات طفيفة للغاية:

using System.Device.Location; // add reference to System.Device.dll
public static class GeoUtils
{
    /// <summary>
    /// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
    /// This methods uses simple geometry equations to calculate the end-point.
    /// </summary>
    /// <param name="source">Point of origin</param>
    /// <param name="range">Range in meters</param>
    /// <param name="bearing">Bearing in degrees</param>
    /// <returns>End-point from the source given the desired range and bearing.</returns>
    public static GeoCoordinate CalculateDerivedPosition(this GeoCoordinate source, double range, double bearing)
    {
        var latA = source.Latitude * DegreesToRadians;
        var lonA = source.Longitude * DegreesToRadians;
        var angularDistance = range / EarthRadius;
        var trueCourse = bearing * DegreesToRadians;

        var lat = Math.Asin(
            Math.Sin(latA) * Math.Cos(angularDistance) +
            Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));

        var dlon = Math.Atan2(
            Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
            Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));

        var lon = ((lonA + dlon + Math.PI) % (Math.PI*2)) - Math.PI;

        return new GeoCoordinate(
            lat * RadiansToDegrees,
            lon * RadiansToDegrees,
            source.Altitude);
    }

    private const double DegreesToRadians = Math.PI/180.0;
    private const double RadiansToDegrees = 180.0/ Math.PI;
    private const double EarthRadius = 6378137.0;
}

الاستعمال:

[TestClass]
public class CalculateDerivedPositionUnitTest
{
    [TestMethod]
    public void OneDegreeSquareAtEquator()
    {
        var center = new GeoCoordinate(0, 0);
        var radius = 111320;
        var southBound = center.CalculateDerivedPosition(radius, -180);
        var westBound = center.CalculateDerivedPosition(radius, -90);
        var eastBound = center.CalculateDerivedPosition(radius, 90);
        var northBound = center.CalculateDerivedPosition(radius, 0);

        Console.Write($"leftBottom: {southBound.Latitude} , {westBound.Longitude} rightTop: {northBound.Latitude} , {eastBound.Longitude}");
    }
}

لست متأكدا مما إذا كنت أفتقد شيئا هنا، لكنني أعتقد أنه يمكن إعادة صياغة السؤال كما، "لدي نقطة لات / لون، وأريد أن أجد النقطة X متر شمالا و X متر جنوب هذه النقطة. "

إذا كان هذا هو السؤال فأنت لا تحتاج إلى العثور على خط خط جديد (مما يجعل الأمور أكثر بساطة)، فأنت بحاجة فقط إلى خط عرض جديد. هناك درجة من خط العرض ما يقرب من 60 ميلا بحريا في أي مكان على الأرض، وبلغ ميل بحري 1852 مترا. لذلك، للطي الجديدة X متر الشمال والجنوب:

north_lat = lat + x / (1852 * 60)
north_lat = min(north_lat, 90)

south_lat = lat - x / (1852 * 60)
south_lat = max(south_lat, -90)

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

http://en.wikipedia.org/wiki/latitudition#degree_length.

هناك مشاكل مع المعادلات موقع إد ويليام رائع... لكنني لم تحللهم لمعرفة السبب.

معادلة ثالثة ذلك وجدت هنا يبدو أن تعطي النتائج المناسبة.

فيما يلي حالة الاختبار في PHP ... المعادلة الثالثة صحيحة، أول اثنين يعطي قيما غير صحيحة بعرض الطول.

<?php
            $lon1 = -108.553412; $lat1 = 35.467155; $linDistance = .5; $bearing = 170;
            $lon1 = deg2rad($lon1); $lat1 = deg2rad($lat1);
            $distance = $linDistance/6371;  // convert dist to angular distance in radians
            $bearing = deg2rad($bearing);

            echo "lon1: " . rad2deg($lon1) . " lat1: " . rad2deg($lat1) . "<br>\n";

// doesn't work
            $lat2 = asin(sin($lat1) * cos($distance) + cos($lat1) * sin($distance) * cos($bearing) );
            $dlon = atan2(sin($bearing) * sin($distance) * cos($lat1), cos($distance) - sin($lat1) * sin($lat2));
            $lon2 = (($lon1 - $dlon + M_PI) % (2 * M_PI)) - M_PI;  // normalise to -180...+180

            echo "lon2: " . rad2deg($lon2) . " lat2: " . rad2deg($lat2) . "<br>\n";

// same results as above
            $lat3 = asin( (sin($lat1) * cos($distance)) + (cos($lat1) * sin($distance) * cos($bearing)));
            $lon3 = (($lon1 - (asin(sin($bearing) * sin($distance) / cos($lat3))) + M_PI) % (2 * M_PI)) - M_PI;

            echo "lon3: " . rad2deg($lon3) . " lat3: " . rad2deg($lat3) . "<br>\n";

// gives correct answer... go figure
            $lat4 = asin(sin($lat1) * cos($linDistance/6371) + cos($lat1) * sin($linDistance/6371) * cos($bearing) );
            $lon4 = $lon1 + atan2( (sin($bearing) * sin($linDistance/6371) * cos($lat1) ), (cos($linDistance/6371) - sin($lat1) * sin($lat2)));

            echo "lon4: " . rad2deg($lon4) . " lat4: " . rad2deg($lat4) . "<br>\n";
?>

لاحظ أنني تلقيت عن طريق البريد الإلكتروني من المؤلف (ED Williams) من المعادلات الأولى:

من "ملاحظات التنفيذ":

ملاحظة على وظيفة وزارة الدفاع. يبدو أن هذا ينفذ بشكل مختلف بلغات مختلفة، مع اتخاذ اتفاقيات مختلفة حول ما إذا كانت علامة النتيجة تتبع علامة المقسوم أو الأرباح. (نريد أن نتبع علامة المقسوم أو أن تكون الإقليدية. C's FMOD و Java٪ لا يعملون.) في هذه الوثيقة، وزارة الدفاع (Y، X) هو الباقي على تقسيم Y بواسطة X ودائما يكمن دائما في النطاق 0 <= وزارة الدفاع <x. على سبيل المثال: وزارة الدفاع (2.3،2) = 0.3 و mod (-2.3،2) = 1.7

إذا كان لديك وظيفة أرضية (int in Excel)، فستظهر الكلمة (x) = "أكبر عدد صحيح أقل من أو يساوي X" على سبيل المثال الكلمة (-2.3) = - 3 والأرضيات (2.3) = 2

mod(y,x) = y - x*floor(y/x)

يجب أن تعمل ما يلي في غياب وظيفة أرضية - بغض النظر عما إذا كان "int" باقتطاع أو جولات إلى أسفل:

mod=y - x * int(y/x)
if ( mod < 0) mod = mod + x

PHP يشبه FMOD في C وهل "خطأ" لأغراضي.

إنه أكثر دقة إذا قمت أولا بتثبيتها utm ثم تحقق المسافة.

أتمنى أن يساعدك هذا

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