bachelor thesis submission
commit
5b4edae20a
|
@ -0,0 +1,96 @@
|
|||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# Files generated by invoking Julia with --code-coverage
|
||||
*.jl.cov
|
||||
*.jl.*.cov
|
||||
|
||||
# Files generated by invoking Julia with --track-allocation
|
||||
*.jl.mem
|
||||
|
||||
# System-specific files and directories generated by the BinaryProvider and BinDeps packages
|
||||
# They contain absolute paths specific to the host computer, and so should not be committed
|
||||
deps/deps.jl
|
||||
deps/build.log
|
||||
deps/downloads/
|
||||
deps/usr/
|
||||
deps/src/
|
||||
|
||||
# Build artifacts for creating documentation generated by the Documenter package
|
||||
docs/build/
|
||||
docs/site/
|
||||
|
||||
# File generated by Pkg, the package manager, based on a corresponding Project.toml
|
||||
# It records a fixed state of all packages used by the project. As such, it should not be
|
||||
# committed for packages, but should be committed for applications that require a static
|
||||
# environment.
|
||||
Manifest.toml
|
||||
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# the following file-extensions are created by the prototype. Therefore they will be ignored
|
||||
*.osm
|
||||
*.pdf
|
||||
*.yaml
|
|
@ -0,0 +1,15 @@
|
|||
ISC License (ISC)
|
||||
|
||||
Copyright 2022 Falk Centner
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
WARNING: This is a prototype which is still under development.
|
||||
|
||||
TODO: See source
|
||||
|
||||
# Required packages
|
||||
|
||||
- LightOSM.jl
|
||||
- LightXML.jl
|
||||
- Graphs.jl
|
||||
- Cairo.jl
|
||||
- MetaGraphs.jl
|
||||
- HTTP.jl
|
||||
- Plots.jl
|
||||
- GraphPlot.jl
|
||||
- GraphRecipes.jl
|
||||
- Fontconfiq.jl
|
||||
- Compose.jl
|
||||
- YAML.jl
|
||||
|
||||
# Usage and Contributing
|
||||
|
||||
If there is an urgent usecase, here is a very short instruction:
|
||||
Start the OSMTrainPath or DataGraph-class.
|
||||
1.) Use the "addRelation(id)"/"addWay(id)"-function to download data from overpass.
|
||||
2.) After you completed all downloads call the "createGraph()"-function.
|
||||
3.) To see the data call "plotGraph()" and search for the "Buffer.pdf"-file in which the plot will be saved.
|
||||
4.) Use "filterOnedirectional(startpoint-id, destinationpoint-id)"-function to get one specific directed graph.
|
||||
5.) Plot again to see the filtered path.
|
||||
6.) If there are maxspeeds "UNKNOWN" you must correct them with the "changeWaySpeed(way-id, newspeed)"-function.
|
||||
7.) If there are more possible ways than one for your whished export, you must remove one way so there is no other possible way.
|
||||
Therefore use the "removeWay(way-id)"-function.
|
||||
8.) After you completed all maxspeeds and only one possibly way, you can export data to a YAML-file.
|
||||
Therefore use the exportPathToYAML(description, filename, startpoint-id, destinationpoint-id).
|
||||
Note that you have to name the filename like *name*.yaml.
|
||||
|
||||
# License
|
||||
|
||||
ISC-License
|
||||
Copyright 2022 Falk Centner
|
|
@ -0,0 +1,239 @@
|
|||
using Graphs, MetaGraphs, GraphPlot, Plots, GraphRecipes, Fontconfig, Cairo, Compose
|
||||
|
||||
include("./input.jl")
|
||||
include("./output.jl")
|
||||
|
||||
nodeDict = Dict()
|
||||
g = Graphs.SimpleDiGraph(1)
|
||||
mdg = MetaDiGraph(g)
|
||||
nodeXPositions = Float64[]
|
||||
nodeYPositions = Float64[]
|
||||
vecXCoordinates, vecYCoordinates = spring_layout(mdg) # This set the layout for the Graph-Packge, witch is used for plotting
|
||||
nodeColorArray = []
|
||||
nodeLabelArray = []
|
||||
|
||||
|
||||
#
|
||||
# The createGraph-function set a all data from the input-class in a MetaDiGraph.
|
||||
# Therefore are some nested functions implemented.
|
||||
#
|
||||
# addDataToDiGraph creates the vertices and the edges in the MetaDiGraph. The data from the NamedTuples will be stored in these graph-objects.
|
||||
#
|
||||
# getNodeColorIndex returns an index-number which will be used later to color the nodes.
|
||||
#
|
||||
# getCartesianX and getCartesianY are used to transfer the lat&lon-coordinates in cartesian coordinates which are used for a plot of the graph (function->plotGraph()).
|
||||
#
|
||||
function createGraph()
|
||||
g = Graphs.SimpleDiGraph(length(getFilteredNodeArray()))
|
||||
global mdg=MetaDiGraph(g)
|
||||
|
||||
function addDatasToDiGraph(filteredNodeArray::Vector{Any},filteredWayArray::Vector{Any})
|
||||
lonCorrection=0
|
||||
for node in filteredNodeArray
|
||||
lonCorrection=lonCorrection+node.lon
|
||||
end
|
||||
lonCorrection=lonCorrection/length(filteredNodeArray)
|
||||
for node in filteredNodeArray
|
||||
push!(nodeDict,node.nodeID=>(length(nodeDict)+1))
|
||||
set_prop!(mdg,get(nodeDict,node.nodeID,"default value"),:id, node.nodeID)
|
||||
push!(nodeColorArray,getNodeColorIndex(node.issignal,node.isswitch))
|
||||
append!(nodeXPositions,getCartesianX(node.lon-lonCorrection,node.lat))
|
||||
append!(nodeYPositions,getCartesianY(node.lon-lonCorrection,node.lat))
|
||||
push!(nodeLabelArray,node.nodeID)
|
||||
end
|
||||
|
||||
for way in filteredWayArray
|
||||
bufferNode = first(way.containedNodeIDs)
|
||||
for node in way.containedNodeIDs
|
||||
if(node == first(way.containedNodeIDs))
|
||||
else
|
||||
Graphs.add_edge!(mdg,get(nodeDict,bufferNode.nodeID,"default value"),get(nodeDict,node.nodeID,"default value"))
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,bufferNode.nodeID,"default value"),get(nodeDict,node.nodeID,"default value")), :maxspeed,way.vmax.forward)
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,bufferNode.nodeID,"default value"),get(nodeDict,node.nodeID,"default value")), :wayID, way.wayID)
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,bufferNode.nodeID,"default value"),get(nodeDict,node.nodeID,"default value")), :length, getEdgelength(node.lat,node.lon,bufferNode.lat,bufferNode.lon))
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,bufferNode.nodeID,"default value"),get(nodeDict,node.nodeID,"default value")), :incline, way.incline.forward)
|
||||
|
||||
Graphs.add_edge!(mdg,get(nodeDict,node.nodeID,"default value"),get(nodeDict,bufferNode.nodeID,"default value"))
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,node.nodeID,"default value"),get(nodeDict,bufferNode.nodeID,"default value")), :maxspeed,way.vmax.backward)
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,node.nodeID,"default value"),get(nodeDict,bufferNode.nodeID,"default value")), :wayID, way.wayID)
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,node.nodeID,"default value"),get(nodeDict,bufferNode.nodeID,"default value")), :length, getEdgelength(node.lat,node.lon,bufferNode.lat,bufferNode.lon))
|
||||
set_prop!(mdg,Graphs.Edge(get(nodeDict,node.nodeID,"default value"),get(nodeDict,bufferNode.nodeID,"default value")), :incline, way.incline.backward)
|
||||
bufferNode = node
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function getNodeColorIndex(issignal::Bool,isswitch::Bool)
|
||||
if(issignal==false&&isswitch==false)
|
||||
return 1
|
||||
elseif(issignal==true&&isswitch==false)
|
||||
return 2
|
||||
elseif(issignal==false&&isswitch==true)
|
||||
return 3
|
||||
else error("signal and switch in one node")
|
||||
end
|
||||
end
|
||||
|
||||
function getCartesianY(lon::Float64,lat::Float64)
|
||||
return cos(deg2rad(lon))*cos(deg2rad(lat))*6371000
|
||||
end
|
||||
|
||||
function getCartesianX(lon::Float64,lat::Float64)
|
||||
return cos(deg2rad(lat))*sin(deg2rad(lon))*6371000
|
||||
end
|
||||
addDatasToDiGraph(getFilteredNodeArray(),getFilteredWayArray())
|
||||
println("Graph created")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The plotGraph-function is used by the user to plot the Graph in it's current data status.
|
||||
# Therefore the allready filled Arrays with the Node-Coordinates will be converted to vectors (necessary for GraphPlot-Package).
|
||||
# Afterwards the function starts to find the horizontal an vertical size for the plot to distort it to an satellite-like view.
|
||||
# Then the function fills the wayLabelArray and the wayColorArray to set them in the graph. The data for the Nodes are allready setted in the nodeColorArray and the nodeLabelArray.
|
||||
# Finaly the function starts the gplot-function from the GraphPlot-Package.
|
||||
# You can change all plot-settings in the gplot-function as it's descripted in the GraphPlot-Package: https://github.com/JuliaGraphs/GraphPlot.jl
|
||||
#
|
||||
function plotGraph()
|
||||
println("start building vectors")
|
||||
vecXCoordinates = vec(nodeXPositions)
|
||||
vecYCoordinates = vec(nodeYPositions)
|
||||
horizontal = (maximum(vecXCoordinates)-minimum(vecXCoordinates))
|
||||
vertical = (maximum(vecYCoordinates)-minimum(vecYCoordinates))
|
||||
wayLabelArray = []
|
||||
wayColorArray = []
|
||||
graphEdges = collect(Graphs.edges(mdg))
|
||||
# println(Graphs.ne(mdg)) # print's the actuell numbers of edges in the Graph
|
||||
for graphEdge in graphEdges
|
||||
push!(wayLabelArray,string(get_prop(mdg,graphEdge,:length))*" m, Way-ID="*string(get_prop(mdg,graphEdge,:wayID))*", maxspeed="*string(get_prop(mdg,graphEdge,:maxspeed))*", incline="*string(round(get_prop(mdg,graphEdge,:incline),digits=4)))
|
||||
push!(wayColorArray, getEdgeColorIndex(get_prop(mdg,graphEdge,:maxspeed)))
|
||||
end
|
||||
nodeColor = [colorant"blue",colorant"red",colorant"orange"]
|
||||
nodefillc = nodeColor[nodeColorArray]
|
||||
edgestrokec = wayColorArray
|
||||
println("start plotting")
|
||||
draw(PDF("DataGraph-Plot.pdf",horizontal, vertical), gplot(mdg, vecXCoordinates, vecYCoordinates,nodelabel=nodeLabelArray, edgelabel=wayLabelArray, edgestrokec = edgestrokec, EDGELINEWIDTH = 1.0 / sqrt(Graphs.nv(g)),nodefillc = nodefillc ,arrowlengthfrac=0.0006 / sqrt(Graphs.nv(g)),NODESIZE = 0.0002 / sqrt(Graphs.nv(g))))
|
||||
# draw(PDF("DataGraph-Plot.pdf"), gplot(mdg, vecXCoordinates, vecYCoordinates,nodelabel=nodeLabelArray, edgelabel=wayLabelArray, edgestrokec = edgestrokec, EDGELINEWIDTH = 1.0 / sqrt(Graphs.nv(g)),nodefillc = nodefillc ,arrowlengthfrac=0.0006 / sqrt(Graphs.nv(g)),NODESIZE = 0.0002 / sqrt(Graphs.nv(g))))
|
||||
# draw(PDF("PlotSaveTestBS-UELZEN.pdf",horizontal, vertical), gplot(mdg, vecXN, vecYN, edgelabel=waylabel, edgestrokec = edgestrokec, EDGELINEWIDTH = 2.5 / sqrt(Graphs.nv(g)),nodefillc = nodefillc ,arrowlengthfrac=0.01 / sqrt(Graphs.nv(g)),NODESIZE = 0.005 / sqrt(Graphs.nv(g))))
|
||||
println("Plot finished. Saved to DataGraph-Plot.pdf")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The getYAMLExportArray-function is normaly used by the exportPathToYAML-function.
|
||||
# It first finds a route and saves the points of the route in "pointsOfRoute".
|
||||
# After that, the exportDataArray will be filled with the parameters for TrainRun.
|
||||
# For the return this exportDataArray will be converted to a vector.
|
||||
#
|
||||
function getYAMLExportArray(startpoint::Int,destinationpoint::Int)
|
||||
exportDataArray=[]
|
||||
sumlength=0
|
||||
pointsOfRoute = Graphs.enumerate_paths(Graphs.dijkstra_shortest_paths(mdg,get(nodeDict,string(startpoint),"default value")),get(nodeDict,string(destinationpoint),"default value"))
|
||||
bufferNode = first(pointsOfRoute)
|
||||
for node in pointsOfRoute
|
||||
if(node==first(pointsOfRoute))
|
||||
else
|
||||
push!(exportDataArray,[round(get_prop(mdg,Graphs.Edge(bufferNode,node), :length)+sumlength,digits=2),parse(Int,get_prop(mdg,Graphs.Edge(bufferNode,node), :maxspeed)),round(get_prop(mdg,Graphs.Edge(bufferNode,node),:incline),digits=4)])
|
||||
sumlength=sumlength+get_prop(mdg,Graphs.Edge(bufferNode,node), :length)
|
||||
bufferNode=node
|
||||
end
|
||||
end
|
||||
dataVector=vec(exportDataArray)
|
||||
println("export-vector created")
|
||||
return dataVector
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The exportPathToYAML-function calls an other function from the "output.jl"-class. Therefore it needs a description (saved in the yaml-file), a filename and the startpoint and the destinationpoint of the route.
|
||||
# It doesn't matter if you've allready filtered the Path onedirectional or not.
|
||||
# Note that it's possible to export only a part of the path of the plot.
|
||||
#
|
||||
function exportPathToYAML(description::String, filename::String, startpoint::Int,destinationpoint::Int)
|
||||
createYAML(description, filename, getYAMLExportArray(startpoint,destinationpoint))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The getEdgelength-function returns the length between two coordinate-positions.
|
||||
# The length is calculated by a formula for spherical geometry, cause the standard coordinates (latitude & longitude) are for a globe and not a typical x-y-chart (cartesian).
|
||||
# It returns a value in meter rounded to two positions after decimal point (cm).
|
||||
#
|
||||
function getEdgelength(lat1,lon1,lat2,lon2)
|
||||
c=acos(sin(lat1*pi/180)*sin(lat2*pi/180)+cos(lat1*pi/180)*cos(lat2*pi/180)*cos(lon1*pi/180-lon2*pi/180))
|
||||
length = round(c*6371000,digits=2)
|
||||
if(length==0.00)
|
||||
return 0.01 #This is necessary because TrainRun is unable to work with an edgelength below 0.01m
|
||||
else return length
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The getEdgeColorIndex-function returns a color for a given String. It's normaly used by the plotGraph()-function.
|
||||
#
|
||||
function getEdgeColorIndex(maxspeed::String)
|
||||
if(maxspeed=="UNKNOWN")
|
||||
return colorant"orange"
|
||||
elseif(maxspeed!="UNKNOWN")
|
||||
return colorant"green"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# filterOnedirectional needs a startpoint and an endpoint to remove all unused edges.
|
||||
# CAUTION!: This function is seraching for the shortest path in the graph.
|
||||
# If there are multiple possiblitys to connect startpoint and endpoint, this function may not find the astimated path.
|
||||
# Prepare the Graph with the "removeWayFromGraph()"-function so there is only one possible path in the graph.
|
||||
#
|
||||
function filterOnedirectional(startpoint::Int,destinationpoint::Int)
|
||||
pointsOfRoute = Graphs.enumerate_paths(Graphs.dijkstra_shortest_paths(mdg,get(nodeDict,string(destinationpoint),"default value")),get(nodeDict,string(startpoint),"default value"))
|
||||
remainingEdges = []
|
||||
bufferNode = first(pointsOfRoute)
|
||||
for node in pointsOfRoute
|
||||
if(node==first(pointsOfRoute))
|
||||
else
|
||||
push!(remainingEdges,Graphs.Edge(node,bufferNode))
|
||||
bufferNode=node
|
||||
end
|
||||
end
|
||||
|
||||
for edge in collect(MetaGraphs.edges(mdg))
|
||||
if(in(edge,remainingEdges))
|
||||
else MetaGraphs.rem_edge!(mdg,edge)
|
||||
end
|
||||
end
|
||||
println("path filtered between "*string(startpoint)*" and "*string(destinationpoint))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The changeWaySpeed-function changes the speed of a way. It doesn't matter what the previous value was.
|
||||
# NOTE!: If you haven't allready filtered the path onedirectional, you change the speed for both directions.
|
||||
# It ist highly recommended to filter onedirectional bevore using this function.
|
||||
# To filter onedirectional you can use the filterOnedirectional-function.
|
||||
#
|
||||
function changeWaySpeed(wayID::Int,newSpeed::Int)
|
||||
for edge in MetaGraphs.edges(mdg)
|
||||
if(get_prop(mdg,edge, :wayID)==string(wayID))
|
||||
set_prop!(mdg,edge, :maxspeed, string(newSpeed))
|
||||
end
|
||||
end
|
||||
println("set new Wayspeed "*string(newSpeed)*" for Way "*string(wayID))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The removeWayFromGraph-function removes a given way from the graph, if the given way (found by it's OSM-ID) is in the graph.
|
||||
#
|
||||
function removeWayFromGraph(wayID::Int)
|
||||
for edge in collect(MetaGraphs.edges(mdg))
|
||||
if(get_prop(mdg,edge, :wayID)==string(wayID))
|
||||
clear_props!(mdg,edge)
|
||||
Graphs.rem_edge!(mdg,edge)
|
||||
end
|
||||
end
|
||||
println("Way "*string(wayID)*" was removed from the Graph")
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
# This is the main-module
|
||||
# All relevant functions are callable from here
|
||||
# This prototype can create path-files for the TrainRun-Tool (https://doi.org/10.5281/zenodo.6448563)
|
||||
# Cause of some problems the typical structure with modules isn't yet setted
|
||||
|
||||
|
||||
include("./input.jl")
|
||||
include("./DataGraph.jl")
|
||||
include("./output.jl")
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
using LightOSM, HTTP, LightXML
|
||||
|
||||
|
||||
#
|
||||
# This function was created in the LightOSM-Package and is under the Copyright of this Package -> https://github.com/DeloitteDigitalAPAC/LightOSM.jl
|
||||
# For the usage in this prototype the original LightOSM-function was addapted.
|
||||
# The function checks if the overpass-server are available.
|
||||
# Adaption of the original function: a print-information was removed.
|
||||
#
|
||||
function overpass_request(data::String)::String
|
||||
LightOSM.check_overpass_server_availability()
|
||||
return String(HTTP.post("http://overpass-api.de/api/interpreter",body=data).body)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function was created in the LightOSM-Package and is under the Copyright of this Package -> https://github.com/DeloitteDigitalAPAC/LightOSM.jl
|
||||
# For the usage in this prototype the original LightOSM-function was addapted.
|
||||
# It calls the overpass_request-function with the given string and a filepath for the datafile, which is also created with this function.
|
||||
# The filetype is allways setted to "osm".
|
||||
# Adaption of the original function: some given parameters were removed, additionally there usage in the function.
|
||||
#
|
||||
function download_osm_network(save_to_file_location,datas)::Union{XMLDocument,Dict{String,Any}}
|
||||
data = overpass_request(datas)
|
||||
#@info "Downloaded osm network data from $(["$k: $v" for (k, v) in download_kwargs]) in $download_format format"
|
||||
|
||||
if !(save_to_file_location isa Nothing)
|
||||
save_to_file_location = LightOSM.validate_save_location(save_to_file_location, "osm")
|
||||
write(save_to_file_location, data)
|
||||
@info "Saved osm network data to disk: $save_to_file_location"
|
||||
end
|
||||
|
||||
deserializer = LightOSM.string_deserializer(:osm)
|
||||
return deserializer(data)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This funtion is used to call the download_osm_network-function with a specific download-query-String, which is created by this function with the given OSM-ID.
|
||||
#
|
||||
function getOSMRelationXML(relationID::Int)
|
||||
return download_osm_network("./Buffer.osm","[out:xml][timeout:25];relation("*string(relationID)*");(._;>>;);out;")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This funtion is used to call the download_osm_network-function with a specific download-query-String, which is created by this function with the given OSM-ID.
|
||||
#
|
||||
function getOSMWayXML(wayID::Int)
|
||||
return download_osm_network("./Buffer.osm","[out:xml][timeout:25];way("*string(wayID)*");(._;>>;);out;")
|
||||
end
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
|
||||
using LightXML
|
||||
include("./download.jl")
|
||||
# `
|
||||
# TODO: change variable names like Array(which are most time Any's).
|
||||
# `
|
||||
|
||||
wayArray = []
|
||||
nodeArray = []
|
||||
filteredWayArray = []
|
||||
filteredNodeArray = []
|
||||
|
||||
|
||||
#
|
||||
# This function returns the filteredWayArray (which is an Any).
|
||||
#
|
||||
function getFilteredWayArray()
|
||||
return filteredWayArray
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function returns the filteredNodeArray (which is an Any).
|
||||
#
|
||||
function getFilteredNodeArray()
|
||||
return filteredNodeArray
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function does a filtering of the given xroot and removes all members with a specific role (for example platform-data).
|
||||
# To get the information which data are relevant, the function needs the relationID where the members are listet.
|
||||
#
|
||||
function filterAllWaysByDataFromRelation(relationID::Union{String, Int},xroot)
|
||||
ID=""
|
||||
if(typeof(relationID)==Int)
|
||||
ID=string(relationID)
|
||||
else
|
||||
ID=relationID
|
||||
end
|
||||
xmlRelations=get_elements_by_tagname(xroot, "relation")
|
||||
for relation in xmlRelations
|
||||
if(attribute(relation,"id")==ID)
|
||||
childnodesOfRelation = collect(child_nodes(relation))
|
||||
for elements in childnodesOfRelation
|
||||
if is_elementnode(elements)
|
||||
if name(elements) == "member"
|
||||
g = XMLElement(elements)
|
||||
if(attribute(g,"role")=="")
|
||||
addToFilteredWayArray(getWayByID(attribute(g,"ref")))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function checks the data-type of the given wayID and afterwards calls the addToFilteredWayArray-function with the ID.
|
||||
#
|
||||
function filterWayToFilteredWayArray(wayID::Union{String, Int})
|
||||
ID=""
|
||||
if(typeof(wayID)==Int)
|
||||
ID=string(wayID)
|
||||
else
|
||||
ID=wayID
|
||||
end
|
||||
addToFilteredWayArray(getWayByID(ID))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function adds all nodes of all ways to the filteredNodeArray by calling the addToFilteredNodeArray-funtion.
|
||||
#
|
||||
function filterAllNodesByDataFromFilteredWayArray(filteredWayArray::Any)
|
||||
for way in filteredWayArray
|
||||
nodes = way.containedNodeIDs
|
||||
for node in nodes
|
||||
addToFilteredNodeArray(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function checks if a way is already saved in the filteredWayArray and returns the result with a Bool.
|
||||
#
|
||||
function checkIfAllreadyInFilteredWayArray(newway::NamedTuple)
|
||||
for way in filteredWayArray
|
||||
if(way==newway)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function checks if a node is already saved in the filteredNodeArray and returns the result with a Bool.
|
||||
#
|
||||
function checkIfAllreadyInFilteredNodeArray(newnode::NamedTuple)
|
||||
for node in filteredNodeArray
|
||||
if(node==newnode)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function adds a node to the filteredNodeArray if it's not already saved there.
|
||||
#
|
||||
function addToFilteredNodeArray(node::NamedTuple)
|
||||
if(!checkIfAllreadyInFilteredNodeArray(node))
|
||||
push!(filteredNodeArray,node)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function adds a way to the filteredWayArray if it's not already saved there.
|
||||
#
|
||||
function addToFilteredWayArray(way::NamedTuple)
|
||||
if(!checkIfAllreadyInFilteredWayArray(way))
|
||||
push!(filteredWayArray,way)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function returns a node-NamedTuple. Therefore the node-ID is required.
|
||||
#
|
||||
function getNodeByID(nodeID::Union{Int,String})
|
||||
if(typeof(nodeID)==Int)
|
||||
for node in nodeArray
|
||||
if(node.nodeID==string(nodeID))
|
||||
return node
|
||||
end
|
||||
end
|
||||
else
|
||||
for node in nodeArray
|
||||
if(node.nodeID==nodeID)
|
||||
return node
|
||||
end
|
||||
end
|
||||
end
|
||||
@debug "missed Node called. NodeID that is missed is: $nodeID"
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function returns a way-NamedTuple from the wayArray by the wayID.
|
||||
#
|
||||
function getWayByID(wayID::Union{Int,String})
|
||||
if(typeof(wayID)==Int)
|
||||
for way in wayArray
|
||||
if(way.wayID==string(wayID))
|
||||
return way
|
||||
end
|
||||
end
|
||||
else
|
||||
for way in wayArray
|
||||
if(way.wayID==wayID)
|
||||
return way
|
||||
end
|
||||
end
|
||||
end
|
||||
@debug "missed Way called. WayID that is missed is: $wayID"
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function returns a way in the filteredWayArray by the wayID.
|
||||
#
|
||||
function getWayFromFilteredWayArrayByID(wayID::Union{Int,String})
|
||||
if(typeof(wayID)==Int)
|
||||
for way in filteredWayArray
|
||||
if(way.wayID==string(wayID))
|
||||
return way
|
||||
end
|
||||
end
|
||||
else
|
||||
for way in filteredWayArray
|
||||
if(way.wayID==wayID)
|
||||
return way
|
||||
end
|
||||
end
|
||||
end
|
||||
@debug "missed Way called. WayID that is missed is: $wayID"
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The createNodes-function transfers the data from a given XMLElement to a NamedTuple and pushs this NamedTuple to the filteredNodeArray.
|
||||
# In the transfer of the data the node-ID, the lat and lon coordinates and additional Bools for signal and switch information are stored in the NamedTuple.
|
||||
#
|
||||
function createNodes(xroot::XMLElement)
|
||||
xmlNodes = get_elements_by_tagname(xroot, "node")
|
||||
for node in xmlNodes
|
||||
issignal = false
|
||||
isswitch = false
|
||||
if(has_children(node))
|
||||
element = child_nodes(node)
|
||||
for c in element
|
||||
if(is_elementnode(c))
|
||||
e= XMLElement(c)
|
||||
if(attribute(e,"k")=="railway" && attribute(e,"v")=="signal")
|
||||
issignal=true
|
||||
end
|
||||
if(attribute(e,"k")=="railway:switch"||(attribute(e,"k")=="railway"&&attribute(e,"v")=="switch"))
|
||||
isswitch=true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
nd = (nodeID = attribute(node,"id"), lat=parse(Float64,attribute(node,"lat")), lon=parse(Float64,attribute(node,"lon")), issignal=issignal, isswitch=isswitch)
|
||||
push!(nodeArray,nd)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The createWay-function transfers the data from a given XMLElement to a NamedTuple and pushs this NamedTuple to the filteredWayArray
|
||||
# In the transfer of the data the way-ID, the containened Nodes (NamedTuples of the nodes), the maxspeed (NamedTuples because of direction-dependent maxspeeds) and the inclines (NamedTuples because of direction-dependent inclines) are stored in the NamedTuple.
|
||||
#
|
||||
function createWays(xroot::XMLElement)
|
||||
xmlWays = get_elements_by_tagname(xroot, "way")
|
||||
for way in xmlWays
|
||||
w = (wayID = attribute(way,"id"), containedNodeIDs = getWayNodeIDs(way),vmax=getWayMaxspeed(way),incline=getWayIncline(way))
|
||||
push!(wayArray,w)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function returns a NamedTuple with the direction-dependent inclines of a given way-XMLElement.
|
||||
# The values in the OSM are percent while in german train-tracks the unit perthousand is common.
|
||||
# To avoid an unit-change-mistake, the units are converted in this function.
|
||||
#
|
||||
function getWayIncline(xWay::XMLElement)
|
||||
elements = child_nodes(xWay.node)
|
||||
incline = 0.0
|
||||
for e in elements
|
||||
if(is_elementnode(e))
|
||||
x = XMLElement(e)
|
||||
if(attribute(x,"k")=="incline")
|
||||
value = attribute(x,"v")
|
||||
if(value=="down"||value=="up")
|
||||
else incline = parse(Float64,replace(attribute(x,"v"),"%"=>""))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return (forward=incline*10,backward=incline*(-10)) # *10 necessary for change from % to per thousand -> (typically used for german-rail-incline)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# The getWayMaxspeed-function returns a NamedTuple with the OSM-maxspeed-data in which the maxspeed is listet with the direction for which the value is valid.
|
||||
# If the OSM-data specify a direction with :forward and :backward, this will be safed in the NamedTuple.
|
||||
# If there is no specification of the direction, both will be saved with the maxspeed-value.
|
||||
# If there is no maxspeed in one or both directions, the value(s) will be saved with "UNKNOWN".
|
||||
#
|
||||
function getWayMaxspeed(xWay::XMLElement)
|
||||
element = child_nodes(xWay.node)
|
||||
maxspeedforward = "UNKNOWN"
|
||||
maxspeedbackward = "UNKNOWN"
|
||||
for c in element
|
||||
if(is_elementnode(c))
|
||||
e = XMLElement(c)
|
||||
if(attribute(e,"k")=="maxspeed")
|
||||
return maxspeed = (forward = attribute(e,"v"), backward = attribute(e,"v"))
|
||||
elseif (attribute(e,"k")=="maxspeed:forward")
|
||||
maxspeedforward = attribute(e,"v")
|
||||
elseif (attribute(e,"k")=="maxspeed:backward")
|
||||
maxspeedbackward = attribute(e,"v")
|
||||
end
|
||||
end
|
||||
end
|
||||
if(maxspeedforward=="UNKNOWN"&&maxspeedbackward=="UNKNOWN")
|
||||
return maxspeed=(forward = "UNKNOWN", backward = "UNKNOWN")
|
||||
else return maxspeed = (forward = maxspeedforward, backward = maxspeedbackward)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function returns an Any which contains the NamedTuples of the Nodes from the given way-XMLElement.
|
||||
# To get the Nodes for the Any, the getNodeByID-funtion is used.
|
||||
#
|
||||
function getWayNodeIDs(xWay::XMLElement)
|
||||
nodeIDs = []
|
||||
element = child_nodes(xWay.node)
|
||||
for c in element
|
||||
if(is_elementnode(c))
|
||||
e = XMLElement(c)
|
||||
if(name(e)=="nd")
|
||||
#push!(nodeIDs,(attribute(e,"ref")))
|
||||
#or entweder nur die Nummer oder den ganzen Knoten
|
||||
push!(nodeIDs,getNodeByID(attribute(e,"ref")))
|
||||
end
|
||||
end
|
||||
end
|
||||
# println(attribute(xWay, "id")," = ", length(nodeIDs))
|
||||
return nodeIDs
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function is used to add an OSM-Relation to the prototype memory.
|
||||
# In contrast to the "addRelation"-funtion, this function reads the data from a given XML/OSM-file.
|
||||
# Therefore the filepath and the OSM-Relation-ID is required.
|
||||
# With these data the function calls the createWays/createNodes-functions and filters the NamedTuples with the filter***-functions.
|
||||
#
|
||||
function addRelationFromFile(id::Int,filepath::String)
|
||||
xdoc = parse_file(filepath)
|
||||
xroot = root(xdoc)
|
||||
createNodes(xroot)
|
||||
createWays(xroot)
|
||||
println(length(nodeArray)," Nodes in nodeArray")
|
||||
println(length(wayArray)," Ways in wayArray")
|
||||
filterAllWaysByDataFromRelation(id,xroot)
|
||||
filterAllNodesByDataFromFilteredWayArray(filteredWayArray)
|
||||
println(length(filteredWayArray)," Ways in filteredWayArray")
|
||||
println(length(filteredNodeArray)," Nodes in filteredNodeArray")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function is used to add an OSM-Way to the prototype memory.
|
||||
# In contrast to the "addWay"-funtion this function reads the data from a given XML/OSM-file.
|
||||
# Therefore the filepath and the OSM-Way-ID is required.
|
||||
# With these data the function calls the createWays/createNodes-functions and filters the NamedTuples with the filter***-functions.
|
||||
#
|
||||
function addWayFromFile(id::Int,filepath::String)
|
||||
xdoc = parse_file(filepath)
|
||||
xroot = root(xdoc)
|
||||
createNodes(xroot)
|
||||
createWays(xroot)
|
||||
println(length(nodeArray)," Nodes in nodeArray")
|
||||
println(length(wayArray)," Ways in wayArray")
|
||||
filterWayToFilteredWayArray(id)
|
||||
filterAllNodesByDataFromFilteredWayArray(filteredWayArray)
|
||||
println(length(filteredWayArray)," Ways in filteredWayArray")
|
||||
println(length(filteredNodeArray)," Nodes in filteredNodeArray")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function is used to add an OSM-Relation to the prototype memory.
|
||||
# It calls the Overpass-API via the download-class. Therefore the OSM-Relation-ID is required.
|
||||
# After the download the function reads the Buffer.osm-file with the data and imports them.
|
||||
# With these data the function calls the createWays/createNodes-functions and filters the NamedTuples with the filter***-functions.
|
||||
#
|
||||
function addRelation(id::Int)
|
||||
getOSMRelationXML(id)
|
||||
xdoc = parse_file("./Buffer.osm")
|
||||
xroot = root(xdoc)
|
||||
createNodes(xroot)
|
||||
createWays(xroot)
|
||||
println(length(nodeArray)," Nodes in nodeArray")
|
||||
println(length(wayArray)," Ways in wayArray")
|
||||
filterAllWaysByDataFromRelation(id,xroot)
|
||||
filterAllNodesByDataFromFilteredWayArray(filteredWayArray)
|
||||
println(length(filteredWayArray)," Ways in filteredWayArray")
|
||||
println(length(filteredNodeArray)," Nodes in filteredNodeArray")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function is used to add an OSM-Way to the prototype memory.
|
||||
# It calls the Overpass-API via the download-class. Therefore the OSM-Way-ID is required.
|
||||
# After the download the function reads the Buffer.osm-file with the data and imports them.
|
||||
# With these data the function calls the createWays/createNodes-functions and filters the NamedTuples with the filter***-functions.
|
||||
#
|
||||
function addWay(id::Int)
|
||||
getOSMWayXML(id)
|
||||
xdoc = parse_file("./Buffer.osm")
|
||||
xroot = root(xdoc)
|
||||
createNodes(xroot)
|
||||
createWays(xroot)
|
||||
println(length(nodeArray)," Nodes in nodeArray")
|
||||
println(length(wayArray)," Ways in wayArray")
|
||||
filterWayToFilteredWayArray(id)
|
||||
filterAllNodesByDataFromFilteredWayArray(filteredWayArray)
|
||||
println(length(filteredWayArray)," Ways in filteredWayArray")
|
||||
println(length(filteredNodeArray)," Nodes in filteredNodeArray")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function is used to clear all collected data in any Arrays.
|
||||
#
|
||||
function clearAllArrays()
|
||||
empty!(wayArray)
|
||||
empty!(nodeArray)
|
||||
empty!(filteredWayArray)
|
||||
empty!(filteredNodeArray)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function prints the ways without maxspeed-information.
|
||||
#
|
||||
function checkWaySpeed()
|
||||
waysWithoutSpeed=[]
|
||||
for way in filteredWayArray
|
||||
if(way.vmax.forward==""||way.vmax.backward=="")
|
||||
push!(waysWithoutSpeed,way)
|
||||
end
|
||||
end
|
||||
println("The following ways have none or one-directional only maxpeed")
|
||||
for way in waysWithoutSpeed
|
||||
println(way.wayID," maxspeed forward = ", way.vmax.forward, ", maxspeed backward = ",way.vmax.backward)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function can set the speed of a way. Therefore maxspeed-information for both direction and the OSM-ID of the Way is required.
|
||||
#
|
||||
function setWaySpeed(wayID::Union{Int,String}, maxspeedforward::Int, maxspeedbackward::Int)
|
||||
w = getWayFromFilteredWayArrayByID(wayID)
|
||||
newW = (wayID = w.wayID, containedNodeIDs = w.containedNodeIDs,vmax=(forward = string(maxspeedforward), backward = string(maxspeedbackward)))
|
||||
replace!(filteredWayArray,w=>newW)
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# This function can remove a way from the data. Therefore the OSM-ID of the Way is required.
|
||||
#
|
||||
function removeWay(id::Int)
|
||||
println(indexin(getWayByID(id),filteredWayArray))
|
||||
println("removed the way")
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
using YAML
|
||||
#
|
||||
# The createYAML-function produce the YAML-output-file of this prototype.
|
||||
# The file is named with the given filename which has to be in a "*name*.yaml" style (so with the .yaml).
|
||||
# A given description is needed and will be setted in the file.
|
||||
#
|
||||
# In this version there is no information of the data-source in the file.
|
||||
# TODO: add data-source information (OpenStreetMap).
|
||||
#
|
||||
function createYAML(description::String, filename::String, datas::Any)
|
||||
dataVector=datas
|
||||
d=Dict()
|
||||
d2=Dict(:name => description, :sectionStarts => nothing, :sectionStarts_kmh => dataVector)
|
||||
push!(d,:path => d2)
|
||||
YAML.write_file(filename, d)
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue