# How to understand the following function excepted from OpenStreetMapX package?

**URL:** <https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075>\
**Category:** General Usage\
**Created:** [July 6, 2019, 6:46pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075 "2019-07-06T18:46:48Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 6, 2019, 6:46pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/1 "2019-07-06T18:46:48Z")

</div>

Hi, I’m reading the code from this great OpenStreetMapX package, and the following function confused me a little bit. I would really appreciate it if anyone can help me clarify some doubts.

```julia
function get_edges(nodes::Dict{Int,T}, roadways::Vector{OpenStreetMapX.Way}) where T<: Union{OpenStreetMapX.ENU, OpenStreetMapX.ECEF}
         oneway_roads = map(OpenStreetMapX.oneway, roadways)
         reverse_roads = map(OpenStreetMapX.reverseway, roadways)
         classes = OpenStreetMapX.classify_roadways(roadways)
         edges = Dict{Tuple{Int, Int}, Int}()
         
         for i = 1:length(roadways)
              for j = 2: length(roadways[I].nodes)
                   n0 = roadways[i].nodes[j-1]
                   n1 = roadways[i].nodes[j]
                   start = n0 * !reverse_roads[i] + n1 * reverse_roads[i]
                   fin = n0 * reverse_roads[i] + n1 * !reverse_roads[i] 
                   edges[(start, fin)] = classes[roadways[i].id]
                   oneway_roads[i] || (edges[(fin,start)] = classes[roadways[i].id])
              end
         end
       return collect(keys(edges)), collect(values(edges))
end

```

what confused me are the two lines to assign values to the variables `start` and `fin`. Any comments are greatly appreciated.

---

<div class="post-metadata">

**Author:** ![Bartosz\_Pankratz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bartosz_pankratz/32/9223_2.png) [@Bartosz\_Pankratz](https://discourse.julialang.org/u/Bartosz_Pankratz)\
**Post date:** [July 7, 2019, 5:06pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/2 "2019-07-07T17:06:20Z")

</div>

Hi,

To answer this question let me clarify what is the way in the context of the Open Street Map and how it is stored and used in OpenStreetMapX. Ways are the basic elements of the OSM files; they are polylines used to describe objects such as roads, buildings, etc. They are stored as an ordered list of nodes, each with unique ID and additional tags describing its function and attributes. OpenStreetMapX maintains this structure, storing ways as objects of type `Way`.

Let’s move to the function itself. In OpenStreetMapX road network is represented as a directed graph and the function `get_edges` is desing to create the list of tuples, which is essentially a list of the edges in this graph.

In order to do it properly function `get_edges` must filter the essential atributes of the roadways from their tags. `reverse` is one of them. It is boolean variable and it describes a special case when one-way segment of the road is stored in the `Way` object in the wrong order - from successor to predecessor. The line:

```julia
reverse_roads = map(OpenStreetMapX.reverseway, roadways)

```

extract this information from all roadways and returns a vector of booleans.

Two lines you are asking about are used to assign the values of the start and final node of the segment, taking into account if it is in reverse or non-reverse order.

For example assume that segment ` i` is non-reversed; then value of `!reverse_roads[i]` and `reverse_roads[i]`will be equal to 1 and 0, respectively. So when we assign the `start` value it will be:

```julia
n0 * 1 + n1 * 0 = n0

```

so we got the proper result; our choosen start node match the order in which it is stored in `Way` object. The variable `fin` works in the same way, but it is created to get the final node of the segment; in this case it will be equal to `n1 `.

Obviously, when the segment is in the reversed order, the boolean values will turn around so the `start` will be equal to `n1` and `fin` will be equal to `n0`, which is again, the solution we are looking for.

I hope my answer may help you.

---

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 8, 2019, 9:40am UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/3 "2019-07-08T09:40:24Z")

</div>

Thank you a lot for your detailed explanations. it’s actually a simple trick math people like to use, right? 😉

---

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 8, 2019, 2:55pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/4 "2019-07-08T14:55:17Z")

</div>

@Bartosz_Pankratz, Hi, I have one more question / doubt if you do not mind, I was wondering, why is there not a mutable struct with name Node in the package OpenStreetMapX? Is it because it is not necessary, since a node is basically just a coordinate, and there are three different coordinate systems with names LLA, ENU and ECEF already? But a node in .osm file also has the tag attribute, right? Take the following except from an xml file as an example.

```julia
<osm version="0.6">
<node lat="50.9", lon="-1.4", id="12345">
<tag k="place" v="city">
<tag k="name" v="Southampton"> 
</node>
<way id="223">
<nd id="1234">
<nd id="1235">
<tag k="highway" v="motorway" />
<tag k="ref" v="M27" />
</way>

```

Thank you so much!

---

<div class="post-metadata">

**Author:** ![Bartosz\_Pankratz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bartosz_pankratz/32/9223_2.png) [@Bartosz\_Pankratz](https://discourse.julialang.org/u/Bartosz_Pankratz)\
**Post date:** [July 9, 2019, 1:34am UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/5 "2019-07-09T01:34:09Z")

</div>

Hi,

Yeah, it’s just a kind of fancy trick 😉

You already answer the question - it is kinda unnecessary and basically adding additional struct Node will only worsen the working experience with the library. We already have the types corresponding with different coordinates systems and it is much more convenient to keep nodes as a dictionaries or pairs, which are mapping: `node_id => coordinates`.

It is especially a better solution when you want to get the coordinates by the node ID, you only need to use ID as a key of the dictionary rather than fiddle with filtering the collection by the struct’s attribute `ID`.

However, there are also tags relevant to the particular nodes, which often are important for some applications (like finding some special object like stores, amenities, etc.). We are storing them as an attribute of the main map object `OSMData` called `features`. They are another dictionary with exactly the same nodes IDs as a keys and the most relevant tags (those corresponding to the categiories of objects) as a values; there are also plenty of function which might be used to filter those features and so on.

In our opinion it was the best solution for this problem and doing about 5 projects with this library have confirmed it. But if you have any comments and ideas which might improve the work of the library, we will be glad to hear them!

---

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 18, 2019, 11:52am UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/6 "2019-07-18T11:52:34Z")

</div>

@Bartosz_Pankratz, Hi, I’m reading the file `classification.jl`, and it seems like in the process of filtering out different osm ways (except features, all the others are ways in essence), only the functions `filter_highways` and `filter_buildings` use `.visible` to check whether it is visible or not. I was wondering, is there a specific reason? Thank you a lot.

---

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 18, 2019, 7:48pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/7 "2019-07-18T19:48:52Z")

</div>

@Bartosz_Pankratz, I think it’s because of the logical design of the code. Since all the ways in osm data are highways, it makes sense to only require the highways and buildings are visible. Is it so?

---

<div class="post-metadata">

**Author:** ![Bartosz\_Pankratz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bartosz_pankratz/32/9223_2.png) [@Bartosz\_Pankratz](https://discourse.julialang.org/u/Bartosz_Pankratz)\
**Post date:** [July 22, 2019, 4:14am UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/8 "2019-07-22T04:14:34Z")

</div>

Hi,

Sorry for not responding earlier. The reason why we use this tag to filter ways is caused by the fact that `osm` files contain data about non-open acessible objects, such as military grounds or airports runways. And basically ` .visible` is used to filter this kind of ways. It is useful when you want to build a a traffic model - obviously drivers cannot use the runways in the same ways as regular roads, so you want to throw them away from the model.

---

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 22, 2019, 9:49am UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/9 "2019-07-22T09:49:46Z")

</div>

Thank you so much for your time and attention! I have another question if you do not mind. 😉

```julia
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)
		ref = parse(Int,relation.members[i]["ref"])
		if relation.members[i]["type"] == "node" && haskey(nodes,ref)
			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])) 
		else
			relation_index = findfirst(relation -> relation.id == ref, relations)
			!isa(relation_index,Nothing) && (valid[i] = !OpenStreetMapX.crop!(nodes,bounds, ways, relations, relations[relation_index])) 
		end
	end
	relation.members = relation.members[valid]
	if sum(valid) == 0
		return true
	else
		return false
	end
end

```

I thought I got the logic of cropping a way yesterday. Then, the above function confuses me a bit.  
More specifically, is there a self-referencing call in the following line:  
`!isa(relation_index,Nothing) && (valid[i] = !OpenStreetMapX.crop!(nodes,bounds, ways, relations, relations[relation_index]))`  
If so, how to make sure that it will eventually end then?

---

<div class="post-metadata">

**Author:** ![Bartosz\_Pankratz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bartosz_pankratz/32/9223_2.png) [@Bartosz\_Pankratz](https://discourse.julialang.org/u/Bartosz_Pankratz)\
**Post date:** [July 24, 2019, 4:17am UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/10 "2019-07-24T04:17:08Z")

</div>

Hi,

Sorry for not replying earlier. The answer is simple, `relations` in `osm` are basically containers storing some other objects which are relating one to another. `relation` might also be a member of another `relation` and thats the reason why we self-referencing this function. We know that this loop won’t be infinte because of the internal logic of the `relation`. If let’s say `relation_1` is a member of `relation_2` then the `relation_2` might be a member of `relation_1` only if they are indentical. And it is impossible because the `OSMData` object keeps only unique elements.

---

<div class="post-metadata">

**Author:** ![bsnyh](https://avatars.discourse-cdn.com/v4/letter/b/ce7236/32.png) [@bsnyh](https://discourse.julialang.org/u/bsnyh)\
**Post date:** [July 25, 2019, 12:18pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/11 "2019-07-25T12:18:09Z")

</div>

Thank you for your detailed reply. One more question if you do not mind. 😉

```julia
function find_route(m::OpenStreetMapX.MapData, node0::Int, node1::Int, node2::Int, 
                    weights::SparseArrays.SparseMatrixCSC{Float64,Int64};
                    routing::Symbol = :astar, heuristic::Function = (u,v) -> zero(Float64), 
                    get_distance::Bool = false, get_time::Bool = false)
    result = Any[]
    route1 = OpenStreetMapX.find_route(m, node0, node1, weights,
                                        routing = routing, heuristic = heuristic,
                                        get_distance = get_distance, get_time = get_time)
    route2 = OpenStreetMapX.find_route(m, node1, node2, weights,
                                        routing = routing, heuristic = heuristic,
                                        get_distance = get_distance, get_time = get_time)
    push!(result,vcat(route1[1],route2[1]))
    for i = 2:length(route1)
        push!(result,route1[i] + route2[i])
    end
    return result
end

```

I understand most of the above code. The only thing, is the two push functions. I’m a bit confused about it…

---

<div class="post-metadata">

**Author:** ![Bartosz\_Pankratz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bartosz_pankratz/32/9223_2.png) [@Bartosz\_Pankratz](https://discourse.julialang.org/u/Bartosz_Pankratz)\
**Post date:** [July 26, 2019, 4:54pm UTC](https://discourse.julialang.org/t/how-to-understand-the-following-function-excepted-from-openstreetmapx-package/26075/12 "2019-07-26T16:54:08Z")

</div>

Hi,

Answer is simple - at the end this functions returns a two element vector, that’s why there are two pushes. First one push the concatenate list nodes of both routes , second one is pushing the sum of the routes costs (eg. time, distance).
