diff --git a/Project.toml b/Project.toml index cbe8087..23e5110 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "OpenStreetMapX" uuid = "86cd37e6-c0ff-550b-95fe-21d72c8d4fc9" authors = ["Przemyslaw Szufel ", "Bartosz Pankratz ", "Anna Szczurek ", "Bogumil Kaminski ", "Pawel Pralat "] -version = "0.3.4" +version = "0.4.0" [deps] CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" diff --git a/docs/make.jl b/docs/make.jl index 95c3ab7..93d479d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,16 +1,19 @@ using Documenter using Pkg -try - using OpenStreetMapX -catch - if !("../src/" in LOAD_PATH) - push!(LOAD_PATH,"../src/") - @info "Added \"../src/\"to the path: $LOAD_PATH " - using OpenStreetMapX + +if isfile("src/OpenStreetMapX.jl") + if !("." in LOAD_PATH) + push!(LOAD_PATH,".") + end +elseif isfile("../src/OpenStreetMapX.jl") + if !(".." in LOAD_PATH) + push!(LOAD_PATH,"..") end end +using OpenStreetMapX + makedocs( sitename = "OpenStreetMapX", format = format = Documenter.HTML( @@ -18,6 +21,7 @@ makedocs( ), modules = [OpenStreetMapX], pages = ["index.md", "spatial.md", "reference.md"], + checkdocs = :exports, doctest = true ) diff --git a/docs/src/reference.md b/docs/src/reference.md index d35da8b..47010c1 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -13,6 +13,8 @@ Representing map data ```@docs MapData get_map_data(::String,::Union{String,Nothing}; ::Set{Int},::Bool,::Bool) +sample_map_path +sample_map ``` Coordinate systems @@ -26,6 +28,10 @@ center inbounds onbounds latlon +getX +getY +getZ +WGS84 ``` @@ -39,6 +45,12 @@ shortest_route fastest_route a_star_algorithm distance +get_distance +nodes_within_driving_time +nodes_within_driving_distance +nodes_within_weights +nearest_node +nodes_within_range ``` Google API routing @@ -64,3 +76,31 @@ PED_CLASSES SPEED_ROADS_URBAN SPEED_ROADS_RURAL ``` + + +Map objects +----------- +```@docs +Way +Relation +``` + +Internal library functions +-------------------------- +```@docs +boundary_point +centroid +classify_cycleways +classify_walkways +crop! +extract_highways +features_to_graph +filter_cycleways +filter_highways +filter_walkways +find_intersections +find_optimal_waypoint_approx +find_optimal_waypoint_exact +find_route +find_segments +``` diff --git a/src/OpenStreetMapX.jl b/src/OpenStreetMapX.jl index 325f899..90f4af2 100644 --- a/src/OpenStreetMapX.jl +++ b/src/OpenStreetMapX.jl @@ -34,8 +34,9 @@ export get_map_data export get_google_route export encode, decode export generate_point_in_bounds, point_to_nodes - +export sample_map, sample_map_path export latlon +export Bounds, Way export ROAD_CLASSES, CYCLE_CLASSES, PED_CLASSES, SPEED_ROADS_URBAN, SPEED_ROADS_RURAL diff --git a/src/classification.jl b/src/classification.jl index c4002f5..be591f0 100644 --- a/src/classification.jl +++ b/src/classification.jl @@ -9,22 +9,29 @@ end getlanes(w::OpenStreetMapX.Way) = parse(Int, w.tags["lanes"]) -visible(obj::T) where T <: OSMElement = (get(obj.tags, "visible", "") != "false") +visible(obj::T) where T <: OSMElement = (get(obj.tags, "visible", "") != "false") services(w::OpenStreetMapX.Way) = (get(w.tags,"highway", "") == "services") -######################## -### Extract Highways ### -######################## +""""" + extract_highways(ways::Vector{OpenStreetMapX.Way}) +Extract Highways +""" extract_highways(ways::Vector{OpenStreetMapX.Way}) = [way for way in ways if isdefined(way,:tags) && haskey(way.tags, "highway")] -filter_highways(ways::Vector{OpenStreetMapX.Way}) = [way for way in ways if OpenStreetMapX.visible(way) && !OpenStreetMapX.services(way)] +""" + filter_highways(ways::Vector{OpenStreetMapX.Way}) -############################################## -### Filter and Classify Highways for Cars ### -############################################## +""" +filter_highways(ways::Vector{OpenStreetMapX.Way}) = [way for way in ways if OpenStreetMapX.visible(way) && !OpenStreetMapX.services(way)] +### +## Filter and Classify Highways for Cars +### +""" + valid_roadway(way, levels::Set{Int}, classes::Dict{String, Int} = OpenStreetMapX.ROAD_CLASSES) +""" function valid_roadway(way, levels::Set{Int}, classes::Dict{String, Int} = OpenStreetMapX.ROAD_CLASSES) highway = get(way.tags, "highway", "") if isempty(highway) || highway == "services" || !haskey(classes, highway) @@ -38,18 +45,15 @@ filter_roadways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = O classify_roadway(way::Way, classes::Dict{String, Int} = OpenStreetMapX.ROAD_CLASSES) = classes[way.tags["highway"]] classify_roadways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = OpenStreetMapX.ROAD_CLASSES) = Dict{Int,Int}(way.id => classify_roadway(way, classes) for way in ways if haskey(classes, way.tags["highway"])) -#################################################### -### Filter and Classify Highways for Pedestrians ### -#################################################### """ filter_walkways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = OpenStreetMapX.PED_CLASSES; levels::Set{Int} = Set(1:length(OpenStreetMapX.PED_CLASSES))) - + Filters a vector of ways to include only those that are relevant for pedestrian walkways. It considers the presence of a "sidewalk" tag and checks if the corresponding value or the "highway" tag value -is present in the specified classes dictionary and levels set. +is present in the specified classes dictionary and levels set. **Arguments** @@ -71,12 +75,12 @@ function filter_walkways(ways::Vector{OpenStreetMapX.Way},classes::Dict{String, end end return walkways -end +end """ classify_walkways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = OpenStreetMapX.PED_CLASSES) - + Classifies a vector of OpenStreetMapX ways based on their pedestrian attributes. It considers the presence of a "sidewalk" tagand checks if the corresponding value or the "highway" tag value is present in the specified classes dictionary @@ -92,9 +96,9 @@ function classify_walkways(ways::Vector{OpenStreetMapX.Way},classes::Dict{String for way in ways sidewalk = get(way.tags, "sidewalk", "") if sidewalk != "no" - if haskey(classes, "sidewalk:$(sidewalk)") + if haskey(classes, "sidewalk:$(sidewalk)") walkways[way.id] = classes["sidewalk:$(sidewalk)"] - elseif haskey(classes, way.tags["highway"]) + elseif haskey(classes, way.tags["highway"]) walkways[way.id] = classes[way.tags["highway"]] end end @@ -110,7 +114,7 @@ end filter_cycleways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = OpenStreetMapX.CYCLE_CLASSES; levels::Set{Int} = Set(1:length(OpenStreetMapX.CYCLE_CLASSES))) - + Filters a vector of OpenStreetMapX ways to include only those that are relevant for cycleways. It considers the presence of "bicycle", "cycleway", and "highway" tags and checks if the corresponding values or the constructed class strings are present in the specified classes dictionary and levels set. @@ -119,7 +123,7 @@ or the constructed class strings are present in the specified classes dictionary * `ways::Vector{OpenStreetMapX.Way}` : Way's vector * `classes` : classes dictionary -* `levels` : set of levels useful to compare with the way tags +* `levels` : set of levels useful to compare with the way tags """ function filter_cycleways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = OpenStreetMapX.CYCLE_CLASSES; levels::Set{Int} = Set(1:length(OpenStreetMapX.CYCLE_CLASSES))) @@ -148,7 +152,7 @@ end """ classify_cycleways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{String, Int} = OpenStreetMapX.CYCLE_CLASSES) - + Classifies a vector of OpenStreetMapX ways based on their cycleway attributes. It considers the presence of "bicycle", "cycleway", and "highway" tags and checks if the corresponding values or the constructed class strings are present in the specified classes dictionary. @@ -170,11 +174,11 @@ function classify_cycleways(ways::Vector{OpenStreetMapX.Way}, classes::Dict{Stri bikeclass = "bicycle:$(bicycle)" if bicycle != "no" - if haskey(classes, cycleclass) + if haskey(classes, cycleclass) cycleways[way.id] = classes[cycleclass] - elseif haskey(classes, bikeclass) + elseif haskey(classes, bikeclass) cycleways[way.id] = classes[bikeclass] - elseif haskey(classes, highway) + elseif haskey(classes, highway) cycleways[way.id] = classes[highway] end end @@ -211,5 +215,5 @@ function filter_graph_features(features::Dict{Int,Tuple{String,String}}, graphFe error("class not in classes") end level = classes[class] - Dict{Int,Int}(key => node for (key,node) in graphFeatures if classes[features[key][1]] == level) + Dict{Int,Int}(key => node for (key,node) in graphFeatures if classes[features[key][1]] == level) end diff --git a/src/crop.jl b/src/crop.jl index b44432b..3b2c753 100644 --- a/src/crop.jl +++ b/src/crop.jl @@ -1,7 +1,8 @@ -####################### -### Crop Single Way ### -####################### +""" + crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, way::OpenStreetMapX.Way) +Crop Single Way +""" function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, way::OpenStreetMapX.Way) valid = falses(length(way.nodes)+2) n = 1 @@ -48,10 +49,11 @@ function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, way::OpenStreetMapX.W end end -################# -### Crop Ways ### -################# +""" + crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStreetMapX.Way}) +Crop Ways +""" function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStreetMapX.Way}) leave = ways[[!OpenStreetMapX.crop!(nodes,bounds,way) for way in ways]] append!(empty!(ways),leave) @@ -59,10 +61,11 @@ function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStre end -############################ -### Crop Single Relation ### -############################ +""" + crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStreetMapX.Way},relations::Vector{OpenStreetMapX.Relation}, relation::OpenStreetMapX.Relation) +Crop Single Relation +""" function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStreetMapX.Way},relations::Vector{OpenStreetMapX.Relation}, relation::OpenStreetMapX.Relation) valid = falses(length(relation.members)) for i = 1:length(relation.members) @@ -71,10 +74,10 @@ function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStre valid[i] = OpenStreetMapX.inbounds(nodes[ref],bounds) elseif relation.members[i]["type"] == "way" way_index = findfirst(way -> way.id == ref, ways) - !isa(way_index,Nothing) && (valid[i] = !OpenStreetMapX.crop!(nodes, bounds, ways[way_index])) + !isa(way_index,Nothing) && (valid[i] = !OpenStreetMapX.crop!(nodes, bounds, ways[way_index])) else relation_index = findfirst(relation -> relation.id == ref, relations) - !isa(relation_index,Nothing) && (valid[i] = !OpenStreetMapX.crop!(nodes,bounds, ways, relations, relations[relation_index])) + !isa(relation_index,Nothing) && (valid[i] = !OpenStreetMapX.crop!(nodes,bounds, ways, relations, relations[relation_index])) end end relation.members = relation.members[valid] @@ -85,20 +88,23 @@ function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStre end end -###################### -### Crop Relations ### -###################### +""" + crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStreetMapX.Way}, relations::Vector{OpenStreetMapX.Relation}) +Crop Relations +""" function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, ways::Vector{OpenStreetMapX.Way}, relations::Vector{OpenStreetMapX.Relation}) leave = relations[[!OpenStreetMapX.crop!(nodes,bounds,ways, relations, relation) for relation in relations]] append!(empty!(relations),leave) return nothing end -#################################### -### Crop Single Node and Feature ### -#################################### +""" + crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, features::Dict, id::Int) + +Crop Single Node and Feature +""" function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, features::Dict, id::Int) if !OpenStreetMapX.inbounds(nodes[id], bounds) id in keys(features) && delete!(features, id) @@ -106,20 +112,22 @@ function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, features::Dict, id::I end end -############################### -### Crop Nodes and Features ### -############################### +""" + crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, features::Dict) +Crop Nodes and Features +""" function crop!(nodes::Dict, bounds::OpenStreetMapX.Bounds, features::Dict) for (key, node) in nodes OpenStreetMapX.crop!(nodes,bounds,features,key) end end -################ -### Crop Map ### -################ +""" + crop!(map::OpenStreetMapX.OSMData; crop_relations = true, crop_ways = true, crop_nodes = true) +Crop Map +""" function crop!(map::OpenStreetMapX.OSMData; crop_relations = true, crop_ways = true, crop_nodes = true) crop_relations && OpenStreetMapX.crop!(map.nodes, map.bounds, map.ways, map.relations) crop_ways && OpenStreetMapX.crop!(map.nodes, map.bounds, map.ways) diff --git a/src/intersections.jl b/src/intersections.jl index ff08a12..eb20226 100644 --- a/src/intersections.jl +++ b/src/intersections.jl @@ -4,6 +4,8 @@ """ + oneway(w::OpenStreetMapX.Way) + Check if Way is One - Way """ function oneway(w::OpenStreetMapX.Way) @@ -20,11 +22,15 @@ end """ + reverseway(w::OpenStreetMapX.Way) + Check if Way is Reverse """ reverseway(w::OpenStreetMapX.Way) = (get(w.tags,"oneway", "") == "-1") """ + distance(nodes::Dict{Int,T}, route::AbstractVector{Int}) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + Compute the distance of a route for some `nodes` data """ function distance(nodes::Dict{Int,T}, route::AbstractVector{Int}) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) @@ -35,7 +41,9 @@ function distance(nodes::Dict{Int,T}, route::AbstractVector{Int}) where T<:(Unio end """ -Find Intersections of Highways ### + find_intersections(highways::Vector{OpenStreetMapX.Way}) + +Find Intersections of Highways """ function find_intersections(highways::Vector{OpenStreetMapX.Way}) seen = Set{Int}() @@ -60,7 +68,9 @@ function find_intersections(highways::Vector{OpenStreetMapX.Way}) end """ -Find Segments of Highways ### + find_segments(nodes::Dict{Int,T}, highways::Vector{OpenStreetMapX.Way}, intersections::Dict{Int,Set{Int}}) where T<:Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF} + +Find Segments of Highways """ function find_segments(nodes::Dict{Int,T}, highways::Vector{OpenStreetMapX.Way}, intersections::Dict{Int,Set{Int}}) where T<:Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF} segments = OpenStreetMapX.Segment[] diff --git a/src/nodes.jl b/src/nodes.jl index 41b04a4..2a86ed0 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -1,4 +1,6 @@ """ + add_new_node!(nodes::Dict{Int,T},loc::T, start_id::Int = reinterpret((Int), hash(loc))) where T <: (Union{OpenStreetMapX.LLA,OpenStreetMapX.ENU}) + Add a New Node """ function add_new_node!(nodes::Dict{Int,T},loc::T, start_id::Int = reinterpret((Int), hash(loc))) where T <: (Union{OpenStreetMapX.LLA,OpenStreetMapX.ENU}) @@ -18,6 +20,8 @@ end """ + nearest_node(nodes::Dict{Int,T}, loc::T) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + Find the nearest node to a given location `loc` """ function nearest_node(nodes::Dict{Int,T}, loc::T) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) @@ -36,6 +40,8 @@ function nearest_node(nodes::Dict{Int,T}, loc::T) where T<:(Union{OpenStreetMapX end """ + nearest_node(m::MapData, loc::ENU, vs_only::Bool=true) + Find the nearest node to a given location `loc` """ function nearest_node(m::MapData, loc::ENU, vs_only::Bool=true) @@ -43,6 +49,8 @@ function nearest_node(m::MapData, loc::ENU, vs_only::Bool=true) end """ + nearest_node(nodes::Dict{Int,T}, loc::T, node_list::AbstractSet{Int}) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + Find the nearest node in a list of nodes """ function nearest_node(nodes::Dict{Int,T}, loc::T, node_list::AbstractSet{Int}) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) @@ -67,6 +75,8 @@ end """ + nodes_within_range(nodes::Dict{Int,T}, loc::T, range::Float64 = Inf) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + Find all nodes within range of a location """ function nodes_within_range(nodes::Dict{Int,T}, loc::T, range::Float64 = Inf) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) @@ -84,6 +94,8 @@ function nodes_within_range(nodes::Dict{Int,T}, loc::T, range::Float64 = Inf) wh end """ + nodes_within_range(nodes::Dict{Int,T}, loc::T, node_list::AbstractSet{Int}, range::Float64 = Inf) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + Find nodes within range of a location using a subset of nodes """ function nodes_within_range(nodes::Dict{Int,T}, loc::T, node_list::AbstractSet{Int}, range::Float64 = Inf) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) @@ -101,11 +113,15 @@ function nodes_within_range(nodes::Dict{Int,T}, loc::T, node_list::AbstractSet{I end """ + nodes_within_range(nodes::Dict{Int,T},loc::T, m::OpenStreetMapX.MapData, range::Float64 = Inf) where T <:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + Find vertices of a routing network within range of a location """ nodes_within_range(nodes::Dict{Int,T},loc::T, m::OpenStreetMapX.MapData, range::Float64 = Inf) where T <:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) = OpenStreetMapX.nodes_within_range(nodes,loc,keys(m.v),range) """ + centroid(nodes::Dict{Int,T}, node_list::Vector{Int}) where T<:(Union{OpenStreetMapX.LLA,OpenStreetMapX.ENU}) + Compute Centroid of List of Nodes """ function centroid(nodes::Dict{Int,T}, node_list::Vector{Int}) where T<:(Union{OpenStreetMapX.LLA,OpenStreetMapX.ENU}) diff --git a/src/parseMap.jl b/src/parseMap.jl index 949ac70..1221641 100644 --- a/src/parseMap.jl +++ b/src/parseMap.jl @@ -1,4 +1,8 @@ """ + parse_element(handler::LibExpat.XPStreamHandler, + name::AbstractString, + attr::Dict{AbstractString,AbstractString}) + Parse Elements of Map """ function parse_element(handler::LibExpat.XPStreamHandler, @@ -111,6 +115,8 @@ function get_map_data(filepath::String,filename::Union{String,Nothing}=nothing; end """ + get_vertices_and_graph_nodes(edges::Vector{Tuple{Int,Int}}) + Get Vertices and nodes for a set of `edges` """ function get_vertices_and_graph_nodes(edges::Vector{Tuple{Int,Int}}) @@ -120,6 +126,8 @@ function get_vertices_and_graph_nodes(edges::Vector{Tuple{Int,Int}}) end """ + MapData(mapdata::OSMData, road_levels::Set{Int}, only_intersections::Bool=true; trim_to_connected_graph::Bool=false, remove_nodes::AbstractSet{Int}=Set{Int}()) + Internal constructor of `MapData` object """ function MapData(mapdata::OSMData, road_levels::Set{Int}, only_intersections::Bool=true; @@ -182,14 +190,25 @@ function MapData(mapdata::OSMData, road_levels::Set{Int}, only_intersections::Bo end end -const __SAMPLE_MAP = Ref{MapData}() +const __SAMPLE_MAP = Ref{MapData}() """ + sample_map_path() + +Produces a path to a sample map file. +""" +function sample_map_path() + joinpath(dirname(pathof(OpenStreetMapX)),"..","test/data/reno_east3.osm") +end + +""" + sample_map() + Produces a MapData object in a lazy loaded way. """ function sample_map() if !isdefined(OpenStreetMapX.__SAMPLE_MAP, 1) - map_file_path = joinpath(dirname(pathof(OpenStreetMapX)),"..","test/data/reno_east3.osm") + map_file_path = sample_map_path() OpenStreetMapX.__SAMPLE_MAP[] = get_map_data(map_file_path, use_cache=false) end deepcopy(OpenStreetMapX.__SAMPLE_MAP[]) diff --git a/src/points.jl b/src/points.jl index 8109a6c..26a5c8e 100644 --- a/src/points.jl +++ b/src/points.jl @@ -7,30 +7,44 @@ const WGS84 = OpenStreetMapX.Ellipsoid(a = 6378137.0, f_inv = 298.257223563) const OSGB36 = OpenStreetMapX.Ellipsoid(a = 6377563.396, b = 6356256.909) const NAD27 = OpenStreetMapX.Ellipsoid(a = 6378206.4, b = 6356583.8) -######################### -### s ### -######################### """ + getX(lla::OpenStreetMapX.LLA) + Point Translator gets longitude """ getX(lla::OpenStreetMapX.LLA) = lla.lon + """ + getY(lla::OpenStreetMapX.LLA) + Point Translator gets lattitude """ getY(lla::OpenStreetMapX.LLA) = lla.lat + """ + getZ(lla::OpenStreetMapX.LLA) + Point Translator gets altitude """ getZ(lla::OpenStreetMapX.LLA) = lla.alt + """ + getX(enu::OpenStreetMapX.ENU) + Point Translator gets enu `east` value """ getX(enu::OpenStreetMapX.ENU) = enu.east + """ + getY(enu::OpenStreetMapX.ENU) + Point Translator gets enu `north` value """ getY(enu::OpenStreetMapX.ENU) = enu.north + """ + getZ(enu::OpenStreetMapX.ENU) + Point Translator gets `up` value """ getZ(enu::OpenStreetMapX.ENU) = enu.up @@ -51,6 +65,11 @@ Calculates a distance between two points `a` and `b` distance(a::ECEF, b::ECEF) = OpenStreetMapX.distance(a.x, a.y, a.z, b.x, b.y, b.z) +""" + distance(x1, y1, z1, x2, y2, z2) + +Calculates eclidean distance in three dimensions. +""" function distance(x1, y1, z1, x2, y2, z2) return sqrt((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2) end diff --git a/src/routing.jl b/src/routing.jl index 96a86c4..7d8b1d6 100644 --- a/src/routing.jl +++ b/src/routing.jl @@ -51,6 +51,8 @@ end """ + dijkstra(m::MapData, w::SparseArrays.SparseMatrixCSC{Float64,Int64}, start_vertex::Int) + Dijkstra's Algorithm """ function dijkstra(m::MapData, w::SparseArrays.SparseMatrixCSC{Float64,Int64}, start_vertex::Int) @@ -58,6 +60,8 @@ function dijkstra(m::MapData, w::SparseArrays.SparseMatrixCSC{Float64,Int64}, st end """ + network_travel_times(m::MapData, class_speeds::Dict{Int,Float64} = OpenStreetMapX.SPEED_ROADS_URBAN) + Transpose distances to times """ function network_travel_times(m::MapData, class_speeds::Dict{Int,Float64} = OpenStreetMapX.SPEED_ROADS_URBAN) @@ -71,6 +75,8 @@ function network_travel_times(m::MapData, class_speeds::Dict{Int,Float64} = Open end """ + create_weights_matrix(m::MapData,weights::Vector{Float64}) + Create a Sparse Matrix for a given vector of weights """ function create_weights_matrix(m::MapData,weights::Vector{Float64}) @@ -86,10 +92,11 @@ function create_weights_matrix(m::MapData,weights::Vector{Float64}) end """ + get_velocities(m::MapData, class_speeds::Dict{Int,Float64} = OpenStreetMapX.SPEED_ROADS_URBAN) + Get velocities matrix ### """ -function get_velocities(m::MapData, - class_speeds::Dict{Int,Float64} = OpenStreetMapX.SPEED_ROADS_URBAN) +function get_velocities(m::MapData, class_speeds::Dict{Int,Float64} = OpenStreetMapX.SPEED_ROADS_URBAN) @assert length(m.e) == length(m.w.nzval) indices = [(m.v[i],m.v[j]) for (i,j) in m.e] V = SparseArrays.spzeros(length(m.v), length(m.v)) @@ -100,6 +107,8 @@ function get_velocities(m::MapData, end """ + extract_route(dijkstra::Graphs.DijkstraState{Float64,Int64}, startIndex::Int, finishIndex::Int) + Extract route from Dijkstra results object """ function extract_route(dijkstra::Graphs.DijkstraState{Float64,Int64}, startIndex::Int, finishIndex::Int) @@ -118,6 +127,8 @@ function extract_route(dijkstra::Graphs.DijkstraState{Float64,Int64}, startIndex end """ + get_route_nodes(m::MapData, route_indices::AbstractVector{Int}) + Extract nodes ID's from route object """ function get_route_nodes(m::MapData, route_indices::AbstractVector{Int}) @@ -125,6 +136,8 @@ function get_route_nodes(m::MapData, route_indices::AbstractVector{Int}) end """ + route_edges(m::MapData, route_nodes::Vector{Int}) + Generate an ordered list of edges traversed in route """ function route_edges(m::MapData, route_nodes::Vector{Int}) @@ -136,12 +149,19 @@ function route_edges(m::MapData, route_nodes::Vector{Int}) end """ -Calculate distance with a given weights + calculate_distance(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, route_indices::Vector{Int64}) = sum(weights[(route_indices[i-1], route_indices[i])] for i = 2:length(route_indices)) + +Calculate distance with a given `weights` for the `route_indices` vector """ -calculate_distance(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, route_indices::Array{Int64,1}) = sum(weights[(route_indices[i-1], route_indices[i])] for i = 2:length(route_indices)) +calculate_distance(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, route_indices::Vector{Int64}) = sum(weights[(route_indices[i-1], route_indices[i])] for i = 2:length(route_indices)) """ + find_route(m::MapData, node0::Int, node1::Int, + weights::SparseArrays.SparseMatrixCSC{Float64,Int64}; + routing::Symbol = :astar, heuristic::Function = (u,v) -> zero(Float64), + get_distance::Bool = false, get_time::Bool = false) + Find Route with Given Weights """ @@ -280,8 +300,10 @@ function fastest_route(m::MapData, node1::Int, node2::Int, node3::Int; end """ -Find waypoint minimizing the route -Approximate solution + find_optimal_waypoint_approx(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, node0::Int, node1::Int, waypoints::Dict{Int,Int}) + +Find waypoint minimizing the route. +Returns an approximate solution. """ function find_optimal_waypoint_approx(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, node0::Int, node1::Int, waypoints::Dict{Int,Int}) dists_start_waypoint = Graphs.dijkstra_shortest_paths(m.g, m.v[node0], weights).dists @@ -299,8 +321,10 @@ function find_optimal_waypoint_approx(m::MapData, weights::SparseArrays.SparseMa end """ -Find waypoint minimizing the route -Exact solution + find_optimal_waypoint_exact(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, node0::Int, node1::Int, waypoints::Dict{Int,Int}) + +Find waypoint minimizing the route. +Returns an exact solution. """ function find_optimal_waypoint_exact(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, node0::Int, node1::Int, waypoints::Dict{Int,Int}) dists_start_waypoint = Graphs.dijkstra_shortest_paths(m.g, m.v[node0], weights).dists @@ -321,13 +345,20 @@ end ### Find Nodes Within Driving Time or Distance - Auxiliary Functions ### ######################################################################## -### Bellman Ford's Algorithm ### +""" + bellman_ford(m::MapData, w::SparseArrays.SparseMatrixCSC{Float64,Int64}, start_vertices::Vector{Int}) + +Bellman Ford's Algorithm +""" function bellman_ford(m::MapData, w::SparseArrays.SparseMatrixCSC{Float64,Int64}, start_vertices::Vector{Int}) return Graphs.bellman_ford_shortest_paths(m.g, start_vertices, w) end -### Filter vertices from bellman_fordStates object ### +""" + filter_vertices(vertices::Dict{Int,Int}, weights::Vector{Float64}, limit::Float64) +Filter vertices from bellman_fordStates object ### +""" function filter_vertices(vertices::Dict{Int,Int}, weights::Vector{Float64}, limit::Float64) if limit == Inf @assert length(vertices) == length(weights) @@ -345,11 +376,12 @@ function filter_vertices(vertices::Dict{Int,Int}, weights::Vector{Float64}, limi return indices, distances end -############################################################################## -### Extract Nodes from bellman_fordStates Object Within an (Optional) Limit ### -### Based on Weights ### -############################################################################## +""" + nodes_within_weights(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, start_indices::Vector{Int}, limit::Float64=Inf) +Extract Nodes from bellman_fordStates Object Within an (Optional) Limit ### +Based on Weights ### +""" function nodes_within_weights(m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, start_indices::Vector{Int}, limit::Float64=Inf) start_vertices = [m.v[i] for i in start_indices] bellman_ford = OpenStreetMapX.bellman_ford(m, weights, start_vertices) @@ -358,11 +390,12 @@ end nodes_within_weights(nodes::Dict{Int,T}, m::MapData, weights::SparseArrays.SparseMatrixCSC{Float64,Int64}, loc::T, limit::Float64=Inf,locrange::Float64=500.0) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) = OpenStreetMapX.nodes_within_weights(m, weights, nodes_within_range(nodes, loc, m, locrange), limit) -############################################################################## -### Extract Nodes from bellman_fordStates Object Within an (Optional) Limit ### -### Based on Driving Distance ### -############################################################################## +""" + nodes_within_driving_distance(m::MapData, start_indices::Vector{Int}, limit::Float64=Inf) +Extract Nodes from bellman_fordStates Object Within an (Optional) Limit ### +Based on Driving Distance ### +""" function nodes_within_driving_distance(m::MapData, start_indices::Vector{Int}, limit::Float64=Inf) start_vertices = [m.v[i] for i in start_indices] bellman_ford = OpenStreetMapX.bellman_ford(m, m.w, start_vertices) @@ -371,11 +404,14 @@ end nodes_within_driving_distance(nodes::Dict{Int,T}, m::MapData, loc::T, limit::Float64=Inf,locrange::Float64=500.0) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF})= OpenStreetMapX.nodes_within_driving_distance(m, nodes_within_range(nodes, loc, m, locrange), limit) -############################################################################## -### Extract Nodes from bellman_fordStates Object Within an (Optional) Limit ### -### Based on Driving Time ### -############################################################################## +""" + nodes_within_driving_time(m::MapData, start_indices::Vector{Int}, limit::Float64=Inf, speeds::Dict{Int,Float64}=SPEED_ROADS_URBAN) + nodes_within_driving_time(nodes::Dict{Int,T}, m::MapData, loc::T, limit::Float64=Inf, locrange::Float64=500.0, speeds::Dict{Int,Float64}=SPEED_ROADS_URBAN) where T<:(Union{OpenStreetMapX.ENU,OpenStreetMapX.ECEF}) + +Extract Nodes from bellman_fordStates Object Within an (Optional) Limit ### +Based on Driving Time ### +""" function nodes_within_driving_time(m::MapData, start_indices::Vector{Int}, limit::Float64=Inf, speeds::Dict{Int,Float64}=SPEED_ROADS_URBAN) w = OpenStreetMapX.create_weights_matrix(m,network_travel_times(m, speeds)) start_vertices = [m.v[i] for i in start_indices] diff --git a/src/types.jl b/src/types.jl index a45ff51..318f7e8 100644 --- a/src/types.jl +++ b/src/types.jl @@ -198,7 +198,7 @@ end ################## """ -Element on Open Street Map +An abstract type representing an element on Open Street Map """ abstract type OSMElement @@ -309,9 +309,9 @@ This is the main data structure used fot map data analytics. **Fields** -* `bounds` : bounds of the area map (stored as a OpenStreetMapX.Bounds object) +* `bounds` : bounds of the area map (stored as a [`Bounds`](@ref) object) * `nodes` : dictionary of nodes representing all the objects on the map (with coordinates in East, North, Up system) -* `roadways` : unique roads stored as a OpenStreetMapX.Way objects +* `roadways` : unique roads stored as a set of [`Way`](@ref)s * `intersections` : roads intersections * `g` : `Graphs` directed graph representing a road network * `v` : vertices in the road network (node id .=> graph vertex) @@ -332,5 +332,4 @@ mutable struct MapData e::Vector{Tuple{Int,Int}} # Edges in graph, stored as a tuple (source,destination) w::SparseArrays.SparseMatrixCSC{Float64, Int} # Edge weights, indexed by graph id class::Vector{Int} # Road class of each edge - #MapData(bounds, nodes, roadways, intersections) = new(bounds, nodes, roadways, intersections, Graphs.SimpleGraphs.SimpleDiGraph{Int64}(), Dict{Int,Int}(),Int[], Tuple{Int64,Int64}[], SparseMatrixCSC(Matrix{Float64}(undef,0,0)),Int[]) end