กำลังคำนวณจุดตัดของสองวง?


29

ฉันพยายามหาวิธีการหาจุดร่วมของวงกลมสองวงบนพื้นผิวโลกด้วยวิธีทางคณิตศาสตร์โดยให้ละติจูด Lat / Lon เป็นศูนย์กลางและรัศมีของแต่ละจุด

ตัวอย่างเช่นกำหนด:

  • Lat / Lon (37.673442, -90.234036) รัศมี 107.5 NM
  • Lat / Lon (36.109997, -90.953669) รัศมี 145 NM

ฉันควรหาจุดตัดกันสองจุดโดยหนึ่งในนั้นคือ (36.948, -088.158)

มันง่ายมากที่จะแก้ปัญหานี้บนระนาบราบ แต่ฉันไม่มีประสบการณ์ใด ๆ ในการแก้สมการบนทรงกลมที่ไม่สมบูรณ์เช่นพื้นผิวโลก


1
หากรัศมีของคุณทั้งหมดมีขนาดเล็ก (น้อยกว่าหลายกิโลเมตร) พื้นโลกจะแบนในระดับนี้และคุณอาจเลือกการฉายที่เรียบง่ายและแม่นยำและทำการคำนวณแบบยุคลิด ตรวจสอบให้แน่ใจว่าคุณคำนวณจุดตัดไปยังตำแหน่งทศนิยมมากกว่าสามตำแหน่ง - ความไม่แน่นอนในตำแหน่งทศนิยมที่สามมีขนาดใหญ่เท่ากับรัศมีของคุณ!
whuber

1
ฉันควรจะเพิ่มหน่วยเป็นรัศมีเหล่านั้นใน NM ดังนั้นมันยังคงเป็นระยะทางที่สั้นเมื่อเทียบกับพื้นผิวโลก แต่ใหญ่กว่าสองสามกิโลเมตร ระดับนั้นส่งผลต่อการบิดเบือนอย่างไร ฉันพยายามหาวิธีแก้ปัญหาที่แม่นยำน้อยกว่า <1nm ดังนั้นจึงไม่จำเป็นต้องแม่นยำมาก ขอบคุณ!
จะ

ทั้งหมดนี้เป็นสิ่งที่ดีที่จะรู้เพราะมันแสดงให้เห็นว่าคุณสามารถใช้แบบจำลองทรงกลมของโลก - แบบจำลองวงรีที่ซับซ้อนกว่านั้นไม่จำเป็น
whuber

@whuber นี่แสดงถึงปัญหาที่อาจได้รับการปรับปรุงใหม่ได้หรือไม่: ค้นหาจุดตัดของทรงกลม 3จุดที่หนึ่งในโลกทรงกลมเป็นโลกและอีกสองแห่งอยู่ในจุดที่มีรัศมีตามลำดับหรือไม่
Kirk Kuykendall

@ Kirk ใช่นั่นคือวิธีที่จะทำโดยสมมติว่าเป็นแบบจำลองทรงกลมของพื้นผิวโลก หลังจากการคำนวณเบื้องต้นที่ลดสิ่งนี้ให้เป็นกรณีพิเศษของปัญหา Trilateration ในแบบ 3 มิติ (การคำนวณจำเป็นต้องแปลงระยะทางตามส่วนโค้งทรงกลมเป็นระยะทางตามคอร์ดทรงกลมซึ่งกลายเป็นรัศมีของทรงกลมเล็ก ๆ สองแห่ง)
whuber

คำตอบ:


21

มันไม่ได้ยากบนทรงกลมมากไปกว่าบนเครื่องบินเมื่อคุณจำได้

  1. ประเด็นในคำถามคือจุดตัดร่วมกันของสามทรงกลม: ทรงกลมที่อยู่ใต้ตำแหน่ง x1 (บนพื้นผิวโลก) ของรัศมีที่กำหนด, ทรงกลมที่อยู่กึ่งกลางใต้ตำแหน่ง x2 (บนพื้นผิวโลก) ของรัศมีที่กำหนดและโลกเอง ซึ่งเป็นทรงกลมที่มีค่ากึ่งกลางที่ O = (0,0,0) ของรัศมีที่กำหนด

  2. จุดตัดของสองทรงกลมแรกที่มีพื้นผิวโลกเป็นวงกลมซึ่งกำหนดระนาบสองระนาบ จุดตัดร่วมกันของทั้งสามทรงกลมจึงอยู่ที่จุดตัดของระนาบทั้งสองนั่นคือเส้น

ดังนั้นปัญหาจะลดลงเป็นการตัดเส้นกับทรงกลมซึ่งเป็นเรื่องง่าย


นี่คือรายละเอียด อินพุตคือจุด P1 = (lat1, lon1) และ P2 = (lat2, lon2) บนพื้นผิวโลกซึ่งถือว่าเป็นทรงกลมและรัศมีสอง r1 และ r2 ที่สอดคล้องกัน

  1. แปลงพิกัดละติจูด (lat, lon) เป็น (x, y, z) ตามปกติเพราะเราอาจเลือกหน่วยการวัดที่โลกมีรัศมีหน่วย

    x = cos(lon) cos(lat)
    y = sin(lon) cos(lat)
    z = sin(lat).
    

    ในตัวอย่าง P1 = (-90.234036 องศา, 37.673442 องศา) มีพิกัดทางภูมิศาสตร์ที่ x1 = (-0.00323306, -0.7915, 0.61116) และ P2 = (-90.953669 องศา, 36.109997 องศา) มีพิกัดทางภูมิศาสตร์ x2 = (-0.0134464, , 0.589337)

  2. แปลง radii r1 และ r2 (ซึ่งวัดตามทรงกลม) เป็นมุมตามทรงกลม ตามคำนิยามหนึ่งไมล์ทะเล (NM) คือ 1/60 องศาของส่วนโค้ง (ซึ่งคือ pi / 180 * 1/60 = 0.0002908888 เรเดียน) ดังนั้นในมุม

    r1 = 107.5 / 60 Degree = 0.0312705 radian
    r2 = 145 / 60 Degree = 0.0421788 radian
    
  3. เนื้อที่วงกลมรัศมี r1 รอบ X1 เป็นจุดตัดของพื้นผิวโลกที่มีที่ยุคลิดทรงกลมของบาปรัศมี (r1) ศูนย์กลางที่ cos (r1) * x1

  4. ระนาบที่กำหนดโดยจุดตัดของทรงกลมของรัศมีบาป (r1) รอบ cos (r1) * x1 และพื้นผิวโลกตั้งฉากกับ x1 และผ่านจุด cos (r1) x1 ดังนั้นสมการของมันคือ x.x1 = cos (r1) ("." หมายถึงผลิตภัณฑ์ dot ปกติ ); เช่นเดียวกันกับระนาบอื่น จะมีจุดที่ไม่ซ้ำกัน x0 บนจุดตัดของระนาบทั้งสองนั่นคือการรวมกันเชิงเส้นของ x1 และ x2 กำลังเขียน x0 = a x1 + b * x2 สองสมการระนาบคือ

    cos(r1) = x.x1 = (a*x1 + b*x2).x1 = a + b*(x2.x1)
    cos(r2) = x.x2 = (a*x1 + b*x2).x2 = a*(x1.x2) + b
    

    การใช้ความจริงที่ว่า x2.x1 = x1.x2 ซึ่งฉันจะเขียนเป็น q จะได้รับการแก้ปัญหา (ถ้ามี)

    a = (cos(r1) - cos(r2)*q) / (1 - q^2),
    b = (cos(r2) - cos(r1)*q) / (1 - q^2).
    

    ในตัวอย่างการรันฉันคำนวณ a = 0.973503 และ b = 0.0260194

    เห็นได้ชัดว่าเราต้องการ q ^ 2! = 1 ซึ่งหมายความว่า x1 และ x2 ไม่สามารถเป็นจุดเดียวกันหรือคะแนนตรงกันข้าม

  5. ทีนี้ประเด็นอื่น ๆ ทั้งหมดในแนวการตัดกันของระนาบทั้งสองนั้นแตกต่างจาก x0 โดยพหุคูณของเวกเตอร์ n ซึ่งตั้งฉากกันกับระนาบทั้งสอง ผลิตภัณฑ์ข้าม

    n = x1~Cross~x2
    

    งานที่มีให้ไม่ใช่ n ไม่ใช่ศูนย์: อีกครั้งซึ่งหมายความว่า x1 และ x2 ไม่ได้เกิดขึ้นพร้อมกันหรือไม่ตรงกันข้าม (เราจำเป็นต้องระมัดระวังในการคำนวณผลิตภัณฑ์ครอสด้วยความแม่นยำสูงเพราะมันเกี่ยวข้องกับการลบด้วยการยกเลิกจำนวนมากเมื่อ x1 และ x2 อยู่ใกล้กัน) ในตัวอย่าง n = (0.0272194, -0.00631254, -0.00803124) .

  6. ดังนั้นเราจึงหาจุดสองจุดของรูปแบบ x0 + t * n ซึ่งอยู่บนพื้นผิวโลกนั่นคือความยาวเท่ากับ 1 ความยาวความยาวกำลังสองเท่ากับ 1:

    1 = squared length = (x0 + t*n).(x0 + t*n) = x0.x0 + 2t*x0.n + t^2*n.n = x0.x0 + t^2*n.n
    

    คำที่มี x0.n จะหายไปเนื่องจาก x0 (เป็นการรวมกันเชิงเส้นของ x1 และ x2) ตั้งฉากกับ n ทั้งสองวิธีแก้ไขได้ง่าย ๆ

    t = sqrt((1 - x0.x0)/n.n)
    

    และลบ เรียกร้องให้มีความแม่นยำสูงอีกครั้งเพราะเมื่ออยู่ใกล้กับ x1 และ x2 x0.x0 นั้นใกล้เคียงกับ 1 มากทำให้สูญเสียความแม่นยำของจุดลอยตัว ในตัวอย่าง t = 1.07509 หรือ t = -1.07509 จุดตัดสองจุดจึงเท่ากัน

    x0 + t*n = (0.0257661, -0.798332, 0.601666)
    x0 - t*n = (-0.0327606, -0.784759, 0.618935)
    
  7. ในที่สุดเราอาจแปลงโซลูชันเหล่านี้กลับเป็น (lat, lon) โดยแปลง geocentric (x, y, z) เป็นพิกัดทางภูมิศาสตร์:

    lon = ArcTan(x,y)
    lat = ArcTan(Sqrt[x^2+y^2], z)
    

    สำหรับลองจิจูดใช้ค่าส่งคืนอาร์กแทนเจนต์แบบทั่วไปในช่วง -180 ถึง 180 องศา (ในแอปพลิเคชันการคำนวณฟังก์ชันนี้ใช้ทั้ง x และ y เป็นอาร์กิวเมนต์แทนที่จะเป็นอัตราส่วน y / x บางครั้งเรียกว่า "ATan2")

    ฉันได้รับสองวิธีแก้ปัญหา (-88.151426, 36.989311) และ (-92.390485, 38.238380) ที่แสดงในรูปเป็นจุดสีเหลือง

รูป 3 มิติ

แกนแสดงพิกัดทางภูมิศาสตร์ (x, y, z) แพทช์สีเทาเป็นส่วนหนึ่งของพื้นผิวโลกจาก -95 ถึง -87 องศาลองจิจูด, ละติจูด 33 ถึง 40 องศา (ทำเครื่องหมายปิดด้วยหนึ่งองศา graticule) พื้นผิวโลกถูกทำให้โปร่งใสบางส่วนเพื่อแสดงทรงกลมทั้งสาม ความถูกต้องของการแก้ปัญหาที่คำนวณนั้นเห็นได้ชัดว่าจุดสีเหลืองอยู่ที่จุดตัดของทรงกลม


บิลนี่ยอดเยี่ยมมาก การชี้แจงหนึ่งที่คุณสามารถเพิ่มได้ขึ้นอยู่กับบุคคลที่พยายามนำไปใช้ ในขั้นตอนที่ 2 คุณไม่ได้ให้การแปลงจากองศาเป็นเรเดียนอย่างชัดเจน
Jersey Andy

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

8

รูปวงรีกรณี:

ปัญหานี้เป็นลักษณะทั่วไปของหนึ่งในการค้นหาขอบเขตทางทะเลที่กำหนดเป็น "เส้นมัธยฐาน" และมีวรรณกรรมมากมายในหัวข้อนี้ ทางออกของปัญหานี้คือการใช้ประโยชน์จากโปรเจกชัน azimuthal ที่เท่ากัน:

  1. เดาที่จุดแยก
  2. ฉายจุดฐานสองจุดโดยใช้จุดตัดที่เดานี้เป็นจุดศูนย์กลางของการฉายภาพแอซิมัทที่มีระยะเท่ากัน
  3. แก้ปัญหาทางแยกในพื้นที่ฉาย 2d
  4. จุดแยกใหม่อยู่ไกลเกินไปจากจุดเก่ากลับไปที่ขั้นตอนที่ 2

อัลกอริธึมนี้มาบรรจบกันเป็นสองส่วนและให้ผลเฉลยที่แม่นยำบนรี (ต้องมีความแม่นยำในกรณีของเขตแดนทางทะเลเนื่องจากเป็นตัวกำหนดสิทธิ์ในการตกปลาน้ำมันและแร่ธาตุ)

สูตรจะได้รับในมาตรา 14 แห่งgeodesics บนทรงรีของการปฏิวัติ รูปวงรีฉาย azimuthal เท่ากันให้บริการโดยGeographicLib รุ่น MATLAB สามารถใช้ได้ที่ ประมาณการ Geodesic สำหรับทรงรี


+1 นั่นเป็นเอกสารที่น่าทึ่ง: คำอธิบายที่สุภาพของคุณที่นี่ไม่ยุติธรรม
whuber

ดูกระดาษสั้นของฉันเกี่ยวกับ geodesics "อัลกอริทึมสำหรับ geodesics" dx.doi.org/10.1007/s00190-012-0578-z (ดาวน์โหลดฟรี!) บวก errata และภาคผนวกสำหรับเอกสารเหล่านี้geographiclib.sf.net/geod-addenda.html
cffk

1

นี่คือรหัส R ที่จะทำ:

p1 <- cbind(-90.234036, 37.673442) 
p2 <- cbind(-90.953669, 36.109997 )

library(geosphere)
steps <- seq(0, 360, 0.1)
c1 <- destPoint(p1, steps, 107.5 * 1852)
c2 <- destPoint(p2, steps, 145 * 1852)

library(raster)
s1 <- spLines(c1)
s2 <- spLines(c2)

i <- intersect(s1, s2)
coordinates(i)

#        x        y
# -92.38241 38.24267
# -88.15830 36.98740

s <- bind(s1, s2)
crs(s) <- "+proj=longlat +datum=WGS84"
plot(s)
points(i, col='red', pch=20, cex=2)

1

ต่อจากคำตอบของ @ whuberต่อไปนี้เป็นโค้ด Java บางส่วนที่มีประโยชน์ด้วยเหตุผลสองประการ:

  • มันเน้น gotcha เกี่ยวกับ ArcTan (สำหรับ Java และภาษาอื่น ๆ ?)
  • มันจัดการกรณีขอบที่เป็นไปได้รวมถึงกรณีที่ไม่ได้กล่าวถึงในคำตอบของ @ whuber

มันไม่ได้รับการปรับให้เหมาะสมหรือสมบูรณ์ (ฉันได้ออกคลาสที่ชัดเจนเช่นนี้Point) แต่ควรทำเคล็ดลับ

public static List<Point> intersection(EarthSurfaceCircle c1, EarthSurfaceCircle c2) {

    List<Point> intersections = new ArrayList<Point>();

    // project to (x,y,z) with unit radius
    UnitVector x1 = UnitVector.toPlanar(c1.lat, c1.lon);
    UnitVector x2 = UnitVector.toPlanar(c2.lat, c2.lon);

    // convert radii to radians:
    double r1 = c1.radius / RadiusEarth;
    double r2 = c2.radius / RadiusEarth;

    // compute the unique point x0
    double q = UnitVector.dot(x1, x2);
    double q2 = q * q;
    if (q2 == 1) {
        // no solution: circle centers are either the same or antipodal
        return intersections;
    }
    double a = (Math.cos(r1) - q * Math.cos(r2)) / (1 - q2);
    double b = (Math.cos(r2) - q * Math.cos(r1)) / (1 - q2);
    UnitVector x0 = UnitVector.add(UnitVector.scale(x1, a), UnitVector.scale(x2, b));

    // we only have a solution if x0 is within the sphere - if not,
    // the circles are not touching.
    double x02 = UnitVector.dot(x0, x0);
    if (x02 > 1) {
        // no solution: circles not touching
        return intersections;
    }

    // get the normal vector:
    UnitVector n = UnitVector.cross(x1, x2);
    double n2 = UnitVector.dot(n, n);
    if (n2 == 0) {
        // no solution: circle centers are either the same or antipodal
        return intersections;
    }

    // find intersections:
    double t = Math.sqrt((1 - UnitVector.dot(x0, x0)) / n2);
    intersections.add(UnitVector.toPolar(UnitVector.add(x0, UnitVector.scale(n, t))));
    if (t > 0) {
        // there's only multiple solutions if t > 0
        intersections.add(UnitVector.toPolar(UnitVector.add(x0, UnitVector.scale(n, -t))));
    }
    return intersections;
}

นอกจากนี้ที่สำคัญให้สังเกตการใช้atan2- มันเป็นสิ่งที่ตรงกันข้ามกับสิ่งที่คุณคาดหวังจากคำตอบของ @ whuber (ฉันไม่รู้ว่าทำไม แต่ใช้งานได้):

    public static Point toPolar(UnitVector a) {
        return new Point(
                Math.toDegrees(Math.atan2(a.z, Math.sqrt(a.x * a.x + a.y * a.y))),
                Math.toDegrees(Math.atan2(a.y, a.x)));          
    }

0

กำลังทำงานรหัส 'R' สำหรับคำตอบ @wuhber

P1 <- c(37.673442, -90.234036)
P2 <- c(36.109997, -90.953669) 

#1 NM nautical-mile is 1852 meters
R1 <- 107.5
R2 <- 145

x1 <- c(
  cos(deg2rad(P1[2])) * cos(deg2rad(P1[1])),  
  sin(deg2rad(P1[2])) * cos(deg2rad(P1[1])),
  sin(deg2rad(P1[1]))
);

x2 <- c(
  cos(deg2rad(P2[2])) * cos(deg2rad(P2[1])),
  sin(deg2rad(P2[2])) * cos(deg2rad(P2[1])),
  sin(deg2rad(P2[1]))
);

r1 = R1 * (pi/180) * (1/60)
r2 = R2 * (pi/180) * (1/60)

q = dot(x1,x2)
a = (cos(r1) - cos(r2) * q) / (1 - q^2)
b = (cos(r2) - cos(r1) * q)/ (1 - q^2)

n <- cross(x1,x2)

x0 = a*x1 + b*x2


t = sqrt((1 - dot(x0, x0))/dot(n,n))

point1 = x0 + (t * n)
point2 = x0 - (t * n)

lat1 = rad2deg(atan2(point1[2] ,point1[1]))
lon1= rad2deg(asin(point1[3]))
paste(lat1, lon1, sep=",")

lat2 = rad2deg(atan2(point2[2] ,point2[1]))
lon2 = rad2deg(asin(point2[3]))
paste(lat2, lon2, sep=",")

-1

หากหนึ่งในวงกลมนั้นคือ Nortstar แสดงว่ามีวิธีที่ง่ายที่สุดสำหรับหน่วยทรงกลม

คุณสามารถวัดละติจูดของคุณด้วย Nortstar จากนั้นคุณมีตำแหน่งสัมพัทธ์บนทรงกลมนี้ v1 (0, sin (la), cos (la)) คุณรู้ตำแหน่ง (มุม) ของดาวดวงอื่น (star2) จาก almanach v2 (sin (lo2) * cos (la2), sin (la2), cos (lo2) * cos (la2)) เวกเตอร์ของมัน จากสมการของทรงกลม

lo2 เป็นลองจิจูดลองจิจูด มันไม่รู้ไม่รู้

มุมระหว่างคุณกับ star2 คุณสามารถวัดได้ด้วย (m) และคุณก็รู้แล้วว่าผลิตภัณฑ์ชั้นในของเวกเตอร์สองหน่วยคือ cos (มุม) ของระหว่าง cos (m) = dot (v1, v2) u สามารถคำนวณได้ในขณะนี้ลองจิจูดลองจิจูด (lo2) LO2 = acos ((cos (เมตร) -sin (LA) * sin (LA2)) / (cos (LA) * cos (LA2)))

หลังจากทั้งหมดคุณเพิ่มลองจิจูดที่แท้จริงของ star2 เป็น lo2 (หรือย่อยขึ้นอยู่กับด้านตะวันตกของคุณหรือตะวันออก) lo2 ตอนนี้เป็นลองจิจูดของคุณ

ขออภัยภาษาอังกฤษของฉันฉันไม่เคยเรียนภาษานี้เลย


2 สิ่ง: Northstar หมายถึงดาวขั้วโลก

อื่น เนื่องจากมุมที่วัดในแนวนอนค่อนข้างจำเป็นต้องมีการแก้ไข 90 มุมเสมอ มันใช้ได้กับมุม m ด้วย

ps: มุมจริงหมายถึง: ตำแหน่งดาว - การแก้ไขเวลา


ไม่ชัดเจนว่าวิธีนี้ตอบคำถามได้อย่างไร
whuber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.