2023-03-30 18:25:12 +02:00
|
|
|
using System.Globalization;
|
2023-03-31 21:56:27 +02:00
|
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
2023-03-30 18:25:12 +02:00
|
|
|
using System.Xml;
|
2023-03-31 21:56:27 +02:00
|
|
|
using OSMDatastructure.Graph;
|
2023-03-30 18:25:12 +02:00
|
|
|
|
|
|
|
namespace Server;
|
|
|
|
|
|
|
|
public class RegionConverter
|
|
|
|
{
|
|
|
|
private static readonly XmlReaderSettings ReaderSettings = new()
|
|
|
|
{
|
|
|
|
IgnoreWhitespace = true,
|
|
|
|
IgnoreComments = true
|
|
|
|
};
|
|
|
|
private static readonly NumberFormatInfo decimalInfo = new()
|
|
|
|
{
|
|
|
|
NumberDecimalSeparator = "."
|
|
|
|
};
|
2023-03-31 21:56:27 +02:00
|
|
|
|
2023-04-01 00:40:06 +02:00
|
|
|
public const string NodesFileName = "region.nodes";
|
|
|
|
public const string WaysFileName = "region.ways";
|
2023-04-01 00:52:13 +02:00
|
|
|
public const string tagsFileName = "region.tags";
|
2023-03-30 18:25:12 +02:00
|
|
|
|
2023-03-31 21:56:27 +02:00
|
|
|
public static void ConvertXMLToRegions(string filePath, string outputPath)
|
2023-03-30 18:25:12 +02:00
|
|
|
{
|
|
|
|
if (!File.Exists(filePath))
|
|
|
|
throw new FileNotFoundException();
|
2023-03-31 21:56:27 +02:00
|
|
|
if (!Directory.Exists(outputPath))
|
|
|
|
Directory.CreateDirectory(outputPath);
|
2023-03-30 18:25:12 +02:00
|
|
|
|
2023-03-31 21:56:27 +02:00
|
|
|
Console.WriteLine("Converting Nodes...");
|
2023-03-30 18:25:12 +02:00
|
|
|
FileStream xmlFileStream = new FileStream(filePath, FileMode.Open);
|
2023-03-31 21:56:27 +02:00
|
|
|
Dictionary<ulong, ulong> nodeIdRegionDict = GetNodesAndRegions(XmlReader.Create(xmlFileStream, ReaderSettings), outputPath);
|
2023-03-30 18:25:12 +02:00
|
|
|
xmlFileStream.Position = 0;
|
|
|
|
|
2023-03-31 21:56:27 +02:00
|
|
|
Console.WriteLine("Converting Ways...");
|
|
|
|
ImportWays(XmlReader.Create(xmlFileStream, ReaderSettings), nodeIdRegionDict, outputPath);
|
2023-03-30 18:25:12 +02:00
|
|
|
}
|
|
|
|
|
2023-03-31 21:56:27 +02:00
|
|
|
private static Dictionary<ulong, ulong> GetNodesAndRegions(XmlReader xmlReader, string outputPath)
|
2023-03-30 18:25:12 +02:00
|
|
|
{
|
2023-03-31 21:56:27 +02:00
|
|
|
BinaryFormatter bFormatter = new BinaryFormatter();
|
|
|
|
Dictionary<ulong, ulong> nodeRegions = new();
|
|
|
|
Dictionary<ulong, FileStream> regionFileStreams = new();
|
|
|
|
Dictionary<ulong, OsmNode> tmpAllNodes = new();
|
2023-04-01 00:40:06 +02:00
|
|
|
bool isHighway;
|
2023-03-31 21:56:27 +02:00
|
|
|
HashSet<ulong> currentIds = new();
|
|
|
|
while (xmlReader.Read())
|
|
|
|
{
|
|
|
|
if (xmlReader.Name == "node")
|
|
|
|
{
|
|
|
|
ulong id = Convert.ToUInt64(xmlReader.GetAttribute("id")!);
|
|
|
|
float lat = Convert.ToSingle(xmlReader.GetAttribute("lat")!, decimalInfo);
|
|
|
|
float lon = Convert.ToSingle(xmlReader.GetAttribute("lon")!, decimalInfo);
|
|
|
|
tmpAllNodes.TryAdd(id, new OsmNode(id, lat, lon));
|
|
|
|
}
|
|
|
|
else if (xmlReader.Name == "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
|
|
|
|
{
|
|
|
|
ulong id = Convert.ToUInt64(xmlReader.GetAttribute("ref")!);
|
|
|
|
currentIds.Add(id);
|
|
|
|
}
|
|
|
|
catch (FormatException) { };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
wayReader.Close();
|
|
|
|
|
|
|
|
foreach (ulong nodeId in currentIds.Where(key => tmpAllNodes.ContainsKey(key)))
|
|
|
|
{
|
|
|
|
if (isHighway)
|
|
|
|
{
|
|
|
|
ulong regionHash = Coordinates.GetRegionHashCode(tmpAllNodes[nodeId].coordinates);
|
|
|
|
FileStream nodesRegionStream;
|
|
|
|
if(regionFileStreams.ContainsKey(regionHash))
|
|
|
|
nodesRegionStream = regionFileStreams[regionHash];
|
|
|
|
else
|
|
|
|
{
|
|
|
|
string regionPath = Path.Combine(outputPath, regionHash.ToString());
|
|
|
|
Directory.CreateDirectory(regionPath);
|
|
|
|
string nodesRegionPath = Path.Combine(regionPath, NodesFileName);
|
|
|
|
nodesRegionStream = new FileStream(nodesRegionPath, FileMode.Create);
|
|
|
|
regionFileStreams.Add(regionHash, nodesRegionStream);
|
|
|
|
}
|
|
|
|
nodeRegions.Add(nodeId, regionHash);
|
|
|
|
|
|
|
|
#pragma warning disable SYSLIB0011 //eheheh
|
|
|
|
bFormatter.Serialize(nodesRegionStream, tmpAllNodes[nodeId]);
|
|
|
|
#pragma warning restore SYSLIB0011
|
|
|
|
}
|
|
|
|
tmpAllNodes.Remove(nodeId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
xmlReader.Close();
|
|
|
|
return nodeRegions;
|
|
|
|
}
|
2023-04-01 00:52:13 +02:00
|
|
|
|
2023-03-31 21:56:27 +02:00
|
|
|
private static void ImportWays(XmlReader xmlReader, Dictionary<ulong, ulong> nodeRegions, string outputPath)
|
|
|
|
{
|
|
|
|
BinaryFormatter bFormatter = new BinaryFormatter();
|
|
|
|
bool currentWayIsHighway;
|
|
|
|
ulong currentWayId = 0;
|
|
|
|
List<ulong> currentNodeIds = new();
|
|
|
|
Dictionary<Tag.TagType, dynamic> currentTags = new();
|
|
|
|
Dictionary<ulong, FileStream> regionWaysFileStreams = new();
|
2023-04-01 00:52:13 +02:00
|
|
|
Dictionary<ulong, FileStream> regionTagsFileStreams = new();
|
2023-03-30 18:25:12 +02:00
|
|
|
while (xmlReader.ReadToFollowing("way"))
|
|
|
|
{
|
2023-03-31 21:56:27 +02:00
|
|
|
ulong wayId = Convert.ToUInt64(xmlReader.GetAttribute("id")!);
|
|
|
|
currentWayIsHighway = false;
|
|
|
|
currentNodeIds.Clear();
|
|
|
|
currentTags.Clear();
|
2023-03-30 18:25:12 +02:00
|
|
|
XmlReader wayReader = xmlReader.ReadSubtree();
|
|
|
|
while (wayReader.Read())
|
|
|
|
{
|
2023-03-31 21:56:27 +02:00
|
|
|
currentWayId = Convert.ToUInt64(wayReader.GetAttribute("id")!);
|
|
|
|
if (wayReader.Name == "tag")
|
2023-03-30 18:25:12 +02:00
|
|
|
{
|
2023-03-31 21:56:27 +02:00
|
|
|
Tag wayTag = Tag.ConvertToTag(wayReader.GetAttribute("k")!, wayReader.GetAttribute("v")!);
|
|
|
|
currentTags.TryAdd(wayTag.key, wayTag.value);
|
|
|
|
if(wayTag.key == Tag.TagType.highway)
|
|
|
|
currentWayIsHighway = true;
|
2023-03-30 18:25:12 +02:00
|
|
|
}
|
2023-03-31 21:56:27 +02:00
|
|
|
else if (wayReader.Name == "nd")
|
2023-03-30 18:25:12 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2023-03-31 21:56:27 +02:00
|
|
|
ulong nodeId = Convert.ToUInt64(wayReader.GetAttribute("ref"));
|
|
|
|
currentNodeIds.Add(nodeId);
|
2023-03-30 18:25:12 +02:00
|
|
|
}
|
|
|
|
catch (FormatException) { };
|
|
|
|
}
|
|
|
|
}
|
2023-03-31 21:56:27 +02:00
|
|
|
wayReader.Close();
|
|
|
|
if (currentWayIsHighway)
|
2023-03-30 18:25:12 +02:00
|
|
|
{
|
2023-03-31 21:56:27 +02:00
|
|
|
for (int i = 0; i < currentNodeIds.Count - 1; i++)
|
|
|
|
{
|
|
|
|
ulong node1Id = currentNodeIds[i];
|
|
|
|
ulong node2Id = currentNodeIds[i+1];
|
|
|
|
if (currentTags.ContainsKey(Tag.TagType.oneway) && (bool)currentTags[Tag.TagType.oneway] && nodeRegions.ContainsKey(node1Id) && nodeRegions.ContainsKey(node2Id))
|
|
|
|
{
|
|
|
|
if (currentTags.ContainsKey(Tag.TagType.forward) && !(bool)currentTags[Tag.TagType.forward])
|
|
|
|
{
|
|
|
|
OsmWay n21e = new OsmWay(currentWayId, node2Id, node1Id, nodeRegions[node2Id]);
|
2023-04-01 00:52:13 +02:00
|
|
|
WriteWay(ref regionWaysFileStreams, nodeRegions[node2Id], n21e, outputPath);
|
|
|
|
WriteTag(ref regionTagsFileStreams, nodeRegions[node2Id], currentTags, outputPath);
|
2023-03-31 21:56:27 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OsmWay n12e = new OsmWay(currentWayId, node1Id, node2Id, nodeRegions[node2Id]);
|
2023-04-01 00:52:13 +02:00
|
|
|
WriteWay(ref regionWaysFileStreams, nodeRegions[node1Id], n12e, outputPath);
|
|
|
|
WriteTag(ref regionTagsFileStreams, nodeRegions[node1Id], currentTags, outputPath);
|
2023-03-31 21:56:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(nodeRegions.ContainsKey(node1Id) && nodeRegions.ContainsKey(node2Id))
|
|
|
|
{
|
|
|
|
OsmWay n12e = new OsmWay(currentWayId, node1Id, node2Id, nodeRegions[node2Id]);
|
2023-04-01 00:52:13 +02:00
|
|
|
WriteWay(ref regionWaysFileStreams, nodeRegions[node1Id], n12e, outputPath);
|
|
|
|
WriteTag(ref regionTagsFileStreams, nodeRegions[node1Id], currentTags, outputPath);
|
2023-03-31 21:56:27 +02:00
|
|
|
|
|
|
|
OsmWay n21e = new OsmWay(currentWayId, node2Id, node1Id, nodeRegions[node2Id]);
|
2023-04-01 00:52:13 +02:00
|
|
|
WriteWay(ref regionWaysFileStreams, nodeRegions[node2Id], n21e, outputPath);
|
|
|
|
WriteTag(ref regionTagsFileStreams, nodeRegions[node2Id], currentTags, outputPath);
|
2023-03-31 21:56:27 +02:00
|
|
|
}
|
|
|
|
}
|
2023-03-30 18:25:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlReader.Close();
|
2023-04-01 00:40:06 +02:00
|
|
|
foreach (FileStream f in regionWaysFileStreams.Values)
|
|
|
|
f.Dispose();
|
2023-04-01 00:52:13 +02:00
|
|
|
foreach(FileStream f in regionTagsFileStreams.Values)
|
|
|
|
f.Dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void WriteWay(ref Dictionary<ulong, FileStream> regionWaysFileStreams, ulong regionHash, OsmWay way, string outputPath)
|
|
|
|
{
|
|
|
|
BinaryFormatter bFormatter = new BinaryFormatter();
|
|
|
|
if (!regionWaysFileStreams.ContainsKey(regionHash))
|
|
|
|
{
|
|
|
|
string waysRegionPath = Path.Combine(outputPath, regionHash.ToString(), WaysFileName);
|
|
|
|
regionWaysFileStreams.Add(regionHash, new FileStream(waysRegionPath, FileMode.OpenOrCreate));
|
2023-04-01 00:40:06 +02:00
|
|
|
}
|
2023-04-01 00:52:13 +02:00
|
|
|
#pragma warning disable SYSLIB0011
|
|
|
|
bFormatter.Serialize(regionWaysFileStreams[regionHash], way);
|
|
|
|
#pragma warning restore SYSLIB0011
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void WriteTag(ref Dictionary<ulong, FileStream> regionTagsFileStreams, ulong regionHash, Dictionary<Tag.TagType, dynamic> currentTags, string outputPath)
|
|
|
|
{
|
|
|
|
BinaryFormatter bFormatter = new BinaryFormatter();
|
|
|
|
if (!regionTagsFileStreams.ContainsKey(regionHash))
|
|
|
|
{
|
|
|
|
string tagsRegionPath = Path.Combine(outputPath, regionHash.ToString(), tagsFileName);
|
|
|
|
regionTagsFileStreams.Add(regionHash, new FileStream(tagsRegionPath, FileMode.OpenOrCreate));
|
|
|
|
}
|
|
|
|
#pragma warning disable SYSLIB0011
|
|
|
|
bFormatter.Serialize(regionTagsFileStreams[regionHash], currentTags);
|
|
|
|
#pragma warning restore SYSLIB0011
|
2023-03-30 18:25:12 +02:00
|
|
|
}
|
|
|
|
}
|