กำลังคำนวณลองจิจูดที่ถูกต้องเมื่อผ่าน | 180 |?


11

ฉันพยายามพัฒนา "สูตร" เพื่อแก้ไขค่า lat-lng

ฉันใช้ vue-leaflet แต่เมื่อคุณเลื่อนออกไปข้างนอกโลก "แรก" คุณจะได้รับจำนวนมาก มากกว่า +180 หรือต่ำกว่า -180

ตัวอย่างเช่นเมื่อฉันหันไปอเมริกาทางขวา (ทิศตะวันออก) ฉันจะได้รับ lng 215 ในใจฉันจะแก้ไขให้ถูกด้วย 215-360=-145

เช่นเดียวกันเมื่อฉันหันไปทางรัสเซียตะวันออกไปทางซ้าย (ทิศตะวันตก) และฉันได้รับตัวอย่าง -222 ตอนนี้ฉันต้องคำนวณ-222+360=138

อย่างไรก็ตามเนื่องจากโลกไม่มีกำหนดผู้ใช้สามารถเลื่อนไปยังโลกที่ 8 และฉันต้องปรับค่า

เป็นไปได้ไหมที่จะคำนวณลองจิจูดที่ถูกต้อง? (และข้อกำหนดอื่นคือเมื่อผู้ใช้อยู่ในโลกแรก 24 lng ควรยัง 24 lng

คำตอบ:


16

คุณต้องเพิ่ม (หรือลบ) 360 ซ้ำ ๆ ในค่าของคุณจนกว่าจะอยู่ในช่วง -180 - 180 ดังนั้นโดยปกติแล้วจะมีลูปเป็นคู่ดังนี้:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}

สัญญาณรอบทางที่ผิด? ควรเป็น lon + = 360 ในกรณีแรก
JimT

4
คุณสามารถทำได้ด้วยการวนซ้ำเพียงครั้งเดียวที่while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }ฉันไม่ได้ให้ไว้เป็นคำตอบเพราะเวอร์ชันของคุณตรงกับคำอธิบายจริง ๆ ในขณะที่เวอร์ชันของฉันเป็นเพียงการเพิ่มประสิทธิภาพที่น่าจะไม่สร้างความแตกต่างใด ๆ ฉันเก็บไว้เป็นความคิดเห็นเท่านั้นเป็นเครื่องย้ำเตือนว่าสิ่งต่าง ๆ สามารถทำได้หลายวิธีบางอย่างปรับให้เหมาะสมกว่าสิ่งอื่น
อังเดร

2
ฉันไม่คิดว่าฉันจะใช้อันนั้นเพราะใช้การเรียก 2 ฟังก์ชั่นต่อลูปและลูปเพียงอันเดียวของฉันจะถูกเรียกใช้งาน อาจไม่ได้สร้างความแตกต่างในตัวอย่างนี้ แต่นั่นคืออคติของฉัน
Ian Turton

ในขณะที่ดูเหมือนว่าฟังก์ชั่นฟังก์ชั่นคณิตศาสตร์ใน JavaScript ควรจะเห็นมากขึ้นเช่นผู้ประกอบการที่มีสัญลักษณ์ verbose ในแง่นี้เราสามารถเห็น + - และ <แม้ฟังก์ชั่นเช่นกัน แก้ไข: ฉันมีวิธีแก้ปัญหาที่นี่ว่าใช้งานไม่ได้จริง ๆ แล้ว
Andrei

2
คุณทำไม่ได้lon %= 180เหรอ
คดีกองทุนของโมนิกา

15

คำตอบที่หลีกเลี่ยงเงื่อนไขและการเรียกใช้ฟังก์ชัน:

longitude = (longitude % 360 + 540) % 360 - 180

ฉันเขียน microbenchmark อย่างรวดเร็วที่https://jsperf.com/longitude-normalisationและโค้ดที่มีเงื่อนไขดูเหมือนว่าจะเร็วกว่า (ใน Chrome บนเครื่องของฉัน) สำหรับค่าอินพุตที่ 'สมเหตุสมผล' โดยทั่วไปคุณอาจไม่ต้องกังวลล่วงหน้าเกี่ยวกับประสิทธิภาพในการคำนวณขนาดเล็กเช่นนี้ให้น้ำหนักมากขึ้นในการอ่านและความสอดคล้องกับส่วนที่เหลือของรหัสฐานข้อมูลของคุณ

อาจมีความสำคัญมากกว่าในกรณีนี้คือคำถามว่ารหัสของคุณอาจมีค่าที่เข้ามามาก (1e10, Infinity ฯลฯ ) หรือไม่ ถ้าเป็นเช่นนั้นการวนลูปอาจจบลงด้วยการทำงานช้ามากหรือหยุดโปรแกรมของคุณอย่างเงียบ ๆ สิ่งนี้อาจเกิดขึ้นกับการคำนวณที่ทำไว้ใกล้เสาเช่นการพยายามเลื่อนไปทางทิศตะวันออกหรือทิศตะวันตกด้วยระยะทาง (แทนที่จะเป็นมุม) จากเสาอาจส่งผลให้เกิดลองจิจูดไม่ จำกัด


1
น่าสนใจ มาแข่ง jmp แบบมีเงื่อนไขกับหาร FP อืมฉันสงสัยว่า
Joshua

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

1
@ jpmc26: ในกรณีนี้การคาดว่าจะวนซ้ำมากกว่าหนึ่งครั้งนั้นเป็นเรื่องโง่
Joshua

1
ไม่มีการเสียดสี จริง ๆ แล้วฉันไม่รู้ว่ามันจะตกแบบไหน
Joshua

1
@ โจชัวอ๋อฉันก็ไม่แน่ใจเหมือนกัน :) ฉันเพิ่มคำตอบเกี่ยวกับประสิทธิภาพ (และกรณีความล้มเหลวที่เป็นไปได้ของรหัสลูป)
Joe Lee-Moyet

5

หนึ่งในสายการบิน:

normalized = remainder(longitude, 360);

คำอธิบาย: คุณต้องการที่จะรู้ว่าสิ่งที่เหลืออยู่หลังจากที่คุณไม่สนใจการหมุนแบบเต็ม (360 °)

กระบวนการนี้เรียกว่า normalizing

ตัวอย่าง (cpp.sh)


1
สิ่งนี้จะไม่ส่งผลให้มีค่า [0, 360) ไม่ใช่ [-180, 180] ตามที่แชดริกซ์ร้องขอหรือไม่?
ผู้ชายกับหมวก

@TheGuywithTheHat ตรวจสอบตัวอย่างนี้: cpp.sh/7uy2v
อิง

อ่าไม่รู้ว่านี่คือ C ++ ในบริบท Shadrix ของ JavaScript ผมตีความเป็นremainder modulusโมดูลัสใน JS จะส่งผลให้ [0, 360)
ผู้ชายกับหมวก

1
ฉันไม่คิดว่ามันจะได้ผล คุณจะต้องลบผลลัพธ์ iff 360 ผลลัพธ์> 180 ปัญหาที่ฉันเพิ่งรู้ด้วย JavaScript คือ modulo นั้นมีความสมมาตรใน 0 เช่น eg -1 % 3คือ -1 ไม่ใช่ 2 ตามที่จำเป็นสำหรับการทำงานที่นี่ remainderเป็นโซลูชัน C ++ ที่ยอดเยี่ยม แต่น่าเสียดายที่ไม่มีฟังก์ชัน / โอเปอเรเตอร์ใน JS ที่คล้ายกันมากพอที่จะเป็นประโยชน์
ผู้ชายกับหมวก

0

ตัวเลือกอื่น: ลองจิจูด = atan2 (cos (ยาว), sin (ยาว))


1
ดูเหมือนจะไม่ใช่ความคิดที่ดี มันยากที่จะเข้าใจราคาคอมพิวเตอร์และอาจมีข้อผิดพลาดในการปัดเศษ
David Richerby

0

หากภาษาการเขียนโปรแกรมที่คุณใช้รองรับตัวดำเนินการ% (mod) กับหมายเลขทศนิยม (เช่น Python และ Ruby) ฉันขอแนะนำให้ใช้ มิฉะนั้นบางภาษาอื่น ๆ (เช่น C และ C ++) อนุญาตให้คุณใช้ fmod ()

(ไม่ว่าคุณจะใช้โอเปอเรเตอร์ mod ตัวใดโปรดตรวจสอบให้แน่ใจก่อนว่ามันจะทำการ mod กับตัวเลขทศนิยมและมันจะให้คำตอบแบบไม่ลบเสมอมิฉะนั้นคุณจะได้รับความประหลาดใจที่น่ารังเกียจในภายหลังเมื่อหลายคน คะแนน lat / lon ไม่ถูกต้อง)

ใช้มันแบบนี้:

# Put the longitude in the range of [0,360):
longitude %= 360

# Put the longitude in the range of [-180,180):
if longitude >= 180:
    longitude -= 360

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

# Put the longitude in the range of [-180,180):
longitude = (longitude + 180) % 360 - 180

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

แก้ไข:

อืม ... ฉันเพิ่งสังเกตเห็นว่า Javascript ดูเหมือนจะไม่จัดการ%กับค่าลบเช่นฉันคิดว่ามันจะ

ในกรณีดังกล่าวลองใช้สายการบินเดียว:

longitude = (longitude + 36180) % 360 - 180

ที่36180เราเพิ่มคือ 36,000 + 180 36,000 คือการย้ายค่าลบไปยังโดเมนบวกและ 180 คือการเลื่อนไปเพื่อที่เมื่อมัน modded โดย360มันจะอยู่ในช่วง [0,360) . ชิ้น- 180ส่วนเลื่อนกลับไปเป็นช่วง [-180,180)

นี่คืออีกหนึ่งสายการบินหนึ่งที่ไม่พึ่งพา 36,000 เป็นใหญ่พอ:

longitude = (longitude % 360 + 360 + 180) % 360 - 180

longitude % 360 + 360ส่วนหนึ่งจะให้แน่ใจว่าการเข้าพักค่าในโดเมนบวกเมื่อมัน modded 360ในภายหลังโดย ชิ้น+ 180ส่วนเลื่อนไปมาเพื่อที่ว่าเมื่อได้รับการหักลบออก 180 ครั้ง (ด้วย- 180) มันจะอยู่ในช่วงที่ต้องการของ [-180,180]


1
หมายเหตุ: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) และilongitude % 360-> [-359 ... +359]
chux - Reinstate Monica

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