From 23429c8a0037c2281d0eec09e693b367f3e25e67 Mon Sep 17 00:00:00 2001 From: glax Date: Thu, 20 Apr 2023 19:40:50 +0200 Subject: [PATCH] Renderer now renders 3 different layers over each other: Area (Regions), gScore-Weights (as blobs) and PathResult path. Returns the Image instead of saving to disk. --- RenderPath/Renderer.cs | 124 +++++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/RenderPath/Renderer.cs b/RenderPath/Renderer.cs index 3b6e797..5cadf14 100644 --- a/RenderPath/Renderer.cs +++ b/RenderPath/Renderer.cs @@ -11,6 +11,10 @@ public static class Renderer { private const int ImageMaxSize = 20000; private const float PenThickness = 4; + private static readonly Color RouteColor = Color.Red; + private static readonly Color WeightStartColor = Color.FromArgb(0, 0, 255); + private static readonly Color WeightCenterColor = Color.FromArgb(255, 255, 0); + private static readonly Color WeightEndColor = Color.FromArgb(0, 255, 0); public class Bounds { @@ -26,17 +30,16 @@ public static class Renderer } [SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")] - public static void DrawGraph(string resultPath, Image? area = null, Bounds? bounds = null) + public static Image DrawPathfinder(Pathfinder pathfinder) { - FileStream fs = new FileStream(resultPath, FileMode.Open); - PathResult graph = JsonSerializer.Deserialize(fs)!; - List coords = new List(); - foreach (PathNode node in graph.pathNodes) - coords.Add(node.coordinates); - string workingDir = new DirectoryInfo(resultPath).FullName; + Console.WriteLine("Rendering loaded Regions"); + ValueTuple areaRender = DrawArea(pathfinder.regionManager); + Console.WriteLine("Rendering gScores (Weights)"); + ValueTuple areaGScoreRender = DrawGScores(pathfinder.gScore!, areaRender.Item1, areaRender.Item2); + Console.WriteLine("Rendering path"); + ValueTuple areaGScorePathRender = DrawPath(pathfinder.pathResult!, areaGScoreRender.Item1, areaGScoreRender.Item2); - Image renderedImage = DrawLoadedNodes(graph.gScoreNodes!, graph.gScore!, coords, area, bounds); - renderedImage.Save($"{workingDir}-routing.png"); + return areaGScorePathRender.Item1; } [SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")] @@ -63,6 +66,7 @@ public static class Renderer Graphics g = Graphics.FromImage(ret); g.Clear(Color.White); + //TODO Use road priority for roadcolor Color start = Color.FromArgb(255, 25, 25, 25); Color center = Color.FromArgb(255, 0, 0, 0); Color end = Color.FromArgb(255, 0, 255, 0); @@ -89,13 +93,54 @@ public static class Renderer } [SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")] - public static Image DrawLoadedNodes(HashSet nodes, Dictionary gScoreDict, - List pathCoordinates, Image? renderOver = null, Bounds? bounds = null) + public static ValueTuple DrawPath(PathResult pathResult, 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); + List coordinates = new(); + foreach(PathNode node in pathResult.pathNodes) + coordinates.Add(node.coordinates); + + float minLat = bounds?.minLat ?? coordinates.Min(coords => coords.latitude); + float minLon = bounds?.minLon ?? coordinates.Min(coords => coords.longitude); + float maxLat = bounds?.maxLat ?? coordinates.Max(coords => coords.latitude); + float maxLon = bounds?.maxLon ?? coordinates.Max(coords => coords.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 = renderOver ?? new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb); + Graphics g = Graphics.FromImage(ret); + if(renderOver is null) + g.Clear(Color.White); + + Pen p = new Pen(RouteColor, PenThickness); + + for (int i = 0; i < coordinates.Count - 1; i++) + { + Coordinates c1 = coordinates[i]; + Coordinates c2 = coordinates[i + 1]; + Point p1 = new(Convert.ToInt32((c1.longitude - minLon) * 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); + } + + return new ValueTuple(ret, new Bounds(minLat,minLon,maxLat,maxLon)); + } + + [SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")] + public static ValueTuple DrawGScores(Dictionary gScoreDict, Image? renderOver = null, + Bounds? bounds = null) + { + float minLat = bounds?.minLat ?? gScoreDict.Min(kv => kv.Key.coordinates.latitude); + float minLon = bounds?.minLon ?? gScoreDict.Min(kv => kv.Key.coordinates.longitude); + float maxLat = bounds?.maxLat ?? gScoreDict.Max(kv => kv.Key.coordinates.latitude); + float maxLon = bounds?.maxLon ?? gScoreDict.Max(kv => kv.Key.coordinates.longitude); double minWeight = gScoreDict.Min(kv => kv.Value); double maxWeight = gScoreDict.Max(kv => kv.Value); @@ -107,55 +152,28 @@ public static class Renderer int pixelsX = (int)(lonDiff * scaleFactor); int pixelsY = (int)(latDiff * scaleFactor); - - Image ret; - Graphics g; - if (renderOver is null) - { - ret = new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb); - g = Graphics.FromImage(ret); + + Image ret = renderOver ?? new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb); + Graphics g = Graphics.FromImage(ret); + if(renderOver is null) g.Clear(Color.White); - } - else - { - ret = renderOver; - g = Graphics.FromImage(ret); - } - - Color start = Color.FromArgb(0, 0, 255); - Color center = Color.FromArgb(255, 255, 0); - Color end = Color.FromArgb(0, 255, 0); - - foreach (KeyValuePair kv in gScoreDict) + + foreach (KeyValuePair kv in gScoreDict) { double percentage = (kv.Value - minWeight) / (maxWeight - minWeight); - Brush b = new SolidBrush(GradientPick(percentage, start, center, end)); - OsmNode node = nodes.First(node => node.nodeId.Equals(kv.Key)); + Brush b = new SolidBrush(GradientPick(percentage, WeightStartColor, WeightCenterColor, WeightEndColor)); - float x = (node.coordinates.longitude - minLon) * scaleFactor; - float y = (maxLat - node.coordinates.latitude) * scaleFactor; + float x = (kv.Key.coordinates.longitude - minLon) * scaleFactor; + float y = (maxLat - kv.Key.coordinates.latitude) * scaleFactor; 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, PenThickness); - for (int i = 0; i < pathCoordinates.Count - 1; i++) - { - Coordinates c1 = pathCoordinates[i]; - Coordinates c2 = pathCoordinates[i + 1]; - Point p1 = new(Convert.ToInt32((c1.longitude - minLon) * 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); - } - - return ret; + return new ValueTuple(ret, new Bounds(minLat,minLon,maxLat,maxLon)); } - + /* * https://stackoverflow.com/questions/55601338/get-a-color-value-within-a-gradient-based-on-a-value */