diff --git a/Server/XmlImporter.cs b/Server/XmlImporter.cs new file mode 100644 index 0000000..16e6f3a --- /dev/null +++ b/Server/XmlImporter.cs @@ -0,0 +1,171 @@ +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 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 requiredNodeIds = GetHighwayNodeIds(XmlReader.Create(xmlFileStream, readerSettings)); + xmlFileStream.Position = 0; + + Console.WriteLine(string.Format("[{0}] Importing Nodes...", DateTime.Now.ToLocalTime())); + Dictionary nodes = + GetHighwayNodesFromIds(XmlReader.Create(xmlFileStream, readerSettings), requiredNodeIds); + requiredNodeIds.Clear(); + xmlFileStream.Position = 0; + + Console.WriteLine(string.Format("[{0}] Importing Ways...", DateTime.Now.ToLocalTime())); + HashSet retNodes = ConnectNodes(XmlReader.Create(xmlFileStream, readerSettings), nodes); + nodes.Clear(); + + return retNodes; + } + + public static HashSet SplitIntoRegions(HashSet nodes) + { + Console.WriteLine(string.Format("[{0}] Splitting into Regions...", DateTime.Now.ToLocalTime())); + Dictionary 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 GetHighwayNodeIds(XmlReader xmlReader) + { + HashSet retSet = new(); + bool isHighway; + HashSet 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 GetHighwayNodesFromIds(XmlReader xmlReader, HashSet ids) + { + Dictionary 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 ConnectNodes(XmlReader xmlReader, Dictionary dict) + { + while (xmlReader.ReadToFollowing("way")) + { + Dictionary tags = new(); + List wayNodeIds = new(); + XmlReader wayReader = xmlReader.ReadSubtree(); + while (wayReader.Read()) + { + if (xmlReader.Name == "tag") + { + KeyValuePair 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(); + } +} \ No newline at end of file