Skip to content

Commit

Permalink
[FEAT] Changed id type to Union{Int, String}
Browse files Browse the repository at this point in the history
  • Loading branch information
ltokareva committed Mar 6, 2024
1 parent c5a0b8f commit 5d4bfbf
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 32 deletions.
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
name = "LightOSM"
uuid = "d1922b25-af4e-4ba3-84af-fe9bea896051"
authors = ["Jack Chan <[email protected]>"]
version = "0.2.12"
version = "0.2.13"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LightXML = "9c8b4983-aa76-5018-a973-4c85ecc9e179"
MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5"
NearestNeighbors = "b8a86587-4115-5ab1-83bc-aa920d37bbce"
Expand Down
4 changes: 2 additions & 2 deletions src/constants.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
Default data types used to construct OSMGraph object.
"""
const DEFAULT_OSM_ID_TYPE = Int64
const DEFAULT_OSM_INDEX_TYPE = Int32
const DEFAULT_OSM_INDEX_TYPE = Int64
const DEFAULT_OSM_ID_TYPE = Union{Int, String}
const DEFAULT_OSM_EDGE_WEIGHT_TYPE = Float64
const DEFAULT_OSM_MAXSPEED_TYPE = Int16
const DEFAULT_OSM_LANES_TYPE = Int8
Expand Down
18 changes: 9 additions & 9 deletions src/graph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ end


"""
add_node_and_edge_mappings!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Integer,W <: Real}
add_node_and_edge_mappings!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Union{Int, String},W <: Real}
Adds mappings between nodes, edges and ways to `OSMGraph`.
"""
function add_node_and_edge_mappings!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Integer,W <: Real}
function add_node_and_edge_mappings!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Union{Int, String},W <: Real}
for (way_id, way) in g.ways
@inbounds for (i, node_id) in enumerate(way.nodes)
if haskey(g.node_to_way, node_id)
Expand Down Expand Up @@ -266,11 +266,11 @@ function add_node_tags!(g::OSMGraph)
end

"""
adjacent_node(g::OSMGraph, node::T, way::T)::Union{T,Vector{<:T}} where T <: Integer
adjacent_node(g::OSMGraph, node::T, way::T)::Union{T,Vector{<:T}} where T <: Union{Int, String}
Finds the adjacent node id on a given way.
"""
function adjacent_node(g::OSMGraph, node::T, way::T)::Union{T,Vector{<:T}} where T <: Integer
function adjacent_node(g::OSMGraph, node::T, way::T)::Union{T,Vector{<:T}} where T <: Union{Int, String}

Check warning on line 273 in src/graph.jl

View check run for this annotation

Codecov / codecov/patch

src/graph.jl#L273

Added line #L273 was not covered by tests
way_nodes = g.ways[way].nodes
if node == way_nodes[1]
return way_nodes[2]
Expand Down Expand Up @@ -300,7 +300,7 @@ Adds restrictions linked lists to `OSMGraph`.
# Example
`[from_way_node_index, ...via_way_node_indices..., to_way_node_index]`
"""
function add_indexed_restrictions!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Integer,W <: Real}
function add_indexed_restrictions!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Union{Int, String},W <: Real}
g.indexed_restrictions = DefaultDict{U,Vector{MutableLinkedList{U}}}(Vector{MutableLinkedList{U}})

for (id, r) in g.restrictions
Expand Down Expand Up @@ -403,7 +403,7 @@ end
Adds a Graphs.AbstractGraph object to `OSMGraph`.
"""
function add_graph!(g::OSMGraph{U, T, W}, graph_type::Symbol=:static) where {U <: Integer, T <: Integer, W <: Real}
function add_graph!(g::OSMGraph{U, T, W}, graph_type::Symbol=:static) where {U <: Integer, T <: Union{Int, String}, W <: Real}
if graph_type == :light
g.graph = DiGraph{T}(g.weights)
elseif graph_type == :static
Expand Down Expand Up @@ -456,7 +456,7 @@ function trim_to_largest_connected_component!(g::OSMGraph{U, T, W}, graph, weigh
end

"""
add_dijkstra_states!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Integer,W <: Real}
add_dijkstra_states!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Union{Int, String},W <: Real}
Adds precomputed dijkstra states for every source node in `OSMGraph`. Precomputing all dijkstra
states is a O(V² + ElogV) operation, where E is the number of edges and V is the number of vertices,
Expand All @@ -465,9 +465,9 @@ may not be possible for larger graphs. Not recommended for graphs with greater t
Note: Not using `cost_adjustment`, i.e. not consdering restrictions in dijkstra computation,
consider adding in the future.
"""
function add_dijkstra_states!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Integer,W <: Real}
function add_dijkstra_states!(g::OSMGraph{U,T,W}) where {U <: Integer,T <: Union{Int, String},W <: Real}

Check warning on line 468 in src/graph.jl

View check run for this annotation

Codecov / codecov/patch

src/graph.jl#L468

Added line #L468 was not covered by tests
@warn "Precomputing all dijkstra states is a O(V² + ElogV) operation, may not be possible for larger graphs."
g.dijkstra_states = Vector{Vector{U}}(undef, n)
g.dijkstra_states = Vector{Vector{U}}(undef, nv(g.graph))

Check warning on line 470 in src/graph.jl

View check run for this annotation

Codecov / codecov/patch

src/graph.jl#L470

Added line #L470 was not covered by tests
set_dijkstra_state!(g, collect(vertices(g.graph)))
end

Expand Down
37 changes: 36 additions & 1 deletion src/graph_utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ Maps node id to index.
node_id_to_index(g::OSMGraph, x::Integer) = g.node_to_index[x]
node_id_to_index(g::OSMGraph, x::Vector{<:Integer}) = [node_id_to_index(g, i) for i in x]

"""
node_id_to_index(g::OSMGraph, x::String)
node_id_to_index(g::OSMGraph, x::Vector{<:String})
Maps node id to index.
"""
node_id_to_index(g::OSMGraph, x::String) = g.node_to_index[x]
node_id_to_index(g::OSMGraph, x::Vector{<:String}) = [node_id_to_index(g, i) for i in x]

Check warning on line 35 in src/graph_utilities.jl

View check run for this annotation

Codecov / codecov/patch

src/graph_utilities.jl#L34-L35

Added lines #L34 - L35 were not covered by tests

"""
node_to_index(g::OSMGraph, x::Node)
node_to_index(g::OSMGraph, x::Vector{Node})
Expand All @@ -40,27 +49,51 @@ node_to_index(g::OSMGraph, x::Vector{Node}) = [node_id_to_index(g, i.id) for i i
Maps node index to dijkstra state (parents).
"""
index_to_dijkstra_state(g::OSMGraph, x::Integer) = g.dijkstra_states[x]
"""
index_to_dijkstra_state(g::OSMGraph, x::String)
Maps node index to dijkstra state (parents).
"""
index_to_dijkstra_state(g::OSMGraph, x::String) = g.dijkstra_states[x]

Check warning on line 57 in src/graph_utilities.jl

View check run for this annotation

Codecov / codecov/patch

src/graph_utilities.jl#L57

Added line #L57 was not covered by tests

"""
node_id_to_dijkstra_state(g::OSMGraph, x::Integer)
Maps node id to dijkstra state (parents).
"""
node_id_to_dijkstra_state(g::OSMGraph, x::Integer) = g.dijkstra_states[node_id_to_index(g, x)]
"""
node_id_to_dijkstra_state(g::OSMGraph, x::String)
Maps node id to dijkstra state (parents).
"""
node_id_to_dijkstra_state(g::OSMGraph, x::String) = g.dijkstra_states[node_id_to_index(g, x)]

Check warning on line 70 in src/graph_utilities.jl

View check run for this annotation

Codecov / codecov/patch

src/graph_utilities.jl#L70

Added line #L70 was not covered by tests

"""
set_dijkstra_state_with_index!(g::OSMGraph, index::Integer, state)
Set dijkstra state (parents) with node index.
"""
set_dijkstra_state_with_index!(g::OSMGraph, index::Integer, state) = push!(g.dijkstra_states, index, state)
"""
set_dijkstra_state_with_index!(g::OSMGraph, index::Integer, state)
Set dijkstra state (parents) with node index.
"""
set_dijkstra_state_with_index!(g::OSMGraph, index::String, state) = push!(g.dijkstra_states, index, state)

Check warning on line 83 in src/graph_utilities.jl

View check run for this annotation

Codecov / codecov/patch

src/graph_utilities.jl#L83

Added line #L83 was not covered by tests

"""
set_dijkstra_state_with_node_id!(g::OSMGraph, index::Integer, state)
Set dijkstra state (parents) with node id.
"""
set_dijkstra_state_with_node_id!(g::OSMGraph, node_id::Integer, state) = push!(g.dijkstra_states, node_id_to_index(g, node_id), state)
"""
set_dijkstra_state_with_node_id!(g::OSMGraph, index::String, state)
Set dijkstra state (parents) with node id.
"""
set_dijkstra_state_with_node_id!(g::OSMGraph, node_id::String, state) = push!(g.dijkstra_states, node_id_to_index(g, node_id), state)

Check warning on line 96 in src/graph_utilities.jl

View check run for this annotation

Codecov / codecov/patch

src/graph_utilities.jl#L96

Added line #L96 was not covered by tests

"""
maxspeed_from_index(g, x::Integer)
Expand All @@ -69,4 +102,6 @@ set_dijkstra_state_with_node_id!(g::OSMGraph, node_id::Integer, state) = push!(g
Get maxspeed from index id or node id.
"""
maxspeed_from_index(g, x::Integer) = index_to_node(g, x).tags["maxspeed"]
maxspeed_from_node_id(g, x::Integer) = g.nodes[x].tags["maxspeed"]
maxspeed_from_node_id(g, x::Integer) = g.nodes[x].tags["maxspeed"]
maxspeed_from_index(g, x::String) = index_to_node(g, x).tags["maxspeed"]
maxspeed_from_node_id(g, x::String) = g.nodes[x].tags["maxspeed"]

Check warning on line 107 in src/graph_utilities.jl

View check run for this annotation

Codecov / codecov/patch

src/graph_utilities.jl#L105-L107

Added lines #L105 - L107 were not covered by tests
7 changes: 7 additions & 0 deletions src/nearest_node.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,20 @@ not included in the results.
"""
nearest_node(g::OSMGraph, node::Node) = nearest_node(g, node.location, (index)->index==g.node_to_index[node.id])
nearest_node(g::OSMGraph, node_id::Integer) = nearest_node(g, g.nodes[node_id])
nearest_node(g::OSMGraph, node_id::String) = nearest_node(g, g.nodes[node_id])

Check warning on line 51 in src/nearest_node.jl

View check run for this annotation

Codecov / codecov/patch

src/nearest_node.jl#L51

Added line #L51 was not covered by tests
nearest_node(g::OSMGraph, nodes::Vector{<:Node}) = nearest_node(g, [n.id for n in nodes])
function nearest_node(g::OSMGraph, node_ids::AbstractVector{<:Integer})
locations = [g.nodes[n].location for n in node_ids]
cartesian_locations = to_cartesian(locations)
idxs, dists = knn(g.kdtree, cartesian_locations, 2, true)
return [g.index_to_node[index[2]] for index in idxs], [d[2] for d in dists]
end
function nearest_node(g::OSMGraph, node_ids::AbstractVector{<:String})
locations = [g.nodes[n].location for n in node_ids]
cartesian_locations = to_cartesian(locations)
idxs, dists = knn(g.kdtree, cartesian_locations, 2, true)
return [g.index_to_node[index[2]] for index in idxs], [d[2] for d in dists]

Check warning on line 63 in src/nearest_node.jl

View check run for this annotation

Codecov / codecov/patch

src/nearest_node.jl#L59-L63

Added lines #L59 - L63 were not covered by tests
end


"""
Expand Down
35 changes: 35 additions & 0 deletions src/nearest_way.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,38 @@ function nearest_point_on_way(g::OSMGraph, point::GeoLocation, way_id::Integer)
end
return EdgePoint(min_edge[1], min_edge[2], min_pos), min_dist
end
"""
nearest_point_on_way(g::OSMGraph, point::GeoLocation, way_id::String)
Finds the nearest position on a way to a given point. Matches to an `EdgePoint`.
# Arguments
- `g::OSMGraph`: LightOSM graph.
- `point::GeoLocation`: Point to find nearest position to.
- `wid::Integer`: Way ID to search.
# Returns
- `::Tuple`:
- `::EdgePoint`: Nearest position along the way between two nodes.
- `::Float64`: Distance from `point` to the nearest position on the way.
"""
function nearest_point_on_way(g::OSMGraph, point::GeoLocation, way_id::String)
nodes = g.ways[way_id].nodes
min_edge = nothing
min_dist = floatmax()
min_pos = 0.0
for edge in zip(nodes[1:end-1], nodes[2:end])
x1 = g.nodes[edge[1]].location.lon
y1 = g.nodes[edge[1]].location.lat
x2 = g.nodes[edge[2]].location.lon
y2 = g.nodes[edge[2]].location.lat
x, y, pos = nearest_point_on_line(x1, y1, x2, y2, point.lon, point.lat)
d = distance(GeoLocation(y, x), point)
if d < min_dist
min_edge = edge
min_dist = d
min_pos = pos

Check warning on line 156 in src/nearest_way.jl

View check run for this annotation

Codecov / codecov/patch

src/nearest_way.jl#L141-L156

Added lines #L141 - L156 were not covered by tests
end
end
return EdgePoint(min_edge[1], min_edge[2], min_pos), min_dist

Check warning on line 159 in src/nearest_way.jl

View check run for this annotation

Codecov / codecov/patch

src/nearest_way.jl#L158-L159

Added lines #L158 - L159 were not covered by tests
end
15 changes: 10 additions & 5 deletions src/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ is_restriction(tags::AbstractDict)::Bool = get(tags, "type", "") == "restriction
"""
Determine if a restriction is valid and has usable data.
"""
function is_valid_restriction(members::AbstractArray, ways::AbstractDict{T,Way{T}})::Bool where T <: Integer
function is_valid_restriction(members::AbstractArray, ways::AbstractDict{T,Way{T}})::Bool where T <: Union{Int, String}

Check warning on line 125 in src/parse.jl

View check run for this annotation

Codecov / codecov/patch

src/parse.jl#L125

Added line #L125 was not covered by tests
role_counts = DefaultDict(0)
role_type_counts = DefaultDict(0)
ways_set = Set{Int}()
Expand Down Expand Up @@ -197,17 +197,18 @@ end
"""
Parse OpenStreetMap data into `Node`, `Way` and `Restriction` objects.
"""
function parse_osm_network_dict(osm_network_dict::AbstractDict,
function parse_osm_network_dict(id_type::Type,
osm_network_dict::AbstractDict,
network_type::Symbol=:drive;
filter_network_type::Bool=true
)::OSMGraph
U = DEFAULT_OSM_INDEX_TYPE
T = DEFAULT_OSM_ID_TYPE
T = id_type
W = DEFAULT_OSM_EDGE_WEIGHT_TYPE
L = DEFAULT_OSM_LANES_TYPE

ways = Dict{T,Way{T}}()
highway_nodes = Set{Int}([])
ways = Dict{}()
highway_nodes = Set{T}([])
for way in osm_network_dict["way"]
if haskey(way, "tags") && haskey(way, "nodes")
tags = way["tags"]
Expand Down Expand Up @@ -342,7 +343,9 @@ function init_graph_from_object(osm_xml_object::XMLDocument,
filter_network_type::Bool=true
)::OSMGraph
dict_to_parse = osm_dict_from_xml(osm_xml_object)
id_type = typeof(dict_to_parse["node"][1]["id"])
return parse_osm_network_dict(
id_type,
dict_to_parse,
network_type;
filter_network_type=filter_network_type
Expand All @@ -357,7 +360,9 @@ function init_graph_from_object(osm_json_object::AbstractDict,
filter_network_type::Bool=true
)::OSMGraph
dict_to_parse = osm_dict_from_json(osm_json_object)
id_type = typeof(dict_to_parse["node"][1]["id"])
return parse_osm_network_dict(
id_type,
dict_to_parse,
network_type;
filter_network_type=filter_network_type
Expand Down
24 changes: 22 additions & 2 deletions src/shortest_path.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ function shortest_path(::Type{A},
isnothing(path) && return
return index_to_node_id(g, path)
end
function shortest_path(::Type{A},

Check warning on line 61 in src/shortest_path.jl

View check run for this annotation

Codecov / codecov/patch

src/shortest_path.jl#L61

Added line #L61 was not covered by tests
g::OSMGraph{U,T,W},
origin::String,
destination::String,
weights::AbstractMatrix{W};
cost_adjustment::Function=(u, v, parents) -> 0.0,
max_distance::W=typemax(W)
)::Union{Nothing,Vector{T}} where {A <: Dijkstra, U, T, W}
o_index = node_id_to_index(g, origin)
d_index = node_id_to_index(g, destination)
path = dijkstra(A, g.graph, weights, o_index, d_index; cost_adjustment=cost_adjustment, max_distance=max_distance)
isnothing(path) && return
return index_to_node_id(g, path)

Check warning on line 73 in src/shortest_path.jl

View check run for this annotation

Codecov / codecov/patch

src/shortest_path.jl#L69-L73

Added lines #L69 - L73 were not covered by tests
end
function shortest_path(::Type{A},
g::OSMGraph{U,T,W},
origin::Integer,
Expand All @@ -76,9 +90,15 @@ end
function shortest_path(::Type{A}, g::OSMGraph{U,T,W}, origin::Integer, destination::Integer; kwargs...)::Union{Nothing,Vector{T}} where {A <: PathAlgorithm, U, T, W}
return shortest_path(A, g, origin, destination, g.weights; kwargs...)
end
function shortest_path(::Type{A}, g::OSMGraph{U,T,W}, origin::String, destination::String; kwargs...)::Union{Nothing,Vector{T}} where {A <: PathAlgorithm, U, T, W}
return shortest_path(A, g, origin, destination, g.weights; kwargs...)

Check warning on line 94 in src/shortest_path.jl

View check run for this annotation

Codecov / codecov/patch

src/shortest_path.jl#L93-L94

Added lines #L93 - L94 were not covered by tests
end
function shortest_path(::Type{A}, g::OSMGraph{U,T,W}, origin::Node{<:Integer}, destination::Node{<:Integer}, args...; kwargs...)::Union{Nothing,Vector{T}} where {A <: PathAlgorithm, U, T, W}
return shortest_path(A, g, origin.id, destination.id, args...; kwargs...)
end
function shortest_path(::Type{A}, g::OSMGraph{U,T,W}, origin::Node{<:String}, destination::Node{<:String}, args...; kwargs...)::Union{Nothing,Vector{T}} where {A <: PathAlgorithm, U, T, W}
return shortest_path(A, g, origin.id, destination.id, args...; kwargs...)

Check warning on line 100 in src/shortest_path.jl

View check run for this annotation

Codecov / codecov/patch

src/shortest_path.jl#L99-L100

Added lines #L99 - L100 were not covered by tests
end
function shortest_path(g::OSMGraph{U,T,W}, args...; kwargs...)::Union{Nothing,Vector{T}} where {U, T, W}
return shortest_path(Dijkstra, g, args...; kwargs...)
end
Expand Down Expand Up @@ -235,7 +255,7 @@ function weights_from_path(g::OSMGraph{U,T,W}, path::Vector{T}; weights=g.weight
end

"""
total_path_weight(g::OSMGraph{U,T,W}, path::Vector{T}; weights=g.weights)::W where {U <: Integer,T <: Integer,W <: Real}
total_path_weight(g::OSMGraph{U,T,W}, path::Vector{T}; weights=g.weights)::W where {U <: Integer,T <: Union{Int, String},W <: Real}
Extract total edge weight along a path.
Expand All @@ -247,7 +267,7 @@ Extract total edge weight along a path.
# Return
- `sum::W`: Total path edge weight, distances are in km, time is in hours.
"""
function total_path_weight(g::OSMGraph{U,T,W}, path::Vector{T}; weights=g.weights)::W where {U <: Integer,T <: Integer,W <: Real}
function total_path_weight(g::OSMGraph{U,T,W}, path::Vector{T}; weights=g.weights)::W where {U <: Integer,T <: Union{Int, String},W <: Real}

Check warning on line 270 in src/shortest_path.jl

View check run for this annotation

Codecov / codecov/patch

src/shortest_path.jl#L270

Added line #L270 was not covered by tests
sum::W = zero(W)
for i in 1:length(path) - 1
sum += weights[g.node_to_index[path[i]], g.node_to_index[path[i + 1]]]
Expand Down
Loading

0 comments on commit 5d4bfbf

Please sign in to comment.