ฉันจะใช้ ArcGIS 10.1 เพื่อค้นหาจุดเท่ากันทางภูมิศาสตร์ที่กำหนดโดยสามจุดได้อย่างไร


12

ตัวอย่างเช่นฉันมีพิกัดสำหรับจุดฐานสามจุดบนแนวชายฝั่งและฉันต้องการค้นหาพิกัดของจุดนอกชายฝั่งซึ่งมีระยะทางเท่ากันจากทั้งสามจุด มันเป็นแบบฝึกหัดที่เรียบง่ายในรูปทรงเรขาคณิต แต่การวัดทั้งหมดต้องคำนึงถึงมาตรวัดด้วย

หากฉันเข้าใกล้สิ่งนี้ในลักษณะ Euclidian ฉันสามารถวัดเส้นทางทางธรณีวิทยาที่เชื่อมต่อกับจุดฐานหาจุดกึ่งกลางของด้านข้างของสามเหลี่ยมที่เกิดขึ้นและสร้าง orthodromes ตั้งฉากกับแต่ละเส้นทางเหล่านั้น Loxodromes ทั้งสามน่าจะมาบรรจบกันที่จุดที่เท่ากัน หากนี่เป็นวิธีที่ถูกต้องจะต้องมีวิธีที่ง่ายกว่าใน Arc

ฉันต้องหา O


มีข้อ จำกัด ในตำแหน่งสัมพัทธ์ของ 3 คะแนนหรือไม่? รูปภาพชายฝั่งตะวันออกจุดกึ่งกลางอยู่ทางตะวันออกสุด โซลูชันของคุณจะไม่ทำงานเนื่องจากฉากตั้งฉากจะไม่มาบรรจบกันที่ฝั่ง ฉันแน่ใจว่าเราสามารถเกิดขึ้นกับกรณีที่เลวร้ายอื่น ๆ !
mkennedy

ฉันสงสัยว่าคุณสามารถใช้การฉายภาพระยะไกลและคำนวณจากที่นั่นได้หรือไม่? progonos.com/furuti/MapProj/Normal/CartProp/DistPres/ … ไม่แน่ใจว่าอัลกอริทึมที่จะทำมันต้องมีอันเดียว ... อาจจะเป็น barycentre: en.wikipedia.org/wiki/Barycentric_coordinate_system
Alex Leith

สำหรับการแก้ปัญหาที่เกี่ยวข้องอย่างใกล้ชิดค้นหาเว็บไซต์ของเราสำหรับ "trilateration" นอกจากนี้gis.stackexchange.com/questions/10332/…เป็นคำที่ซ้ำกัน แต่ไม่มีคำตอบที่เพียงพอ (ส่วนใหญ่เป็นเพราะคำถามถูกถามในลักษณะที่สับสน)
whuber

@mkennedy โดยหลักการแล้วไม่มีกรณีที่ไม่ดีมีเพียงตัวเลขที่ไม่เสถียร สิ่งเหล่านี้เกิดขึ้นเมื่อจุดฐานทั้งสามนั้นเป็นเส้นตรง การแก้ปัญหาทั้งสอง (ในแบบจำลองทรงกลม) เกิดขึ้นที่เสาสองอันของธรณีวิทยาทั่วไป ในรูปแบบวงรีพวกเขาเกิดขึ้นใกล้กับที่คาดว่าเสาเหล่านั้น
whuber

การใช้ loxodromes ที่นี่จะไม่ถูกต้อง: พวกมันไม่ใช่เส้นแบ่งครึ่งตั้งฉาก บนทรงกลมเส้นเหล่านี้จะเป็นส่วนหนึ่งของวงกลมใหญ่ (geodesics) แต่บนวงรีพวกมันจะแยกออกจากการเป็นธรณีวิทยาเล็กน้อย
whuber

คำตอบ:


10

คำตอบนี้แบ่งออกเป็นหลายส่วน:

  • การวิเคราะห์และการลดปัญหาแสดงวิธีการหาจุดที่ต้องการด้วยรูทีน "canned"

  • ภาพประกอบ: ต้นแบบการทำงานให้รหัสการทำงาน

  • ตัวอย่างแสดงตัวอย่างของการแก้ปัญหา

  • ข้อผิดพลาดการพูดคุยปัญหาที่อาจเกิดขึ้นและวิธีรับมือกับพวกเขา

  • การใช้ ArcGISความคิดเห็นเกี่ยวกับการสร้างเครื่องมือ ArcGIS ที่กำหนดเองและสถานที่ที่จะได้รับรูทีนที่จำเป็น


การวิเคราะห์และการลดปัญหา

เรามาเริ่มด้วยการสังเกตว่าในรูปแบบทรงกลม (รอบที่ดีที่สุด) จะมีทางออกเสมอ - ในความเป็นจริงแล้วมีสองวิธี รับคะแนนฐาน A, B และ C แต่ละคู่จะกำหนด "เส้นแบ่งครึ่งตั้งฉาก" ซึ่งเป็นชุดของจุดที่เท่ากันจากจุดที่กำหนดทั้งสอง เส้นแบ่งครึ่งนี้เป็น geodesic (วงกลมใหญ่) รูปทรงกลมทรงรีคือวงรี : สอง geodesics ตัดกัน (ในสองจุดที่ไม่ซ้ำกัน) ดังนั้นจุดตัดของเส้นแบ่งครึ่งของ AB และเส้นแบ่งครึ่งของ BC คือ - โดยนิยาม - เท่ากันจาก A, B และ C ดังนั้นจึงเป็นการแก้ปัญหา (ดูรูปแรกด้านล่าง)

สิ่งต่าง ๆ ดูซับซ้อนกว่าในวงรีแต่เนื่องจากมันเป็นการรบกวนรอบตัวเล็ก ๆ เราจึงสามารถคาดหวังพฤติกรรมที่คล้ายกันได้ (การวิเคราะห์สิ่งนี้จะนำเราไปไกลเกินไป) สูตรที่ซับซ้อนที่ใช้ (ภายในภายใน GIS) เพื่อคำนวณระยะทางที่แม่นยำในรูปวงรีไม่ใช่ปัญหาแทรกซ้อนแนวความคิด แต่โดยทั่วไปแล้วปัญหาจะเหมือนกัน เพื่อดูว่าปัญหาง่ายจริงเพียงใดให้รัฐค่อนข้างนามธรรม ในคำแถลงนี้ "d (U, V)" หมายถึงระยะทางที่แท้จริงและแม่นยำมากระหว่างจุด U และ V

ให้สามคะแนน A, B, C (เป็นคู่ lat-lon) บนทรงรีหาจุด X ที่ (1) d (X, A) = d (X, B) = d (X, C) และ ( 2) ระยะทางทั่วไปนี้มีขนาดเล็กที่สุด

ทั้งสามระยะทางทั้งหมดขึ้นอยู่กับที่ไม่รู้จักX ดังนั้นความแตกต่างในระยะทาง u (X) = d (X, A) - d (X, B) และ v (X) = d (X, B) - d (X, C) เป็นฟังก์ชันที่มีมูลค่าจริงของ X อีกครั้งค่อนข้างเป็นนามธรรมเราอาจรวบรวมความแตกต่างเหล่านี้เป็นคู่ที่สั่งซื้อ นอกจากนี้เรายังจะใช้ (lat, lon) เป็นพิกัดสำหรับ X ช่วยให้เราพิจารณาว่าเป็นคู่ที่สั่งซื้อด้วยเช่นกันพูดว่า X = (phi, lambda) ในการตั้งค่านี้ฟังก์ชั่น

F (phi, lambda) = (u (X), v (X))

เป็นฟังก์ชั่นจากส่วนหนึ่งของพื้นที่สองมิติที่รับค่าในพื้นที่สองมิติและปัญหาของเราลดลง

ค้นหาความเป็นไปได้ทั้งหมด (phi, lambda) ซึ่ง F (phi, lambda) = (0,0)

นี่คือที่ที่สิ่งที่เป็นนามธรรมจ่ายออกไป: มีซอฟต์แวร์ที่ยอดเยี่ยมมากมายที่มีอยู่เพื่อแก้ปัญหานี้ วิธีการทำงานคือคุณเขียนรูทีนเพื่อคำนวณFจากนั้นส่งผ่านไปยังซอฟต์แวร์พร้อมกับข้อมูลใด ๆ เกี่ยวกับข้อ จำกัด ของอินพุต ( phiต้องอยู่ระหว่าง -90 ถึง 90 องศาและแลมบ์ดาต้องอยู่ระหว่าง -180 ถึง 180 องศา) มันจะแยกออกไปเป็นเสี้ยววินาทีและส่งคืน (โดยทั่วไป) เพียงหนึ่งค่า ( phi , lambda ) หากสามารถหาได้

มีรายละเอียดที่จะจัดการเนื่องจากมีศิลปะในการนี้: มีวิธีการแก้ปัญหาต่าง ๆ ให้เลือกขึ้นอยู่กับวิธีF "พฤติกรรม"; ช่วยในการ "คัดท้าย" ซอฟต์แวร์โดยให้จุดเริ่มต้นที่สมเหตุสมผลสำหรับการค้นหา (นี่คือวิธีหนึ่งที่เราจะได้รับโซลูชันที่ใกล้ที่สุดแทนที่จะเป็นซอฟต์แวร์อื่น) และโดยปกติคุณจะต้องระบุว่าคุณต้องการให้โซลูชันนั้นถูกต้องมากน้อยเพียงใด (เพื่อให้ทราบว่าจะหยุดการค้นหาเมื่อใด) (สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่นักวิเคราะห์ระบบสารสนเทศภูมิศาสตร์จำเป็นต้องทราบเกี่ยวกับรายละเอียดดังกล่าวซึ่งเกิดขึ้นมากในปัญหา GIS กรุณาเยี่ยมชมหัวข้อแนะนำที่จะรวมอยู่ในหลักสูตรวิทยาศาสตร์คอมพิวเตอร์สำหรับวิชาเทคโนโลยีเชิงพื้นที่และดูในส่วน )


ภาพประกอบ: ต้นแบบการทำงาน

การวิเคราะห์แสดงให้เห็นว่าเราต้องเขียนโปรแกรมสองสิ่ง: การประมาณค่าเริ่มต้นอย่างหยาบของการแก้ปัญหาและการคำนวณค่าFเอง

การประเมินเบื้องต้นสามารถทำได้โดย "เฉลี่ยทรงกลม" ของสามจุดฐาน สิ่งนี้ได้มาจากการแทนค่าพวกมันในพิกัดคาร์ทีเซียน (x, y, z), คำนวณค่าเฉลี่ยของพิกัดเหล่านั้นและคาดการณ์ค่าเฉลี่ยนั้นกลับไปยังทรงกลมและแสดงพิกัดละติจูดและลองจิจูดอีกครั้ง ขนาดของทรงกลมนั้นไม่มีสาระสำคัญและการคำนวณจึงตรงไปตรงมา: เนื่องจากนี่เป็นเพียงจุดเริ่มต้นเราไม่จำเป็นต้องคำนวณรูปวงรี

สำหรับต้นแบบการทำงานนี้ฉันใช้Mathematica 8

sphericalMean[points_] := Module[{sToC, cToS, cMean},
  sToC[{f_, l_}] := {Cos[f] Cos[l], Cos[f] Sin[l], Sin[f]};
  cToS[{x_, y_, z_}] := {ArcTan[x, y], ArcTan[Norm[{x, y}], z]};
  cMean = Mean[sToC /@ (points Degree)];
  If[Norm[Most@cMean] < 10^(-8), Mean[points], cToS[cMean]] / Degree
  ]

( Ifเงื่อนไขสุดท้ายทดสอบว่าค่าเฉลี่ยอาจล้มเหลวอย่างเห็นได้ชัดเพื่อระบุลองจิจูดถ้าเป็นเช่นนั้นกลับไปที่ค่าเฉลี่ยเลขคณิตตรงของละติจูดและลองจิจูดของอินพุต - อาจไม่ใช่ตัวเลือกที่ดี แต่อย่างน้อยก็เป็นค่าที่ถูกต้อง สำหรับผู้ที่ใช้รหัสนี้เพื่อเป็นแนวทางในการใช้งานโปรดทราบว่าข้อโต้แย้งของMathematica ArcTanนั้นตรงกันข้ามกับการใช้งานอื่น ๆ ส่วนใหญ่อาร์กิวเมนต์แรกคือพิกัด x ส่วนที่สองคือพิกัด y และส่งคืนมุมที่ทำโดยเวกเตอร์ ( x, y).)

เท่าที่ส่วนที่สองไปเนื่องจากMathematica - like ArcGIS และ GISes อื่น ๆ เกือบทั้งหมด - มีรหัสเพื่อคำนวณระยะทางที่แม่นยำบนรี ellipsoid แทบไม่มีอะไรจะเขียน เราเพียงเรียกรูทีนการรูท:

tri[a_, b_, c_] := Block[{d = sphericalMean[{a, b, c}], sol, f, q},
   sol = FindRoot[{GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, a] == 
                   GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, b] ==
                   GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, c]}, 
           {{f, d[[1]]}, {q, d[[2]]}}, 
           MaxIterations -> 1000, AccuracyGoal -> Infinity, PrecisionGoal -> 8];
   {Mod[f, 180, -90], Mod[q, 360, -180]} /. sol
   ];

สิ่งสำคัญที่สุดของการใช้งานนี้คือวิธีที่มันจำเป็นต้อง จำกัด ละติจูด ( f) และลองจิจูด ( q) โดยการคำนวณมันแบบโมดูโล 180 และ 360 องศาตามลำดับ วิธีนี้หลีกเลี่ยงการ จำกัด ปัญหา (ซึ่งมักสร้างภาวะแทรกซ้อน) พารามิเตอร์การควบคุมMaxIterationsฯลฯ ถูกปรับแต่งเพื่อให้รหัสนี้ให้ความแม่นยำที่เป็นไปได้มากที่สุดเท่าที่จะทำได้

หากต้องการดูการทำงานลองนำไปใช้กับจุดฐานทั้งสามที่ให้ไว้ในคำถามที่เกี่ยวข้อง :

sol = tri @@ (bases = {{-6.28530175, 106.9004975375}, {-6.28955287, 106.89573839}, {-6.28388865789474, 106.908087643421}})

{-6.29692, 106.907}

ระยะทางที่คำนวณระหว่างคำตอบนี้กับจุดสามจุดคือ

{1450.23206979, 1450.23206979, 1450.23206978}

(เหล่านี้คือเมตร) พวกเขาเห็นพ้องผ่านหลักสำคัญที่สิบเอ็ด (ซึ่งแม่นยำเกินไปจริง ๆ แล้วเนื่องจากระยะทางนั้นไม่ค่อยแม่นยำถึงดีกว่ามิลลิเมตรหรือมากกว่านั้น) นี่คือภาพของจุดสามจุด (สีดำ) เส้นแบ่งครึ่งทั้งสามของพวกเขาและวิธีแก้ปัญหา (สีแดง):

รูปที่ 1


ตัวอย่าง

เพื่อทดสอบการนำไปปฏิบัตินี้และทำความเข้าใจกับวิธีการทำงานของปัญหาได้ดีขึ้นนี่คือโครงร่างของความคลาดเคลื่อนกำลังสองเฉลี่ยของรูทในระยะทางสำหรับจุดฐานที่เว้นระยะสามจุด (ความคลาดเคลื่อน RMS นั้นได้มาจากการคำนวณความแตกต่างทั้งสาม d (X, A) -d (X, B), d (X, B) -d (X, C) และ d (X, C) -d (X , A), หาค่าเฉลี่ยกำลังสองของพวกเขาและรับสแควร์รูทมันเท่ากับศูนย์เมื่อ X แก้ปัญหาและเพิ่มขึ้นเมื่อ X เคลื่อนที่ห่างจากโซลูชันและวัดว่า "ปิด" เราจะเป็นวิธีแก้ปัญหาได้ทุกที่ )

รูปที่ 2

คะแนนฐาน (60, -120), (10, -40), และ (45,10) จะแสดงเป็นสีแดงในการฉายภาพ Plate Carree; วิธีแก้ปัญหา (49.2644488, -49.9052992) - ซึ่งต้องใช้การคำนวณ 0.03 วินาที - เป็นสีเหลือง ความคลาดเคลื่อน RMS นั้นน้อยกว่าสามนาโนเมตรแม้จะมีระยะทางที่เกี่ยวข้องทั้งหมดเป็นระยะทางหลายพันกิโลเมตร พื้นที่มืดแสดงค่าขนาดเล็กของ RMS และพื้นที่แสงแสดงค่าสูง

แผนที่นี้แสดงให้เห็นถึงวิธีแก้ไขปัญหาอื่นอย่างชัดเจนซึ่งอยู่ใกล้กับ (-49.2018206, 130.0297177) (คำนวณเป็น RMS สองนาโนเมตรโดยการตั้งค่าการค้นหาเริ่มต้นตรงข้ามกับโซลูชั่นแรก)


ผิดพลาด

ความไม่แน่นอนเชิงตัวเลข

เมื่อจุดฐานเกือบ collinear และอยู่ใกล้กันการแก้ปัญหาทั้งหมดจะเกือบครึ่งโลกและยากที่จะปักลงอย่างแม่นยำ เหตุผลก็คือการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ ในสถานที่ต่างๆทั่วโลก - เคลื่อนไปทางหรือออกจากจุดฐาน - จะทำให้เกิดการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ อย่างไม่น่าเชื่อในความแตกต่างของระยะทาง มีความแม่นยำและความแม่นยำไม่เพียงพอที่สร้างขึ้นในการคำนวณระยะทางธรณีวิทยาตามปกติเพื่อตรึงผลลัพธ์

ตัวอย่างเช่นเริ่มต้นด้วยคะแนนฐานที่ (45.001, 0), (45, 0) และ (44.999,0) ซึ่งแยกตาม Prime Meridian เพียง 111 เมตรระหว่างแต่ละคู่triได้รับโซลูชัน (11.8213, 77.745 ) ระยะทางจากจุดถึงจุดฐานคือ 8,127,964.998 77; 8,127,964.998 41; และ 8,127,964.998 65 เมตรตามลำดับ พวกเขาเห็นด้วยกับมิลลิเมตรที่ใกล้ที่สุด! ฉันไม่แน่ใจว่าผลลัพธ์นี้แม่นยำเพียงใด แต่จะไม่แปลกใจหากการใช้งานอื่น ๆ ส่งคืนสถานที่ห่างไกลจากจุดนี้แสดงให้เห็นว่ามีความเสมอภาคที่ดีของระยะทางสามระยะ

เวลาในการคำนวณ

การคำนวณเหล่านี้เนื่องจากพวกเขาเกี่ยวข้องกับการค้นหาจำนวนมากโดยใช้การคำนวณระยะทางที่ซับซ้อนไม่เร็วนักซึ่งมักจะต้องใช้เวลาเพียงเสี้ยววินาทีที่เห็นได้ชัดเจน แอปพลิเคชันแบบเรียลไทม์จำเป็นต้องทราบสิ่งนี้


การใช้งาน ArcGIS

Python เป็นสภาพแวดล้อมการเขียนสคริปต์ที่ต้องการสำหรับ ArcGIS (เริ่มต้นด้วยรุ่น 9) แพคเกจ scipy.optimizeมี rootfinder หลายตัวแปรrootที่ควรทำในสิ่งที่FindRootไม่อยู่ในMathematicaรหัส แน่นอนว่า ArcGIS นั้นมีการคำนวณระยะทางรีที่แม่นยำ ส่วนที่เหลือนั้นคือรายละเอียดการใช้งานทั้งหมด: ตัดสินใจว่าจะรับพิกัดจุดฐานได้อย่างไร (จากเลเยอร์ที่ผู้ใช้พิมพ์จากไฟล์ข้อความจากเมาส์หรือไม่) และวิธีแสดงผลลัพธ์จะเป็นอย่างไร ปรากฏบนหน้าจอเป็นจุดกราฟิกเป็นวัตถุจุดใหม่ในเลเยอร์เขียนอินเทอร์เฟซนั้นพอร์ตรหัสMathematica ที่แสดงที่นี่ (ตรงไปตรงมา) และคุณจะได้รับการตั้งค่าทั้งหมด


3
+1 ถี่ถ้วนมาก ฉันคิดว่าคุณอาจต้องเริ่มต้นเรียกเก็บเงินสำหรับสิ่งนี้ @whuber
Radar

2
@ Radad ขอบคุณ ฉันหวังว่าผู้คนจะซื้อหนังสือของฉันเมื่อมันปรากฏขึ้นในที่สุด :-)
whuber

1
จะทำบิล ... ส่งร่าง !!!

ยอดเยี่ยม ถึงกระนั้นก็ดูเหมือนว่าจะมีวิธีการวิเคราะห์ที่เป็นไปได้ โดยการแก้ไขปัญหาให้เป็นพื้นที่คาร์ทีเซียน 3 มิติด้วย 3 คะแนน A, B, C และ E โดยที่ E เป็นศูนย์กลางของโลก ถัดไปค้นหาเครื่องบินสองลำ Plane1 และ Plane2 Plane1 จะเป็นเครื่องบินที่ปกติกับ planeABE และผ่าน E, จุดกึ่งกลาง (A, B) ในทำนองเดียวกัน Plane2 จะเป็นระนาบปกติไปยัง planeACE และผ่าน E, จุดกึ่งกลาง (C, E) lineO ที่เกิดขึ้นจากจุดตัดของ Plane1 และ Plane2 แสดงถึงจุดที่เท่ากับ 3 จุด ยิ่งใกล้จุดสองจุดไปที่ A (หรือ B หรือ C) โดยที่ lineO ตัดกันทรงกลมคือ pointO
Kirk Kuykendall

โซลูชันการวิเคราะห์นั้น @Kirk ใช้กับทรงกลมเท่านั้น (จุดตัดของระนาบที่มีรูปวงรีไม่เคยตั้งฉาก bisectors ในเมตริกของรูปวงรียกเว้นบางกรณีที่เห็นได้ชัดเจน: เมื่อพวกเขาเป็นเส้นเมอริเดียนหรือเส้นศูนย์สูตร)
whuber

3

ดังที่คุณทราบปัญหานี้เกิดขึ้นในการกำหนดขอบเขตของการเดินเรือ มันมักจะถูกเรียกว่าปัญหา "จุดสามจุด" และคุณสามารถ Google นี้และค้นหาเอกสารหลายฉบับที่อยู่ หนึ่งในเอกสารเหล่านี้คือฉัน (!) และฉันขอเสนอโซลูชันที่ถูกต้องและรวดเร็ว ดูส่วนที่ 14 ของhttp://arxiv.org/abs/1102.1215

วิธีการประกอบด้วยขั้นตอนต่อไปนี้:

  1. คาดเดาจุดสามจุด
  2. ใช้ O เป็นศูนย์กลางของการฉายภาพระยะทางเท่ากันของ azimuthal
  3. โครงการ A, B, C ถึงการประมาณการนี้
  4. หาจุดสามจุดในการฉายภาพนี้ O '
  5. ใช้ O 'เป็นศูนย์กลางการฉายภาพใหม่
  6. ทำซ้ำจนกระทั่ง O 'และ O ตรงกัน

สูตรที่จำเป็นสำหรับการแก้ปัญหาจุดสามจุดในการฉายภาพนั้นมีอยู่ในกระดาษ ตราบใดที่คุณใช้โปรเจกต์ azimuthal ที่มีความยาวเท่ากันแม่นยำคำตอบก็จะถูกต้อง การบรรจบกันเป็นสมการกำลังสองที่จำเป็นต้องทำซ้ำเพียงไม่กี่ครั้ง วิธีนี้จะมีประสิทธิภาพสูงกว่าวิธีการค้นหารูททั่วไปที่ @whuber แนะนำ

ฉันไม่สามารถช่วยเหลือคุณด้วย ArcGIS โดยตรง คุณสามารถคว้าแพคเกจหลามของฉันสำหรับการคำนวณทางธรณีวิทยาจากhttps://pypi.python.org/pypi/geographiclib และการเข้ารหัสการประมาณการตามนี้เป็นเรื่องง่าย


แก้ไข

ปัญหาของการค้นหาจุดสามจุดในกรณีความเสื่อมของ @ whuber (45 + eps, 0) (45,0) (45-eps, 0) ได้รับการพิจารณาโดย Cayley ในOn the geodesic lines บนทรงกลม oblate , Phil พูดเรื่องไม่มีสาระ (1870), http://books.google.co.th/books?id=4XGIOoCMYYAC&pg=PA15

ในกรณีนี้ tri-point ได้มาจากการทำ geodesic จาก (45,0) ด้วย azimuth 90 และหาจุดที่มาตราส่วนเกี่ยวกับ geodesic หายไป สำหรับ WGS84 ellipsoid จุดนี้คือ (-0.10690908732248, 89.89291072793167) ระยะทางจากจุดนี้ถึงแต่ละ (45.001,0), (45,0), (44.999) คือ 10010287.665788943 m (ภายในนาโนเมตรหรือมากกว่านั้น) นี่คือประมาณ 1,882 กม. มากกว่าประมาณการของ whuber (ซึ่งเพิ่งไปแสดงว่ากรณีนี้ไม่เสถียร) สำหรับโลกทรงกลมจุดสามจุดคือ (0,90) หรือ (0, -90) แน่นอน

เพิ่ม: นี่คือการดำเนินการตามวิธีระยะเวลาเท่ากัน azimuthal โดยใช้ Matlab

function [lat, lon] = tripoint(lat1, lon1, lat2, lon2, lat3, lon3)
% Compute point equidistant from arguments
% Requires:
%   http://www.mathworks.com/matlabcentral/fileexchange/39108
%   http://www.mathworks.com/matlabcentral/fileexchange/39366
  lats = [lat1, lat2, lat3];
  lons = [lon1, lon2, lon3];
  lat0 = lat1;  lon0 = lon1; % feeble guess for tri point
  for i = 1:6
    [x, y] = eqdazim_fwd(lat0, lon0, lats, lons);
    a = [x(1), y(1), 0];
    b = [x(2), y(2), 0];
    c = [x(3), y(3), 0];
    z = [0, 0, 1];
    % Eq. (97) of http://arxiv.org/abs/1102.1215
    o = cross((a*a') * (b - c) + (b*b') * (c - a) + (c*c') * (a - b), z) ...
        / (2 * dot(cross(a - b, b - c), z));
    [lat0, lon0] = eqdazim_inv(lat0, lon0, o(1), o(2))
  end
  % optional check
  s12 = geoddistance(lat0, lon0, lats, lons); ds12 = max(s12) - min(s12)
  lat = lat0; lon = lon0;
end

ทดสอบสิ่งนี้โดยใช้ Octave ที่ฉันได้รับ

อ็อกเทฟ: 1> รูปแบบยาว
อ็อกเทฟ: 2> [lat0, lon0] = tripoint (41, -74,36,140, ​​-41,175)
lat0 = 15.4151378380375
lon0 = -162.479314381144
lat0 = 15.9969703299812
lon0 = -147.046790722192
lat0 = 16.2232960167545
lon0 = -147.157646039471
lat0 = 16.2233394851560
lon0 = -147.157748279290
lat0 = 16.2233394851809
lon0 = -147.157748279312
lat0 = 16.2233394851809
lon0 = -147.157748279312
ds12 = 3.72529029846191e-09
lat0 = 16.2233394851809
lon0 = -147.157748279312

เป็นจุดที่สามสำหรับนิวยอร์กโตเกียวและเวลลิงตัน

วิธีนี้ไม่ถูกต้องสำหรับคะแนน colinear ที่อยู่ใกล้เคียงเช่น [45.001,0], [45,0], [44.999,0] ในกรณีนั้นคุณควรแก้หา M 12 = 0 บน geodesic ที่เล็ดลอดออกมาจาก [45,0] ที่ azimuth 90 ฟังก์ชันต่อไปนี้ทำการหลอกลวง (โดยใช้วิธีของนิวตัน):

function [lat2,lon2] = semiconj(lat1, lon1, azi1)
% Find the point where neighboring parallel geodesics emanating from
% close to [lat1, lon1] with azimuth azi1 intersect.

  % First guess is 90 deg on aux sphere
  [lat2, lon2, ~, ~, m12, M12, M21, s12] = ...
      geodreckon(lat1, lon1, 90, azi1, defaultellipsoid(), true);
  M12
  % dM12/ds2 = - (1 - M12*M21/m12)
  for i = 1:3
    s12 = s12 - M12 / ( -(1 - M12*M21)/m12 ); % Newton
    [lat2, lon2, ~, ~, m12, M12, M21] = geodreckon(lat1, lon1, s12, azi1);
    M12
  end
end

ตัวอย่างเช่นสิ่งนี้ให้:

[lat2, lon2] = semiconj (45, 0, 90)
M12 = 0.00262997817649321
M12 = -6.08402492665097e-09
M12 = 4.38017677684144e-17
M12 = 4.38017677684144e-17
lat2 = -0.106909087322479
lon2 = 89.8929107279317

+1 อย่างไรก็ตามมันไม่ชัดเจนว่าตัวค้นหารูตทั่วไปจะทำงานได้ดีน้อยกว่า: ฟังก์ชันนั้นทำหน้าที่ได้ดีใกล้กับวิธีที่ดีที่สุดและวิธีของนิวตันเช่นกัน ( โดยปกติแล้วMathematicaจะใช้เวลาประมาณสี่ขั้นตอนในการรวมกันแต่ละขั้นตอนต้องใช้การประเมินสี่ขั้นเพื่อประเมิน Jacobian) ประโยชน์ที่แท้จริงที่ฉันเห็นกับวิธีการของคุณคือมันสามารถสคริปต์ได้อย่างง่ายดายใน GIS โดยไม่ต้องใช้เครื่องมือค้นหาราก
whuber

ฉันเห็นด้วย. วิธีการของฉันเทียบเท่ากับนิวตันและตรงกันข้ามกับวิธีการค้นหารากของ Mathematica ไม่จำเป็นต้องประเมินการไล่ระดับสีโดยใช้ความแตกต่าง
cffk

ถูกต้อง - แต่คุณต้องปฏิเสธสิ่งที่เกิดขึ้นในแต่ละครั้งซึ่งดูเหมือนว่าจะมีปริมาณงานเท่ากัน ฉันขอขอบคุณความเรียบง่ายและความสง่างามของวิธีการของคุณแม้ว่า: มันชัดเจนทันทีว่าควรทำงานและจะมาบรรจบกันอย่างรวดเร็ว
whuber

ฉันโพสต์ผลลัพธ์สำหรับจุดทดสอบเดียวกันในคำตอบของฉัน
Kirk Kuykendall

3

ฉันอยากรู้ว่าวิธีการที่ @ cffk มาบรรจบกันอย่างรวดเร็วในวิธีการแก้ปัญหาดังนั้นฉันจึงเขียนการทดสอบโดยใช้ arcobjects ซึ่งผลิตผลลัพธ์นี้ ระยะทางเป็นเมตร:

0 longitude: 0 latitude: 90
    Distances: 3134.05443974188 2844.67237777542 3234.33025754997
    Diffs: 289.382061966458 -389.657879774548 -100.27581780809
1 longitude: 106.906152157596 latitude: -6.31307123035178
    Distances: 1450.23208989615 1450.23208089398 1450.23209429293
    Diffs: 9.00216559784894E-06 -1.33989510686661E-05 -4.39678547081712E-06
2 longitude: 106.906583669013 latitude: -6.29691590176649
    Distances: 1450.23206976414 1450.23206976408 1450.23206976433
    Diffs: 6.18456397205591E-11 -2.47382558882236E-10 -1.85536919161677E-10
3 longitude: 106.906583669041 latitude: -6.29691590154641
    Distances: 1450.23206976438 1450.23206976423 1450.23206976459
    Diffs: 1.47565515362658E-10 -3.61751517630182E-10 -2.14186002267525E-10
4 longitude: 106.906583669041 latitude: -6.29691590154641
    Distances: 1450.23206976438 1450.23206976423 1450.23206976459
    Diffs: 1.47565515362658E-10 -3.61751517630182E-10 -2.14186002267525E-10

นี่คือซอร์สโค้ด (แก้ไข) เปลี่ยน FindCircleCenter เพื่อจัดการทางแยก (จุดกึ่งกลาง) ที่หลุดออกจากขอบของการฉายภาพแบบอะซิมุ ธ :

public static void Test()
{
    var t = Type.GetTypeFromProgID("esriGeometry.SpatialReferenceEnvironment");
    var srf = Activator.CreateInstance(t) as ISpatialReferenceFactory2;
    var pcs = srf.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_WGS1984N_PoleAziEqui)
        as IProjectedCoordinateSystem2;

    var pntA = MakePoint(106.9004975375, -6.28530175, pcs.GeographicCoordinateSystem);
    var pntB = MakePoint(106.89573839, -6.28955287, pcs.GeographicCoordinateSystem);
    var pntC = MakePoint(106.908087643421, -6.28388865789474, pcs.GeographicCoordinateSystem);

    int maxIter = 5;
    for (int i = 0; i < maxIter; i++)
    {
        var msg = string.Format("{0} longitude: {1} latitude: {2}", i, pcs.get_CentralMeridian(true), pcs.LatitudeOfOrigin);
        Debug.Print(msg);
        var newCenter = FindCircleCenter(ProjectClone(pntA, pcs), ProjectClone(pntB, pcs), ProjectClone(pntC, pcs));
        newCenter.Project(pcs.GeographicCoordinateSystem); // unproject
        var distA = GetGeodesicDistance(newCenter, pntA);
        var distB = GetGeodesicDistance(newCenter, pntB);
        var distC = GetGeodesicDistance(newCenter, pntC);
        Debug.Print("\tDistances: {0} {1} {2}", distA, distB, distC);
        var diffAB = distA - distB;
        var diffBC = distB - distC;
        var diffAC = distA - distC;
        Debug.Print("\tDiffs: {0} {1} {2}", diffAB, diffBC, diffAC);

        pcs.set_CentralMeridian(true, newCenter.X);
        pcs.LatitudeOfOrigin = newCenter.Y;
    }
}
public static IPoint FindCircleCenter(IPoint a, IPoint b, IPoint c)
{
    // from http://blog.csharphelper.com/2011/11/08/draw-a-circle-through-three-points-in-c.aspx
    // Get the perpendicular bisector of (x1, y1) and (x2, y2).
    var x1 = (b.X + a.X) / 2;
    var y1 = (b.Y + a.Y) / 2;
    var dy1 = b.X - a.X;
    var dx1 = -(b.Y - a.Y);

    // Get the perpendicular bisector of (x2, y2) and (x3, y3).
    var x2 = (c.X + b.X) / 2;
    var y2 = (c.Y + b.Y) / 2;
    var dy2 = c.X - b.X;
    var dx2 = -(c.Y - b.Y);

    // See where the lines intersect.
    var cx = (y1 * dx1 * dx2 + x2 * dx1 * dy2 - x1 * dy1 * dx2 - y2 * dx1 * dx2)
        / (dx1 * dy2 - dy1 * dx2);
    var cy = (cx - x1) * dy1 / dx1 + y1;

    // make sure the intersection point falls
    // within the projection.
    var earthRadius = ((IProjectedCoordinateSystem)a.SpatialReference).GeographicCoordinateSystem.Datum.Spheroid.SemiMinorAxis;

    // distance is from center of projection
    var dist = Math.Sqrt((cx * cx) + (cy * cy));
    double factor = 1.0;
    if (dist > earthRadius * Math.PI)
    {
        // apply a factor so we don't fall off the edge
        // of the projection
        factor = earthRadius / dist;
    }
    var outPoint = new PointClass() as IPoint;
    outPoint.PutCoords(cx * factor, cy* factor);
    outPoint.SpatialReference = a.SpatialReference;
    return outPoint;
}

public static double GetGeodesicDistance(IPoint pnt1, IPoint pnt2)
{
    var pc = new PolylineClass() as IPointCollection;
    var gcs = pnt1.SpatialReference as IGeographicCoordinateSystem;
    if (gcs == null)
        throw new Exception("point does not have a gcs");
    ((IGeometry)pc).SpatialReference = gcs;
    pc.AddPoint(pnt1);
    pc.AddPoint(pnt2);
    var t = Type.GetTypeFromProgID("esriGeometry.SpatialReferenceEnvironment");
    var srf = Activator.CreateInstance(t) as ISpatialReferenceFactory2;
    var unit = srf.CreateUnit((int)esriSRUnitType.esriSRUnit_Meter) as ILinearUnit;
    var pcGeodetic = pc as IPolycurveGeodetic;
    return pcGeodetic.get_LengthGeodetic(esriGeodeticType.esriGeodeticTypeGeodesic, unit);
}

public static IPoint ProjectClone(IPoint pnt, ISpatialReference sr)
{
    var clone = ((IClone)pnt).Clone() as IPoint;
    clone.Project(sr);
    return clone;
}

public static IPoint MakePoint(double longitude, double latitude, ISpatialReference sr)
{
    var pnt = new PointClass() as IPoint;
    pnt.PutCoords(longitude, latitude);
    pnt.SpatialReference = sr;
    return pnt;
}

นอกจากนี้ยังมีวิธีทางเลือกในเดือนมิถุนายน 2013 ปัญหาของนิตยสารของ MSDN อะมีบาวิธีการเพิ่มประสิทธิภาพโดยใช้ C #


แก้ไข

รหัสที่โพสต์ก่อนหน้านี้รวมเข้ากับ antipode ในบางกรณี ฉันได้แก้ไขโค้ดเพื่อให้มันสร้างผลลัพธ์นี้สำหรับจุดทดสอบของ @ cffk

นี่คือผลลัพธ์ที่มันผลิตตอนนี้:

0 0
0 longitude: 0 latitude: 0
    MaxDiff: 1859074.90170379 Distances: 13541157.6493561 11682082.7476523 11863320.2116807
1 longitude: 43.5318402621384 latitude: -17.1167429904981
    MaxDiff: 21796.9793742411 Distances: 12584188.7592282 12588146.4851222 12566349.505748
2 longitude: 32.8331167578493 latitude: -16.2707976739314
    MaxDiff: 6.05585224926472 Distances: 12577536.3369782 12577541.3560203 12577542.3928305
3 longitude: 32.8623898057665 latitude: -16.1374156408507
    MaxDiff: 5.58793544769287E-07 Distances: 12577539.6118671 12577539.6118666 12577539.6118669
4 longitude: -147.137582018133 latitude: 16.1374288796667
    MaxDiff: 1.12284109462053 Distances: 7441375.08265703 7441376.12671342 7441376.20549812
5 longitude: -147.157742373074 latitude: 16.2233413614432
    MaxDiff: 7.45058059692383E-09 Distances: 7441375.70752843 7441375.70752842 7441375.70752842
5 longitude: -147.157742373074 latitude: 16.2233413614432 Distance 7441375.70752843
iterations: 5

นี่คือรหัสที่แก้ไขแล้ว:

class Program
{
    private static LicenseInitializer m_AOLicenseInitializer = new tripoint.LicenseInitializer();

    [STAThread()]
    static void Main(string[] args)
    {
        //ESRI License Initializer generated code.
        m_AOLicenseInitializer.InitializeApplication(new esriLicenseProductCode[] { esriLicenseProductCode.esriLicenseProductCodeStandard },
        new esriLicenseExtensionCode[] { });
        try
        {
            var t = Type.GetTypeFromProgID("esriGeometry.SpatialReferenceEnvironment");
            var srf = Activator.CreateInstance(t) as ISpatialReferenceFactory2;
            var pcs = srf.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_World_AzimuthalEquidistant)
                as IProjectedCoordinateSystem2;
            Debug.Print("{0} {1}", pcs.get_CentralMeridian(true), pcs.LatitudeOfOrigin);
            int max = int.MinValue;
            for (int i = 0; i < 1; i++)
            {
                var iterations = Test(pcs);
                max = Math.Max(max, iterations);
                Debug.Print("iterations: {0}", iterations);
            }
            Debug.Print("max number of iterations: {0}", max);
        }
        catch (Exception ex)
        {
            Debug.Print(ex.Message);
            Debug.Print(ex.StackTrace);
        }
        //ESRI License Initializer generated code.
        //Do not make any call to ArcObjects after ShutDownApplication()
        m_AOLicenseInitializer.ShutdownApplication();
    }
    public static int Test(IProjectedCoordinateSystem2 pcs)
    {
        var pntA = MakePoint(-74.0, 41.0, pcs.GeographicCoordinateSystem);
        var pntB = MakePoint(140.0, 36.0, pcs.GeographicCoordinateSystem);
        var pntC = MakePoint(175.0, -41.0, pcs.GeographicCoordinateSystem);


        //var r = new Random();
        //var pntA = MakeRandomPoint(r, pcs.GeographicCoordinateSystem);
        //var pntB = MakeRandomPoint(r, pcs.GeographicCoordinateSystem);
        //var pntC = MakeRandomPoint(r, pcs.GeographicCoordinateSystem);

        int maxIterations = 100;
        for (int i = 0; i < maxIterations; i++)
        {
            var msg = string.Format("{0} longitude: {1} latitude: {2}", i, pcs.get_CentralMeridian(true), pcs.LatitudeOfOrigin);
            Debug.Print(msg);
            var newCenter = FindCircleCenter(ProjectClone(pntA, pcs), ProjectClone(pntB, pcs), ProjectClone(pntC, pcs));
            var c = ((IClone)newCenter).Clone() as IPoint;
            newCenter.Project(pcs.GeographicCoordinateSystem); // unproject
            //newCenter = MakePoint(-147.1577482, 16.2233394, pcs.GeographicCoordinateSystem);
            var distA = GetGeodesicDistance(newCenter, pntA);
            var distB = GetGeodesicDistance(newCenter, pntB);
            var distC = GetGeodesicDistance(newCenter, pntC);
            var diffAB = Math.Abs(distA - distB);
            var diffBC = Math.Abs(distB - distC);
            var diffAC = Math.Abs(distA - distC);
            var maxDiff = GetMax(new double[] {diffAB,diffAC,diffBC});
            Debug.Print("\tMaxDiff: {0} Distances: {1} {2} {3}",maxDiff, distA, distB, distC);
            if (maxDiff < 0.000001)
            {
                var earthRadius = pcs.GeographicCoordinateSystem.Datum.Spheroid.SemiMinorAxis;
                if (distA > earthRadius * Math.PI / 2.0)
                {
                    newCenter = AntiPode(newCenter);
                }
                else
                {
                    Debug.Print("{0} longitude: {1} latitude: {2} Distance {3}", i, pcs.get_CentralMeridian(true), pcs.LatitudeOfOrigin, distA);
                    return i;
                }
            }
            //Debug.Print("\tDiffs: {0} {1} {2}", diffAB, diffBC, diffAC);

            pcs.set_CentralMeridian(true, newCenter.X);
            pcs.LatitudeOfOrigin = newCenter.Y;
        }
        return maxIterations;
    }

    public static IPoint FindCircleCenter(IPoint a, IPoint b, IPoint c)
    {
        // from http://blog.csharphelper.com/2011/11/08/draw-a-circle-through-three-points-in-c.aspx
        // Get the perpendicular bisector of (x1, y1) and (x2, y2).
        var x1 = (b.X + a.X) / 2;
        var y1 = (b.Y + a.Y) / 2;
        var dy1 = b.X - a.X;
        var dx1 = -(b.Y - a.Y);

        // Get the perpendicular bisector of (x2, y2) and (x3, y3).
        var x2 = (c.X + b.X) / 2;
        var y2 = (c.Y + b.Y) / 2;
        var dy2 = c.X - b.X;
        var dx2 = -(c.Y - b.Y);

        // See where the lines intersect.
        var cx = (y1 * dx1 * dx2 + x2 * dx1 * dy2 - x1 * dy1 * dx2 - y2 * dx1 * dx2)
            / (dx1 * dy2 - dy1 * dx2);
        var cy = (cx - x1) * dy1 / dx1 + y1;

        // make sure the intersection point falls
        // within the projection.
        var earthRadius = ((IProjectedCoordinateSystem)a.SpatialReference).GeographicCoordinateSystem.Datum.Spheroid.SemiMinorAxis;

        // distance is from center of projection
        var dist = Math.Sqrt((cx * cx) + (cy * cy));
        double factor = 1.0;
        if (dist > earthRadius * Math.PI)
        {
            // apply a factor so we don't fall off the edge
            // of the projection
            factor = earthRadius / dist;
        }
        var outPoint = new PointClass() as IPoint;
        outPoint.PutCoords(cx * factor, cy* factor);
        outPoint.SpatialReference = a.SpatialReference;
        return outPoint;
    }

    public static IPoint AntiPode(IPoint pnt)
    {
        if (!(pnt.SpatialReference is IGeographicCoordinateSystem))
            throw new Exception("antipode of non-gcs projection not supported");
        var outPnt = new PointClass() as IPoint;
        outPnt.SpatialReference = pnt.SpatialReference;
        if (pnt.X < 0.0)
            outPnt.X = 180.0 + pnt.X;
        else
            outPnt.X = pnt.X - 180.0;
        outPnt.Y = -pnt.Y;
        return outPnt;
    }

    public static IPoint MakeRandomPoint(Random r, IGeographicCoordinateSystem gcs)
    {
        var latitude = (r.NextDouble() - 0.5) * 180.0;
        var longitude = (r.NextDouble() - 0.5) * 360.0;
        //Debug.Print("{0} {1}", latitude, longitude);
        return MakePoint(longitude, latitude, gcs);
    }
    public static double GetMax(double[] dbls)
    {
        var max = double.MinValue;
        foreach (var d in dbls)
        {
            if (d > max)
                max = d;
        }
        return max;
    }
    public static IPoint MakePoint(IPoint[] pnts)
    {
        double sumx = 0.0;
        double sumy = 0.0;
        foreach (var pnt in pnts)
        {
            sumx += pnt.X;
            sumy += pnt.Y;
        }
        return MakePoint(sumx / pnts.Length, sumy / pnts.Length, pnts[0].SpatialReference);
    }
    public static double GetGeodesicDistance(IPoint pnt1, IPoint pnt2)
    {
        var pc = new PolylineClass() as IPointCollection;
        var gcs = pnt1.SpatialReference as IGeographicCoordinateSystem;
        if (gcs == null)
            throw new Exception("point does not have a gcs");
        ((IGeometry)pc).SpatialReference = gcs;
        pc.AddPoint(pnt1);
        pc.AddPoint(pnt2);
        var t = Type.GetTypeFromProgID("esriGeometry.SpatialReferenceEnvironment");
        var srf = Activator.CreateInstance(t) as ISpatialReferenceFactory2;
        var unit = srf.CreateUnit((int)esriSRUnitType.esriSRUnit_Meter) as ILinearUnit;
        var pcGeodetic = pc as IPolycurveGeodetic;
        return pcGeodetic.get_LengthGeodetic(esriGeodeticType.esriGeodeticTypeGeodesic, unit);
    }

    public static IPoint ProjectClone(IPoint pnt, ISpatialReference sr)
    {
        var clone = ((IClone)pnt).Clone() as IPoint;
        clone.Project(sr);
        return clone;
    }

    public static IPoint MakePoint(double longitude, double latitude, ISpatialReference sr)
    {
        var pnt = new PointClass() as IPoint;
        pnt.PutCoords(longitude, latitude);
        pnt.SpatialReference = sr;
        return pnt;
    }
}

แก้ไข

นี่คือผลลัพธ์ที่ฉันได้รับด้วย esriSRProjCS_WGS1984N_PoleAziEqui

0 90
0 longitude: 0 latitude: 90
    MaxDiff: 1275775.91880553 Distances: 8003451.67666723 7797996.2370572 6727675.7578617
1 longitude: -148.003774863594 latitude: 9.20238223616225
    MaxDiff: 14487.6784785809 Distances: 7439006.46128994 7432752.45732905 7447240.13580763
2 longitude: -147.197808459106 latitude: 16.3073233548167
    MaxDiff: 2.32572609744966 Distances: 7441374.94409209 7441377.26981819 7441375.90768183
3 longitude: -147.157734641831 latitude: 16.2233338760411
    MaxDiff: 7.72997736930847E-08 Distances: 7441375.70752842 7441375.70752848 7441375.7075284
3 longitude: -147.157734641831 latitude: 16.2233338760411 Distance 7441375.70752842

เป็นการบรรจบกันอย่างรวดเร็วที่น่าประทับใจ! (+1)
whuber

คุณควรใช้การฉายภาพระยะห่างแบบ azimuthal ที่มีความซื่อสัตย์ต่อความดีตรงไปตรงมาโดยมีศูนย์กลางที่ศูนย์ใหม่ แต่คุณใช้การฉายภาพโดยมีศูนย์กลางที่ขั้ว N และเปลี่ยนจุดกำเนิดไปที่ศูนย์ใหม่ ดังนั้นจึงอาจเป็นเรื่องบังเอิญที่คุณได้รับคำตอบที่ถูกต้องในกรณีนี้ (อาจเป็นเพราะประเด็นเหล่านี้อยู่ใกล้กัน) มันเป็นการดีที่จะลองด้วยห่างกัน 3 พันกิโลเมตร มีการใช้งานการฉายภาพระยะเวลาเท่ากันของ azimuthal ในmathworks.com/matlabcentral/fileexchange/…
cffk

@ cffk วิธีอื่นที่ฉันเห็นในการสร้างการฉายภาพระยะยาวแบบ azimuthal ที่มีศูนย์กลางอยู่ที่จุดใดจุดหนึ่งคือการใช้วิธีการเดียวกัน แต่ใช้ esriSRProjCS_World_AzimuthalEquidistant แทน esriSRProjCS_WGS1984N_PoleAziEqui ความแตกต่างเพียงอย่างเดียวคือมันอยู่กึ่งกลางที่ 0,0 แทนที่จะเป็น 0,90 (หรือ 0, -90) คุณช่วยแนะนำฉันในการทดสอบกับ mathworks เพื่อดูว่าสิ่งนี้ให้ผลลัพธ์ที่แตกต่างจากการฉาย "ซื่อสัตย์ต่อความดี" หรือไม่?
Kirk Kuykendall

@ KirkKuykendall: ดูภาคผนวกของคำตอบแรกของฉัน
cffk

1
@ KirkKuykendall ดังนั้น ESRI อาจใช้การฉายภาพ "ซื่อสัตย์ต่อความดี" คุณสมบัติหลักที่จำเป็นสำหรับอัลกอริธึมในการทำงานคือระยะทางที่วัดได้จาก "จุดศูนย์กลาง" เป็นจริง และสถานที่ให้บริการนี้เป็นเรื่องง่ายพอที่จะตรวจสอบ (คุณสมบัติ azimuthal ที่เกี่ยวข้องกับจุดศูนย์กลางเป็นที่รองและอาจส่งผลกระทบต่ออัตราการบรรจบกันเท่านั้น)
cffk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.