@@ -10,7 +10,7 @@ function is_endpoint(g::AbstractGraph, v)
1010 return true
1111 elseif outdegree (g, v) == 0 || indegree (g, v) == 0 # sink or source
1212 return true
13- elseif length (neighbors) != 2 || indegree (g, v) != outdegree (g, v) # change to one way
13+ elseif length (neighbors) != 2 || indegree (g, v) != outdegree (g, v) # change to/from one way
1414 return true
1515 end
1616 return false
@@ -45,55 +45,78 @@ function path_to_endpoint(g::AbstractGraph, (ep, ep_succ)::Tuple{T,T}) where {T<
4545 return path
4646end
4747
48+ """
49+ Return the total weight of a path given as a Vector of Ids.
50+ """
4851function total_weight (g:: OSMGraph , path:: Vector{<:Integer} )
4952 sum ((g. weights[path[[i, i+ 1 ]]. .. ] for i in 1 : length (path)- 1 ))
5053end
54+
55+ function ways_in_path (g:: OSMGraph , path:: Vector{<:Integer} )
56+ ways = Set {Int} ()
57+ for i in 1 : (length (path)- 1 )
58+ edge = [g. index_to_node[path[i]], g. index_to_node[path[i+ 1 ]]]
59+ push! (ways, g. edge_to_way[edge])
60+ end
61+ return collect (ways)
62+ end
63+
5164"""
5265Build a new graph which simplifies the topology of osmg.graph.
5366The resulting graph only contains intersections and dead ends from the original graph.
5467The geometry of the contracted nodes is kept in the edge_gdf DataFrame
5568"""
56- function simplify_graph (osmg:: OSMGraph )
69+ function simplify_graph (osmg:: OSMGraph{U, T, W} ) where {U, T, W}
5770 g = osmg. graph
5871 relevant_nodes = collect (endpoints (g))
59- n = length (relevant_nodes)
60- (n == nv (g)) && return g # nothing to simplify here
72+ n_relevant = length (relevant_nodes)
73+ graph = DiGraph (n_relevant)
74+ weights = similar (osmg. weights, (n_relevant, n_relevant))
75+ node_coordinates = Vector {Vector{W}} (undef, n_relevant)
76+ node_to_index = OrderedDict {T,U} ()
77+ index_to_node = OrderedDict {U,T} ()
6178
62-
63- G_simplified = DiGraph (n)
64- weights = similar (osmg. weights, (n, n))
65- edge_gdf = DataFrame (
66- u = Int[],
67- v = Int[],
68- key = Int[],
69- weight = Vector {eltype(osmg.weights)} (),
70- geom = IGeometry[],
71- )
72- node_gdf = DataFrame (id = Int[], geom = IGeometry[])
73-
74-
75- index_mapping = Dict {Int,Int} ()
79+ index_mapping = Dict {U,U} ()
7680 for (new_i, old_i) in enumerate (relevant_nodes)
7781 index_mapping[old_i] = new_i
78- geo = createpoint (osmg. node_coordinates[old_i])
79- push! (node_gdf, (new_i, geo))
82+ node_coordinates[new_i] = osmg. node_coordinates[old_i]
83+ node = osmg. index_to_node[old_i]
84+ index_to_node[new_i] = node
85+ node_to_index[node] = new_i
8086 end
8187
88+ edges = Dict {NTuple{3,U}, Vector{U}} ()
89+ edge_count = Dict {Tuple{U,U}, Int} ()
8290 for path in paths_to_reduce (g)
8391 u = index_mapping[first (path)]
8492 v = index_mapping[last (path)]
8593 path_weight = total_weight (osmg, path)
86- geo = createlinestring (osmg. node_coordinates[path])
87-
88- if add_edge! (G_simplified, (u, v))
94+ if add_edge! (graph, (u, v))
8995 key = 0
9096 weights[u, v] = path_weight
97+ edge_count[u,v] = 1
9198 else # parallel edge
92- key = sum ((edge_gdf. u .== u) .& (edge_gdf. v .== v))
99+ key = edge_count[u,v]
100+ edge_count[u,v] += 1
93101 weights[u, v] = min (path_weight, weights[u, v])
94102 end
95- push! (edge_gdf, (u, v, key, path_weight, geo))
103+ edges[u,v,key] = path
104+ end
105+
106+ edge_to_way = Dict {NTuple{3,U}, Vector{T}} ()
107+ for (edge, path) in edges
108+ edge_to_way[edge] = ways_in_path (osmg, path)
96109 end
97110
98- return G_simplified, weights, node_gdf, edge_gdf
111+ return SimplifiedOSMGraph (
112+ osmg,
113+ node_coordinates,
114+ node_to_index,
115+ index_to_node,
116+ edge_to_way,
117+ graph,
118+ edges,
119+ weights,
120+ nothing
121+ )
99122end
0 commit comments