171 lines
6.0 KiB
C#
171 lines
6.0 KiB
C#
|
using System.Globalization;
|
||
|
using System.Xml;
|
||
|
using OSMDatastructure;
|
||
|
using OSMImporter;
|
||
|
|
||
|
namespace Server;
|
||
|
|
||
|
public static class XmlImporter
|
||
|
{
|
||
|
private static readonly XmlReaderSettings readerSettings = new()
|
||
|
{
|
||
|
IgnoreWhitespace = true,
|
||
|
IgnoreComments = true
|
||
|
};
|
||
|
|
||
|
public static HashSet<OsmNode> ImportXml(string filePath)
|
||
|
{
|
||
|
if (!File.Exists(filePath))
|
||
|
throw new FileNotFoundException();
|
||
|
|
||
|
Console.WriteLine(string.Format("[{0}] Getting highwayNodeIds...", DateTime.Now.ToLocalTime()));
|
||
|
FileStream xmlFileStream = new FileStream(filePath, FileMode.Open);
|
||
|
HashSet<ulong> requiredNodeIds = GetHighwayNodeIds(XmlReader.Create(xmlFileStream, readerSettings));
|
||
|
xmlFileStream.Position = 0;
|
||
|
|
||
|
Console.WriteLine(string.Format("[{0}] Importing Nodes...", DateTime.Now.ToLocalTime()));
|
||
|
Dictionary<ulong, OsmNode> nodes =
|
||
|
GetHighwayNodesFromIds(XmlReader.Create(xmlFileStream, readerSettings), requiredNodeIds);
|
||
|
requiredNodeIds.Clear();
|
||
|
xmlFileStream.Position = 0;
|
||
|
|
||
|
Console.WriteLine(string.Format("[{0}] Importing Ways...", DateTime.Now.ToLocalTime()));
|
||
|
HashSet<OsmNode> retNodes = ConnectNodes(XmlReader.Create(xmlFileStream, readerSettings), nodes);
|
||
|
nodes.Clear();
|
||
|
|
||
|
return retNodes;
|
||
|
}
|
||
|
|
||
|
public static HashSet<Region> SplitIntoRegions(HashSet<OsmNode> nodes)
|
||
|
{
|
||
|
Console.WriteLine(string.Format("[{0}] Splitting into Regions...", DateTime.Now.ToLocalTime()));
|
||
|
Dictionary<ulong, Region> retRegions = new();
|
||
|
foreach (OsmNode node in nodes)
|
||
|
{
|
||
|
ulong regionHash = node.coordinates.GetRegionHash();
|
||
|
if(retRegions.ContainsKey(regionHash))
|
||
|
{
|
||
|
retRegions[regionHash].nodes.Add(node);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Region newRegion = new Region(regionHash);
|
||
|
newRegion.nodes.Add(node);
|
||
|
retRegions.Add(regionHash, newRegion);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retRegions.Values.ToHashSet();
|
||
|
}
|
||
|
|
||
|
private static readonly NumberFormatInfo decimalInfo = new()
|
||
|
{
|
||
|
NumberDecimalSeparator = "."
|
||
|
};
|
||
|
private static HashSet<ulong> GetHighwayNodeIds(XmlReader xmlReader)
|
||
|
{
|
||
|
HashSet<ulong> retSet = new();
|
||
|
bool isHighway;
|
||
|
HashSet<ulong> currentIds = new();
|
||
|
while (xmlReader.ReadToFollowing("way"))
|
||
|
{
|
||
|
isHighway = false;
|
||
|
currentIds.Clear();
|
||
|
XmlReader wayReader = xmlReader.ReadSubtree();
|
||
|
while (wayReader.Read())
|
||
|
{
|
||
|
if (xmlReader.Name == "tag" && xmlReader.GetAttribute("k")!.Equals("highway"))
|
||
|
{
|
||
|
isHighway = true;
|
||
|
}
|
||
|
else if (xmlReader.Name == "nd")
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
currentIds.Add(Convert.ToUInt64(xmlReader.GetAttribute("ref")));
|
||
|
}
|
||
|
catch (FormatException) { };
|
||
|
}
|
||
|
}
|
||
|
if (isHighway)
|
||
|
{
|
||
|
retSet.UnionWith(currentIds);
|
||
|
}
|
||
|
wayReader.Close();
|
||
|
}
|
||
|
xmlReader.Close();
|
||
|
|
||
|
return retSet;
|
||
|
}
|
||
|
|
||
|
private static Dictionary<ulong, OsmNode> GetHighwayNodesFromIds(XmlReader xmlReader, HashSet<ulong> ids)
|
||
|
{
|
||
|
Dictionary<ulong, OsmNode> retDict = new();
|
||
|
|
||
|
while (xmlReader.ReadToFollowing("node"))
|
||
|
{
|
||
|
ulong id = Convert.ToUInt64(xmlReader.GetAttribute("id"));
|
||
|
if (ids.Contains(id))
|
||
|
{
|
||
|
float lat = Convert.ToSingle(xmlReader.GetAttribute("lat")!, decimalInfo);
|
||
|
float lon = Convert.ToSingle(xmlReader.GetAttribute("lon")!, decimalInfo);
|
||
|
retDict.Add(id, new OsmNode(lat, lon));
|
||
|
}
|
||
|
}
|
||
|
xmlReader.Close();
|
||
|
|
||
|
return retDict;
|
||
|
}
|
||
|
|
||
|
private static HashSet<OsmNode> ConnectNodes(XmlReader xmlReader, Dictionary<ulong, OsmNode> dict)
|
||
|
{
|
||
|
while (xmlReader.ReadToFollowing("way"))
|
||
|
{
|
||
|
Dictionary<OsmEdge.tagType, object> tags = new();
|
||
|
List<ulong> wayNodeIds = new();
|
||
|
XmlReader wayReader = xmlReader.ReadSubtree();
|
||
|
while (wayReader.Read())
|
||
|
{
|
||
|
if (xmlReader.Name == "tag")
|
||
|
{
|
||
|
KeyValuePair<OsmEdge.tagType, object> tag =
|
||
|
OsmEdge.ConvertToTag(wayReader.GetAttribute("k")!, wayReader.GetAttribute("v")!);
|
||
|
tags.TryAdd(tag.Key, tag.Value);
|
||
|
}
|
||
|
else if (xmlReader.Name == "nd")
|
||
|
{
|
||
|
wayNodeIds.Add(Convert.ToUInt64(xmlReader.GetAttribute("ref")));
|
||
|
}
|
||
|
}
|
||
|
if (tags.ContainsKey(OsmEdge.tagType.highway))
|
||
|
{
|
||
|
ulong[] ids = wayNodeIds.Where(dict.ContainsKey).ToArray();
|
||
|
for (int i = 0; i < ids.Length - 1; i++)
|
||
|
{
|
||
|
OsmNode n1 = dict[ids[i]];
|
||
|
OsmNode n2 = dict[ids[i + 1]];
|
||
|
if (tags.ContainsKey(OsmEdge.tagType.oneway) && (bool)tags[OsmEdge.tagType.oneway])
|
||
|
{
|
||
|
if (tags.ContainsKey(OsmEdge.tagType.forward) && !(bool)tags[OsmEdge.tagType.forward])
|
||
|
{
|
||
|
n2.edges.Add(new OsmEdge(n1.coordinates, tags));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
n1.edges.Add(new OsmEdge(n2.coordinates, tags));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
n1.edges.Add(new OsmEdge(n2.coordinates, tags));
|
||
|
n2.edges.Add(new OsmEdge(n1.coordinates, tags));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
wayReader.Close();
|
||
|
}
|
||
|
xmlReader.Close();
|
||
|
|
||
|
return dict.Values.ToHashSet();
|
||
|
}
|
||
|
}
|