diff --git a/CHANGELOG.md b/CHANGELOG.md index e0a710101da..6e618c2e997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased - Changes from 6.0.0 + - Profiles: + - ADDED: Use `is_sidepath:of:name` and `street:name` as fallback names for unnamed sidewalks and sidepaths in foot and bicycle profiles [#7259](https://github.com/Project-OSRM/osrm-backend/issues/7259) - Build: - FIXED: Reduce MSVC compiler warnings by suppressing informational warnings while preserving bug-indicating warnings [#7253](https://github.com/Project-OSRM/osrm-backend/issues/7253) - Misc: diff --git a/docs/profiles.md b/docs/profiles.md index 54c4b13348e..2ec6d8f12d2 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -71,7 +71,7 @@ If you want to prioritize certain streets, increase the rate on these. A profile should set `api_version` at the top of your profile. This is done to ensure that older profiles are still supported when the api changes. If `api_version` is not defined, 0 will be assumed. The current api version is 4. ### Library files -The folder [profiles/lib/](../profiles/lib/) contains LUA library files for handling many common processing tasks. +The folder [profiles/lib/](../profiles/lib/) contains Lua library files for handling many common processing tasks. File | Notes ------------------|------------------------------ @@ -89,7 +89,7 @@ They all return a table of functions when you use `require` to load them. You ca ### setup() The `setup` function is called once when the profile is loaded and must return a table of configurations. It's also where you can do other global setup, like loading data sources that are used during processing. -Note that processing of data is parallelized and several unconnected LUA interpreters will be running at the same time. The `setup` function will be called once for each. Each LUA interpreter will have its own set of globals. +Note that processing of data is parallelized and several unconnected Lua interpreters will be running at the same time. The `setup` function will be called once for each. Each Lua interpreter will have its own set of globals. The following global properties can be set under `properties` in the hash you return in the `setup` function: @@ -347,10 +347,34 @@ road_classification.road_priority_class | Enum | Guidance: order in priority road_classification.may_be_ignored | Boolean | Guidance: way is non-highway road_classification.num_lanes | Unsigned | Guidance: total number of lanes in way +### Way names +The `WayHandlers.names` function in [way_handlers.lua](../profiles/lib/way_handlers.lua) handles extraction of way names for routing instructions. It processes the following OSM tags: + +Tag | Notes +----------------------|------------------------------ +`name` | Primary name of the way +`name:pronunciation` | Pronunciation hint for text-to-speech +`ref` | Road reference number (e.g., "A1", "I-95") +`junction:ref` | Exit or junction reference number + +For unnamed sidewalks and sidepaths (where `highway=footway`, `highway=cycleway`, or `highway=path`), the function also supports fallback name tags when the way is marked as a sidepath: + +Tag | Notes +----------------------|------------------------------ +`is_sidepath:of:name` | Name of the street the sidepath follows (checked first) +`street:name` | Alternative tag for the associated street name + +The fallback is only applied when the way has one of these sidepath markers: +- `footway=sidewalk` +- `cycleway=sidepath` +- `is_sidepath=yes` + +This allows routing instructions to show street names for separately mapped sidewalks, e.g., "Turn right onto Main Street" instead of just "Turn right". + ### process_segment(profile, segment) The `process_segment` function is called for every segment of OSM ways. A segment is a straight line between two OSM nodes. -On OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However many ways are long. For example, many ways pass hills without any change in tags. +An OpenStreetMap way cannot have different tags on different parts of a way. Instead you would split the way into several smaller ways. However, many ways are long. For example, many ways pass over hills without any change in tags. Processing each segment of an OSM way makes it possible to have different speeds on different parts of a way based on external data like data about elevation, pollution, noise or scenic value and adjust weight and duration of the segment accordingly. @@ -453,10 +477,10 @@ When turning from `a` to `b` via `x`, * `roads_on_the_left[1]` is the road `xe` * `roads_on_the_left[2]` is the road `xc` -Note that indices of arrays in lua are 1-based. +Note that indices of arrays in Lua are 1-based. #### `highway_turn_classification` and `access_turn_classification` -When setting appropriate turn weights and duration, information about the highway and access tags of roads that are involved in the turn are necessary. The lua turn function `process_turn` does not have access to the original osrm tags anymore. However, `highway_turn_classification` and `access_turn_classification` can be set during setup. The classification set during setup can be later used in `process_turn`. +When setting appropriate turn weights and duration, information about the highway and access tags of roads that are involved in the turn are necessary. The Lua turn function `process_turn` does not have access to the original OSM tags anymore. However, `highway_turn_classification` and `access_turn_classification` can be set during setup. The classification set during setup can be later used in `process_turn`. **Example** @@ -513,7 +537,7 @@ function setup() end ``` -The input data must an ASCII file with rows of integers. e.g.: +The input data must be an ASCII file with rows of integers, e.g.: ``` 0 0 0 0 diff --git a/features/bicycle/sidepath_names.feature b/features/bicycle/sidepath_names.feature new file mode 100644 index 00000000000..57ab93bf9a1 --- /dev/null +++ b/features/bicycle/sidepath_names.feature @@ -0,0 +1,77 @@ +@routing @bicycle @sidepath +Feature: Bicycle - Sidepath street names + + Background: + Given the profile "bicycle" + Given a grid size of 200 meters + + Scenario: Bicycle - Use is_sidepath:of:name for cycleway sidepath + Given the node map + """ + a b c + """ + + And the ways + | nodes | highway | cycleway | name | is_sidepath:of:name | + | ab | cycleway | sidepath | | Highway 1 | + | bc | cycleway | sidepath | | Highway 2 | + + When I route I should get + | from | to | route | + | a | c | Highway 1,Highway 2,Highway 2 | + + Scenario: Bicycle - Use street:name for cycleway sidepath + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | cycleway | name | street:name | + | ab | cycleway | sidepath | | Bike Lane | + + When I route I should get + | from | to | route | + | a | b | Bike Lane,Bike Lane | + + Scenario: Bicycle - Explicit name takes priority + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | cycleway | name | is_sidepath:of:name | + | ab | cycleway | sidepath | Named Path | Fallback | + + When I route I should get + | from | to | route | + | a | b | Named Path,Named Path | + + Scenario: Bicycle - Use is_sidepath=yes with is_sidepath:of:name + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | is_sidepath | name | is_sidepath:of:name | + | ab | path | yes | | Cycle Route | + + When I route I should get + | from | to | route | + | a | b | Cycle Route,Cycle Route | + + Scenario: Bicycle - No fallback without sidepath marker + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | name | street:name | + | ab | cycleway | | Should Not Show | + + When I route I should get + | from | to | route | + | a | b | , | diff --git a/features/car/sidepath_names.feature b/features/car/sidepath_names.feature new file mode 100644 index 00000000000..59b5ca8baeb --- /dev/null +++ b/features/car/sidepath_names.feature @@ -0,0 +1,48 @@ +@routing @car @sidepath +Feature: Car - Sidepath names should not affect car routing + + Background: + Given the profile "car" + Given a grid size of 200 meters + + Scenario: Car - Does not use sidepath name fallback on roads + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | name | street:name | + | ab | primary | | Should Not Show | + + When I route I should get + | from | to | route | + | a | b | , | + + Scenario: Car - Does not pick up is_sidepath:of:name on roads + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | name | is_sidepath:of:name | + | ab | primary | | Should Not Show | + + When I route I should get + | from | to | route | + | a | b | , | + + Scenario: Car - Sidepath markers do not affect car roads + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | footway | name | is_sidepath:of:name | + | ab | primary | sidewalk | | Should Not Show | + + When I route I should get + | from | to | route | + | a | b | , | diff --git a/features/foot/sidepath_names.feature b/features/foot/sidepath_names.feature new file mode 100644 index 00000000000..e2e774c3e99 --- /dev/null +++ b/features/foot/sidepath_names.feature @@ -0,0 +1,92 @@ +@routing @foot @sidepath +Feature: Foot - Sidepath street names + + Background: + Given the profile "foot" + Given a grid size of 200 meters + + Scenario: Foot - Use is_sidepath:of:name for unnamed sidewalk + Given the node map + """ + a b c + """ + + And the ways + | nodes | highway | footway | name | is_sidepath:of:name | + | ab | footway | sidewalk | | Main Street | + | bc | footway | sidewalk | | Oak Avenue | + + When I route I should get + | from | to | route | + | a | c | Main Street,Oak Avenue,Oak Avenue | + + Scenario: Foot - Use street:name for unnamed sidewalk + Given the node map + """ + a b c + """ + + And the ways + | nodes | highway | footway | name | street:name | + | ab | footway | sidewalk | | Elm Street | + | bc | footway | sidewalk | | Pine Road | + + When I route I should get + | from | to | route | + | a | c | Elm Street,Pine Road,Pine Road | + + Scenario: Foot - is_sidepath:of:name takes priority over street:name + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | footway | name | is_sidepath:of:name | street:name | + | ab | footway | sidewalk | | Primary Name | Secondary | + + When I route I should get + | from | to | route | + | a | b | Primary Name,Primary Name | + + Scenario: Foot - Explicit name tag takes priority over fallback + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | footway | name | is_sidepath:of:name | + | ab | footway | sidewalk | Explicit Name | Fallback Name | + + When I route I should get + | from | to | route | + | a | b | Explicit Name,Explicit Name | + + Scenario: Foot - Use is_sidepath=yes with street:name + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | is_sidepath | name | street:name | + | ab | path | yes | | River Path | + + When I route I should get + | from | to | route | + | a | b | River Path,River Path | + + Scenario: Foot - No fallback without sidepath marker + Given the node map + """ + a b + """ + + And the ways + | nodes | highway | name | street:name | + | ab | footway | | Should Not Show | + + When I route I should get + | from | to | route | + | a | b | , | diff --git a/profiles/lib/way_handlers.lua b/profiles/lib/way_handlers.lua index b1341023509..37c2c2f65a4 100644 --- a/profiles/lib/way_handlers.lua +++ b/profiles/lib/way_handlers.lua @@ -39,6 +39,23 @@ function WayHandlers.names(profile,way,result,data) -- Set the name that will be used for instructions if name then result.name = name + else + -- Fallback for unnamed sidewalks and sidepaths + -- Use is_sidepath:of:name or street:name when way is marked as a sidepath + local sidepath_name = way:get_value_by_key("is_sidepath:of:name") or + way:get_value_by_key("street:name") + if sidepath_name then + local highway = way:get_value_by_key("highway") + local footway = way:get_value_by_key("footway") + local cycleway = way:get_value_by_key("cycleway") + local is_sidepath = way:get_value_by_key("is_sidepath") + -- Only apply to footway/cycleway/path highway types + if highway == "footway" or highway == "cycleway" or highway == "path" then + if footway == "sidewalk" or cycleway == "sidepath" or is_sidepath == "yes" then + result.name = sidepath_name + end + end + end end if ref then