Обчислення правильної довготи, коли вона перевищує | 180 |


11

Я намагаюся розробити "формулу" для виправлення значень lat-lng.

Я використовую vue-листівку, але коли ви переходите за межі "першого" світу, ви отримуєте великі цифри. Понад +180 або менше -180.

Наприклад: коли я рухаюсь до Америки праворуч (східний напрямок), я отримую як lng 215. У своєму розумі я би просто виправив це за допомогою 215-360=-145

Те саме відбувається, коли я рухаюсь до східної Росії вліво (західний напрямок), і я отримую, наприклад, -222. Тепер мені потрібно прорахувати-222+360=138

Однак, оскільки світ невизначений, користувач міг перейти до восьмого світу, і мені довелося коригувати значення.

Чи можна обчислити правильну довготу? (і ще одна вимога - коли користувач знаходиться у першому світі, 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

хоча вони виглядають як функції, функції Math в JavaScript слід розглядати більше як оператори з багатослівними символами. У цьому сенсі ми також можемо бачити + - і навіть <як функції. Редагувати: У мене було рішення, що воно насправді не спрацювало
Андрій

2
Ви не можете зробити lon %= 180?
Фонд позову Моніки

15

Відповідь, яка уникає умовних і функціональних викликів:

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

Я написав швидкий мікро-орієнтир на https://jsperf.com/longitude-normalisation, і умовний код здається, що швидше (в Chrome на моїй машині) для "розумних" діапазонів вхідних значень. Як правило, ви, мабуть, не повинні заздалегідь турбуватися про ефективність таких невеликих обчислень, що надає більшої ваги читабельності та узгодженості з рештою вашої бази даних.

Напевно, важливішим у цьому випадку є питання, чи міг ваш код коли-небудь стикатися з крайніми вхідними значеннями (1e10, Infinity тощо). Якщо так, то зациклення реалізація може в кінцевому підсумку працює дуже повільно або мовчки висить програму. Це може статися при обчисленнях, проведених біля полюсів, наприклад, намагання просунути схід чи захід на деяку відстань (а не кут) від полюса може легко призвести до нескінченної довготи.


1
Цікаво. Давайте змагатимемося за умовний jmp проти FP-поділу. Хммм, дивуюсь.
Джошуа

1
@Joshua Не можна використовувати умовний стрибок. Ви повинні використовувати кілька умовних стрибків , також цикл. (Плюс цикл містить додаткову плаваючу крапку, яка не є вільною.) Скільки ітерацій потрібно циклу, залежить від введення. Таким чином, ви повинні знати щось про дані, щоб переглянути ефективність. Якщо переважна більшість знаходиться в межах бажаного діапазону і вимагає декількох ітерацій, впевнений, цикл додавання може бути швидшим, але це не так очевидно, як пропонує ваш сарказм.
jpmc26

1
@ jpmc26: У цьому випадку очікувати, що минешся довкола циклу не один раз, нерозумно.
Джошуа

1
Сарказму не було. Я насправді не знаю, куди воно впаде.
Джошуа

1
@ Джошуа так, я не був впевнений :) Я додав більше відповіді щодо продуктивності (і потенційного випадку несправності коду циклу)
Джо Лі-Моєт

5

Одноколісний:

normalized = remainder(longitude, 360);

Пояснення: Ви хочете знати, що залишається після того, як ви нехтуєте повними обертаннями (360 °).

Цей процес називається нормалізуючим.

Приклад (cpp.sh)


1
Чи не призведе це до значення [0, 360), а не [-180, 180], як просив Shadrix?
Хлопець із

@TheGuywithTheHat Перевірте цей приклад: cpp.sh/7uy2v
На основі

Ах, не знав, що це C ++. У контексті JavaScript Шадрікса я трактував remainderяк modulus. Модуль в JS призведе до [0, 360).
Хлопець із

1
Я не думаю, що це спрацювало б. Вам потрібно буде відняти результат 360 iff> 180. Ще одна проблема, яку я щойно зрозумів із JavaScript, полягає в тому, що модуль симетричний через 0, наприклад -1 % 3, -1, а не 2, як це було б потрібно для роботи тут. remainderце чудове рішення C ++, але, на жаль, у JS просто немає функції / оператора, що є досить подібним, щоб бути корисним.
Хлопець із

0

Інший варіант: довгота = atan2 (cos (довгий), sin (довгий))


1
Це не здається гарною ідеєю. Це дуже важко зрозуміти, обчислювально дорогий і потенційно може зазнати помилок округлення.
Девід Річербі

0

Якщо мова програмування, яку ви використовуєте, підтримує оператор% (mod) на числах з плаваючою комою (наприклад, Python та Ruby), я рекомендую використовувати його. В іншому випадку деякі інші мови (наприклад, C і C ++) дозволяють використовувати fmod ().

(Незалежно від того, яким оператором ви користуєтеся, переконайтеся, що він буде робити операції з модами над номерами з плаваючою комою, і що він завжди дасть вам негативні відповіді. Інакше ви отримаєте неприємний сюрприз пізніше, коли багато хто з ваших 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Ми додаємо в 36000 + 180. 36000, щоб перемістити від'ємне значення в позитивній області, і 180, щоб зрушити його над тим , що , коли він модом на 360, він буде перебувати в діапазоні [0360) . В - 180зрушення частина його назад в діапазоні [-180,180).

Ось ще одна вкладиш, яка не розраховує на те, що 36 000 є достатньо великими:

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

longitude % 360 + 360Частина гарантуватиме перебування значення в позитивній області , коли вона пізніше мод на 360. У + 180зрушеннях частини її над тим , що , коли він пізніше отримує 180 віднімає з нього (з - 180), він буде перебувати в необхідному діапазоні [-180,180).


1
Примітка: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) і ilongitude % 360-> [-359 ... +359].
chux

@chux - я не знав про це, тому я просто перевірив це, і, здається, ти прав. Дякую, що вказали на це.
JL
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.