Naming Changes

This commit is contained in:
2023-02-02 22:30:43 +01:00
parent f7edc288c1
commit 58aac549c7
17 changed files with 366 additions and 298 deletions

View File

@ -0,0 +1,50 @@
using System.Globalization;
namespace OSMImporter
{
public class Coordinates
{
public float lat { get; }
public float lon { get; }
public Coordinates(float lat, float lon)
{
this.lat = lat;
this.lon = lon;
}
private const float decimalCoordsSave = 10000;
private const ulong offset = 10000000;
//Latitude maxChars = 7
//Longitude maxChars = 8
public ulong GetHash()
{
ulong latHash = Convert.ToUInt64((this.lat + 90) * decimalCoordsSave);
ulong lonHash = Convert.ToUInt64((this.lon + 180) * decimalCoordsSave);
return latHash * offset + lonHash;
}
public ulong GetRegionHash()
{
float latRegion = this.lat - this.lat % Importer.regionSize;
float lonRegion = this.lon - this.lon % Importer.regionSize;
ulong latHash = Convert.ToUInt64((latRegion + 90) * decimalCoordsSave);
ulong lonHash = Convert.ToUInt64((lonRegion + 180) * decimalCoordsSave);
return latHash * offset + lonHash;
}
public static Coordinates GetFromHash(ulong hash)
{
ulong latHash = (hash / offset) - 90;
ulong lonHash = (hash % offset) - 180;
float lat = Convert.ToSingle(latHash) / decimalCoordsSave;
float lon = Convert.ToSingle(lonHash) / decimalCoordsSave;
return new Coordinates(lat, lon);
}
public override string ToString()
{
return string.Format("{0} {1}", this.lat.ToString(CultureInfo.InvariantCulture), this.lon.ToString(CultureInfo.InvariantCulture));
}
}
}

188
OSMImporter/Importer.cs Normal file
View File

@ -0,0 +1,188 @@
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 = "."
};
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));
}
}
}
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);
foreach (Node node in region.GetNodes())
{
byte[] nodeByte = node.ToByte();
fileStream.Write(nodeByte, 0, nodeByte.Length );
}
fileStream.Close();
}
}
}

44
OSMImporter/Node.cs Normal file
View File

@ -0,0 +1,44 @@
namespace OSMImporter
{
public class Node : Coordinates
{
private readonly HashSet<Connection> _connections = new HashSet<Connection>();
public Node(float lat, float lon) : base(lat, lon)
{
}
public void AddConnection(Connection connection)
{
this._connections.Add(connection);
}
public Connection[] GetConnections()
{
return this._connections.ToArray();
}
/*
* Returns byte array in order:
* Value 1: Latitude (4bytes)
* Value 2: Longitude (4bytes)
* Value 3: Connections-Count (1 byte)
* Value x: Connection (8bytes) //TODO
*/
public byte[] ToByte()
{
float[] coords = { this.lat, this.lon };
byte[] ret = new byte[sizeof(float) * coords.Length + 1 + _connections.Count * sizeof(ulong)];
Buffer.BlockCopy(coords, 0, ret, 0, sizeof(float) * coords.Length );
byte countConnections = Convert.ToByte(_connections.Count);
Connection[] conns = this._connections.ToArray();
for (int i = 0; i < conns.Length; i++)
{
byte[] connection = conns[i].ToByte();
Buffer.BlockCopy(connection, 0, ret, sizeof(float) * coords.Length + 1 + i * connection.Length, connection.Length);
}
return ret;
}
}
}

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>OSMServer</RootNamespace>
</PropertyGroup>
</Project>

29
OSMImporter/Region.cs Normal file
View File

@ -0,0 +1,29 @@
namespace OSMImporter
{
public class Region
{
private readonly Dictionary<ulong, Node> _nodesInRegion = new Dictionary<ulong, Node>();
public ulong regionHash { get; }
public Region(Coordinates regionCoordinates)
{
this.regionHash = regionCoordinates.GetRegionHash();
}
public Region(ulong nodeId, Node firstNode)
{
this.regionHash = firstNode.GetRegionHash();
this._nodesInRegion.Add(nodeId, value: firstNode);
}
public void AddNode(ulong nodeId, Node node)
{
this._nodesInRegion.Add(nodeId, value: node);
}
public Node[] GetNodes()
{
return this._nodesInRegion.Values.ToArray();
}
}
}

View File

@ -0,0 +1,29 @@
namespace OSMImporter
{
public class RegionManager
{
private readonly Dictionary<ulong, Region> _regions;
public RegionManager()
{
this._regions = new Dictionary<ulong, Region>();
}
public Region GetRegion(Coordinates coordinates)
{
if(this._regions.ContainsKey(coordinates.GetRegionHash()))
return this._regions[coordinates.GetRegionHash()];
else
{
Region newRegion = new Region(coordinates);
this._regions.Add(newRegion.regionHash, value: newRegion);
return newRegion;
}
}
public Region[] GetAllRegions()
{
return this._regions.Values.ToArray();
}
}
}