Compare commits

..

No commits in common. "556b0736f12936896bb4b91d9aaa827131798c0c" and "9444e2ac8e62db2b2d90a546eebbdc93a56822db" have entirely different histories.

7 changed files with 49 additions and 297 deletions

View File

@ -44,7 +44,7 @@ public class OsmEdge
highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype, id, EMPTY highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype, id, EMPTY
} }
private static readonly Dictionary<wayType, byte> defaultSpeedCar = new() { public static Dictionary<wayType, byte> speedcar = new() {
{ wayType.NONE, 0 }, { wayType.NONE, 0 },
{ wayType.motorway, 110 }, { wayType.motorway, 110 },
{ wayType.trunk, 100 }, { wayType.trunk, 100 },
@ -76,7 +76,7 @@ public class OsmEdge
{ wayType.construction, 0 } { wayType.construction, 0 }
}; };
private static readonly Dictionary<wayType, byte> defaultSpeedPedestrian = new() { public static Dictionary<wayType, byte> speedped = new() {
{ wayType.NONE, 0 }, { wayType.NONE, 0 },
{ wayType.motorway, 0 }, { wayType.motorway, 0 },
{ wayType.trunk, 0 }, { wayType.trunk, 0 },
@ -115,7 +115,7 @@ public class OsmEdge
{ {
KeyValuePair<tagType, object> tag = ConvertToTag(key, value); KeyValuePair<tagType, object> tag = ConvertToTag(key, value);
if(tag.Key != tagType.EMPTY) if(tag.Key != tagType.EMPTY)
tags.Add(tag.Key, tag.Value); this.tags.Add(tag.Key, tag.Value);
} }
public static KeyValuePair<tagType, object> ConvertToTag(string key, string value) public static KeyValuePair<tagType, object> ConvertToTag(string key, string value)
@ -134,11 +134,7 @@ public class OsmEdge
case "maxspeed": case "maxspeed":
try try
{ {
byte speed = Convert.ToByte(value); return new KeyValuePair<tagType, object>(tagType.maxspeed, 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) catch (Exception)
{ {
@ -165,64 +161,36 @@ public class OsmEdge
public ulong GetId() public ulong GetId()
{ {
return tags.ContainsKey(tagType.id) ? (ulong)tags[tagType.id] : 0; return this.tags.ContainsKey(tagType.id) ? (ulong)this.tags[tagType.id] : 0;
} }
public wayType GetHighwayType() public wayType GetHighwayType()
{ {
if (!tags.ContainsKey(tagType.highway)) return this.tags.ContainsKey(tagType.highway) ? (wayType)this.tags[tagType.highway] : wayType.NONE;
throw new Exception("Not a road?");
return (wayType)tags[tagType.highway];
} }
public bool IsOneWay() public bool IsOneWay()
{ {
return tags.ContainsKey(tagType.oneway) && (bool)tags[tagType.oneway]; return this.tags.ContainsKey(tagType.oneway) && (bool)this.tags[tagType.oneway];
} }
public byte GetMaxSpeed(speedType type) public byte? GetMaxSpeed(speedType type)
{ {
switch (type) if(type == speedType.road)
{ {
case speedType.road: return this.tags.ContainsKey(tagType.maxspeed) ? (byte)this.tags[tagType.maxspeed] : null;
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;
} }
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() public bool IsForward()
{ {
return this.tags.ContainsKey(tagType.forward) && (bool)this.tags[tagType.forward]; 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;
}
}
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);
}
} }

View File

@ -7,7 +7,6 @@ public class OsmNode
public OsmNode? previousPathNode = null; public OsmNode? previousPathNode = null;
public double currentPathWeight = double.MaxValue; public double currentPathWeight = double.MaxValue;
public double currentPathLength = double.MaxValue;
public double directDistanceToGoal = double.MaxValue; public double directDistanceToGoal = double.MaxValue;
public OsmNode(float lat, float lon) public OsmNode(float lat, float lon)
@ -42,15 +41,9 @@ public class OsmNode
public override string ToString() public override string ToString()
{ {
if(this.previousPathNode != null)
return string.Format( return string.Format(
"NODE {0} Edges-Count: {1} previousPathNode: {2} currentPathWeight: {3} currentPathLength: {4} directDistanceToGoal: {5}", "NODE {0} Edges-Count: {1} previousPathNode: {2} currentPathWeight: {3} directDistanceToGoal: {4}",
this.coordinates.ToString(), this.edges.Count, this.previousPathNode.coordinates.ToString(), this.coordinates.ToString(), this.edges.Count, this.previousPathNode.coordinates.ToString(),
this.currentPathWeight, this.currentPathLength, this.directDistanceToGoal); this.currentPathWeight, this.directDistanceToGoal);
else
return string.Format(
"NODE {0} Edges-Count: {1} previousPathNode: NO PREVIOUS NODE currentPathWeight: {2} currentPathLength: {3} directDistanceToGoal: {4}",
this.coordinates.ToString(), this.edges.Count,
this.currentPathWeight, this.currentPathLength, this.directDistanceToGoal);
} }
} }

View File

@ -6,10 +6,11 @@ namespace Pathfinding;
public class Pathfinder public class Pathfinder
{ {
public static List<OsmNode> CustomAStar(string workingDir, Coordinates start, Coordinates goal, OsmEdge.speedType vehicle) 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;
OsmNode? startNode, goalNode;
try try
{ {
startRegion = regionManager.GetRegion(start); startRegion = regionManager.GetRegion(start);
@ -20,20 +21,18 @@ public class Pathfinder
throw new Exception(string.Format("No region at coordinates {0}", e.FileName), e); throw new Exception(string.Format("No region at coordinates {0}", e.FileName), e);
} }
OsmNode? startNode = ClosestNodeToCoordinates(start, startRegion); startNode = ClosestNodeToCoordinates(start, startRegion);
OsmNode? goalNode = ClosestNodeToCoordinates(goal, goalRegion); goalNode = ClosestNodeToCoordinates(goal, goalRegion);
if (startNode == null || goalNode == null) if (startNode == null || goalNode == null)
return new List<OsmNode>(); return new List<OsmNode>();
List<OsmNode> toVisit = new() { startNode }; List<OsmNode> toVisit = new() { startNode };
OsmNode closestNodeToGoal = toVisit.First(); OsmNode closestNodeToGoal;
closestNodeToGoal.currentPathWeight = 0;
closestNodeToGoal.currentPathLength = 0;
bool stop = false; bool stop = false;
while (toVisit.Count > 0 && !stop) while (toVisit.Count > 0 && !stop)
{ {
//Console.WriteLine("toVisit-length: {0}", toVisit.Count); Console.WriteLine("toVisit length: {0}", toVisit.Count.ToString());
closestNodeToGoal = toVisit.First(); closestNodeToGoal = toVisit.First();
foreach (OsmNode node in toVisit) foreach (OsmNode node in toVisit)
{ {
@ -47,18 +46,15 @@ public class Pathfinder
} }
} }
foreach (OsmEdge edge in closestNodeToGoal.edges) foreach (OsmEdge connection in closestNodeToGoal.edges)
{ {
OsmNode? neighbor = regionManager.GetNode(edge.neighborCoordinates); OsmNode? neighbor = regionManager.GetNode(connection.neighborCoordinates);
if (neighbor != null) Console.WriteLine(neighbor);
{ if (neighbor != null && neighbor.currentPathWeight < closestNodeToGoal.currentPathWeight + Utils.DistanceBetween(closestNodeToGoal, neighbor))
double newPotentialWeight =
closestNodeToGoal.currentPathWeight + edge.GetWeight(closestNodeToGoal, vehicle);
if (neighbor.currentPathWeight > newPotentialWeight)
{ {
neighbor.previousPathNode = closestNodeToGoal; neighbor.previousPathNode = closestNodeToGoal;
neighbor.currentPathWeight = newPotentialWeight; neighbor.currentPathWeight = closestNodeToGoal.currentPathWeight +
neighbor.currentPathLength = closestNodeToGoal.currentPathLength + Utils.DistanceBetween(closestNodeToGoal, neighbor); Utils.DistanceBetween(closestNodeToGoal, neighbor);
if (neighbor.Equals(goalNode)) if (neighbor.Equals(goalNode))
stop = true; stop = true;
@ -66,7 +62,6 @@ public class Pathfinder
toVisit.Add(neighbor); toVisit.Add(neighbor);
} }
} }
}
toVisit.Remove(closestNodeToGoal); toVisit.Remove(closestNodeToGoal);
} }
@ -79,7 +74,6 @@ public class Pathfinder
currentNode = currentNode.previousPathNode; currentNode = currentNode.previousPathNode;
} }
path.Add(startNode); path.Add(startNode);
path.Reverse();
return path; return path;
} }

View File

@ -45,21 +45,18 @@ namespace OSMImporter
private Region LoadRegion(Coordinates coordinates) private Region LoadRegion(Coordinates coordinates)
{ {
string fullPath = Path.Combine(workingDirectory, coordinates.GetRegionHash().ToString()); string fullPath = Path.Combine(workingDirectory, coordinates.GetRegionHash().ToString());
DateTime startTime = DateTime.Now; Console.WriteLine("Loading {0}", fullPath);
if (!File.Exists(fullPath)) if (!File.Exists(fullPath))
{ {
throw new FileNotFoundException(string.Format("[{0}] Region does not exist: {1}", startTime, fullPath)); throw new FileNotFoundException(string.Format("Region does not exist: {0}", fullPath));
} }
FileStream fileStream = new FileStream(fullPath, FileMode.Open); FileStream fileStream = new FileStream(fullPath, FileMode.Open);
long fileStreamLength = fileStream.Length;
Console.WriteLine("[{0}] Loading [{1}]bytes from {2}", startTime.ToLocalTime(), fileStreamLength, fullPath);
byte[] regionBytes = new byte[fileStream.Length]; byte[] regionBytes = new byte[fileStream.Length];
int loadedBytesLength = fileStream.Read(regionBytes, 0, regionBytes.Length); int _ = fileStream.Read(regionBytes, 0, regionBytes.Length);
fileStream.Close(); fileStream.Close();
Console.WriteLine("\tLoaded [{0}]bytes ({1:P1}) in [{2}]ms", loadedBytesLength, fileStreamLength / loadedBytesLength,DateTime.Now.Subtract(startTime).TotalMilliseconds);
return ByteConverter.ToRegion(regionBytes); return ByteConverter.ToRegion(regionBytes);
} }

View File

@ -1,6 +1,6 @@
using OSMDatastructure; using OSMDatastructure;
namespace OSMDatastructure namespace Pathfinding
{ {
public struct Utils public struct Utils
{ {

View File

@ -5,39 +5,10 @@ namespace Server;
public class Server public class Server
{ {
private static void WriteRegionsToFile(HashSet<Region> regions, string outputFolderPath)
{
Console.WriteLine(string.Format("[{0}] Writing files...", DateTime.Now.ToLocalTime()));
Directory.CreateDirectory(outputFolderPath);
foreach (Region region in regions)
{
FileStream regionFileStream =
new FileStream(Path.Combine(outputFolderPath, region.regionHash.ToString()), FileMode.Create);
regionFileStream.Write(ByteConverter.GetBytes(region));
regionFileStream.Close();
}
}
public static void Main(string[] args) public static void Main(string[] args)
{ {
//HashSet<OsmNode> nodes = XmlImporter.ImportXml("/home/glax/Downloads/oberbayern-latest.osm"); //XmlImporter.Split("/home/glax/Downloads/oberbayern-latest.osm", "/home/glax/Downloads/oberbayern-latest");
//HashSet<Region> regions = XmlImporter.SplitIntoRegions(nodes); //Region r = LoadRegion("/home/glax/Downloads/bayern-latest", new Coordinates(47.890f,12.56f));
//WriteRegionsToFile(regions, "/home/glax/Downloads/oberbayern-latest"); Pathfinder.CustomAStar("/home/glax/Downloads/oberbayern-latest", new Coordinates(48.243351f, 11.640417f), new Coordinates(48.25239f, 11.53272f));
Coordinates start = new Coordinates(48.243351f, 11.640417f);
Coordinates finish = new Coordinates(48.25239f, 11.53272f);
OsmNode[] path = Pathfinder.CustomAStar("/home/glax/Downloads/oberbayern-latest", start, finish, OsmEdge.speedType.car).ToArray();
Console.WriteLine("{0}\n", path[0].ToString());
for (int i = 0; i < path.Length - 1; i++)
{
OsmNode n1 = path[i];
OsmNode n2 = path[i + 1];
OsmEdge? e = n1.GetEdgeToNode(n2);
if(e != null)
Console.WriteLine("{0}\n{1}", e.ToString(), n2.ToString());
else
Console.WriteLine("NO EDGE\n{0}", n2.ToString());
}
Console.WriteLine();
} }
} }

View File

@ -1,171 +0,0 @@
using System.Globalization;
using System.Xml;
using OSMDatastructure;
using OSMImporter;
namespace Server;
public static class XmlImporter
{
private static readonly XmlReaderSettings readerSettings = new()
{
IgnoreWhitespace = true,
IgnoreComments = true
};
public static HashSet<OsmNode> ImportXml(string filePath)
{
if (!File.Exists(filePath))
throw new FileNotFoundException();
Console.WriteLine(string.Format("[{0}] Getting highwayNodeIds...", DateTime.Now.ToLocalTime()));
FileStream xmlFileStream = new FileStream(filePath, FileMode.Open);
HashSet<ulong> requiredNodeIds = GetHighwayNodeIds(XmlReader.Create(xmlFileStream, readerSettings));
xmlFileStream.Position = 0;
Console.WriteLine(string.Format("[{0}] Importing Nodes...", DateTime.Now.ToLocalTime()));
Dictionary<ulong, OsmNode> nodes =
GetHighwayNodesFromIds(XmlReader.Create(xmlFileStream, readerSettings), requiredNodeIds);
requiredNodeIds.Clear();
xmlFileStream.Position = 0;
Console.WriteLine(string.Format("[{0}] Importing Ways...", DateTime.Now.ToLocalTime()));
HashSet<OsmNode> retNodes = ConnectNodes(XmlReader.Create(xmlFileStream, readerSettings), nodes);
nodes.Clear();
return retNodes;
}
public static HashSet<Region> SplitIntoRegions(HashSet<OsmNode> nodes)
{
Console.WriteLine(string.Format("[{0}] Splitting into Regions...", DateTime.Now.ToLocalTime()));
Dictionary<ulong, Region> retRegions = new();
foreach (OsmNode node in nodes)
{
ulong regionHash = node.coordinates.GetRegionHash();
if(retRegions.ContainsKey(regionHash))
{
retRegions[regionHash].nodes.Add(node);
}
else
{
Region newRegion = new Region(regionHash);
newRegion.nodes.Add(node);
retRegions.Add(regionHash, newRegion);
}
}
return retRegions.Values.ToHashSet();
}
private static readonly NumberFormatInfo decimalInfo = new()
{
NumberDecimalSeparator = "."
};
private static HashSet<ulong> GetHighwayNodeIds(XmlReader xmlReader)
{
HashSet<ulong> retSet = new();
bool isHighway;
HashSet<ulong> currentIds = new();
while (xmlReader.ReadToFollowing("way"))
{
isHighway = false;
currentIds.Clear();
XmlReader wayReader = xmlReader.ReadSubtree();
while (wayReader.Read())
{
if (xmlReader.Name == "tag" && xmlReader.GetAttribute("k")!.Equals("highway"))
{
isHighway = true;
}
else if (xmlReader.Name == "nd")
{
try
{
currentIds.Add(Convert.ToUInt64(xmlReader.GetAttribute("ref")));
}
catch (FormatException) { };
}
}
if (isHighway)
{
retSet.UnionWith(currentIds);
}
wayReader.Close();
}
xmlReader.Close();
return retSet;
}
private static Dictionary<ulong, OsmNode> GetHighwayNodesFromIds(XmlReader xmlReader, HashSet<ulong> ids)
{
Dictionary<ulong, OsmNode> retDict = new();
while (xmlReader.ReadToFollowing("node"))
{
ulong id = Convert.ToUInt64(xmlReader.GetAttribute("id"));
if (ids.Contains(id))
{
float lat = Convert.ToSingle(xmlReader.GetAttribute("lat")!, decimalInfo);
float lon = Convert.ToSingle(xmlReader.GetAttribute("lon")!, decimalInfo);
retDict.Add(id, new OsmNode(lat, lon));
}
}
xmlReader.Close();
return retDict;
}
private static HashSet<OsmNode> ConnectNodes(XmlReader xmlReader, Dictionary<ulong, OsmNode> dict)
{
while (xmlReader.ReadToFollowing("way"))
{
Dictionary<OsmEdge.tagType, object> tags = new();
List<ulong> wayNodeIds = new();
XmlReader wayReader = xmlReader.ReadSubtree();
while (wayReader.Read())
{
if (xmlReader.Name == "tag")
{
KeyValuePair<OsmEdge.tagType, object> tag =
OsmEdge.ConvertToTag(wayReader.GetAttribute("k")!, wayReader.GetAttribute("v")!);
tags.TryAdd(tag.Key, tag.Value);
}
else if (xmlReader.Name == "nd")
{
wayNodeIds.Add(Convert.ToUInt64(xmlReader.GetAttribute("ref")));
}
}
if (tags.ContainsKey(OsmEdge.tagType.highway))
{
ulong[] ids = wayNodeIds.Where(dict.ContainsKey).ToArray();
for (int i = 0; i < ids.Length - 1; i++)
{
OsmNode n1 = dict[ids[i]];
OsmNode n2 = dict[ids[i + 1]];
if (tags.ContainsKey(OsmEdge.tagType.oneway) && (bool)tags[OsmEdge.tagType.oneway])
{
if (tags.ContainsKey(OsmEdge.tagType.forward) && !(bool)tags[OsmEdge.tagType.forward])
{
n2.edges.Add(new OsmEdge(n1.coordinates, tags));
}
else
{
n1.edges.Add(new OsmEdge(n2.coordinates, tags));
}
}
else
{
n1.edges.Add(new OsmEdge(n2.coordinates, tags));
n2.edges.Add(new OsmEdge(n1.coordinates, tags));
}
}
}
wayReader.Close();
}
xmlReader.Close();
return dict.Values.ToHashSet();
}
}