Datastructure rewrite
This commit is contained in:
parent
2c18162398
commit
e265c56bce
@ -1,198 +1,35 @@
|
|||||||
|
using System.Text;
|
||||||
|
using GeoGraph;
|
||||||
|
|
||||||
namespace OSMDatastructure;
|
namespace OSMDatastructure;
|
||||||
|
|
||||||
public static class ByteConverter
|
public static class ByteConverter
|
||||||
{
|
{
|
||||||
#region Node
|
|
||||||
/*
|
|
||||||
* Node Byteform:
|
|
||||||
* +-------------------------------+
|
|
||||||
* | Latitude | Longitude | ConnectionSize| connection |
|
|
||||||
* |---------------+---------------+---------------+---------------+
|
|
||||||
* | 4 bytes | 4 bytes | 4 bytes | ConnectionSize|
|
|
||||||
* | float | float | int | Connection |
|
|
||||||
* +---------------+---------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static byte[] GetBytes(Node node)
|
|
||||||
{
|
|
||||||
byte[] latitudeBytes = BitConverter.GetBytes(node.lat);
|
|
||||||
byte[] longitudeBytes = BitConverter.GetBytes(node.lon);
|
|
||||||
|
|
||||||
Connection[] connections = node.GetConnections();
|
|
||||||
Dictionary<byte[], byte[]> connectionsBytes = new ();
|
|
||||||
int byteArraySize = latitudeBytes.Length + longitudeBytes.Length;
|
|
||||||
|
|
||||||
foreach (Connection connection in connections)
|
|
||||||
{
|
|
||||||
byte[] connectionBytes = ByteConverter.GetBytes(connection);
|
|
||||||
byte[] connectionSizeBytes = BitConverter.GetBytes(connectionBytes.Length);
|
|
||||||
connectionsBytes.Add(connectionSizeBytes, connectionBytes);
|
|
||||||
byteArraySize += connectionSizeBytes.Length + connectionBytes.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] retByteArray = new byte[byteArraySize];
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
Array.Copy(latitudeBytes, 0, retByteArray, offset, latitudeBytes.Length);
|
|
||||||
offset += latitudeBytes.Length;
|
|
||||||
|
|
||||||
Array.Copy(longitudeBytes, 0, retByteArray, offset, longitudeBytes.Length);
|
|
||||||
offset += longitudeBytes.Length;
|
|
||||||
|
|
||||||
foreach (KeyValuePair<byte[], byte[]> connectionBytes in connectionsBytes)
|
|
||||||
{
|
|
||||||
Array.Copy(connectionBytes.Key, 0, retByteArray, offset, connectionBytes.Key.Length);
|
|
||||||
offset += connectionBytes.Key.Length;
|
|
||||||
|
|
||||||
Array.Copy(connectionBytes.Value, 0, retByteArray, offset, connectionBytes.Value.Length);
|
|
||||||
offset += connectionBytes.Value.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retByteArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Node ToNode(byte[] bytes)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
float lat = BitConverter.ToSingle(bytes, offset);
|
|
||||||
offset += sizeof(float);
|
|
||||||
|
|
||||||
float lon = BitConverter.ToSingle(bytes, offset);
|
|
||||||
offset += sizeof(float);
|
|
||||||
|
|
||||||
Node retNode = new Node(lat, lon);
|
|
||||||
|
|
||||||
while (offset < bytes.Length)
|
|
||||||
{
|
|
||||||
int size = BitConverter.ToInt32(bytes, offset);
|
|
||||||
offset += sizeof(int);
|
|
||||||
|
|
||||||
byte[] connectionBytes = new byte[size];
|
|
||||||
Array.Copy(bytes, offset, connectionBytes, 0, size);
|
|
||||||
retNode.AddConnection(ByteConverter.ToConnection(connectionBytes));
|
|
||||||
offset += connectionBytes.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retNode;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Connection
|
|
||||||
/*
|
|
||||||
* Connection Byteform:
|
|
||||||
* +---------------+---------------+
|
|
||||||
* | endId | endLatitude | endLongitude | tagBytes | tag | value |
|
|
||||||
* |---------------+---------------+---------------+---------------+---------------+---------------+
|
|
||||||
* | 8 bytes | 4 bytes | 4 bytes | 4 bytes | 1 byte | 1 byte |
|
|
||||||
* | ulong | float | float | int | | |
|
|
||||||
* +---------------+---------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static byte[] GetBytes(Connection connection)
|
|
||||||
{
|
|
||||||
byte[] endIdBytes = BitConverter.GetBytes(connection.endNodeId);
|
|
||||||
byte[] endLatBytes = BitConverter.GetBytes(connection.endNodeCoordinates.lat);
|
|
||||||
byte[] endLonBytes = BitConverter.GetBytes(connection.endNodeCoordinates.lon);
|
|
||||||
|
|
||||||
Dictionary<Connection.tagType, object> connectionTags = connection.GetTags();
|
|
||||||
byte[] tagBytes = BitConverter.GetBytes(connectionTags.Count * 2);
|
|
||||||
|
|
||||||
int byteArraySize = endIdBytes.Length + endLatBytes.Length + endLonBytes.Length + tagBytes.Length + connectionTags.Count * 2;
|
|
||||||
byte[] retBytes = new byte[byteArraySize];
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
Array.Copy(endIdBytes, 0, retBytes, offset, endIdBytes.Length);
|
|
||||||
offset += endIdBytes.Length;
|
|
||||||
|
|
||||||
Array.Copy(endLatBytes, 0, retBytes, offset, endLatBytes.Length);
|
|
||||||
offset += endLatBytes.Length;
|
|
||||||
|
|
||||||
Array.Copy(endLonBytes, 0 , retBytes, offset, endLonBytes.Length);
|
|
||||||
offset += endLonBytes.Length;
|
|
||||||
|
|
||||||
Array.Copy(tagBytes, 0, retBytes, offset, tagBytes.Length);
|
|
||||||
offset += tagBytes.Length;
|
|
||||||
|
|
||||||
foreach (KeyValuePair<Connection.tagType, object> tagKv in connectionTags)
|
|
||||||
{
|
|
||||||
retBytes[offset] = (byte)tagKv.Key;
|
|
||||||
offset++;
|
|
||||||
retBytes[offset] = (byte)tagKv.Value;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Connection ToConnection(byte[] bytes)
|
|
||||||
{
|
|
||||||
int offset = 0;
|
|
||||||
ulong endId = BitConverter.ToUInt64(bytes, offset);
|
|
||||||
offset += sizeof(ulong);
|
|
||||||
|
|
||||||
float endLat = BitConverter.ToSingle(bytes, offset);
|
|
||||||
offset += sizeof(float);
|
|
||||||
|
|
||||||
float endLon = BitConverter.ToSingle(bytes, offset);
|
|
||||||
offset += sizeof(float);
|
|
||||||
|
|
||||||
Connection retConnection = new Connection(endId, new Coordinates(endLat, endLon));
|
|
||||||
|
|
||||||
int tagBytes = BitConverter.ToInt32(bytes, offset);
|
|
||||||
offset += sizeof(int);
|
|
||||||
while (offset < bytes.Length)
|
|
||||||
{
|
|
||||||
byte key = bytes[offset];
|
|
||||||
byte value = bytes[offset + 1];
|
|
||||||
retConnection.AddTag(key, value);
|
|
||||||
offset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retConnection;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Region
|
#region Region
|
||||||
/*
|
/*
|
||||||
* Region Byteform:
|
* | regionHash | Nodes |
|
||||||
* +---------------+---------------+---------------+
|
* |---------------+---------------+
|
||||||
* | regionHash | nodeBytes | nodeId | node |
|
* | 8 bytes |
|
||||||
* |---------------+---------------+---------------+---------------+
|
* | ulong |
|
||||||
* | 8 bytes | 4 bytes | 8 bytes | nodeBytes |
|
|
||||||
* | ulong | int | ulong | Node |
|
|
||||||
* +---------------+---------------+---------------+
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static byte[] GetBytes(Region region)
|
public static byte[] GetBytes(Region region)
|
||||||
{
|
{
|
||||||
byte[] regionHashBytes = BitConverter.GetBytes(region.regionHash);
|
int totalNodeBytes = 0;
|
||||||
int byteArraySize = regionHashBytes.Length;
|
HashSet<byte[]> nodes = new();
|
||||||
|
foreach (OsmNode node in region.nodes)
|
||||||
Dictionary<byte[], byte[]> nodesBytes = new();
|
|
||||||
foreach(KeyValuePair<ulong, Node> nodeKv in region.GetNodes())
|
|
||||||
{
|
{
|
||||||
byte[] nodeIdBytes = BitConverter.GetBytes(nodeKv.Key);
|
byte[] nodeBytes = GetBytes(node);
|
||||||
byte[] nodeBytes = GetBytes(nodeKv.Value);
|
totalNodeBytes += nodeBytes.Length;
|
||||||
nodesBytes.Add(nodeIdBytes, nodeBytes);
|
nodes.Add(nodeBytes);
|
||||||
byteArraySize += sizeof(int) + nodeIdBytes.Length + nodeBytes.Length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] retBytes = new byte[byteArraySize];
|
byte[] retBytes = new byte[sizeof(ulong) + totalNodeBytes];
|
||||||
int offset = 0;
|
Array.Copy(BitConverter.GetBytes(region.regionHash), 0, retBytes, 0, sizeof(ulong));
|
||||||
|
int offset = sizeof(ulong);
|
||||||
Array.Copy(regionHashBytes, 0, retBytes, offset, regionHashBytes.Length);
|
foreach (byte[] node in nodes)
|
||||||
offset += regionHashBytes.Length;
|
|
||||||
|
|
||||||
foreach (KeyValuePair<byte[], byte[]> nodeByteKv in nodesBytes)
|
|
||||||
{
|
{
|
||||||
Array.Copy(BitConverter.GetBytes(nodeByteKv.Value.Length), 0, retBytes, offset, sizeof(int));
|
Array.Copy(node, 0, retBytes, offset, node.Length);
|
||||||
offset += sizeof(int);
|
offset += node.Length;
|
||||||
|
|
||||||
Array.Copy(nodeByteKv.Key, 0, retBytes, offset, nodeByteKv.Key.Length);
|
|
||||||
offset += nodeByteKv.Key.Length;
|
|
||||||
|
|
||||||
Array.Copy(nodeByteKv.Value, 0, retBytes, offset, nodeByteKv.Value.Length);
|
|
||||||
offset += nodeByteKv.Value.Length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retBytes;
|
return retBytes;
|
||||||
@ -200,27 +37,228 @@ public static class ByteConverter
|
|||||||
|
|
||||||
public static Region ToRegion(byte[] bytes)
|
public static Region ToRegion(byte[] bytes)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
Region retRegion = new Region(BitConverter.ToUInt64(bytes, 0));
|
||||||
ulong regionHash = BitConverter.ToUInt64(bytes, offset);
|
int offset = sizeof(ulong);
|
||||||
offset += sizeof(ulong);
|
|
||||||
|
|
||||||
Region retRegion = new Region(regionHash);
|
|
||||||
|
|
||||||
while (offset < bytes.Length)
|
while (offset < bytes.Length)
|
||||||
{
|
{
|
||||||
int nodeBytesAmount = BitConverter.ToInt32(bytes, offset);
|
int size = BitConverter.ToInt32(bytes, offset);
|
||||||
offset += sizeof(int);
|
byte[] nodeBytes = new byte[size];
|
||||||
|
Array.Copy(bytes, offset, nodeBytes, 0, size);
|
||||||
ulong nodeId = BitConverter.ToUInt64(bytes, offset);
|
offset += size;
|
||||||
offset += sizeof(ulong);
|
retRegion.nodes.Add(ToNode(nodeBytes));
|
||||||
|
|
||||||
byte[] nodeBytes = new byte[nodeBytesAmount];
|
|
||||||
Array.Copy(bytes, offset, nodeBytes, 0, nodeBytesAmount);
|
|
||||||
retRegion.AddNode(nodeId, ByteConverter.ToNode(nodeBytes));
|
|
||||||
offset += nodeBytes.Length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retRegion;
|
return retRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Coordinates
|
||||||
|
|
||||||
|
/*
|
||||||
|
* | Latitude | Longitude |
|
||||||
|
* |---------------+---------------+
|
||||||
|
* | 4 bytes | 4 bytes |
|
||||||
|
* | float | float |
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static byte[] GetBytes(Coordinates coordinates)
|
||||||
|
{
|
||||||
|
byte[] retBytes = new byte[8];
|
||||||
|
Array.Copy(BitConverter.GetBytes(coordinates.latitude), 0, retBytes, 0, sizeof(float));
|
||||||
|
Array.Copy(BitConverter.GetBytes(coordinates.longitude), 0, retBytes, sizeof(float), sizeof(float));
|
||||||
|
return retBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Coordinates ToCoordinates(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes.Length != 8)
|
||||||
|
throw new ArgumentException("Needs exactly 8 bytes", nameof(bytes));
|
||||||
|
float latitude = BitConverter.ToSingle(bytes, 0);
|
||||||
|
float longitude = BitConverter.ToSingle(bytes, sizeof(float));
|
||||||
|
return new Coordinates(latitude, longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OsmNode
|
||||||
|
|
||||||
|
/*
|
||||||
|
* | Size | Coordinates | Edges
|
||||||
|
* |---------------+---------------+---------------+
|
||||||
|
* | 4 bytes | 8 bytes |
|
||||||
|
* | int | byte[] |
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static byte[] GetBytes(OsmNode node)
|
||||||
|
{
|
||||||
|
int totalBytes = 4 + 8; //size + Coordinates
|
||||||
|
HashSet<byte[]> edges = new();
|
||||||
|
foreach (OsmEdge edge in node.edges)
|
||||||
|
{
|
||||||
|
edges.Add(GetBytes(edge));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] retBytes = new byte[totalBytes];
|
||||||
|
Array.Copy(BitConverter.GetBytes(totalBytes), retBytes, 4);
|
||||||
|
Array.Copy(GetBytes(node.coordinates), 0, retBytes, 4, 8);
|
||||||
|
int offset = 4 + 8;
|
||||||
|
foreach (byte[] edgeBytes in edges)
|
||||||
|
{
|
||||||
|
Array.Copy(edgeBytes, 0, retBytes, offset, edgeBytes.Length);
|
||||||
|
offset += edgeBytes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsmNode ToNode(byte[] bytes)
|
||||||
|
{
|
||||||
|
byte[] coordinateBytes = new byte[8];
|
||||||
|
Array.Copy(bytes, 4, coordinateBytes, 0, 8);
|
||||||
|
Coordinates coordinates = ToCoordinates(coordinateBytes);
|
||||||
|
|
||||||
|
OsmNode retNode = new OsmNode(coordinates);
|
||||||
|
|
||||||
|
int offset = sizeof(int) + 8;
|
||||||
|
while (offset < bytes.Length)
|
||||||
|
{
|
||||||
|
int tagsSize = BitConverter.ToInt32(bytes, offset);
|
||||||
|
byte[] edgeBytes = new byte[sizeof(int) + 8 + tagsSize];
|
||||||
|
Array.Copy(bytes, offset, edgeBytes, 0, edgeBytes.Length);
|
||||||
|
offset += edgeBytes.Length;
|
||||||
|
retNode.edges.Add(ToEdge(edgeBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
return retNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OsmEdge
|
||||||
|
|
||||||
|
/* Edge:
|
||||||
|
* | tagsSize | neighborCoord | tags
|
||||||
|
* |---------------+---------------+--------------
|
||||||
|
* | 4 bytes | 8 bytes |
|
||||||
|
* | int | byte[] |
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static byte[] GetBytes(OsmEdge edge)
|
||||||
|
{
|
||||||
|
int totalBytes = sizeof(int) + 8; //size + Coordinates
|
||||||
|
int offset = totalBytes;
|
||||||
|
|
||||||
|
int tagsSize = 0;
|
||||||
|
HashSet<byte[]> tags = new();
|
||||||
|
foreach (KeyValuePair<OsmEdge.tagType, object> kv in edge.tags)
|
||||||
|
{
|
||||||
|
byte[] tagBytes = GetBytes(kv);
|
||||||
|
tags.Add(tagBytes);
|
||||||
|
tagsSize += tagBytes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] retBytes = new byte[totalBytes];
|
||||||
|
Array.Copy(BitConverter.GetBytes(tagsSize), retBytes, 4);
|
||||||
|
Array.Copy(GetBytes(edge.neighborCoordinates), 0, retBytes, sizeof(int), 8);
|
||||||
|
|
||||||
|
foreach (byte[] tag in tags)
|
||||||
|
{
|
||||||
|
Array.Copy(tag, 0, retBytes, offset, tag.Length);
|
||||||
|
offset += tag.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OsmEdge ToEdge(byte[] bytes)
|
||||||
|
{
|
||||||
|
byte[] coordinateBytes = new byte[8];
|
||||||
|
Array.Copy(bytes, 4, coordinateBytes, 0, 8);
|
||||||
|
Coordinates coordinates = ToCoordinates(coordinateBytes);
|
||||||
|
|
||||||
|
OsmEdge retEdge = new OsmEdge(coordinates);
|
||||||
|
|
||||||
|
int offset = sizeof(int) + 8;
|
||||||
|
while (offset < bytes.Length)
|
||||||
|
{
|
||||||
|
int tagContentSize = BitConverter.ToInt32(bytes, offset);
|
||||||
|
byte[] tagBytes = new byte[sizeof(int) + 1 + tagContentSize];
|
||||||
|
Array.Copy(bytes, offset, tagBytes, 0, tagBytes.Length);
|
||||||
|
offset += tagBytes.Length;
|
||||||
|
KeyValuePair<OsmEdge.tagType, object> tag = ToTag(tagBytes);
|
||||||
|
retEdge.tags.Add(tag.Key, tag.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OsmEdge.Tag
|
||||||
|
/*
|
||||||
|
* Tag:
|
||||||
|
* | contentSize | tagType | tagContent
|
||||||
|
* |---------------+---------------+---------------
|
||||||
|
* | 4 bytes | 1 byte |
|
||||||
|
* | int | byte |
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static byte[] GetBytes(KeyValuePair<OsmEdge.tagType, object> tag)
|
||||||
|
{
|
||||||
|
byte[] objectBytes = Array.Empty<byte>();
|
||||||
|
if (tag.Value.GetType() == Type.GetType("string"))
|
||||||
|
{
|
||||||
|
objectBytes = Encoding.ASCII.GetBytes((string)tag.Value);
|
||||||
|
}
|
||||||
|
else if (tag.Value.GetType() == Type.GetType("bool"))
|
||||||
|
{
|
||||||
|
objectBytes = BitConverter.GetBytes((bool)tag.Value);
|
||||||
|
}
|
||||||
|
else if (tag.Value.GetType() == Type.GetType("int"))
|
||||||
|
{
|
||||||
|
objectBytes = BitConverter.GetBytes((int)tag.Value);
|
||||||
|
}
|
||||||
|
else if (tag.Value.GetType() == Type.GetType("ulong"))
|
||||||
|
{
|
||||||
|
objectBytes = BitConverter.GetBytes((ulong)tag.Value);
|
||||||
|
}
|
||||||
|
else if (tag.Value.GetType() == Type.GetType("byte"))
|
||||||
|
{
|
||||||
|
objectBytes = new[] { (byte)tag.Value };
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] retBytes = new byte[sizeof(int) + 1 + objectBytes.Length];
|
||||||
|
Array.Copy(BitConverter.GetBytes(objectBytes.Length), 0, retBytes, 0, sizeof(int));
|
||||||
|
retBytes[sizeof(int)] = (byte)tag.Key;
|
||||||
|
Array.Copy(objectBytes, 0, retBytes, sizeof(int) + 1, retBytes.Length);
|
||||||
|
return retBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyValuePair<OsmEdge.tagType, object> ToTag(byte[] bytes)
|
||||||
|
{
|
||||||
|
OsmEdge.tagType tagType = (OsmEdge.tagType)bytes[sizeof(int)];
|
||||||
|
int contentSize = BitConverter.ToInt32(bytes, 0);
|
||||||
|
byte[] content = new byte[contentSize];
|
||||||
|
Array.Copy(bytes, sizeof(int) + 1, content, 0, contentSize);
|
||||||
|
|
||||||
|
switch (tagType)
|
||||||
|
{
|
||||||
|
case OsmEdge.tagType.highway:
|
||||||
|
return new KeyValuePair<OsmEdge.tagType, object>(tagType, (Way.wayType)content[0]);
|
||||||
|
case OsmEdge.tagType.maxspeed:
|
||||||
|
return new KeyValuePair<OsmEdge.tagType, object>(tagType, content[0]);
|
||||||
|
case OsmEdge.tagType.oneway:
|
||||||
|
return new KeyValuePair<OsmEdge.tagType, object>(tagType, BitConverter.ToBoolean(content));
|
||||||
|
case OsmEdge.tagType.forward:
|
||||||
|
return new KeyValuePair<OsmEdge.tagType, object>(tagType, BitConverter.ToBoolean(content));
|
||||||
|
case OsmEdge.tagType.id:
|
||||||
|
return new KeyValuePair<OsmEdge.tagType, object>(tagType, BitConverter.ToUInt64(content));
|
||||||
|
default:
|
||||||
|
return new KeyValuePair<OsmEdge.tagType, object>(tagType, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,166 +0,0 @@
|
|||||||
namespace OSMDatastructure
|
|
||||||
{
|
|
||||||
public class Connection
|
|
||||||
{
|
|
||||||
public ulong endNodeId { get; }
|
|
||||||
|
|
||||||
public Coordinates endNodeCoordinates { get; }
|
|
||||||
|
|
||||||
private readonly Dictionary<tagType, object> _tags = new();
|
|
||||||
|
|
||||||
public enum tagType : byte
|
|
||||||
{
|
|
||||||
highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype
|
|
||||||
}
|
|
||||||
|
|
||||||
public Connection(ulong endNodeId, Coordinates endNodeCoordinates)
|
|
||||||
{
|
|
||||||
this.endNodeId = endNodeId;
|
|
||||||
this.endNodeCoordinates = endNodeCoordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Connection(ulong endNodeId, Coordinates endNodeCoordinates, Dictionary<string, string> tags)
|
|
||||||
{
|
|
||||||
this.endNodeId = endNodeId;
|
|
||||||
this.endNodeCoordinates = endNodeCoordinates;
|
|
||||||
ImportTags(tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTag(string key, string value)
|
|
||||||
{
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case "highway":
|
|
||||||
if(Enum.TryParse(value, out highwayType hwType))
|
|
||||||
this._tags.TryAdd(key: tagType.highway, hwType);
|
|
||||||
break;
|
|
||||||
case "footway":
|
|
||||||
if(Enum.TryParse(value, out footwayType fwType))
|
|
||||||
this._tags.TryAdd(tagType.footway, fwType);
|
|
||||||
break;
|
|
||||||
case "oneway":
|
|
||||||
if (value.Equals("yes", StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
this._tags.TryAdd(tagType.oneway, (byte)1);
|
|
||||||
}
|
|
||||||
else if (value.Equals("no", StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
this._tags.TryAdd(tagType.oneway, (byte)0);
|
|
||||||
}
|
|
||||||
else if (value.Equals("reversible", StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
this._tags.TryAdd(tagType.oneway, (byte)1);
|
|
||||||
this._tags.TryAdd(tagType.forward, (byte)0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "sidewalk":
|
|
||||||
if(Enum.TryParse(value, out sidewalkSide swType))
|
|
||||||
this._tags.TryAdd(tagType.footway, swType);
|
|
||||||
break;
|
|
||||||
case "cycleway":
|
|
||||||
if(Enum.TryParse(value, out cyclewayType cwType))
|
|
||||||
this._tags.TryAdd(tagType.footway, cwType);
|
|
||||||
break;
|
|
||||||
case "busway":
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case "maxspeed":
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this._tags.TryAdd(tagType.maxspeed, Convert.ToByte(value));
|
|
||||||
}
|
|
||||||
catch (FormatException e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("maxspeed '{0}' is not a number", value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "name":
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case "surface":
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case "lanes":
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case "access":
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case "tracktype":
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Console.WriteLine("Unknown Tag: {0} Value: {1}", key, value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTag(byte tag, byte value)
|
|
||||||
{
|
|
||||||
switch ((tagType)tag)
|
|
||||||
{
|
|
||||||
case tagType.highway:
|
|
||||||
this._tags.TryAdd(tagType.highway, (highwayType)value);
|
|
||||||
break;
|
|
||||||
case tagType.footway:
|
|
||||||
this._tags.TryAdd(tagType.footway, (footwayType)value);
|
|
||||||
break;
|
|
||||||
case tagType.oneway:
|
|
||||||
this._tags.TryAdd(tagType.oneway, value);
|
|
||||||
break;
|
|
||||||
case tagType.sidewalk:
|
|
||||||
this._tags.TryAdd(tagType.sidewalk, (sidewalkSide)value);
|
|
||||||
break;
|
|
||||||
case tagType.cycleway:
|
|
||||||
this._tags.TryAdd(tagType.cycleway, (cyclewayType)value);
|
|
||||||
break;
|
|
||||||
case tagType.busway:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case tagType.maxspeed:
|
|
||||||
this._tags.TryAdd(tagType.maxspeed, value);
|
|
||||||
break;
|
|
||||||
case tagType.name:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case tagType.surface:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case tagType.lanes:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case tagType.access:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case tagType.tracktype:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ImportTags(Dictionary<string, string> tags)
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<string, string> tag in tags)
|
|
||||||
{
|
|
||||||
this.AddTag(tag.Key, tag.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? GetTag(string key)
|
|
||||||
{
|
|
||||||
if (Enum.TryParse(key, out tagType tag))
|
|
||||||
{
|
|
||||||
return this._tags.ContainsKey(tag) ? this._tags[tag] : null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<tagType, object> GetTags()
|
|
||||||
{
|
|
||||||
return this._tags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +1,42 @@
|
|||||||
using System.Globalization;
|
namespace OSMDatastructure;
|
||||||
|
|
||||||
namespace OSMDatastructure
|
public class Coordinates
|
||||||
{
|
{
|
||||||
public class Coordinates
|
public float latitude { get; }
|
||||||
|
public float longitude { get; }
|
||||||
|
|
||||||
|
public Coordinates(float latitude, float longitude)
|
||||||
{
|
{
|
||||||
public float lat { get; }
|
this.latitude = latitude;
|
||||||
public float lon { get; }
|
this.longitude = longitude;
|
||||||
|
}
|
||||||
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 % Region.regionSize;
|
|
||||||
float lonRegion = this.lon - this.lon % Region.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));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (obj != null && obj.GetType() == this.GetType())
|
|
||||||
{
|
|
||||||
Coordinates objconv = (Coordinates)obj;
|
|
||||||
if (objconv.lat.Equals(this.lat) && objconv.lon.Equals(this.lon))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != this.GetType())
|
||||||
return false;
|
return false;
|
||||||
}
|
Coordinates convObj = (Coordinates)obj;
|
||||||
|
// ReSharper disable twice CompareOfFloatsByEqualityOperator static values
|
||||||
|
return convObj.latitude == this.latitude && convObj.longitude == this.longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float decimalCoordsSave = 10000;
|
||||||
|
private const ulong offset = 10000000;
|
||||||
|
//Latitude maxChars = 7
|
||||||
|
//Longitude maxChars = 8
|
||||||
|
public ulong GetHash()
|
||||||
|
{
|
||||||
|
ulong latHash = Convert.ToUInt64((this.latitude + 90) * decimalCoordsSave);
|
||||||
|
ulong lonHash = Convert.ToUInt64((this.longitude + 180) * decimalCoordsSave);
|
||||||
|
return latHash * offset + lonHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong GetRegionHash()
|
||||||
|
{
|
||||||
|
float latRegion = this.latitude - this.latitude % Region.regionSize;
|
||||||
|
float lonRegion = this.longitude - this.longitude % Region.regionSize;
|
||||||
|
ulong latHash = Convert.ToUInt64((latRegion + 90) * decimalCoordsSave);
|
||||||
|
ulong lonHash = Convert.ToUInt64((lonRegion + 180) * decimalCoordsSave);
|
||||||
|
return latHash * offset + lonHash;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,22 +0,0 @@
|
|||||||
namespace OSMDatastructure
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,4 +6,8 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Geo-Graph\Geo-Graph\Geo-Graph.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
172
OSMDatastructure/OSMEdge.cs
Normal file
172
OSMDatastructure/OSMEdge.cs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
namespace OSMDatastructure;
|
||||||
|
|
||||||
|
public class OsmEdge
|
||||||
|
{
|
||||||
|
public Coordinates neighborCoordinates { get; }
|
||||||
|
public Dictionary<tagType, object> tags { get; }
|
||||||
|
|
||||||
|
public OsmEdge(float lat, float lon)
|
||||||
|
{
|
||||||
|
this.neighborCoordinates = new Coordinates(lat, lon);
|
||||||
|
this.tags = new();
|
||||||
|
//TODO tags
|
||||||
|
}
|
||||||
|
|
||||||
|
public OsmEdge(Coordinates neighborCoordinates)
|
||||||
|
{
|
||||||
|
this.neighborCoordinates = neighborCoordinates;
|
||||||
|
this.tags = new();
|
||||||
|
//TODO tags
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum tagType : byte
|
||||||
|
{
|
||||||
|
highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype, id
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<wayType, byte> speedcar = new() {
|
||||||
|
{ wayType.NONE, 0 },
|
||||||
|
{ wayType.motorway, 110 },
|
||||||
|
{ wayType.trunk, 100 },
|
||||||
|
{ wayType.primary, 80 },
|
||||||
|
{ wayType.secondary, 80 },
|
||||||
|
{ wayType.tertiary, 70 },
|
||||||
|
{ wayType.unclassified, 20 },
|
||||||
|
{ wayType.residential, 10 },
|
||||||
|
{ wayType.motorway_link, 50 },
|
||||||
|
{wayType.trunk_link, 50 },
|
||||||
|
{wayType.primary_link, 30 },
|
||||||
|
{ wayType.secondary_link, 25 },
|
||||||
|
{ wayType.tertiary_link, 25 },
|
||||||
|
{ wayType.living_street, 10 },
|
||||||
|
{ wayType.service, 0 },
|
||||||
|
{ wayType.pedestrian, 0 },
|
||||||
|
{ wayType.track, 0 },
|
||||||
|
{ wayType.bus_guideway, 0 },
|
||||||
|
{ wayType.escape, 0 },
|
||||||
|
{ wayType.raceway, 0 },
|
||||||
|
{ wayType.road, 25 },
|
||||||
|
{ wayType.busway, 0 },
|
||||||
|
{ wayType.footway, 0 },
|
||||||
|
{ wayType.bridleway, 0 },
|
||||||
|
{ wayType.steps, 0 },
|
||||||
|
{ wayType.corridor, 0 },
|
||||||
|
{ wayType.path, 0 },
|
||||||
|
{ wayType.cycleway, 0 },
|
||||||
|
{ wayType.construction, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Dictionary<wayType, byte> speedped = new() {
|
||||||
|
{ wayType.NONE, 0 },
|
||||||
|
{ wayType.motorway, 0 },
|
||||||
|
{ wayType.trunk, 0 },
|
||||||
|
{ wayType.primary, 0 },
|
||||||
|
{ wayType.secondary, 0 },
|
||||||
|
{ wayType.tertiary, 0 },
|
||||||
|
{ wayType.unclassified, 1 },
|
||||||
|
{ wayType.residential, 3 },
|
||||||
|
{ wayType.motorway_link, 0 },
|
||||||
|
{ wayType.trunk_link, 0 },
|
||||||
|
{ wayType.primary_link, 0 },
|
||||||
|
{ wayType.secondary_link, 0 },
|
||||||
|
{ wayType.tertiary_link, 0 },
|
||||||
|
{ wayType.living_street, 5 },
|
||||||
|
{ wayType.service, 2 },
|
||||||
|
{ wayType.pedestrian, 5 },
|
||||||
|
{ wayType.track, 0 },
|
||||||
|
{ wayType.bus_guideway, 0 },
|
||||||
|
{ wayType.escape, 0 },
|
||||||
|
{ wayType.raceway, 0 },
|
||||||
|
{ wayType.road, 3 },
|
||||||
|
{ wayType.busway, 0 },
|
||||||
|
{ wayType.footway, 4 },
|
||||||
|
{ wayType.bridleway, 1 },
|
||||||
|
{ wayType.steps, 2 },
|
||||||
|
{ wayType.corridor, 3 },
|
||||||
|
{ wayType.path, 4 },
|
||||||
|
{ wayType.cycleway, 2 },
|
||||||
|
{ wayType.construction, 0 }
|
||||||
|
};
|
||||||
|
public enum wayType { NONE, motorway, trunk, primary, secondary, tertiary, unclassified, residential, motorway_link, trunk_link, primary_link, secondary_link, tertiary_link, living_street, service, pedestrian, track, bus_guideway, escape, raceway, road, busway, footway, bridleway, steps, corridor, path, cycleway, construction }
|
||||||
|
|
||||||
|
public enum speedType { pedestrian, car, road }
|
||||||
|
|
||||||
|
public void AddTag(string key, string value)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case "highway":
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.tags.Add(tagType.highway, (wayType)Enum.Parse(typeof(wayType), value, true));
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "maxspeed":
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.tags.Add(tagType.maxspeed, Convert.ToByte(value));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "oneway":
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "yes":
|
||||||
|
this.tags.Add(tagType.oneway, true);
|
||||||
|
break;
|
||||||
|
case "-1":
|
||||||
|
this.tags.Add(tagType.forward, false);
|
||||||
|
break;
|
||||||
|
case "no":
|
||||||
|
this.tags.Add(tagType.oneway, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "id":
|
||||||
|
this.tags.Add(tagType.id, Convert.ToUInt64(value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong GetId()
|
||||||
|
{
|
||||||
|
return this.tags.ContainsKey(tagType.id) ? (ulong)this.tags[tagType.id] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public wayType GetHighwayType()
|
||||||
|
{
|
||||||
|
return this.tags.ContainsKey(tagType.highway) ? (wayType)this.tags[tagType.highway] : wayType.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsOneWay()
|
||||||
|
{
|
||||||
|
return this.tags.ContainsKey(tagType.oneway) && (bool)this.tags[tagType.oneway];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte? GetMaxSpeed(speedType type)
|
||||||
|
{
|
||||||
|
if(type == speedType.road)
|
||||||
|
{
|
||||||
|
return this.tags.ContainsKey(tagType.maxspeed) ? (byte)this.tags[tagType.maxspeed] : null;
|
||||||
|
}
|
||||||
|
if(type == speedType.car)
|
||||||
|
{
|
||||||
|
return this.tags.ContainsKey(tagType.maxspeed)
|
||||||
|
? (byte)this.tags[tagType.maxspeed]
|
||||||
|
: speedcar[this.GetHighwayType()];
|
||||||
|
}
|
||||||
|
return speedped[this.GetHighwayType()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsForward()
|
||||||
|
{
|
||||||
|
return this.tags.ContainsKey(tagType.forward) && (bool)this.tags[tagType.forward];
|
||||||
|
}
|
||||||
|
}
|
33
OSMDatastructure/OsmNode.cs
Normal file
33
OSMDatastructure/OsmNode.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using GeoGraph;
|
||||||
|
|
||||||
|
namespace OSMDatastructure;
|
||||||
|
|
||||||
|
public class OsmNode : Node
|
||||||
|
{
|
||||||
|
public new HashSet<OsmEdge> edges { get; }
|
||||||
|
public Coordinates coordinates { get; }
|
||||||
|
|
||||||
|
public OsmNode previousPathNode = null;
|
||||||
|
public double currentPathWeight = double.MaxValue;
|
||||||
|
public double DirectDistanceToGoal = double.MaxValue;
|
||||||
|
|
||||||
|
public OsmNode(float lat, float lon) : base(lat, lon)
|
||||||
|
{
|
||||||
|
this.edges = new();
|
||||||
|
this.coordinates = new Coordinates(lat, lon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OsmNode(Coordinates coordinates) : base(coordinates.latitude, coordinates.longitude)
|
||||||
|
{
|
||||||
|
this.edges = new();
|
||||||
|
this.coordinates = new Coordinates(lat, lon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OsmEdge? GetEdgeToNode(OsmNode n)
|
||||||
|
{
|
||||||
|
foreach (OsmEdge e in this.edges)
|
||||||
|
if (e.neighborCoordinates.Equals(n.coordinates))
|
||||||
|
return e;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,51 +1,26 @@
|
|||||||
namespace OSMDatastructure
|
namespace OSMDatastructure;
|
||||||
|
|
||||||
|
public class Region
|
||||||
{
|
{
|
||||||
public class Region
|
public const float regionSize = 0.01f;
|
||||||
|
public readonly HashSet<OsmNode> nodes = new();
|
||||||
|
public ulong regionHash { get; }
|
||||||
|
|
||||||
|
public Region(ulong regionHash)
|
||||||
{
|
{
|
||||||
public const float regionSize = 0.01f; //For Splitting
|
this.regionHash = regionHash;
|
||||||
private readonly Dictionary<ulong, Node> _nodesInRegion = new();
|
}
|
||||||
public ulong regionHash { get; }
|
|
||||||
|
|
||||||
public Region(Coordinates regionCoordinates)
|
public Region(Coordinates regionCoordinates)
|
||||||
{
|
{
|
||||||
this.regionHash = regionCoordinates.GetRegionHash();
|
this.regionHash = regionCoordinates.GetRegionHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Region(ulong nodeId, Node firstNode)
|
public OsmNode? GetNode(Coordinates coordinates)
|
||||||
{
|
{
|
||||||
this.regionHash = firstNode.GetRegionHash();
|
foreach(OsmNode node in this.nodes)
|
||||||
this._nodesInRegion.Add(nodeId, value: firstNode);
|
if (node.coordinates.Equals(coordinates))
|
||||||
}
|
return node;
|
||||||
|
return null;
|
||||||
public Region(ulong regionHash)
|
|
||||||
{
|
|
||||||
this.regionHash = regionHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddNode(ulong nodeId, Node node)
|
|
||||||
{
|
|
||||||
this._nodesInRegion.Add(nodeId, value: node);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<ulong, Node> GetNodes()
|
|
||||||
{
|
|
||||||
return this._nodesInRegion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node? GetNode(ulong id)
|
|
||||||
{
|
|
||||||
return this._nodesInRegion.ContainsKey(id) ? this._nodesInRegion[id] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node? GetNode(Coordinates coordinates)
|
|
||||||
{
|
|
||||||
foreach (Node node in this._nodesInRegion.Values)
|
|
||||||
{
|
|
||||||
if (node.Equals(coordinates))
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +0,0 @@
|
|||||||
namespace OSMDatastructure;
|
|
||||||
|
|
||||||
public enum cyclewayType : byte
|
|
||||||
{
|
|
||||||
lane,
|
|
||||||
opposite,
|
|
||||||
opposite_lane,
|
|
||||||
track,
|
|
||||||
opposite_track,
|
|
||||||
share_busway,
|
|
||||||
opposite_share_busway,
|
|
||||||
shared_lane
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace OSMDatastructure;
|
|
||||||
|
|
||||||
public enum footwayType : byte
|
|
||||||
{
|
|
||||||
sidewalk,
|
|
||||||
crossing
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
namespace OSMDatastructure
|
|
||||||
{
|
|
||||||
public enum highwayType : byte
|
|
||||||
{
|
|
||||||
motorway,
|
|
||||||
trunk,
|
|
||||||
primary,
|
|
||||||
secondary,
|
|
||||||
tertiary,
|
|
||||||
unclassified,
|
|
||||||
residential,
|
|
||||||
motorway_link,
|
|
||||||
trunk_link,
|
|
||||||
primary_link,
|
|
||||||
secondary_link,
|
|
||||||
tertiary_link,
|
|
||||||
living_street,
|
|
||||||
service,
|
|
||||||
pedestrian,
|
|
||||||
track,
|
|
||||||
bus_guideway,
|
|
||||||
escape,
|
|
||||||
raceway,
|
|
||||||
road,
|
|
||||||
busway,
|
|
||||||
footway,
|
|
||||||
bridleway,
|
|
||||||
steps,
|
|
||||||
corridor,
|
|
||||||
path,
|
|
||||||
via_ferratsa,
|
|
||||||
cycleway,
|
|
||||||
proposed,
|
|
||||||
construction
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
namespace OSMDatastructure;
|
|
||||||
|
|
||||||
public enum sidewalkSide : byte
|
|
||||||
{
|
|
||||||
both,
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
no
|
|
||||||
}
|
|
@ -1,23 +1,19 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSMSplitter", "OSMSplitter\OSMSplitter.csproj", "{BE5C111D-AD61-433A-AE7E-F02B78551347}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSMDatastructure", "OSMDatastructure\OSMDatastructure.csproj", "{A2489EF1-64E9-41C9-A295-B3D551D810DA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OSMDatastructure", "OSMDatastructure\OSMDatastructure.csproj", "{A2489EF1-64E9-41C9-A295-B3D551D810DA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pathfinding", "Pathfinding\Pathfinding.csproj", "{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pathfinding", "Pathfinding\Pathfinding.csproj", "{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geo-Graph", "..\Geo-Graph\Geo-Graph\Geo-Graph.csproj", "{2F3E2E4A-6C1E-46AF-AC2C-62E5D4E317A0}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{BE5C111D-AD61-433A-AE7E-F02B78551347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{BE5C111D-AD61-433A-AE7E-F02B78551347}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{BE5C111D-AD61-433A-AE7E-F02B78551347}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{BE5C111D-AD61-433A-AE7E-F02B78551347}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{7E025EFC-B889-4B57-A03F-EF294CFFBCD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@ -30,5 +26,9 @@ Global
|
|||||||
{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D4AA1C47-98D4-415C-B026-3BC25B6B6F9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2F3E2E4A-6C1E-46AF-AC2C-62E5D4E317A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2F3E2E4A-6C1E-46AF-AC2C-62E5D4E317A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2F3E2E4A-6C1E-46AF-AC2C-62E5D4E317A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2F3E2E4A-6C1E-46AF-AC2C-62E5D4E317A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
using OSMDatastructure;
|
|
||||||
|
|
||||||
namespace Pathfinding;
|
|
||||||
|
|
||||||
public class PathNode : Node
|
|
||||||
{
|
|
||||||
public PathNode? previousPathNode = null;
|
|
||||||
public double currentPathWeight = double.MaxValue;
|
|
||||||
public double DirectDistanceToGoal = double.MaxValue;
|
|
||||||
|
|
||||||
|
|
||||||
public PathNode(float lat, float lon) : base(lat, lon)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PathNode FromNode(Node node)
|
|
||||||
{
|
|
||||||
return new PathNode(node.lat, node.lon);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -6,48 +6,50 @@ namespace Pathfinding;
|
|||||||
public class Pathfinder
|
public class Pathfinder
|
||||||
{
|
{
|
||||||
|
|
||||||
public static List<PathNode> CustomAStar(string workingDir, Coordinates start, Coordinates goal)
|
public static List<OsmNode> CustomAStar(string workingDir, Coordinates start, Coordinates goal)
|
||||||
{
|
{
|
||||||
RegionManager regionManager = new RegionManager(workingDir);
|
RegionManager regionManager = new RegionManager(workingDir);
|
||||||
Region startRegion, goalRegion;
|
Region startRegion, goalRegion;
|
||||||
PathNode startNode, goalNode;
|
OsmNode? startNode, goalNode;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
startRegion = regionManager.GetRegion(start);
|
startRegion = regionManager.GetRegion(start);
|
||||||
startNode = PathNode.FromNode(ClosestNodeToCoordinates(start, startRegion)!); //TODO null handling
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException e)
|
|
||||||
{
|
|
||||||
throw new Exception(string.Format("No region at coordinates {0}", start), e);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
goalRegion = regionManager.GetRegion(goal);
|
goalRegion = regionManager.GetRegion(goal);
|
||||||
goalNode = PathNode.FromNode(ClosestNodeToCoordinates(goal, goalRegion)!); //TODO null handling
|
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException e)
|
catch (FileNotFoundException e)
|
||||||
{
|
{
|
||||||
throw new Exception(string.Format("No region at coordinates {0}", start), e);
|
throw new Exception(string.Format("No region at coordinates {0}", e.FileName), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PathNode> toVisit = new() { startNode };
|
startNode = ClosestNodeToCoordinates(start, startRegion);
|
||||||
startNode.DirectDistanceToGoal = Utils.DistanceBetween(startNode, goalNode);
|
goalNode = ClosestNodeToCoordinates(goal, goalRegion);
|
||||||
|
if (startNode == null || goalNode == null)
|
||||||
|
return new List<OsmNode>();
|
||||||
|
|
||||||
|
List<OsmNode> toVisit = new() { startNode };
|
||||||
|
OsmNode closestNodeToGoal;
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
|
|
||||||
while (toVisit.Count > 0 && !stop)
|
while (toVisit.Count > 0 && !stop)
|
||||||
{
|
{
|
||||||
PathNode closestNodeToGoal = toVisit.First();
|
Console.WriteLine("toVisit length: {0}", toVisit.Count.ToString());
|
||||||
foreach (PathNode node in toVisit)
|
closestNodeToGoal = toVisit.First();
|
||||||
|
foreach (OsmNode node in toVisit)
|
||||||
{
|
{
|
||||||
|
if (node.DirectDistanceToGoal.Equals(double.MaxValue))
|
||||||
|
{
|
||||||
|
node.DirectDistanceToGoal = Utils.DistanceBetween(node, goalNode);
|
||||||
|
}
|
||||||
if (node.DirectDistanceToGoal < closestNodeToGoal.DirectDistanceToGoal)
|
if (node.DirectDistanceToGoal < closestNodeToGoal.DirectDistanceToGoal)
|
||||||
{
|
{
|
||||||
closestNodeToGoal = node;
|
closestNodeToGoal = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Connection connection in closestNodeToGoal.GetConnections())
|
foreach (OsmEdge connection in closestNodeToGoal.edges)
|
||||||
{
|
{
|
||||||
PathNode? neighbor = (PathNode)regionManager.GetNode(connection.endNodeCoordinates);
|
OsmNode? neighbor = regionManager.GetNode(connection.neighborCoordinates);
|
||||||
|
Console.WriteLine(neighbor);
|
||||||
if (neighbor != null && neighbor.currentPathWeight < closestNodeToGoal.currentPathWeight + Utils.DistanceBetween(closestNodeToGoal, neighbor))
|
if (neighbor != null && neighbor.currentPathWeight < closestNodeToGoal.currentPathWeight + Utils.DistanceBetween(closestNodeToGoal, neighbor))
|
||||||
{
|
{
|
||||||
neighbor.previousPathNode = closestNodeToGoal;
|
neighbor.previousPathNode = closestNodeToGoal;
|
||||||
@ -60,40 +62,36 @@ public class Pathfinder
|
|||||||
toVisit.Add(neighbor);
|
toVisit.Add(neighbor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toVisit.Remove(closestNodeToGoal);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PathNode> path = new();
|
List<OsmNode> path = new();
|
||||||
PathNode currentNode = goalNode;
|
OsmNode? currentNode = goalNode;
|
||||||
while (!currentNode.Equals(startNode))
|
while (currentNode != null && !currentNode.Equals(startNode))
|
||||||
{
|
{
|
||||||
path.Add(currentNode);
|
path.Add(currentNode);
|
||||||
currentNode = currentNode.previousPathNode!;
|
currentNode = currentNode.previousPathNode;
|
||||||
}
|
}
|
||||||
path.Add(startNode);
|
path.Add(startNode);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Node? ClosestNodeToCoordinates(Coordinates coordinates, Region region)
|
private static OsmNode? ClosestNodeToCoordinates(Coordinates coordinates, Region region)
|
||||||
{
|
{
|
||||||
ulong? closestId = ClosestNodeIdToCoordinates(coordinates, region);
|
OsmNode? closest = null;
|
||||||
return closestId != null ? region.GetNode((ulong)closestId) : null;
|
double distance = double.MaxValue;
|
||||||
}
|
foreach (OsmNode node in region.nodes)
|
||||||
|
|
||||||
private static ulong? ClosestNodeIdToCoordinates(Coordinates coordinates, Region region)
|
|
||||||
{
|
|
||||||
ulong? closestId = null;
|
|
||||||
double closestDistance = double.MaxValue, distance;
|
|
||||||
|
|
||||||
foreach (KeyValuePair<ulong, Node> kv in region.GetNodes())
|
|
||||||
{
|
{
|
||||||
distance = Utils.DistanceBetween(kv.Value, coordinates);
|
double nodeDistance = Utils.DistanceBetween(node, coordinates);
|
||||||
if (distance < closestDistance)
|
if (nodeDistance < distance)
|
||||||
{
|
{
|
||||||
closestDistance = distance;
|
closest = node;
|
||||||
closestId = kv.Key;
|
distance = nodeDistance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return closestId;
|
|
||||||
|
return closest;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
|
using Pathfinding;
|
||||||
|
|
||||||
namespace OSMImporter
|
namespace OSMImporter
|
||||||
{
|
{
|
||||||
@ -59,23 +60,9 @@ namespace OSMImporter
|
|||||||
return ByteConverter.ToRegion(regionBytes);
|
return ByteConverter.ToRegion(regionBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node? GetNode(ulong id)
|
public OsmNode? GetNode(Coordinates coordinates)
|
||||||
{
|
{
|
||||||
foreach (Region region in this._regions.Values)
|
Region regionWithNode = GetRegion(coordinates);
|
||||||
{
|
|
||||||
Node? node = region.GetNode(id);
|
|
||||||
if (node != null)
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node? GetNode(Coordinates coordinates)
|
|
||||||
{
|
|
||||||
Region? regionWithNode = GetRegion(coordinates);
|
|
||||||
if (regionWithNode == null)
|
|
||||||
return null;//TODO null handling
|
|
||||||
return regionWithNode.GetNode(coordinates);
|
return regionWithNode.GetNode(coordinates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ namespace Pathfinding
|
|||||||
{
|
{
|
||||||
public static double DistanceBetween(Coordinates c1, Coordinates n2)
|
public static double DistanceBetween(Coordinates c1, Coordinates n2)
|
||||||
{
|
{
|
||||||
return DistanceBetween(c1.lat, c1.lon, n2.lat, n2.lon);
|
return DistanceBetween(c1.latitude, c1.longitude, n2.latitude, n2.longitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double DistanceBetween(Coordinates c1, float lat2, float lon2)
|
public static double DistanceBetween(Coordinates c1, float lat2, float lon2)
|
||||||
{
|
{
|
||||||
return DistanceBetween(c1.lat, c1.lon, lat2, lon2);
|
return DistanceBetween(c1.latitude, c1.longitude, lat2, lon2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double DistanceBetween(float lat1, float lon1, Coordinates c2)
|
public static double DistanceBetween(float lat1, float lon1, Coordinates c2)
|
||||||
@ -19,6 +19,21 @@ namespace Pathfinding
|
|||||||
return DistanceBetween(c2, lat1, lon1);
|
return DistanceBetween(c2, lat1, lon1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double DistanceBetween(OsmNode node1, OsmNode node2)
|
||||||
|
{
|
||||||
|
return DistanceBetween(node1.coordinates, node2.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double DistanceBetween(OsmNode node1, Coordinates c2)
|
||||||
|
{
|
||||||
|
return DistanceBetween(node1.coordinates, c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double DistanceBetween(Coordinates c1, OsmNode n2)
|
||||||
|
{
|
||||||
|
return DistanceBetween(c1, n2.coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
public static double DistanceBetween(float lat1, float lon1, float lat2, float lon2) //Law of Cosines
|
public static double DistanceBetween(float lat1, float lon1, float lat2, float lon2) //Law of Cosines
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1,31 +1,14 @@
|
|||||||
using OSMImporter;
|
|
||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
|
using Pathfinding;
|
||||||
|
|
||||||
namespace Server;
|
namespace Server;
|
||||||
|
|
||||||
public class Server
|
public class Server
|
||||||
{
|
{
|
||||||
|
|
||||||
public static Region LoadRegion(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);
|
|
||||||
|
|
||||||
byte[] regionBytes = new byte[fileStream.Length];
|
|
||||||
fileStream.Read(regionBytes, 0, regionBytes.Length);
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return ByteConverter.ToRegion(regionBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Importer.Split("/home/glax/Downloads/bayern-latest.osm", "/home/glax/Downloads/bayern-latest");
|
//XmlImporter.Split("/home/glax/Downloads/oberbayern-latest.osm", "/home/glax/Downloads/oberbayern-latest");
|
||||||
Region r = LoadRegion("/home/glax/Downloads/bayern-latest", new Coordinates(47.890f,12.56f));
|
//Region r = LoadRegion("/home/glax/Downloads/bayern-latest", new Coordinates(47.890f,12.56f));
|
||||||
|
Pathfinder.CustomAStar("/home/glax/Downloads/oberbayern-latest", new Coordinates(48.243351f, 11.640417f), new Coordinates(48.25239f, 11.53272f));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,7 +8,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OSMSplitter\OSMSplitter.csproj" />
|
|
||||||
<ProjectReference Include="..\Pathfinding\Pathfinding.csproj" />
|
<ProjectReference Include="..\Pathfinding\Pathfinding.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user