Save Pathfinding result to file.

Load result for render.
This commit is contained in:
glax 2023-04-13 19:18:25 +02:00
parent 08ebc9a26b
commit 055a751c9d
8 changed files with 123 additions and 50 deletions

View File

@ -16,23 +16,20 @@ var app = builder.Build();
app.MapGet("/getRoute", (float latStart, float lonStart, float latEnd, float lonEnd, Tag.SpeedType vehicle, double stayOnSameRoadPriority, double useHigherLevelRoadsPriority, double useRoadsWithLessJunctionsPriority) => app.MapGet("/getRoute", (float latStart, float lonStart, float latEnd, float lonEnd, Tag.SpeedType vehicle, double stayOnSameRoadPriority, double useHigherLevelRoadsPriority, double useRoadsWithLessJunctionsPriority) =>
{ {
DateTime startCalc = DateTime.Now;
List<PathNode> result = Pathfinder.AStar("D:/stuttgart-regbez-latest", new Coordinates(latStart, lonStart), PathResult result = Pathfinder.AStar("D:/stuttgart-regbez-latest", new Coordinates(latStart, lonStart),
new Coordinates(latEnd, lonEnd), vehicle, useHigherLevelRoadsPriority, stayOnSameRoadPriority, new Coordinates(latEnd, lonEnd), vehicle, useHigherLevelRoadsPriority, stayOnSameRoadPriority,
useRoadsWithLessJunctionsPriority); useRoadsWithLessJunctionsPriority);
PathResult pathResult = new PathResult(DateTime.Now - startCalc, result); return result;
return pathResult;
} }
); );
app.MapGet("/getShortestRoute", (float latStart, float lonStart, float latEnd, float lonEnd) => app.MapGet("/getShortestRoute", (float latStart, float lonStart, float latEnd, float lonEnd) =>
{ {
DateTime startCalc = DateTime.Now; PathResult result = Pathfinder.AStar("D:/stuttgart-regbez-latest", new Coordinates(latStart, lonStart),
List<PathNode> result = Pathfinder.AStar("D:/stuttgart-regbez-latest", new Coordinates(latStart, lonStart),
new Coordinates(latEnd, lonEnd), Tag.SpeedType.any, 0, 0, new Coordinates(latEnd, lonEnd), Tag.SpeedType.any, 0, 0,
0); 0);
PathResult pathResult = new PathResult(DateTime.Now - startCalc, result); return result;
return pathResult;
} }
); );
@ -57,14 +54,3 @@ app.MapControllers();
app.Run(); app.Run();
internal class PathResult
{
[JsonInclude]public TimeSpan calcTime;
[JsonInclude]public List<PathNode> pathNodes;
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes)
{
this.calcTime = calcTime;
this.pathNodes = pathNodes;
}
}

View File

@ -1,3 +1,4 @@
using System.Diagnostics.Tracing;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using OSMDatastructure; using OSMDatastructure;
using OSMDatastructure.Graph; using OSMDatastructure.Graph;
@ -7,6 +8,12 @@ namespace Pathfinding;
public class PathNode : OsmNode public class PathNode : OsmNode
{ {
[JsonInclude]public Dictionary<string, string> tags = new(); [JsonInclude]public Dictionary<string, string> tags = new();
[JsonConstructor]
public PathNode(ulong nodeId, Coordinates coordinates, Dictionary<string, string> tags) : base(nodeId, coordinates)
{
this.tags = tags;
}
public PathNode(ulong nodeId, float lat, float lon) : base(nodeId, lat, lon) public PathNode(ulong nodeId, float lat, float lon) : base(nodeId, lat, lon)
{ {

46
Pathfinding/PathResult.cs Normal file
View File

@ -0,0 +1,46 @@
using System.Text.Json.Serialization;
using OSMDatastructure.Graph;
namespace Pathfinding;
public class PathResult
{
[JsonInclude]public TimeSpan calcTime;
[JsonInclude]public List<PathNode> pathNodes;
[JsonInclude]public Dictionary<ulong, double>? gScore;
[JsonInclude]public HashSet<OsmNode>? nodes;
public string? name { get; set; }
[JsonConstructor]
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes, Dictionary<ulong, double>? gScore, HashSet<OsmNode>? nodes)
{
this.calcTime = calcTime;
this.pathNodes = pathNodes;
this.gScore = gScore;
this.nodes = nodes;
}
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes)
{
this.calcTime = calcTime;
this.pathNodes = pathNodes;
}
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes, Dictionary<OsmNode, double> gScore)
{
this.calcTime = calcTime;
this.pathNodes = pathNodes;
AddGScores(gScore);
}
public void AddGScores(Dictionary<OsmNode, double> gScore)
{
this.gScore = new();
this.nodes = new();
foreach (KeyValuePair<OsmNode, double> kv in gScore)
{
this.gScore.Add(kv.Key.nodeId, kv.Value);
this.nodes.Add(kv.Key);
}
}
}

View File

@ -1,6 +1,6 @@
using OSMDatastructure; using System.Text.Json;
using OSMDatastructure;
using OSMDatastructure.Graph; using OSMDatastructure.Graph;
using RenderPath;
using static OSMDatastructure.Tag; using static OSMDatastructure.Tag;
using WayType = OSMDatastructure.Tag.WayType; using WayType = OSMDatastructure.Tag.WayType;
@ -8,16 +8,17 @@ namespace Pathfinding;
public static class Pathfinder public static class Pathfinder
{ {
public static List<PathNode> AStar(string workingDir, Coordinates startCoordinates, Coordinates goalCoordinates, public static PathResult AStar(string workingDir, Coordinates startCoordinates, Coordinates goalCoordinates,
SpeedType vehicle, double heuristicRoadLevelPriority, double heuristicSameRoadPriority, SpeedType vehicle, double heuristicRoadLevelPriority, double heuristicSameRoadPriority,
double heuristicFewJunctionsPriority) double heuristicFewJunctionsPriority)
{ {
DateTime startCalc = DateTime.Now;
RegionManager regionManager = new RegionManager(workingDir); RegionManager regionManager = new RegionManager(workingDir);
OsmNode? startNode = regionManager.ClosestNodeToCoordinates(startCoordinates, vehicle); OsmNode? startNode = regionManager.ClosestNodeToCoordinates(startCoordinates, vehicle);
OsmNode? goalNode = regionManager.ClosestNodeToCoordinates(goalCoordinates, vehicle); OsmNode? goalNode = regionManager.ClosestNodeToCoordinates(goalCoordinates, vehicle);
if (startNode is null || goalNode is null) if (startNode is null || goalNode is null)
return new List<PathNode>(); return new PathResult(DateTime.Now - startCalc, new List<PathNode>());
PriorityQueue<OsmNode, double> openSetfScore = new(); PriorityQueue<OsmNode, double> openSetfScore = new();
openSetfScore.Enqueue(startNode, 0); openSetfScore.Enqueue(startNode, 0);
@ -31,13 +32,12 @@ public static class Pathfinder
if (currentNode.Equals(goalNode)) if (currentNode.Equals(goalNode))
{ {
Console.WriteLine("Path found."); Console.WriteLine("Path found.");
List<PathNode> path = GetPath(cameFromDict, goalNode, regionManager); PathResult path = GetPath(cameFromDict, goalNode, regionManager, DateTime.Now - startCalc);
Console.WriteLine("Rendering."); path.AddGScores(gScore);
List<Coordinates> coords = new(); string fileName = $"{new DirectoryInfo(workingDir).Name}-{DateTime.Now.ToFileTime()}.result";
foreach(PathNode pn in path) string outputFilepath = Path.Join(Directory.GetParent(workingDir)!.FullName, fileName);
coords.Add(pn.coordinates); path.name = outputFilepath;
Renderer.DrawLoadedNodes(gScore, coords, workingDir); SaveGraph(path, outputFilepath);
Console.WriteLine("Done.");
return path; return path;
} }
@ -46,7 +46,8 @@ public static class Pathfinder
OsmNode? neighbor = regionManager.GetNode(edge.neighborId, edge.neighborRegion); OsmNode? neighbor = regionManager.GetNode(edge.neighborId, edge.neighborRegion);
if (neighbor is not null) if (neighbor is not null)
{ {
double tentativeGScore = gScore[currentNode] + Weight(currentNode, neighbor, edge, vehicle, regionManager); double tentativeGScore =
gScore[currentNode] + Weight(currentNode, neighbor, edge, vehicle, regionManager);
gScore.TryAdd(neighbor, double.MaxValue); gScore.TryAdd(neighbor, double.MaxValue);
if (tentativeGScore < gScore[neighbor]) if (tentativeGScore < gScore[neighbor])
{ {
@ -62,16 +63,24 @@ public static class Pathfinder
heuristicRoadLevelPriority, heuristicFewJunctionsPriority, heuristicSameRoadPriority); heuristicRoadLevelPriority, heuristicFewJunctionsPriority, heuristicSameRoadPriority);
//Console.WriteLine($"Queue: {openSetfScore.Count:00000} Current Distance: {Utils.DistanceBetween(currentNode, goalNode):000000.00} Visited: {cameFromDict.Count:00000} Current heuristic: {h:00000.00}"); //Console.WriteLine($"Queue: {openSetfScore.Count:00000} Current Distance: {Utils.DistanceBetween(currentNode, goalNode):000000.00} Visited: {cameFromDict.Count:00000} Current heuristic: {h:00000.00}");
openSetfScore.Enqueue(neighbor, tentativeGScore + h); openSetfScore.Enqueue(neighbor, tentativeGScore + h);
} }
} }
} }
} }
return new List<PathNode>(); return new PathResult(DateTime.Now - startCalc, new List<PathNode>());
} }
private static List<PathNode> GetPath(Dictionary<OsmNode, OsmNode> cameFromDict, OsmNode goalNode, RegionManager regionManager) private static void SaveGraph(PathResult pathResult, string outputFilepath)
{
FileStream fs = new FileStream(outputFilepath, FileMode.CreateNew);
JsonSerializer.Serialize(fs, pathResult, JsonSerializerOptions.Default);
fs.Dispose();
Console.WriteLine($"Saved result to {outputFilepath}");
}
private static PathResult GetPath(Dictionary<OsmNode, OsmNode> cameFromDict, OsmNode goalNode, RegionManager regionManager, TimeSpan calcFinished)
{ {
List<PathNode> path = new List<PathNode>(); List<PathNode> path = new List<PathNode>();
OsmNode currentNode = goalNode; OsmNode currentNode = goalNode;
@ -88,7 +97,7 @@ public static class Pathfinder
path.Reverse(); path.Reverse();
return path; return new PathResult(calcFinished, path);
} }
private static double Weight(OsmNode fromNode, OsmNode neighborNode, OsmEdge edge, SpeedType vehicle, RegionManager regionManager) private static double Weight(OsmNode fromNode, OsmNode neighborNode, OsmEdge edge, SpeedType vehicle, RegionManager regionManager)

View File

@ -8,7 +8,10 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\OSMDatastructure\OSMDatastructure.csproj" /> <ProjectReference Include="..\OSMDatastructure\OSMDatastructure.csproj" />
<ProjectReference Include="..\RenderPath\RenderPath.csproj" /> </ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,10 +8,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\OSMDatastructure\OSMDatastructure.csproj" /> <ProjectReference Include="..\OSMDatastructure\OSMDatastructure.csproj" />
<ProjectReference Include="..\Pathfinding\Pathfinding.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,20 +1,34 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Text.Json;
using OSMDatastructure.Graph; using OSMDatastructure.Graph;
using Pathfinding;
namespace RenderPath; namespace RenderPath;
public class Renderer public class Renderer
{ {
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
public static void DrawLoadedNodes(Dictionary<OsmNode, double> gScoreDict, List<Coordinates> pathCoordinates, string workingDir) public static void DrawGraph(string resultPath)
{ {
float minLat = gScoreDict.Min(kv => kv.Key.coordinates.latitude); FileStream fs = new FileStream(resultPath, FileMode.Open);
float minLon = gScoreDict.Min(kv => kv.Key.coordinates.longitude); PathResult graph = JsonSerializer.Deserialize<PathResult>(fs)!;
float maxLat = gScoreDict.Max(kv => kv.Key.coordinates.latitude); List<Coordinates> coords = new List<Coordinates>();
float maxLon = gScoreDict.Max(kv => kv.Key.coordinates.longitude); foreach (PathNode node in graph.pathNodes)
coords.Add(node.coordinates);
string workingDir = new DirectoryInfo(resultPath).FullName;
DrawLoadedNodes(graph.nodes!, graph.gScore!, coords, workingDir);
}
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
public static void DrawLoadedNodes(HashSet<OsmNode> nodes, Dictionary<ulong, double> gScoreDict, List<Coordinates> pathCoordinates, string workingDir)
{
float minLat = nodes.Min(node => node.coordinates.latitude);
float minLon = nodes.Min(node => node.coordinates.longitude);
float maxLat = nodes.Max(node => node.coordinates.latitude);
float maxLon = nodes.Max(node => node.coordinates.longitude);
double minWeight = gScoreDict.Min(kv => kv.Value); double minWeight = gScoreDict.Min(kv => kv.Value);
double maxWeight = gScoreDict.Max(kv => kv.Value); double maxWeight = gScoreDict.Max(kv => kv.Value);
@ -36,12 +50,14 @@ public class Renderer
Color center = Color.FromArgb(255, 255, 0); Color center = Color.FromArgb(255, 255, 0);
Color end = Color.FromArgb(0, 255, 0); Color end = Color.FromArgb(0, 255, 0);
foreach (KeyValuePair<OsmNode, double> kv in gScoreDict) foreach (KeyValuePair<ulong, double> kv in gScoreDict)
{ {
double percentage = (kv.Value - minWeight) / (maxWeight - minWeight); double percentage = (kv.Value - minWeight) / (maxWeight - minWeight);
Brush b = new SolidBrush(GradientPick(percentage, start, center, end)); Brush b = new SolidBrush(GradientPick(percentage, start, center, end));
float x = (kv.Key.coordinates.longitude - minLon) * scaleFactor; OsmNode node = nodes.First(node => node.nodeId.Equals(kv.Key));
float y = (maxLat - kv.Key.coordinates.latitude) * scaleFactor;
float x = (node.coordinates.longitude - minLon) * scaleFactor;
float y = (maxLat - node.coordinates.latitude) * scaleFactor;
g.FillEllipse(b, x, y, 2, 2); g.FillEllipse(b, x, y, 2, 2);
} }
@ -56,7 +72,7 @@ public class Renderer
g.DrawLine(p, p1, p2); g.DrawLine(p, p1, p2);
} }
ret.Save(Path.Join(Directory.GetParent(workingDir)!.FullName, "routing.png"), ImageFormat.Bmp); ret.Save($"{workingDir}-routing.png", ImageFormat.Bmp);
} }
/* /*

View File

@ -1,6 +1,7 @@
using OSMDatastructure; using OSMDatastructure;
using OSMDatastructure.Graph; using OSMDatastructure.Graph;
using Pathfinding; using Pathfinding;
using RenderPath;
namespace Server; namespace Server;
@ -17,10 +18,13 @@ public class Server
//RegionConverter.ConvertXMLToRegions("D:/map.osm", "D:/map"); //RegionConverter.ConvertXMLToRegions("D:/map.osm", "D:/map");
//RegionConverter.ConvertXMLToRegions("D:/germany-latest.osm", "D:/germany-latest"); //RegionConverter.ConvertXMLToRegions("D:/germany-latest.osm", "D:/germany-latest");
Coordinates start = new Coordinates( 48.7933798f, 9.8275859f); Coordinates start = new Coordinates( 48.7933798f, 9.8275859f);
Coordinates finish = new Coordinates( 48.8407632f, 10.0676979f); Coordinates finish = new Coordinates( 48.795918f, 9.021618f);
List<PathNode> result = Pathfinder.AStar("D:/stuttgart-regbez-latest", start, PathResult result = Pathfinder.AStar("D:/stuttgart-regbez-latest", start,
finish, Tag.SpeedType.car, 20, 2, finish, Tag.SpeedType.car, 0.1, 0.2,
0); 0);
Renderer.DrawGraph(result.name);
} }
} }