From 0091432163346d3f3f76c8fac0c5144e31bb0c0d Mon Sep 17 00:00:00 2001 From: Henrik Wolf Date: Wed, 9 Nov 2022 16:52:01 +0100 Subject: [PATCH 1/5] added parsing of "lanes:forward", "lanes:backward"and "lanes:both_ways" --- src/constants.jl | 27 +++++++++++++++++++++++---- src/parse.jl | 46 +++++++++++++++++++++++++++++++++++++++------- test/stub.jl | 8 ++++---- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/constants.jl b/src/constants.jl index 32da03e..d0d8f20 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -167,6 +167,14 @@ const DEFAULT_LANES = Ref(Dict{String,DEFAULT_OSM_LANES_TYPE}( "other" => 1 )) +""" +Default number of lanes:both_ways based in highway type. +""" +const DEFAULT_LANES_BOTH_WAYS = Ref(Dict{String,DEFAULT_OSM_LANES_TYPE}( + "other" => 0 +)) + + """ Default oneway attribute based on highway type. """ @@ -225,8 +233,8 @@ optional. # Keyword Arguments - `maxspeeds::AbstractDict{String,<:Real}`: If no `maxspeed` way tag is available, these - values are used instead based on the value of the `highway` way tag. If no - `highway` way tag is available, the value for `"other"` is used. Unit is km/h. + values are used instead based on the value of the `highway` way tag. If the value of the + `highway` tag is not a key of the dictionary, the value for `"other"` is used. Unit is km/h. Default value: ``` Dict( @@ -241,8 +249,8 @@ optional. ) ``` - `lanes::AbstractDict{String,<:Integer}`: If no `lanes` way tag is available, these - values are used instead based on the value of the `highway` way tag. If no - `highway` way tag is available, the value for `"other"` is used. + values are used instead based on the value of the `highway` way tag. If the value of the + `highway` tag is not a key of the dictionary, the value for `"other"` is used. Default value: ``` Dict( @@ -256,6 +264,15 @@ optional. "other" => 1 ) ``` +- `lanes_both_ways::AbstractDict{String,<:Integer}`: If no `lanes:both_ways` tag is available, these + values are used instead, based on the value of the `highway` way tag. If the value of the + `highway` tag is not a key of the dictionary, the value for `"other"` is used. + Default value: + ``` + Dict( + "other" => 0 + ) + ``` - `lane_efficiency::AbstractDict{<:Integer,<:Real}`: Gives the lane efficiency based on number of lanes. `1.0` is used for any number of lanes not specified here. Default value: @@ -282,12 +299,14 @@ optional. function set_defaults(; maxspeeds::AbstractDict{String,<:Real}=DEFAULT_MAXSPEEDS[], lanes::AbstractDict{String,<:Integer}=DEFAULT_LANES[], + lanes_both_ways::AbstractDict{String,<:Integer}=DEFAULT_LANES_BOTH_WAYS[], lane_efficiency::AbstractDict{<:Integer,<:Real}=LANE_EFFICIENCY[], building_height_per_level::Real=DEFAULT_BUILDING_HEIGHT_PER_LEVEL[], max_building_levels::Integer=DEFAULT_MAX_BUILDING_LEVELS[] ) DEFAULT_MAXSPEEDS[] = maxspeeds DEFAULT_LANES[] = lanes + DEFAULT_LANES_BOTH_WAYS[] = lanes_both_ways LANE_EFFICIENCY[] = lane_efficiency DEFAULT_BUILDING_HEIGHT_PER_LEVEL[] = building_height_per_level DEFAULT_MAX_BUILDING_LEVELS[] = max_building_levels diff --git a/src/parse.jl b/src/parse.jl index 39a1c57..8cd2583 100644 --- a/src/parse.jl +++ b/src/parse.jl @@ -35,10 +35,26 @@ function maxspeed(tags::AbstractDict)::DEFAULT_OSM_MAXSPEED_TYPE end """ -Determine number of lanes given osm way tags dictionary. +get correct DEFAULT_LANES dictionary based on the passed in tag +""" +function appropriate_lane_source(lanetag::AbstractString)::AbstractDict + if lanetag == "lanes" + return DEFAULT_LANES[] + elseif lanetag == "lanes:forward" || lanetag == "lanes:backward" + return DEFAULT_LANES[] + elseif lanetag == "lanes:both_ways" + return DEFAULT_LANES_BOTH_WAYS[] + else + throw(ErrorException("$lanetag does not have an associated default dictionary")) + end +end + + """ -function lanes(tags::AbstractDict)::DEFAULT_OSM_LANES_TYPE - lanes = get(tags, "lanes", "default") +Determine number of lanes, given osm way tags dictionary and tag which contains said lanes +""" +function lanes(tags::AbstractDict, lanetag::AbstractString)::DEFAULT_OSM_LANES_TYPE + lanes = get(tags, lanetag, "default") U = DEFAULT_OSM_LANES_TYPE if lanes != "default" @@ -51,14 +67,16 @@ function lanes(tags::AbstractDict)::DEFAULT_OSM_LANES_TYPE lanes = [remove_non_numeric(l) for l in lanes] return U(round(mean(lanes))) else - throw(ErrorException("Lanes is neither a string nor number, check data quality: $lanes")) + throw(ErrorException("$lanetag is neither a string nor number, check data quality: $lanes")) end else highway_type = get(tags, "highway", "other") - key = getkey(DEFAULT_LANES[], highway_type, "other") - return U(DEFAULT_LANES[][key]) + default_lane_source = appropriate_lane_source(lanetag) + key = getkey(default_lane_source, highway_type, "other") + return U(default_lane_source[key]) end end + """ @@ -209,9 +227,23 @@ function parse_osm_network_dict(osm_network_dict::AbstractDict, network_type::Sy tags = way["tags"] if is_highway(tags) && matches_network_type(tags, network_type) tags["maxspeed"] = maxspeed(tags) - tags["lanes"] = lanes(tags) + tags["lanes"] = lanes(tags, "lanes") tags["oneway"] = is_oneway(tags) tags["reverseway"] = is_reverseway(tags) + if tags["oneway"] + if tags["reverseway"] + tags["lanes:forward"] = DEFAULT_OSM_LANES_TYPE(0) + tags["lanes:backward"] = tags["lanes"] + else + tags["lanes:forward"] = tags["lanes"] + tags["lanes:backward"] = DEFAULT_OSM_LANES_TYPE(0) + end + tags["lanes:both_ways"] = DEFAULT_OSM_LANES_TYPE(0) + else + tags["lanes:forward"] = lanes(tags, "lanes:forward") + tags["lanes:backward"] = lanes(tags, "lanes:backward") + tags["lanes:both_ways"] = lanes(tags, "lanes:both_ways") + end nds = way["nodes"] union!(highway_nodes, nds) id = way["id"] diff --git a/test/stub.jl b/test/stub.jl index 8be9b3f..681e3e9 100644 --- a/test/stub.jl +++ b/test/stub.jl @@ -40,10 +40,10 @@ function basic_osm_graph_stub(weight_type=:distance, graph_type=:static) [1008, 1007], ] tag_dicts = [ - Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(2)), - Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(100), "lanes" => Int8(4)), - Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(2)), - Dict{String, Any}("oneway" => true, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(1)), + Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(2), "lanes:forward"=>Int8(2), "lanes:backward"=>Int8(2), "lanes:both_ways"=>Int8(0)), + Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(100), "lanes" => Int8(4), "lanes:forward"=>Int8(3), "lanes:backward"=>Int8(3), "lanes:both_ways"=>Int8(2)), + Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(2), "lanes:forward"=>Int8(3), "lanes:backward"=>Int8(1), "lanes:both_ways"=>Int8(0)), + Dict{String, Any}("oneway" => true, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(1), "lanes:forward"=>Int8(1), "lanes:backward"=>Int8(0), "lanes:both_ways"=>Int8(0)), ] ways = Dict(way_id => Way(way_id, nodes, tag_dict) for (way_id, nodes, tag_dict) in zip(way_ids, way_nodes, tag_dicts)) From 3008569f682d658e6c557b55f4f3ec01a0627869 Mon Sep 17 00:00:00 2001 From: Henrik Wolf Date: Wed, 9 Nov 2022 18:38:16 +0100 Subject: [PATCH 2/5] added paragraph on defaults to documentation --- docs/src/defaults.md | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/src/defaults.md b/docs/src/defaults.md index 620ecd6..84cb9d4 100644 --- a/docs/src/defaults.md +++ b/docs/src/defaults.md @@ -1,4 +1,66 @@ # Default Values +## Ways +During parsing, only `way`s with tags and nodes are considered. Further, the tags have to contain a key of either `"highway"` or `"railway"`. If the tags contain tags which have been excluded due to the `network_type` keyword (e.g. on download) are also discarded. This is relevant, if you downloaded the full network and want to generate only the `:bike` network from it. + +### Highways +The returned `Way` is guaranteed to have the following `keys`: +- (`highway::String`) +- `maxspeed::DEFAULT_OSM_MAXSPEED_TYPE` + - If the tag exists before parsing, `LightOSM` attempts to parse the content to a number in km/h, while automatically converting units of `mph`. If multiple speeds are mapped, the average is returned. + - If the tag does not exist before parsing, the default value as given by `DEFAULT_MAXSPEEDS[tags["highway"]]` is returned. If there is no tag with key `"highway"` in `DEFAULT_MAXSPEEDS`, then `DEFAULT_MAXSPEEDS["other"]` is used. +- `oneway::Bool` +- `reverseway::Bool` +- `lanes::DEFAULT_OSM_LANES_TYPE` + - If the tag exists before parsing, `LightOSM` attempts to parse the content to a `DEFAULT_OSM_LANES_TYPE` + - If the tag does not exist before parsing, the default value as given by `DEFAULT_LANES[tags["highway"]]` is returned. If there is no tag with key `"highway"` in `DEFAULT_LANES`, then `DEFAULT_LANES["other"]` is used. + +- `lanes:forward::DEFAULT_OSM_LANES_TYPE` + - If the way is `oneway` and `reverseway` this value is 0 + - If the way is `oneway` and not `reverseway` this value is the same as the `lanes` tag + - If the way is not `oneway`, the value is parsed like `lanes`, but with `"lanes"=>"lanes:forward"` + +- `lanes:backward::DEFAULT_OSM_LANES_TYPE` + - If the way is `oneway` and not `reverseway` this value is 0 + - If the way is `oneway` and `reverseway` this value is the same as the `lanes` tag + - If the way is not `oneway`, the value is parsed like `lanes`, but with `"lanes"=>"lanes:backward"` + +- `lanes:both_ways::DEFAULT_OSM_LANES_TYPE` + - If the way is `oneway`, this value is 0 + - If the way is not `oneway`: + - If the tag exists before parsing, `LightOSM` attempts to parse the content to a `DEFAULT_OSM_LANES_TYPE` + - If the tag does not exist before parsing, the default value as given by `DEFAULT_LANES_BOTH_WAYS[tags["highway"]]` is returned. If there is no tag with key `"highway"` in `DEFAULT_LANES_BOTH_WAYS`, `DEFAULT_LANES_BOTH_WAYS["other"]` is used. + +all further tags present on the original way are preserved, but not parsed to appropriate datatypes, but rather left as `String`. + +See [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L4) for the full implementation of the `maxspeed` parsing, and [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L56) for the full implementation of any `lanes` parsing. + +### Railways +The returned `Way` is guaranteed to have the following `keys`: +- (`railway::String`) +- `rail_type::String` set to `"unknown"` if not mapped +- `electrified::String` set to `"unknown"` if not mapped +- `gauge::Union{String, Nothin}` set to `nothing` if not mapped +- `usage::String` set to `"unknown"` if not mapped +- `name::String` set to `"unknown"` if not mapped +- `lanes::Union{String, Int64}` set to `1` if not mapped. +- `maxspeed::DEFAULT_OSM_MAXSPEED_TYPE` +- `oneway::DEFAULT_OSM_LANES_TYPE` +- `reverseway::DEFAULT_OSM_LANES_TYPE` + +all further tags present on the original `way` are preserved, but not parsed to appropriate datatypes, but rather left as `String`. + +The tags `maxspeed`, `oneway` and `reverseway` are set in the same way as described in [highways](#Highways). + +## Buildings +During parsing, only `relation`s and `way`s with tags, where one of these tags has to have a key of `"building"` are considered. After parsing, the following `keys` are guaranteed to exist: +- (`building`) +- `height` (see [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/buildings.jl#L171) for source) + +The height value is parsed via the funcitno + + +all further tags present in the original object are preserved, but not parsed to appropriate datatypes, but rather left as `String`. + ```@docs LightOSM.set_defaults From c0c5614da0f3cc4d0cde81ff3663b4dcb7b92a14 Mon Sep 17 00:00:00 2001 From: Henrik Wolf Date: Wed, 9 Nov 2022 19:04:09 +0100 Subject: [PATCH 3/5] lane efficiency uses lanes:forward and lanes:backward --- src/graph.jl | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/graph.jl b/src/graph.jl index d08b65b..84df0fc 100644 --- a/src/graph.jl +++ b/src/graph.jl @@ -367,7 +367,22 @@ function add_weights!(g::OSMGraph, weight_type::Symbol=:distance) if weight_type == :time weight = dist / maxspeed else - lanes = g.ways[highway].tags["lanes"]::DEFAULT_OSM_LANES_TYPE + if g.ways[highway].tags["oneway"]::Bool + lanes = g.ways[highway].tags["lanes"]::DEFAULT_OSM_LANES_TYPE + else + nodes = g.ways[highway].nodes + source_indices = findall(==(edge[1]), nodes) + if nodes[1] == nodes[end] + dest_indices = mod1.(source_indices.+1, length(nodes)) + else + dest_indices = [i+1 for i in source_indices if i < length(nodes)] + end + if edge[2] in nodes[dest_indices] + lanes = g.ways[highway].tags["lanes:forward"] + else + lanes = g.ways[highway].tags["lanes:backward"] + end + end lane_efficiency = get(LANE_EFFICIENCY[], lanes, 1.0) weight = dist / (maxspeed * lane_efficiency) end From fccb8e48ad4c4f1e8edbd5894df93b11cac816d0 Mon Sep 17 00:00:00 2001 From: SuperGrobi <49985053+SuperGrobi@users.noreply.github.com> Date: Wed, 9 Nov 2022 19:23:55 +0100 Subject: [PATCH 4/5] added short paragraph on the dangers of using the lanes tag --- docs/src/defaults.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/defaults.md b/docs/src/defaults.md index 84cb9d4..f5b72ab 100644 --- a/docs/src/defaults.md +++ b/docs/src/defaults.md @@ -34,6 +34,8 @@ all further tags present on the original way are preserved, but not parsed to ap See [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L4) for the full implementation of the `maxspeed` parsing, and [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L56) for the full implementation of any `lanes` parsing. +Also note that the `lanes` tag is interpreted as the number of lanes in one direction of the road. This conflicts with the official [OSM documentation](https://wiki.openstreetmap.org/wiki/Key:lanes?uselang=en). If you need accurate numbers of lanes in both directions, you want to use `lanes:forward` and `lanes:backward`. This discrepancy will be fixed in future releases. + ### Railways The returned `Way` is guaranteed to have the following `keys`: - (`railway::String`) From 1381fd5faf4e15565e580a260af965180a996e5d Mon Sep 17 00:00:00 2001 From: Henrik Wolf Date: Thu, 17 Nov 2022 14:38:33 +0100 Subject: [PATCH 5/5] doubled number of default lanes, made default parsing more coherent. --- docs/src/defaults.md | 10 +++++---- src/constants.jl | 8 +++---- src/parse.jl | 50 ++++++++++++++++++++++++++++++++------------ test/constants.jl | 6 +++--- test/stub.jl | 6 +++--- 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/docs/src/defaults.md b/docs/src/defaults.md index 84cb9d4..5a1b117 100644 --- a/docs/src/defaults.md +++ b/docs/src/defaults.md @@ -12,16 +12,16 @@ The returned `Way` is guaranteed to have the following `keys`: - `reverseway::Bool` - `lanes::DEFAULT_OSM_LANES_TYPE` - If the tag exists before parsing, `LightOSM` attempts to parse the content to a `DEFAULT_OSM_LANES_TYPE` - - If the tag does not exist before parsing, the default value as given by `DEFAULT_LANES[tags["highway"]]` is returned. If there is no tag with key `"highway"` in `DEFAULT_LANES`, then `DEFAULT_LANES["other"]` is used. + - If the tag does not exist before parsing, the default value as given by `DEFAULT_LANES_ONE_WAY[tags["highway"]]` is returned. If there is no tag with key `"highway"` in `DEFAULT_LANES_ONE_WAY`, then `DEFAULT_LANES_ONE_WAY["other"]` is used. (If the street is not `oneway`, the above discussed return values are multiplied by a factor of 2, one for every direction.) - `lanes:forward::DEFAULT_OSM_LANES_TYPE` - If the way is `oneway` and `reverseway` this value is 0 - - If the way is `oneway` and not `reverseway` this value is the same as the `lanes` tag - - If the way is not `oneway`, the value is parsed like `lanes`, but with `"lanes"=>"lanes:forward"` + - If the way is `oneway` and not `reverseway` this value is parsed like `lines` but with `"lanes"=>"lanes:forward"`. If the tag `"lanes:forward"` did not exist before parsing, the value of `"lanes"` is choose instead. + - If the way is not `oneway`, the value is parsed like `lanes`, but with `"lanes"=>"lanes:forward"`, but without the factor of 2. - `lanes:backward::DEFAULT_OSM_LANES_TYPE` - If the way is `oneway` and not `reverseway` this value is 0 - - If the way is `oneway` and `reverseway` this value is the same as the `lanes` tag + - If the way is `oneway` and `reverseway` this value is parsed like `lines` but with `"lanes"=>"lanes:backward"`. If the tag `"lanes:backward"` did not exist before parsing, the value of `"lanes"` is choose instead. - If the way is not `oneway`, the value is parsed like `lanes`, but with `"lanes"=>"lanes:backward"` - `lanes:both_ways::DEFAULT_OSM_LANES_TYPE` @@ -34,6 +34,8 @@ all further tags present on the original way are preserved, but not parsed to ap See [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L4) for the full implementation of the `maxspeed` parsing, and [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L56) for the full implementation of any `lanes` parsing. +See [here](https://github.com/DeloitteOptimalReality/LightOSM.jl/blob/master/src/parse.jl#L228) for the full implementation on how the final values are selected. + ### Railways The returned `Way` is guaranteed to have the following `keys`: - (`railway::String`) diff --git a/src/constants.jl b/src/constants.jl index d0d8f20..fa02e1f 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -154,9 +154,9 @@ const DEFAULT_MAXSPEEDS = Ref(Dict{String,DEFAULT_OSM_MAXSPEED_TYPE}( )) """ -Default number of lanes based on highway type. +Default number of lanes based on highway type in one direction of the road. """ -const DEFAULT_LANES = Ref(Dict{String,DEFAULT_OSM_LANES_TYPE}( +const DEFAULT_LANES_ONE_WAY = Ref(Dict{String,DEFAULT_OSM_LANES_TYPE}( "motorway" => 3, "trunk" => 3, "primary" => 2, @@ -298,14 +298,14 @@ optional. """ function set_defaults(; maxspeeds::AbstractDict{String,<:Real}=DEFAULT_MAXSPEEDS[], - lanes::AbstractDict{String,<:Integer}=DEFAULT_LANES[], + lanes::AbstractDict{String,<:Integer}=DEFAULT_LANES_ONE_WAY[], lanes_both_ways::AbstractDict{String,<:Integer}=DEFAULT_LANES_BOTH_WAYS[], lane_efficiency::AbstractDict{<:Integer,<:Real}=LANE_EFFICIENCY[], building_height_per_level::Real=DEFAULT_BUILDING_HEIGHT_PER_LEVEL[], max_building_levels::Integer=DEFAULT_MAX_BUILDING_LEVELS[] ) DEFAULT_MAXSPEEDS[] = maxspeeds - DEFAULT_LANES[] = lanes + DEFAULT_LANES_ONE_WAY[] = lanes DEFAULT_LANES_BOTH_WAYS[] = lanes_both_ways LANE_EFFICIENCY[] = lane_efficiency DEFAULT_BUILDING_HEIGHT_PER_LEVEL[] = building_height_per_level diff --git a/src/parse.jl b/src/parse.jl index 8cd2583..4ac0b00 100644 --- a/src/parse.jl +++ b/src/parse.jl @@ -39,9 +39,9 @@ get correct DEFAULT_LANES dictionary based on the passed in tag """ function appropriate_lane_source(lanetag::AbstractString)::AbstractDict if lanetag == "lanes" - return DEFAULT_LANES[] + return DEFAULT_LANES_ONE_WAY[] elseif lanetag == "lanes:forward" || lanetag == "lanes:backward" - return DEFAULT_LANES[] + return DEFAULT_LANES_ONE_WAY[] elseif lanetag == "lanes:both_ways" return DEFAULT_LANES_BOTH_WAYS[] else @@ -53,7 +53,7 @@ end """ Determine number of lanes, given osm way tags dictionary and tag which contains said lanes """ -function lanes(tags::AbstractDict, lanetag::AbstractString)::DEFAULT_OSM_LANES_TYPE +function parse_lanes(tags::AbstractDict, lanetag::AbstractString)::DEFAULT_OSM_LANES_TYPE lanes = get(tags, lanetag, "default") U = DEFAULT_OSM_LANES_TYPE @@ -227,23 +227,47 @@ function parse_osm_network_dict(osm_network_dict::AbstractDict, network_type::Sy tags = way["tags"] if is_highway(tags) && matches_network_type(tags, network_type) tags["maxspeed"] = maxspeed(tags) - tags["lanes"] = lanes(tags, "lanes") tags["oneway"] = is_oneway(tags) tags["reverseway"] = is_reverseway(tags) + + # get values from tags, regardless if the exist + lanes = parse_lanes(tags, "lanes") + lanes_forward = parse_lanes(tags, "lanes:forward") + lanes_backward = parse_lanes(tags, "lanes:backward") + lanes_both_ways = parse_lanes(tags, "lanes:both_ways") + if tags["oneway"] if tags["reverseway"] - tags["lanes:forward"] = DEFAULT_OSM_LANES_TYPE(0) - tags["lanes:backward"] = tags["lanes"] + lanes_forward = DEFAULT_OSM_LANES_TYPE(0) + lanes_backward = haskey(tags, "lanes:backward") ? lanes_backward : lanes else - tags["lanes:forward"] = tags["lanes"] - tags["lanes:backward"] = DEFAULT_OSM_LANES_TYPE(0) + lanes_forward = haskey(tags, "lanes:forward") ? lanes_forward : lanes + lanes_backward = DEFAULT_OSM_LANES_TYPE(0) + end + lanes_both_ways = DEFAULT_OSM_LANES_TYPE(0) + else # if street is both ways + lanes = haskey(tags, "lanes") ? lanes : DEFAULT_OSM_LANES_TYPE(2*lanes) + if !(haskey(tags, "lanes:forward") && haskey(tags, "lanes:backward")) && (lanes % 2 == 0) + lanes_forward = DEFAULT_OSM_LANES_TYPE(lanes/2) + lanes_backward = DEFAULT_OSM_LANES_TYPE(lanes/2) + elseif lanes == 1 + lanes_forward = DEFAULT_OSM_LANES_TYPE(0) + lanes_backward = DEFAULT_OSM_LANES_TYPE(0) + lanes_both_ways = DEFAULT_OSM_LANES_TYPE(1) end - tags["lanes:both_ways"] = DEFAULT_OSM_LANES_TYPE(0) - else - tags["lanes:forward"] = lanes(tags, "lanes:forward") - tags["lanes:backward"] = lanes(tags, "lanes:backward") - tags["lanes:both_ways"] = lanes(tags, "lanes:both_ways") end + + # check integrity + if lanes != lanes_forward + lanes_backward + lanes_both_ways + @warn "the number of lanes ($lanes) on way with id $(way["id"]) does not match the total number of lanes:forward ($lanes_forward), lanes:backward ($lanes_backward) and lanes:both_ways ($lanes_both_ways)" + end + + # actually updating the values of the tags + tags["lanes"] = lanes + tags["lanes:forward"] = lanes_forward + tags["lanes:backward"] = lanes_backward + tags["lanes:both_ways"] = lanes_both_ways + nds = way["nodes"] union!(highway_nodes, nds) id = way["id"] diff --git a/test/constants.jl b/test/constants.jl index 65f95e6..a26ce7f 100644 --- a/test/constants.jl +++ b/test/constants.jl @@ -36,7 +36,7 @@ end # Get original defaults original_maxspeeds = deepcopy(LightOSM.DEFAULT_MAXSPEEDS[]) - original_lanes = deepcopy(LightOSM.DEFAULT_LANES[]) + original_lanes = deepcopy(LightOSM.DEFAULT_LANES_ONE_WAY[]) # Create graph using originals original_g = LightOSM.graph_from_object(deepcopy(data); graph_type=:static, weight_type=:lane_efficiency) @@ -76,6 +76,6 @@ end # "surface": "asphalt" @test original_g.ways[217499573].tags["maxspeed"] == original_maxspeeds["secondary"] @test new_g.ways[217499573].tags["maxspeed"] == new_maxspeeds["secondary"] - @test original_g.ways[217499573].tags["lanes"] == original_lanes["secondary"] - @test new_g.ways[217499573].tags["lanes"] == new_lanes["secondary"] + @test original_g.ways[217499573].tags["lanes"] == 2*original_lanes["secondary"] + @test new_g.ways[217499573].tags["lanes"] == 2*new_lanes["secondary"] end diff --git a/test/stub.jl b/test/stub.jl index 681e3e9..9fae458 100644 --- a/test/stub.jl +++ b/test/stub.jl @@ -40,9 +40,9 @@ function basic_osm_graph_stub(weight_type=:distance, graph_type=:static) [1008, 1007], ] tag_dicts = [ - Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(2), "lanes:forward"=>Int8(2), "lanes:backward"=>Int8(2), "lanes:both_ways"=>Int8(0)), - Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(100), "lanes" => Int8(4), "lanes:forward"=>Int8(3), "lanes:backward"=>Int8(3), "lanes:both_ways"=>Int8(2)), - Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(2), "lanes:forward"=>Int8(3), "lanes:backward"=>Int8(1), "lanes:both_ways"=>Int8(0)), + Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(4), "lanes:forward"=>Int8(2), "lanes:backward"=>Int8(2), "lanes:both_ways"=>Int8(0)), + Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(100), "lanes" => Int8(8), "lanes:forward"=>Int8(3), "lanes:backward"=>Int8(3), "lanes:both_ways"=>Int8(2)), + Dict{String, Any}("oneway" => false, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(4), "lanes:forward"=>Int8(3), "lanes:backward"=>Int8(1), "lanes:both_ways"=>Int8(0)), Dict{String, Any}("oneway" => true, "reverseway" => false, "maxspeed" => Int16(50), "lanes" => Int8(1), "lanes:forward"=>Int8(1), "lanes:backward"=>Int8(0), "lanes:both_ways"=>Int8(0)), ] ways = Dict(way_id => Way(way_id, nodes, tag_dict) for (way_id, nodes, tag_dict) in zip(way_ids, way_nodes, tag_dicts))