Combining Datastructures and Serialization
//TODO
This commit is contained in:
@ -1,272 +0,0 @@
|
||||
using System.Text;
|
||||
using OSMDatastructure.Graph;
|
||||
|
||||
namespace OSMDatastructure;
|
||||
|
||||
public static class ByteConverter
|
||||
{
|
||||
#region Region
|
||||
/*
|
||||
* | regionHash | Nodes |
|
||||
* |---------------+---------------+
|
||||
* | 4 bytes |
|
||||
* | int |
|
||||
*/
|
||||
public static byte[] GetBytes(Region region)
|
||||
{
|
||||
int totalNodeBytes = 0;
|
||||
HashSet<byte[]> nodes = new();
|
||||
foreach (OsmNode node in region.nodes)
|
||||
{
|
||||
byte[] nodeBytes = GetBytes(node);
|
||||
totalNodeBytes += nodeBytes.Length;
|
||||
nodes.Add(nodeBytes);
|
||||
}
|
||||
|
||||
byte[] retBytes = new byte[sizeof(int) + totalNodeBytes];
|
||||
Array.Copy(BitConverter.GetBytes(region.regionHash), 0, retBytes, 0, sizeof(int));
|
||||
int offset = sizeof(int);
|
||||
foreach (byte[] node in nodes)
|
||||
{
|
||||
Array.Copy(node, 0, retBytes, offset, node.Length);
|
||||
offset += node.Length;
|
||||
}
|
||||
|
||||
return retBytes;
|
||||
}
|
||||
|
||||
public static Region ToRegion(byte[] bytes)
|
||||
{
|
||||
Region retRegion = new Region(BitConverter.ToInt32(bytes, 0));
|
||||
int offset = sizeof(int);
|
||||
while (offset < bytes.Length)
|
||||
{
|
||||
int size = BitConverter.ToInt32(bytes, offset);
|
||||
byte[] nodeBytes = new byte[size];
|
||||
Array.Copy(bytes, offset, nodeBytes, 0, size);
|
||||
offset += size;
|
||||
retRegion.nodes.Add(ToNode(nodeBytes));
|
||||
}
|
||||
|
||||
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 = sizeof(int) + 8; //size + Coordinates
|
||||
HashSet<byte[]> edges = new();
|
||||
foreach (OsmEdge edge in node.edges)
|
||||
{
|
||||
byte[] edgeBytes = GetBytes(edge);
|
||||
edges.Add(edgeBytes);
|
||||
totalBytes += edgeBytes.Length;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
totalBytes += tagsSize;
|
||||
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;
|
||||
Type objectType = tag.Value.GetType();
|
||||
if (objectType == Type.GetType("System.String"))
|
||||
{
|
||||
objectBytes = Encoding.ASCII.GetBytes((string)tag.Value);
|
||||
}
|
||||
else if (objectType == Type.GetType("System.Boolean"))
|
||||
{
|
||||
objectBytes = BitConverter.GetBytes((bool)tag.Value);
|
||||
}
|
||||
else if (objectType == Type.GetType("System.Int32"))
|
||||
{
|
||||
objectBytes = BitConverter.GetBytes((int)tag.Value);
|
||||
}
|
||||
else if (objectType == Type.GetType("System.UInt64"))
|
||||
{
|
||||
objectBytes = BitConverter.GetBytes((ulong)tag.Value);
|
||||
}
|
||||
else if (objectType == Type.GetType("System.Byte") || objectType.Name == "wayType")
|
||||
{
|
||||
objectBytes = new[] { (byte)tag.Value };
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(string.Format("Tag-Bytes object-Type: {0}", tag.Value.GetType()));
|
||||
}
|
||||
|
||||
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, objectBytes.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, (OsmEdge.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
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace OSMDatastructure.Graph;
|
||||
|
||||
[Serializable]
|
||||
public class Coordinates
|
||||
{
|
||||
public float latitude { get; }
|
||||
@ -20,37 +23,32 @@ public class Coordinates
|
||||
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 override int GetHashCode()
|
||||
{
|
||||
return GetHashCode(latitude, longitude);
|
||||
}
|
||||
|
||||
public static int GetRegionHashCode(float latitude, float longitude)
|
||||
public static ulong GetRegionHashCode(float latitude, float longitude)
|
||||
{
|
||||
float latRegion = latitude - latitude % Region.RegionSize;
|
||||
float lonRegion = longitude - longitude % Region.RegionSize;
|
||||
return GetHashCode(latRegion, lonRegion);
|
||||
}
|
||||
|
||||
public static int GetRegionHashCode(Coordinates coordinates)
|
||||
public static ulong GetRegionHashCode(Coordinates coordinates)
|
||||
{
|
||||
float latRegion = coordinates.latitude - coordinates.latitude % Region.RegionSize;
|
||||
float lonRegion = coordinates.longitude - coordinates.longitude % Region.RegionSize;
|
||||
return GetHashCode(latRegion, lonRegion);
|
||||
}
|
||||
|
||||
public static int GetHashCode(float latitude, float longitude)
|
||||
|
||||
private const float decimalCoordsSave = 10000; //Latitude maxChars = 7
|
||||
private const ulong offset = 10000000; //Longitude maxChars = 8
|
||||
public static ulong GetHashCode(float latitude, float longitude)
|
||||
{
|
||||
return HashCode.Combine(latitude, longitude);
|
||||
ulong latHash = Convert.ToUInt64((latitude + 90) * decimalCoordsSave);
|
||||
ulong lonHash = Convert.ToUInt64((longitude + 180) * decimalCoordsSave);
|
||||
return latHash * offset + lonHash;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("COORDINATES Lat: {0} Lon: {1}", this.latitude, this.longitude);
|
||||
return
|
||||
$"COORDINATES Lat: {this.latitude.ToString(NumberFormatInfo.InvariantInfo)} Lon: {this.longitude.ToString(CultureInfo.InvariantCulture)}";
|
||||
}
|
||||
}
|
@ -1,228 +1,22 @@
|
||||
namespace OSMDatastructure.Graph;
|
||||
|
||||
[Serializable]
|
||||
public class OsmEdge
|
||||
{
|
||||
public Coordinates neighborCoordinates { get; }
|
||||
public readonly Dictionary<tagType, object> tags = new();
|
||||
|
||||
public OsmEdge(float lat, float lon)
|
||||
{
|
||||
this.neighborCoordinates = new Coordinates(lat, lon);
|
||||
this.tags = new();
|
||||
}
|
||||
public ulong wayId { get; }
|
||||
public ulong neighborId { get; }
|
||||
public ulong neighborRegion { get; }
|
||||
|
||||
public OsmEdge(Coordinates neighborCoordinates)
|
||||
|
||||
public OsmEdge(ulong wayID, ulong neighborID, ulong neighborRegion)
|
||||
{
|
||||
this.neighborCoordinates = neighborCoordinates;
|
||||
this.tags = new();
|
||||
}
|
||||
|
||||
public OsmEdge(float lat, float lon, Dictionary<tagType, object> tags)
|
||||
{
|
||||
this.neighborCoordinates = new Coordinates(lat, lon);
|
||||
//To prevent "EMPTY" tags
|
||||
foreach (KeyValuePair<tagType, object> tag in tags)
|
||||
{
|
||||
if(tag.Key != tagType.EMPTY)
|
||||
this.tags.Add(tag.Key, tag.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public OsmEdge(Coordinates neighborCoordinates, Dictionary<tagType, object> tags)
|
||||
{
|
||||
this.neighborCoordinates = neighborCoordinates;
|
||||
//To prevent "EMPTY" tags
|
||||
foreach (KeyValuePair<tagType, object> tag in tags)
|
||||
{
|
||||
if(tag.Key != tagType.EMPTY)
|
||||
this.tags.Add(tag.Key, tag.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public enum tagType : byte
|
||||
{
|
||||
highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype, id, EMPTY
|
||||
}
|
||||
|
||||
private static readonly Dictionary<wayType, byte> defaultSpeedCar = 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 }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<wayType, byte> defaultSpeedPedestrian = 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 : byte { 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)
|
||||
{
|
||||
KeyValuePair<tagType, object> tag = ConvertToTag(key, value);
|
||||
if(tag.Key != tagType.EMPTY)
|
||||
tags.Add(tag.Key, tag.Value);
|
||||
}
|
||||
|
||||
public static KeyValuePair<tagType, object> ConvertToTag(string key, string value)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case "highway":
|
||||
try
|
||||
{
|
||||
return new KeyValuePair<tagType, object>(tagType.highway, (wayType)Enum.Parse(typeof(wayType), value, true));
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return new KeyValuePair<tagType, object>(tagType.highway, wayType.unclassified);
|
||||
}
|
||||
case "maxspeed":
|
||||
try
|
||||
{
|
||||
byte speed = Convert.ToByte(value);
|
||||
if(speed == 255)
|
||||
return new KeyValuePair<tagType, object>(tagType.EMPTY, 0);
|
||||
else
|
||||
return new KeyValuePair<tagType, object>(tagType.maxspeed, speed);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Console.WriteLine(e);
|
||||
//Console.WriteLine("Continuing...");
|
||||
return new KeyValuePair<tagType, object>(tagType.maxspeed, byte.MaxValue);
|
||||
}
|
||||
case "oneway":
|
||||
switch (value)
|
||||
{
|
||||
case "yes":
|
||||
return new KeyValuePair<tagType, object>(tagType.oneway, true);
|
||||
case "-1":
|
||||
return new KeyValuePair<tagType, object>(tagType.forward, false);
|
||||
case "no":
|
||||
return new KeyValuePair<tagType, object>(tagType.oneway, false);
|
||||
}
|
||||
break;
|
||||
case "id":
|
||||
return new KeyValuePair<tagType, object>(tagType.id, Convert.ToUInt64(value));
|
||||
}
|
||||
return new KeyValuePair<tagType, object>(tagType.EMPTY, 0);
|
||||
}
|
||||
|
||||
public ulong GetId()
|
||||
{
|
||||
return tags.ContainsKey(tagType.id) ? (ulong)tags[tagType.id] : 0;
|
||||
}
|
||||
|
||||
public wayType GetHighwayType()
|
||||
{
|
||||
if (!tags.ContainsKey(tagType.highway))
|
||||
throw new Exception("Not a road?");
|
||||
return (wayType)tags[tagType.highway];
|
||||
}
|
||||
|
||||
public bool IsOneWay()
|
||||
{
|
||||
return tags.ContainsKey(tagType.oneway) && (bool)tags[tagType.oneway];
|
||||
}
|
||||
|
||||
public byte GetMaxSpeed(speedType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case speedType.road:
|
||||
return tags.ContainsKey(tagType.maxspeed) ? (byte)tags[tagType.maxspeed] : (byte)0;
|
||||
case speedType.car:
|
||||
return tags.ContainsKey(tagType.maxspeed) ? (byte)tags[tagType.maxspeed] : defaultSpeedCar[GetHighwayType()];
|
||||
case speedType.pedestrian:
|
||||
return defaultSpeedPedestrian[GetHighwayType()];
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsForward()
|
||||
{
|
||||
return this.tags.ContainsKey(tagType.forward) && (bool)this.tags[tagType.forward];
|
||||
}
|
||||
|
||||
public double GetWeight(OsmNode parentNode, speedType vehicle)
|
||||
{
|
||||
double distance = Utils.DistanceBetween(parentNode, neighborCoordinates);
|
||||
byte speedByte = GetMaxSpeed(vehicle);
|
||||
if (speedByte > 0)
|
||||
{
|
||||
double speed = Convert.ToDouble(speedByte);
|
||||
return distance / speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return double.MaxValue;
|
||||
}
|
||||
this.wayId = wayID;
|
||||
this.neighborId = neighborID;
|
||||
this.neighborRegion = neighborRegion;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string tagsString = "";
|
||||
foreach (KeyValuePair<tagType, object> tag in tags)
|
||||
{
|
||||
tagsString += string.Format("\n\t{0}: {1}", tag.Key, tag.Value);
|
||||
}
|
||||
|
||||
return string.Format("EDGE neighborCoordinates: {0} {1}", neighborCoordinates.ToString(), tagsString);
|
||||
return $"EDGE WayID: {wayId} NeighborID: {neighborId} {neighborRegion}";
|
||||
}
|
||||
}
|
@ -1,23 +1,27 @@
|
||||
namespace OSMDatastructure.Graph;
|
||||
|
||||
[Serializable]
|
||||
public class OsmNode
|
||||
{
|
||||
public ulong nodeId { get; }
|
||||
public HashSet<OsmEdge> edges { get; }
|
||||
public Coordinates coordinates { get; }
|
||||
|
||||
public OsmNode? previousPathNode = null;
|
||||
public double currentPathWeight = double.MaxValue;
|
||||
public double currentPathLength = double.MaxValue;
|
||||
public double directDistanceToGoal = double.MaxValue;
|
||||
[NonSerialized]public OsmNode? previousPathNode = null;
|
||||
[NonSerialized]public double currentPathWeight = double.MaxValue;
|
||||
[NonSerialized]public double currentPathLength = double.MaxValue;
|
||||
[NonSerialized]public double directDistanceToGoal = double.MaxValue;
|
||||
|
||||
public OsmNode(float lat, float lon)
|
||||
public OsmNode(ulong nodeId, float lat, float lon)
|
||||
{
|
||||
this.nodeId = nodeId;
|
||||
this.edges = new();
|
||||
this.coordinates = new Coordinates(lat, lon);
|
||||
}
|
||||
|
||||
public OsmNode(Coordinates coordinates)
|
||||
public OsmNode(ulong nodeId, Coordinates coordinates)
|
||||
{
|
||||
this.nodeId = nodeId;
|
||||
this.edges = new();
|
||||
this.coordinates = coordinates;
|
||||
}
|
||||
@ -25,14 +29,14 @@ public class OsmNode
|
||||
public OsmEdge? GetEdgeToNode(OsmNode n)
|
||||
{
|
||||
foreach (OsmEdge e in this.edges)
|
||||
if (e.neighborCoordinates.Equals(n.coordinates))
|
||||
if (e.neighborId == n.nodeId)
|
||||
return e;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj != null && obj.GetType() == this.GetType() && ((OsmNode)obj).coordinates.Equals(this.coordinates);
|
||||
return obj != null && obj.GetType() == this.GetType() && ((OsmNode)obj).nodeId == this.nodeId;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
@ -2,20 +2,24 @@ using OSMDatastructure.Graph;
|
||||
|
||||
namespace OSMDatastructure;
|
||||
|
||||
[Serializable]
|
||||
public class Region
|
||||
{
|
||||
public const float RegionSize = 0.01f;
|
||||
[NonSerialized]public const float RegionSize = 0.01f;
|
||||
public readonly HashSet<OsmNode> nodes = new();
|
||||
public int regionHash { get; }
|
||||
public ulong regionHash { get; }
|
||||
public TagManager tagManager { get; }
|
||||
|
||||
public Region(int regionHash)
|
||||
public Region(ulong regionHash)
|
||||
{
|
||||
this.regionHash = regionHash;
|
||||
tagManager = new TagManager();
|
||||
}
|
||||
|
||||
public Region(Coordinates coordinates)
|
||||
{
|
||||
regionHash = Coordinates.GetRegionHashCode(coordinates);
|
||||
tagManager = new TagManager();
|
||||
}
|
||||
|
||||
public OsmNode? GetNodeWithCoordinates(Coordinates coordinates)
|
||||
|
150
OSMDatastructure/Tag.cs
Normal file
150
OSMDatastructure/Tag.cs
Normal file
@ -0,0 +1,150 @@
|
||||
namespace OSMDatastructure.Graph;
|
||||
|
||||
[Serializable]
|
||||
public class Tag
|
||||
{
|
||||
public TagType key { get; }
|
||||
public dynamic value { get; }
|
||||
|
||||
|
||||
public Tag(TagType key, dynamic value)
|
||||
{
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static Tag FromBytes(byte[] bytes)
|
||||
{
|
||||
TagType type = (TagType)bytes[0];
|
||||
dynamic value = false;
|
||||
switch (type)
|
||||
{
|
||||
case TagType.highway:
|
||||
case TagType.oneway:
|
||||
case TagType.forward:
|
||||
value = BitConverter.ToBoolean(bytes, 1);
|
||||
break;
|
||||
case TagType.maxspeed:
|
||||
value = bytes[1];
|
||||
break;
|
||||
}
|
||||
|
||||
return new Tag(type, value);
|
||||
}
|
||||
|
||||
public static Tag ConvertToTag(string key, string value)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case "highway":
|
||||
try
|
||||
{
|
||||
return new Tag(Tag.TagType.highway, (Tag.WayType)Enum.Parse(typeof(Tag.WayType), value, true));
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return new Tag(Tag.TagType.highway, Tag.WayType.unclassified);
|
||||
}
|
||||
case "maxspeed":
|
||||
try
|
||||
{
|
||||
byte speed = Convert.ToByte(value);
|
||||
if (speed == 255)
|
||||
return new Tag(Tag.TagType.highway, false);
|
||||
else
|
||||
return new Tag(Tag.TagType.maxspeed, speed);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//Console.WriteLine(e);
|
||||
//Console.WriteLine("Continuing...");
|
||||
return new Tag(Tag.TagType.maxspeed, byte.MaxValue);
|
||||
}
|
||||
case "oneway":
|
||||
switch (value)
|
||||
{
|
||||
case "yes":
|
||||
return new Tag(Tag.TagType.oneway, true);
|
||||
case "-1":
|
||||
return new Tag(Tag.TagType.forward, false);
|
||||
case "no":
|
||||
return new Tag(Tag.TagType.oneway, false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return new Tag(Tag.TagType.EMPTY, false);
|
||||
}
|
||||
|
||||
public enum TagType : byte
|
||||
{
|
||||
highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype, id, EMPTY
|
||||
}
|
||||
|
||||
public static readonly Dictionary<WayType, byte> defaultSpeedCar = 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 readonly Dictionary<WayType, byte> defaultSpeedPedestrian = 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 : byte { 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 }
|
||||
}
|
45
OSMDatastructure/TagManager.cs
Normal file
45
OSMDatastructure/TagManager.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace OSMDatastructure.Graph;
|
||||
|
||||
[Serializable]
|
||||
public class TagManager
|
||||
{
|
||||
public readonly Dictionary<ulong, HashSet<Tag>> wayTags = new();
|
||||
|
||||
public bool ContainsKey(ulong wayId, Tag.TagType key)
|
||||
{
|
||||
return wayTags.ContainsKey(wayId) && wayTags[wayId].Any(tag => tag.key == key);
|
||||
}
|
||||
|
||||
public object? GetTag(ulong wayId, Tag.TagType key)
|
||||
{
|
||||
return ContainsKey(wayId, key) ? wayTags[wayId].First(tag => tag.key == key) : null;
|
||||
}
|
||||
|
||||
public void AddTag(ulong wayId, string key, string value)
|
||||
{
|
||||
Tag tag = Tag.ConvertToTag(key, value);
|
||||
AddTag(wayId, tag);
|
||||
}
|
||||
|
||||
public void AddTag(ulong wayId, Tag tag)
|
||||
{
|
||||
if (tag.key != Tag.TagType.EMPTY)
|
||||
{
|
||||
if(!wayTags.ContainsKey(wayId))
|
||||
wayTags.Add(wayId, new HashSet<Tag>());
|
||||
wayTags[wayId].Add(tag);
|
||||
}
|
||||
}
|
||||
|
||||
public HashSet<Tag>? GetTagsForWayId(ulong wayId)
|
||||
{
|
||||
return wayTags.TryGetValue(wayId, out HashSet<Tag>? value) ? value : null;
|
||||
}
|
||||
|
||||
public bool ContainsWay(ulong wayId)
|
||||
{
|
||||
return wayTags.ContainsKey(wayId);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user