Skip to main content

Двійкові мапи OsmAnd - .obf

Вступ

Розмова про *.travel.obf, *.wiki.obf, *.roads.obf, ..

Багато запитань стосуються вмісту та проблем з даними мап у застосунку. Ця тема розкриває деякі технічні деталі внутрішнього формату даних та обробки даних. Це може бути цікаво для не-розробників, які знайомі зі структурою даних OSM.

Офлайн дані мап OsmAnd містяться у файлах 'obf'. Файли 'obf' мають складну структуру і можуть складатися з багатьох частин. Настійно рекомендується зберігати розмір файлів менше 2 Гб. Наразі файли obf можуть мати багато частин, що складаються з декількох частин POI, декількох частин даних маршрутизації, декількох частин мап, декількох частин транспорту та декількох частин адресних даних. Цей список може бути розширений у майбутньому. Щоб об'єднати, розділити або видалити деякі частини з файлу obf, використовуйте консольний інструмент 'binary_inspector', що надається з OsmAndMapCreator.

  • Частина POI, Транспорт
  • Частина мапи
  • Частина адреси

З: Як mapcreator генерує свій список усіх місць, які пізніше з'являться в офлайн пошуку адрес OsmAnd? Які об'єкти детально використовуються для цього? Які вузли з тегом place включені, а які виключені?

В: Усі місця, які видно в OsmAnd як міста, беруться з вузлів, що мають тег "place" https://wiki.openstreetmap.org/wiki/Place. Наразі використовуються city, town, suburb, village, hamlet.

З: Як mapcreator обробляє полігон області, який задано через відношення з boundary=administrative? Як ви пов'язуєте місце, задане як вузол, з його межею, коли воно присутнє в даних OSM?

В: Простіше кажучи: наразі це працює за назвою. Mapcreator намагається відвідати всі межі та створює замкнену (!) межу з відношення або з окремих шляхів і пов'язує її лише з однією назвою. Після цього він намагається зіставити *place* з *boundary name* за допомогою алгоритму *contains of*. Також є додаткова перевірка, чи містить ця межа місце. Якщо є багато меж різного admin_level з однаковою назвою (що містять одна одну, наприклад, район/місто/регіон мають однакову назву), буде обрано найвищий admin_level з точним збігом. TODO Тут має бути більше деталей (про райони міста...) ...

З: Де знаходиться документація, що описує, який admin level є правильним для побудови асоціації з певним вузлом місця? Які країни віддають перевагу якому admin level?

В: Наразі асоціація між відношенням admin_level та admin_centre не використовується. Оскільки лише кілька відношень надають цю інформацію.

З: Як MapCreator знає, яка вулиця належить до якого місця? Чи є різні випадки, коли задано полігон межі, а коли його немає?

В: Існує багато стратегій перевірки, і вони пріоритезуються в такому порядку:

  • Найважливішими є місця та їхні межі. Щоб алгоритм управління вулицями працював правильно, межі, що відповідають місцям, мають бути правильними. Якщо вулиця належить до багатьох меж, вона буде зареєстрована у всіх відповідних місцях.
  • тег is_in (він застарів). Отже, якщо вулиця має тег is_in, він буде розібраний і розділений комою, і вулиця буде приєднана до всіх відповідних міст (за точним збігом назви). (ПЕРЕВІРИТИ: базова перевірка, чи вулиця знаходиться в радіусі міста?)
  • Якщо вулиця не належить до жодної межі (неправильно замкнені межі можуть бути проблемою тут), вона намагається знайти найближче/найбільше місто та зареєструвати вулицю в цьому місті (іноді вона реєструється в місті на відстані 1 км і пропускає найближчий хутір на відстані лише 100 м).

Остання частина дуже неточна. Ось чому багато вулиць приєднуються до сусіднього міста.

У налаштуваннях MapCreator у вас є ще п'ять налаштувань для суфіксів вулиць, масштабування, плавності та рендерингу... які детальні ефекти ви можете досягти за допомогою кожного з них? Чи використовуються ці налаштування насправді?

Інструменти

  • OsmAndMapCreator може відображати, які вулиці пов'язані з яким містом (контекстне меню -> Показати адресу). Локальні файли obf мають бути присутніми та налаштованими в Налаштуваннях.
  • Інструмент Binary inspector може показати список вулиць для кожного міста. Запустіть інструмент без параметрів, щоб побачити можливі параметри.
  • Наразі всі індексні файли містять gen.log. Переглядаючи файл журналу, ви можете знайти помилки в процесі створення мапи, і це може дати відповідь, чому деякі вулиці не знаходяться в належному місці адресного індексу.

Частина адреси - робочий процес

Існують такі відношення:

місто -> 0..1 межа

межа -> 0..** місто (використовується для визначення передмістя міста)

перебирати всі вузли Osm і реєструвати як міста, якщо присутній тег = PLACE:

  • витягти міста (TOWN, CITY).
  • витягти села (все інше).

перебирати всі відношення та шляхи з type=boundary і реєструвати всі межі:

  • межа називається Сутністю (шлях або відношення) з тегом 'boundary=administrative' або з тегом 'place=...'.
  • межа має бути admin_level > 4 або не мати admin_level.
  • межа не завжди пов'язана з містом (або штатом, ...).
  • межа може мати член 'admin_center', 'label', що вказує на вузол міста.
  • межа точно збігається за назвою з вузлом міста, і вузол міста потрапляє в межу.
  • межа збігається за початком, кінцем або підрядком за назвою з вузлом міста, і вузол міста потрапляє в межу.

Багато меж можуть бути пов'язані з одним містом. Ось порядок, за яким береться найважливіша межа і пов'язується з містом:

  • Межа точно збігається за назвою і має тег place.
  • Межа точно збігається за назвою і має admin_level 8 > 7 > 6 > 9 > 10 > 5... або нічого.
  • Межа має збіг admin_id.
  • Усі інші випадки, включаючи сортування admin_level.

якщо місто не має призначеної межі, то всі межі, які не мають центрів міст і містять це місто, будуть перевірені, і буде призначена межа з admin_level >=7.

для кожної межі створити список міст, які знаходяться всередині неї.

перебирати всі відношення та знаходити адреси (Postal_Addresses):

відношення з типом тегу "address", і є типом адреси "house" або "a6".

шукати пов'язане відношення Street та члени house.

спробувати знайти місто для вулиці та місто для адреси будинку.

шукати міста (ми вже повинні були знайти їх на попередніх кроках!).

якщо у нас є місто та вулиця, зареєструвати їх у базі даних:

для реєстрації вулиці, див.: зареєструвати вулицю для міста

якщо вулиця зареєстрована, і ми обробляємо вулицю:

перебирати всіх членів відношення:

  • знайти вулицю -> записати вузли вулиці в базу даних
  • знайти будинок -> записати будинок до вулиці

якщо вулиця зареєстрована, і ми обробляємо будинок:

  • знайти номер будинку
  • знайти межу будинку: якщо знайдено, зберегти: будівля для вулиці

зареєструвати вулицю (вулиця, місцезнаходження вулиці (los), міста):

Примітка: ми можемо зареєструвати вулицю в кількох містах = це означає, що вулиця може знаходитись у вкладених областях, передмісті, місті, хуторі тощо... Для кожної області ми хочемо зареєструвати вулицю, в якій вона знаходиться.

для кожного міста:

знайти існуючу реєстрацію вулиці в межах міста:

якщо вулиця існує:

  • якщо частина міста невідома -> оновити частину міста існуючої вулиці
  • спробувати знайти частину міста для нашої вулиці та знову знайти вулицю

якщо вулиця не існує: (може змінитися після пошуку)

  • зареєструвати вулицю для міста, частини міста, місцезнаходження та назви вулиці

знайтиАбоЗареєструвати вулицю

  • знайти близькі міста до вулиці
  • якщо вулиця знаходиться в межах міста, додати місто для пошуку
  • якщо місто не знайдено за межею, знайти найближче місто для вулиці
  • зареєструвати вулицю: для знайдених міст

перебирати всі вузли, потім шляхи, потім відношення (перебирати основну сутність)

знайти шляхи - інтерполяції:

  • для кожної інтерполяції знайтиАбоЗареєструвати вулицю з місцезнаходженням інтерполяції
  • для кожних двох вузлів створити будівлю, що представляє інтерполяцію

для будь-якої сутності знайти тег addr:housenumber та addr:street (також може бути знову інтерполяція вузлів!!!):

  • пропустити, якщо будівля для цієї сутності вже існує!
  • знайтиАбоЗареєструвати вулиці для вулиці
  • знайти номер будинку
  • якщо номер будинку містить '-', спробувати створити інтерпольований номер будинку (відсутній latlon2?)
  • якщо номер будинку містить '/', спробувати знайти другу вулицю addr:street2 --> здається, тільки для RU osm:
  • існує більше варіацій для цього: adr:housenumber2, addr2:street, addr2:housenumber тощо...
  • для кожної вулиці зберегти існуючий будинок

для шляху з тегом - name & тегом - highway, але без addr:housenumber та addr:street:

  • Примітка: це можуть бути шляхи для автомобілів, з назвами (highway, або щось подібне)
  • пропустити, якщо така вулиця вже існує
  • знайтиАбоЗареєструвати вулицю для міста
  • записати вузли для кожної знайденої вулиці в кожному місті

Кожне відношення з "postal_code", зберегти для подальшого використання.

Примітка: це не включає address:type = pc та addr:postalcode

обробка поштових індексів:

  • для кожного збереженого відношення postal_code
  • для кожного члена будівлі оновити postal_code

записати індекс:

розділити міста на: міста+містечка, передмістя (передмістя з тегом is_in), села (не місто чи містечко)

записати міста+містечка, використовуючи передмістя

прочитати вулиці з міст+містечок + відповідних передмість для кожного містечка

  • тут може бути більше вулиць з однаковою назвою для одного міста, в такому випадку ми намагаємося знайти частину міста для вулиці (передмістя), де знаходиться вулиця. Не повинно бути більше вулиць з однаковою назвою в межах однієї частини міста!

для кожної вулиці

  • для кожної будівлі зареєструвати/створити/знайти поштовий індекс, зареєструвати вулицю

записати села

  • те саме, що й містечка...

записати витягнуті поштові індекси та їхні вулиці