Menghitung garis bujur yang benar ketika lebih dari | 180 |?

11

Saya mencoba mengembangkan "formula" untuk memperbaiki nilai lat-lng.

Saya menggunakan selebaran tetapi ketika Anda menjelajah di luar dunia "pertama" Anda mendapatkan angka besar. Lebih dari +180 atau di bawah -180.

Sebagai contoh: ketika saya menggeser Amerika ke kanan (arah timur), saya mendapatkan 215. Dalam pikiran saya, saya hanya akan memperbaikinya dengan 215-360=-145

Hal yang sama adalah ketika saya menggeser rusia timur ke kiri (arah barat) dan saya dapatkan misalnya -222. Sekarang saya perlu menghitung-222+360=138

Namun, karena dunia tidak terbatas, pengguna dapat beralih ke dunia ke-8 dan saya harus menyesuaikan nilainya.

Apakah mungkin menghitung garis bujur yang benar? (dan persyaratan lain adalah ketika pengguna berada di dunia pertama, 24 lng masih harus 24 lng.

Shadrix
sumber

Jawaban:

16

Anda harus berulang kali menambahkan (atau mengurangi) 360 ke nilai Anda hingga nilai itu berada pada kisaran -180 - 180. Jadi biasanya sepasang loop seperti:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}
Ian Turton
sumber
tanda-tanda yang salah? Harus lon + = 360 dalam kasus pertama.
JimT
4
Anda dapat melakukannya hanya dengan satu loop. while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }Saya tidak memberikannya sebagai jawaban karena versi Anda benar-benar cocok dengan penjelasan, sementara versi saya hanya optimasi yang kemungkinan tidak membuat perbedaan. Saya menyimpannya sebagai komentar hanya sebagai pengingat bahwa hal-hal dapat dilakukan dalam berbagai cara, beberapa lebih dioptimalkan daripada yang lain.
Andrei
2
Saya tidak berpikir saya akan pernah menggunakan yang itu karena menggunakan 2 panggilan fungsi per loop dan hanya satu dari loop saya yang akan pernah dijalankan. Mungkin tidak ada bedanya dalam contoh ini, tetapi itu adalah prasangka saya
Ian Turton
sementara mereka terlihat seperti fungsi, fungsi Matematika dalam JavaScript harus dilihat lebih seperti operator dengan simbol verbose. Dalam pengertian ini kita juga dapat melihat + - dan bahkan <sebagai fungsi juga. Sunting: Saya punya solusi di sini yang sebenarnya tidak berfungsi
Andrei
2
Anda tidak bisa melakukannya lon %= 180?
Dana Gugatan Monica
15

Jawaban yang menghindari panggilan kondisional dan fungsi:

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

Saya menulis microbenchmark cepat di https://jsperf.com/longitude-normalisation dan kode kondisional tampaknya lebih cepat (di Chrome di mesin saya) untuk rentang nilai input yang 'masuk akal'. Secara umum Anda mungkin tidak perlu khawatir sebelumnya tentang kinerja dalam perhitungan kecil seperti ini, memberikan bobot lebih untuk keterbacaan dan konsistensi dengan sisa basis kode Anda.

Mungkin yang lebih penting dalam hal ini adalah pertanyaan apakah kode Anda dapat menemukan nilai input ekstrem (1e10, Infinity, dll.). Jika demikian, implementasi pengulangan dapat berjalan sangat lambat atau diam-diam menggantung program Anda. Ini mungkin terjadi dengan perhitungan yang dilakukan di dekat kutub, misalnya mencoba menjelajah timur atau barat dengan jarak tertentu (bukan sudut) dari kutub dapat dengan mudah menghasilkan bujur yang tak terbatas.

Joe Lee-Moyet
sumber
1
Menarik. Mari kita balapan jmp bersyarat terhadap FP FP. Hmmm saya bertanya-tanya.
Yosua
1
@ Yosua Anda tidak dapat menggunakan lompatan bersyarat. Anda harus menggunakan beberapa lompatan kondisional , alias sebuah loop. (Ditambah loop berisi floating point tambahan, yang tidak gratis.) Berapa banyak iterasi yang dibutuhkan loop tergantung pada input. Jadi, Anda harus tahu sesuatu tentang data untuk melihat kinerja. Jika sebagian besar berada di dekat kisaran yang diinginkan dan memerlukan beberapa iterasi, tentu, loop tambahan mungkin lebih cepat, tetapi itu tidak sejelas yang disarankan sarkasme Anda.
jpmc26
1
@ jpmc26: Dalam hal ini, mengharapkan untuk berkeliling berulang kali itu konyol.
Yosua
1
Tidak ada sarkasme. Saya sebenarnya tidak tahu ke mana itu akan jatuh.
Yosua
1
@Joshua ya, saya juga tidak yakin :). Saya menambahkan lebih banyak ke jawaban tentang kinerja (dan kasus kegagalan potensial dari kode loop)
Joe Lee-Moyet
5

Satu-liner:

normalized = remainder(longitude, 360);

Penjelasan: Anda ingin tahu apa yang tersisa setelah Anda mengabaikan rotasi penuh (360 °).

Proses ini disebut normalisasi.

Contoh (cpp.sh)

Berdasarkan
sumber
1
Tidakkah ini menghasilkan nilai [0, 360), bukan [-180, 180] seperti yang diminta Shadrix?
The Guy with The Hat
@TheGuywithTheHat Periksa contoh ini: cpp.sh/7uy2v
Berbasis
Ah, tidak tahu ini C ++. Dalam konteks JavaScript Shadrix, saya menafsirkannya remaindersebagai modulus. Modulus dalam JS akan menghasilkan [0, 360).
The Guy with The Hat
1
Saya tidak berpikir itu akan berhasil. Anda perlu mengurangi 360 hasil iff> 180. Masalah lain yang baru saya sadari dengan JavaScript adalah modulo simetris pada 0, mis. -1 % 3Adalah -1, bukan 2 sebagaimana diperlukan agar dapat bekerja di sini. remainderadalah solusi C ++ yang bagus, tapi sayangnya tidak ada fungsi / operator di JS yang cukup mirip untuk berguna.
The Guy with The Hat
0

Pilihan lain: bujur = atan2 (cos (panjang), sin (panjang))

Andres
sumber
1
Ini sepertinya bukan ide yang bagus. Sangat sulit untuk dipahami, mahal secara komputasi dan berpotensi mengalami kesalahan pembulatan.
David Richerby
0

Jika bahasa pemrograman yang Anda gunakan mendukung operator% (mod) pada angka floating point (seperti Python dan Ruby), saya sarankan menggunakan itu. Jika tidak, beberapa bahasa lain (seperti C dan C ++) memungkinkan Anda untuk menggunakan fmod ().

(Operator mod mana pun yang Anda gunakan, pastikan sebelumnya bahwa ia akan melakukan operasi mod pada angka floating-point, dan itu akan selalu memberi Anda jawaban yang tidak negatif. Kalau tidak, Anda akan mendapatkan kejutan yang tidak menyenangkan nantinya ketika banyak dari Anda poin lat / lon tidak benar.)

Gunakan seperti ini:

# 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

Jika Anda lebih suka melakukan semuanya dalam satu baris:

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

Pendekatan-pendekatan ini tidak memiliki loop, sehingga mereka akan menormalkan nilai-nilai bujur tanpa perlu berulang kali menambah atau mengurangi, tidak peduli berapa kali pengamatan Anda telah berputar di sekitar bumi.

Edit:

Hmmm ... Saya baru saja memperhatikan bahwa Javascript sepertinya tidak menangani %dengan nilai negatif seperti yang saya kira.

Jika demikian, coba satu-baris ini:

longitude = (longitude + 36180) % 360 - 180

Yang 36180kami tambahkan adalah 36.000 + 180. 36.000 adalah untuk memindahkan nilai negatif ke domain positif, dan 180 adalah untuk menggesernya sehingga ketika dimodekan oleh 360, itu akan berada di kisaran [0,360) . Bagian - 180itu menggesernya kembali ke kisaran [-180.180).

Ini satu kalimat lagi, yang tidak bergantung pada 36.000 cukup besar:

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

Bagian longitude % 360 + 360akan memastikan nilai tetap di domain positif ketika nanti diubah oleh 360. Bagian + 180itu menggesernya sehingga ketika nanti dikurangi menjadi 180 (dengan - 180), itu akan berada dalam kisaran yang diinginkan [-180.180).

JL
sumber
1
Catatan: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) dan ilongitude % 360-> [-359 ... +359].
chux - Reinstate Monica
@ chux - Saya tidak tahu tentang itu, jadi saya hanya mengujinya, dan tampaknya Anda benar. Terima kasih telah menunjukkannya.
JL