Compare commits

...

6 Commits

Author SHA1 Message Date
619cad61ee Adjusted to new Functions and return values.
Now renders complete result with path and all loaded regions.
2023-04-19 22:55:49 +02:00
bfb117164e Added Area-render (Renders all loaded nodes and edges)
Route can now be drawn over other pictures (e.g. the area-render)
Increased resolution to 20.000
Added Bounds-Class for information exchange with image.
2023-04-19 22:53:49 +02:00
208c000577 Changed values for heuristic and weight functions, as well as increased priority for type1-roads (motorways). 2023-04-19 22:51:47 +02:00
5212e43897 Add regionManager to PathResult for internal use 2023-04-19 22:15:57 +02:00
6fb88b5c9c Include RegionManager in result for internal use 2023-04-19 22:15:43 +02:00
9e0c4f65db appropriate names in PathResult for nodes gSCoreNodes 2023-04-19 22:02:15 +02:00
5 changed files with 120 additions and 34 deletions

View File

@ -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);
} }
} }
} }

View File

@ -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)

View File

@ -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;
if (renderOver is null)
{
ret = new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb);
g = Graphics.FromImage(ret);
g.Clear(Color.White); 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;
} }
/* /*

View File

@ -1,3 +1,4 @@
using System.Drawing;
using OSMDatastructure; using OSMDatastructure;
using OSMDatastructure.Graph; using OSMDatastructure.Graph;
using Pathfinding; using Pathfinding;
@ -22,9 +23,13 @@ public class Server
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);
} }
} }

View File

@ -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>