Save Pathfinding result to file.
Load result for render.
This commit is contained in:
parent
08ebc9a26b
commit
055a751c9d
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
46
Pathfinding/PathResult.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user