diff --git a/Graph_Renderer.sln.DotSettings.user b/Graph_Renderer.sln.DotSettings.user new file mode 100644 index 0000000..d5c2113 --- /dev/null +++ b/Graph_Renderer.sln.DotSettings.user @@ -0,0 +1,4 @@ + + True + True + True \ No newline at end of file diff --git a/Graph_Renderer/Coloring.cs b/Graph_Renderer/Coloring.cs new file mode 100644 index 0000000..e9e0c94 --- /dev/null +++ b/Graph_Renderer/Coloring.cs @@ -0,0 +1,49 @@ +using System.Drawing; +using astar.PathingHelper; +using Graph; + +namespace Graph_Renderer; + +public static class Coloring +{ + public static Color GetColorForWay(Way way) + { + if (!way.Tags.TryGetValue("highway", out string? highwayTypeStr)) + return Color.Gray; + if (!Enum.TryParse(highwayTypeStr, out HighwayType highwayType)) + return Color.Gray; + return ColorDictionary[highwayType]; + } + + private static readonly Dictionary ColorDictionary = new() { + { HighwayType.NONE, Color.Gray }, + { HighwayType.motorway, Color.OrangeRed }, + { HighwayType.trunk, Color.Orange }, + { HighwayType.primary, Color.Yellow }, + { HighwayType.secondary, Color.Aqua }, + { HighwayType.tertiary, Color.Black }, + { HighwayType.unclassified, Color.Gray }, + { HighwayType.residential, Color.Gray }, + { HighwayType.motorway_link, Color.OrangeRed }, + { HighwayType.trunk_link, Color.Orange }, + { HighwayType.primary_link, Color.Yellow }, + { HighwayType.secondary_link, Color.Aqua }, + { HighwayType.tertiary_link, Color.Black }, + { HighwayType.living_street, Color.Gray }, + { HighwayType.service, Color.Gray }, + { HighwayType.pedestrian, Color.ForestGreen }, + { HighwayType.track, Color.Gray }, + { HighwayType.bus_guideway, Color.Navy }, + { HighwayType.escape, Color.Gray }, + { HighwayType.raceway, Color.Gray }, + { HighwayType.road, Color.Gray }, + { HighwayType.busway, Color.Navy }, + { HighwayType.footway, Color.GreenYellow }, + { HighwayType.bridleway, Color.Gray }, + { HighwayType.steps, Color.PaleGreen }, + { HighwayType.corridor, Color.Green }, + { HighwayType.path, Color.Green }, + { HighwayType.cycleway, Color.Salmon }, + { HighwayType.construction, Color.Gray } + }; +} \ No newline at end of file diff --git a/Graph_Renderer/Graph_Renderer.csproj b/Graph_Renderer/Graph_Renderer.csproj index 2f4fc77..2ce7315 100644 --- a/Graph_Renderer/Graph_Renderer.csproj +++ b/Graph_Renderer/Graph_Renderer.csproj @@ -7,4 +7,22 @@ enable + + + ..\..\astar\Executable\bin\Debug\net8.0\astar.dll + + + ..\..\OSM_Graph\OSM_Graph\bin\Debug\net8.0\Graph.dll + + + ..\..\OSM_Graph\OSM_Graph\bin\Debug\net8.0\OSM_Graph.dll + + + + + + + + + diff --git a/Graph_Renderer/Program.cs b/Graph_Renderer/Program.cs index e5dff12..daf48c4 100644 --- a/Graph_Renderer/Program.cs +++ b/Graph_Renderer/Program.cs @@ -1,3 +1,43 @@ // See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); \ No newline at end of file +using System.Globalization; +using System.Runtime.InteropServices; +using astar; +using GlaxArguments; +using GlaxLogger; +using Graph_Renderer; +using Microsoft.Extensions.Logging; + +if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) +{ + Console.WriteLine("Only runs on Windows. Sorry."); + return -1; +} + +Argument regionArg = new (["-r", "--regionSize"], 1, "Region-Size"); +Argument importPathArg = new (["-i", "--importPath"], 1, "Region-Directory"); +Argument routeCoordinateArg = new(["-c", "--route", "--coordinates"], 4, "Start and end coordinates"); + +ArgumentFetcher af = new ([regionArg, importPathArg, routeCoordinateArg]); + +Dictionary arguments = af.Fetch(args); + +if (!arguments.TryGetValue(regionArg, out string[]? regionVal) || + !float.TryParse(regionVal[0], NumberFormatInfo.InvariantInfo, out float regionSize) || + !arguments.TryGetValue(importPathArg, out string[]? importPathVal) || + !arguments.TryGetValue(routeCoordinateArg, out string[]? routeCoordinateVal) || + !float.TryParse(routeCoordinateVal[0], NumberFormatInfo.InvariantInfo, out float startLat) || + !float.TryParse(routeCoordinateVal[1], NumberFormatInfo.InvariantInfo, out float startLon) || + !float.TryParse(routeCoordinateVal[2], NumberFormatInfo.InvariantInfo, out float endLat) || + !float.TryParse(routeCoordinateVal[3], NumberFormatInfo.InvariantInfo, out float endLon)) +{ + return -1; +} + +Logger logger = new(LogLevel.Information, consoleOut: Console.Out); + +Route r = Astar.FindPath(startLat, startLon, endLat, endLon, regionSize, true, importPathVal[0], logger); + +Renderer.Render(r, 30000, "render.png"); + +return 0; \ No newline at end of file diff --git a/Graph_Renderer/Renderer.cs b/Graph_Renderer/Renderer.cs new file mode 100644 index 0000000..aa8b5cf --- /dev/null +++ b/Graph_Renderer/Renderer.cs @@ -0,0 +1,79 @@ +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Versioning; +using astar; + +namespace Graph_Renderer; + +public static class Renderer +{ + + [SupportedOSPlatform("Windows")] + public static void Render(Route r, int longestEdge, string outputPath) + { + ValueTuple minCoordinates = r.MinCoordinates(); + ValueTuple maxCoordinates = r.MaxCoordinates(); + float deltaLat = maxCoordinates.Item1 - minCoordinates.Item1; + float deltaLon = maxCoordinates.Item2 - minCoordinates.Item2; + float multiplier = deltaLat > deltaLon ? longestEdge / deltaLat : longestEdge / deltaLon; + + + Bitmap bitmap = new((int)(deltaLon * multiplier), (int)(deltaLat * multiplier), System.Drawing.Imaging.PixelFormat.Format32bppPArgb); + Graphics graphics = Graphics.FromImage(bitmap); + Pen previous = new (Color.White, 2); + using(GraphicsPath capPath = new ()) + { + // A triangle + capPath.AddLines(new Point[]{new (-2, -2), new (0, 2), new (2, -2)}); + + previous.CustomEndCap = new CustomLineCap(null, capPath); + } + + foreach ((ulong nodeId, Node? node) in r.Graph.Nodes) + { + Point startCoordinates = PixelCoordinatesFromGeoCoordinates(node, minCoordinates, multiplier, bitmap.Height); + + //All neighbors + foreach ((ulong neighborNodeId, ulong wayId) in node.Neighbors.Where(kv => r.Graph.ContainsNode(kv.Key))) + { + Point endCoordinates = PixelCoordinatesFromGeoCoordinates(r.Graph.Nodes[neighborNodeId], minCoordinates, multiplier, bitmap.Height); + graphics.DrawLine(new Pen(Coloring.GetColorForWay(r.Graph.Ways[wayId]), 2), startCoordinates, endCoordinates); + } + + //Previous + if (node.PreviousNodeId is not null) + { + Point previousCoordinates = PixelCoordinatesFromGeoCoordinates(r.Graph.Nodes[(ulong)node.PreviousNodeId], minCoordinates, multiplier, bitmap.Height); + graphics.DrawLine(previous, startCoordinates, previousCoordinates); + } + } + + if (r.RouteFound) + { + Pen route = new(Color.BlueViolet, 2); + foreach (Step step in r.Steps) + { + Point startCoordinates = PixelCoordinatesFromGeoCoordinates(step.Node1, minCoordinates, multiplier, bitmap.Height); + Point endCoordinates = PixelCoordinatesFromGeoCoordinates(step.Node2, minCoordinates, multiplier, bitmap.Height); + graphics.DrawLine(route, startCoordinates, endCoordinates); + } + } + + Directory.CreateDirectory(new FileInfo(outputPath).DirectoryName!); + bitmap.Save(outputPath); + Console.WriteLine(outputPath); + } + + private static Point PixelCoordinatesFromGeoCoordinates + (Node node, ValueTuple minCoordinates, float multiplier, int height) => + PixelCoordinatesFromGeoCoordinates(node.Lat, node.Lon, minCoordinates, multiplier, height); + + private static Point PixelCoordinatesFromGeoCoordinates(float lat, float lon, + ValueTuple minCoordinates, float multiplier, int height) + { + float pLat = lat - minCoordinates.Item1; + float pLon = lon - minCoordinates.Item2; + + return new Point((int)(pLon * multiplier), height - (int)(pLat * multiplier)); + } +} \ No newline at end of file