الإحداثيات الجغرافية المكانية والمسافة بالكيلومترات

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

سؤال

هذه متابعة هذا السؤال.

يبدو أنني عالق في هذا. في الأساس، أحتاج إلى تحويل جيئة وذهابا للإشارة إلى الإحداثيات إما في نظام الدرجات القياسية أو عن طريق قياس مسافة شمال من القطب الجنوبي على طول خط التاريخ الدولي، ثم بدءا من هذه النقطة في التاريخ خط. للقيام بذلك (بالإضافة إلى بعض أشكال القياس المسافة أكثر عمومية)، لدي طريقة واحدة لتحديد المسافة بين نقطتين Lat / Lat / Lat، وطريقة أخرى تأخذ نقطة Lat / Lon، عنوان وعائدات نقطة LAT / LON في نهاية هذه الدورة.

فيما يلي الطرق الثابتة التي حددتها:

/* Takes two lon/lat pairs and returns the distance between them in kilometers.
*/
public static double distance (double lat1, double lon1, double lat2, double lon2) {
    double theta = toRadians(lon1-lon2);
    lat1 = toRadians(lat1);
    lon1 = toRadians(lon1);
    lat2 = toRadians(lat2);
    lon2 = toRadians(lon2);

    double dist = sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(theta);
    dist = toDegrees(acos(dist)) * 60 * 1.1515 * 1.609344 * 1000;

    return dist;
}

/* endOfCourse takes a lat/lon pair, a heading (in degrees clockwise from north), and a distance (in kilometers), and returns
 * the lat/lon pair that would be reached by traveling that distance in that direction from the given point.
 */
public static double[] endOfCourse (double lat1, double lon1, double tc, double dist) {
    double pi = Math.PI;
    lat1 = toRadians(lat1);
    lon1 = toRadians(lon1);
    tc = toRadians(tc);
    double dist_radians = toRadians(dist / (60 * 1.1515 * 1.609344 * 1000));
    double lat = asin(sin(lat1) * cos(dist_radians) + cos(lat1) * sin(dist_radians) * cos(tc));
    double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat));
    double lon = ((lon1-dlon + pi) % (2*pi)) - pi;
    double[] endPoint = new double[2];
    endPoint[0] = lat; endPoint[1] = lon;
    return endPoint;
}

وهنا هي الوظيفة التي أستخدمها لاختبارها:

public static void main(String args[]) throws java.io.IOException, java.io.FileNotFoundException {
    double distNorth = distance(0.0, 0.0, 72.0, 0.0);
    double distEast = distance(72.0, 0.0, 72.0, 31.5);
    double lat1 = endOfCourse(0.0, 0.0, 0.0, distNorth)[0];
    double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1];
    System.out.println("end at: " + lat1 + " / " + lon1);
    return;
}

يجب أن تكون قيم "النهاية في" appx. 72.0 / 31.5. ولكن بدلا من ذلك، أحصل على ما يقرب من 1.25 / 0.021.

أفترض أنني يجب أن أفتقد شيئا غبيا أو نسيان تحويل الوحدات في مكان ما أو شيء ما ... أي مساعدة سيكون موضع تقدير كبير!

التحديث 1:

لقد كتبت (بشكل صحيح) وظيفة المسافة للعودة عداد، لكنني كتبت كيلومترات في التعليقات عن طريق الخطأ ... أي بالطبع حيرة مني عندما عدت إليها اليوم. على أي حال، الآن تم إصلاحه، لقد قمت بإصلاح خطأ العوملة في طريقة EndOfcourse، وأدركت أيضا أنني نسيت تحويلها إلى درجات من الرضيات في هذه الطريقة أيضا. على أي حال: في حين أن يبدو أنني أحصل الآن على رقم خط العرض الصحيح (71.99 ...)، فإن رقم الطول هو الطريق خارج (أحصل على 3.54 بدلا من 11.5).

تحديث 2:كان لدي خطأ مطبعي في الاختبار، كما ذكر أدناه. لقد تم إصلاحه الآن في التعليمات البرمجية. ومع ذلك، لا يزال عدد الطول هو الخطأ: أحصل الآن على -11.34 بدلا من 11.5. أعتقد أنه يجب أن يكون هناك خطأ في هذه الخطوط:

double dlon = atan2(sin(tc) * sin(dist_radians) * cos(lat1), cos(dist_radians) - sin(lat1) * sin(lat));
double lon = ((lon1-dlon + pi) % (2*pi)) - pi;
هل كانت مفيدة؟

المحلول

لديك حالة خطيرة من الأرقام السحرية في التعليمات البرمجية. التعبير:

 (60 * 1.1515 * 1.609344 * 1000)

يظهر مرتين، ولكن ليس هناك الكثير من التفسير لذلك. مع بعض المساعدة: 1.609344 هو عدد الكيلومترات في ميل؛ 60 هو عدد الدقائق في درجة؛ 1000 هو عدد الأمتار في كيلومتر واحد؛ و 1.1515 هو عدد الأميال الأساسية في ميل بحري (شكرا، دانم). ميل بحري واحد هو طول دقيقة واحدة من خط العرض في خط الاستواء.

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

أول صيغة - تحويل بين اثنين من أزواج خطوط الطول والعرض - أمر غريب. تحتاج كل من Delta-Lat (λλ) و Delta-Lon (δφ) لفرز الإجابة. علاوة على ذلك، المسافة بين الأزواج:

(60° N, 30° W), (60° N, 60° W)
(60° N, 60° W), (60° N, 90° W)

يجب أن تكون هي نفسها - لكنني متأكد من أن رمزك ينتج إجابات مختلفة.

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

[... الوقت يمر ... تفريغ القيام به ...]

إعطاء مثلث كروي مع الزوايا أ, ب, جيم في القمم والجانبين أ, ب, جيم مقابل تلك القمم (أي جانب أ انه من ب ل جيم, ، إلخ)، صيغة جيب التمام هي:

cos a = cos b . cos c + sin b . sin c . cos A

تطبيق هذا على المشكلة، يمكننا الاتصال بالنقطتين المعطى ب و جيم, ، ونحن نخلق مثلث كروي أيمن مع زاوية اليمين في أ.

ASCII الفن في أسوأ الأسوأ:

                  + C
                 /|
                / |
            a  /  | b
              /   |
             /    |
            /     |
         B +------+ A
              c

الجانب جيم يساوي الفرق في خط الطول؛ الجانب ب يساوي الفرق في خط العرض؛ الزاوية أ هو 90 درجة، لذلك كوس أ = 0. لذلك، أعتقد معادلة أ يكون:

cos a = cos Δλ . cos Δφ + sin Δλ . sin Δφ . cos 90°

a = arccos (cos Δλ . cos Δφ)

الزاوية أ ثم يتم بعد ذلك تحويلها إلى مسافة مضرب عن طريق دائرة نصف قطرها الأرض. بدلا من ذلك، معين أ في درجات (وفقدان درجة)، فهناك 60 ميلا بحري إلى حد ما، وبالتالي 60 * 1.1515 أميال قانونية، و 60 * 1.1515 * 1.609344 إلى حد ما. ما لم تكن تريد المسافة بالأمتار، لا أرى حاجة لعامل 1000.

بول تومبلين يشير إلى مكونات الطيران V1.44. كمصدر للمعادلة - وبالفعل، هناك، جنبا إلى جنب مع نسخة مستقرة عديمة عدديا عندما يكون الفرق في الموقف صغيرا.

الذهاب إلى علم المثلثات الأساسية، ونحن نعلم أيضا أن:

cos (A - B) = cos A . cos B + sin A . sin B

تطبيق ذلك مرتين في المعادلة التي قدمتها قد ينتهي بك الأمر في الصيغة في مصلحة الطيران.

(مرجعي: "علم الفلك: المبادئ والممارسة، الطبعة الرابعة" بواسطة AE ROY و D Clarke (2003)؛ نسختي هي الطبعة الأولى من عام 1977، آدم هيلجر، ISBN 0-85274-346-7.)


ملح تحقق من (جوجل) تحديد: "ميل بحري"؛ يبدو أن ميل بحري الآن 1852 م (1.852 كم) بحكم التعريف. يتوافق 1.1515 المضاعف مع التعريف القديم لما بعد حوالي 6080 قدم. باستخدام bc مع مقياس من 10، أحصل على:

(1852/(3*0.3048))/1760
1.1507794480

أي عامل يعمل بالنسبة لك يعتمد على ما هو أساسك.


بالنظر إلى المشكلة الثانية من المبادئ الأولى، لدينا إعداد مختلف قليلا، ونحن بحاجة إلى معادلة علم المثلثات الكروية "الأخرى"، وصيغة جيبية:

sin A   sin B   sin C
----- = ----- = -----
sin a   sin b   sin c

تكييف المخطط السابق:

                  + C
                 /|
                / |
            a  /  | b
           |  /   |
           |X/    |
           |/     |
         B +------+ A
              c

يتم إعطاؤك نقطة الانطلاق ب, ، زاوية عاشر = 90º - ب، طول (زاوية) أ, ، والزاوية أ = 90 درجة. ما أنت بعد ب (دلتا في خط العرض) و جيم (دلتا خط الطول).

اذا لدينا:

sin a   sin b
----- = ----
sin A   sin B

أو

        sin a . sin B
sin b = -------------
            sin A

أو منذ A = 90 درجة، SIN A = 1، و SIN B = SIN (90 ° - X) = COS X:

sin b = sin a . cos X

وهذا يعني أنك تحويل المسافة المقطوعة إلى زاوية أ, ، خذ جيب ذلك، مضاعفة جيب التمام في اتجاه الدورة التدريبية، واتخاذ Arcsine من النتيجة.

منح أ, ب (حساب فقط) و أ و ب, ، يمكننا تطبيق صيغة جيب التمام جيم. وبعد لاحظ أنه لا يمكننا ببساطة إعادة تطبيق صيغة Sine للحصول على جيم لأنه ليس لدينا قيمة جيم ولأننا نلعب مع علم المثلثات الكروية، لا توجد قاعدة مريحة التي c = 90 ° - ب (يمكن أن يكون مجموع الزوايا في مثلث كروي أكبر من 180 درجة؛ النظر في مثلث كروي متساوي الأضلاع مع جميع الزوايا تساوي 90 درجة، والتي هي ممكنة تماما).


نصائح أخرى

الدفع http://www.movable-type.co.uk/scripts/latlong.html.

يحتوي هذا الموقع على الكثير من الصيغ المختلفة ورمز JavaScript الذي يجب أن يساعدك. لقد قمت بنجاح بترجمةها إلى كل من C # و SQL Server UDF وأنا استخدمها في جميع أنحاء المكان.

على سبيل المثال لجافا سكريبت لحساب المسافة:

var R = 6371; // km
var φ1 = lat1.toRadians();
var φ2 = lat2.toRadians();
var Δφ = (lat2-lat1).toRadians();
var Δλ = (lon2-lon1).toRadians();

var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
        Math.cos(φ1) * Math.cos(φ2) *
        Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

var d = R * c; 

استمتع!

التحول الخاص بك بين كم والراديان هو الخطأ. ميل بحري هو 1/60 درجة، لذا افتراض أن 1.15 ... هو تحويلك من الأميال إلى الأميال البحرية، و 1.6 ... هو تحويلك من كيلومتر واحد إلى الأميال النظامية،

   nm = km /  (1.1515 * 1.609344);
   deg = nm / 60;
   rad = toRadians(deg);

وبعبارة أخرى، أعتقد أنك خارج عامل 1000.

فيما يتعلق بسؤالك المحدث: لا ينبغي

double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[0];

يكون

double lon1 = endOfCourse(lat1, 0.0, 90.0, distEast)[1];

اكتشفت المشكلة الكبيرة في هذه الصيغ، بصرف النظر عن أخطاء التنفيذ المذكورة في الإجابات والتحديثات الأخرى.

المشكلة الكبيرة كانت هذه: كانت طريقة المسافة (لحساب المسافة بين نقطتين) الحوسبة لمسافات دائرة رائعة. وهذا بالطبع، منطقي - هذا هو أقصر طريق بين النقطتين. ومع ذلك, ، فإن المسافة الكبرى الدائرة بين نقطتين تكمن على نفس الموازية (خط خط العرض) ليست هي نفس المسافة بين هاتين النقاط عند السفر مباشرة على طول خط الطول، إلا إذا كنت في خط الاستواء.

لذلك: تعمل الوظائف بشكل صحيح؛ ومع ذلك، يتطلب نظام الإحداثيات البديل الذي اقترحته في السؤال الأصلي أن ننظر فقط عند المسافة الشمالية على طول IDL تليها المسافة الشرقية على طول الطريق الموازي في خط العرض الناتج. وحساب المسافة على طول موازي محدد مختلف تماما عن حساب المسافة على طول دائرة رائعة!

على أي حال، فإنه يوجد لديك.

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