using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Imaging; using System.Text.Json; using OSMDatastructure.Graph; using Pathfinding; namespace RenderPath; public class Renderer { public static void DrawGraph(string resultPath) { 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; DrawLoadedNodes(graph.nodes!, graph.gScore!, coords, workingDir); } [SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")] public static void DrawLoadedNodes(HashSet nodes, Dictionary gScoreDict, List 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 maxWeight = gScoreDict.Max(kv => kv.Value); float latDiff = maxLat - minLat; float lonDiff = maxLon - minLon; const int imageMaxSize = 10000; float scaleFactor = latDiff > lonDiff ? imageMaxSize / latDiff : imageMaxSize / lonDiff; int pixelsX = (int)(lonDiff * scaleFactor); int pixelsY = (int)(latDiff * scaleFactor); Bitmap ret = new Bitmap(pixelsX, pixelsY, PixelFormat.Format32bppRgb); Graphics g = Graphics.FromImage(ret); g.Clear(Color.White); 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) { 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)); float x = (node.coordinates.longitude - minLon) * scaleFactor; float y = (maxLat - node.coordinates.latitude) * scaleFactor; g.FillEllipse(b, x, y, 2, 2); } Pen p = new Pen(Color.Red, 2); 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); } ret.Save($"{workingDir}-routing.png", ImageFormat.Bmp); } /* * https://stackoverflow.com/questions/55601338/get-a-color-value-within-a-gradient-based-on-a-value */ private static int LinearInterp(int start, int end, double percentage) => start + (int)Math.Round(percentage * (end - start)); private static Color ColorInterp(Color start, Color end, double percentage) => Color.FromArgb(LinearInterp(start.A, end.A, percentage), LinearInterp(start.R, end.R, percentage), LinearInterp(start.G, end.G, percentage), LinearInterp(start.B, end.B, percentage)); private static Color GradientPick(double percentage, Color Start, Color Center, Color End) { if (percentage < 0.5) return ColorInterp(Start, Center, percentage / 0.5); else if (percentage == 0.5) return Center; else return ColorInterp(Center, End, (percentage - 0.5)/0.5); } }