Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "None, but a sign allows cycling on sidewalk" as an option for cycleway overlay/quest #5575

Merged
merged 29 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
cc02017
Transfer progress from SCEE
wielandb Apr 6, 2024
c4f5900
Add and remove signed-tag
wielandb Apr 7, 2024
67e2f9f
Change more tags when changing choices
wielandb Apr 9, 2024
c4a7d46
Merge branch 'master' into sidewalk-bicycle-yes
wielandb May 1, 2024
90b7ec0
Add tests and functionality
wielandb May 2, 2024
16ba5c9
Remove comment that's no longer accurate
wielandb May 2, 2024
4e64b67
Put NONE back on the top
wielandb May 2, 2024
34ca816
Add SVGs of new icons
wielandb May 2, 2024
d4eda97
Remove a no longer needed string
wielandb May 2, 2024
536b82a
make "NOT_ALLOWED" explicitly signed and make it selectable
wielandb May 4, 2024
127db15
Expand more tags
wielandb May 4, 2024
a3dd92d
Only remove sidewalk:-tags if :signed is yes
wielandb May 4, 2024
a9d30d3
Require signed to be yes to be parsed as SIDEWALK_OK
wielandb May 4, 2024
bb676e0
Remove bicycle:signed when switching to NOT_DESIGNATED
wielandb May 4, 2024
3074b38
handle sidewalk:<side>:(foot/bicycle)=designated
wielandb May 4, 2024
4dec7c5
Revert handling `sidewalk:<side>:(bicycle/foot)`
wielandb May 4, 2024
a1ca1a8
Remove a no longer needed string
wielandb May 4, 2024
95405ce
Simplify list of available seperate cycleway options
wielandb May 4, 2024
26c2ffc
use variable
westnordost May 12, 2024
d8d2317
remove unused variable
westnordost May 12, 2024
793358c
remove unnecessary statement
westnordost May 12, 2024
ccbf16c
Reset SeparateCyclewayCreatorKtTest.kt
wielandb May 15, 2024
d7321d7
Add 4 new tests to SeparateCyclewayCreatorKtTest.kt
wielandb May 15, 2024
aa6dbee
Make one Test no longer fail
wielandb May 30, 2024
43560e8
Add some tests to CyclewayParserKtTest
wielandb May 30, 2024
e9b7df5
Add tests for sidewalk:<side>:bicycle=designated
wielandb May 30, 2024
2b563c2
Update strings.xml
wielandb May 31, 2024
02d1943
Remove designated from the last three options
wielandb Jun 1, 2024
dc98717
Refactor isCyclingOkOnSideWalk and isCyclingDesignatedOnSidewalk parsing
wielandb Jun 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,8 @@ enum class Cycleway {
/** cyclists explicitly ought to share the sidewalk with pedestrians, i.e. the cycle track is
* not segregated from the sidewalk */
SIDEWALK_EXPLICIT,
// the following not anymore, see #2276
// no cycleway, but cyclists are allowed on sidewalk
// SIDEWALK_OK,
SIDEWALK_OK,

/** no cycle track or lane */
NONE,
Expand Down Expand Up @@ -190,6 +189,7 @@ fun getSelectableCycleways(
PICTOGRAMS,
BUSWAY,
SIDEWALK_EXPLICIT,
SIDEWALK_OK,
SHOULDER
)
val dualCycleways = listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ fun LeftAndRightCycleway.applyTo(tags: Tags, isLeftHandTraffic: Boolean) {
tags.expandSides("cycleway", "lane", false)
tags.expandSides("cycleway", "oneway", false)
tags.expandSides("cycleway", "segregated", false)
tags.expandSides("sidewalk", "bicycle", false)
tags.expandSides("sidewalk", "bicycle:signed", false)

applyOnewayNotForCyclists(tags)
left?.applyTo(tags, false, isLeftHandTraffic)
Expand All @@ -39,6 +41,8 @@ fun LeftAndRightCycleway.applyTo(tags: Tags, isLeftHandTraffic: Boolean) {
tags.mergeSides("cycleway", "lane")
tags.mergeSides("cycleway", "oneway")
tags.mergeSides("cycleway", "segregated")
tags.mergeSides("sidewalk", "bicycle")
tags.mergeSides("sidewalk", "bicycle:signed")

// update check date
if (!tags.hasChanges || tags.hasCheckDateForKey("cycleway")) {
Expand Down Expand Up @@ -104,6 +108,7 @@ private fun LeftAndRightCycleway.applyOnewayNotForCyclists(tags: Tags) {
private fun CyclewayAndDirection.applyTo(tags: Tags, isRight: Boolean, isLeftHandTraffic: Boolean) {
val side = if (isRight) "right" else "left"
val cyclewayKey = "cycleway:$side"

when (cycleway) {
NONE, NONE_NO_ONEWAY -> {
tags[cyclewayKey] = "no"
Expand Down Expand Up @@ -131,6 +136,7 @@ private fun CyclewayAndDirection.applyTo(tags: Tags, isRight: Boolean, isLeftHan
// https://wiki.openstreetmap.org/wiki/File:Z240GemeinsamerGehundRadweg.jpeg
tags[cyclewayKey] = "track"
tags["$cyclewayKey:segregated"] = "no"

}
PICTOGRAMS -> {
tags[cyclewayKey] = "shared_lane"
Expand All @@ -153,6 +159,11 @@ private fun CyclewayAndDirection.applyTo(tags: Tags, isRight: Boolean, isLeftHan
SEPARATE -> {
tags[cyclewayKey] = "separate"
}
SIDEWALK_OK -> {
tags[cyclewayKey] = "no"
tags["sidewalk:$side:bicycle"] = "yes"
tags["sidewalk:$side:bicycle:signed"] = "yes"
}
else -> {
throw IllegalArgumentException("Invalid cycleway")
}
Expand Down Expand Up @@ -185,6 +196,11 @@ private fun CyclewayAndDirection.applyTo(tags: Tags, isRight: Boolean, isLeftHan
if (!touchedSegregatedValue) {
tags.remove("$cyclewayKey:segregated")
}
// no matter what option was chosen, if it's not SIDEWAY_OK, remove that cycling is signed and ok on sidewalk if it's there
if (cycleway != SIDEWALK_OK && tags.containsKey("sidewalk:$side:bicycle") && tags["sidewalk:$side:bicycle"] == "yes" && tags.containsKey("sidewalk:$side:bicycle:signed")) {
wielandb marked this conversation as resolved.
Show resolved Hide resolved
tags.remove("sidewalk:$side:bicycle")
tags.remove("sidewalk:$side:bicycle:signed")
}
}

private val Direction.onewayValue get() = when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ private fun Cycleway.getRightHandTrafficIconResId(countryInfo: CountryInfo): Int
NONE_NO_ONEWAY -> R.drawable.ic_cycleway_none_no_oneway
PICTOGRAMS -> countryInfo.pictogramCycleLaneResId
SIDEWALK_EXPLICIT -> R.drawable.ic_cycleway_sidewalk_explicit
SIDEWALK_OK -> R.drawable.ic_cycleway_sidewalk_ok
BUSWAY -> R.drawable.ic_cycleway_bus_lane
SEPARATE -> R.drawable.ic_cycleway_none
SHOULDER -> R.drawable.ic_cycleway_shoulder
Expand All @@ -139,6 +140,7 @@ private fun Cycleway.getLeftHandTrafficIconResId(countryInfo: CountryInfo): Int
NONE_NO_ONEWAY -> R.drawable.ic_cycleway_none_no_oneway_l
PICTOGRAMS -> countryInfo.pictogramCycleLaneMirroredResId
SIDEWALK_EXPLICIT -> R.drawable.ic_cycleway_sidewalk_explicit_l
SIDEWALK_OK -> R.drawable.ic_cycleway_sidewalk_ok_l
BUSWAY -> R.drawable.ic_cycleway_bus_lane_l
SEPARATE -> R.drawable.ic_cycleway_none
SHOULDER -> R.drawable.ic_cycleway_shoulder
Expand Down Expand Up @@ -181,5 +183,6 @@ private fun CyclewayAndDirection.getTitleResId(isContraflowInOneway: Boolean): I
BUSWAY -> R.string.quest_cycleway_value_bus_lane
SEPARATE -> R.string.quest_cycleway_value_separate
SHOULDER -> R.string.quest_cycleway_value_shoulder
SIDEWALK_OK -> R.string.quest_cycleway_value_sidewalk_ok
else -> 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ private fun parseCyclewayForSide(
val cycleway = tags[cyclewayKey]
val cyclewayLane = tags["$cyclewayKey:lane"]
val isSegregated = tags["$cyclewayKey:segregated"] != "no"
val isCyclingOkOnSidewalk = tags["sidewalk$sideVal:bicycle"] == "yes" || tags["sidewalk:both:bicycle"] == "yes"
westnordost marked this conversation as resolved.
Show resolved Hide resolved
wielandb marked this conversation as resolved.
Show resolved Hide resolved
wielandb marked this conversation as resolved.
Show resolved Hide resolved

val result = when (cycleway) {
"lane", "opposite_lane" -> {
Expand Down Expand Up @@ -122,7 +123,11 @@ private fun parseCyclewayForSide(
if (isSegregated) TRACK else SIDEWALK_EXPLICIT
}
"separate" -> SEPARATE
"no", "opposite" -> NONE
"opposite" -> NONE
"no" -> when (isCyclingOkOnSidewalk) {
true -> SIDEWALK_OK
false -> NONE
}
"share_busway", "opposite_share_busway" -> BUSWAY
"shoulder" -> SHOULDER
// values known to be invalid, ambiguous or obsolete:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ fun SeparateCycleway.applyTo(tags: Tags) {
if (tags.containsKey("bicycle") && tags["bicycle"] !in yesButNotDesignated) {
tags["bicycle"] = "yes"
}
if (tags.containsKey("bicycle:signed")) {
tags.remove("bicycle:signed")
}
}
NOT_ALLOWED -> {
if (tags["bicycle"] !in noCycling) tags["bicycle"] = "no"
Expand All @@ -40,6 +43,8 @@ fun SeparateCycleway.applyTo(tags: Tags) {

if (this == ALLOWED_ON_FOOTWAY) {
if (tags["bicycle"] !in yesButNotDesignated) tags["bicycle"] = "yes"
// add bicycle:signed=yes if not already present
tags["bicycle:signed"] = "yes"
} else {
if (tags["bicycle"] == "designated") tags.remove("bicycle")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fun SeparateCycleway.asItem(isLeftHandTraffic: Boolean) =
private val SeparateCycleway.titleResId: Int get() = when (this) {
PATH -> R.string.separate_cycleway_path
NOT_ALLOWED -> R.string.separate_cycleway_no
ALLOWED_ON_FOOTWAY -> R.string.separate_cycleway_allowed
ALLOWED_ON_FOOTWAY -> R.string.separate_cycleway_footway_allowed_sign
NON_DESIGNATED_ON_FOOTWAY -> R.string.separate_cycleway_no_or_allowed
NON_SEGREGATED -> R.string.separate_cycleway_non_segregated
SEGREGATED -> R.string.separate_cycleway_segregated
Expand All @@ -20,7 +20,7 @@ private val SeparateCycleway.titleResId: Int get() = when (this) {

private fun SeparateCycleway.getIconResId(isLeftHandTraffic: Boolean): Int = when (this) {
PATH -> R.drawable.ic_separate_cycleway_path
NOT_ALLOWED -> R.drawable.ic_separate_cycleway_no
NOT_ALLOWED -> R.drawable.ic_separate_cycleway_disallowed
westnordost marked this conversation as resolved.
Show resolved Hide resolved
ALLOWED_ON_FOOTWAY -> R.drawable.ic_separate_cycleway_allowed
NON_DESIGNATED_ON_FOOTWAY -> R.drawable.ic_separate_cycleway_no
NON_SEGREGATED -> R.drawable.ic_separate_cycleway_not_segregated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ fun parseSeparateCycleway(tags: Map<String, String>): SeparateCycleway? {
else -> null // only happens if highway=footway
}

val bicycleSigned = tags["bicycle:signed"] == "yes"

// footway implies foot=designated, path implies foot=yes
val foot = tags["foot"] ?: when (tags["highway"]) {
"footway" -> "designated"
Expand All @@ -37,12 +39,14 @@ fun parseSeparateCycleway(tags: Map<String, String>): SeparateCycleway? {

if (bicycle in noCycling) return NOT_ALLOWED

if (bicycle in yesButNotDesignated && foot == "designated") return ALLOWED_ON_FOOTWAY
if (bicycle in yesButNotDesignated && bicycleSigned && foot == "designated") return ALLOWED_ON_FOOTWAY

if (bicycle in yesButNotDesignated && foot != "designated") return PATH

if (bicycle != "designated") return NON_DESIGNATED_ON_FOOTWAY
// highway=path and foot=no should be treated as PATH
if (tags["highway"] == "path" && foot == "no") return PATH
wielandb marked this conversation as resolved.
Show resolved Hide resolved

if (bicycle != "designated") return NON_DESIGNATED_ON_FOOTWAY
val hasSidewalk = parseSidewalkSides(tags)?.any { it == Sidewalk.YES } == true || tags["sidewalk"] == "yes"
if (hasSidewalk) return EXCLUSIVE_WITH_SIDEWALK

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,19 @@ private fun getSeparateCyclewayStyle(element: Element) =

private fun SeparateCycleway?.getColor() = when (this) {
SeparateCycleway.NOT_ALLOWED,
SeparateCycleway.ALLOWED_ON_FOOTWAY,
SeparateCycleway.NON_DESIGNATED_ON_FOOTWAY,
SeparateCycleway.PATH ->
Color.BLACK

SeparateCycleway.NON_SEGREGATED ->
Color.CYAN

SeparateCycleway.SEGREGATED,
SeparateCycleway.EXCLUSIVE,
SeparateCycleway.EXCLUSIVE_WITH_SIDEWALK ->
Color.BLUE
SeparateCycleway.ALLOWED_ON_FOOTWAY ->
Color.AQUAMARINE

null ->
Color.INVISIBLE
Expand Down Expand Up @@ -151,7 +152,7 @@ private fun Cycleway?.getStyle(countryInfo: CountryInfo) = when (this) {
StrokeStyle(Color.LIME, dashed = true)

SIDEWALK_EXPLICIT ->
StrokeStyle(Color.CYAN, dashed = true)
StrokeStyle(Color.CYAN, dashed = false)

NONE ->
StrokeStyle(Color.BLACK)
Expand All @@ -161,4 +162,6 @@ private fun Cycleway?.getStyle(countryInfo: CountryInfo) = when (this) {

SEPARATE ->
StrokeStyle(Color.INVISIBLE)
SIDEWALK_OK ->
StrokeStyle(Color.CYAN, dashed = true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import org.koin.android.ext.android.inject
class SeparateCyclewayForm : AImageSelectOverlayForm<SeparateCycleway>() {

override val items: List<DisplayItem<SeparateCycleway>> get() =
listOf(PATH, NON_DESIGNATED_ON_FOOTWAY, NON_SEGREGATED, SEGREGATED, EXCLUSIVE_WITH_SIDEWALK, EXCLUSIVE).map {
listOf(PATH, NON_DESIGNATED_ON_FOOTWAY, ALLOWED_ON_FOOTWAY, NON_SEGREGATED, SEGREGATED, EXCLUSIVE_WITH_SIDEWALK, EXCLUSIVE).map {
it.asItem(countryInfo.isLeftHandTraffic)
}

Expand Down Expand Up @@ -75,7 +75,7 @@ class SeparateCyclewayForm : AImageSelectOverlayForm<SeparateCycleway>() {
prerequisite for it being displayed as a selectable option due to the reasons stated
above.
*/
currentCycleway = if (cycleway == NOT_ALLOWED || cycleway == ALLOWED_ON_FOOTWAY) NON_DESIGNATED_ON_FOOTWAY else cycleway
currentCycleway = if (cycleway == NOT_ALLOWED) NON_DESIGNATED_ON_FOOTWAY else cycleway
selectedItem = currentCycleway?.asItem(countryInfo.isLeftHandTraffic)
}

Expand Down
53 changes: 53 additions & 0 deletions app/src/main/res/drawable/ic_cycleway_sidewalk_ok.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
wielandb marked this conversation as resolved.
Show resolved Hide resolved
android:width="256dp"
android:height="256dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M128,0.01l72,0l0,256l-72,0z"
android:fillColor="#aaa"/>
<path
android:pathData="m192,231.99l8,0m-8,-24l8,0m-8,-24l8,0m0,-24l-8,0m0,-24l8,0m-8,-24l8,0m-8,-24l8,0m-8,-24l8,0m-8,-24l8,0m-8,-24l8,0m-72,216l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-48l16,0m-16,-24l16,0m-16,-48l16,0m-16,24l16,0m-16,72l16,0m16,120l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-48l16,0m-16,-24l16,0m-16,-48l16,0m-16,24l16,0m-16,72l16,0m-32,132l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-48l16,0m-16,-24l16,0m-16,-48l16,0m-16,24l16,0m-16,72l16,0m32,156l0,-256m-16,0l0,256m-16,0l0,-256m-16,0l0,256m32,-228.58l16,0m-16,24l16,0m-16,192l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-24l16,0m-16,-72l16,0"
android:strokeWidth="4"
android:fillColor="#00000000"
android:strokeColor="#999"/>
<path
android:pathData="M120,0.01l8,0l0,256l-8,0z"
android:fillColor="#999"/>
<path
android:pathData="M200,0.01l8,0l0,256l-8,0z"
android:fillColor="#999"/>
<path
android:pathData="M112,0.01l8,0l0,256l-8,0z"
android:fillColor="#666"/>
<path
android:pathData="m168.11,92.45c-2.87,0 -5.19,2.32 -5.19,5.19 0,2.87 2.33,5.19 5.19,5.19 2.87,0 5.19,-2.32 5.19,-5.19 0,-2.87 -2.32,-5.19 -5.19,-5.19zM162.68,104.72c-5.25,1.96 -9.3,5.3 -9.35,10.86 0,1.42 1.15,2.57 2.57,2.57 1.42,0 2.57,-1.15 2.57,-2.57 0.04,-1.42 0.64,-2.62 1.52,-3.59 0.03,1.26 0.23,2.68 0.66,4.26 -0.27,0.45 -0.38,1.12 -0.27,2.1 -0.91,5.23 -6.67,8.63 -10.39,10.32 -1.3,0.58 -1.89,2.1 -1.31,3.4 0.58,1.3 2.1,1.89 3.4,1.31 4.93,-2.57 11.2,-6.71 13,-12.15 4.1,1.91 7.93,6.2 8.62,10.16 0.2,1.41 1.51,2.38 2.91,2.18 1.41,-0.2 2.39,-1.5 2.18,-2.91 -1.07,-6.35 -5.45,-11.05 -10.93,-13.81 -1.58,-0.68 -1.71,-4.38 -1.62,-5.71 4.8,2.73 9.72,3.94 14.59,1.55 1.27,-0.64 1.79,-2.18 1.15,-3.45 -0.64,-1.27 -2.18,-1.79 -3.45,-1.15 -5.72,2.83 -9.29,-1.5 -12.3,-3.26 -1.08,-0.75 -2.51,-0.76 -3.58,-0.1z"
android:strokeWidth="3.78"
android:fillColor="#ffffff"
android:strokeColor="#00000000"/>
<path
android:pathData="m153.73,140.93l22.41,0a4.8,4.8 0,0 1,4.8 4.79l0,20.41a4.8,4.8 0,0 1,-4.8 4.79l-22.41,0a4.8,4.8 0,0 1,-4.8 -4.79l0,-20.41a4.8,4.8 0,0 1,4.8 -4.79z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#ffffff"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
<path
android:pathData="m162.06,155.14a4.64,4.66 90,0 1,-4.66 4.64,4.64 4.66,90 0,1 -4.66,-4.64 4.64,4.66 90,0 1,4.66 -4.64,4.64 4.66,90 0,1 4.66,4.64zM177.24,155.14a4.64,4.66 90,0 1,-4.66 4.64,4.64 4.66,90 0,1 -4.66,-4.64 4.64,4.66 90,0 1,4.66 -4.64,4.64 4.66,90 0,1 4.66,4.64zM159.99,147.99 L165.88,155.11l6.73,0L167.99,147.99L160,147.99m5.89,7.12 l2.11,-8.8m0,0 l2.05,-0.01m-12.57,8.8 l3.51,-10.39l3.36,0"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
<path
android:pathData="m164.94,164.93c0,1.5 -0.99,3 -3,3 -2.01,0 -3.03,-1.47 -3,-3 0.03,-1.52 0.95,-3 3,-3 2.05,0 3,1.5 3,3zM163.44,164.93c0,-0.73 -0.5,-1.5 -1.5,-1.5 -1.01,0 -1.5,0.74 -1.5,1.5 0,0.76 0.5,1.5 1.5,1.5 1,0 1.5,-0.77 1.5,-1.5z"
android:strokeWidth="0.5"
android:fillColor="#000000"/>
<path
android:pathData="m171.43,167.94l-1.64,0l-1.85,-2.5 -0.5,0.5l0,2l-1.5,0l0,-6l1.5,0l0,2.5l2.5,-2.5l1.65,0l-2.65,2.6z"
android:strokeWidth="0.5"
android:fillColor="#000000"/>
<path
android:pathData="M0,0h112v256h-112z"
android:fillColor="#808080"/>
</vector>