Compare commits

..

59 Commits

Author SHA1 Message Date
zyphlar
f8e2eb037f Fix conf path 2025-06-20 15:20:10 +00:00
zyphlar
7591e99cef Fix MwmDiff tool building 2025-06-19 12:51:08 +00:00
zyphlar
8584d6634e pastk4: s14>13 for poor 2025-06-19 12:26:02 +00:00
zyphlar
b8b529ca78 WIP Laos test gen 2025-06-19 12:21:14 +00:00
zyphlar
486babe27e Revert "Upgrade all high_f2 to high"
This reverts commit 2e7713568a.
2025-06-17 11:04:38 +00:00
zyphlar
fedbc2d57f pastk3: all > f2, poor > f4, high_f2 > s16 2025-06-17 11:04:19 +00:00
zyphlar
2e7713568a Upgrade all high_f2 to high 2025-06-16 14:18:48 +00:00
zyphlar
dfaac372ee Add all missing as poor 2025-06-16 14:17:19 +00:00
zyphlar
15fd7a0bd5 Upgrade poor to 100m f2 s14 2025-06-16 14:15:38 +00:00
zyphlar
467e97b231 Algeria Central to poor 2025-06-16 14:15:08 +00:00
zyphlar
2075b79dee Add new mwms as poor
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-16 14:12:41 +00:00
zyphlar
55d162f354 WIP Tune isolines profiles
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-16 10:18:44 +00:00
zyphlar
2fa1714575 WIP [cmake] Fix cppjansson build
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-16 10:06:44 +00:00
zyphlar
9a2dc676a7 Update generator scripts for docker/prod
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:34:00 +00:00
zyphlar
4bcf5a8f98 Add docker run script
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:04:21 +00:00
Konstantin Pastbin
6afa6a8476 Increase Features threads from 12 to 16
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-06-11 01:04:21 +00:00
zyphlar
b04bda4ff2 Update tools/unix/docker_maps_generator.sh
Signed-off-by: zyphlar <zyphlar@noreply.codeberg.org>
2025-06-11 01:04:21 +00:00
zyphlar
da150c87a5 Tweaks, get subway hooks proper
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:04:21 +00:00
Konstantin Pastbin
e17e122f0b Update subways path
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-06-11 01:04:21 +00:00
Konstantin Pastbin
96d9cbf1fa Update INI
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-06-11 01:04:21 +00:00
zyphlar
cf2fea216e Fix s3 variables
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:04:21 +00:00
zyphlar
2c9a85d5a3 Map generation mostly working, but slow and not doing full planet with add-ins yet
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:04:21 +00:00
zyphlar
42c30cb775 On-server tweaks
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:04:21 +00:00
zyphlar
c58f915063 Add files to automatically generate maps with Docker
Signed-off-by: zyphlar <zyphlar@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
d754bf0e0a 4 threads for Taiwan_North search indexer.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
622a5bf3bf Avoid py dependencies.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
cecb9d9200 Do not inherit "oneway" and "surface" from Relation.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
f731ff0612 Fixed hgt tile's grid traversal.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Alexander Borsuk
2524d074b4 Quotes support for CSV parser
Signed-off-by: Alexander Borsuk <me@alex.bio>
2025-06-11 01:04:21 +00:00
Viktor Govako
d56432e484 Borders 2025-06-11 01:04:21 +00:00
Viktor Govako
04b3c01816 Check default max speeds consistency.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
8dc633bfd9 Added SrtmTileManager::GetBilinearHeight.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
23f8a73ef6 Print SRTM tiles usage.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
099ecde058 Added maxspeed OSM related warnings.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
6d6140ee33 Fixed getting url bug.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
623c4ed9fe Fixed altitude tiles cache bug.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
b4cc6b140b Fixed races.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
fca2a64a80 Added SrtmTileManager::GetTriangleHeight.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
81c06f1ae7 Use pre-downloaded wiki descriptions.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
2bfcf0089b Updated scripts.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
0d08a53224 Added "tr" description language.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
980bd36d02 Stop running StageMWM when any country was failed.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
e16c8f3591 Get all URLs.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
727c0db4b0 Enable StageDescriptions.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
3b44a61f9d Set boost addr2line option for stacktrace.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:21 +00:00
Viktor Govako
3195450519 Fixed some 'double comparison' tests.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:20 +00:00
Viktor Govako
58f7c24620 Crash dump in topography_generator_tool.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:20 +00:00
Alexander Borsuk
bcf65ee2e5 Use release with debug info for easier crashlog analysis
Note: use tools/unix/build_omim.sh -R
2025-06-11 01:04:20 +00:00
vng
fc859c65d5 [tools] Build Release with Debug info with a script
TODO: Support this configuration in python generator build
2025-06-11 01:04:20 +00:00
vng
794f0f01aa Added LTO and -Ofast.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
2025-06-11 01:04:20 +00:00
Alexander Borsuk
032183414b Fixed reading SRTM from squashfs 2025-06-11 01:04:20 +00:00
vng
aab883171d Added ASTER tif into SRTM hgt converter.
Signed-off-by: vng <viktor.govako@gmail.com>
2025-06-11 01:04:20 +00:00
Konstantin Pastbin
9d31c7f37f [planet] Update map data to 250602
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-06-10 16:13:03 +02:00
Mihail Mitrofanov
1f950d2c0b [android] Prevent crash when direction arrow view is missing in landscape mode
Signed-off-by: Mihail Mitrofanov <mitrofanov@bitrix.ru>
2025-06-10 14:15:23 +02:00
Konstantin Pastbin
111bb0b94c [fdroid] Release notes 2025.06.10
Signed-off-by: Konstantin Pastbin <konstantin.pastbin@gmail.com>
2025-06-10 13:23:30 +02:00
Codeberg Translate
5567e011db [strings] Update from Codeberg Translate
Co-authored-by: AnanasSux <ananassux@noreply.codeberg.org>
Co-authored-by: Cayenne79 <cayenne79@noreply.codeberg.org>
Co-authored-by: Codeberg Translate <translate@codeberg.org>
Co-authored-by: Fjuro <git@alius.cz>
Co-authored-by: Priit Jõerüüt <jrtcdbrg@noreply.codeberg.org>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate Translation Memory <noreply-mt-weblate-translation-memory@weblate.org>
Co-authored-by: gedankenstuecke <gedankenstuecke@noreply.codeberg.org>
Co-authored-by: loscati <loscati@noreply.codeberg.org>
Co-authored-by: matheusgomesms <matheusgomesms@noreply.codeberg.org>
Co-authored-by: openfab <openfab@noreply.codeberg.org>
Co-authored-by: oxisol <oxisol@noreply.codeberg.org>
Co-authored-by: phama <phama@noreply.codeberg.org>
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/de/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/fi/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/tr/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/zh_Hant/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/cs/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/de/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/et/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/fi/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/fr/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/it/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/ja/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/pt_BR/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/tr/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/zh_Hans/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/zh_Hant/
Translate-URL: https://translate.codeberg.org/projects/comaps/appstore-descriptions/de/
Translate-URL: https://translate.codeberg.org/projects/comaps/fdroid-app-description/fi/
Translate-URL: https://translate.codeberg.org/projects/comaps/google-play-descriptions/fi/
Translate-URL: https://translate.codeberg.org/projects/comaps/google-play-descriptions/pt_BR/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/de/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/fi/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/tr/
Translation: CoMaps/Android - Map Feature Types
Translation: CoMaps/Android UI Strings
Translation: CoMaps/Apple AppStore description
Translation: CoMaps/F-Droid app description
Translation: CoMaps/Google Play and Huawei AppGallery descriptions
Translation: CoMaps/iOS - Map Feature Types
2025-06-09 21:22:16 +00:00
Codeberg Translate
6cafc1da75 [strings] Update from Codeberg Translate
Co-authored-by: Codeberg Translate <translate@codeberg.org>
Co-authored-by: Priit Jõerüüt <jrtcdbrg@noreply.codeberg.org>
Co-authored-by: gpesquero <gpesquero@noreply.codeberg.org>
Co-authored-by: jeanbaptisteC <jeanbaptistec@noreply.codeberg.org>
Co-authored-by: oxisol <oxisol@noreply.codeberg.org>
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/es/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/ja/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/zh_Hans/
Translate-URL: https://translate.codeberg.org/projects/comaps/android-typestrings/zh_Hant/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/es/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/et/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/fr/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/ja/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/zh_Hans/
Translate-URL: https://translate.codeberg.org/projects/comaps/android/zh_Hant/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/es/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/ja/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/zh_Hans/
Translate-URL: https://translate.codeberg.org/projects/comaps/ios-typestrings/zh_Hant/
Translation: CoMaps/Android - Map Feature Types
Translation: CoMaps/Android UI Strings
Translation: CoMaps/iOS - Map Feature Types
2025-06-09 09:47:00 +00:00
Mihail Mitrofanov
5eff4f56ca [android] Allow customization of the first (OM logo / About) button 2025-06-09 11:46:56 +02:00
Jean-Baptiste
d38ffe2fa8 [android] Migrate login screen to Material components
Signed-off-by: Jean-Baptiste Charron <jeanbaptiste.charron@outlook.fr>
2025-06-09 11:41:10 +02:00
133 changed files with 5023 additions and 3359 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@ Makefile.Release
object_script.*.Debug
object_script.*.Release
compile_commands.json
*.local.*
stxxl.errlog
stxxl.log

View File

@@ -31,6 +31,7 @@ if (NOT WITH_SYSTEM_PROVIDED_3PARTY)
set(JANSSON_WITHOUT_TESTS ON)
add_subdirectory(jansson/jansson/)
target_include_directories(jansson INTERFACE "${PROJECT_BINARY_DIR}/3party/jansson/jansson/include")
add_library(jansson::jansson ALIAS jansson)
# Add gflags library.
set(GFLAGS_BUILD_TESTING OFF)

View File

@@ -94,6 +94,11 @@ if (PLATFORM_WIN)
)
endif()
# Try fast native arch.
if (PLATFORM_LINUX)
add_compile_options(-march=native)
endif()
# Built-in CMake configurations: Debug, Release, RelWithDebInfo, MinSizeRel
if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
add_definitions(-DDEBUG)
@@ -103,12 +108,29 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
elseif (${CMAKE_BUILD_TYPE} MATCHES "Rel")
add_definitions(-DRELEASE)
if (NOT MSVC)
add_compile_options(-Ofast) # Also enables -ffast-math
add_compile_options(-Ofast $<$<CXX_COMPILER_ID:GNU>:-flto=auto>) # Also enables -ffast-math
endif()
else()
message(FATAL_ERROR "Unknown build type: " ${CMAKE_BUILD_TYPE})
endif()
if (${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
add_compile_options(-fno-omit-frame-pointer)
endif()
# Linux GCC LTO plugin fix.
if (PLATFORM_LINUX AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_BUILD_TYPE MATCHES "^Rel"))
# To force errors if LTO was not enabled.
add_compile_options(-fno-fat-lto-objects)
# To fix ar and ranlib "plugin needed to handle lto object".
string(REGEX MATCH "[0-9]+" GCC_MAJOR_VERSION ${CMAKE_CXX_COMPILER_VERSION})
file(GLOB_RECURSE plugin /usr/lib/gcc/*/${GCC_MAJOR_VERSION}/liblto_plugin.so)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> --plugin ${plugin} qcs <TARGET> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> --plugin ${plugin} <TARGET>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> --plugin ${plugin} qcs <TARGET> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> --plugin ${plugin} <TARGET>")
endif()
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
if (PLATFORM_LINUX OR PLATFORM_ANDROID)

View File

@@ -1,10 +1,8 @@
Erster CoMaps Release!
Was ist neu im Vergleich zu Organic Maps:
OpenStreetMap-Daten vom 15. Mai
OSM Login jetzt über den Webbrowser
Der halbtransparente Hintergrund in der U-Bahn-Ansicht wurde entfernt
Größe der lokalen Karte beim ersten Karten download anzeigen
Der Metaserver wurde durch eine feste Liste an Kartenservern ersetzt
• Der Nachtmodus schaltet jetzt besser um, auch wenn kein GPS-Signal da ist
• OpenStreetMap Daten vom 2. Juni
• Neue Einstellungsoption zum Ändern oder Ausblenden der "Über CoMaps" Schaltfläche ganz links
Routen als GPS Track speichern
Qingdao Metro, Gärtnereien, Leitplanken, Leitern, Studios, Tanzsäle, Feuerstellen und Stundenhotels hinzugefügt
• transparente Navigationsleiste im Light Mode
Mastodon und Bluesky Kontaktoptionen für POIs und im OSM-Editor hinzugefügt
Anzeige der Kompassgradzahl in der Richtungspfeilansicht
• Übersetzungen aktualisiert
• Rebranding das Logo ist noch vorläufig

View File

@@ -1,11 +1,8 @@
Initial CoMaps release!
Changes from the Organic Maps upstream:
OpenStreetMap data as of May 15
login to OSM account via a web browser
removed semi-transparent background in Subway layer
replaced metaserver with a static map servers list
add local map size to the startup download screen
• improved auto night mode switch when there is no location fix
• fix incorrect map info when tapping on a not downloaded region
• OpenStreetMap data as of June 2
• add a setting to change the leftmost button or hide it
save built routes as tracks
add Qingdao metro, plant nurseries, highway guard rails, ladders, studios, dance venues, firepits, love hotels
transparent system navigation bar in the light mode
add Mastodon and Bluesky contact options to POIs and OSM editor
display Azimuth angle in direction arrow view
• update translations
• rebranding - the logo is provisional still

View File

@@ -1,12 +0,0 @@
Lanzamiento inicial de CoMaps
Cambios respecto a la versión de Organic Maps:
• Datos nuevos al 15 de mayo
• Inicio de sesión a OSM a través de navegador
• Eliminado fondo semitransparente en la capa de Metro
• Sustitución del metaserver por lista estática de servidores
• Añadido tamaño del mapa local al inicio
• Mejora del cambio automático al modo nocturno al no conocerse ubicación
• Correcciones de fallos
• Actualización de traducciones
• Cambio de branding con logo provisional

View File

@@ -0,0 +1 @@
Helppo karttanavigointi - Löydä lisää matkaltasi - Yhteisön voimin

View File

@@ -1 +1 @@
CoMaps - Vaella, pyöräile, autoile ilman verkkoyhteyttä yksityisesti
CoMaps - Patikoi, pyöräile, autoile ilman verkkoyhteyttä yksityisesti

View File

@@ -1,11 +1,8 @@
Première version de CoMaps!
Changements par rapport à Organic Maps:
Données OpenStreetMap du 15 mai
Connexion au compte OSM via le navigateur
Retrait du fond semi-transparent sur la couche Métro
Remplacement du metaserveur par une liste statique de serveurs
• Ajout de la taille de la carte locale au premier démarrage
• Amélioration du mode nuit automatique
• Correction de la suggestion de téléchargements de cartes
• Données OpenStreetMap du 02 juin
• Ajout d'une option pour personnaliser le bouton tout à gauche sur l'écran principal
Ajout de la possibilité d'enregistrer un itinéraire en tant que traces GPS
Ajout du métro de Qingdao, et divers objets sur la carte
Support de la barre de navigation transparent en mode clair
Ajout des tags Mastodon et Bluesky sur les lieux et dans l'éditeur
• Affichage de l'azimut
• Mise à jour des traductions
• Rebranding - le logo est encore provisoire

View File

@@ -0,0 +1,8 @@
• Data di OpenStreetmap fino a giugno 2°
• Nuova impostazione per cambiare o modificare la positione del tasto sinistra
• Salvare i percorsi costruiti come tracce
• È stato aggiunto: metropolitana di Qingdao, giardinaggi, guardrail, scale, studio,
sala da ballo, focolari, love hotel
• Barra di navigatione transparente di sisteme in moda luce
• Aggiungi le opzioni di contatto Mastodon e Bluesky ai POI e all'editor di OSM
• Visualizza l'angolo di azimut nella freccia di direzione

View File

@@ -1,11 +0,0 @@
Pierwsze wydanie CoMaps!
Zmiany w stosunku do Organic Maps:
• dane OSM z 15.05,
• logowanie do OSM przez przeglądarkę,
• usunięto półprzezroczyste tło w warstwie Metra,
• zastąpiono metaserver statyczną listą serwerów map,
• dodano rozmiar mapy do ekranu pobierania przy uruchamianiu,
• poprawiono przełączanie trybu nocnego bez lokalizacji,
• poprawiono niepoprawne informacje o mapie po dotknięciu niepobranego regionu,
• zaktualizowano tłumaczenia,
• rebranding - logo wciąż tymczasowe.

View File

@@ -1,9 +1,8 @@
Lançamento inicial do CoMaps!
Alterações em relação ao Organic Maps:
Dados do OSM de 15/05
Login na conta OSM por meio de autenticação no navegador
Remoção do fundo semitransparente na camada Metrô
Substituição do metaserver por uma lista estática de servidores de mapas
Melhoria na alternância automática do modo noturno quando não há localização
• Dados do OSM de 2/06
• Adicionada uma configuração para alterar ou ocultar o botão mais à esquerda
Salve rotas construídas como trilhas
Adicionado metrô de Qingdao, viveiros de plantas, guarda-corpos de rodovias, escadas, estúdios, casas de dança, fogueiras e motéis
Barra de navegação do sistema transparente no modo claro
Adicionadas opções de contato Mastodon e Bluesky aos POIs e ao editor OSM
Exibição de ângulo de azimute na visualização de seta de direção
• Novas traduções
• Rebranding - O logo ainda é provisório

View File

@@ -1,9 +0,0 @@
Lançamento inicial do CoMaps!
Alterações em relação ao Organic Maps:
• Dados do OSM de 15/05
• Login na conta OSM através de um navegador web auth
• Removido o fundo semi-transparente na camada do Metro
• Substituído o metaserver por uma lista estática de servidores de mapas
• Melhoria na mudança automática do modo noturno quando não há localização
• Novas traduções
• Rebranding - logótipo ainda provisório

View File

@@ -0,0 +1,7 @@
• карты OpenStreetMap от 2 июня
• настройка для изменения функции левой кнопки или её скрытия
• сохранение построенных маршрутов в виде треков
• добавлены: метро в Qingdao, питомники растений, отбойники на шоссе, постоянные лестницы-стремянки, студии, места для танцев, кострища, отели любви
• прозрачная полоска с системными кнопками (в светлом режиме)
• в объекты на карте (а также в их редактор) добавлены Mastodon и Bluesky контакты
• к стрелке направления на выбранный объект добавлен азимут

View File

@@ -0,0 +1 @@
Helppo karttanavigointi - Löydä lisää matkaltasi - Yhteisön voimin

View File

@@ -0,0 +1,45 @@
Um aplicativo de mapas gratuito e de código aberto, liderado pela comunidade e baseado em dados do OpenStreetMap, reforçado pelo compromisso com a transparência, privacidade e sem fins lucrativos.
Junte-se à comunidade e ajude a criar o melhor aplicativo de mapas.
• Use o aplicativo e divulgue-o.
• Envie feedback e relate problemas.
• Atualize os dados do mapa no aplicativo ou no site do OpenStreetMap.
<i>Seu feedback e avaliações 5 estrelas são o nosso melhor suporte!</i>
‣ <b>Simples e refinado</b>: recursos essenciais e fáceis de usar que simplesmente funcionam.
‣ <b>Foco offline</b>: Planeje e navegue em sua viagem ao exterior sem a necessidade de sinal de celular, pesquise pontos de referência durante uma caminhada distante, etc. Todas as funções do aplicativo foram projetadas para funcionar offline.
‣ <b>Respeitando a privacidade</b>: O aplicativo foi projetado com a privacidade em mente - não identifica pessoas, não rastreia e não coleta informações pessoais. Livre de anúncios.
‣ <b>Economiza bateria e espaço</b>: Não esgota a bateria como outros aplicativos de navegação. Mapas compactos economizam espaço precioso no seu celular.
‣ <b>Gratuito e desenvolvido pela comunidade</b>: Pessoas como você ajudaram a desenvolver o aplicativo adicionando locais ao OpenStreetMap, testando e dando feedback sobre os recursos, além de contribuir com suas habilidades de desenvolvimento e recursos financeiros.
‣ <b>Tomada de decisões e finanças abertas e transparentes, sem fins lucrativos e totalmente de código aberto.</b>
‣ Simples e sofisticado: recursos essenciais e fáceis de usar que simplesmente funcionam.
‣ Foco offline: Planeje e navegue em sua viagem ao exterior sem a necessidade de sinal de celular, pesquise pontos de referência durante uma caminhada distante, etc. Todas as funções do aplicativo foram projetadas para funcionar offline.
‣ Respeito à privacidade: O aplicativo foi projetado com a privacidade em mente - não identifica pessoas, não rastreia e não coleta informações pessoais. Livre de anúncios.
‣ Economiza bateria e espaço: Não consome bateria como outros aplicativos de navegação. Mapas compactos economizam espaço precioso no seu celular.
‣ Gratuito e desenvolvido pela comunidade: Pessoas como você ajudaram a desenvolver o aplicativo adicionando lugares ao OpenStreetMap, testando e dando feedback sobre os recursos e contribuindo com dinheiro e habilidades de desenvolvimento.
‣ Tomada de decisões e finanças abertas e transparentes, sem fins lucrativos e totalmente de código aberto.
Principais recursos:
• Mapas detalhados para download com locais que não estão disponíveis em muitos mapas comerciais
• Modo ao ar livre com trilhas destacadas, acampamentos, fontes de água, picos, curvas de nível, etc.
• Trilhas para caminhada e ciclovias
• Pontos de interesse como restaurantes, postos de gasolina, hotéis, lojas, pontos turísticos e muito mais
• Pesquise por nome, endereço ou categoria de ponto de interesse
• Navegação com anúncios de voz para caminhada, ciclismo ou direção
• Marque seus lugares favoritos com um único toque
• Sincronização com iCloud para seus favoritos e trilhas
• Artigos offline da Wikipédia
• Camada e direções de transporte público de metrô
• Gravação de trilhas
• Exporte e importe favoritos e trilhas nos formatos KML, KMZ e GPX
• Modo escuro para usar à noite
• Aprimore os dados do mapa para todos usando um editor básico integrado
• Suporte para Android Auto
Por favor, reporte problemas com o aplicativo, sugira ideias e junte-se à nossa comunidade no site <b><i>comaps.app</i></b>.
<b>A Liberdade Chegou</b>
Descubra sua jornada, navegue pelo mundo com privacidade e comunidade em primeiro lugar!

View File

@@ -0,0 +1 @@
Fácil navegação - Descubra mais sobre sua jornada - Desenvolvido pela comunidade

View File

@@ -0,0 +1 @@
CoMaps - Navegue privadamente

View File

@@ -36,6 +36,7 @@ import androidx.annotation.StyleRes;
import androidx.annotation.UiThread;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
@@ -100,9 +101,9 @@ import app.organicmaps.settings.DrivingOptionsActivity;
import app.organicmaps.settings.RoadType;
import app.organicmaps.settings.SettingsActivity;
import app.organicmaps.settings.UnitLocale;
import app.organicmaps.universalbuttons.UniversalButton;
import app.organicmaps.universalbuttons.UniversalButtonsHolder;
import app.organicmaps.universalbuttons.UniversalToggleButton;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftButtonsHolder;
import app.organicmaps.leftbutton.LeftToggleButton;
import app.organicmaps.util.Config;
import app.organicmaps.util.LocationUtils;
import app.organicmaps.util.PowerManagment;
@@ -132,9 +133,10 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static app.organicmaps.location.LocationState.FOLLOW;
import static app.organicmaps.location.LocationState.FOLLOW_AND_ROTATE;
import static app.organicmaps.location.LocationState.LOCATION_TAG;
import static app.organicmaps.universalbuttons.UniversalButtonsHolder.BUTTON_ADD_PLACE_CODE;
import static app.organicmaps.universalbuttons.UniversalButtonsHolder.BUTTON_RECORD_TRACK_CODE;
import static app.organicmaps.universalbuttons.UniversalButtonsHolder.BUTTON_SETTINGS_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_ADD_PLACE_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_HELP_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_RECORD_TRACK_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_SETTINGS_CODE;
import static app.organicmaps.util.PowerManagment.POWER_MANAGEMENT_TAG;
public class MwmActivity extends BaseMwmFragmentActivity
@@ -208,7 +210,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
private int mNavBarHeight;
private UniversalButtonsHolder buttonsHolder;
private LeftButtonsHolder buttonsHolder;
private PlacePageViewModel mPlacePageViewModel;
private MapButtonsViewModel mMapButtonsViewModel;
@@ -611,12 +613,12 @@ public class MwmActivity extends BaseMwmFragmentActivity
if (activityResult.getResultCode() == Activity.RESULT_OK)
{
Intent data = activityResult.getData();
if (data != null && data.hasExtra(UniversalButtonsHolder.KEY_PREF_UNIVERSAL_BUTTON))
if (data != null && data.hasExtra(MwmActivity.this.getString(R.string.pref_left_button)))
{
MapButtonsController mMapButtonsController = (MapButtonsController) getSupportFragmentManager().findFragmentById(R.id.map_buttons);
if (mMapButtonsController != null)
{
mMapButtonsController.reloadUniversalButton(buttonsHolder.getActiveButton());
mMapButtonsController.reloadLeftButton(buttonsHolder.getActiveButton());
}
}
}
@@ -823,9 +825,35 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void prepareNavigationButtons()
{
buttonsHolder = UniversalButtonsHolder.getInstance(this);
buttonsHolder.registerDefaultUniversalButtons(this);
buttonsHolder.registerButton(new UniversalButton()
buttonsHolder = LeftButtonsHolder.getInstance(this);
buttonsHolder.registerButton(new LeftButton()
{
@Override
public String getCode()
{
return BUTTON_HELP_CODE;
}
@Override
public String getPrefsName()
{
return getString(R.string.help);
}
@Override
public void drawIcon(FloatingActionButton imageView)
{
imageView.setImageResource(R.drawable.ic_question_mark);
}
@Override
public void onClick(FloatingActionButton left)
{
Intent intent = new Intent(MwmActivity.this, HelpActivity.class);
MwmActivity.this.startActivity(intent);
}
});
buttonsHolder.registerButton(new LeftButton()
{
@Override
public String getCode()
@@ -846,12 +874,12 @@ public class MwmActivity extends BaseMwmFragmentActivity
}
@Override
public void onClick(FloatingActionButton universalButtonView)
public void onClick(FloatingActionButton left)
{
onAddPlace();
}
});
buttonsHolder.registerButton(new UniversalButton()
buttonsHolder.registerButton(new LeftButton()
{
@Override
public String getCode()
@@ -872,13 +900,13 @@ public class MwmActivity extends BaseMwmFragmentActivity
}
@Override
public void onClick(FloatingActionButton universalButtonView)
public void onClick(FloatingActionButton left)
{
onOpenSettings();
}
});
buttonsHolder.registerButton(new UniversalToggleButton()
buttonsHolder.registerButton(new LeftToggleButton()
{
private boolean isRecording = TrackRecorder.nativeIsTrackRecordingEnabled();
@@ -906,7 +934,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
imageView.setImageResource(R.drawable.ic_track_recording_off);
int color = isRecording
? Color.parseColor("#0057ff")
? ContextCompat.getColor(MwmActivity.this, R.color.active_track_recording)
: ThemeUtils.getColor(MwmActivity.this, R.attr.iconTint);
ColorStateList colorStateList = ColorStateList.valueOf(color);
@@ -914,10 +942,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
}
@Override
public void onClick(FloatingActionButton universalButtonView)
public void onClick(FloatingActionButton left)
{
onTrackRecordingOptionSelected();
drawIcon(universalButtonView);
drawIcon(left);
}
});
}
@@ -928,7 +956,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
if (mPreviousMapLayoutMode != layoutMode)
{
MapButtonsController mapButtonsController = new MapButtonsController();
mapButtonsController.setUniversalButton(buttonsHolder.getActiveButton());
mapButtonsController.setLeftButton(buttonsHolder.getActiveButton());
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction().replace(R.id.map_buttons, mapButtonsController);

View File

@@ -6,7 +6,6 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.ScrollView;
@@ -24,14 +23,16 @@ import app.organicmaps.util.Utils;
import app.organicmaps.util.WindowInsetUtils.ScrollableContentInsetsListener;
import app.organicmaps.util.concurrency.ThreadPool;
import app.organicmaps.util.concurrency.UiThread;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
public class OsmLoginFragment extends BaseMwmToolbarFragment
{
private ProgressBar mProgress;
private Button mLoginButton;
private Button mLostPasswordButton;
private MaterialButton mLoginButton;
private MaterialButton mLostPasswordButton;
private TextInputEditText mLoginInput;
private TextInputEditText mPasswordInput;
@@ -51,7 +52,7 @@ public class OsmLoginFragment extends BaseMwmToolbarFragment
mPasswordInput = view.findViewById(R.id.osm_password);
mLoginButton = view.findViewById(R.id.login);
mLostPasswordButton = view.findViewById(R.id.lost_password);
Button registerButton = view.findViewById(R.id.register);
MaterialButton registerButton = view.findViewById(R.id.register);
registerButton.setOnClickListener((v) -> Utils.openUrl(requireActivity(), Constants.Url.OSM_REGISTER));
mProgress = view.findViewById(R.id.osm_login_progress);
final String dataVersion = DateUtils.getShortDateFormatter().format(Framework.getDataVersion());

View File

@@ -6,9 +6,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -22,15 +20,17 @@ import app.organicmaps.util.WindowInsetUtils;
import app.organicmaps.util.concurrency.ThreadPool;
import app.organicmaps.util.concurrency.UiThread;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.imageview.ShapeableImageView;
import com.google.android.material.textview.MaterialTextView;
import java.text.NumberFormat;
public class ProfileFragment extends BaseMwmToolbarFragment
{
private View mUserInfoBlock;
private TextView mEditsSent;
private TextView mProfileName;
private ImageView mProfileImage;
private MaterialTextView mEditsSent;
private MaterialTextView mProfileName;
private ShapeableImageView mProfileImage;
private ProgressBar mProfileInfoLoading;
@Nullable

View File

@@ -0,0 +1,14 @@
package app.organicmaps.leftbutton;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public interface LeftButton
{
String getCode();
String getPrefsName();
default void drawIcon(FloatingActionButton imageView) {}
default void onClick(FloatingActionButton leftButtonView) {}
}

View File

@@ -0,0 +1,96 @@
package app.organicmaps.leftbutton;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceManager;
import app.organicmaps.R;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class LeftButtonsHolder
{
private static volatile LeftButtonsHolder instance;
public static final String DISABLE_BUTTON_CODE = "disable";
public static final String BUTTON_HELP_CODE = "help";
public static final String BUTTON_SETTINGS_CODE = "settings";
public static final String BUTTON_ADD_PLACE_CODE = "add-place";
public static final String BUTTON_RECORD_TRACK_CODE = "record-track";
private static final String DEFAULT_BUTTON_CODE = BUTTON_HELP_CODE;
private final String leftButtonPreferenceKey;
private final SharedPreferences prefs;
private final Map<String, LeftButton> availableButtons = new LinkedHashMap<>();
private LeftButtonsHolder(Context context)
{
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.leftButtonPreferenceKey = context.getString(R.string.pref_left_button);
initDisableButton(context);
}
public void registerButton(LeftButton button)
{
availableButtons.put(button.getCode(), button);
}
@Nullable
public LeftButton getActiveButton()
{
String activeButtonCode = prefs.getString(leftButtonPreferenceKey, DEFAULT_BUTTON_CODE);
if (!TextUtils.isEmpty(activeButtonCode))
return availableButtons.get(activeButtonCode);
else
return null;
}
public Collection<LeftButton> getAllButtons()
{
return availableButtons.values();
}
public static LeftButtonsHolder getInstance(Context context)
{
LeftButtonsHolder localInstance = instance;
if (localInstance == null)
{
synchronized (LeftButtonsHolder.class)
{
localInstance = instance;
if (localInstance == null)
{
instance = localInstance = new LeftButtonsHolder(context);
}
}
}
return localInstance;
}
private void initDisableButton(Context context)
{
availableButtons.put(DISABLE_BUTTON_CODE, new LeftButton()
{
@Override
public String getCode()
{
return DISABLE_BUTTON_CODE;
}
@Override
public String getPrefsName()
{
return context.getString(R.string.pref_left_button_disable);
}
}
);
}
}

View File

@@ -0,0 +1,6 @@
package app.organicmaps.leftbutton;
public interface LeftToggleButton extends LeftButton
{
void setChecked(boolean checked);
}

View File

@@ -1,5 +1,8 @@
package app.organicmaps.maplayer;
import static app.organicmaps.leftbutton.LeftButtonsHolder.BUTTON_HELP_CODE;
import static app.organicmaps.leftbutton.LeftButtonsHolder.DISABLE_BUTTON_CODE;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.content.Context;
@@ -33,8 +36,8 @@ import app.organicmaps.maplayer.isolines.IsolinesManager;
import app.organicmaps.maplayer.subway.SubwayManager;
import app.organicmaps.maplayer.traffic.TrafficManager;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.universalbuttons.UniversalButton;
import app.organicmaps.universalbuttons.UniversalToggleButton;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftToggleButton;
import app.organicmaps.util.Config;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.UiUtils;
@@ -81,11 +84,11 @@ public class MapButtonsController extends Fragment
private final Observer<Boolean> mTrackRecorderObserver = (enable) -> {
updateMenuBadge(enable);
showButton(enable, MapButtons.trackRecordingStatus);
updateUniversalButtonState(enable);
updateLeftButtonToggleState(enable);
};
private final Observer<Integer> mTopButtonMarginObserver = this::updateTopButtonsMargin;
private UniversalButton mUniversalButton;
private LeftButton mLeftButton;
@Nullable
@Override
@@ -153,7 +156,7 @@ public class MapButtonsController extends Fragment
private void initBottomButtons()
{
// universal button
applyUniversalButton();
applyLeftButton();
// bookmarks button
View bookmarksButton = mFrame.findViewById(R.id.btn_bookmarks);
@@ -190,32 +193,32 @@ public class MapButtonsController extends Fragment
}
}
private void applyUniversalButton()
private void applyLeftButton()
{
FloatingActionButton universalButtonView = mFrame.findViewById(R.id.universal_button);
if (universalButtonView != null && mUniversalButton != null)
FloatingActionButton leftButtonView = mFrame.findViewById(R.id.left_button);
if (leftButtonView != null && mLeftButton != null && !mLeftButton.getCode().equals(DISABLE_BUTTON_CODE))
{
UiUtils.show(universalButtonView);
UiUtils.show(leftButtonView);
Context context = getContext();
if (context == null)
return;
universalButtonView.setImageTintList(ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.iconTint)));
leftButtonView.setImageTintList(ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.iconTint)));
// Christmas tree with help button
if (Config.isNY() &&
mUniversalButton.getCode().equals("help") &&
mLeftButton.getCode().equals(BUTTON_HELP_CODE) &&
!TextUtils.isEmpty(Config.getDonateUrl(requireContext()))
)
{
universalButtonView.setImageResource(R.drawable.ic_christmas_tree);
universalButtonView.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help));
leftButtonView.setImageResource(R.drawable.ic_christmas_tree);
leftButtonView.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help));
}
else
{
mUniversalButton.drawIcon(universalButtonView);
universalButtonView.setOnClickListener((v) -> mUniversalButton.onClick(universalButtonView));
mLeftButton.drawIcon(leftButtonView);
leftButtonView.setOnClickListener((v) -> mLeftButton.onClick(leftButtonView));
}
// else
// {
@@ -225,9 +228,9 @@ public class MapButtonsController extends Fragment
// if (!ThemeUtils.isNightTheme(requireContext()))
// helpButton.getDrawable().setTintList(null);
}
else if (universalButtonView != null)
else if (leftButtonView != null)
{
UiUtils.hide(universalButtonView);
UiUtils.hide(leftButtonView);
}
}
@@ -504,24 +507,24 @@ public class MapButtonsController extends Fragment
mSearchWheel.reset();
}
public void setUniversalButton(UniversalButton universalButton)
public void setLeftButton(LeftButton leftButton)
{
this.mUniversalButton = universalButton;
this.mLeftButton = leftButton;
}
public void reloadUniversalButton(UniversalButton universalButton)
public void reloadLeftButton(LeftButton leftButton)
{
setUniversalButton(universalButton);
applyUniversalButton();
setLeftButton(leftButton);
applyLeftButton();
}
private void updateUniversalButtonState(boolean isEnabled)
private void updateLeftButtonToggleState(boolean isEnabled)
{
if (mUniversalButton instanceof UniversalToggleButton)
if (mLeftButton instanceof LeftToggleButton)
{
((UniversalToggleButton) mUniversalButton).setChecked(isEnabled);
((LeftToggleButton) mLeftButton).setChecked(isEnabled);
reloadUniversalButton(mUniversalButton);
reloadLeftButton(mLeftButton);
}
}

View File

@@ -1,5 +1,7 @@
package app.organicmaps.settings;
import static app.organicmaps.leftbutton.LeftButtonsHolder.DISABLE_BUTTON_CODE;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
@@ -25,8 +27,8 @@ import app.organicmaps.help.HelpActivity;
import app.organicmaps.location.LocationHelper;
import app.organicmaps.location.LocationProviderFactory;
import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.universalbuttons.UniversalButton;
import app.organicmaps.universalbuttons.UniversalButtonsHolder;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftButtonsHolder;
import app.organicmaps.util.Config;
import app.organicmaps.util.NetworkPolicy;
import app.organicmaps.util.PowerManagment;
@@ -39,6 +41,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
@@ -73,26 +77,22 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
initSearchPrivacyPrefsCallbacks();
initScreenSleepEnabledPrefsCallbacks();
initShowOnLockScreenPrefsCallbacks();
initUniversalButtonPrefs();
initLeftButtonPrefs();
}
private void initUniversalButtonPrefs()
private void initLeftButtonPrefs()
{
final ListPreference pref = getPreference(UniversalButtonsHolder.KEY_PREF_UNIVERSAL_BUTTON);
UniversalButtonsHolder holder = UniversalButtonsHolder.getInstance(requireContext());
final String leftButtonPreferenceKey = getString(R.string.pref_left_button);
final ListPreference pref = getPreference(leftButtonPreferenceKey);
LeftButtonsHolder holder = LeftButtonsHolder.getInstance(requireContext());
UniversalButton currentButton = holder.getActiveButton();
Collection<UniversalButton> buttons = holder.getAllButtons();
LeftButton currentButton = holder.getActiveButton();
Collection<LeftButton> buttons = holder.getAllButtons();
List<String> entryList = new ArrayList<>(buttons.size() + 1);
List<String> valueList = new ArrayList<>(buttons.size() + 1);
List<String> entryList = new ArrayList<>(buttons.size());
List<String> valueList = new ArrayList<>(buttons.size());
String notDisplayId = "not_display";
entryList.add(requireContext().getString(R.string.pref_universal_button_not_display));
valueList.add(notDisplayId);
for (UniversalButton button : buttons)
for (LeftButton button : buttons)
{
entryList.add(button.getPrefsName());
valueList.add(button.getCode());
@@ -108,8 +108,8 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
}
else
{
pref.setSummary(R.string.pref_universal_button_not_display);
pref.setValue(notDisplayId);
pref.setSummary(R.string.pref_left_button_disable);
pref.setValue(DISABLE_BUTTON_CODE);
}
pref.setOnPreferenceChangeListener((preference, newValue) -> {
@@ -120,7 +120,7 @@ public class SettingsPrefsFragment extends BaseXmlSettingsFragment implements La
}
Intent intent = new Intent();
intent.putExtra(UniversalButtonsHolder.KEY_PREF_UNIVERSAL_BUTTON, newValue.toString());
intent.putExtra(leftButtonPreferenceKey, newValue.toString());
requireActivity().setResult(-1, intent);

View File

@@ -1,14 +0,0 @@
package app.organicmaps.universalbuttons;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public interface UniversalButton
{
String getCode();
String getPrefsName();
void drawIcon(FloatingActionButton imageView);
void onClick(FloatingActionButton universalButtonView);
}

View File

@@ -1,109 +0,0 @@
package app.organicmaps.universalbuttons;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceManager;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.help.HelpActivity;
public class UniversalButtonsHolder
{
private static volatile UniversalButtonsHolder instance;
public static final String KEY_PREF_UNIVERSAL_BUTTON = "universal_button";
private static final String BUTTON_HELP_CODE = "help";
public static final String BUTTON_SETTINGS_CODE = "settings";
public static final String BUTTON_ADD_PLACE_CODE = "add-place";
public static final String BUTTON_RECORD_TRACK_CODE = "record-track";
private static final String DEFAULT_BUTTON_CODE = BUTTON_HELP_CODE;
private final Context context;
private final SharedPreferences prefs;
private final Map<String, UniversalButton> availableButtons = new HashMap<>();
private UniversalButtonsHolder(Context context)
{
this.context = context;
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
}
public void registerButton(UniversalButton button)
{
availableButtons.put(button.getCode(), button);
}
public void registerDefaultUniversalButtons(Context context)
{
registerButton(new UniversalButton()
{
@Override
public String getCode()
{
return BUTTON_HELP_CODE;
}
@Override
public String getPrefsName()
{
return context.getString(R.string.help);
}
@Override
public void drawIcon(FloatingActionButton imageView)
{
imageView.setImageResource(R.drawable.ic_question_mark);
}
@Override
public void onClick(FloatingActionButton universalButtonView)
{
Intent intent = new Intent(context, HelpActivity.class);
context.startActivity(intent);
}
});
}
@Nullable
public UniversalButton getActiveButton()
{
String activeButtonCode = prefs.getString(KEY_PREF_UNIVERSAL_BUTTON, DEFAULT_BUTTON_CODE);
if (!TextUtils.isEmpty(activeButtonCode))
return availableButtons.get(activeButtonCode);
else
return null;
}
public Collection<UniversalButton> getAllButtons()
{
return availableButtons.values();
}
public static UniversalButtonsHolder getInstance(Context context)
{
UniversalButtonsHolder localInstance = instance;
if (localInstance == null)
{
synchronized (UniversalButtonsHolder.class)
{
localInstance = instance;
if (localInstance == null)
{
instance = localInstance = new UniversalButtonsHolder(context);
}
}
}
return localInstance;
}
}

View File

@@ -1,8 +0,0 @@
package app.organicmaps.universalbuttons;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
public interface UniversalToggleButton extends UniversalButton
{
void setChecked(boolean checked);
}

View File

@@ -6,7 +6,7 @@
android:viewportHeight="80">
<path
android:pathData="m4.858,10.076c0,-5.523 4.477,-10 10,-10h60c5.523,0 10,4.477 10,10v60c0,5.523 -4.477,10 -10,10h-60c-5.523,0 -10,-4.477 -10,-10z"
android:fillColor="#0057ff"
android:fillColor="@color/active_track_recording"
android:fillAlpha="0.78" />
<path
android:pathData="m78.907,32.87 l-31.833,13.318 13.335,5.772 6.188,13.147z"

View File

@@ -3,5 +3,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="12dp" />
<solid android:color="#0057ff" />
<solid android:color="@color/active_track_recording" />
</shape>

View File

@@ -52,5 +52,15 @@
android:layout_marginTop="@dimen/margin_direction_mid"
android:textSize="@dimen/text_direction_dist"
tools:text="9000 km"/>
<TextView
android:id="@+id/tv__azimuth"
style="@style/MwmWidget.TextView.Direction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_direction_small"
android:gravity="center_horizontal"
android:textSize="@dimen/text_direction_subtitle"
tools:text="123.4°" />
</LinearLayout>
</RelativeLayout>

View File

@@ -35,7 +35,7 @@
android:layout_weight="1"
android:orientation="vertical"
android:padding="@dimen/margin_base">
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -47,7 +47,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imageView"
android:layout_width="@dimen/osm_logo"
android:layout_height="@dimen/osm_logo"
@@ -56,7 +56,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/osm_presentation"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -108,7 +108,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base">
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/login"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"
@@ -123,7 +123,7 @@
android:elevation="@dimen/design_fab_elevation"
android:visibility="gone" />
</FrameLayout>
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/lost_password"
style="@style/MwmWidget.Button"
android:layout_width="match_parent"
@@ -138,14 +138,14 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoRegular"
android:text="@string/no_osm_account"
android:textAppearance="@style/MwmTextAppearance.Body2"
android:textColor="?android:textColorPrimary" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/register"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"

View File

@@ -9,7 +9,7 @@
android:clipChildren="false"
android:clipToPadding="false">
<include
android:id="@+id/universal_button"
android:id="@+id/left_button"
layout="@layout/map_buttons_help"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -25,7 +25,7 @@
android:layout_marginStart="@dimen/margin_base_plus"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_goneMarginStart="@dimen/margin_half_plus"
app:layout_constraintStart_toEndOf="@+id/universal_button" />
app:layout_constraintStart_toEndOf="@+id/left_button" />
<include
android:id="@+id/btn_bookmarks"
layout="@layout/map_buttons_bookmarks_square"

View File

@@ -26,7 +26,7 @@
android:orientation="vertical"
android:padding="@dimen/margin_base"
tools:ignore="ScrollViewSize">
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -39,7 +39,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base">
<ImageView
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/osm_logo"
android:layout_width="@dimen/osm_logo"
android:layout_height="@dimen/osm_logo"
@@ -48,7 +48,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/osm_presentation"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -92,7 +92,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base">
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/login"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"
@@ -107,7 +107,7 @@
android:elevation="@dimen/design_fab_elevation"
android:visibility="gone" />
</FrameLayout>
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/lost_password"
style="@style/MwmWidget.Button"
android:layout_width="wrap_content"
@@ -122,14 +122,14 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoRegular"
android:text="@string/no_osm_account"
android:textAppearance="@style/MwmTextAppearance.Body2"
android:textColor="?android:textColorPrimary" />
<Button
<com.google.android.material.button.MaterialButton
android:id="@+id/register"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"

View File

@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/MwmWidget.ToolbarStyle"
android:layout_width="match_parent"
@@ -15,7 +15,7 @@
android:gravity="end|center_vertical"
android:theme="@style/MwmWidget.ToolbarTheme"
tools:ignore="UnusedAttribute">
<ImageView
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/logout"
android:layout_width="?actionBarSize"
android:layout_height="?actionBarSize"
@@ -24,7 +24,7 @@
android:scaleType="center"
app:srcCompat="@drawable/ic_logout"
android:contentDescription="@string/logout" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.MaterialToolbar>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<ImageView
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/user_profile_image"
android:layout_width="100dp"
android:layout_height="match_parent"
@@ -57,7 +57,7 @@
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/user_profile_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -68,7 +68,7 @@
android:autoSizeTextType="uniform"
android:textSize="25sp"
tools:text="Long Username" />
<androidx.appcompat.widget.AppCompatTextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/user_sent_edits"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -76,7 +76,7 @@
android:textSize="35sp"
android:textStyle="bold"
tools:text="2,000,000" />
<androidx.appcompat.widget.AppCompatTextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/verified_changes_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -93,7 +93,7 @@
android:layout_height="0dp"
android:layout_weight="1">
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/osm_history"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -110,7 +110,7 @@
android:textColor="?colorAccent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/osm_notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -126,7 +126,7 @@
android:textColor="?colorAccent"
app:layout_constraintTop_toBottomOf="@id/osm_history" />
<TextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/about_osm"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -13,7 +13,7 @@
android:clipChildren="false"
android:clipToPadding="false">
<include
android:id="@+id/universal_button"
android:id="@+id/left_button"
layout="@layout/map_buttons_help"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -32,7 +32,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btn_bookmarks"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/universal_button" />
app:layout_constraintStart_toEndOf="@+id/left_button" />
<include
android:id="@+id/btn_bookmarks"
layout="@layout/map_buttons_bookmarks_square"

View File

@@ -879,4 +879,7 @@
<string name="error_enter_correct_fediverse_page">Zadejte platné uživatelské jméno nebo webovou adresu Mastodonu</string>
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_bluesky_page">Zadejte platné uživatelské jméno nebo webovou adresu Bluesky</string>
<string name="saved">Uloženo</string>
<string name="pref_left_button_disable">Zakázat</string>
<string name="pref_left_button_title">Nastavení levého tlačítka</string>
</resources>

View File

@@ -11,7 +11,7 @@
<!-- Settings/Downloader - info for country when download fails -->
<string name="download_has_failed">Herunterladen fehlgeschlagen. Antippen für einen neuen Versuch.</string>
<!-- Settings/Downloader - info for country which started downloading -->
<string name="downloading">Wird heruntergeladen…</string>
<string name="downloading">Wird heruntergeladen </string>
<!-- Choose measurement on first launch alert - choose metric system button -->
<string name="kilometres">Kilometer</string>
<!-- Choose measurement on first launch alert - choose imperial system button -->
@@ -888,4 +888,7 @@
<string name="error_enter_correct_bluesky_page">Geben Sie einen gültigen Bluesky-Nutzernamen oder Webadresse ein</string>
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_fediverse_page">Geben Sie einen gültigen Mastodon-Nutzernamen oder Webadresse an</string>
<string name="pref_left_button_title">Einstellung linker Knopf</string>
<string name="saved">Gespeichert</string>
<string name="pref_left_button_disable">Deaktivieren</string>
</resources>

View File

@@ -1395,7 +1395,7 @@
<string name="type.sport.diving">Tauchen</string>
<string name="type.amenity.love_hotel">Stundenhotel</string>
<string name="type.landuse.plant_nursery">Gartenbau</string>
<string name="type.leisure.firepit">Feuerschale</string>
<string name="type.leisure.firepit">Feuerstelle</string>
<string name="type.barrier.guard_rail">Leitplanke</string>
<string name="type.highway.ladder">Leiter</string>
<string name="type.amenity.studio">Studio</string>

View File

@@ -38,15 +38,15 @@
<string name="try_again">Intentar otra vez</string>
<string name="about_menu_title">Acerca de CoMaps</string>
<!-- Text in About screen -->
<string name="about_headline">Gratis para todos, hecho con amor</string>
<string name="about_headline">Proyecto abierto impulsado por la comunidad</string>
<!-- Text in About screen -->
<string name="about_proposition_1">Sin anuncios, sin rastreo, sin recopilación de datos</string>
<string name="about_proposition_1">Fácil de utilizar y depurado</string>
<!-- Text in About screen -->
<string name="about_proposition_2">Consumo de batería mínimo, funciona sin conexión</string>
<string name="about_proposition_2">Enfocado a la privacidad y sin anuncios</string>
<!-- Text in About screen -->
<string name="about_proposition_3">Rápido, minimalista, desarrollado por la comunidad</string>
<string name="about_proposition_3">No necesita conexión a internet, rápido y compacto</string>
<!-- Text in About screen -->
<string name="about_developed_by_enthusiasts">Aplicación de código abierto creada por entusiastas y voluntarios.</string>
<string name="about_developed_by_enthusiasts">Completamente de código abierto, sin ánimo de lucro, y con procesos de toma de decisiones y finanzas transparentes.</string>
<!-- The button that opens system location settings -->
<string name="location_settings">Ajustes de ubicación</string>
<string name="close">Cerrar</string>
@@ -302,9 +302,9 @@
<!-- Item in context menu. -->
<string name="downloader_update_map">Actualizar mapa</string>
<!-- Preference title -->
<string name="google_play_services">Servicios de localización de Google Play</string>
<string name="google_play_services">Servicio de localización de Google Fused</string>
<!-- Preference text -->
<string name="pref_use_google_play">Determina rápidamente su ubicación aproximada mediante Bluetooth, WiFi o red móvil</string>
<string name="pref_use_google_play">Un servicio propietario que combina señal GPS, Wi-Fi, redes móviles, etc. para determinar tu ubicación con más precisión. Puede que se conecte a servidores de Google.</string>
<!-- Preference title -->
<!-- Preference description -->
<!-- Text for routing error dialog -->
@@ -886,4 +886,12 @@
<string name="comma_separated_pair">%1$s, %2$s</string>
<string name="level_value_generic">Nivel: %s</string>
<string name="editor_line_social_network">LINE</string>
<string name="saved">Guardado</string>
<string name="codeberg">Codeberg</string>
<string name="error_enter_correct_fediverse_page">Introduce un nombre de usuario o una dirección web de Mastodon válidos</string>
<string name="instagram_url">https://www.instagram.com/comapscommunity</string>
<string name="app_site_url">https://comaps.app/</string>
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_bluesky_page">Introduce un nombre de usuario o una dirección web de Bluesky válidos</string>
<string name="telegram_url">https://t.me/CoMapsApp/</string>
</resources>

View File

@@ -1395,4 +1395,11 @@
<string name="type.fee.yes">$</string>
<string name="type.railway.narrow_gauge.tunnel">Túnel de vía férrea estrecha</string>
<string name="type.railway.light_rail.bridge">Puente de tren ligero</string>
<string name="type.highway.ladder">Escalera</string>
<string name="type.amenity.studio">Estudio</string>
<string name="type.landuse.plant_nursery">Vivero de plantas</string>
<string name="type.barrier.guard_rail">Guardarraíl</string>
<string name="type.sport.diving">Buceo</string>
<string name="type.leisure.firepit">Fogón</string>
<string name="type.amenity.love_hotel">Hotel del amor</string>
</resources>

View File

@@ -883,4 +883,7 @@
<string name="error_enter_correct_fediverse_page">Sisesta korrektne Mastodoni kasutajanimi või veebiaadress</string>
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_bluesky_page">Sisesta korrektne Bluesky kasutajanimi või veebiaadress</string>
<string name="saved">Salvestatud</string>
<string name="pref_left_button_disable">Keela</string>
<string name="pref_left_button_title">Vasaku nupu seadistused</string>
</resources>

View File

@@ -49,7 +49,7 @@
<!-- Text in About screen -->
<string name="about_proposition_3">• Yhteydetön tila, nopea ja kompakti</string>
<!-- Text in About screen -->
<string name="about_developed_by_enthusiasts">Harrastajien ja vapaaehtoisten luoma avoimen lähdekoodin sovellus.</string>
<string name="about_developed_by_enthusiasts">Täysin avoimeen lähdekoodiin perustuva, voittoa tavoittelematon sekä läpinäkyvä päätöksenteko ja talous.</string>
<!-- The button that opens system location settings -->
<string name="location_settings">Sijaintiasetukset</string>
<string name="close">Sulje</string>
@@ -304,9 +304,9 @@
<!-- Item in context menu. -->
<string name="downloader_update_map">Päivitä kartta</string>
<!-- Preference title -->
<string name="google_play_services">Google Play Sijaintipalvelut</string>
<string name="google_play_services">Google Fused Sijaintipalvelu</string>
<!-- Preference text -->
<string name="pref_use_google_play">Määritä nopeasti likimääräinen sijaintisi Bluetoothin, WiFin tai matkapuhelinverkon kautta</string>
<string name="pref_use_google_play">Suljetun lähdekoodin palvelu, joka yhdistää GPS:n, Wi-Fi:n ja mobiiliverkot yms. löytääksesi sijaintisi tarkemmin. Se voi ottaa yhteyttä Googlen palvelimiin.</string>
<!-- Preference title -->
<!-- Preference description -->
<!-- Text for routing error dialog -->
@@ -492,7 +492,7 @@
<string name="placepage_add_business_button">Lisää organisaatio</string>
<string name="message_invalid_feature_position">Kohdetta ei voida asettaa tänne</string>
<!-- Text in About and OSM Login screens. First %@ is replaced by a local, human readable date. -->
<string name="osm_presentation">Yhteisön luomat OpenStreetMap-tiedot %s:sta alkaen. Lisätietoja kartan muokkaamisesta ja päivittämisestä osoitteessa OpenStreetMap.org.</string>
<string name="osm_presentation">Yhteisön luomat OpenStreetMap-tiedot %s:sta alkaen. Lisätietoja kartan muokkaamisesta ja päivittämisestä osoitteessa OpenStreetMap.org</string>
<!-- OSM explanation on Android login screen -->
<string name="login_osm_presentation">OpenStreetMap.org (OSM) on yhteisöprojekti, jonka tarkoituksena on rakentaa ilmainen ja avoin kartta. Se on CoMapsin tärkein karttatietojen lähde ja toimii samalla tavalla kuin Wikipedia. Voit lisätä tai muokata paikkoja, ja ne tulevat miljoonien käyttäjien saataville kaikkialla maailmassa. \nLiity yhteisöön ja auta tekemään parempi kartta kaikille!</string>
<string name="login_to_make_edits_visible">Luo OpenStreetMap-tili tai kirjaudu sisään, jotta voit julkaista karttamuokkauksesi maailmalle.</string>
@@ -511,7 +511,7 @@
<!-- Title for OSM note section in the editor -->
<string name="editor_other_info">Huomautus OpenStreetMapin vapaaehtoisille (valinnainen)</string>
<!-- Hint of the input field in the OSM note section of the editor -->
<string name="editor_note_hint">Kuvaile kartassa olevia virheitä tai asioita, joita ei voi muokata CoMapsilla.</string>
<string name="editor_note_hint">Kuvaile kartassa olevia virheitä tai asioita, joita ei voi muokata CoMapsilla</string>
<!-- Information about OSM at the top of the editing page -->
<string name="editor_about_osm">Muokkauksesi ladataan julkiseen <a href="https://wiki.openstreetmap.org/wiki/About_OpenStreetMap">OpenStreetMap</a>-tietokantaan. Älä lisää henkilökohtaisia tai tekijänoikeudella suojattuja tietoja.</string>
<string name="editor_more_about_osm">Lisätietoja OpenStreetMap:sta</string>
@@ -685,7 +685,7 @@
<string name="avoid_ferry">Vältä lautan käyttöä</string>
<string name="avoid_motorways">Vältä moottoritietä</string>
<string name="unable_to_calc_alert_title">Reittiä ei voi luoda</string>
<string name="unable_to_calc_alert_subtitle">Valitettavasti emme voineet luoda reittiä valituilla vaihtoehdoilla. Vaihda asetuksia ja yritä uudelleen</string>
<string name="unable_to_calc_alert_subtitle">Valitettavasti emme voineet luoda reittiä valituilla vaihtoehdoilla. Tämä voi johtua reittiasetuksista tai OpenStreetMap:n puuttuvista tiedoista. Vaihda reititysasetuksia ja yritä uudelleen.</string>
<string name="define_to_avoid_btn">Määritä vältettävät tiet</string>
<string name="change_driving_options_btn">Reititysvalinnat ovat päällä</string>
<string name="toll_road">Maksullinen tie</string>
@@ -799,7 +799,7 @@
<!-- App tip #09 -->
<string name="app_tip_09">Päätavoitteemme on rakentaa nopeita, yksityisyyteen keskittyviä, helppokäyttöisiä karttoja, joista pidät.</string>
<!-- Text on the Android Auto or CarPlay placeholder screen that maps are displayed on the phone screen -->
<string name="car_used_on_the_phone_screen">Käytät nyt puhelimen näytöllä CoMaps -palvelua.</string>
<string name="car_used_on_the_phone_screen">Käytät nyt CoMapsia puhelimen näytöllä</string>
<!-- Text on the phone placeholder screen that maps are displayed on the car screen -->
<string name="car_used_on_the_car_screen">Käytät nyt CoMaps auton näytöllä</string>
<!-- Displayed on the phone screen. Android Auto connected -->
@@ -858,7 +858,7 @@
<!-- Message for the toast when saving the track recording is finished but nothing to save. -->
<string name="track_recording_toast_nothing_to_save">Reitti on tyhjä - ei mitään tallennettavaa</string>
<!-- Error message when there are no File Manager apps installed to select a folder when importing Bookmarks and Tracks -->
<string name="error_no_file_manager_app">Kansiovalintaikkunaa ei voida näyttää, koska laitteeseen ei ole asennettu sopivaa sovellusta. Asenna tiedostonhallintasovellus ja yritä uudelleen</string>
<string name="error_no_file_manager_app">Kansiovalintaikkunaa ei voida näyttää, koska laitteeseen ei ole asennettu sopivaa sovellusta. Asenna tiedostonhallintasovellus ja yritä uudelleen.</string>
<string name="choose_color">Valitse väri</string>
<string name="edit_track">Muokkaa reittiä</string>
<string name="uri_open_location_failed">Ei asennettua sovellusta, joka voi avata sijainnin</string>
@@ -888,4 +888,7 @@
<string name="error_enter_correct_bluesky_page">Kirjoita kelvollinen Bluesky-käyttäjänimi tai verkko-osoite</string>
<string name="instagram_url">https://www.instagram.com/comapscommunity</string>
<string name="app_site_url">https://comaps.app/</string>
<string name="pref_left_button_title">Vasemman painikkeen asettelu</string>
<string name="pref_left_button_disable">Poista käytöstä</string>
<string name="saved">Tallennettu</string>
</resources>

View File

@@ -1312,4 +1312,30 @@
<string name="type.route">Reitti</string>
<string name="type.boundary.administrative.3">Alueellinen raja</string>
<string name="type.boundary.administrative.4">Alueellinen raja</string>
<string name="type.aeroway">Airspace Infrastructure</string>
<string name="type.aeroway.apron">Apron</string>
<string name="type.amenity.vending_machine.excrement_bags">Koirankakkapussiautomaatti</string>
<string name="type.hwtag.yescar">hwtag-yescar</string>
<string name="type.amenity.biergarten">Olutpuutarha</string>
<string name="type.highway.ladder">Tikapuut</string>
<string name="type.hwtag.yesfoot">hwtag-yesfoot</string>
<string name="type.landuse.plant_nursery">Kasvitarha</string>
<string name="type.highway.world_towns_level">highway-world_towns_level</string>
<string name="type.cuisine.fish_and_chips">Fish and Chips</string>
<string name="type.highway.world_level">highway-world_level</string>
<string name="type.hwtag.bidir_bicycle">hwtag-bidir_bicycle</string>
<string name="type.hwtag.private">hwtag-private</string>
<string name="type.hwtag">hwtag</string>
<string name="type.amenity.studio">Studio</string>
<string name="type.barrier.guard_rail">Tiekaide</string>
<string name="type.hwtag.onedir_bicycle">hwtag-onedir_bicycle</string>
<string name="type.hwtag.lit">hwtag-lit</string>
<string name="type.hwtag.nobicycle">hwtag-nobicycle</string>
<string name="type.hwtag.nocar">hwtag-nocar</string>
<string name="type.hwtag.nofoot">hwtag-nofoot</string>
<string name="type.hwtag.oneway">hwtag-oneway</string>
<string name="type.hwtag.toll">hwtag-toll</string>
<string name="type.hwtag.yesbicycle">hwtag-yesbicycle</string>
<string name="type.leisure.firepit">Tulentekopaikka</string>
<string name="type.leisure">Leisure</string>
</resources>

View File

@@ -126,7 +126,7 @@
<!-- Search category for parking lots; any changes should be duplicated in categories.txt @category_parking! -->
<string name="category_parking">Stationnement</string>
<!-- Search category for malls/clothes/shoes/gifts/jewellery/sport shops; any changes should be duplicated in categories.txt @category_shopping! -->
<string name="category_shopping">Shopping</string>
<string name="category_shopping">Magasins</string>
<!-- Search category for second_hand/charity/antique/auction shops; any changes should be duplicated in categories.txt @category_secondhand! -->
<string name="category_secondhand">D\'occasion</string>
<!-- Search category for places to stay; any changes should be duplicated in categories.txt @category_hotel! -->
@@ -619,7 +619,7 @@
<string name="bookmark_lists_show_all">Tout afficher</string>
<plurals name="bookmarks_places">
<item quantity="one">%d signet</item>
<item quantity="many"/>
<item quantity="many">%d signets</item>
<item quantity="other">%d signets</item>
</plurals>
<string name="bookmarks_create_new_group">Créer une nouvelle liste</string>
@@ -638,13 +638,13 @@
<string name="profile">Profil OpenStreetMap</string>
<plurals name="bookmarks_detect_message">
<item quantity="one">%d fichier a été trouvé. Vous le verrez après la conversion.</item>
<item quantity="many"/>
<item quantity="many">%d fichiers ont été trouvés. Vous les verrez après la conversion.</item>
<item quantity="other">%d fichiers ont été trouvés. Vous les verrez après la conversion.</item>
</plurals>
<string name="restore">Restaurer</string>
<plurals name="tracks">
<item quantity="one">%d piste</item>
<item quantity="many"/>
<item quantity="many">%d pistes</item>
<item quantity="other">%d pistes</item>
</plurals>
<!-- Settings privacy group in settings screen -->
@@ -894,4 +894,7 @@
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_bluesky_page">Entrez un nom d\'utilisateur ou une adresse web Bluesky correct</string>
<string name="error_enter_correct_fediverse_page">Entrez un nom d\'utilisateur ou une adresse web Mastodon correct</string>
<string name="saved">Enregistré</string>
<string name="pref_left_button_title">Configuration du bouton en bas à gauche</string>
<string name="pref_left_button_disable">Désactiver</string>
</resources>

View File

@@ -883,4 +883,5 @@
<string name="error_enter_correct_bluesky_page">Inserisci un nome utente o un indirizzo web Bluesky valido</string>
<string name="instagram_url">https://www.instagram.com/comapscommunity/</string>
<string name="telegram_url">https://t.me/CoMapsApp/</string>
<string name="saved">Salvato</string>
</resources>

View File

@@ -461,7 +461,7 @@
<!-- Text field to enter non-existing street name, below list of known streets around -->
<string name="add_street">通りを追加</string>
<!-- Error to display when a new street name is not entered in the New street dialog -->
<string name="empty_street_name_error">通りの名前を入力してください</string>
<string name="empty_street_name_error">通りの名前を入力してください</string>
<string name="choose_language">言語を選択</string>
<string name="choose_street">通りを選択</string>
<string name="postal_code">郵便番号</string>
@@ -485,7 +485,7 @@
<string name="editor_add_place_title">追加中</string>
<string name="editor_edit_place_name_hint">場所の名前</string>
<!-- The second part of the editor_edit_place_name_hint to explain that name should be entered in a local language, see https://wiki.openstreetmap.org/wiki/Key:name -->
<string name="editor_default_language_hint">現地の言葉でこう書かれている</string>
<string name="editor_default_language_hint">現地の言葉でこう書かれている</string>
<string name="editor_edit_place_category_title">カテゴリ</string>
<string name="detailed_problem_description">問題の詳細な説明</string>
<string name="editor_report_problem_other_title">異なる問題</string>
@@ -494,7 +494,7 @@
<!-- Text in About and OSM Login screens. First %@ is replaced by a local, human readable date. -->
<string name="osm_presentation">コミュニティが作成した%s時点の OpenStreetMap のデータ。地図の編集や更新の方法については、OpenStreetMap.org を参照してください</string>
<!-- OSM explanation on Android login screen -->
<string name="login_osm_presentation">OpenStreetMap.org(OSM)は、フリーでオープンな地図を構築するコミュニティ・プロジェクトです。OSMは、CoMapsの地図データの主要なソースであり、ウィキペディアと同じように機能します。あなたが場所を追加したり編集したりすると、世界中の何百万人ものユーザーがその場所を利用できるようになります</string>
<string name="login_osm_presentation">OpenStreetMap.org(OSM)は、フリーでオープンな地図を構築するコミュニティ・プロジェクトです。OSMは、CoMapsの地図データの主要なソースであり、ウィキペディアと同じように機能します。あなたが場所を追加したり編集したりすると、世界中の何百万人ものユーザーがその場所を利用できるようになります</string>
<string name="login_to_make_edits_visible">OpenStreetMapのアカウントを作成するかログインして、あなたの地図編集を世界中に公開しましょう。</string>
<!-- Downloaded 10 **of** 20 <- it is that "of" -->
<string name="downloader_of">%2$dのうち%1$d</string>
@@ -511,7 +511,7 @@
<!-- Title for OSM note section in the editor -->
<string name="editor_other_info">OpenStreetMapボランティアへの注意オプション</string>
<!-- Hint of the input field in the OSM note section of the editor -->
<string name="editor_note_hint">地図上のエラーやCoMapsで編集できないものについて説明します</string>
<string name="editor_note_hint">地図上のエラーやCoMapsで編集できないものについて説明します</string>
<!-- Information about OSM at the top of the editing page -->
<string name="editor_about_osm">あなたの編集は公開されている<a href="https://wiki.openstreetmap.org/wiki/JA:参加する">OpenStreetMap</a>データベースにアップロードされます。個人情報や著作権のある情報は追加しないでください。</string>
<string name="editor_more_about_osm">OpenStreetMapについての詳細</string>
@@ -589,7 +589,7 @@
<string name="enable_logging">ログを有効化</string>
<!-- Settings: "Send general feedback" button -->
<string name="feedback_general">一般的なフィードバック</string>
<string name="prefs_languages_information">音声案内にはシステムの TTS を使用します。多くの Android 端末が Google の TTS を使用しており、Google Play (https://play.google.com/store/apps/details?id=com.google.android.tts) からダウンロードや更新を行うことができます</string>
<string name="prefs_languages_information">音声案内にはシステムの TTS を使用します。多くの Android 端末が Google の TTS を使用しており、Google Play (https://play.google.com/store/apps/details?id=com.google.android.tts) からダウンロードや更新を行うことができます</string>
<string name="prefs_languages_information_off">いくつかの言語では、アプリストア(Google Play、Galaxy Store 、App Gallery、FDroid)から音声合成または追加の言語パックをインストールする必要があります。\nお使いのデバイスで [設定] → [言語と入力] → [音声] → [音声出力] を開いてください。\nここで音声合成の設定 (たとえば、オフラインで使用する言語パックのダウンロードなど) を管理し、別の音声合成エンジンを選択できます。</string>
<string name="prefs_languages_information_off_link">詳細については、このガイドをご確認ください。</string>
<string name="transliteration_title">ラテン文字への翻字</string>
@@ -607,7 +607,7 @@
<!-- Alert to ask user relogin to OpenStreetMap with OAuth2 flow after OAuth1 authentication is deprecated. -->
<string name="alert_reauth_message">すべてのマップ編集を自動的にアップロードするには、OpenStreetMapにログインしてください。詳しくは <a href="https://github.com/organicmaps/organicmaps/issues/6144">こちら</a>.</string>
<string name="dialog_error_storage_title">ストレージアクセスの問題</string>
<string name="dialog_error_storage_message">外部ストレージは使用できません。おそらく SD カードが取り外されたか、破損しているか、あるいはファイルシステムが読み取り専用になっています。SD カードを確認するか、support@comaps.app までご連絡ください</string>
<string name="dialog_error_storage_message">外部ストレージは使用できません。おそらく SD カードが取り外されたか、破損しているか、あるいはファイルシステムが読み取り専用になっています。SD カードを確認するか、support@comaps.app までご連絡ください</string>
<string name="setting_emulate_bad_storage">壊れたストレージをシミュレートする</string>
<string name="core_entrance">入口</string>
<string name="error_enter_correct_name">正しい名前を入力してください</string>
@@ -648,7 +648,7 @@
<string name="layers_title">マップのスタイルとレイヤー</string>
<string name="subway_data_unavailable">地下鉄路線図はご利用いただけません</string>
<string name="bookmarks_empty_list_title">このリストは空です</string>
<string name="bookmarks_empty_list_message">ブックマークを追加するには、地図上の場所をタップし、星のアイコンをタップしてください</string>
<string name="bookmarks_empty_list_message">ブックマークを追加するには、地図上の場所をタップし、星のアイコンをタップしてください</string>
<string name="category_desc_more">詳細</string>
<string name="export_file">KMZをエクスポートする</string>
<string name="export_file_gpx">GPXをエクスポートする</string>
@@ -887,4 +887,6 @@
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
<string name="app_site_url">https://comaps.app/</string>
<string name="bluesky">Bluesky</string>
<string name="pref_left_button_title">左ボタンの設定</string>
<string name="pref_left_button_disable">無効にする</string>
</resources>

View File

@@ -1328,4 +1328,8 @@
<string name="type.highway.ladder">階子</string>
<string name="type.attraction.bumper_car">バンパーカー</string>
<string name="type.sport.diving">飛込</string>
<string name="type.recycling.cartons">紙箱</string>
<string name="type.organic.only">有機</string>
<string name="type.organic.yes">有機</string>
<string name="type.power.pole">電柱</string>
</resources>

View File

@@ -36,11 +36,11 @@
<string name="try_again">Tentar novamente</string>
<string name="about_menu_title">Sobre o CoMaps</string>
<!-- Text in About screen -->
<string name="about_headline">Grátis para todos, feito com amor</string>
<string name="about_headline">Projeto aberto impulsionado pela comunidade</string>
<!-- Text in About screen -->
<string name="about_proposition_1">Sem anúncios, rastreamento ou coleta de dados</string>
<string name="about_proposition_1">Fácil de usar e elegante</string>
<!-- Text in About screen -->
<string name="about_proposition_2">Sem consumo de bateria, funciona off-line</string>
<string name="about_proposition_2">Focado na privacidade e sem anúncios</string>
<!-- The button that opens system location settings -->
<string name="location_settings">Configurações de localização</string>
<string name="close">Fechar</string>
@@ -82,7 +82,7 @@
<!-- Header of settings activity where user defines storage path -->
<string name="maps_storage">Salvar mapas para</string>
<!-- Detailed description of Maps Storage settings button -->
<string name="maps_storage_summary">Selecione o local para onde os mapas devem ser baixados</string>
<string name="maps_storage_summary">Selecione o local para onde os mapas devem ser baixados.</string>
<!-- E.g. "Downloaded maps: 500Mb" in Maps Storage settings -->
<string name="maps_storage_downloaded">Mapas</string>
<!-- Internal storage type in Maps Storage settings (not accessible by the user) -->
@@ -275,7 +275,7 @@
<!-- Item in context menu. -->
<string name="downloader_update_map">Atualizar mapa</string>
<!-- Preference text -->
<string name="pref_use_google_play">Determine rapidamente sua localização aproximada via Bluetooth, WiFi ou rede móvel</string>
<string name="pref_use_google_play">Um serviço proprietário que combina GPS, Wi-Fi, redes móveis etc. para determinar sua localização com mais precisão. Ele pode se conectar aos servidores do Google.</string>
<!-- Preference title -->
<!-- Preference description -->
<!-- Text for routing error dialog -->
@@ -367,8 +367,8 @@
<string name="read_in_wikipedia">Wikipédia</string>
<string name="p2p_your_location">Localização atual</string>
<string name="p2p_start">Iniciar</string>
<string name="p2p_from_here">De</string>
<string name="p2p_to_here">Para</string>
<string name="p2p_from_here">Rota de</string>
<string name="p2p_to_here">Rota para</string>
<string name="p2p_only_from_current">Só é possível navegar a partir da sua localização atual.</string>
<string name="p2p_reroute_from_current">Deseja planejar uma rota a partir da sua localização atual?</string>
<!-- Edit open hours/set time and minutes dialog -->
@@ -548,7 +548,7 @@
<string name="bookmark_lists_show_all">Exibir tudo</string>
<plurals name="bookmarks_places">
<item quantity="one">%d favorito</item>
<item quantity="many"/>
<item quantity="many">%d favoritos</item>
<item quantity="other">%d favoritos</item>
</plurals>
<string name="bookmarks_create_new_group">Criar nova lista</string>
@@ -567,13 +567,13 @@
<string name="profile">Perfil do OpenStreetMap</string>
<plurals name="bookmarks_detect_message">
<item quantity="one">%d arquivo foi encontrado. Você vai ver depois da conversão.</item>
<item quantity="many"/>
<item quantity="many">%d arquivos foram encontrados. Você os verá depois da conversão.</item>
<item quantity="other">%d arquivos foram encontrados. Você os verá depois da conversão.</item>
</plurals>
<string name="restore">Restaurar</string>
<plurals name="tracks">
<item quantity="one">%d trilha</item>
<item quantity="many"/>
<item quantity="many">%d trilhas</item>
<item quantity="other">%d trilhas</item>
</plurals>
<string name="privacy_policy">Política de privacidade</string>
@@ -691,7 +691,7 @@
<!-- A preference title; keep short! -->
<string name="enable_show_on_lock_screen">Mostrar na tela de bloqueio</string>
<!-- Description in preferences -->
<string name="enable_show_on_lock_screen_description">Quando ativado, você não precisará debloquear seu dispositivo toda vez que o aplicativo estiver funcionando</string>
<string name="enable_show_on_lock_screen_description">Quando ativado, você não precisará desbloquear seu dispositivo toda vez que o aplicativo estiver funcionando.</string>
<!-- Current language of the map! -->
<string name="change_map_locale">Idioma do mapa</string>
<!-- OpenStreetMap text on splash screen -->
@@ -771,16 +771,100 @@
<!-- Message for the toast when saving the track recording is finished but nothing to save. -->
<string name="track_recording_toast_nothing_to_save">A trilha está vazia - não há nada para salvar</string>
<!-- Error message when there are no File Manager apps installed to select a folder when importing Bookmarks and Tracks -->
<string name="error_no_file_manager_app">Não é possível exibir a caixa de diálogo de seleção de pastas porque nenhum aplicativo adequado está instalado no seu dispositivo. Instale um aplicativo gerenciador de arquivos e tente novamente</string>
<string name="error_no_file_manager_app">Não é possível exibir a caixa de diálogo de seleção de pastas porque nenhum aplicativo adequado está instalado no seu dispositivo. Instale um aplicativo gerenciador de arquivos e tente novamente.</string>
<string name="choose_color">Escolher cor</string>
<string name="edit_track">Editar trilha</string>
<string name="uri_open_location_failed">Nenhum aplicativo instalado que possa abrir o local</string>
<!-- preference string for using auto theme only in navigation mode -->
<string name="nav_auto">Automático na navegação</string>
<string name="wikimedia_commons">Wikimedia Commons</string>
<string name="about_proposition_3">Rápido, minimalista, desenvolvido pela comunidade</string>
<string name="about_proposition_3">Não precisa de conexão à internet, rápido e leve</string>
<string name="drive_through">Drive-through</string>
<string name="editor_operator">Operador</string>
<string name="mb">MB</string>
<string name="gb">GB</string>
<string name="editor_line_social_network">LINE</string>
<string name="pref_map_style_title">Modo noturno</string>
<string name="off">Desativado</string>
<string name="on">Ativado</string>
<string name="menu">Menu</string>
<string name="news">Notícias</string>
<string name="github">GitHub</string>
<string name="telegram">Telegram</string>
<string name="matrix">[Matrix]</string>
<string name="about_developed_by_enthusiasts">Totalmente de código aberto, sem fins lucrativos, com processos de tomada de decisões e finanças transparentes.</string>
<string name="limited_accuracy">Precisão limitada</string>
<string name="pref_tts_street_names_title">Anunciar nomes de ruas</string>
<string name="faq">Perguntas frequentes</string>
<string name="bluesky">Bluesky</string>
<string name="openstreetmap">OpenStreetMap</string>
<string name="already_donated">Já doei</string>
<string name="remind_me_later">Lembre-me mais tarde</string>
<string name="mastodon">Mastodon</string>
<string name="facebook">Facebook</string>
<string name="twitter">X (Twitter)</string>
<string name="instagram">Instagram</string>
<string name="vk">VK</string>
<string name="app_site_url">https://comaps.app/pt-BR/</string>
<string name="dialog_routing_change_intermediate">Não foi possível localizar o ponto intermediário.</string>
<string name="editor_time_from">De</string>
<string name="how_to_support_us">Apoie o projeto</string>
<string name="google_play_services">Serviço de localização integrada do Google</string>
<string name="editor_time_title">Horário de funcionamento</string>
<string name="support_organic_maps">Apoie o CoMaps</string>
<string name="long_tap_toast">Dê um toque longo no mapa novamente para ver a interface</string>
<string name="editor_time_add">Adicionar horário</string>
<string name="editor_time_open">Aberto</string>
<string name="editor_time_close">Fechado</string>
<string name="editor_time_advanced">Modo avançado</string>
<string name="editor_time_simple">Modo simples</string>
<string name="editor_hours_closed">Horas sem funcionamento</string>
<string name="editor_example_values">Valores de exemplo</string>
<string name="editor_time_to">Para</string>
<string name="layers_title">Estilos e camadas de mapas</string>
<string name="export_file">Exportar KMZ</string>
<string name="export_file_gpx">Exportar GPX</string>
<string name="elevation_profile_descent">Descida</string>
<string name="elevation_profile_difficulty">Dificuldade</string>
<string name="osm_wiki_about_url">https://wiki.openstreetmap.org/wiki/Pt:Sobre_o_OpenStreetMap</string>
<string name="editor_focus_map_on_location">Mova o mapa para colocar a cruz na localização da empresa ou do local.</string>
<string name="pref_left_button_disable">Desabilitar</string>
<string name="saved">Salvo</string>
<string name="privacy">Privacidade</string>
<string name="pref_tts_speedcams_auto">Avisar se exceder limite de velocidade</string>
<string name="telegram_url">https://t.me/CoMapsApp/</string>
<string name="elevation_profile_ascent">Subida</string>
<string name="editor_other_info">Nota para os voluntários do OpenStreetMap (opcional)</string>
<string name="building">Edifício</string>
<string name="level">Andar</string>
<string name="editor_default_language_hint">Como escrito na língua local</string>
<string name="navigation_stop_button">Parar</string>
<string name="network">Rede: %s</string>
<string name="by_name">Por nome</string>
<string name="comma_separated_pair">%1$s, %2$s</string>
<string name="clear_the_search">Limpar a pesquisa</string>
<string name="zoom_out">Diminuir o zoom</string>
<string name="volume">Volume</string>
<string name="pref_left_button_title">Configuração do botão esquerdo</string>
<string name="error_enter_correct_facebook_page">Insira um endereço da web, conta ou nome de página válidos do Facebook</string>
<string name="error_enter_correct_line_page">Insira um ID de LINE ou endereço da web válido</string>
<string name="social_media">Redes sociais</string>
<string name="tts_info_link">https://www.comaps.app/support/tts-configuration-guide-for-android/</string>
<string name="editor_add_phone">Adicionar telefone</string>
<string name="outdoor_seating">Assentos ao ar livre</string>
<string name="capacity">Capacidade: %s</string>
<string name="editor_correct_mistake">Corrigir erro</string>
<string name="editor_add_select_location">Selecione a localização</string>
<string name="not_signed_in">Não conectado</string>
<string name="level_value_generic">Andar: %s</string>
<string name="editor_note_hint">Descreva erros no mapa ou coisas que não podem ser editadas com CoMaps</string>
<string name="operator">Operador: %s</string>
<string name="error_enter_correct_instagram_page">Insira um nome de usuário válido do Instagram ou endereço da web</string>
<string name="error_enter_correct_twitter_page">Digite um nome de usuário válido do Twitter ou endereço da web</string>
<string name="error_enter_correct_vk_page">Digite um nome de usuário ou endereço da web válido do VK</string>
<string name="error_enter_correct_fediverse_page">Digite um nome de usuário ou endereço da web válido do Mastodon</string>
<string name="error_enter_correct_bluesky_page">Digite um nome de usuário ou endereço da web válido do Bluesky</string>
<string name="prefs_languages_information_off">Para alguns idiomas, você precisará instalar um sintetizador de voz ou um pacote de idiomas adicional da loja de aplicativos (Google Play, Galaxy Store, App Gallery, FDroid).\nAbra as configurações do seu dispositivo → Idioma e entrada → Fala → Saída de texto para fala.\nAqui, você pode gerenciar as configurações de síntese de voz (por exemplo, baixar o pacote de idiomas para uso offline) e selecionar outro mecanismo de conversão de texto para fala.</string>
<string name="codeberg">Codeberg</string>
<string name="instagram_url">https://www.instagram.com/comapscommunity/</string>
</resources>

View File

@@ -887,4 +887,10 @@
<string name="instagram_url">https://www.instagram.com/comapscommunity</string>
<string name="codeberg">Codeberg</string>
<string name="telegram_url">https://t.me/CoMapsApp/</string>
<string name="pref_left_button_title">Sol alt tuş ataması</string>
<string name="pref_left_button_disable">Devre dışı</string>
<string name="error_enter_correct_fediverse_page">Gireceğiniz Mastodon kullanıcı adı ve adresi halihazırda mevcut olmalı</string>
<string name="saved">Kaydedildi</string>
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_bluesky_page">Gireceğiniz Bluesky kullanıcı adı ve adresi halihazırda mevcut olmalı</string>
</resources>

View File

@@ -1367,4 +1367,7 @@
<string name="type.fee.yes"></string>
<string name="type.power.pole">Elektrik Direği</string>
<string name="type.man_made.utility_pole">Hizmet Direği</string>
<string name="type.amenity.studio">Stüdyo</string>
<string name="type.sport.diving">Dalış Sporu</string>
<string name="type.man_made.survey_point">Anket Noktası</string>
</resources>

View File

@@ -503,7 +503,7 @@
<!-- Text in About and OSM Login screens. First %@ is replaced by a local, human readable date. -->
<string name="osm_presentation">截至 %s 的社群創建的 OpenStreetMap 資料。請訪問 OpenStreetMap.org 以了解有關如何編輯和更新地圖的更多資訊</string>
<!-- OSM explanation on Android login screen -->
<string name="login_osm_presentation">OpenStreetMap.orgOSM是一個建立免費開放地圖的社群專案。 它是CoMaps中地圖資料的主要來源其工作原理類似於維基百科。 您可以新增或編輯地點,可供全世界數以百萬計的使用者使用並受益。\n 加入OSM讓我們共繪更優質的地圖吧</string>
<string name="login_osm_presentation">OpenStreetMap.orgOSM是一個建立免費開放地圖的社群專案。 它是 CoMaps 中地圖資料的主要來源,其工作原理類似於維基百科。 您可以新增或編輯地點,可供全世界數以百萬計的使用者使用並受益。\n 加入OSM讓我們共繪更優質的地圖吧</string>
<string name="login_to_make_edits_visible">建立 OpenStreetMap 帳戶或登入以向全世界發布您的地圖編輯。</string>
<!-- Downloaded 10 **of** 20 <- it is that "of" -->
<string name="downloader_of">%1$d / %2$d</string>
@@ -892,4 +892,6 @@
<string name="error_enter_correct_fediverse_page">請輸入有效的 Mastodon 使用者名稱或網址</string>
<string name="error_enter_correct_bluesky_page">請輸入有效的 Bluesky 使用者名稱或網址</string>
<string name="bluesky">Bluesky</string>
<string name="pref_left_button_disable">停用</string>
<string name="pref_left_button_title">左側按鈕設定</string>
</resources>

View File

@@ -20,4 +20,16 @@
<string name="type.tourism.information.visitor_centre">旅遊服務中心</string>
<string name="type.man_made.silo">筒倉</string>
<string name="type.tourism.viewpoint">觀光景點</string>
<string name="type.highway.world_level">高速公路—世界級</string>
<string name="type.organic.only">有機</string>
<string name="type.recycling.cardboard">硬紙板</string>
<string name="type.recycling.cans">金屬罐</string>
<string name="type.recycling.shoes">鞋子</string>
<string name="type.recycling.green_waste">綠色垃圾/有機廢棄物</string>
<string name="type.recycling.cartons">紙盒</string>
<string name="type.highway.world_towns_level">高速公路—鎮級</string>
<string name="type.leisure.track.area">賽道</string>
<string name="type.organic.yes">有機</string>
<string name="type.power.pole">電線桿</string>
<string name="type.amenity.shelter.lean_to">三面避難所</string>
</resources>

View File

@@ -503,7 +503,7 @@
<!-- Text in About and OSM Login screens. First %@ is replaced by a local, human readable date. -->
<string name="osm_presentation">截至 %s 的社区创建的 OpenStreetMap 数据。请访问 OpenStreetMap.org 以了解有关如何编辑和更新地图的信息</string>
<!-- OSM explanation on Android login screen -->
<string name="login_osm_presentation">OpenStreetMap.orgOSM是一个构建免费开放地图的社区项目。它是CoMaps中地图数据的主要来源其工作原理类似于维基百科。您可以添加或编辑地点可供全世界数以百万计的用户使用并受益。\n加入OSM让我们共绘更优质的地图吧</string>
<string name="login_osm_presentation">OpenStreetMap.orgOSM是一个构建免费开放地图的社区项目。它是 CoMaps 中地图数据的主要来源,其工作原理类似于维基百科。您可以添加或编辑地点,可供全世界数以百万计的用户使用并受益。\n加入OSM让我们共绘更优质的地图吧</string>
<string name="login_to_make_edits_visible">创建 OpenStreetMap 账号或登录,向全世界发布您编辑的地图。</string>
<!-- Downloaded 10 **of** 20 <- it is that "of" -->
<string name="downloader_of">%1$d / %2$d</string>
@@ -892,4 +892,6 @@
<string name="bluesky">Bluesky</string>
<string name="error_enter_correct_bluesky_page">请输入有效的 Bluesky 用户名或网址</string>
<string name="saved">已保存</string>
<string name="pref_left_button_disable">禁用</string>
<string name="pref_left_button_title">左侧按钮设置</string>
</resources>

View File

@@ -652,7 +652,7 @@
<string name="type.leisure.swimming_pool">游泳池</string>
<string name="type.leisure.swimming_pool.private">游泳池</string>
<string name="type.leisure.track">賽道</string>
<string name="type.leisure.track.area"></string>
<string name="type.leisure.track.area"></string>
<string name="type.leisure.water_park">水上乐园</string>
<string name="type.leisure.beach_resort">海滨度假区</string>
<string name="type.man_made">人造要素</string>

View File

@@ -138,6 +138,8 @@
<color name="elevation_profile">#1E96F0</color>
<color name="elevation_profile_dark">#4BB9E6</color>
<color name="active_track_recording">#0057ff</color>
<color name="material_calendar_surface_dark">#929292</color>
<color name="notification_warning">#FFC22219</color>
</resources>

View File

@@ -41,6 +41,7 @@
<string name="pref_keep_screen_on" translatable="false">KeepScreenOn</string>
<string name="pref_show_on_lock_screen" translatable="false">ShowOnLockScreen</string>
<string name="pref_map_locale" translatable="false">MapLanguage</string>
<string name="pref_left_button" translatable="false">LeftButton</string>
<string name="notification_ticker_ltr" translatable="false">%1$s: %2$s</string>
<string name="notification_ticker_rtl" translatable="false">%2$s :%1$s</string>

View File

@@ -930,6 +930,6 @@
<!-- preference string for using auto theme only in navigation mode -->
<string name="nav_auto">Auto in navigation</string>
<string name="codeberg">Codeberg</string>
<string name="pref_universal_button">Universal button setup</string>
<string name="pref_universal_button_not_display">Do not display</string>
<string name="pref_left_button_title">Left button setup</string>
<string name="pref_left_button_disable">Disable</string>
</resources>

View File

@@ -28,16 +28,22 @@
app:singleLineTitle="false"
android:summary="@string/pref_zoom_summary"
android:order="2"/>
<ListPreference
android:key="@string/pref_left_button"
android:title="@string/pref_left_button_title"
app:singleLineTitle="false"
android:persistent="true"
android:order="3"/>
<SwitchPreferenceCompat
android:key="@string/pref_3d_buildings"
android:title="@string/pref_map_3d_buildings_title"
app:singleLineTitle="false"
android:order="3"/>
android:order="4"/>
<SwitchPreferenceCompat
android:key="@string/pref_autodownload"
android:title="@string/autodownload"
app:singleLineTitle="false"
android:order="4"/>
android:order="5"/>
<SwitchPreferenceCompat
android:key="@string/pref_large_fonts_size"
android:title="@string/big_font"
@@ -106,12 +112,6 @@
app:singleLineTitle="false"
android:persistent="false"
android:order="18"/>
<ListPreference
android:key="universal_button"
android:title="@string/pref_universal_button"
app:singleLineTitle="false"
android:persistent="true"
android:order="20"/>
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory

View File

@@ -67,7 +67,11 @@ UNIT_TEST(AlmostEqualULPs_double)
TEST(!base::AlmostEqualULPs(1.0, -1.0), ());
TEST(!base::AlmostEqualULPs(2.0, -2.0), ());
TEST(!base::AlmostEqualULPs(dmax, -dmax), ());
// That's why AlmostEqualULPs is a strange function, IMHO.
TEST(!base::AlmostEqualULPs(0.0, eps), ());
TEST(!base::AlmostEqualULPs(-eps, 0.0), ());
TEST(!base::AlmostEqualULPs(eps, 2.0*eps), ());
}
UNIT_TEST(AlmostEqualULPs_float)
@@ -91,7 +95,11 @@ UNIT_TEST(AlmostEqualULPs_float)
TEST(!base::AlmostEqualULPs(1.0f, -1.0f), ());
TEST(!base::AlmostEqualULPs(2.0f, -2.0f), ());
TEST(!base::AlmostEqualULPs(dmax, -dmax), ());
// That's why AlmostEqualULPs is a strange function, IMHO.
TEST(!base::AlmostEqualULPs(0.0f, eps), ());
TEST(!base::AlmostEqualULPs(-eps, 0.0f), ());
TEST(!base::AlmostEqualULPs(eps, 2.0f*eps), ());
}
UNIT_TEST(AlmostEqual_Smoke)

View File

@@ -34,6 +34,8 @@ public:
}
size_t size() const { return m_map.size(); }
auto begin() const { return m_map.begin(); }
auto end() const { return m_map.end(); }
protected:
/// @todo buffer_vector is not suitable now, because Key/Value is not default constructible.

View File

@@ -440,15 +440,66 @@ bool AlmostEqual(std::string const & str1, std::string const & str2, size_t mism
return false;
}
void ParseCSVRow(std::string const & s, char const delimiter, std::vector<std::string> & target)
namespace
{
// Trim, unquote the string, and unescape two double quotes.
std::string & UnescapeCSVColumn(std::string & s)
{
Trim(s);
if (s.size() < 2)
return s;
if (*s.begin() == '"' && *s.rbegin() == '"')
s = s.substr(1, s.size() - 2);
for (size_t i = 1; i < s.size(); ++i)
if (s[i] == '"' && s[i - 1] == '"')
s.erase(i, 1);
return s;
}
} // namespace
void ParseCSVRow(std::string const & row, char const delimiter, std::vector<std::string> & target)
{
target.clear();
TokenizeIterator<SimpleDelimiter, std::string::const_iterator, true /* KeepEmptyTokens */> it(s.begin(), s.end(), delimiter);
for (; it; ++it)
std::string prevColumns;
for (TokenizeIterator<SimpleDelimiter, std::string::const_iterator, true /* KeepEmptyTokens */> it {row.begin(), row.end(), delimiter}; it; ++it)
{
std::string column(*it);
Trim(column);
target.push_back(std::move(column));
std::string_view column = *it;
size_t const quotesCount = std::count(column.begin(), column.end(), '"');
bool const evenQuotes = quotesCount % 2 == 0;
if (prevColumns.empty())
{
if (evenQuotes)
{
if (quotesCount == 0)
target.emplace_back(column);
else
{
std::string strColumn {column};
target.push_back(UnescapeCSVColumn(strColumn));
}
}
else
{
prevColumns = column;
prevColumns.push_back(',');
}
}
else
{
prevColumns.append(column);
if (evenQuotes)
prevColumns.push_back(',');
else
{
target.push_back(UnescapeCSVColumn(prevColumns));
prevColumns.clear();
}
}
}
// Special case: if the string is empty, return an empty array instead of {""}.

View File

@@ -8,6 +8,8 @@
#include <string>
#include <vector>
namespace csv_reader_test
{
using platform::tests_support::ScopedFile;
using Row = coding::CSVReader::Row;
@@ -179,3 +181,41 @@ UNIT_TEST(CSVReaderIterator)
TEST_EQUAL(index, answer.size(), ());
}
}
UNIT_TEST(CSVReaderEmptyColumns)
{
auto const kContentWithEmptyColumns = ",,2,,4,\n,,,,,";
auto const fileName = "test.csv";
ScopedFile sf(fileName, kContentWithEmptyColumns);
Rows const answer = {{"", "", "2", "", "4", ""}, {"", "", "", "", "", ""}};
coding::CSVReader reader(sf.GetFullPath());
size_t index = 0;
while (auto const optionalRow = reader.ReadRow())
{
TEST_EQUAL(*optionalRow, answer[index], ());
++index;
}
TEST_EQUAL(index, answer.size(), ());
TEST(!reader.ReadRow(), ());
TEST(!reader.ReadRow(), ());
}
UNIT_TEST(CSVReaderQuotes)
{
auto const kContentWithQuotes = R"(noquotes, "" , "with space","with, comma","""double"" quotes","""double,"", commas", """""",)";
auto const fileName = "test.csv";
ScopedFile sf(fileName, kContentWithQuotes);
Rows const answer = {{"noquotes", "", "with space", "with, comma", "\"double\" quotes", "\"double,\", commas","\"\"", ""}};
coding::CSVReader reader(sf.GetFullPath());
size_t index = 0;
while (auto const optionalRow = reader.ReadRow())
{
TEST_EQUAL(*optionalRow, answer[index], ());
++index;
}
TEST_EQUAL(index, answer.size(), ());
TEST(!reader.ReadRow(), ());
TEST(!reader.ReadRow(), ());
}
} // namespace csv_reader_test

View File

@@ -1,14 +1,11 @@
#include "testing/testing.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/writer.hpp"
#include "base/logging.hpp"
#include <cstring> // strlen
#include <fstream>
#include <string>
#include <vector>
namespace file_data_test
{
@@ -220,6 +217,35 @@ UNIT_TEST(EmptyFile)
TEST(DeleteFileX(copy), ());
}
UNIT_TEST(RenameOnExistingFile)
{
using namespace base;
std::string const name = "test.empty";
std::string const copy = "test.empty.copy";
{
FileData f(name, FileData::Op::WRITE_TRUNCATE);
uint8_t const x = 1;
f.Write(&x, 1);
}
{
FileData f(copy, FileData::Op::WRITE_TRUNCATE);
uint8_t const x = 2;
f.Write(&x, 1);
}
TEST(RenameFileX(name, copy), ());
{
FileData f(copy, FileData::Op::READ);
uint8_t x;
f.Read(0, &x, 1);
TEST_EQUAL(x, 1, ());
}
TEST(DeleteFileX(copy), ());
}
// Made this 'obvious' test for getline. I had (or not?) behaviour when 'while (getline)' loop
// didn't get last string in file without trailing '\n'.
UNIT_TEST(File_StdGetLine)

View File

@@ -19,7 +19,7 @@ with open('countries-to-generate.json') as f1:
entry = {
"key": c,
"value": {
"profileName": "normal",
"profileName": "poor",
"tileCoordsSubset": list(),
"tilesAreBanned": False
}

View File

@@ -27,7 +27,7 @@
{
"key": "Algeria_Central",
"value": {
"profileName": "extra_small",
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
@@ -9691,6 +9691,262 @@
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Angola",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Australia_Northern Territory",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Australia_Queensland",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Australia_Western Australia",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Brazil_Mato Grosso",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Brazil_North Region_East",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Brazil_North Region_West",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Cameroon_Central",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Canada_Nunavut_North",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Canada_Nunavut_South",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "China_Gansu",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "China_Sichuan",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Colombia_East",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Congo-Kinshasa_West",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Indonesia_Central",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Indonesia_West",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Iran_East",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Kenya",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Libya",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Madagascar",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Malaysia",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Mali",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Mongolia",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Mozambique",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Myanmar",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Vietnam",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Nigeria_South",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Russia_Krasnoyarsk Krai_North",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Russia_Sakha Republic",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Tanzania",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Zambia",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
},
{
"key": "Zimbabwe",
"value": {
"profileName": "poor",
"tileCoordsSubset": [],
"tilesAreBanned": false
}
}
]
}
}

View File

@@ -63,13 +63,13 @@
{
"key": "poor",
"value": {
"alitudesStep": 500,
"alitudesStep": 100,
"gaussianFilterRFactor": 1.0,
"gaussianFilterStDev": 2.0,
"latLonStepFactor": 2,
"latLonStepFactor": 4,
"maxIsolinesLength": 500,
"medianFilterR": 1,
"simplificationZoom": 14
"simplificationZoom": 13
}
},
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
#include "testing/testing.hpp"
#include "drape_frontend/path_text_handle.hpp"
#include "drape_frontend/visual_params.hpp"
#include "base/logging.hpp"
@@ -15,10 +16,12 @@ bool IsSmooth(m2::SplineEx const & spline)
}
return true;
}
}
} // namespace
UNIT_TEST(Rounding_Spline)
{
df::VisualParams::Init(1.0, 1024);
m2::SplineEx spline1;
df::AddPointAndRound(spline1, m2::PointD(0, 200));
df::AddPointAndRound(spline1, m2::PointD(0, 0));

View File

@@ -3,54 +3,47 @@
#include "routing/routing_helpers.hpp"
#include "indexer/altitude_loader.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_altitude.hpp"
#include "indexer/feature_data.hpp"
#include "indexer/feature_processor.hpp"
#include "coding/files_container.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/read_write_utils.hpp"
#include "coding/reader.hpp"
#include "coding/succinct_mapper.hpp"
#include "coding/varint.hpp"
#include "geometry/latlon.hpp"
#include "base/assert.hpp"
#include "base/checked_cast.hpp"
#include "base/file_name_utils.hpp"
#include "base/logging.hpp"
#include "base/scope_guard.hpp"
#include "base/stl_helpers.hpp"
#include "base/string_utils.hpp"
#include "defines.hpp"
#include <algorithm>
#include <type_traits>
#include <utility>
#include <vector>
#include "3party/succinct/elias_fano.hpp"
#include "3party/succinct/mapper.hpp"
#include "3party/succinct/rs_bit_vector.hpp"
namespace routing
{
using namespace feature;
using namespace geometry;
namespace
{
using namespace routing;
class SrtmGetter : public AltitudeGetter
{
public:
explicit SrtmGetter(std::string const & srtmDir) : m_srtmManager(srtmDir) {}
// AltitudeGetter overrides:
geometry::Altitude GetAltitude(m2::PointD const & p) override
Altitude GetAltitude(m2::PointD const & p) override
{
return m_srtmManager.GetHeight(mercator::ToLatLon(p));
return m_srtmManager.GetAltitude(mercator::ToLatLon(p));
}
void PrintStatsAndPurge() override
{
LOG(LINFO, ("Srtm tiles number (x26Mb):", m_srtmManager.GeTilesNumber()));
m_srtmManager.Purge();
}
private:
@@ -62,39 +55,24 @@ class Processor
public:
struct FeatureAltitude
{
FeatureAltitude() : m_featureId(0) {}
FeatureAltitude(uint32_t featureId, Altitudes const & altitudes)
: m_featureId(featureId), m_altitudes(altitudes)
FeatureAltitude(uint32_t featureId, geometry::Altitudes && altitudes)
: m_featureId(featureId), m_altitudes(std::move(altitudes))
{
}
uint32_t m_featureId;
Altitudes m_altitudes;
feature::Altitudes m_altitudes;
};
using TFeatureAltitudes = std::vector<FeatureAltitude>;
explicit Processor(AltitudeGetter & altitudeGetter)
: m_altitudeGetter(altitudeGetter), m_minAltitude(geometry::kInvalidAltitude)
: m_minAltitude(geometry::kInvalidAltitude), m_altitudeGetter(altitudeGetter)
{
}
TFeatureAltitudes const & GetFeatureAltitudes() const { return m_featureAltitudes; }
succinct::bit_vector_builder & GetAltitudeAvailabilityBuilder()
void operator()(FeatureType & f, uint32_t id)
{
return m_altitudeAvailabilityBuilder;
}
geometry::Altitude GetMinAltitude() const { return m_minAltitude; }
void operator()(FeatureType & f, uint32_t const & id)
{
if (id != m_altitudeAvailabilityBuilder.size())
{
LOG(LERROR, ("There's a gap in feature id order."));
return;
}
CHECK_EQUAL(f.GetID().m_index, id, ());
CHECK_EQUAL(id, m_altitudeAvailabilityBuilder.size(), ());
bool hasAltitude = false;
SCOPE_GUARD(altitudeAvailabilityBuilding,
@@ -109,12 +87,19 @@ public:
return;
geometry::Altitudes altitudes;
geometry::Altitude minFeatureAltitude = geometry::kInvalidAltitude;
altitudes.reserve(pointsCount);
Altitude minFeatureAltitude = geometry::kInvalidAltitude;
for (size_t i = 0; i < pointsCount; ++i)
{
geometry::Altitude const a = m_altitudeGetter.GetAltitude(f.GetPoint(i));
auto const & pt = f.GetPoint(i);
Altitude const a = m_altitudeGetter.GetAltitude(pt);
if (a == geometry::kInvalidAltitude)
{
// Print warning for missing altitude point (if not a ferry or so).
auto const type = CarModel::AllLimitsInstance().GetHighwayType(feature::TypesHolder(f));
if (type && *type != HighwayType::RouteFerry && *type != HighwayType::RouteShuttleTrain)
LOG(LWARNING, ("Invalid altitude at:", mercator::ToLatLon(pt)));
// One invalid point invalidates the whole feature.
return;
}
@@ -128,7 +113,7 @@ public:
}
hasAltitude = true;
m_featureAltitudes.emplace_back(id, Altitudes(std::move(altitudes)));
m_featureAltitudes.emplace_back(id, std::move(altitudes));
if (m_minAltitude == geometry::kInvalidAltitude)
m_minAltitude = minFeatureAltitude;
@@ -138,22 +123,15 @@ public:
bool HasAltitudeInfo() const { return !m_featureAltitudes.empty(); }
bool IsFeatureAltitudesSorted()
{
return std::is_sorted(m_featureAltitudes.begin(), m_featureAltitudes.end(),
base::LessBy(&Processor::FeatureAltitude::m_featureId));
}
private:
AltitudeGetter & m_altitudeGetter;
TFeatureAltitudes m_featureAltitudes;
public:
std::vector<FeatureAltitude> m_featureAltitudes;
succinct::bit_vector_builder m_altitudeAvailabilityBuilder;
geometry::Altitude m_minAltitude;
Altitude m_minAltitude;
AltitudeGetter & m_altitudeGetter;
};
} // namespace
namespace routing
{
void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGetter)
{
try
@@ -161,28 +139,27 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
// Preparing altitude information.
Processor processor(altitudeGetter);
feature::ForEachFeature(mwmPath, processor);
processor.m_altitudeGetter.PrintStatsAndPurge();
if (!processor.HasAltitudeInfo())
{
LOG(LINFO, ("No altitude information for road features of mwm:", mwmPath));
// Possible for small islands like Bouvet or Willis.
LOG(LWARNING, ("No altitude information for road features of mwm:", mwmPath));
return;
}
CHECK(processor.IsFeatureAltitudesSorted(), ());
FilesContainerW cont(mwmPath, FileWriter::OP_WRITE_EXISTING);
auto w = cont.GetWriter(ALTITUDES_FILE_TAG);
AltitudeHeader header;
header.m_minAltitude = processor.GetMinAltitude();
header.m_minAltitude = processor.m_minAltitude;
auto const startOffset = w->Pos();
header.Serialize(*w);
{
// Altitude availability serialization.
coding::FreezeVisitor<Writer> visitor(*w);
succinct::bit_vector_builder & builder = processor.GetAltitudeAvailabilityBuilder();
succinct::rs_bit_vector(&builder).map(visitor);
succinct::rs_bit_vector(&processor.m_altitudeAvailabilityBuilder).map(visitor);
}
header.m_featureTableOffset = base::checked_cast<uint32_t>(w->Pos() - startOffset);
@@ -191,8 +168,7 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
{
// Altitude info serialization to memory.
MemWriter<std::vector<uint8_t>> writer(deltas);
Processor::TFeatureAltitudes const & featureAltitudes = processor.GetFeatureAltitudes();
for (auto const & a : featureAltitudes)
for (auto const & a : processor.m_featureAltitudes)
{
offsets.push_back(base::checked_cast<uint32_t>(writer.Pos()));
a.m_altitudes.Serialize(header.m_minAltitude, writer);
@@ -200,8 +176,7 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
}
{
// Altitude offsets serialization.
CHECK(std::is_sorted(offsets.begin(), offsets.end()), ());
CHECK(adjacent_find(offsets.begin(), offsets.end()) == offsets.end(), ());
CHECK(base::IsSortedAndUnique(offsets.begin(), offsets.end()), ());
succinct::elias_fano::elias_fano_builder builder(offsets.back(), offsets.size());
for (uint32_t offset : offsets)
@@ -221,9 +196,10 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
w->Seek(startOffset);
header.Serialize(w);
w->Seek(endOffset);
LOG(LINFO, (ALTITUDES_FILE_TAG, "section is ready. The size is", header.m_endOffset));
if (processor.HasAltitudeInfo())
LOG(LINFO, ("Min altitude is", processor.GetMinAltitude()));
LOG(LINFO, ("Min altitude is", processor.m_minAltitude));
else
LOG(LINFO, ("Min altitude isn't defined."));
}

View File

@@ -3,8 +3,6 @@
#include "geometry/point2d.hpp"
#include "geometry/point_with_altitude.hpp"
#include "indexer/feature_altitude.hpp"
#include <string>
namespace routing
@@ -13,6 +11,7 @@ class AltitudeGetter
{
public:
virtual geometry::Altitude GetAltitude(m2::PointD const & p) = 0;
virtual void PrintStatsAndPurge() {}
};
/// \brief Adds altitude section to mwm. It has the following format:

View File

@@ -13,7 +13,6 @@
#include "coding/varint.hpp"
#include "geometry/mercator.hpp"
#include "geometry/parametrized_segment.hpp"
#include "geometry/simplification.hpp"
#include "base/assert.hpp"
@@ -24,20 +23,18 @@
#include <cmath>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <vector>
#include "base/assert.hpp"
#include "base/string_utils.hpp"
#include "defines.hpp"
namespace borders
{
namespace
{
template <class ToDo>
void ForEachCountry(std::string const & baseDir, ToDo && toDo)
{
@@ -49,11 +46,11 @@ void ForEachCountry(std::string const & baseDir, ToDo && toDo)
Platform::GetFilesByExt(bordersDir, BORDERS_EXTENSION, files);
for (std::string file : files)
{
std::vector<m2::RegionD> polygons;
PolygonsList polygons;
if (LoadBorders(bordersDir + file, polygons))
{
base::GetNameWithoutExt(file);
toDo(file, polygons);
toDo(std::move(file), std::move(polygons));
}
}
}
@@ -65,7 +62,7 @@ public:
{
}
void operator()(std::string const & name, std::vector<m2::RegionD> const & borders)
void operator()(std::string name, PolygonsList && borders)
{
// use index in vector as tag
auto w = m_writer.GetWriter(strings::to_string(m_polys.size()));
@@ -105,7 +102,7 @@ private:
std::vector<storage::CountryDef> m_polys;
};
bool ReadPolygon(std::istream & stream, m2::RegionD & region, std::string const & filename)
bool ReadPolygon(std::istream & stream, Polygon & poly, std::string const & filename)
{
std::string line, name;
double lon, lat;
@@ -130,7 +127,7 @@ bool ReadPolygon(std::istream & stream, m2::RegionD & region, std::string const
iss >> lon >> lat;
CHECK(!iss.fail(), ("Incorrect data in", filename));
region.AddPoint(mercator::FromLatLon(lat, lon));
poly.AddPoint(mercator::FromLatLon(lat, lon));
}
// drop inner rings
@@ -146,7 +143,7 @@ bool CountryPolygons::Contains(m2::PointD const & point) const
});
}
bool LoadBorders(std::string const & borderFile, std::vector<m2::RegionD> & outBorders)
bool LoadBorders(std::string const & borderFile, PolygonsList & outBorders)
{
std::ifstream stream(borderFile);
std::string line;
@@ -156,12 +153,12 @@ bool LoadBorders(std::string const & borderFile, std::vector<m2::RegionD> & outB
return false;
}
m2::RegionD currentPolygon;
Polygon currentPolygon;
while (ReadPolygon(stream, currentPolygon, borderFile))
{
CHECK(currentPolygon.IsValid(), ("Invalid region in", borderFile));
outBorders.emplace_back(std::move(currentPolygon));
currentPolygon = m2::RegionD();
currentPolygon = {};
}
CHECK(!outBorders.empty(), ("No borders were loaded from", borderFile));
@@ -178,7 +175,7 @@ bool GetBordersRect(std::string const & baseDir, std::string const & country,
return false;
}
std::vector<m2::RegionD> borders;
PolygonsList borders;
CHECK(LoadBorders(bordersFile, borders), ());
bordersRect.MakeEmpty();
for (auto const & border : borders)
@@ -192,13 +189,16 @@ CountryPolygonsCollection LoadCountriesList(std::string const & baseDir)
LOG(LINFO, ("Loading countries in", BORDERS_DIR, "folder in", baseDir));
CountryPolygonsCollection countryPolygonsCollection;
ForEachCountry(baseDir, [&](auto const & name, auto const & borders)
ForEachCountry(baseDir, [&](std::string name, PolygonsList && borders)
{
PolygonsTree polygons;
for (m2::RegionD const & border : borders)
polygons.Add(border, border.GetRect());
for (Polygon & border : borders)
{
auto const rect = border.GetRect();
polygons.Add(std::move(border), rect);
}
countryPolygonsCollection.Add(CountryPolygons(name, polygons));
countryPolygonsCollection.Add(CountryPolygons(std::move(name), std::move(polygons)));
});
LOG(LINFO, ("Countries loaded:", countryPolygonsCollection.GetSize()));
@@ -214,7 +214,7 @@ void GeneratePackedBorders(std::string const & baseDir)
}
void DumpBorderToPolyFile(std::string const & targetDir, storage::CountryId const & mwmName,
std::vector<m2::RegionD> const & polygons)
PolygonsList const & polygons)
{
CHECK(!polygons.empty(), ());
@@ -222,7 +222,8 @@ void DumpBorderToPolyFile(std::string const & targetDir, storage::CountryId cons
std::ofstream poly(filePath);
CHECK(poly.good(), ());
poly << std::setprecision(20) << std::fixed;
// Used to have fixed precicion with 6 digits. And Alaska has 4 digits after comma :) Strange, but as is.
poly << std::setprecision(6) << std::fixed;
poly << mwmName << std::endl;
size_t polygonId = 1;

View File

@@ -1,7 +1,5 @@
#pragma once
#include "generator/feature_builder.hpp"
#include "storage/storage_defines.hpp"
#include "coding/geometry_coding.hpp"
@@ -11,12 +9,9 @@
#include "geometry/region2d.hpp"
#include "geometry/tree4d.hpp"
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#define BORDERS_DIR "borders/"
@@ -48,9 +43,8 @@ class CountryPolygons
{
public:
CountryPolygons() = default;
explicit CountryPolygons(std::string const & name, PolygonsTree const & regions)
: m_name(name)
, m_polygons(regions)
explicit CountryPolygons(std::string && name, PolygonsTree && regions)
: m_name(std::move(name)), m_polygons(std::move(regions))
{
}
@@ -97,6 +91,8 @@ public:
private:
std::string m_name;
/// @todo Is it an overkill to store Tree4D for each country's polygon?
PolygonsTree m_polygons;
};
@@ -105,11 +101,15 @@ class CountryPolygonsCollection
public:
CountryPolygonsCollection() = default;
void Add(CountryPolygons const & countryPolygons)
void Add(CountryPolygons && countryPolygons)
{
auto const it = m_countryPolygonsMap.emplace(countryPolygons.GetName(), countryPolygons);
countryPolygons.ForEachPolygon([&](auto const & polygon) {
m_regionsTree.Add(it.first->second, polygon.GetRect());
auto const res = m_countryPolygonsMap.emplace(countryPolygons.GetName(), std::move(countryPolygons));
CHECK(res.second, ());
auto const & inserted = res.first->second;
inserted.ForEachPolygon([&inserted, this](Polygon const & polygon)
{
m_regionsTree.Add(inserted, polygon.GetRect());
});
}
@@ -119,9 +119,10 @@ public:
void ForEachCountryInRect(m2::RectD const & rect, ToDo && toDo) const
{
std::unordered_set<CountryPolygons const *> uniq;
m_regionsTree.ForEachInRect(rect, [&](auto const & countryPolygons) {
if (uniq.emplace(&countryPolygons.get()).second)
toDo(countryPolygons);
m_regionsTree.ForEachInRect(rect, [&](CountryPolygons const & cp)
{
if (uniq.insert(&cp).second)
toDo(cp);
});
}
@@ -142,8 +143,10 @@ private:
std::unordered_map<std::string, CountryPolygons> m_countryPolygonsMap;
};
using PolygonsList = std::vector<Polygon>;
/// @return false if borderFile can't be opened
bool LoadBorders(std::string const & borderFile, std::vector<m2::RegionD> & outBorders);
bool LoadBorders(std::string const & borderFile, PolygonsList & outBorders);
bool GetBordersRect(std::string const & baseDir, std::string const & country,
m2::RectD & bordersRect);
@@ -153,10 +156,10 @@ bool LoadCountriesList(std::string const & baseDir, CountryPolygonsCollection &
void GeneratePackedBorders(std::string const & baseDir);
template <typename Source>
std::vector<m2::RegionD> ReadPolygonsOfOneBorder(Source & src)
PolygonsList ReadPolygonsOfOneBorder(Source & src)
{
auto const count = ReadVarUint<uint32_t>(src);
std::vector<m2::RegionD> result(count);
PolygonsList result(count);
for (size_t i = 0; i < count; ++i)
{
std::vector<m2::PointD> points;
@@ -168,7 +171,7 @@ std::vector<m2::RegionD> ReadPolygonsOfOneBorder(Source & src)
}
void DumpBorderToPolyFile(std::string const & filePath, storage::CountryId const & mwmName,
std::vector<m2::RegionD> const & polygons);
PolygonsList const & polygons);
void UnpackBorders(std::string const & baseDir, std::string const & targetDir);
CountryPolygonsCollection const & GetOrCreateCountryPolygonsTree(std::string const & baseDir);

View File

@@ -2,7 +2,6 @@
#include "generator/utils.hpp"
#include "indexer/feature.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "indexer/feature_processor.hpp"
#include "platform/platform.hpp"
@@ -88,45 +87,38 @@ std::string DescriptionsCollectionBuilderStat::LangStatisticsToString() const
void DescriptionsCollector::operator() (FeatureType & ft, uint32_t featureId)
{
auto const & attractionsChecker = ftypes::AttractionsChecker::Instance();
if (!attractionsChecker(ft))
return;
// auto const & attractionsChecker = ftypes::AttractionsChecker::Instance();
// if (!attractionsChecker(ft))
// return;
(*this)(ft.GetMetadata().GetWikiURL(), featureId);
}
void DescriptionsCollector::operator() (std::string const & wikiUrl, uint32_t featureId)
{
std::string path;
descriptions::LangMeta langsMeta;
size_t size = 0;
// First try to get wikipedia url.
bool const isWikiUrl = !wikiUrl.empty();
if (isWikiUrl)
if (!wikiUrl.empty())
size = FindPageAndFill(MakePathForWikipedia(m_wikipediaDir, wikiUrl), langsMeta);
// Second try to get wikidata id.
bool const isWikiUrl = !langsMeta.empty();
if (!isWikiUrl)
{
path = MakePathForWikipedia(m_wikipediaDir, wikiUrl);
}
else
{
// Second try to get wikidata id.
auto const wikidataId = m_wikidataHelper.GetWikidataId(featureId);
if (wikidataId)
path = MakePathForWikidata(m_wikipediaDir, *wikidataId);
size = FindPageAndFill(MakePathForWikidata(m_wikipediaDir, *wikidataId), langsMeta);
}
if (path.empty())
if (langsMeta.empty())
return;
descriptions::LangMeta langsMeta;
int const sz = FindPageAndFill(path, langsMeta);
if (sz < 0)
{
LOG(LWARNING, ("Page", path, "not found."));
return;
}
else if (sz > 0)
if (size > 0)
{
// Add only new loaded pages (not from cache).
m_stat.AddSize(sz);
m_stat.AddSize(size);
m_stat.IncPage();
}
@@ -166,10 +158,10 @@ std::string DescriptionsCollector::FillStringFromFile(std::string const & fullPa
return std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
}
int DescriptionsCollector::FindPageAndFill(std::string const & path, descriptions::LangMeta & meta)
size_t DescriptionsCollector::FindPageAndFill(std::string const & path, descriptions::LangMeta & meta)
{
int size = -1;
if (!IsValidDir(path))
size_t size = 0;
if (path.empty() || !IsValidDir(path))
return size;
Platform::FilesList filelist;
@@ -184,24 +176,27 @@ int DescriptionsCollector::FindPageAndFill(std::string const & path, description
continue;
}
if (size < 0)
size = 0;
m_stat.IncCode(code);
auto res = m_path2Index.try_emplace(base::JoinPath(path, filename), 0);
if (res.second)
{
auto const & filePath = res.first->first;
auto content = FillStringFromFile(filePath);
size_t const sz = content.size();
if (sz == 0)
{
LOG(LWARNING, ("Empty descriptions file:", filePath));
m_path2Index.erase(res.first);
continue;
}
auto & strings = m_collection.m_strings;
res.first->second = strings.size();
strings.push_back(FillStringFromFile(filePath));
strings.push_back(std::move(content));
size_t const sz = strings.back().size();
CHECK(sz > 0, ("Empty file:", filePath));
size += sz;
}
m_stat.IncCode(code);
meta.emplace_back(code, res.first->second);
}

View File

@@ -78,8 +78,8 @@ public:
static std::string FillStringFromFile(std::string const & fullPath);
/// @return -1 If page not found. 0 if page from cache. Size > 0 if page was loaded from disk.
int FindPageAndFill(std::string const & wikipediaUrl, descriptions::LangMeta & meta);
/// @return Aggregated loaded from disk page's size.
size_t FindPageAndFill(std::string const & wikipediaUrl, descriptions::LangMeta & meta);
public:
DescriptionsCollectionBuilderStat m_stat;

View File

@@ -188,7 +188,7 @@ public:
for (uint32_t i = 0; i < numPoints; ++i)
{
// Feature segment altitude.
geometry::Altitude altitude = m_srtmManager.GetHeight(mercator::ToLatLon(f.GetPoint(i)));
geometry::Altitude altitude = m_srtmManager.GetAltitude(mercator::ToLatLon(f.GetPoint(i)));
pointAltitudes[i] = altitude == geometry::kInvalidAltitude ? 0 : altitude;
if (i == 0)
{

View File

@@ -113,8 +113,10 @@ public:
StringUtf8Multilang str;
std::string const badUrl = "https://en.wikipedia.org/wiki/Not_exists";
auto const path = DescriptionsCollector::MakePathForWikipedia(m_wikiDir, badUrl);
descriptions::LangMeta meta;
TEST_EQUAL(collector.FindPageAndFill(path, meta), -1, ());
TEST_EQUAL(collector.FindPageAndFill(path, meta), 0, ());
TEST(meta.empty(), ());
}
}

View File

@@ -2,13 +2,26 @@
#include "generator/srtm_parser.hpp"
using namespace generator;
#include "coding/endianness.hpp"
namespace
#include <iostream>
namespace srtm_parser_test
{
inline std::string GetBase(ms::LatLon const & coord) { return SrtmTile::GetBase(coord); }
using namespace generator;
using namespace geometry;
UNIT_TEST(FilenameTests)
inline std::string GetBase(ms::LatLon const & coord)
{
return SrtmTile::GetBase(coord);
}
inline SrtmTile::LatLonKey GetKey(ms::LatLon const & coord)
{
return SrtmTile::GetKey(coord);
}
UNIT_TEST(SRTM_FilenameTest)
{
auto name = GetBase({56.4566, 37.3467});
TEST_EQUAL(name, "N56E037", ());
@@ -16,13 +29,110 @@ UNIT_TEST(FilenameTests)
name = GetBase({34.077433, -118.304569});
TEST_EQUAL(name, "N34W119", ());
name = GetBase({1.0, 1.0});
TEST_EQUAL(name, "N01E001", ());
name = GetBase({0.1, 0.1});
TEST_EQUAL(name, "N00E000", ());
TEST_NOT_EQUAL(GetKey({0.1, 0.1}), GetKey({1.0, 1.0}), ());
name = GetBase({-0.1, -0.1});
TEST_EQUAL(name, "S01W001", ());
TEST_NOT_EQUAL(GetKey({0.1, 0.1}), GetKey({-0.1, -0.1}), ());
name = GetBase({-0.9, -0.9});
TEST_EQUAL(name, "S01W001", ());
TEST_EQUAL(GetKey({-0.9, -0.9}), GetKey({-0.1, -0.1}), ());
name = GetBase({-1.0, -1.0});
TEST_EQUAL(name, "S01W001", ());
TEST_EQUAL(GetKey({-0.9, -0.9}), GetKey({-1.0, -1.0}), ());
name = GetBase({-1.9, -1.1});
TEST_EQUAL(name, "S02W002", ());
TEST_NOT_EQUAL(GetKey({-1.1, -1.1}), GetKey({-1.0, -1.0}), ());
name = GetBase({-35.35, -12.1});
TEST_EQUAL(name, "S36W013", ());
name = GetBase({-34.622358, -58.383654});
TEST_EQUAL(name, "S35W059", ());
}
} // namespace
UNIT_TEST(SRTM_TileTest)
{
SrtmTile tile;
size_t sz;
Altitude * data = tile.DataForTests(sz);
// Fill 5 last rows:
// -4 -4 -4
// -2 -2 -2
// 0 0 0
// 2 2 2
// 4 4 4
size_t row = sz - 1;
for (Altitude a = 4; a >= -4; a -= 2)
{
for (size_t i = row * sz; i < (row + 1) * sz; ++i)
data[i] = ReverseByteOrder(a);
--row;
}
double const len = 1.0 / (sz - 1);
TEST_EQUAL(tile.GetHeight({0, 0}), 4, ());
TEST_ALMOST_EQUAL_ULPS(tile.GetTriangleHeight({0, 0}), 4.0, ());
TEST_ALMOST_EQUAL_ULPS(tile.GetBilinearHeight({0, 0}), 4.0, ());
TEST_EQUAL(tile.GetHeight({len, len}), 2, ());
TEST_ALMOST_EQUAL_ULPS(tile.GetTriangleHeight({len, len}), 2.0, ());
TEST_ALMOST_EQUAL_ULPS(tile.GetBilinearHeight({len, len}), 2.0, ());
double l = len / 2;
Altitude h = tile.GetHeight({l, l});
TEST(h == 4 || h == 2, (h));
TEST_ALMOST_EQUAL_ULPS(tile.GetTriangleHeight({l, l}), 3.0, ());
TEST_ALMOST_EQUAL_ULPS(tile.GetBilinearHeight({l, l}), 3.0, ());
l = 3 * len + len / 2;
h = tile.GetHeight({l, l});
TEST(h == -4 || h == -2, (h));
TEST_ALMOST_EQUAL_ULPS(tile.GetTriangleHeight({l, l}), -3.0, ());
TEST_ALMOST_EQUAL_ULPS(tile.GetBilinearHeight({l, l}), -3.0, ());
}
/*
UNIT_TEST(SRTM_SamplesTest)
{
SrtmTileManager manager("/Users/vng/SRTM");
std::initializer_list<ms::LatLon> arr[] = {
{{ 41.899802800880578957, 12.498703841110341273}, { 41.899748897914214751, 12.498642150302543996}, { 41.899315676124750496, 12.498172763721441925}, { 41.899207869324136766, 12.498057428732948893 }},
{{ 41.900315874986389986, 12.499267105007675127}, { 41.900234022973513959, 12.499175909900486658}, { 41.899802800880578957, 12.498703841110341273 }},
{{ 41.899317672545265623, 12.499556783583443575}, { 41.899704976945002954, 12.498910371206022774}, { 41.899716955394147533, 12.49888623132471821}, { 41.899730930248637151, 12.498862091443413647}, { 41.899744905100071435, 12.49882990493497914}, { 41.899760876355117034, 12.498797718426573056}, { 41.899772854793766896, 12.498768214127181864}, { 41.899788826041820755, 12.498736027618775779}, { 41.899802800880578957, 12.498703841110341273 }},
{{ 41.900297907480371862, 12.497869674100513748}, { 41.900259976062137923, 12.497931364908311025}, { 41.899866685818835776, 12.498593870539906447}, { 41.899834743357700972, 12.498647514720602203}, { 41.899818772121129484, 12.498674336810950081}, { 41.899802800880578957, 12.498703841110341273 }},
{{ 41.899728933841061007, 12.497309092412223208}, { 41.900224041013551357, 12.497850898637267392}, { 41.90023202658165502, 12.49786430968242712}, { 41.900224041013551357, 12.497888449563731683}, { 41.899826757739916161, 12.498548272986312213}, { 41.899808790096251698, 12.498556319613442156}, { 41.899802800880578957, 12.498550955195355527}, { 41.89979281885320006, 12.498545590777297321}, { 41.899307690442057606, 12.498009148970311344}, { 41.899301701179375357, 12.497995737925151616}, { 41.899309686862821422, 12.497976962461905259}, { 41.899716955394147533, 12.497311774621238101}, { 41.899728933841061007, 12.497309092412223208 }},
{{ 41.899802800880578957, 12.498550955195355527}, { 41.899748897914214751, 12.498642150302543996}, { 41.899681020039992063, 12.498754803082022136 }},
{{ 41.899912603078725226, 12.498650196929645517}, { 41.899866685818835776, 12.498593870539906447}, { 41.899826757739916161, 12.498548272986312213 }},
{{ 41.899994455503602353, 12.498516086477906128}, { 41.899912603078725226, 12.498650196929645517}, { 41.899912603078725226, 12.498685065647094916}, { 41.900285929140210328, 12.499090079211356397}, { 41.90030589303923847, 12.499111536883646068}, { 41.90070516970908443, 12.498435620206862495}, { 41.900711158840110215, 12.49842489137071766}, { 41.900715151593857399, 12.498408798116514618}, { 41.900713155217019334, 12.498398069280369782}, { 41.90056342677709722, 12.498237136738282516}, { 41.900327853320931126, 12.497979644670920152}, { 41.900317871375655443, 12.497976962461905259}, { 41.900307889428788144, 12.497982326879963466}, { 41.899994455503602353, 12.498516086477906128 }},
{{ 44.759886801735603967, 34.316046940654871378 }, { 44.759500178870737841, 34.315553414192436321 }, { 44.759132599068138347, 34.315443443622029918 }, { 44.758765016927078761, 34.315430032576841768 }, { 44.758071746835689453, 34.315253006780551459 }, { 44.758037464032938146, 34.315255688989566352 }, { 44.757483222565575431, 34.315306650961247215 }, { 44.756708037437867631, 34.315676795808059296 }, { 44.756323297960172169, 34.315652655926726311 }, { 44.755963316624225001, 34.315430032576841768 }, { 44.755833798981250027, 34.315153765046261469 }, { 44.755789991477485046, 34.314949917159594861 }},
{{ 44.759886801735603967, 34.316046940654871378 }, { 44.760006787615907342, 34.315175222718522718 }, { 44.760048687388419353, 34.315011607967392138 }, { 44.760260090322724125, 34.314772891363304552 }, { 44.760437211104594724, 34.314665603001913041 }, { 44.760572431981174191, 34.314383971053246114 }, { 44.760701939002856875, 34.314300822573159166 }, { 44.761223773178279828, 34.314088928059419459 }, { 44.761292334982400121, 34.314091610268434351 }, { 44.761376132632506142, 34.314011143997390718 }, { 44.761667518969709079, 34.313895809008897686 }, { 44.761739889204726239, 34.31379924948365101 }, { 44.761739889204726239, 34.313705372167419227 }, { 44.76183130410882427, 34.313568579506636524 }, { 44.761930336758403826, 34.313549804043390168 }, { 44.761981757490261202, 34.313442515681998657 }, { 44.762050318394869919, 34.313396918128404423 }, { 44.762176013175370315, 34.313391553710346216 }, { 44.762316943361625476, 34.313359367201911709 }, { 44.762610229403847484, 34.313332545111563832 }, { 44.762627369451166714, 34.313343273947708667 }, { 44.762663553978839559, 34.313313769648317475 }, { 44.762673076219179791, 34.313278900930868076 }, { 44.762678789562635018, 34.313233303377273842 }, { 44.762692120695184883, 34.31320379907788265 }, { 44.762720687397411723, 34.313182341405621401 }, { 44.762734018520298207, 34.313107239552635974 }, { 44.762747349640086725, 34.313091146298432932 }, { 44.7628063874193316, 34.313101875134577767 }, { 44.76292065391750441, 34.313123332806839016 }, { 44.762977787081830172, 34.313056277580983533 }, { 44.763063486722373341, 34.313107239552635974 }, { 44.763282496337311045, 34.313088464089389618 }},
{{ 44.756521381971580809, 34.332137512655094724 }, { 44.756469956380023234, 34.331619846311355104 }, { 44.756412816780184016, 34.331308710063325407 }, { 44.756359486436011252, 34.331040489159818208 }, { 44.75633282124546497, 34.330965387306861203 }, { 44.756294728094793811, 34.330860781154484584 }, { 44.756264253556160781, 34.330694484194339111 }, { 44.756294728094793811, 34.330608653505208849 }, { 44.756323297960172169, 34.330533551652223423 }, { 44.756433767973362592, 34.330359208064976428 }, { 44.756555665673857902, 34.330109762624715586 }, { 44.756641374840555159, 34.329940783455526798 }, { 44.756755653531747896, 34.329755711032106547 }, { 44.757010875126020721, 34.329463350247323206 }, { 44.757180387352946127, 34.329117345281815687 }, { 44.757266095593031707, 34.32893495506743875 }, { 44.757448939413642108, 34.328564810220626669 }, { 44.757591785745901802, 34.328301953735206098 }, { 44.757746059388104243, 34.327797698436654628 }, { 44.757807006886359602, 34.327470468934393466 }, { 44.75787366813893442, 34.327239798957407402 }, { 44.757986039790637278, 34.327089595251464971 }, { 44.758026036427494887, 34.326995717935233188 }, { 44.758113648011466523, 34.326907205037088033 }, { 44.75817078592944398, 34.326783823421465058 }, { 44.758237446762365153, 34.326400267529493249 }, { 44.758264111073970071, 34.3263519877668557 }, { 44.758357436067782942, 34.326177644179608706 }, { 44.758412669156371066, 34.325909423276101506 }, { 44.758505993910240761, 34.325775312824362118 }, { 44.758526944344453113, 34.325598287028071809 }, { 44.758479329710219474, 34.325461494367289106 }, { 44.758391718680712756, 34.325370299260100637 }, { 44.758429810449001707, 34.32524423543546277 }, { 44.75854789477109108, 34.325085985102390396 }, { 44.758637410144764601, 34.324914323724158294 }, { 44.758685024648755757, 34.324734615718824671 }, { 44.758707879596705936, 34.324613916312273432 }, { 44.758766921503791991, 34.324568318758679197 }, { 44.758749780311177346, 34.32444225493404133 }, { 44.758799299298182461, 34.324206220538968637 }, { 44.75882786792522694, 34.323988961607142301 }, { 44.758825963350531651, 34.323667096522939346 }, { 44.758843104520543932, 34.323423015500765132 }, { 44.758862150259034252, 34.323181616687634232 }, { 44.758915478293424428, 34.322983133219054253 }, { 44.758944046863021526, 34.322875844857662742 }, { 44.759084984933011242, 34.322862433812474592 }, { 44.758966901708539865, 34.32266126813487972 }, { 44.758865959405987667, 34.32256202640058973 }, { 44.758753589465527511, 34.322331356423575244 }, { 44.75867359717138072, 34.322089957610444344 }, { 44.758690738386590624, 34.321875380887661322 }, { 44.758690738386590624, 34.321754681481081661 }, { 44.758698356702829813, 34.321642028701631943 }, { 44.758643123887310367, 34.321379172216211373 }, { 44.758641219306547043, 34.321231650719283834 }, { 44.758665978851873035, 34.321027802832645648 }, { 44.758732639113461005, 34.320837365991167189 }, { 44.75867359717138072, 34.320502089861804507 }, { 44.75867931091034535, 34.320392119291369681 }, { 44.758808822175438991, 34.320268737675775128 }, { 44.758793585571083895, 34.320099758506557919 }, { 44.758978329127899087, 34.319783257840441593 }, { 44.759109744288181787, 34.319584774371861613 }, { 44.75926782299799811, 34.31950430810081798 }, { 44.759357337256332698, 34.319305824632238 }, { 44.759387810163708821, 34.319016146056469552 }, { 44.759481133342561066, 34.318686234345193498 }, { 44.75951351073673834, 34.318530666221164438 }, { 44.759524938047988485, 34.318332182752584458 }, { 44.759637306488322395, 34.317903029306989993 }, { 44.759671588341880977, 34.317436324934931235 }, { 44.759871565415501493, 34.317044722415829483 }, { 44.759902038051663453, 34.316647755478669524 }, { 44.759915369824923914, 34.316167640061422617 }, { 44.759886801735603967, 34.316046940654871378 }},
};
using namespace std;
for (auto const & points : arr)
{
for (auto const & p : points)
cout << manager.GetTriangleHeight(p) << ", ";
cout << endl;
}
}
*/
} // namespace srtm_parser_test

View File

@@ -7,6 +7,7 @@
#include "routing/maxspeeds_serialization.hpp"
#include "routing/routing_helpers.hpp"
#include "routing_common/car_model_coefs.hpp"
#include "routing_common/maxspeed_conversion.hpp"
#include "indexer/feature.hpp"
@@ -37,6 +38,10 @@ using namespace routing;
using std::string;
char constexpr kDelim[] = ", \t\r\n";
double constexpr kMinDefSpeedRoadsLengthKm = 5.0;
double constexpr kMaxPossibleDefSpeedKmH = 400.0;
// This factor should be greater than sqrt(2) / 2 - prefer diagonal link to square path.
double constexpr kLinkToMainSpeedFactor = 0.85;
template <class TokenizerT> bool ParseOneSpeedValue(TokenizerT & iter, MaxspeedType & value)
{
@@ -68,11 +73,21 @@ class MaxspeedsMwmCollector
{
double m_lengthKM = 0;
double m_timeH = 0;
double m_speed = -1; // invalid initial value
friend std::string DebugPrint(AvgInfo const & i)
{
std::ostringstream ss;
ss << "AvgInfo{ " << i.m_speed << ", " << i.m_lengthKM << ", " << i.m_timeH << " }";
return ss.str();
}
};
static int constexpr SPEEDS_COUNT = MaxspeedsSerializer::DEFAULT_SPEEDS_COUNT;
static int constexpr kSpeedsCount = MaxspeedsSerializer::DEFAULT_SPEEDS_COUNT;
static int constexpr kOutsideCityIdx = 0;
// 0 - outside a city; 1 - inside a city.
std::unordered_map<HighwayType, AvgInfo> m_avgSpeeds[SPEEDS_COUNT];
std::unordered_map<HighwayType, AvgInfo> m_avgSpeeds[kSpeedsCount];
base::GeoObjectId GetOsmID(uint32_t fid) const
{
@@ -87,10 +102,14 @@ class MaxspeedsMwmCollector
return m_graph->GetRoadGeometry(fid);
}
// OSM data related warning tag for convenient grep.
std::string m_logTag;
public:
MaxspeedsMwmCollector(string const & dataPath, FeatureIdToOsmId const & ft2osm, IndexGraph * graph)
: m_dataPath(dataPath), m_ft2osm(ft2osm), m_graph(graph)
, m_converter(MaxspeedConverter::Instance())
, m_logTag("SpeedsBuilder")
{
}
@@ -146,9 +165,8 @@ public:
(*parentHwType == HighwayType::HighwayTertiary && hwType == HighwayType::HighwayTertiaryLink))
{
// Reduce factor from parent road. See DontUseLinksWhenRidingOnMotorway test.
// 0.85, this factor should be greater than sqrt(2) / 2 - prefer diagonal link to square path.
return converter.ClosestValidMacro(
{ base::asserted_cast<MaxspeedType>(std::lround(s.GetForward() * 0.85)), s.GetUnits() });
{ base::asserted_cast<MaxspeedType>(std::lround(s.GetForward() * kLinkToMainSpeedFactor)), s.GetUnits() });
}
return {};
@@ -265,8 +283,16 @@ public:
});
}
private:
void AddSpeed(uint32_t featureID, uint64_t osmID, Maxspeed const & speed)
{
MaxspeedType constexpr kMaxReasonableSpeed = 280;
if ((speed.GetSpeedKmPH(true) >= kMaxReasonableSpeed) ||
(speed.IsBidirectional() && speed.GetSpeedKmPH(false) >= kMaxReasonableSpeed))
{
LOG(LWARNING, (m_logTag, "Very big speed", speed, "for way", osmID));
}
// Add converted macro speed.
SpeedInUnits const forward(speed.GetForward(), speed.GetUnits());
CHECK(forward.IsValid(), ());
@@ -278,12 +304,12 @@ public:
if (ftSpeed.m_forward == SpeedMacro::Undefined)
{
LOG(LWARNING, ("Undefined forward speed macro", forward, "for way", osmID));
LOG(LWARNING, (m_logTag, "Undefined forward speed macro", forward, "for way", osmID));
return;
}
if (backward.IsValid() && backwardMacro == SpeedMacro::Undefined)
{
LOG(LWARNING, ("Undefined backward speed macro", backward, "for way", osmID));
LOG(LWARNING, (m_logTag, "Undefined backward speed macro", backward, "for way", osmID));
}
m_maxspeeds.push_back(ftSpeed);
@@ -311,36 +337,167 @@ public:
}
}
else
LOG(LWARNING, ("Undefined HighwayType for way", osmID));
LOG(LWARNING, (m_logTag, "Undefined HighwayType for way", osmID));
}
void SerializeMaxspeeds() const
public:
void CalculateDefaultTypeSpeeds(MaxspeedsSerializer::HW2SpeedMap typeSpeeds[])
{
if (m_maxspeeds.empty())
return;
MaxspeedsSerializer::HW2SpeedMap typeSpeeds[SPEEDS_COUNT];
for (int ind = 0; ind < SPEEDS_COUNT; ++ind)
std::vector<std::pair<HighwayType, InOutCitySpeedKMpH>> baseSpeeds(
kHighwayBasedSpeeds.begin(), kHighwayBasedSpeeds.end());
// Remove links, because they don't conform speed consistency.
baseSpeeds.erase(std::remove_if(baseSpeeds.begin(), baseSpeeds.end(), [](auto const & e)
{
LOG(LINFO, ("Average speeds", ind == 0 ? "outside" : "inside", "a city:"));
return (e.first == HighwayType::HighwayMotorwayLink ||
e.first == HighwayType::HighwayTrunkLink ||
e.first == HighwayType::HighwayPrimaryLink ||
e.first == HighwayType::HighwaySecondaryLink ||
e.first == HighwayType::HighwayTertiaryLink);
}), baseSpeeds.end());
for (int ind = 0; ind < kSpeedsCount; ++ind)
{
// Calculate average speed.
for (auto & e : m_avgSpeeds[ind])
{
// Check some reasonable conditions when assigning average speed.
if (e.second.m_lengthKM > kMinDefSpeedRoadsLengthKm)
{
auto const speed = e.second.m_lengthKM / e.second.m_timeH;
if (speed < kMaxPossibleDefSpeedKmH)
e.second.m_speed = speed;
}
}
// Prepare ethalon vector.
bool const inCity = ind != kOutsideCityIdx;
std::sort(baseSpeeds.begin(), baseSpeeds.end(), [inCity](auto const & l, auto const & r)
{
// Sort from biggest to smallest.
return r.second.GetSpeed(inCity).m_weight < l.second.GetSpeed(inCity).m_weight;
});
// First of all check that calculated speed and base speed difference is less than 2x.
for (auto const & e : baseSpeeds)
{
auto & l = m_avgSpeeds[ind][e.first];
if (l.m_speed > 0)
{
double const base = e.second.GetSpeed(inCity).m_weight;
double const factor = l.m_speed / base;
if (factor > 2 || factor < 0.5)
{
LOG(LWARNING, (m_logTag, "More than 2x diff:", e.first, l.m_speed, base));
l.m_speed = -1;
}
}
}
// Check speed's pairs consistency.
// Constraints from the previous iteration can be broken if we modify l-speed on the next iteration.
for (size_t il = 0, ir = 1; ir < baseSpeeds.size(); ++ir)
{
auto & l = m_avgSpeeds[ind][baseSpeeds[il].first];
if (l.m_speed < 0)
{
++il;
continue;
}
auto & r = m_avgSpeeds[ind][baseSpeeds[ir].first];
if (r.m_speed < 0)
continue;
// |l| should be greater than |r|
if (l.m_speed < r.m_speed)
{
LOG(LWARNING, (m_logTag, "Bad def speeds pair:", baseSpeeds[il].first, baseSpeeds[ir].first, l, r));
if (l.m_lengthKM >= r.m_lengthKM)
r.m_speed = l.m_speed;
else
l.m_speed = r.m_speed;
}
il = ir;
}
auto const getSpeed = [this, ind, inCity](HighwayType type)
{
auto const s = m_avgSpeeds[ind][type].m_speed;
if (s > 0)
return s;
auto const * p = kHighwayBasedSpeeds.Find(type);
CHECK(p, ());
return p->GetSpeed(inCity).m_weight;
};
// These speeds: Primary, Secondary, Tertiary, Residential have the biggest routing quality impact.
{
double const primaryS = getSpeed(HighwayType::HighwayPrimary);
double const secondaryS = getSpeed(HighwayType::HighwaySecondary);
double const tertiaryS = getSpeed(HighwayType::HighwayTertiary);
double const residentialS = getSpeed(HighwayType::HighwayResidential);
double constexpr eps = 1.0;
if (primaryS + eps < secondaryS || secondaryS + eps < tertiaryS || tertiaryS + eps < residentialS)
{
LOG(LWARNING, (m_logTag, "Ignore primary, secondary, tertiary, residential speeds:",
primaryS, secondaryS, tertiaryS, residentialS));
m_avgSpeeds[ind][HighwayType::HighwayPrimary].m_speed = -1;
m_avgSpeeds[ind][HighwayType::HighwaySecondary].m_speed = -1;
m_avgSpeeds[ind][HighwayType::HighwayTertiary].m_speed = -1;
m_avgSpeeds[ind][HighwayType::HighwayResidential].m_speed = -1;
}
}
// Update links.
std::pair<HighwayType, HighwayType> arrLinks[] = {
{HighwayType::HighwayMotorway, HighwayType::HighwayMotorwayLink},
{HighwayType::HighwayTrunk, HighwayType::HighwayTrunkLink},
{HighwayType::HighwayPrimary, HighwayType::HighwayPrimaryLink},
{HighwayType::HighwaySecondary, HighwayType::HighwaySecondaryLink},
{HighwayType::HighwayTertiary, HighwayType::HighwayTertiaryLink},
};
for (auto const & e : arrLinks)
{
auto const main = m_avgSpeeds[ind][e.first].m_speed;
auto & link = m_avgSpeeds[ind][e.second].m_speed;
if (main > 0)
link = kLinkToMainSpeedFactor * main;
else
link = -1;
}
// Fill type-speed map.
LOG(LINFO, ("Average speeds", ind == kOutsideCityIdx ? "outside" : "inside", "a city:"));
for (auto const & e : m_avgSpeeds[ind])
{
long const speed = std::lround(e.second.m_lengthKM / e.second.m_timeH);
if (speed < routing::kInvalidSpeed)
if (e.second.m_speed > 0)
{
// Store type speeds in Metric system, like VehicleModel profiles.
auto const speedInUnits = m_converter.ClosestValidMacro(
{ static_cast<MaxspeedType>(speed), measurement_utils::Units::Metric });
{ static_cast<MaxspeedType>(e.second.m_speed), measurement_utils::Units::Metric });
LOG(LINFO, ("*", e.first, "=", speedInUnits));
typeSpeeds[ind][e.first] = m_converter.SpeedToMacro(speedInUnits);
}
else
LOG(LWARNING, ("Large average speed for", e.first, "=", speed));
}
}
}
void SerializeMaxspeeds()
{
if (m_maxspeeds.empty())
return;
MaxspeedsSerializer::HW2SpeedMap typeSpeeds[kSpeedsCount];
/// @todo There are too many claims/bugs with Turkey calculated defaults.
/// And yes, now this dummy country check :)
if (m_dataPath.find("Turkey_") == std::string::npos)
CalculateDefaultTypeSpeeds(typeSpeeds);
// Serialize speeds.
FilesContainerW cont(m_dataPath, FileWriter::OP_WRITE_EXISTING);
auto writer = cont.GetWriter(MAXSPEEDS_FILE_TAG);
MaxspeedsSerializer::Serialize(m_maxspeeds, typeSpeeds, *writer);

View File

@@ -4,14 +4,10 @@
#include "routing_common/maxspeed_conversion.hpp"
#include "platform/measurement_utils.hpp"
#include "base/geo_object_id.hpp"
#include <cstdint>
#include <map>
#include <string>
#include <vector>
namespace routing
{

View File

@@ -209,7 +209,11 @@ void RelationTagsWay::Process(RelationElement const & e)
continue;
// Do not pass "ref" tags from boundaries and other, non-route relations to highways.
if (p.first == "ref" && isHighway)
if (isHighway && p.first == "ref")
continue;
// https://github.com/organicmaps/organicmaps/issues/8246
if (type == "route" && (p.first == "oneway" || p.first == "surface"))
continue;
Base::AddCustomTag(p);

View File

@@ -2,72 +2,116 @@
#include "routing/routing_helpers.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_altitude.hpp"
#include "indexer/feature_data.hpp"
#include "indexer/feature_processor.hpp"
#include "geometry/distance_on_sphere.hpp"
#include "geometry/mercator.hpp"
#include "geometry/point_with_altitude.hpp"
#include "platform/country_file.hpp"
#include "platform/local_country_file.hpp"
#include "platform/local_country_file_utils.hpp"
#include "platform/platform.hpp"
#include "base/logging.hpp"
#include <cstddef>
#include <cstdint>
#include <limits>
#include <iostream>
#include <mutex>
#include <vector>
#include <gflags/gflags.h>
DEFINE_string(srtm_path, "", "Path to directory with SRTM files");
DEFINE_string(mwm_path, "", "Path to mwm files (writable dir)");
DEFINE_bool(check_dist, false, "Check feature sections distance");
int main(int argc, char * argv[])
class SafeTileManager
{
gflags::SetUsageMessage("SRTM coverage checker.");
gflags::ParseCommandLineFlags(&argc, &argv, true);
generator::SrtmTileManager m_manager;
std::mutex m_mutex;
Platform & platform = GetPlatform();
if (!FLAGS_mwm_path.empty())
platform.SetWritableDirForTests(FLAGS_mwm_path);
uint32_t m_ferry;
if (FLAGS_srtm_path.empty())
public:
explicit SafeTileManager(std::string const & dir) : m_manager(dir)
{
LOG(LERROR, ("SRTM files directory is not specified."));
return -1;
m_ferry = classif().GetTypeByPath({"route", "ferry"});
CHECK(m_ferry != Classificator::INVALID_TYPE, ());
}
LOG(LINFO, ("writable dir =", platform.WritableDir()));
LOG(LINFO, ("srtm dir =", FLAGS_srtm_path));
bool IsAltitudeRoad(FeatureType & ft) const
{
feature::TypesHolder types(ft);
return (routing::IsRoad(types) && !types.Has(m_ferry));
}
geometry::Altitude GetAltitude(ms::LatLon const & coord)
{
std::lock_guard guard(m_mutex);
return m_manager.GetAltitude(coord);
}
void Purge()
{
std::lock_guard guard(m_mutex);
m_manager.Purge();
}
};
template <class FnT> void ForEachMWM(SafeTileManager & manager, FnT && fn)
{
std::vector<platform::LocalCountryFile> localFiles;
FindAllLocalMapsAndCleanup(std::numeric_limits<int64_t>::max() /* latestVersion */, localFiles);
generator::SrtmTileManager manager(FLAGS_srtm_path);
classificator::Load();
// Better use ComputationalThreadPool, but we want to call SafeTileManager::Purge after each batch.
size_t constexpr kThreadsCount = 24;
std::vector<std::thread> pool;
size_t workers = 0;
for (auto & file : localFiles)
{
// Skip worlds.
if (file.GetDirectory().empty() || file.GetCountryName().starts_with("World"))
continue;
file.SyncWithDisk();
if (!file.OnDisk(MapFileType::Map))
{
LOG(LINFO, ("Warning! Routing file not found for:", file.GetCountryName()));
LOG_SHORT(LWARNING, ("Map file not found for:", file.GetCountryName()));
continue;
}
auto const path = file.GetPath(MapFileType::Map);
LOG(LINFO, ("Mwm", path, "is being processed."));
LOG_SHORT(LINFO, ("Processing", file.GetCountryName()));
pool.emplace_back([&fn, &file]() { fn(file); });
if (++workers == kThreadsCount)
{
for (auto & t : pool)
t.join();
pool.clear();
manager.Purge();
workers = 0;
}
}
for (auto & t : pool)
t.join();
}
void CheckCoverage(SafeTileManager & manager)
{
ForEachMWM(manager, [&](platform::LocalCountryFile const & file)
{
size_t all = 0;
size_t good = 0;
feature::ForEachFeature(path, [&](FeatureType & ft, uint32_t fid) {
if (!routing::IsRoad(feature::TypesHolder(ft)))
feature::ForEachFeature(file.GetPath(MapFileType::Map), [&](FeatureType & ft, uint32_t)
{
if (!manager.IsAltitudeRoad(ft))
return;
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
@@ -75,16 +119,136 @@ int main(int argc, char * argv[])
for (size_t i = 0; i < ft.GetPointsCount(); ++i)
{
auto const height = manager.GetHeight(mercator::ToLatLon(ft.GetPoint(i)));
auto const height = manager.GetAltitude(mercator::ToLatLon(ft.GetPoint(i)));
if (height != geometry::kInvalidAltitude)
good++;
}
});
auto const bad = all - good;
auto const percent = all == 0 ? 0.0 : bad * 100.0 / all;
LOG(LINFO, (percent > 10.0 ? "Huge" : "Low", "error rate in:", file.GetCountryName(),
"good:", good, "bad:", bad, "all:", all, "%:", percent));
auto const percent = (all == 0) ? 0.0 : bad * 100.0 / all;
LOG_SHORT(LINFO, (percent > 10.0 ? "Huge" : "Low", "error rate in:", file.GetCountryName(),
"good:", good, "bad:", bad, "all:", all, "%:", percent));
});
}
void CheckDistance(SafeTileManager & manager)
{
ForEachMWM(manager, [&](platform::LocalCountryFile const & file)
{
size_t all = 0;
size_t added = 0;
size_t invalid = 0;
feature::ForEachFeature(file.GetPath(MapFileType::Map), [&](FeatureType & ft, uint32_t)
{
if (!manager.IsAltitudeRoad(ft))
return;
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
all += ft.GetPointsCount();
for (size_t i = 1; i < ft.GetPointsCount(); ++i)
{
auto const ll1 = mercator::ToLatLon(ft.GetPoint(i-1));
auto const alt1 = manager.GetAltitude(ll1);
auto const ll2 = mercator::ToLatLon(ft.GetPoint(i));
auto const alt2 = manager.GetAltitude(ll2);
if (alt1 == geometry::kInvalidAltitude || alt2 == geometry::kInvalidAltitude)
{
++invalid;
continue;
}
// Divide by 1 second sections.
size_t const sections = std::round(ms::DistanceOnSphere(ll1.m_lat, ll1.m_lon, ll2.m_lat, ll2.m_lon) * 3600);
if (sections < 2)
continue;
for (size_t j = 1; j < sections; ++j)
{
double const a = j / double(sections);
ms::LatLon const ll(ll2.m_lat * a + ll1.m_lat * (1 - a), ll2.m_lon * a + ll1.m_lon * (1 - a));
// Get diff between approx altitude and real one.
auto const alt = manager.GetAltitude(ll);
if (alt == geometry::kInvalidAltitude)
{
LOG_SHORT(LWARNING, ("Invalid altitude for the middle point:", ll));
++added;
}
else
{
auto const approxAlt = static_cast<geometry::Altitude>(std::round(alt2 * a + alt1 * (1 - a)));
if (abs(alt - approxAlt) >= std::max(1, abs(alt)/10)) // 10%
++added;
}
}
}
});
auto const percent = added * 100.0 / all;
std::string prefix = "Low";
if (percent >= 1)
prefix = "Huge";
else if (added >= 1000)
prefix = "Medium";
LOG_SHORT(LINFO, (prefix, file.GetCountryName(), "all:", all, "invalid:", invalid, "added:", added, "%:", percent));
});
}
int main(int argc, char * argv[])
{
gflags::SetUsageMessage("SRTM coverage checker.");
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_srtm_path.empty())
{
LOG_SHORT(LERROR, ("SRTM files directory is not specified."));
return -1;
}
classificator::Load();
if (!FLAGS_mwm_path.empty())
{
SafeTileManager manager(FLAGS_srtm_path);
Platform & platform = GetPlatform();
platform.SetWritableDirForTests(FLAGS_mwm_path);
if (FLAGS_check_dist)
CheckDistance(manager);
else
CheckCoverage(manager);
}
else
{
generator::SrtmTileManager manager(FLAGS_srtm_path);
using namespace std;
cout << "Enter lat lon. Or Ctrl + C to exit." << endl;
while (true)
{
double lat, lon;
cin >> lat >> lon;
if (!cin)
{
cout << "Invalid lat lon." << endl;
cin.clear();
cin.ignore(10000, '\n');
}
else
{
auto const & tile = manager.GetTile({lat, lon});
cout << "H = " << tile.GetHeight({lat, lon}) <<
"; Trg = " << tile.GetTriangleHeight({lat, lon}) <<
"; Bilinear = " << tile.GetBilinearHeight({lat, lon});
cout << endl;
}
}
}
return 0;

View File

@@ -16,15 +16,21 @@ namespace generator
{
namespace
{
size_t constexpr kArcSecondsInDegree = 60 * 60;
int constexpr kArcSecondsInDegree = 60 * 60;
size_t constexpr kSrtmTileSize = (kArcSecondsInDegree + 1) * (kArcSecondsInDegree + 1) * 2;
struct UnzipMemDelegate : public ZipFileReader::Delegate
{
explicit UnzipMemDelegate(std::string & buffer) : m_buffer(buffer), m_completed(false) {}
explicit UnzipMemDelegate(std::vector<uint8_t> & buffer) : m_buffer(buffer), m_completed(false)
{
m_buffer.reserve(kSrtmTileSize);
}
// ZipFileReader::Delegate overrides:
void OnBlockUnzipped(size_t size, char const * data) override { m_buffer.append(data, size); }
void OnBlockUnzipped(size_t size, char const * data) override
{
m_buffer.insert(m_buffer.end(), data, data + size);
}
void OnStarted() override
{
@@ -34,7 +40,7 @@ struct UnzipMemDelegate : public ZipFileReader::Delegate
void OnCompleted() override { m_completed = true; }
std::string & m_buffer;
std::vector<uint8_t> & m_buffer;
bool m_completed;
};
@@ -45,11 +51,6 @@ std::string GetSrtmContFileName(std::string const & dir, std::string const & bas
} // namespace
// SrtmTile ----------------------------------------------------------------------------------------
SrtmTile::SrtmTile()
{
Invalidate();
}
SrtmTile::SrtmTile(SrtmTile && rhs) : m_data(std::move(rhs.m_data)), m_valid(rhs.m_valid)
{
rhs.Invalidate();
@@ -90,7 +91,7 @@ void SrtmTile::Init(std::string const & dir, ms::LatLon const & coord)
}
else
{
GetPlatform().GetReader(file)->ReadAsString(m_data);
m_data = base::ReadFile(base::JoinPath(dir, file));
}
if (m_data.size() != kSrtmTileSize)
@@ -103,11 +104,9 @@ void SrtmTile::Init(std::string const & dir, ms::LatLon const & coord)
m_valid = true;
}
geometry::Altitude SrtmTile::GetHeight(ms::LatLon const & coord) const
// static
ms::LatLon SrtmTile::GetCoordInSeconds(ms::LatLon const & coord)
{
if (!IsValid())
return geometry::kInvalidAltitude;
double ln = coord.m_lon - static_cast<int>(coord.m_lon);
if (ln < 0)
ln += 1;
@@ -116,15 +115,98 @@ geometry::Altitude SrtmTile::GetHeight(ms::LatLon const & coord) const
lt += 1;
lt = 1 - lt; // from North to South
auto const row = static_cast<size_t>(std::round(kArcSecondsInDegree * lt));
auto const col = static_cast<size_t>(std::round(kArcSecondsInDegree * ln));
return { kArcSecondsInDegree * lt, kArcSecondsInDegree * ln };
}
geometry::Altitude SrtmTile::GetHeight(ms::LatLon const & coord) const
{
if (!IsValid())
return geometry::kInvalidAltitude;
auto const ll = GetCoordInSeconds(coord);
return GetHeightRC(static_cast<size_t>(std::round(ll.m_lat)), static_cast<size_t>(std::round(ll.m_lon)));
}
geometry::Altitude SrtmTile::GetHeightRC(size_t row, size_t col) const
{
size_t const ix = row * (kArcSecondsInDegree + 1) + col;
CHECK_LESS(ix, Size(), (coord));
CHECK_LESS(ix, Size(), (row, col));
return ReverseByteOrder(Data()[ix]);
}
double SrtmTile::GetTriangleHeight(ms::LatLon const & coord) const
{
if (!IsValid())
return geometry::kInvalidAltitude;
auto const ll = GetCoordInSeconds(coord);
m2::Point<int> const p1(static_cast<int>(std::round(ll.m_lon)), static_cast<int>(std::round(ll.m_lat)));
auto p2 = p1;
if (p2.x > ll.m_lon)
{
if (p2.x > 0)
--p2.x;
}
else if (p2.x < ll.m_lon)
{
if (p2.x < kArcSecondsInDegree)
++p2.x;
}
auto p3 = p1;
if (p3.y > ll.m_lat)
{
if (p3.y > 0)
--p3.y;
}
else if (p3.y < ll.m_lat)
{
if (p3.y < kArcSecondsInDegree)
++p3.y;
}
// Approximate height from triangle p1, p2, p3.
// p1.y == p2.y; p1.x == p3.x
// https://stackoverflow.com/questions/36090269/finding-height-of-point-on-height-map-triangles
int const det = (p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y);
if (det == 0)
return GetHeightRC(p1.y, p1.x);
double const a1 = ((p2.y - p3.y) * (ll.m_lon - p3.x) + (p3.x - p2.x) * (ll.m_lat - p3.y)) / det;
double const a2 = ((p3.y - p1.y) * (ll.m_lon - p3.x) + (p1.x - p3.x) * (ll.m_lat - p3.y)) / det;
double const a3 = 1 - a1 - a2;
return a1 * GetHeightRC(p1.y, p1.x) + a2 * GetHeightRC(p2.y, p2.x) + a3 * GetHeightRC(p3.y, p3.x);
}
double SrtmTile::GetBilinearHeight(ms::LatLon const & coord) const
{
if (!IsValid())
return geometry::kInvalidAltitude;
auto const ll = GetCoordInSeconds(coord);
m2::Point<int> const p1(static_cast<int>(ll.m_lon), static_cast<int>(ll.m_lat));
auto p2 = p1;
if (p2.x < kArcSecondsInDegree)
++p2.x;
if (p2.y < kArcSecondsInDegree)
++p2.y;
// https://en.wikipedia.org/wiki/Bilinear_interpolation
double const denom = (p2.x - p1.x) * (p2.y - p1.y);
if (denom == 0)
return GetHeightRC(p1.y, p1.x);
return (GetHeightRC(p1.y, p1.x) * (p2.x - ll.m_lon) * (p2.y - ll.m_lat) +
GetHeightRC(p1.y, p2.x) * (ll.m_lon - p1.x) * (p2.y - ll.m_lat) +
GetHeightRC(p2.y, p1.x) * (p2.x - ll.m_lon) * (ll.m_lat - p1.y) +
GetHeightRC(p2.y, p2.x) * (ll.m_lon - p1.x) * (ll.m_lat - p1.y)) / denom;
}
// static
std::string SrtmTile::GetPath(std::string const & dir, std::string const & base)
{
@@ -132,42 +214,52 @@ std::string SrtmTile::GetPath(std::string const & dir, std::string const & base)
}
// static
ms::LatLon SrtmTile::GetCenter(ms::LatLon const & coord)
SrtmTile::LatLonKey SrtmTile::GetKey(ms::LatLon const & coord)
{
return {floor(coord.m_lat) + 0.5, floor(coord.m_lon) + 0.5};
ms::LatLon center{floor(coord.m_lat) + 0.5, floor(coord.m_lon) + 0.5};
if (coord.m_lat < 0)
center.m_lat -= 1.0;
if (coord.m_lon < 0)
center.m_lon -= 1.0;
return {static_cast<int32_t>(center.m_lat), static_cast<int32_t>(center.m_lon)};
}
// static
std::string SrtmTile::GetBase(ms::LatLon const & coord)
{
auto center = GetCenter(coord);
auto key = GetKey(coord);
std::ostringstream ss;
if (center.m_lat < 0)
if (coord.m_lat < 0)
{
ss << "S";
center.m_lat *= -1;
center.m_lat += 1;
key.first = -key.first;
}
else
{
ss << "N";
}
ss << std::setw(2) << std::setfill('0') << static_cast<int>(center.m_lat);
if (center.m_lon < 0)
ss << std::setw(2) << std::setfill('0') << key.first;
if (coord.m_lon < 0)
{
ss << "W";
center.m_lon *= -1;
center.m_lon += 1;
key.second = -key.second;
}
else
{
ss << "E";
}
ss << std::setw(3) << static_cast<int>(center.m_lon);
ss << std::setw(3) << key.second;
return ss.str();
}
geometry::Altitude * SrtmTile::DataForTests(size_t & sz)
{
m_valid = true;
sz = kArcSecondsInDegree + 1;
m_data.resize(kSrtmTileSize, 0);
return reinterpret_cast<geometry::Altitude *>(m_data.data());
}
void SrtmTile::Invalidate()
{
m_data.clear();
@@ -176,47 +268,27 @@ void SrtmTile::Invalidate()
}
// SrtmTileManager ---------------------------------------------------------------------------------
SrtmTileManager::SrtmTileManager(std::string const & dir) : m_dir(dir) {}
geometry::Altitude SrtmTileManager::GetHeight(ms::LatLon const & coord)
SrtmTile const & SrtmTileManager::GetTile(ms::LatLon const & coord)
{
auto const key = GetKey(coord);
auto it = m_tiles.find(key);
if (it == m_tiles.end())
auto res = m_tiles.emplace(SrtmTile::GetKey(coord), SrtmTile());
if (res.second)
{
SrtmTile tile;
try
{
tile.Init(m_dir, coord);
res.first->second.Init(m_dir, coord);
}
catch (RootException const & e)
{
std::string const base = SrtmTile::GetBase(coord);
LOG(LINFO, ("Can't init SRTM tile:", base, "reason:", e.Msg()));
}
// It's OK to store even invalid tiles and return invalid height
// for them later.
it = m_tiles.emplace(key, std::move(tile)).first;
}
return it->second.GetHeight(coord);
return res.first->second;
}
// static
SrtmTileManager::LatLonKey SrtmTileManager::GetKey(ms::LatLon const & coord)
void SrtmTileManager::Purge()
{
auto const tileCenter = SrtmTile::GetCenter(coord);
return {static_cast<int32_t>(tileCenter.m_lat), static_cast<int32_t>(tileCenter.m_lon)};
MapT().swap(m_tiles);
}
SrtmTile const & SrtmTileManager::GetTile(ms::LatLon const & coord)
{
// Touch the tile to force its loading.
GetHeight(coord);
auto const key = GetKey(coord);
auto const it = m_tiles.find(key);
CHECK(it != m_tiles.end(), (coord));
return it->second;
}
} // namespace generator

View File

@@ -2,44 +2,67 @@
#include "geometry/latlon.hpp"
#include "indexer/feature_altitude.hpp"
#include "geometry/point_with_altitude.hpp"
#include "base/macros.hpp"
#include <boost/container_hash/hash.hpp>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace generator
{
class SrtmTile
{
public:
SrtmTile();
SrtmTile() : m_valid(false) {}
SrtmTile(SrtmTile && rhs);
void Init(std::string const & dir, ms::LatLon const & coord);
inline bool IsValid() const { return m_valid; }
// Returns height in meters at |coord| or kInvalidAltitude.
/// @return Height in meters at |coord| or kInvalidAltitude.
/// @{
/// Nearest serialized height.
geometry::Altitude GetHeight(ms::LatLon const & coord) const;
/// Triangle interpolation.
double GetTriangleHeight(ms::LatLon const & coord) const;
/// Bilinear interpolation.
double GetBilinearHeight(ms::LatLon const & coord) const;
geometry::Altitude GetAltitude(ms::LatLon const & coord) const
{
return static_cast<geometry::Altitude>(std::round(GetBilinearHeight(coord)));
}
/// @}
using LatLonKey = std::pair<int32_t, int32_t>;
static LatLonKey GetKey(ms::LatLon const & coord);
static std::string GetBase(ms::LatLon const & coord);
static ms::LatLon GetCenter(ms::LatLon const & coord);
static std::string GetPath(std::string const & dir, std::string const & base);
/// Used in unit tests only to prepare mock tile.
geometry::Altitude * DataForTests(size_t & sz);
private:
static ms::LatLon GetCoordInSeconds(ms::LatLon const & coord);
geometry::Altitude GetHeightRC(size_t row, size_t col) const;
inline geometry::Altitude const * Data() const
{
return reinterpret_cast<geometry::Altitude const *>(m_data.data());
};
}
inline size_t Size() const { return m_data.size() / sizeof(geometry::Altitude); }
void Invalidate();
std::string m_data;
std::vector<uint8_t> m_data;
bool m_valid;
DISALLOW_COPY(SrtmTile);
@@ -48,27 +71,35 @@ private:
class SrtmTileManager
{
public:
explicit SrtmTileManager(std::string const & dir);
geometry::Altitude GetHeight(ms::LatLon const & coord);
explicit SrtmTileManager(std::string const & dir) : m_dir(dir) {}
SrtmTile const & GetTile(ms::LatLon const & coord);
private:
using LatLonKey = std::pair<int32_t, int32_t>;
static LatLonKey GetKey(ms::LatLon const & coord);
geometry::Altitude GetAltitude(ms::LatLon const & coord)
{
return GetTile(coord).GetAltitude(coord);
}
size_t GeTilesNumber() const { return m_tiles.size(); }
void Purge();
private:
std::string m_dir;
struct Hash
{
size_t operator()(LatLonKey const & key) const
size_t operator()(SrtmTile::LatLonKey const & key) const
{
return (static_cast<size_t>(key.first) << 32u) | static_cast<size_t>(key.second);
size_t seed = 0;
boost::hash_combine(seed, key.first);
boost::hash_combine(seed, key.second);
return seed;
}
};
std::unordered_map<LatLonKey, SrtmTile, Hash> m_tiles;
using MapT = std::unordered_map<SrtmTile::LatLonKey, SrtmTile, Hash>;
MapT m_tiles;
DISALLOW_COPY(SrtmTileManager);
};

View File

@@ -24,6 +24,7 @@
#include <vector>
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>
namespace generator

View File

@@ -55,10 +55,10 @@ void WikiUrlDumper::Dump(size_t cpuCount) const
// static
void WikiUrlDumper::DumpOne(std::string const & path, std::ostream & stream)
{
auto const & needWikiUrl = ftypes::AttractionsChecker::Instance();
//auto const & needWikiUrl = ftypes::AttractionsChecker::Instance();
feature::ForEachFeatureRawFormat(path, [&](FeatureBuilder const & feature, uint64_t /* pos */) {
if (!needWikiUrl(feature.GetTypesHolder()))
return;
// if (!needWikiUrl(feature.GetTypesHolder()))
// return;
auto const wikiUrl = feature.GetMetadata().GetWikiURL();
if (wikiUrl.empty())
@@ -89,10 +89,10 @@ WikiDataFilter::WikiDataFilter(std::string const & path, std::vector<std::string
void WikiDataFilter::FilterOne(std::string const & path, std::map<base::GeoObjectId, std::string> const & idToWikiData,
std::ostream & stream)
{
auto const & needWikiUrl = ftypes::AttractionsChecker::Instance();
//auto const & needWikiUrl = ftypes::AttractionsChecker::Instance();
feature::ForEachFeatureRawFormat(path, [&](FeatureBuilder const & feature, uint64_t /* pos */) {
if (!needWikiUrl(feature.GetTypesHolder()))
return;
// if (!needWikiUrl(feature.GetTypesHolder()))
// return;
auto const it = idToWikiData.find(feature.GetMostGenericOsmId());
if (it == std::end(idToWikiData))

View File

@@ -62,8 +62,12 @@ UNIT_TEST(Segment_Smoke)
TEST(!OnSegment(P(10 + eps, 10), ps), ());
TEST(!OnSegment(P(0, 0), ps), ());
}
}
// Paranoid tests.
// This paranoid test doesn' work with Release optimizations (LTO?).
#ifndef NDEBUG
UNIT_TEST(Segment_Paranoid)
{
{
P ps[] = {{0, 0}, {1e100, 1e100}};
TEST(OnSegment(ps[0], ps), ());
@@ -94,6 +98,7 @@ UNIT_TEST(Segment_Smoke)
TEST(!OnSegment(P(1e-16, 2.0 * 1e-16), ps), ());
}
}
#endif
UNIT_TEST(Triangle_Smoke)
{
@@ -129,6 +134,8 @@ UNIT_TEST(Triangle_PointInsideSegment)
TEST(!InsideTriangle(P(eps, eps), ps), ());
}
// This paranoid test doesn' work with Release optimizations (LTO?).
#ifndef NDEBUG
UNIT_TEST(Triangle_PointInsidePoint)
{
double constexpr eps = 1.0E-10;
@@ -147,6 +154,7 @@ UNIT_TEST(Triangle_PointInsidePoint)
TEST(!InsideTriangle(P(eps, eps), ps), ());
#endif
}
#endif
UNIT_TEST(PolygonSelfIntersections_IntersectSmoke)
{

View File

@@ -12,15 +12,38 @@ using namespace std;
using m2::Spline;
using m2::PointD;
namespace
{
double constexpr kAlmostZero = 1.0E-16;
void TestEqual(double x, double y)
{
if (fabs(x) < kAlmostZero || fabs(y) < kAlmostZero)
TEST_ALMOST_EQUAL_ABS(x, y, kAlmostZero, ());
else
TEST_ALMOST_EQUAL_ULPS(x, y, ());
}
void TestPointDDir(PointD const & dst, PointD const & src)
{
double const len1 = dst.Length();
double const len2 = src.Length();
TEST_ALMOST_EQUAL_ULPS(dst.x/len1, src.x/len2, ());
TEST_ALMOST_EQUAL_ULPS(dst.y/len1, src.y/len2, ());
if (len1 < kAlmostZero || len2 < kAlmostZero)
{
TestEqual(dst.x, src.x);
TestEqual(dst.y, src.y);
}
else
{
TestEqual(dst.x/len1, src.x/len2);
TestEqual(dst.y/len1, src.y/len2);
}
}
UNIT_TEST(SmoothedDirections)
} // namespace
UNIT_TEST(Spline_SmoothedDirections)
{
vector<PointD> path;
path.push_back(PointD(0, 0));

View File

@@ -157,6 +157,7 @@ public:
}
Container const & Data() const { return m_points; }
Container & MutableData() { return m_points; }
template <typename EqualFn>
static bool IsIntersect(Coord const & x11, Coord const & y11, Coord const & x12,

View File

@@ -77,7 +77,7 @@ class Altitudes
public:
Altitudes() = default;
explicit Altitudes(geometry::Altitudes const & altitudes) : m_altitudes(altitudes) {}
explicit Altitudes(geometry::Altitudes && altitudes) : m_altitudes(std::move(altitudes)) {}
template <class TSink>
void Serialize(geometry::Altitude minAltitude, TSink & sink) const

View File

@@ -7,20 +7,25 @@
#include <memory>
#include <string>
#include <utility>
namespace feature
{
template <class ToDo>
void ForEachFeature(ModelReaderPtr const & reader, ToDo && toDo)
void ForEachFeature(FilesContainerR const & cont, ToDo && toDo)
{
FeaturesVectorTest features((FilesContainerR(reader)));
features.GetVector().ForEach(std::forward<ToDo>(toDo));
FeaturesVectorTest features(cont);
features.GetVector().ForEach(toDo);
}
template <class ToDo>
void ForEachFeature(ModelReaderPtr reader, ToDo && toDo)
{
ForEachFeature(FilesContainerR(reader), toDo);
}
template <class ToDo>
void ForEachFeature(std::string const & fPath, ToDo && toDo)
{
ForEachFeature(std::make_unique<FileReader>(fPath), std::forward<ToDo>(toDo));
ForEachFeature(std::make_unique<FileReader>(fPath), toDo);
}
} // namespace feature

View File

@@ -1488,6 +1488,6 @@
"type.barrier.guard_rail" = "Leitplanke";
"type.highway.ladder" = "Leiter";
"type.landuse.plant_nursery" = "Gartenbau";
"type.leisure.firepit" = "Feuerschale";
"type.leisure.firepit" = "Feuerstelle";
"type.amenity.studio" = "Studio";
"type.sport.diving" = "Tauchen";

View File

@@ -1484,3 +1484,10 @@
/* https://wiki.openstreetmap.org/wiki/Tag:leisure=sports_hall */
"type.leisure.sports_hall" = "Pabellón deportivo";
"type.amenity.studio" = "Estudio";
"type.leisure.firepit" = "Fogón";
"type.amenity.love_hotel" = "Hotel del amor";
"type.barrier.guard_rail" = "Guardarraíl";
"type.highway.ladder" = "Escalera";
"type.landuse.plant_nursery" = "Vivero de plantas";
"type.sport.diving" = "Buceo";

View File

@@ -27,7 +27,7 @@
"type.amenity.bicycle_parking" = "Polkupyöräpysäköinti";
"type.amenity.bicycle_rental" = "Polkupyöränvuokraus";
"type.amenity.bicycle_repair_station" = "Polkupyörän korjausasema";
"type.amenity.biergarten" = "Biergarten";
"type.amenity.biergarten" = "Olutpuutarha";
"type.amenity.brothel" = "Bordelli";
"type.amenity.bureau_de_change" = "Rahanvaihto";
"type.amenity.bus_station" = "Linja-autoasema";
@@ -179,7 +179,7 @@
"type.amenity.vending_machine.parking_tickets" = "Pysäköintimaksuautomaatti";
"type.amenity.vending_machine.public_transport_tickets" = "Julkisen liikenteen lippuautomaatti";
"type.amenity.vending_machine.sweets" = "Makeisautomaatti";
"type.amenity.vending_machine.excrement_bags" = "Excrement Bags Dispenser";
"type.amenity.vending_machine.excrement_bags" = "Koirankakkapussiautomaatti";
"type.amenity.parcel_locker" = "Pakettilokero";
"type.amenity.vehicle_inspection" = "Ajoneuvon tarkastus";
"type.amenity.vending_machine.fuel" = "Bensa-automaatti";
@@ -1486,3 +1486,8 @@
"type.leisure.sports_hall" = "Urheiluhalli";
"type.amenity.love_hotel" = "Rakkaushotelli";
"type.sport.diving" = "Sukellus";
"type.amenity.studio" = "Studio";
"type.barrier.guard_rail" = "Tiekaide";
"type.highway.ladder" = "Tikapuut";
"type.landuse.plant_nursery" = "Kasvitarha";
"type.leisure.firepit" = "Tulentekopaikka";

View File

@@ -143,7 +143,7 @@
"type.recycling.cans" = "缶";
"type.recycling.shoes" = "靴";
"type.recycling.green_waste" = "有機性廃棄物";
"type.recycling.cartons" = "Cartons";
"type.recycling.cartons" = "紙箱";
"type.amenity.restaurant" = "レストラン";
"type.amenity.sanitary_dump_station" = "ダンプステーション";
"type.amenity.school" = "学校";
@@ -836,8 +836,8 @@
"type.office.lawyer" = "弁護士事務所";
"type.office.ngo" = "NGO 事務局";
"type.office.telecommunication" = "携帯電話事業者";
"type.organic.only" = "Organic";
"type.organic.yes" = "Organic";
"type.organic.only" = "有機";
"type.organic.yes" = "有機";
"type.place.city" = "市";
"type.place.city.capital" = "首都";
"type.place.city.capital.10" = "市";
@@ -898,7 +898,7 @@
"type.power.tower" = "電柱";
/* A single pole supporting minor power lines. */
"type.power.pole" = "Power Pole";
"type.power.pole" = "電柱";
/* A single pole supporting various public utilities, such as lighting or telephony. */
"type.man_made.utility_pole" = "Utility Pole";

View File

@@ -647,7 +647,6 @@
"type.hwtag" = "hwtag";
"type.hwtag.bidir_bicycle" = "hwtag-bidir_bicycle";
"type.hwtag.onedir_bicycle" = "hwtag-onedir_bicycle";
"type.hwtag.lit" = "hwtag-lit";
"type.hwtag.nobicycle" = "hwtag-nobicycle";
"type.hwtag.nocar" = "hwtag-nocar";
"type.hwtag.nofoot" = "hwtag-nofoot";
@@ -742,7 +741,7 @@
"type.man_made.cairn" = "Höyük";
"type.man_made.chimney" = "Fabrika Bacası";
"type.man_made.cutline" = "Kesme Çizgisi";
"type.man_made.survey_point" = "Survey Point";
"type.man_made.survey_point" = "Anket Noktası";
"type.man_made.flagpole" = "Bayrak Direği";
"type.man_made.lighthouse" = "Deniz Feneri";
"type.man_made.mast" = "Direk";
@@ -1484,3 +1483,5 @@
/* https://wiki.openstreetmap.org/wiki/Tag:leisure=sports_hall */
"type.leisure.sports_hall" = "Spor salonu";
"type.amenity.studio" = "Stüdyo";
"type.sport.diving" = "Dalış Sporu";

Some files were not shown because too many files have changed in this diff Show More