Compare commits
6 Commits
055a751c9d
...
619cad61ee
Author | SHA1 | Date | |
---|---|---|---|
619cad61ee | |||
bfb117164e | |||
208c000577 | |||
5212e43897 | |||
6fb88b5c9c | |||
9e0c4f65db |
@ -8,16 +8,17 @@ public class PathResult
|
|||||||
[JsonInclude]public TimeSpan calcTime;
|
[JsonInclude]public TimeSpan calcTime;
|
||||||
[JsonInclude]public List<PathNode> pathNodes;
|
[JsonInclude]public List<PathNode> pathNodes;
|
||||||
[JsonInclude]public Dictionary<ulong, double>? gScore;
|
[JsonInclude]public Dictionary<ulong, double>? gScore;
|
||||||
[JsonInclude]public HashSet<OsmNode>? nodes;
|
[JsonInclude]public HashSet<OsmNode>? gScoreNodes;
|
||||||
|
[JsonIgnore] public RegionManager? regionManager { get; set; }
|
||||||
public string? name { get; set; }
|
public string? name { get; set; }
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes, Dictionary<ulong, double>? gScore, HashSet<OsmNode>? nodes)
|
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes, Dictionary<ulong, double>? gScore, HashSet<OsmNode>? gScoreNodes)
|
||||||
{
|
{
|
||||||
this.calcTime = calcTime;
|
this.calcTime = calcTime;
|
||||||
this.pathNodes = pathNodes;
|
this.pathNodes = pathNodes;
|
||||||
this.gScore = gScore;
|
this.gScore = gScore;
|
||||||
this.nodes = nodes;
|
this.gScoreNodes = gScoreNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes)
|
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes)
|
||||||
@ -36,11 +37,11 @@ public class PathResult
|
|||||||
public void AddGScores(Dictionary<OsmNode, double> gScore)
|
public void AddGScores(Dictionary<OsmNode, double> gScore)
|
||||||
{
|
{
|
||||||
this.gScore = new();
|
this.gScore = new();
|
||||||
this.nodes = new();
|
this.gScoreNodes = new();
|
||||||
foreach (KeyValuePair<OsmNode, double> kv in gScore)
|
foreach (KeyValuePair<OsmNode, double> kv in gScore)
|
||||||
{
|
{
|
||||||
this.gScore.Add(kv.Key.nodeId, kv.Value);
|
this.gScore.Add(kv.Key.nodeId, kv.Value);
|
||||||
this.nodes.Add(kv.Key);
|
this.gScoreNodes.Add(kv.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,11 +33,12 @@ public static class Pathfinder
|
|||||||
{
|
{
|
||||||
Console.WriteLine("Path found.");
|
Console.WriteLine("Path found.");
|
||||||
PathResult path = GetPath(cameFromDict, goalNode, regionManager, DateTime.Now - startCalc);
|
PathResult path = GetPath(cameFromDict, goalNode, regionManager, DateTime.Now - startCalc);
|
||||||
path.AddGScores(gScore);
|
|
||||||
string fileName = $"{new DirectoryInfo(workingDir).Name}-{DateTime.Now.ToFileTime()}.result";
|
string fileName = $"{new DirectoryInfo(workingDir).Name}-{DateTime.Now.ToFileTime()}.result";
|
||||||
string outputFilepath = Path.Join(Directory.GetParent(workingDir)!.FullName, fileName);
|
string outputFilepath = Path.Join(Directory.GetParent(workingDir)!.FullName, fileName);
|
||||||
path.name = outputFilepath;
|
path.name = outputFilepath;
|
||||||
|
path.AddGScores(gScore);
|
||||||
SaveGraph(path, outputFilepath);
|
SaveGraph(path, outputFilepath);
|
||||||
|
path.regionManager = regionManager;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +64,6 @@ 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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ public static class Pathfinder
|
|||||||
double distance = Utils.DistanceBetween(fromNode, neighborNode);
|
double distance = Utils.DistanceBetween(fromNode, neighborNode);
|
||||||
double speed = regionManager.GetSpeedForEdge(fromNode, edge.wayId, vehicle);
|
double speed = regionManager.GetSpeedForEdge(fromNode, edge.wayId, vehicle);
|
||||||
double prio = GetPriorityVehicleRoad(edge, vehicle, regionManager.GetRegion(fromNode.coordinates)!);
|
double prio = GetPriorityVehicleRoad(edge, vehicle, regionManager.GetRegion(fromNode.coordinates)!);
|
||||||
return distance / (speed + prio * 50);
|
return distance / speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double Heuristic(OsmNode fromNode, OsmNode neighborNode, OsmNode goalNode, OsmEdge edge, SpeedType vehicle, RegionManager regionManager, double roadPriorityFactor, double junctionFactor, double sameRoadFactor)
|
private static double Heuristic(OsmNode fromNode, OsmNode neighborNode, OsmNode goalNode, OsmEdge edge, SpeedType vehicle, RegionManager regionManager, double roadPriorityFactor, double junctionFactor, double sameRoadFactor)
|
||||||
@ -131,9 +131,7 @@ public static class Pathfinder
|
|||||||
|
|
||||||
double junctionCount = (neighborNode.edges.Count > 2 ? 0 : 1) * junctionFactor;
|
double junctionCount = (neighborNode.edges.Count > 2 ? 0 : 1) * junctionFactor;
|
||||||
|
|
||||||
//Console.WriteLine($"{roadPriority:000.00} {sameRoadName:000.00} {junctionCount:000.00} {distanceImprovement:+000.00;-000.00;0000.00}");
|
return Utils.DistanceBetween(neighborNode, goalNode) / (1 + roadPriority + sameRoadName + junctionCount);
|
||||||
|
|
||||||
return Utils.DistanceBetween(neighborNode, goalNode) - (roadPriority + sameRoadName + junctionCount) * 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double GetPriorityVehicleRoad(OsmEdge edge, SpeedType vehicle, Region region)
|
private static double GetPriorityVehicleRoad(OsmEdge edge, SpeedType vehicle, Region region)
|
||||||
@ -154,10 +152,10 @@ public static class Pathfinder
|
|||||||
case WayType.trunk_link:
|
case WayType.trunk_link:
|
||||||
case WayType.primary:
|
case WayType.primary:
|
||||||
case WayType.primary_link:
|
case WayType.primary_link:
|
||||||
return 8;
|
return 10;
|
||||||
case WayType.secondary:
|
case WayType.secondary:
|
||||||
case WayType.secondary_link:
|
case WayType.secondary_link:
|
||||||
return 6;
|
return 7;
|
||||||
case WayType.tertiary:
|
case WayType.tertiary:
|
||||||
case WayType.tertiary_link:
|
case WayType.tertiary_link:
|
||||||
return 5;
|
return 5;
|
||||||
@ -168,7 +166,7 @@ public static class Pathfinder
|
|||||||
return 2;
|
return 2;
|
||||||
case WayType.service:
|
case WayType.service:
|
||||||
case WayType.track:
|
case WayType.track:
|
||||||
return 0.01;
|
return 0.0001;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vehicle == SpeedType.pedestrian)
|
if (vehicle == SpeedType.pedestrian)
|
||||||
|
@ -7,10 +7,26 @@ using Pathfinding;
|
|||||||
|
|
||||||
namespace RenderPath;
|
namespace RenderPath;
|
||||||
|
|
||||||
public class Renderer
|
public static class Renderer
|
||||||
{
|
{
|
||||||
|
private const int ImageMaxSize = 20000;
|
||||||
|
private const float PenThickness = 4;
|
||||||
|
|
||||||
public static void DrawGraph(string resultPath)
|
public class Bounds
|
||||||
|
{
|
||||||
|
public readonly float minLat, maxLat, minLon, maxLon;
|
||||||
|
|
||||||
|
public Bounds(float minLat, float minLon, float maxLat, float maxLon)
|
||||||
|
{
|
||||||
|
this.minLon = minLon;
|
||||||
|
this.maxLat = maxLat;
|
||||||
|
this.maxLon = maxLon;
|
||||||
|
this.minLat = minLat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
|
||||||
|
public static void DrawGraph(string resultPath, Image? area = null, Bounds? bounds = null)
|
||||||
{
|
{
|
||||||
FileStream fs = new FileStream(resultPath, FileMode.Open);
|
FileStream fs = new FileStream(resultPath, FileMode.Open);
|
||||||
PathResult graph = JsonSerializer.Deserialize<PathResult>(fs)!;
|
PathResult graph = JsonSerializer.Deserialize<PathResult>(fs)!;
|
||||||
@ -19,32 +35,92 @@ public class Renderer
|
|||||||
coords.Add(node.coordinates);
|
coords.Add(node.coordinates);
|
||||||
string workingDir = new DirectoryInfo(resultPath).FullName;
|
string workingDir = new DirectoryInfo(resultPath).FullName;
|
||||||
|
|
||||||
DrawLoadedNodes(graph.nodes!, graph.gScore!, coords, workingDir);
|
Image renderedImage = DrawLoadedNodes(graph.gScoreNodes!, graph.gScore!, coords, area, bounds);
|
||||||
|
renderedImage.Save($"{workingDir}-routing.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
|
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
|
||||||
public static void DrawLoadedNodes(HashSet<OsmNode> nodes, Dictionary<ulong, double> gScoreDict, List<Coordinates> pathCoordinates, string workingDir)
|
public static ValueTuple<Image, Bounds> DrawArea(RegionManager rm)
|
||||||
{
|
{
|
||||||
|
HashSet<OsmNode> nodes = new HashSet<OsmNode>();
|
||||||
|
foreach (OSMDatastructure.Region r in rm.GetAllRegions())
|
||||||
|
nodes = nodes.Concat(r.nodes).ToHashSet();
|
||||||
|
|
||||||
float minLat = nodes.Min(node => node.coordinates.latitude);
|
float minLat = nodes.Min(node => node.coordinates.latitude);
|
||||||
float minLon = nodes.Min(node => node.coordinates.longitude);
|
float minLon = nodes.Min(node => node.coordinates.longitude);
|
||||||
float maxLat = nodes.Max(node => node.coordinates.latitude);
|
float maxLat = nodes.Max(node => node.coordinates.latitude);
|
||||||
float maxLon = nodes.Max(node => node.coordinates.longitude);
|
float maxLon = nodes.Max(node => node.coordinates.longitude);
|
||||||
|
|
||||||
|
float latDiff = maxLat - minLat;
|
||||||
|
float lonDiff = maxLon - minLon;
|
||||||
|
|
||||||
|
float scaleFactor = latDiff > lonDiff ? ImageMaxSize / latDiff : ImageMaxSize / lonDiff;
|
||||||
|
|
||||||
|
int pixelsX = (int)(lonDiff * scaleFactor);
|
||||||
|
int pixelsY = (int)(latDiff * scaleFactor);
|
||||||
|
|
||||||
|
Image ret = new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb);
|
||||||
|
Graphics g = Graphics.FromImage(ret);
|
||||||
|
g.Clear(Color.White);
|
||||||
|
|
||||||
|
Color start = Color.FromArgb(255, 25, 25, 25);
|
||||||
|
Color center = Color.FromArgb(255, 0, 0, 0);
|
||||||
|
Color end = Color.FromArgb(255, 0, 255, 0);
|
||||||
|
|
||||||
|
foreach (OsmNode node in nodes)
|
||||||
|
{
|
||||||
|
foreach (OsmEdge edge in node.edges)
|
||||||
|
{
|
||||||
|
Coordinates c1 = node.coordinates;
|
||||||
|
OsmNode nNode = rm.GetNode(edge.neighborId, edge.neighborRegion)!;
|
||||||
|
Coordinates c2 = nNode.coordinates;
|
||||||
|
|
||||||
|
Pen p = new Pen(GradientPick(0, start, center, end), PenThickness);
|
||||||
|
float x1 = (c1.longitude - minLon) * scaleFactor;
|
||||||
|
float y1 = (maxLat - c1.latitude) * scaleFactor;
|
||||||
|
float x2 = (c2.longitude - minLon) * scaleFactor;
|
||||||
|
float y2 = (maxLat - c2.latitude) * scaleFactor;
|
||||||
|
|
||||||
|
g.DrawLine(p, x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ValueTuple<Image, Bounds>(ret, new Bounds(minLat,minLon,maxLat,maxLon));
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
|
||||||
|
public static Image DrawLoadedNodes(HashSet<OsmNode> nodes, Dictionary<ulong, double> gScoreDict,
|
||||||
|
List<Coordinates> pathCoordinates, Image? renderOver = null, Bounds? bounds = null)
|
||||||
|
{
|
||||||
|
float minLat = bounds?.minLat ?? nodes.Min(node => node.coordinates.latitude);
|
||||||
|
float minLon = bounds?.minLon ?? nodes.Min(node => node.coordinates.longitude);
|
||||||
|
float maxLat = bounds?.maxLat ?? nodes.Max(node => node.coordinates.latitude);
|
||||||
|
float maxLon = bounds?.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);
|
||||||
|
|
||||||
float latDiff = maxLat - minLat;
|
float latDiff = maxLat - minLat;
|
||||||
float lonDiff = maxLon - minLon;
|
float lonDiff = maxLon - minLon;
|
||||||
|
|
||||||
const int imageMaxSize = 10000;
|
float scaleFactor = latDiff > lonDiff ? ImageMaxSize / latDiff : ImageMaxSize / lonDiff;
|
||||||
float scaleFactor = latDiff > lonDiff ? imageMaxSize / latDiff : imageMaxSize / lonDiff;
|
|
||||||
|
|
||||||
int pixelsX = (int)(lonDiff * scaleFactor);
|
int pixelsX = (int)(lonDiff * scaleFactor);
|
||||||
int pixelsY = (int)(latDiff * scaleFactor);
|
int pixelsY = (int)(latDiff * scaleFactor);
|
||||||
|
|
||||||
Bitmap ret = new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb);
|
Image ret;
|
||||||
Graphics g = Graphics.FromImage(ret);
|
Graphics g;
|
||||||
g.Clear(Color.White);
|
if (renderOver is null)
|
||||||
|
{
|
||||||
|
ret = new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb);
|
||||||
|
g = Graphics.FromImage(ret);
|
||||||
|
g.Clear(Color.White);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = renderOver;
|
||||||
|
g = Graphics.FromImage(ret);
|
||||||
|
}
|
||||||
|
|
||||||
Color start = Color.FromArgb(0, 0, 255);
|
Color start = Color.FromArgb(0, 0, 255);
|
||||||
Color center = Color.FromArgb(255, 255, 0);
|
Color center = Color.FromArgb(255, 255, 0);
|
||||||
@ -58,21 +134,26 @@ public class Renderer
|
|||||||
|
|
||||||
float x = (node.coordinates.longitude - minLon) * scaleFactor;
|
float x = (node.coordinates.longitude - minLon) * scaleFactor;
|
||||||
float y = (maxLat - node.coordinates.latitude) * scaleFactor;
|
float y = (maxLat - node.coordinates.latitude) * scaleFactor;
|
||||||
g.FillEllipse(b, x, y, 2, 2);
|
|
||||||
|
x -= (PenThickness * 1.5f) / 2;
|
||||||
|
y -= (PenThickness * 1.5f) / 2;
|
||||||
|
g.FillEllipse(b, x, y, PenThickness * 1.5f, PenThickness * 1.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pen p = new Pen(Color.Red, 2);
|
Pen p = new Pen(Color.Red, PenThickness);
|
||||||
|
|
||||||
for (int i = 0; i < pathCoordinates.Count - 1; i++)
|
for (int i = 0; i < pathCoordinates.Count - 1; i++)
|
||||||
{
|
{
|
||||||
Coordinates c1 = pathCoordinates[i];
|
Coordinates c1 = pathCoordinates[i];
|
||||||
Coordinates c2 = pathCoordinates[i+1];
|
Coordinates c2 = pathCoordinates[i + 1];
|
||||||
Point p1 = new(Convert.ToInt32((c1.longitude - minLon) * scaleFactor), Convert.ToInt32((maxLat - c1.latitude) * scaleFactor));
|
Point p1 = new(Convert.ToInt32((c1.longitude - minLon) * scaleFactor),
|
||||||
Point p2 = new(Convert.ToInt32((c2.longitude - minLon) * scaleFactor), Convert.ToInt32((maxLat - c2.latitude) * scaleFactor));
|
Convert.ToInt32((maxLat - c1.latitude) * scaleFactor));
|
||||||
|
Point p2 = new(Convert.ToInt32((c2.longitude - minLon) * scaleFactor),
|
||||||
|
Convert.ToInt32((maxLat - c2.latitude) * scaleFactor));
|
||||||
g.DrawLine(p, p1, p2);
|
g.DrawLine(p, p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.Save($"{workingDir}-routing.png", ImageFormat.Bmp);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Drawing;
|
||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
using Pathfinding;
|
using Pathfinding;
|
||||||
@ -19,12 +20,16 @@ public class Server
|
|||||||
//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.795918f, 9.021618f);
|
Coordinates finish = new Coordinates(48.795918f, 9.021618f);
|
||||||
PathResult result = Pathfinder.AStar("D:/stuttgart-regbez-latest", start,
|
PathResult result = Pathfinder.AStar("D:/stuttgart-regbez-latest", start,
|
||||||
finish, Tag.SpeedType.car, 0.1, 0.2,
|
finish, Tag.SpeedType.car, 0.01, 0.0001,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
Renderer.DrawGraph(result.name);
|
Console.WriteLine("Drawing area");
|
||||||
|
ValueTuple<Image, Renderer.Bounds> area = Renderer.DrawArea(result.regionManager);
|
||||||
|
|
||||||
|
Console.WriteLine("Drawing route");
|
||||||
|
Renderer.DrawGraph(result.name, area.Item1, area.Item2);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user