From 5f60b3db6aae872226c088ae2522e815a652abd8 Mon Sep 17 00:00:00 2001 From: Kai Michael Poppe Date: Sun, 12 Jan 2025 21:29:08 +0100 Subject: [PATCH 01/15] Add Bus Stop Name Suggestions Resolves #5187 --- .../streetcomplete/quests/QuestsModule.kt | 2 + .../bus_stop_name/AddBusStopNameForm.kt | 22 +++++ .../BusStopNameSuggestionsSource.kt | 81 +++++++++++++++++++ .../res/layout/quest_localizedname_row.xml | 72 +++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt create mode 100644 app/src/main/res/layout/quest_localizedname_row.xml diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt index daab2febcc4..b2cb643d604 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt @@ -54,6 +54,7 @@ import de.westnordost.streetcomplete.quests.bus_stop_bench.AddBenchStatusOnBusSt import de.westnordost.streetcomplete.quests.bus_stop_bin.AddBinStatusOnBusStop import de.westnordost.streetcomplete.quests.bus_stop_lit.AddBusStopLit import de.westnordost.streetcomplete.quests.bus_stop_name.AddBusStopName +import de.westnordost.streetcomplete.quests.bus_stop_name.BusStopNameSuggestionsSource import de.westnordost.streetcomplete.quests.bus_stop_ref.AddBusStopRef import de.westnordost.streetcomplete.quests.bus_stop_shelter.AddBusStopShelter import de.westnordost.streetcomplete.quests.camera_type.AddCameraType @@ -187,6 +188,7 @@ import org.koin.dsl.module val questsModule = module { factory { RoadNameSuggestionsSource(get()) } + factory { BusStopNameSuggestionsSource(get()) } single { questTypeRegistry( diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt index a871c96315a..d2d7fcef6d5 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt @@ -2,10 +2,14 @@ package de.westnordost.streetcomplete.quests.bus_stop_name import androidx.appcompat.app.AlertDialog import de.westnordost.streetcomplete.R +import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry +import de.westnordost.streetcomplete.data.osm.geometry.ElementPolygonsGeometry +import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry import de.westnordost.streetcomplete.databinding.QuestLocalizednameBinding import de.westnordost.streetcomplete.osm.LocalizedName import de.westnordost.streetcomplete.quests.AAddLocalizedNameForm import de.westnordost.streetcomplete.quests.AnswerItem +import org.koin.android.ext.android.inject class AddBusStopNameForm : AAddLocalizedNameForm() { @@ -15,11 +19,25 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { override val addLanguageButton get() = binding.addLanguageButton override val namesList get() = binding.namesList + override val adapterRowLayoutResId = R.layout.quest_localizedname_row + override val otherAnswers = listOf( AnswerItem(R.string.quest_placeName_no_name_answer) { confirmNoName() }, AnswerItem(R.string.quest_streetName_answer_cantType) { showKeyboardInfo() } ) + private val busStopNameSuggestionsSource: BusStopNameSuggestionsSource by inject() + override fun getLocalizedNameSuggestions(): List> { + val polyline = when (val geom = geometry) { + is ElementPolylinesGeometry -> geom.polylines.first() + is ElementPolygonsGeometry -> geom.polygons.first() + is ElementPointGeometry -> listOf(geom.center) + } + return busStopNameSuggestionsSource.getNames( + listOf(polyline.first(), polyline.last()), + MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION + ) + } override fun onClickOk(names: List) { applyAnswer(BusStopName(names)) } @@ -31,4 +49,8 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { .setNegativeButton(R.string.quest_generic_confirmation_no, null) .show() } + + companion object { + const val MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION = 250.0 // m + } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt new file mode 100644 index 00000000000..ce5b21e5c8f --- /dev/null +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt @@ -0,0 +1,81 @@ +package de.westnordost.streetcomplete.quests.bus_stop_name + +import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource +import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry +import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry +import de.westnordost.streetcomplete.data.osm.mapdata.LatLon +import de.westnordost.streetcomplete.osm.LocalizedName +import de.westnordost.streetcomplete.osm.parseLocalizedNames +import de.westnordost.streetcomplete.util.math.distanceTo +import de.westnordost.streetcomplete.util.math.enclosingBoundingBox +import de.westnordost.streetcomplete.util.math.enlargedBy + +class BusStopNameSuggestionsSource( + private val mapDataSource: MapDataWithEditsSource +) { + + fun getNames(points: List, maxDistance: Double): List> { + if (points.isEmpty()) return emptyList() + + /* add 100m radius for bbox query because roads will only be included in the result that have + at least one node in the bounding box around the tap position. This is a problem for long + straight roads (#3797). This doesn't completely solve this issue but mitigates it */ + val bbox = points.enclosingBoundingBox().enlargedBy(maxDistance + 100) + val mapData = mapDataSource.getMapDataWithGeometry(bbox) + val busStopWaysWithNames = mapData.ways.filter { busStopFilter(it.tags) } + val busStopNodesWithNames = mapData.nodes.filter { busStopFilter(it.tags) } + + val result = mutableMapOf, Double>() + + for (busStop in busStopWaysWithNames) { + val geometry = mapData.getWayGeometry(busStop.id) as? ElementPolylinesGeometry ?: continue + + val polyline = geometry.polylines.firstOrNull() ?: continue + if (polyline.isEmpty()) continue + + val minDistanceToRoad = points.distanceTo(polyline) + if (minDistanceToRoad > maxDistance) continue + + val names = parseLocalizedNames(busStop.tags) ?: continue + + // eliminate duplicates (same road, different segments, different distances) + val prev = result[names] + if (prev != null && prev < minDistanceToRoad) continue + + result[names] = minDistanceToRoad + } + + for (busStop in busStopNodesWithNames) { + val geometry = mapData.getNodeGeometry(busStop.id) ?: continue + + val minDistanceToRoad = points.distanceTo(listOf(geometry.center)) + if (minDistanceToRoad > maxDistance) continue + + val names = parseLocalizedNames(busStop.tags) ?: continue + // eliminate duplicates (same road, different segments, different distances) + val prev = result[names] + if (prev != null && prev < minDistanceToRoad) continue + + result[names] = minDistanceToRoad + } + + // return only the road names, sorted by distance ascending + return result.entries.sortedBy { it.value }.map { it.key } + } + + private fun busStopFilter(tags: Map): Boolean { + return ( + tags.containsKey("name") && + ( + ( + (tags["highway"].equals("bus_stop") && !tags["public_transport"].equals("stop_position")) + || (tags["public_transport"].equals("platform") && tags["bus"].equals("yes")) + || tags["railway"].equals("halt") + || tags["railway"].equals("station") + || tags["railway"].equals("tram_stop") + ) + ) + ) + } + +} diff --git a/app/src/main/res/layout/quest_localizedname_row.xml b/app/src/main/res/layout/quest_localizedname_row.xml new file mode 100644 index 00000000000..411956ad5d3 --- /dev/null +++ b/app/src/main/res/layout/quest_localizedname_row.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + From 3b832c25ffdbe29a565a1d9c763d82711bc4cae5 Mon Sep 17 00:00:00 2001 From: Kai Michael Poppe Date: Mon, 13 Jan 2025 12:14:07 +0100 Subject: [PATCH 02/15] Update quest_localizedname_row.xml Removed forced colors to make quest_localizedname_row layout work with Light and Dark themes. --- app/src/main/res/layout/quest_localizedname_row.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/res/layout/quest_localizedname_row.xml b/app/src/main/res/layout/quest_localizedname_row.xml index 411956ad5d3..a1910785548 100644 --- a/app/src/main/res/layout/quest_localizedname_row.xml +++ b/app/src/main/res/layout/quest_localizedname_row.xml @@ -40,8 +40,6 @@ android:textAlignment="center" android:maxLines="1" android:inputType="text|textNoSuggestions|textCapSentences" - android:textColor="@color/traffic_black" - android:background="@color/traffic_white" tools:text="Sesame Street" tools:ignore="RtlCompat,SpUsage" /> @@ -52,12 +50,10 @@ android:layout_width="50dp" android:layout_height="wrap_content" app:srcCompat="@drawable/ic_arrow_expand_down_24dp" - app:tint="@color/traffic_black" android:layout_toStartOf="@+id/deleteButton" android:layout_centerVertical="true" android:layout_marginEnd="8dp" - style="@style/Base.Widget.AppCompat.Button.Borderless" - android:background="@color/background" /> + style="@style/Base.Widget.AppCompat.Button.Borderless" /> Date: Mon, 13 Jan 2025 12:46:12 +0100 Subject: [PATCH 03/15] Simplify busStopFilter by @FloEdelmann Co-authored-by: Flo Edelmann --- .../BusStopNameSuggestionsSource.kt | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt index ce5b21e5c8f..5f41c2adcd2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt @@ -63,19 +63,13 @@ class BusStopNameSuggestionsSource( return result.entries.sortedBy { it.value }.map { it.key } } - private fun busStopFilter(tags: Map): Boolean { - return ( - tags.containsKey("name") && - ( - ( - (tags["highway"].equals("bus_stop") && !tags["public_transport"].equals("stop_position")) - || (tags["public_transport"].equals("platform") && tags["bus"].equals("yes")) - || tags["railway"].equals("halt") - || tags["railway"].equals("station") - || tags["railway"].equals("tram_stop") - ) - ) + private fun busStopFilter(tags: Map) = + tags.containsKey("name") + && ( + (tags["highway"] == "bus_stop" && tags["public_transport"] != "stop_position") + || (tags["public_transport"] == "platform" && tags["bus"] == "yes") + || tags["railway"] == "halt" + || tags["railway"] == "station" + || tags["railway"] == "tram_stop" ) - } - } From 86bd839b8d5aca7e0909fabdd73b9f8b34d9c6a6 Mon Sep 17 00:00:00 2001 From: Kai Michael Poppe Date: Sun, 19 Jan 2025 11:38:43 +0100 Subject: [PATCH 04/15] Add NameSuggestionSource, declutter Bus- and RoadNameSuggestionSource Adding a centralized NameSuggestionSource, Bus- and RoadNameSuggestionSource now use their functions. De-Clutter BusNameSuggestionSource --- .../quests/NameSuggestionSource.kt | 73 +++++++++++++++++ .../bus_stop_name/AddBusStopNameForm.kt | 9 +-- .../BusStopNameSuggestionsSource.kt | 79 +++++-------------- .../road_name/RoadNameSuggestionsSource.kt | 53 +++---------- 4 files changed, 106 insertions(+), 108 deletions(-) create mode 100644 app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt new file mode 100644 index 00000000000..c42dc1ec2db --- /dev/null +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt @@ -0,0 +1,73 @@ +package de.westnordost.streetcomplete.quests + +import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource +import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry +import de.westnordost.streetcomplete.data.osm.mapdata.Element +import de.westnordost.streetcomplete.data.osm.mapdata.LatLon +import de.westnordost.streetcomplete.data.osm.mapdata.MapDataWithGeometry +import de.westnordost.streetcomplete.data.osm.mapdata.Way +import de.westnordost.streetcomplete.data.osm.mapdata.Node +import de.westnordost.streetcomplete.data.osm.mapdata.Relation +import de.westnordost.streetcomplete.osm.LocalizedName +import de.westnordost.streetcomplete.osm.parseLocalizedNames +import de.westnordost.streetcomplete.util.math.distanceTo +import de.westnordost.streetcomplete.util.math.enclosingBoundingBox +import de.westnordost.streetcomplete.util.math.enlargedBy + +class NameSuggestionSource( + private val mapDataSource: MapDataWithEditsSource +) { + + fun getNames( + points: List, + maxDistance: Double, + mapData: MapDataWithGeometry, + filteredElements: Sequence + ): List> { + if (points.isEmpty()) return emptyList() + + val result = mutableMapOf, Double>() + + for (elem in filteredElements) { + + var minDistanceToRoad = 0.0 + + if (elem is Way) { + val geometry = mapData.getWayGeometry(elem.id) as? ElementPolylinesGeometry ?: continue + + val polyline = geometry.polylines.firstOrNull() ?: continue + if (polyline.isEmpty()) continue + + minDistanceToRoad = points.distanceTo(polyline) + } + + if (elem is Node) { + val geometry = mapData.getNodeGeometry(elem.id) ?: continue + minDistanceToRoad = points.distanceTo(listOf(geometry.center)) + } + + if (elem is Relation) continue + + if (minDistanceToRoad > maxDistance) continue + val names = parseLocalizedNames(elem.tags) ?: continue + + // eliminate duplicates + val prev = result[names] + if (prev != null && prev < minDistanceToRoad) continue + + result[names] = minDistanceToRoad + } + + // return only the road names, sorted by distance ascending + return result.entries.sortedBy { it.value }.map { it.key } + } + + fun expandedMapData(points: List, maxDistance: Double): MapDataWithGeometry { + /* add 100m radius for bbox query because roads will only be included in the result that have + at least one node in the bounding box around the tap position. This is a problem for long + straight roads (#3797). This doesn't completely solve this issue but mitigates it */ + return mapDataSource.getMapDataWithGeometry( + points.enclosingBoundingBox().enlargedBy(maxDistance + 100) + ) + } +} diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt index d2d7fcef6d5..b805938ab4b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt @@ -19,8 +19,6 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { override val addLanguageButton get() = binding.addLanguageButton override val namesList get() = binding.namesList - override val adapterRowLayoutResId = R.layout.quest_localizedname_row - override val otherAnswers = listOf( AnswerItem(R.string.quest_placeName_no_name_answer) { confirmNoName() }, AnswerItem(R.string.quest_streetName_answer_cantType) { showKeyboardInfo() } @@ -28,13 +26,8 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { private val busStopNameSuggestionsSource: BusStopNameSuggestionsSource by inject() override fun getLocalizedNameSuggestions(): List> { - val polyline = when (val geom = geometry) { - is ElementPolylinesGeometry -> geom.polylines.first() - is ElementPolygonsGeometry -> geom.polygons.first() - is ElementPointGeometry -> listOf(geom.center) - } return busStopNameSuggestionsSource.getNames( - listOf(polyline.first(), polyline.last()), + listOf(geometry.center), MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION ) } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt index 5f41c2adcd2..00e6f868ce3 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt @@ -1,14 +1,10 @@ package de.westnordost.streetcomplete.quests.bus_stop_name import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource -import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry -import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry import de.westnordost.streetcomplete.data.osm.mapdata.LatLon +import de.westnordost.streetcomplete.data.osm.mapdata.filter import de.westnordost.streetcomplete.osm.LocalizedName -import de.westnordost.streetcomplete.osm.parseLocalizedNames -import de.westnordost.streetcomplete.util.math.distanceTo -import de.westnordost.streetcomplete.util.math.enclosingBoundingBox -import de.westnordost.streetcomplete.util.math.enlargedBy +import de.westnordost.streetcomplete.quests.NameSuggestionSource class BusStopNameSuggestionsSource( private val mapDataSource: MapDataWithEditsSource @@ -17,59 +13,22 @@ class BusStopNameSuggestionsSource( fun getNames(points: List, maxDistance: Double): List> { if (points.isEmpty()) return emptyList() - /* add 100m radius for bbox query because roads will only be included in the result that have - at least one node in the bounding box around the tap position. This is a problem for long - straight roads (#3797). This doesn't completely solve this issue but mitigates it */ - val bbox = points.enclosingBoundingBox().enlargedBy(maxDistance + 100) - val mapData = mapDataSource.getMapDataWithGeometry(bbox) - val busStopWaysWithNames = mapData.ways.filter { busStopFilter(it.tags) } - val busStopNodesWithNames = mapData.nodes.filter { busStopFilter(it.tags) } - - val result = mutableMapOf, Double>() - - for (busStop in busStopWaysWithNames) { - val geometry = mapData.getWayGeometry(busStop.id) as? ElementPolylinesGeometry ?: continue - - val polyline = geometry.polylines.firstOrNull() ?: continue - if (polyline.isEmpty()) continue - - val minDistanceToRoad = points.distanceTo(polyline) - if (minDistanceToRoad > maxDistance) continue - - val names = parseLocalizedNames(busStop.tags) ?: continue - - // eliminate duplicates (same road, different segments, different distances) - val prev = result[names] - if (prev != null && prev < minDistanceToRoad) continue - - result[names] = minDistanceToRoad - } - - for (busStop in busStopNodesWithNames) { - val geometry = mapData.getNodeGeometry(busStop.id) ?: continue - - val minDistanceToRoad = points.distanceTo(listOf(geometry.center)) - if (minDistanceToRoad > maxDistance) continue - - val names = parseLocalizedNames(busStop.tags) ?: continue - // eliminate duplicates (same road, different segments, different distances) - val prev = result[names] - if (prev != null && prev < minDistanceToRoad) continue - - result[names] = minDistanceToRoad - } - - // return only the road names, sorted by distance ascending - return result.entries.sortedBy { it.value }.map { it.key } - } - - private fun busStopFilter(tags: Map) = - tags.containsKey("name") - && ( - (tags["highway"] == "bus_stop" && tags["public_transport"] != "stop_position") - || (tags["public_transport"] == "platform" && tags["bus"] == "yes") - || tags["railway"] == "halt" - || tags["railway"] == "station" - || tags["railway"] == "tram_stop" + val nameSuggestionSource = NameSuggestionSource(mapDataSource) + val mapData = nameSuggestionSource.expandedMapData(points, maxDistance) + val elementFilter = """ + nodes, ways with + ( + public_transport = platform and bus = yes + or (highway = bus_stop and public_transport != stop_position) + or railway = halt + or railway = station + or railway = tram_stop + ) + and name + """ + + return nameSuggestionSource.getNames( + points, maxDistance, mapData, mapData.filter(elementFilter) ) + } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt index 64baa11c8f8..688a131f47b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt @@ -1,16 +1,12 @@ package de.westnordost.streetcomplete.quests.road_name import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource -import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry import de.westnordost.streetcomplete.data.osm.mapdata.LatLon -import de.westnordost.streetcomplete.data.osm.mapdata.Way +import de.westnordost.streetcomplete.data.osm.mapdata.filter import de.westnordost.streetcomplete.osm.ALL_PATHS import de.westnordost.streetcomplete.osm.ALL_ROADS import de.westnordost.streetcomplete.osm.LocalizedName -import de.westnordost.streetcomplete.osm.parseLocalizedNames -import de.westnordost.streetcomplete.util.math.distanceTo -import de.westnordost.streetcomplete.util.math.enclosingBoundingBox -import de.westnordost.streetcomplete.util.math.enlargedBy +import de.westnordost.streetcomplete.quests.NameSuggestionSource class RoadNameSuggestionsSource( private val mapDataSource: MapDataWithEditsSource @@ -19,39 +15,16 @@ class RoadNameSuggestionsSource( fun getNames(points: List, maxDistance: Double): List> { if (points.isEmpty()) return emptyList() - /* add 100m radius for bbox query because roads will only be included in the result that have - at least one node in the bounding box around the tap position. This is a problem for long - straight roads (#3797). This doesn't completely solve this issue but mitigates it */ - val bbox = points.enclosingBoundingBox().enlargedBy(maxDistance + 100) - val mapData = mapDataSource.getMapDataWithGeometry(bbox) - val roadsWithNames = mapData.ways.filter { it.isRoadWithName() } - - val result = mutableMapOf, Double>() - for (road in roadsWithNames) { - val geometry = mapData.getWayGeometry(road.id) as? ElementPolylinesGeometry ?: continue - - val polyline = geometry.polylines.firstOrNull() ?: continue - if (polyline.isEmpty()) continue - - val minDistanceToRoad = points.distanceTo(polyline) - if (minDistanceToRoad > maxDistance) continue - - val names = parseLocalizedNames(road.tags) ?: continue - - // eliminate duplicates (same road, different segments, different distances) - val prev = result[names] - if (prev != null && prev < minDistanceToRoad) continue - - result[names] = minDistanceToRoad - } - // return only the road names, sorted by distance ascending - return result.entries.sortedBy { it.value }.map { it.key } - } - - private fun Way.isRoadWithName(): Boolean = - tags.containsKey("name") && tags["highway"] in ALL_ROADS_AND_PATHS - - companion object { - private val ALL_ROADS_AND_PATHS = ALL_ROADS + ALL_PATHS + val nameSuggestionSource = NameSuggestionSource(mapDataSource) + val mapData = nameSuggestionSource.expandedMapData(points, maxDistance) + val elementFilter = """ + ways with + highway ~ ${(ALL_ROADS + ALL_PATHS).joinToString("|")} + and name + """ + + return nameSuggestionSource.getNames( + points, maxDistance, mapData, mapData.filter(elementFilter) + ) } } From fa25d861c5207cc99a310fb8fdb92edbb6862747 Mon Sep 17 00:00:00 2001 From: Kai Michael Poppe Date: Sun, 19 Jan 2025 20:14:59 +0100 Subject: [PATCH 05/15] remove in-betweens for Road- and BusNameSuggestions, use NameSuggestionsSource in all Quests --- .../AddressStreetNameInputViewController.kt | 9 ++--- .../StreetOrPlaceNameViewController.kt | 6 ++-- .../overlays/address/AddressOverlayForm.kt | 6 ++-- ...tionSource.kt => NameSuggestionsSource.kt} | 17 +++++++--- .../streetcomplete/quests/QuestsModule.kt | 5 +-- .../quests/address/AddAddressStreetForm.kt | 6 ++-- .../bus_stop_name/AddBusStopNameForm.kt | 24 +++++++++---- .../BusStopNameSuggestionsSource.kt | 34 ------------------- .../quests/road_name/AddRoadNameForm.kt | 17 ++++++++-- .../road_name/RoadNameSuggestionsSource.kt | 30 ---------------- 10 files changed, 60 insertions(+), 94 deletions(-) rename app/src/main/java/de/westnordost/streetcomplete/quests/{NameSuggestionSource.kt => NameSuggestionsSource.kt} (83%) delete mode 100644 app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt delete mode 100644 app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt index 67659e3370e..2e8ed3c3d5f 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt @@ -4,7 +4,8 @@ import android.widget.EditText import androidx.core.widget.doAfterTextChanged import de.westnordost.streetcomplete.data.meta.AbbreviationsByLocale import de.westnordost.streetcomplete.data.osm.mapdata.LatLon -import de.westnordost.streetcomplete.quests.road_name.RoadNameSuggestionsSource +import de.westnordost.streetcomplete.quests.NameSuggestionsSource +import de.westnordost.streetcomplete.quests.road_name.AddRoadNameForm import de.westnordost.streetcomplete.util.ktx.nonBlankTextOrNull import de.westnordost.streetcomplete.view.controller.AutoCorrectAbbreviationsViewController import java.util.Locale @@ -14,7 +15,7 @@ import java.util.Locale * automatically expanded, e.g. "Main st" becomes "Main street" */ class AddressStreetNameInputViewController( private val streetNameInput: EditText, - private val roadNameSuggestionsSource: RoadNameSuggestionsSource, + private val nameSuggestionsSource: NameSuggestionsSource, abbreviationsByLocale: AbbreviationsByLocale, private val countryLocale: Locale ) { @@ -37,8 +38,8 @@ class AddressStreetNameInputViewController( * instead of typing it in the edit text */ fun selectStreetAt(position: LatLon, radiusInMeters: Double): Boolean { val dist = radiusInMeters + 5 - val namesByLocale = roadNameSuggestionsSource - .getNames(listOf(position), dist) + val namesByLocale = nameSuggestionsSource + .getNames(listOf(position), dist, AddRoadNameForm.elementFilter) .firstOrNull() ?.associate { it.languageTag to it.name }?.toMutableMap() ?: return false diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/address/StreetOrPlaceNameViewController.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/address/StreetOrPlaceNameViewController.kt index eb59439fcb5..6e1122c01fd 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/address/StreetOrPlaceNameViewController.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/address/StreetOrPlaceNameViewController.kt @@ -11,7 +11,7 @@ import de.westnordost.streetcomplete.R import de.westnordost.streetcomplete.data.meta.AbbreviationsByLocale import de.westnordost.streetcomplete.data.osm.mapdata.LatLon import de.westnordost.streetcomplete.osm.address.StreetOrPlaceNameViewController.StreetOrPlace.* -import de.westnordost.streetcomplete.quests.road_name.RoadNameSuggestionsSource +import de.westnordost.streetcomplete.quests.NameSuggestionsSource import de.westnordost.streetcomplete.util.ktx.nonBlankTextOrNull import de.westnordost.streetcomplete.view.OnAdapterItemSelectedListener import java.util.Locale @@ -26,13 +26,13 @@ class StreetOrPlaceNameViewController( private val placeNameInput: EditText, private val streetNameInputContainer: View, private val streetNameInput: EditText, - roadNameSuggestionsSource: RoadNameSuggestionsSource, + nameSuggestionsSource: NameSuggestionsSource, abbreviationsByLocale: AbbreviationsByLocale, countryLocale: Locale, startWithPlace: Boolean, ) { private val streetNameInputCtrl = AddressStreetNameInputViewController( - streetNameInput, roadNameSuggestionsSource, abbreviationsByLocale, countryLocale + streetNameInput, nameSuggestionsSource, abbreviationsByLocale, countryLocale ) var onInputChanged: (() -> Unit)? = null diff --git a/app/src/main/java/de/westnordost/streetcomplete/overlays/address/AddressOverlayForm.kt b/app/src/main/java/de/westnordost/streetcomplete/overlays/address/AddressOverlayForm.kt index 569569dfc26..aa29a00097f 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/overlays/address/AddressOverlayForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/overlays/address/AddressOverlayForm.kt @@ -40,7 +40,7 @@ import de.westnordost.streetcomplete.osm.address.streetHouseNumber import de.westnordost.streetcomplete.overlays.AbstractOverlayForm import de.westnordost.streetcomplete.overlays.AnswerItem import de.westnordost.streetcomplete.overlays.IAnswerItem -import de.westnordost.streetcomplete.quests.road_name.RoadNameSuggestionsSource +import de.westnordost.streetcomplete.quests.NameSuggestionsSource import de.westnordost.streetcomplete.screens.main.bottom_sheet.IsMapPositionAware import de.westnordost.streetcomplete.util.getNameAndLocationSpanned import de.westnordost.streetcomplete.util.ktx.dpToPx @@ -57,7 +57,7 @@ class AddressOverlayForm : AbstractOverlayForm(), IsMapPositionAware { private val mapDataWithEditsSource: MapDataWithEditsSource by inject() private val abbreviationsByLocale: AbbreviationsByLocale by inject() - private val roadNameSuggestionsSource: RoadNameSuggestionsSource by inject() + private val nameSuggestionsSource: NameSuggestionsSource by inject() private lateinit var numberOrNameInputCtrl: AddressNumberAndNameInputViewController private lateinit var streetOrPlaceCtrl: StreetOrPlaceNameViewController @@ -149,7 +149,7 @@ class AddressOverlayForm : AbstractOverlayForm(), IsMapPositionAware { placeNameInput = streetOrPlaceBinding.placeNameInput.apply { hint = lastPlaceName }, streetNameInputContainer = streetOrPlaceBinding.streetNameInputContainer, streetNameInput = streetOrPlaceBinding.streetNameInput.apply { hint = lastStreetName }, - roadNameSuggestionsSource = roadNameSuggestionsSource, + nameSuggestionsSource = nameSuggestionsSource, abbreviationsByLocale = abbreviationsByLocale, countryLocale = countryInfo.locale, startWithPlace = isShowingPlaceName diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt similarity index 83% rename from app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt rename to app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index c42dc1ec2db..814ebe3a9a2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -8,24 +8,33 @@ import de.westnordost.streetcomplete.data.osm.mapdata.MapDataWithGeometry import de.westnordost.streetcomplete.data.osm.mapdata.Way import de.westnordost.streetcomplete.data.osm.mapdata.Node import de.westnordost.streetcomplete.data.osm.mapdata.Relation +import de.westnordost.streetcomplete.data.osm.mapdata.filter import de.westnordost.streetcomplete.osm.LocalizedName import de.westnordost.streetcomplete.osm.parseLocalizedNames import de.westnordost.streetcomplete.util.math.distanceTo import de.westnordost.streetcomplete.util.math.enclosingBoundingBox import de.westnordost.streetcomplete.util.math.enlargedBy -class NameSuggestionSource( +class NameSuggestionsSource( private val mapDataSource: MapDataWithEditsSource ) { - fun getNames( + fun getNames(points: List, maxDistance: Double, elementFilter: String): List> { + return getNamesFiltered( + points, + maxDistance, + expandedMapData(points, maxDistance).filter(elementFilter) + ) + } + + private fun getNamesFiltered( points: List, maxDistance: Double, - mapData: MapDataWithGeometry, filteredElements: Sequence ): List> { if (points.isEmpty()) return emptyList() + val mapData = expandedMapData(points, maxDistance) val result = mutableMapOf, Double>() for (elem in filteredElements) { @@ -62,7 +71,7 @@ class NameSuggestionSource( return result.entries.sortedBy { it.value }.map { it.key } } - fun expandedMapData(points: List, maxDistance: Double): MapDataWithGeometry { + private fun expandedMapData(points: List, maxDistance: Double): MapDataWithGeometry { /* add 100m radius for bbox query because roads will only be included in the result that have at least one node in the bounding box around the tap position. This is a problem for long straight roads (#3797). This doesn't completely solve this issue but mitigates it */ diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt index b2cb643d604..75adefc05f2 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/QuestsModule.kt @@ -54,7 +54,6 @@ import de.westnordost.streetcomplete.quests.bus_stop_bench.AddBenchStatusOnBusSt import de.westnordost.streetcomplete.quests.bus_stop_bin.AddBinStatusOnBusStop import de.westnordost.streetcomplete.quests.bus_stop_lit.AddBusStopLit import de.westnordost.streetcomplete.quests.bus_stop_name.AddBusStopName -import de.westnordost.streetcomplete.quests.bus_stop_name.BusStopNameSuggestionsSource import de.westnordost.streetcomplete.quests.bus_stop_ref.AddBusStopRef import de.westnordost.streetcomplete.quests.bus_stop_shelter.AddBusStopShelter import de.westnordost.streetcomplete.quests.camera_type.AddCameraType @@ -136,7 +135,6 @@ import de.westnordost.streetcomplete.quests.recycling_material.AddRecyclingConta import de.westnordost.streetcomplete.quests.religion.AddReligionToPlaceOfWorship import de.westnordost.streetcomplete.quests.religion.AddReligionToWaysideShrine import de.westnordost.streetcomplete.quests.road_name.AddRoadName -import de.westnordost.streetcomplete.quests.road_name.RoadNameSuggestionsSource import de.westnordost.streetcomplete.quests.roof_shape.AddRoofShape import de.westnordost.streetcomplete.quests.sanitary_dump_station.AddSanitaryDumpStation import de.westnordost.streetcomplete.quests.seating.AddSeating @@ -187,8 +185,7 @@ import org.koin.core.qualifier.named import org.koin.dsl.module val questsModule = module { - factory { RoadNameSuggestionsSource(get()) } - factory { BusStopNameSuggestionsSource(get()) } + factory { NameSuggestionsSource(get()) } single { questTypeRegistry( diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/address/AddAddressStreetForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/address/AddAddressStreetForm.kt index 21a827daa38..bc438c236a8 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/address/AddAddressStreetForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/address/AddAddressStreetForm.kt @@ -12,7 +12,7 @@ import de.westnordost.streetcomplete.osm.address.StreetOrPlaceName import de.westnordost.streetcomplete.osm.address.StreetOrPlaceNameViewController import de.westnordost.streetcomplete.quests.AbstractOsmQuestForm import de.westnordost.streetcomplete.quests.AnswerItem -import de.westnordost.streetcomplete.quests.road_name.RoadNameSuggestionsSource +import de.westnordost.streetcomplete.quests.NameSuggestionsSource import de.westnordost.streetcomplete.util.getNameAndLocationSpanned import org.koin.android.ext.android.inject @@ -21,7 +21,7 @@ class AddAddressStreetForm : AbstractOsmQuestForm() { private val binding by contentViewBinding(ViewStreetOrPlaceNameInputBinding::bind) private val abbreviationsByLocale: AbbreviationsByLocale by inject() - private val roadNameSuggestionsSource: RoadNameSuggestionsSource by inject() + private val nameSuggestionsSource: NameSuggestionsSource by inject() private lateinit var streetOrPlaceCtrl: StreetOrPlaceNameViewController @@ -51,7 +51,7 @@ class AddAddressStreetForm : AbstractOsmQuestForm() { placeNameInput = binding.placeNameInput, streetNameInputContainer = binding.streetNameInputContainer, streetNameInput = binding.streetNameInput, - roadNameSuggestionsSource = roadNameSuggestionsSource, + nameSuggestionsSource = nameSuggestionsSource, abbreviationsByLocale = abbreviationsByLocale, countryLocale = countryInfo.locale, startWithPlace = isShowingPlaceName diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt index b805938ab4b..cb3b86b238b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt @@ -2,13 +2,11 @@ package de.westnordost.streetcomplete.quests.bus_stop_name import androidx.appcompat.app.AlertDialog import de.westnordost.streetcomplete.R -import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry -import de.westnordost.streetcomplete.data.osm.geometry.ElementPolygonsGeometry -import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry import de.westnordost.streetcomplete.databinding.QuestLocalizednameBinding import de.westnordost.streetcomplete.osm.LocalizedName import de.westnordost.streetcomplete.quests.AAddLocalizedNameForm import de.westnordost.streetcomplete.quests.AnswerItem +import de.westnordost.streetcomplete.quests.NameSuggestionsSource import org.koin.android.ext.android.inject class AddBusStopNameForm : AAddLocalizedNameForm() { @@ -23,13 +21,27 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { AnswerItem(R.string.quest_placeName_no_name_answer) { confirmNoName() }, AnswerItem(R.string.quest_streetName_answer_cantType) { showKeyboardInfo() } ) - private val busStopNameSuggestionsSource: BusStopNameSuggestionsSource by inject() + private val nameSuggestionsSource: NameSuggestionsSource by inject() override fun getLocalizedNameSuggestions(): List> { - return busStopNameSuggestionsSource.getNames( + val elementFilter = """ + nodes, ways with + ( + public_transport = platform and bus = yes + or (highway = bus_stop and public_transport != stop_position) + or railway = halt + or railway = station + or railway = tram_stop + ) + and name + """ + + return nameSuggestionsSource.getNames( listOf(geometry.center), - MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION + MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION, + elementFilter ) + } override fun onClickOk(names: List) { applyAnswer(BusStopName(names)) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt deleted file mode 100644 index 00e6f868ce3..00000000000 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/BusStopNameSuggestionsSource.kt +++ /dev/null @@ -1,34 +0,0 @@ -package de.westnordost.streetcomplete.quests.bus_stop_name - -import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource -import de.westnordost.streetcomplete.data.osm.mapdata.LatLon -import de.westnordost.streetcomplete.data.osm.mapdata.filter -import de.westnordost.streetcomplete.osm.LocalizedName -import de.westnordost.streetcomplete.quests.NameSuggestionSource - -class BusStopNameSuggestionsSource( - private val mapDataSource: MapDataWithEditsSource -) { - - fun getNames(points: List, maxDistance: Double): List> { - if (points.isEmpty()) return emptyList() - - val nameSuggestionSource = NameSuggestionSource(mapDataSource) - val mapData = nameSuggestionSource.expandedMapData(points, maxDistance) - val elementFilter = """ - nodes, ways with - ( - public_transport = platform and bus = yes - or (highway = bus_stop and public_transport != stop_position) - or railway = halt - or railway = station - or railway = tram_stop - ) - and name - """ - - return nameSuggestionSource.getNames( - points, maxDistance, mapData, mapData.filter(elementFilter) - ) - } -} diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt index 5ba3063f8d2..48f19ef8967 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt @@ -8,9 +8,12 @@ import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry import de.westnordost.streetcomplete.data.osm.geometry.ElementPolygonsGeometry import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry import de.westnordost.streetcomplete.databinding.QuestRoadnameBinding +import de.westnordost.streetcomplete.osm.ALL_PATHS +import de.westnordost.streetcomplete.osm.ALL_ROADS import de.westnordost.streetcomplete.osm.LocalizedName import de.westnordost.streetcomplete.quests.AAddLocalizedNameForm import de.westnordost.streetcomplete.quests.AnswerItem +import de.westnordost.streetcomplete.quests.NameSuggestionsSource import org.koin.android.ext.android.inject import java.lang.IllegalStateException import java.util.LinkedList @@ -32,7 +35,7 @@ class AddRoadNameForm : AAddLocalizedNameForm() { ) private val abbrByLocale: AbbreviationsByLocale by inject() - private val roadNameSuggestionsSource: RoadNameSuggestionsSource by inject() + private val nameSuggestionsSource: NameSuggestionsSource by inject() override fun getAbbreviationsByLocale(): AbbreviationsByLocale = abbrByLocale @@ -42,9 +45,11 @@ class AddRoadNameForm : AAddLocalizedNameForm() { is ElementPolygonsGeometry -> geom.polygons.first() is ElementPointGeometry -> listOf(geom.center) } - return roadNameSuggestionsSource.getNames( + + return nameSuggestionsSource.getNames( listOf(polyline.first(), polyline.last()), - MAX_DIST_FOR_ROAD_NAME_SUGGESTION + MAX_DIST_FOR_ROAD_NAME_SUGGESTION, + elementFilter ) } @@ -137,5 +142,11 @@ class AddRoadNameForm : AAddLocalizedNameForm() { companion object { const val MAX_DIST_FOR_ROAD_NAME_SUGGESTION = 30.0 // m + + val elementFilter = """ + ways with + highway ~ ${(ALL_ROADS + ALL_PATHS).joinToString("|")} + and name + """ } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt deleted file mode 100644 index 688a131f47b..00000000000 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/RoadNameSuggestionsSource.kt +++ /dev/null @@ -1,30 +0,0 @@ -package de.westnordost.streetcomplete.quests.road_name - -import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource -import de.westnordost.streetcomplete.data.osm.mapdata.LatLon -import de.westnordost.streetcomplete.data.osm.mapdata.filter -import de.westnordost.streetcomplete.osm.ALL_PATHS -import de.westnordost.streetcomplete.osm.ALL_ROADS -import de.westnordost.streetcomplete.osm.LocalizedName -import de.westnordost.streetcomplete.quests.NameSuggestionSource - -class RoadNameSuggestionsSource( - private val mapDataSource: MapDataWithEditsSource -) { - - fun getNames(points: List, maxDistance: Double): List> { - if (points.isEmpty()) return emptyList() - - val nameSuggestionSource = NameSuggestionSource(mapDataSource) - val mapData = nameSuggestionSource.expandedMapData(points, maxDistance) - val elementFilter = """ - ways with - highway ~ ${(ALL_ROADS + ALL_PATHS).joinToString("|")} - and name - """ - - return nameSuggestionSource.getNames( - points, maxDistance, mapData, mapData.filter(elementFilter) - ) - } -} From d2b42f668060d379f19b848a41c033af6c278316 Mon Sep 17 00:00:00 2001 From: Kai Michael Poppe Date: Sun, 19 Jan 2025 20:24:38 +0100 Subject: [PATCH 06/15] Delete quest_localizedname_row.xml Remove unused layout --- .../res/layout/quest_localizedname_row.xml | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 app/src/main/res/layout/quest_localizedname_row.xml diff --git a/app/src/main/res/layout/quest_localizedname_row.xml b/app/src/main/res/layout/quest_localizedname_row.xml deleted file mode 100644 index a1910785548..00000000000 --- a/app/src/main/res/layout/quest_localizedname_row.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - From a2f80e7db7ac43445c287a38adc3d86ef91e30a4 Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 12:34:21 +0100 Subject: [PATCH 07/15] make the element filter a private field --- .../bus_stop_name/AddBusStopNameForm.kt | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt index cb3b86b238b..5719ab6f6fe 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt @@ -11,6 +11,8 @@ import org.koin.android.ext.android.inject class AddBusStopNameForm : AAddLocalizedNameForm() { + private val nameSuggestionsSource: NameSuggestionsSource by inject() + override val contentLayoutResId = R.layout.quest_localizedname private val binding by contentViewBinding(QuestLocalizednameBinding::bind) @@ -21,28 +23,26 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { AnswerItem(R.string.quest_placeName_no_name_answer) { confirmNoName() }, AnswerItem(R.string.quest_streetName_answer_cantType) { showKeyboardInfo() } ) - private val nameSuggestionsSource: NameSuggestionsSource by inject() - override fun getLocalizedNameSuggestions(): List> { - val elementFilter = """ - nodes, ways with - ( - public_transport = platform and bus = yes - or (highway = bus_stop and public_transport != stop_position) - or railway = halt - or railway = station - or railway = tram_stop - ) - and name - """ - - return nameSuggestionsSource.getNames( + private val busStopsWithNamesFilter = """ + nodes, ways with + ( + public_transport = platform and bus = yes + or (highway = bus_stop and public_transport != stop_position) + or railway = halt + or railway = station + or railway = tram_stop + ) + and name + """ + + override fun getLocalizedNameSuggestions(): List> = + nameSuggestionsSource.getNames( listOf(geometry.center), MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION, - elementFilter + busStopsWithNamesFilter ) - } override fun onClickOk(names: List) { applyAnswer(BusStopName(names)) } From 35871517f4978f96b9a6f7e29f6e8aed56d7cc6e Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 12:46:26 +0100 Subject: [PATCH 08/15] add doc comment --- .../streetcomplete/quests/NameSuggestionsSource.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index 814ebe3a9a2..8732b2a282e 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -18,7 +18,12 @@ import de.westnordost.streetcomplete.util.math.enlargedBy class NameSuggestionsSource( private val mapDataSource: MapDataWithEditsSource ) { - + /** + * Return a list of [LocalizedName]s of elements with name(s), sorted by distance ascending to + * any of the given [points] that have at most a distance of [maxDistance] to those. The + * elements can be filtered with the given [elementFilter] expression, to e.g. only find + * roads with names. + */ fun getNames(points: List, maxDistance: Double, elementFilter: String): List> { return getNamesFiltered( points, From 9e84a6083643f5677f71477b1f5c772a9438d377 Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 12:46:47 +0100 Subject: [PATCH 09/15] no need for private function --- .../streetcomplete/quests/NameSuggestionsSource.kt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index 8732b2a282e..3c55e31b089 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -25,21 +25,10 @@ class NameSuggestionsSource( * roads with names. */ fun getNames(points: List, maxDistance: Double, elementFilter: String): List> { - return getNamesFiltered( - points, - maxDistance, - expandedMapData(points, maxDistance).filter(elementFilter) - ) - } - - private fun getNamesFiltered( - points: List, - maxDistance: Double, - filteredElements: Sequence - ): List> { if (points.isEmpty()) return emptyList() val mapData = expandedMapData(points, maxDistance) + val filteredElements = mapData.filter(elementFilter) val result = mutableMapOf, Double>() for (elem in filteredElements) { From c9c43319d94df3a8f2ff9461ca608b1b4fa44aca Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 12:56:22 +0100 Subject: [PATCH 10/15] correct variable name --- .../streetcomplete/quests/NameSuggestionsSource.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index 3c55e31b089..7200b52ea8b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -33,7 +33,7 @@ class NameSuggestionsSource( for (elem in filteredElements) { - var minDistanceToRoad = 0.0 + var minDistance = 0.0 if (elem is Way) { val geometry = mapData.getWayGeometry(elem.id) as? ElementPolylinesGeometry ?: continue @@ -41,24 +41,24 @@ class NameSuggestionsSource( val polyline = geometry.polylines.firstOrNull() ?: continue if (polyline.isEmpty()) continue - minDistanceToRoad = points.distanceTo(polyline) + minDistance = points.distanceTo(polyline) } if (elem is Node) { val geometry = mapData.getNodeGeometry(elem.id) ?: continue - minDistanceToRoad = points.distanceTo(listOf(geometry.center)) + minDistance = points.distanceTo(listOf(geometry.center)) } if (elem is Relation) continue - if (minDistanceToRoad > maxDistance) continue + if (minDistance > maxDistance) continue val names = parseLocalizedNames(elem.tags) ?: continue // eliminate duplicates val prev = result[names] - if (prev != null && prev < minDistanceToRoad) continue + if (prev != null && prev < minDistance) continue - result[names] = minDistanceToRoad + result[names] = minDistance } // return only the road names, sorted by distance ascending From 75883721e2b149adddcf254fe1bfaea2f72bd013 Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 13:02:01 +0100 Subject: [PATCH 11/15] simplify distance of points to node (List.distanceTo(List, ...) is documented as distance of two polylines. It is only by "coincidence" that this is equal to minimum distance of two sets of points to each other) --- .../westnordost/streetcomplete/quests/NameSuggestionsSource.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index 7200b52ea8b..0ec97895098 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -45,8 +45,7 @@ class NameSuggestionsSource( } if (elem is Node) { - val geometry = mapData.getNodeGeometry(elem.id) ?: continue - minDistance = points.distanceTo(listOf(geometry.center)) + minDistance = points.minOf { elem.position.distanceTo(it) } } if (elem is Relation) continue From c84838bdf363f8529df71ab6493f3288a4f04c77 Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 13:06:05 +0100 Subject: [PATCH 12/15] no need for private function --- .../quests/NameSuggestionsSource.kt | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index 0ec97895098..0767ceda7ca 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -2,9 +2,7 @@ package de.westnordost.streetcomplete.quests import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry -import de.westnordost.streetcomplete.data.osm.mapdata.Element import de.westnordost.streetcomplete.data.osm.mapdata.LatLon -import de.westnordost.streetcomplete.data.osm.mapdata.MapDataWithGeometry import de.westnordost.streetcomplete.data.osm.mapdata.Way import de.westnordost.streetcomplete.data.osm.mapdata.Node import de.westnordost.streetcomplete.data.osm.mapdata.Relation @@ -27,8 +25,13 @@ class NameSuggestionsSource( fun getNames(points: List, maxDistance: Double, elementFilter: String): List> { if (points.isEmpty()) return emptyList() - val mapData = expandedMapData(points, maxDistance) + /* add 100m radius for bbox query because roads will only be included in the result that + have at least one node in the bounding box around the tap position. This is a problem for + long straight roads (#3797). This doesn't completely solve this issue but mitigates it */ + val bbox = points.enclosingBoundingBox().enlargedBy(maxDistance + 100) + val mapData = mapDataSource.getMapDataWithGeometry(bbox) val filteredElements = mapData.filter(elementFilter) + // map of localized names -> min distance val result = mutableMapOf, Double>() for (elem in filteredElements) { @@ -63,13 +66,4 @@ class NameSuggestionsSource( // return only the road names, sorted by distance ascending return result.entries.sortedBy { it.value }.map { it.key } } - - private fun expandedMapData(points: List, maxDistance: Double): MapDataWithGeometry { - /* add 100m radius for bbox query because roads will only be included in the result that have - at least one node in the bounding box around the tap position. This is a problem for long - straight roads (#3797). This doesn't completely solve this issue but mitigates it */ - return mapDataSource.getMapDataWithGeometry( - points.enclosingBoundingBox().enlargedBy(maxDistance + 100) - ) - } } From 363e4817b2406e544d09382d09b37b8c759d632e Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 13:28:08 +0100 Subject: [PATCH 13/15] add global function to get minimum distance between a point and an element geometry --- .../quests/NameSuggestionsSource.kt | 28 ++++--------------- .../util/math/ElementGeometryMath.kt | 19 +++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index 0767ceda7ca..d5238a9eb73 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -1,15 +1,11 @@ package de.westnordost.streetcomplete.quests import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource -import de.westnordost.streetcomplete.data.osm.geometry.ElementPolylinesGeometry import de.westnordost.streetcomplete.data.osm.mapdata.LatLon -import de.westnordost.streetcomplete.data.osm.mapdata.Way -import de.westnordost.streetcomplete.data.osm.mapdata.Node -import de.westnordost.streetcomplete.data.osm.mapdata.Relation import de.westnordost.streetcomplete.data.osm.mapdata.filter import de.westnordost.streetcomplete.osm.LocalizedName import de.westnordost.streetcomplete.osm.parseLocalizedNames -import de.westnordost.streetcomplete.util.math.distanceTo +import de.westnordost.streetcomplete.util.math.distance import de.westnordost.streetcomplete.util.math.enclosingBoundingBox import de.westnordost.streetcomplete.util.math.enlargedBy @@ -35,28 +31,14 @@ class NameSuggestionsSource( val result = mutableMapOf, Double>() for (elem in filteredElements) { + val geometry = mapData.getGeometry(elem.type, elem.id) ?: continue - var minDistance = 0.0 - - if (elem is Way) { - val geometry = mapData.getWayGeometry(elem.id) as? ElementPolylinesGeometry ?: continue - - val polyline = geometry.polylines.firstOrNull() ?: continue - if (polyline.isEmpty()) continue - - minDistance = points.distanceTo(polyline) - } - - if (elem is Node) { - minDistance = points.minOf { elem.position.distanceTo(it) } - } - - if (elem is Relation) continue - + val minDistance = points.minOf { geometry.distance(it) } if (minDistance > maxDistance) continue + val names = parseLocalizedNames(elem.tags) ?: continue - // eliminate duplicates + // eliminate duplicates (e.g. same road, different segments, different distances) val prev = result[names] if (prev != null && prev < minDistance) continue diff --git a/app/src/main/java/de/westnordost/streetcomplete/util/math/ElementGeometryMath.kt b/app/src/main/java/de/westnordost/streetcomplete/util/math/ElementGeometryMath.kt index af9935b4708..1724dd36972 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/util/math/ElementGeometryMath.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/util/math/ElementGeometryMath.kt @@ -24,6 +24,25 @@ fun ElementGeometry.intersects(other: ElementGeometry): Boolean { } } +/** Minimum distance to a [point]. If this is a polygon(s), the distance is 0 if [point] is within + * this polygon(s). */ +fun ElementGeometry.distance(point: LatLon): Double = + when (this) { + is ElementPointGeometry -> { + center.distanceTo(point) + } + is ElementPolylinesGeometry -> { + polylines.filter { it.isNotEmpty() }.minOf { point.distanceToArcs(it) } + } + is ElementPolygonsGeometry -> { + if (polygons.any { point.isInPolygon(it) }) { + 0.0 + } else { + polygons.filter { it.isNotEmpty() }.minOf { point.distanceToArcs(it) } + } + } + } + private fun ElementGeometry.asList(): List> = when (this) { is ElementPointGeometry -> listOf(listOf(center)) is ElementPolygonsGeometry -> polygons From 7b559761613978a1ec520a62385428a7bf34d7ec Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 13:46:10 +0100 Subject: [PATCH 14/15] replace string filter on getNames with properly typed parameter, add explanatory comments as for the parameters chosen --- .../AddressStreetNameInputViewController.kt | 16 +++++++++-- .../quests/NameSuggestionsSource.kt | 23 ++++++++------- .../quests/bus_stop_name/AddBusStopName.kt | 1 + .../bus_stop_name/AddBusStopNameForm.kt | 17 ++++++----- .../quests/road_name/AddRoadNameForm.kt | 28 +++++++++---------- 5 files changed, 48 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt b/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt index 2e8ed3c3d5f..5484e688e05 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/osm/address/AddressStreetNameInputViewController.kt @@ -2,8 +2,11 @@ package de.westnordost.streetcomplete.osm.address import android.widget.EditText import androidx.core.widget.doAfterTextChanged +import de.westnordost.streetcomplete.data.elementfilter.toElementFilterExpression import de.westnordost.streetcomplete.data.meta.AbbreviationsByLocale import de.westnordost.streetcomplete.data.osm.mapdata.LatLon +import de.westnordost.streetcomplete.osm.ALL_PATHS +import de.westnordost.streetcomplete.osm.ALL_ROADS import de.westnordost.streetcomplete.quests.NameSuggestionsSource import de.westnordost.streetcomplete.quests.road_name.AddRoadNameForm import de.westnordost.streetcomplete.util.ktx.nonBlankTextOrNull @@ -21,6 +24,10 @@ class AddressStreetNameInputViewController( ) { private val autoCorrectAbbreviationsViewController: AutoCorrectAbbreviationsViewController + private val roadsWithNamesFilter = + "ways with highway ~ ${(ALL_ROADS + ALL_PATHS).joinToString("|")} and name" + .toElementFilterExpression() + var onInputChanged: (() -> Unit)? = null var streetName: String? @@ -34,12 +41,15 @@ class AddressStreetNameInputViewController( streetNameInput.doAfterTextChanged { onInputChanged?.invoke() } } - /** select the name of the street near the given [position] (ast most [radiusInMeters] from it) + /** select the name of the street near the given [position] (at most [radiusInMeters] from it) * instead of typing it in the edit text */ fun selectStreetAt(position: LatLon, radiusInMeters: Double): Boolean { - val dist = radiusInMeters + 5 val namesByLocale = nameSuggestionsSource - .getNames(listOf(position), dist, AddRoadNameForm.elementFilter) + .getNames( + points = listOf(position), + maxDistance = radiusInMeters, + filter = roadsWithNamesFilter + ) .firstOrNull() ?.associate { it.languageTag to it.name }?.toMutableMap() ?: return false diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt index d5238a9eb73..4e101a03eae 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/NameSuggestionsSource.kt @@ -1,5 +1,6 @@ package de.westnordost.streetcomplete.quests +import de.westnordost.streetcomplete.data.elementfilter.ElementFilterExpression import de.westnordost.streetcomplete.data.osm.edits.MapDataWithEditsSource import de.westnordost.streetcomplete.data.osm.mapdata.LatLon import de.westnordost.streetcomplete.data.osm.mapdata.filter @@ -9,16 +10,18 @@ import de.westnordost.streetcomplete.util.math.distance import de.westnordost.streetcomplete.util.math.enclosingBoundingBox import de.westnordost.streetcomplete.util.math.enlargedBy -class NameSuggestionsSource( - private val mapDataSource: MapDataWithEditsSource -) { +class NameSuggestionsSource(private val mapDataSource: MapDataWithEditsSource) { /** * Return a list of [LocalizedName]s of elements with name(s), sorted by distance ascending to - * any of the given [points] that have at most a distance of [maxDistance] to those. The - * elements can be filtered with the given [elementFilter] expression, to e.g. only find + * any of the given [points] that have at most a distance of [maxDistance] in m to those. The + * elements can be filtered with the given [filter] expression, to e.g. only find * roads with names. */ - fun getNames(points: List, maxDistance: Double, elementFilter: String): List> { + fun getNames( + points: List, + maxDistance: Double, + filter: ElementFilterExpression + ): List> { if (points.isEmpty()) return emptyList() /* add 100m radius for bbox query because roads will only be included in the result that @@ -26,17 +29,17 @@ class NameSuggestionsSource( long straight roads (#3797). This doesn't completely solve this issue but mitigates it */ val bbox = points.enclosingBoundingBox().enlargedBy(maxDistance + 100) val mapData = mapDataSource.getMapDataWithGeometry(bbox) - val filteredElements = mapData.filter(elementFilter) + val filteredElements = mapData.filter(filter) // map of localized names -> min distance val result = mutableMapOf, Double>() - for (elem in filteredElements) { - val geometry = mapData.getGeometry(elem.type, elem.id) ?: continue + for (element in filteredElements) { + val geometry = mapData.getGeometry(element.type, element.id) ?: continue val minDistance = points.minOf { geometry.distance(it) } if (minDistance > maxDistance) continue - val names = parseLocalizedNames(elem.tags) ?: continue + val names = parseLocalizedNames(element.tags) ?: continue // eliminate duplicates (e.g. same road, different segments, different distances) val prev = result[names] diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt index 079a0d34f27..970947bc8c1 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt @@ -10,6 +10,7 @@ import de.westnordost.streetcomplete.osm.applyTo class AddBusStopName : OsmFilterQuestType() { + // this filter needs to be kept somewhat in sync with the filter in AddBusStopNameForm override val elementFilter = """ nodes, ways, relations with ( diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt index 5719ab6f6fe..41396e72178 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt @@ -2,6 +2,7 @@ package de.westnordost.streetcomplete.quests.bus_stop_name import androidx.appcompat.app.AlertDialog import de.westnordost.streetcomplete.R +import de.westnordost.streetcomplete.data.elementfilter.toElementFilterExpression import de.westnordost.streetcomplete.databinding.QuestLocalizednameBinding import de.westnordost.streetcomplete.osm.LocalizedName import de.westnordost.streetcomplete.quests.AAddLocalizedNameForm @@ -24,8 +25,9 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { AnswerItem(R.string.quest_streetName_answer_cantType) { showKeyboardInfo() } ) + // this filter needs to be kept somewhat in sync with the filter in AddBusStopName private val busStopsWithNamesFilter = """ - nodes, ways with + nodes, ways, relations with ( public_transport = platform and bus = yes or (highway = bus_stop and public_transport != stop_position) @@ -34,13 +36,14 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { or railway = tram_stop ) and name - """ + """.toElementFilterExpression() override fun getLocalizedNameSuggestions(): List> = nameSuggestionsSource.getNames( - listOf(geometry.center), - MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION, - busStopsWithNamesFilter + // bus stops are usually not that large, we can just take the center for the dist check + points = listOf(geometry.center), + maxDistance = 250.0, + filter = busStopsWithNamesFilter ) override fun onClickOk(names: List) { @@ -54,8 +57,4 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { .setNegativeButton(R.string.quest_generic_confirmation_no, null) .show() } - - companion object { - const val MAX_DIST_FOR_BUS_STOP_NAME_SUGGESTION = 250.0 // m - } } diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt index 48f19ef8967..f9e32301943 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/road_name/AddRoadNameForm.kt @@ -3,6 +3,7 @@ package de.westnordost.streetcomplete.quests.road_name import android.content.DialogInterface import androidx.appcompat.app.AlertDialog import de.westnordost.streetcomplete.R +import de.westnordost.streetcomplete.data.elementfilter.toElementFilterExpression import de.westnordost.streetcomplete.data.meta.AbbreviationsByLocale import de.westnordost.streetcomplete.data.osm.geometry.ElementPointGeometry import de.westnordost.streetcomplete.data.osm.geometry.ElementPolygonsGeometry @@ -37,19 +38,26 @@ class AddRoadNameForm : AAddLocalizedNameForm() { private val abbrByLocale: AbbreviationsByLocale by inject() private val nameSuggestionsSource: NameSuggestionsSource by inject() + private val roadsWithNamesFilter = + "ways with highway ~ ${(ALL_ROADS + ALL_PATHS).joinToString("|")} and name" + .toElementFilterExpression() + override fun getAbbreviationsByLocale(): AbbreviationsByLocale = abbrByLocale override fun getLocalizedNameSuggestions(): List> { - val polyline = when (val geom = geometry) { + val firstAndLast = when (val geom = geometry) { is ElementPolylinesGeometry -> geom.polylines.first() is ElementPolygonsGeometry -> geom.polygons.first() is ElementPointGeometry -> listOf(geom.center) - } + }.let { listOf(it.first(), it.last()) } return nameSuggestionsSource.getNames( - listOf(polyline.first(), polyline.last()), - MAX_DIST_FOR_ROAD_NAME_SUGGESTION, - elementFilter + // only first and last point of polyline because a still unnamed section of road is + // usually (if at all) a continuation of a neighbouring road section + points = firstAndLast, + // and hence we can also search only in a very small area only + maxDistance = 30.0, + filter = roadsWithNamesFilter ) } @@ -139,14 +147,4 @@ class AddRoadNameForm : AAddLocalizedNameForm() { .setNegativeButton(R.string.quest_generic_confirmation_no, null) .show() } - - companion object { - const val MAX_DIST_FOR_ROAD_NAME_SUGGESTION = 30.0 // m - - val elementFilter = """ - ways with - highway ~ ${(ALL_ROADS + ALL_PATHS).joinToString("|")} - and name - """ - } } From 2db05c98e54def23bbea4a0fd529f70d7dc1986f Mon Sep 17 00:00:00 2001 From: Tobias Zwick Date: Wed, 22 Jan 2025 14:23:01 +0100 Subject: [PATCH 15/15] shorten expression --- .../streetcomplete/quests/bus_stop_name/AddBusStopName.kt | 6 ++---- .../quests/bus_stop_name/AddBusStopNameForm.kt | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt index 970947bc8c1..6487664a46f 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopName.kt @@ -15,10 +15,8 @@ class AddBusStopName : OsmFilterQuestType() { nodes, ways, relations with ( public_transport = platform and bus = yes - or (highway = bus_stop and public_transport != stop_position) - or railway = halt - or railway = station - or railway = tram_stop + or highway = bus_stop and public_transport != stop_position + or railway ~ halt|station|tram_stop ) and !name and noname != yes and name:signed != no """ diff --git a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt index 41396e72178..1bceeb5377b 100644 --- a/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt +++ b/app/src/main/java/de/westnordost/streetcomplete/quests/bus_stop_name/AddBusStopNameForm.kt @@ -30,10 +30,8 @@ class AddBusStopNameForm : AAddLocalizedNameForm() { nodes, ways, relations with ( public_transport = platform and bus = yes - or (highway = bus_stop and public_transport != stop_position) - or railway = halt - or railway = station - or railway = tram_stop + or highway = bus_stop and public_transport != stop_position + or railway ~ halt|station|tram_stop ) and name """.toElementFilterExpression()