2023-02-02 22:30:43 +01:00
|
|
|
using System.Globalization;
|
|
|
|
using System.Text;
|
|
|
|
using System.Xml;
|
|
|
|
|
|
|
|
namespace OSMImporter
|
|
|
|
{
|
|
|
|
public static class Importer
|
|
|
|
{
|
|
|
|
|
|
|
|
public const float regionSize = 0.01f;
|
|
|
|
private static readonly XmlReaderSettings readerSettings = new()
|
|
|
|
{
|
|
|
|
IgnoreWhitespace = true,
|
|
|
|
IgnoreComments = true
|
|
|
|
};
|
|
|
|
|
|
|
|
private static readonly NumberFormatInfo coordinateFormat = new NumberFormatInfo()
|
|
|
|
{
|
|
|
|
NumberDecimalSeparator = "."
|
|
|
|
};
|
|
|
|
|
2023-02-03 00:02:04 +01:00
|
|
|
public static Region ImportRegion(string folderPath, Coordinates coordinates)
|
|
|
|
{
|
|
|
|
string fullPath = Path.Combine(folderPath, coordinates.GetRegionHash().ToString());
|
|
|
|
Console.WriteLine(fullPath);
|
|
|
|
Region retRegion = new Region(coordinates);
|
|
|
|
if (!File.Exists(fullPath))
|
|
|
|
return retRegion;
|
|
|
|
|
|
|
|
FileStream fileStream = new FileStream(fullPath, FileMode.Open);
|
|
|
|
|
|
|
|
while (fileStream.Position < fileStream.Length)
|
|
|
|
{
|
|
|
|
byte[] nodeIdBytes = new byte[sizeof(ulong)];
|
|
|
|
fileStream.ReadExactly(nodeIdBytes,0,nodeIdBytes.Length);
|
|
|
|
ulong[] nodeId = new ulong[1];
|
|
|
|
Buffer.BlockCopy(nodeIdBytes,0,nodeId,0,nodeIdBytes.Length);
|
|
|
|
byte[] latBytes = new byte[sizeof(float)];
|
|
|
|
fileStream.ReadExactly(latBytes, 0, latBytes.Length);
|
|
|
|
byte[] lonBytes = new byte[sizeof(float)];
|
|
|
|
fileStream.ReadExactly(lonBytes, 0, latBytes.Length);
|
|
|
|
|
|
|
|
Node newNode = NodeFromBytes(latBytes, lonBytes);
|
|
|
|
retRegion.AddNode(nodeId[0], newNode);
|
|
|
|
|
|
|
|
byte connectionsAmount = Convert.ToByte(fileStream.ReadByte());
|
|
|
|
for (byte connectionInt = 0; connectionInt < connectionsAmount; connectionInt++)
|
|
|
|
{
|
|
|
|
byte[] endIdBytes = new byte[sizeof(ulong)];
|
|
|
|
fileStream.ReadExactly(endIdBytes, 0, endIdBytes.Length);
|
|
|
|
Connection connection = ConnectionFromByte(endIdBytes);
|
|
|
|
newNode.AddConnection(connection);
|
|
|
|
|
|
|
|
byte tagsAmount = Convert.ToByte(fileStream.ReadByte());
|
|
|
|
for (byte tagInt = 0; tagInt < tagsAmount; tagInt++)
|
|
|
|
{
|
|
|
|
byte keyByte = Convert.ToByte(fileStream.ReadByte());
|
|
|
|
byte valueByte = Convert.ToByte(fileStream.ReadByte());
|
|
|
|
connection.AddTag(keyByte, valueByte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fileStream.Close();
|
|
|
|
return retRegion;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Node NodeFromBytes(byte[] latByte, byte[] lonByte)
|
|
|
|
{
|
|
|
|
float[] lat = new float[1];
|
|
|
|
float[] lon = new float[1];
|
|
|
|
Buffer.BlockCopy(latByte, 0, lat, 0, latByte.Length);
|
|
|
|
Buffer.BlockCopy(lonByte, 0, lon, 0, lonByte.Length);
|
|
|
|
return new Node(lat[0], lon[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Connection ConnectionFromByte(byte[] endIdByte)
|
|
|
|
{
|
|
|
|
ulong[] endId = new ulong[1];
|
|
|
|
Buffer.BlockCopy(endIdByte, 0, endId, 0, endIdByte.Length);
|
|
|
|
return new Connection(endId[0]);
|
|
|
|
}
|
|
|
|
|
2023-02-02 22:30:43 +01:00
|
|
|
public static void Split(string xmlFilePath, string outputFolderPath)
|
|
|
|
{
|
|
|
|
if (!File.Exists(xmlFilePath))
|
|
|
|
throw new FileNotFoundException();
|
|
|
|
FileStream xmlFileStream = File.OpenRead(xmlFilePath);
|
|
|
|
|
|
|
|
Console.WriteLine("Reading ways once...");
|
|
|
|
Dictionary<ulong, Node?> nodes = ReturnNodeIdDictionary(XmlReader.Create(xmlFileStream, readerSettings));
|
|
|
|
|
|
|
|
xmlFileStream.Position = 0;
|
|
|
|
RegionManager regionManager = new RegionManager();
|
|
|
|
|
|
|
|
Console.WriteLine("Reading nodes...");
|
|
|
|
LoadNodesIntoDictionary(ref nodes, XmlReader.Create(xmlFileStream, readerSettings), ref regionManager);
|
|
|
|
|
|
|
|
xmlFileStream.Position = 0;
|
|
|
|
|
|
|
|
Console.WriteLine("Reading ways twice...");
|
|
|
|
CreateConnections(XmlReader.Create(xmlFileStream, readerSettings), ref nodes);
|
|
|
|
|
|
|
|
Console.WriteLine("Writing...");
|
|
|
|
|
|
|
|
foreach(Region region in regionManager.GetAllRegions())
|
|
|
|
WriteRegion(region, outputFolderPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Dictionary<ulong, Node?> ReturnNodeIdDictionary(XmlReader xmlReader)
|
|
|
|
{
|
|
|
|
Dictionary<ulong, Node?> retSet = new Dictionary<ulong, Node?>();
|
|
|
|
while (xmlReader.ReadToFollowing("way"))
|
|
|
|
{
|
|
|
|
byte[] byteArray = Encoding.ASCII.GetBytes(xmlReader.ReadOuterXml());
|
|
|
|
MemoryStream wayStream = new MemoryStream(byteArray);
|
|
|
|
XmlReader wayReader = XmlReader.Create(wayStream);
|
|
|
|
bool addNodes = false;
|
|
|
|
while (wayReader.ReadToFollowing("tag") && !addNodes)
|
|
|
|
{
|
|
|
|
if (wayReader.GetAttribute("v")!.Equals("highway"))
|
|
|
|
{
|
|
|
|
addNodes = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addNodes)
|
|
|
|
{
|
|
|
|
wayStream.Position = 0;
|
|
|
|
wayReader = XmlReader.Create(wayStream);
|
|
|
|
while (wayReader.ReadToFollowing("nd"))
|
|
|
|
{
|
|
|
|
retSet.TryAdd(Convert.ToUInt64(wayReader.GetAttribute("ref")!), null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlReader.Close();
|
|
|
|
return retSet;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void LoadNodesIntoDictionary(ref Dictionary<ulong, Node?> nodes, XmlReader xmlReader, ref RegionManager regionManager)
|
|
|
|
{
|
|
|
|
while (xmlReader.ReadToFollowing("node"))
|
|
|
|
{
|
|
|
|
ulong id = Convert.ToUInt64(xmlReader.GetAttribute("id"));
|
|
|
|
if (nodes.ContainsKey(id))
|
|
|
|
{
|
|
|
|
float lat = Convert.ToSingle(xmlReader.GetAttribute("lat")!, coordinateFormat);
|
|
|
|
float lon = Convert.ToSingle(xmlReader.GetAttribute("lon")!, coordinateFormat);
|
|
|
|
Node newNode = new Node(lat, lon);
|
|
|
|
nodes[id] = newNode;
|
|
|
|
regionManager.GetRegion(newNode).AddNode(id, newNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlReader.Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void CreateConnections(XmlReader xmlReader, ref Dictionary<ulong, Node?> nodes)
|
|
|
|
{
|
|
|
|
while (xmlReader.ReadToFollowing("way"))
|
|
|
|
{
|
|
|
|
byte[] byteArray = Encoding.ASCII.GetBytes(xmlReader.ReadOuterXml());
|
|
|
|
MemoryStream wayStream = new MemoryStream(byteArray);
|
|
|
|
XmlReader wayReader = XmlReader.Create(wayStream);
|
|
|
|
Dictionary<string, string> tags = new Dictionary<string, string>();
|
|
|
|
|
|
|
|
bool addNodes = false;
|
|
|
|
while (wayReader.ReadToFollowing("tag"))
|
|
|
|
{
|
|
|
|
if (wayReader.GetAttribute("v")!.Equals("highway"))
|
|
|
|
{
|
|
|
|
addNodes = true;
|
|
|
|
}
|
|
|
|
tags.Add(wayReader.GetAttribute("k")!, value: wayReader.GetAttribute("v")!);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (addNodes)
|
|
|
|
{
|
|
|
|
HashSet<ulong> nodesInWay = new HashSet<ulong>();
|
|
|
|
wayStream.Position = 0;
|
|
|
|
wayReader = XmlReader.Create(wayStream);
|
|
|
|
while (wayReader.ReadToFollowing("nd"))
|
|
|
|
{
|
|
|
|
nodesInWay.Add(Convert.ToUInt64(wayReader.GetAttribute("ref")));
|
|
|
|
}
|
|
|
|
ConnectNodesOfWay(nodes, nodesInWay.ToArray(), tags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlReader.Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void ConnectNodesOfWay(Dictionary<ulong, Node?> nodes, ulong[] nodeIds,
|
|
|
|
Dictionary<string, string> tags)
|
|
|
|
{
|
|
|
|
string oneWayString = tags.ContainsKey("oneway") ? tags["oneway"] : "no";
|
|
|
|
bool oneWay = false;
|
|
|
|
bool forward = true;
|
|
|
|
switch (oneWayString)
|
|
|
|
{
|
|
|
|
case "yes":
|
|
|
|
oneWay = true;
|
|
|
|
break;
|
|
|
|
case "-1":
|
|
|
|
forward = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < nodeIds.Length - 1; i++)
|
|
|
|
{
|
|
|
|
if (oneWay)
|
|
|
|
{
|
|
|
|
if(nodes.ContainsKey(nodeIds[i]))
|
|
|
|
nodes[nodeIds[i]]!.AddConnection(new Connection(nodeIds[i + 1], tags));
|
|
|
|
if(nodes.ContainsKey(nodeIds[i + 1]))
|
|
|
|
nodes[nodeIds[i + 1]]!.AddConnection(new Connection(nodeIds[i], tags));
|
|
|
|
}
|
|
|
|
else if (forward)
|
|
|
|
{
|
|
|
|
if(nodes.ContainsKey(nodeIds[i]))
|
|
|
|
nodes[nodeIds[i]]!.AddConnection(new Connection(nodeIds[i + 1], tags));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(nodes.ContainsKey(nodeIds[i + 1]))
|
|
|
|
nodes[nodeIds[i + 1]]!.AddConnection(new Connection(nodeIds[i], tags));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-03 00:02:04 +01:00
|
|
|
/*
|
|
|
|
* Value x: nodeId (4bytes)
|
|
|
|
* Value x+1: Node (xbytes)
|
|
|
|
*/
|
2023-02-02 22:30:43 +01:00
|
|
|
private static void WriteRegion(Region region, string outputFolderPath)
|
|
|
|
{
|
|
|
|
if (!Directory.Exists(outputFolderPath))
|
|
|
|
Directory.CreateDirectory(outputFolderPath);
|
|
|
|
string fileName = region.regionHash.ToString();
|
|
|
|
string fullPath = Path.Combine(outputFolderPath, fileName);
|
|
|
|
if (!File.Exists(fullPath))
|
|
|
|
File.Create(fullPath).Close();
|
|
|
|
FileStream fileStream = new FileStream(fullPath, FileMode.Append);
|
2023-02-03 00:02:04 +01:00
|
|
|
foreach (KeyValuePair<ulong, Node> nodeKeyValuePair in region.GetNodes())
|
2023-02-02 22:30:43 +01:00
|
|
|
{
|
2023-02-03 00:02:04 +01:00
|
|
|
byte[] nodeByte = nodeKeyValuePair.Value.ToByte();
|
|
|
|
byte[] nodeIdByte = new byte[sizeof(long)];
|
|
|
|
ulong[] nodeId = new ulong[]{nodeKeyValuePair.Key};
|
|
|
|
Buffer.BlockCopy(nodeId,0,nodeIdByte,0,nodeIdByte.Length);
|
|
|
|
|
|
|
|
fileStream.Write(nodeIdByte);
|
2023-02-02 22:30:43 +01:00
|
|
|
fileStream.Write(nodeByte, 0, nodeByte.Length );
|
|
|
|
}
|
|
|
|
fileStream.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|