diff --git a/Executable/Executable.csproj b/Executable/Executable.csproj index 4d8c158..2a4e87b 100644 --- a/Executable/Executable.csproj +++ b/Executable/Executable.csproj @@ -13,14 +13,18 @@ - - C:\Users\glax\source\repos\Geo-Graph\Geo-Graph\bin\Debug\net6.0\Geo-Graph.dll + + + + + + ..\..\OSM_Graph\OSM_Graph\bin\Debug\net8.0\Graph.dll - - ..\..\Logging\Logging\bin\Debug\net6.0\Logging.dll + + ..\..\OSM_Graph\OSM_Graph\bin\Debug\net8.0\OSM_Graph.dll - - C:\Users\glax\source\repos\OSM-XML-Importer\OSM-XML-Importer\bin\Debug\net6.0\OSM-XML-Importer.dll + + ..\..\OSM_Regions\OSM_Regions\bin\Debug\net8.0\OSM_Regions.dll diff --git a/Executable/Program.cs b/Executable/Program.cs index ec3856f..ca1a363 100644 --- a/Executable/Program.cs +++ b/Executable/Program.cs @@ -1,60 +1,80 @@ -using GeoGraph; -using Logging; +using System.Diagnostics; +using System.Globalization; using astar; -using OSM_XML_Importer; +using GlaxArguments; +using GlaxLogger; +using Microsoft.Extensions.Logging; +using OSM_Regions; -string[] confirmation = { "yes", "1", "true" }; +Logger logger = new(LogLevel.Debug, consoleOut: Console.Out); -Logger logger = new(LogType.CONSOLE, LogLevel.DEBUG); -string xmlPath; -bool onlyJunctions; -switch (args.Length) +Argument pathArg = new (["-p", "--path"], 1, "Path to OSM-XML-File"); +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 ([pathArg, regionArg, importPathArg, routeCoordinateArg]); + +Dictionary arguments = af.Fetch(args); + +if (!arguments.ContainsKey(regionArg)) { - case 0: - xmlPath = @""; - onlyJunctions = true; - break; - case 1: - xmlPath = args[0]; - onlyJunctions = true; - if (!File.Exists(xmlPath)) - { - logger.Log(LogLevel.INFO, "File {0} does not exist.", xmlPath); - throw new FileNotFoundException(xmlPath); - } - break; - case 2: - xmlPath = args[0]; - if (!File.Exists(xmlPath)) - { - logger.Log(LogLevel.INFO, "File {0} does not exist.", xmlPath); - throw new FileNotFoundException(xmlPath); - } - if (confirmation.Contains(args[1].ToLower())) - onlyJunctions = true; - else - onlyJunctions = false; - break; - default: - logger.Log(LogLevel.INFO, "Invalid Arguments."); - logger.Log(LogLevel.INFO, "Arguments can be:"); - logger.Log(LogLevel.INFO, "arg0 Path to file: string"); - logger.Log(LogLevel.INFO, "arg1 onlyJunctions: 'yes', '1', 'true'"); - return; + PrintUsage(); + return; +} +if (!float.TryParse(arguments[regionArg][0], NumberFormatInfo.InvariantInfo, out float regionSize)) +{ + logger.LogError($"Failed to parse region Size from input w{arguments[regionArg][0]}"); + return; } -Graph graph = Importer.Import(xmlPath, onlyJunctions, logger); - -Random r = new(); -Route _route; -Node n1, n2; -do +if (!arguments.ContainsKey(routeCoordinateArg)) { - do + PrintUsage(); + return; +} +if (!float.TryParse(arguments[routeCoordinateArg][0], NumberFormatInfo.InvariantInfo, out float startLat) || + !float.TryParse(arguments[routeCoordinateArg][1], NumberFormatInfo.InvariantInfo, out float startLon) || + !float.TryParse(arguments[routeCoordinateArg][2], NumberFormatInfo.InvariantInfo, out float endLat) || + !float.TryParse(arguments[routeCoordinateArg][3], NumberFormatInfo.InvariantInfo, out float endLon) ) +{ + logger.LogError($"Failed to parse start/end coordinates."); + return; +} + +string? importPath = null; +if (arguments.TryGetValue(importPathArg, out string[]? importPathVal)) +{ + importPath = importPathVal[0]; +} + +if (arguments.TryGetValue(pathArg, out string[]? pathValue)) +{ + if(!File.Exists(pathValue[0])) { - n1 = graph.NodeAtIndex(r.Next(0, graph.GetNodeCount() - 1)); - n2 = graph.NodeAtIndex(r.Next(0, graph.GetNodeCount() - 1)); - _route = new Astar().FindPath(graph, n1, n2, logger); - } while (!_route.routeFound); - logger.Log(LogLevel.INFO, "Press Enter to find new path."); -} while (Console.ReadKey().Key.Equals(ConsoleKey.Enter)); + logger.LogError($"File doesn't exist {pathValue[0]}"); + PrintUsage(); + return; + } + + Converter converter = new (regionSize, importPath, logger: logger); + converter.SplitOsmExportIntoRegionFiles(pathValue[0]); +} + +Route route = Astar.FindPath(startLat, startLon, endLat, endLon, regionSize, importPath, logger); +if(route.RouteFound) + Console.WriteLine($"{string.Join("\n", route.Steps)}\n" + + $"Distance: {route.Distance:000000.00}m"); +else + Console.WriteLine("No route found."); + +Console.WriteLine($"Visited Nodes: {route.Graph.Nodes.Values.Count(node => node.Previous is not null)}"); + + +void PrintUsage() +{ + Console.WriteLine($"Usage: {Process.GetCurrentProcess().MainModule?.FileName} <-r regionSize> <-c startLat startLon endLat endLon> \n" + + $"Options:\n" + + $"\t-h onlyHighways\n" + + $"\t-p Path to OSM-XML file to split into regions"); +} \ No newline at end of file diff --git a/astar/Astar.cs b/astar/Astar.cs index 48d77d8..96a3ea5 100644 --- a/astar/Astar.cs +++ b/astar/Astar.cs @@ -1,191 +1,240 @@ -using Logging; -using GeoGraph; -using GeoGraph.Utils; +using Microsoft.Extensions.Logging; +using Graph.Utils; +using OSM_Regions; namespace astar { - public class Astar + public static class Astar { - private Dictionary timeRequired = new(); - private Dictionary goalDistance = new(); - private Dictionary previousNode = new(); - - public Route FindPath(Graph graph, Node start, Node goal, Logger? logger) + public static Route FindPath(float startLat, float startLon, float endLat, float endLon, float regionSize, string? importFolderPath = null, + ILogger? logger = null) { - logger?.Log(LogLevel.INFO, "From {0:000.00000}#{1:000.00000} to {2:000.00000}#{3:000.00000} Great-Circle {4:00000.00}km", start.lat, start.lon, goal.lat, goal.lon, Utils.DistanceBetweenNodes(start, goal)/1000); - List toVisit = new(); - toVisit.Add(start); - Node currentNode = start; - SetTimeRequiredToReach(start, 0); - SetDistanceToGoal(start, Convert.ToSingle(Utils.DistanceBetweenNodes(start, goal))); - while (toVisit.Count > 0 && GetTimeRequiredToReach(toVisit[0]) < GetTimeRequiredToReach(goal)) + RegionLoader rl = new(regionSize, importFolderPath, logger: logger); + Graph graph = Spiral(rl, startLat, startLon, regionSize); + KeyValuePair startNode = graph.ClosestNodeToCoordinates(startLat, startLon); + startNode.Value.PreviousIsFromStart = true; + startNode.Value.Previous = new KeyValuePair(startNode.Key, 0f); + + Graph endRegion = Spiral(rl, endLat, endLon, regionSize); + graph.ConcatGraph(endRegion); + KeyValuePair endNode = graph.ClosestNodeToCoordinates(endLat, endLon); + endNode.Value.PreviousIsFromStart = false; + endNode.Value.Previous = new KeyValuePair(endNode.Key, 0f); + + logger?.Log(LogLevel.Information, + "From {0:00.00000}#{1:000.00000} to {2:00.00000}#{3:000.00000} Great-Circle {4:00000.00}km", + startNode.Value.Lat, startNode.Value.Lon, endNode.Value.Lat, endNode.Value.Lon, + NodeUtils.DistanceBetween(startNode.Value, endNode.Value) / 1000); + + PriorityQueue toVisitStart = new(); + toVisitStart.Enqueue(startNode.Key, NodeUtils.DistanceBetween(startNode.Value, endNode.Value)); + PriorityQueue toVisitEnd = new(); + toVisitEnd.Enqueue(endNode.Key, NodeUtils.DistanceBetween(endNode.Value, startNode.Value)); + + while (toVisitStart.Count > 0 && toVisitEnd.Count > 0) { - currentNode = toVisit.First(); - logger?.Log(LogLevel.VERBOSE, "toVisit-length: {0} path-length: {1} goal-distance: {2}", toVisit.Count, timeRequired[currentNode], goalDistance[currentNode]); - //Check all neighbors of current node - foreach (Edge e in currentNode.edges) + logger?.LogDebug($"Length toVisit-Start: {toVisitStart.Count} -End: {toVisitEnd.Count}"); + /* + * FROM START + */ + ulong currentNodeStartId = toVisitStart.Dequeue(); + Node? currentNodeStart; + if (!graph.ContainsNode(currentNodeStartId)) { - if (GetTimeRequiredToReach(e.neighbor) > GetTimeRequiredToReach(currentNode) + e.time) + Graph? newRegion = Graph.FromGraph(rl.LoadRegionFromNodeId(currentNodeStartId)); + if (newRegion is null) { - SetDistanceToGoal(e.neighbor, Convert.ToSingle(Utils.DistanceBetweenNodes(e.neighbor, goal))); - SetTimeRequiredToReach(e.neighbor, GetTimeRequiredToReach(currentNode) + e.time); - SetPreviousNodeOf(e.neighbor, currentNode); - if (!toVisit.Contains(e.neighbor)) - toVisit.Add(e.neighbor); + logger?.LogError($"Could not load Region for Node {currentNodeStartId}"); + currentNodeStart = null; + } + else + { + graph.ConcatGraph(newRegion); + currentNodeStart = graph.Nodes[currentNodeStartId]; } } - - toVisit.Remove(currentNode); //"Mark" as visited - toVisit.Sort(CompareDistance); - } - - if(GetPreviousNodeOf(goal) != null) - { - logger?.Log(LogLevel.INFO, "Way found, shortest option."); - currentNode = goal; - } - else - { - logger?.Log(LogLevel.INFO, "No path between {0:000.00000}#{1:000.00000} and {2:000.00000}#{3:000.00000}", start.lat, start.lon, goal.lat, goal.lon); - return new Route(new List(), false, float.MaxValue, float.MaxValue); - } - -#pragma warning disable CS8604, CS8600 // Route was found, so has to have a previous node and edges - List tempNodes = new(); - tempNodes.Add(goal); - while(currentNode != start) - { - tempNodes.Add(GetPreviousNodeOf(currentNode)); - currentNode = GetPreviousNodeOf(currentNode); - } - tempNodes.Reverse(); - - List steps = new(); - float totalDistance = 0; - - for(int i = 0; i < tempNodes.Count - 1; i++) - { - Edge e = tempNodes[i].GetEdgeToNode(tempNodes[i + 1]); - steps.Add(new Step(tempNodes[i], e, GetTimeRequiredToReach(tempNodes[i]), GetDistanceToGoal(tempNodes[i]))); - totalDistance += e.distance; - } - - Route _route = new Route(steps, true, totalDistance, GetTimeRequiredToReach(goal)); - - logger?.Log(LogLevel.INFO, "Path found"); - - if(logger?.level > LogLevel.INFO) - { - - float time = 0; - float distance = 0; - - logger?.Log(LogLevel.DEBUG, "Route Distance: {0:00000.00km} Time: {1}", _route.distance/1000, TimeSpan.FromSeconds(_route.time)); - for(int i = 0; i < _route.steps.Count; i++) + else + currentNodeStart = graph.Nodes[currentNodeStartId]; + logger?.LogTrace($"Current Node Start: {currentNodeStartId} {currentNodeStart}"); + if (currentNodeStart is not null) { - Step s = _route.steps[i]; - time += s.edge.time; - distance += s.edge.distance; - logger?.Log(LogLevel.DEBUG, "Step {0:000} From {1:000.00000}#{2:000.00000} To {3:000.00000}#{4:000.00000} along {5:0000000000} after {6} and {7:0000.00}km", i, s.start.lat, s.start.lon, s.edge.neighbor.lat, s.edge.neighbor.lon, s.edge.id, TimeSpan.FromSeconds(timeRequired[s.start]), distance/1000); + foreach ((ulong nodeId, ulong wayId) in currentNodeStart.Neighbors) + { + //TODO checks for way-stuff + Node? neighbor; + if (!graph.ContainsNode(nodeId)) + { + Graph? newRegion = Graph.FromGraph(rl.LoadRegionFromNodeId(nodeId)); + if (newRegion is null) + { + logger?.LogError($"Could not load Region for Node {nodeId}"); + neighbor = null; + } + else + { + graph.ConcatGraph(newRegion); + neighbor = Node.FromGraphNode(graph.Nodes[nodeId]); + } + } + else + { + neighbor = graph.Nodes[nodeId]; + } + + if (neighbor is not null) + { + /* + * IMPORTANT SHIT BELOW + */ + if (neighbor.PreviousIsFromStart is false)//Check if we found the opposite End + return PathFound(graph, currentNodeStart, neighbor); + float distance = currentNodeStart.Previous!.Value.Value + (float)neighbor.DistanceTo(currentNodeStart); + if (neighbor.Previous is null || neighbor.Previous.Value.Value > distance) + { + neighbor.Previous = new KeyValuePair(currentNodeStartId, distance); + neighbor.PreviousIsFromStart = true; + toVisitStart.Enqueue(nodeId, NodeUtils.DistanceBetween(neighbor, endNode.Value)); + } + logger?.LogTrace($"Neighbor {nodeId} {neighbor}"); + } + } + } + + /* + * FROM END + */ + ulong currentNodeEndId = toVisitEnd.Dequeue(); + Node? currentNodeEnd; + if (!graph.ContainsNode(currentNodeEndId)) + { + Graph? newRegion = Graph.FromGraph(rl.LoadRegionFromNodeId(currentNodeEndId)); + if (newRegion is null) + { + logger?.LogError($"Could not load Region for Node {currentNodeEndId}"); + currentNodeEnd = null; + } + else + { + graph.ConcatGraph(newRegion); + currentNodeEnd = graph.Nodes[currentNodeEndId]; + } + } + else + currentNodeEnd = graph.Nodes[currentNodeEndId]; + logger?.LogTrace($"Current Node End: {currentNodeEndId} {currentNodeEnd}"); + + if (currentNodeEnd is not null) + { + foreach ((ulong nodeId, ulong wayId) in currentNodeEnd.Neighbors) + { + //TODO checks for way-stuff + Node? neighbor; + if (!graph.ContainsNode(nodeId)) + { + Graph? newRegion = Graph.FromGraph(rl.LoadRegionFromNodeId(nodeId)); + if (newRegion is null) + { + logger?.LogError($"Could not load Region for Node {nodeId}"); + neighbor = null; + } + else + { + graph.ConcatGraph(newRegion); + neighbor = Node.FromGraphNode(graph.Nodes[nodeId]); + } + } + else + { + neighbor = graph.Nodes[nodeId]; + } + + if (neighbor is not null) + { + /* + * IMPORTANT SHIT BELOW + */ + if (neighbor.PreviousIsFromStart is true)//Check if we found the opposite End + return PathFound(graph, neighbor, currentNodeEnd); + + float distance = currentNodeEnd.Previous!.Value.Value + (float)neighbor.DistanceTo(currentNodeEnd); + if (neighbor.Previous is null || neighbor.Previous.Value.Value > distance) + { + neighbor.Previous = new KeyValuePair(currentNodeEndId, distance); + neighbor.PreviousIsFromStart = false; + toVisitEnd.Enqueue(nodeId, NodeUtils.DistanceBetween(neighbor, startNode.Value)); + } + logger?.LogTrace($"Neighbor {nodeId} {neighbor}"); + } + } } } - - return _route; -#pragma warning restore CS8604, CS8600 + return new Route(graph, Array.Empty().ToList(), false); } - /* - * Compares two nodes and returns the node closer to the goal - * -1 => n1 smaller n2 - * 0 => n1 equal n2 - * 1 => n1 larger n2 - */ - private int CompareDistance(Node n1, Node n2) + private static Route PathFound(Graph graph, Node fromStart, Node fromEnd) { - if (n1 == null || n2 == null) - return 0; - else + List path = new(); + Node current = fromStart; + while (current.Previous is not null && current.Previous.Value.Value == 0f) { - if (GetDistanceToGoal(n1) < GetDistanceToGoal(n2)) - return -1; - else if (GetDistanceToGoal(n1) > GetDistanceToGoal(n2)) - return 1; - else return 0; + Step step = new((float)NodeUtils.DistanceBetween(graph.Nodes[current.Previous.Value.Key], current), graph.Nodes[current.Previous.Value.Key], current); + path.Add(step); + current = graph.Nodes[current.Previous.Value.Key]; } - } - - /* - * Compares two nodes and returns the node with the shorter path - * -1 => n1 smaller n2 - * 0 => n1 equal n2 - * 1 => n1 larger n2 - */ - private int ComparePathLength(Node n1, Node n2) - { - if (n1 == null || n2 == null) - return 0; - else + path.Reverse();//Since we go from the middle backwards until here + path.Add(new Step((float)NodeUtils.DistanceBetween(fromStart, fromEnd), fromStart, fromEnd)); + current = fromEnd; + while (current.Previous is not null && current.Previous.Value.Value == 0f) { - if (GetTimeRequiredToReach(n1) < GetTimeRequiredToReach(n2)) - return -1; - else if (GetTimeRequiredToReach(n1) > GetTimeRequiredToReach(n2)) - return 1; - else return 0; + Step step = new((float)NodeUtils.DistanceBetween(graph.Nodes[current.Previous.Value.Key], current), current, graph.Nodes[current.Previous.Value.Key]); + path.Add(step); + current = graph.Nodes[current.Previous.Value.Key]; } + + return new Route(graph, path, true); } - - private float GetTimeRequiredToReach(Node n) + private static Graph Spiral(RegionLoader loader, float lat, float lon, float regionSize) { - if (timeRequired.TryGetValue(n, out float t)) + Graph? ret = Graph.FromGraph(loader.LoadRegionFromCoordinates(lat, lon)); + int iteration = 1; + while (ret is null) { - return t; + for (int x = -iteration; x <= iteration; x++) + { + Graph? g1 = Graph.FromGraph(loader.LoadRegionFromCoordinates(lat + x * regionSize, lon - iteration * regionSize)); + Graph? g2 = Graph.FromGraph(loader.LoadRegionFromCoordinates(lat + x * regionSize, lon + iteration * regionSize)); + if (ret is not null) + { + ret.ConcatGraph(g1); + ret.ConcatGraph(g2); + } + else if (ret is null && g1 is not null) + { + ret = g1; + ret.ConcatGraph(g2); + }else if (ret is null && g2 is not null) + ret = g2; + } + for (int y = -iteration + 1; y < iteration; y++) + { + Graph? g1 = Graph.FromGraph(loader.LoadRegionFromCoordinates(lat - iteration * regionSize, lon + y * regionSize)); + Graph? g2 = Graph.FromGraph(loader.LoadRegionFromCoordinates(lat + iteration * regionSize, lon + y * regionSize)); + if (ret is not null) + { + ret.ConcatGraph(g1); + ret.ConcatGraph(g2); + } + else if (ret is null && g1 is not null) + { + ret = g1; + ret.ConcatGraph(g2); + }else if (ret is null && g2 is not null) + ret = g2; + } + iteration++; } - else - { - return float.MaxValue; - } - } - - private void SetTimeRequiredToReach(Node n, float t) - { - if (!timeRequired.TryAdd(n, t)) - timeRequired[n] = t; - } - - private float GetDistanceToGoal(Node n) - { - if (goalDistance.TryGetValue(n, out float t)) - { - return t; - } - else - { - return float.MaxValue; - } - } - - private void SetDistanceToGoal(Node n, float d) - { - if (!goalDistance.TryAdd(n, d)) - goalDistance[n] = d; - } - - private Node? GetPreviousNodeOf(Node n) - { - if(previousNode.TryGetValue(n, out Node? t)) - { - return t; - }else - { - return null; - } - } - - private void SetPreviousNodeOf(Node n, Node p) - { - if (!previousNode.TryAdd(n, p)) - previousNode[n] = p; + return ret; } } } \ No newline at end of file diff --git a/astar/Graph.cs b/astar/Graph.cs new file mode 100644 index 0000000..b3d7c2c --- /dev/null +++ b/astar/Graph.cs @@ -0,0 +1,61 @@ +using Graph; + +namespace astar; + +public class Graph +{ + public readonly Dictionary Nodes = new(); + public readonly Dictionary Ways = new (); + + public static Graph? FromGraph(global::Graph.Graph? graph) + { + if (graph is null) + return null; + Graph ret = new(); + foreach ((ulong id, global::Graph.Node? node) in graph.Nodes) + ret.Nodes.Add(id, Node.FromGraphNode(node)); + foreach ((ulong id, Way? way) in graph.Ways) + ret.Ways.Add(id, way); + return ret; + } + + public void ConcatGraph(Graph? graph) + { + if (graph is null) + return; + foreach ((ulong id, Node n) in graph.Nodes) + this.Nodes.TryAdd(id, n); + foreach ((ulong id, Way w) in graph.Ways) + this.Ways.TryAdd(id, w); + } + + public bool ContainsNode(Node node) + { + return Nodes.ContainsValue(node); + } + + public bool ContainsNode(ulong nodeId) + { + return Nodes.ContainsKey(nodeId); + } + + public bool ContainsWay(Way way) + { + return Ways.ContainsValue(way); + } + + public bool ContainsWay(ulong wayId) + { + return Ways.ContainsKey(wayId); + } + + public KeyValuePair ClosestNodeToCoordinates(float lat, float lon) + { + return Nodes.MinBy(n => n.Value.DistanceTo(lat, lon)); + } + + public override string ToString() + { + return $"Graph {Nodes.Count} Nodes {Ways.Count} Ways."; + } +} \ No newline at end of file diff --git a/astar/Node.cs b/astar/Node.cs new file mode 100644 index 0000000..5d1ab29 --- /dev/null +++ b/astar/Node.cs @@ -0,0 +1,14 @@ +namespace astar; + +public class Node(float lat, float lon, Dictionary? neighbors = null) : global::Graph.Node(lat, lon, neighbors) +{ + public KeyValuePair? Previous = null; + public bool? PreviousIsFromStart = null; + + public static Node FromGraphNode(global::Graph.Node node) => new (node.Lat, node.Lon, node.Neighbors); + + public override string ToString() + { + return $"{Lat:00.000000} {Lon:000.000000} Previous {Previous?.Key} {(PreviousIsFromStart is not null ? PreviousIsFromStart.Value ?"Start":"End" : null)}"; + } +} \ No newline at end of file diff --git a/astar/Route.cs b/astar/Route.cs index f42386a..e322356 100644 --- a/astar/Route.cs +++ b/astar/Route.cs @@ -1,36 +1,57 @@ -using GeoGraph; -namespace astar +namespace astar { - public class Route + public class Route(Graph graph, List steps, bool routeFound) { - public List steps { get; } - public bool routeFound { get; } - public float distance { get; } - public float time { get; } + public Graph Graph { get; } = graph; + public List Steps { get; } = steps; + public bool RouteFound { get; } = routeFound; + public float Distance => Steps.Sum(step => step.Distance); - - public Route(List steps, bool routeFound, float distance, float timeRequired) + public KeyValuePair MinCoordinates() { - this.steps = steps; - this.routeFound = routeFound; - this.distance = distance; - this.time = timeRequired; + float minLat, minLon; + if (RouteFound) + { + Step minLatStep = Steps.MinBy(step => step.Node1.Lat < step.Node2.Lat ? step.Node1.Lat : step.Node2.Lat); + Step minLonStep = Steps.MinBy(step => step.Node1.Lon < step.Node2.Lon ? step.Node1.Lon : step.Node2.Lon); + minLat = minLatStep.Node1.Lat < minLatStep.Node2.Lat ? minLatStep.Node1.Lat : minLatStep.Node2.Lat; + minLon = minLonStep.Node1.Lon < minLonStep.Node2.Lon ? minLonStep.Node1.Lon : minLonStep.Node2.Lon; + } + else + { + minLat = Graph.Nodes.MinBy(node => node.Value.Lat).Value.Lat; + minLon = Graph.Nodes.MinBy(node => node.Value.Lon).Value.Lon; + } + return new KeyValuePair(minLat, minLon); + } + + public KeyValuePair MaxCoordinates() + { + float maxLat, maxLon; + if (RouteFound) + { + Step maxLatStep = Steps.MaxBy(step => step.Node1.Lat > step.Node2.Lat ? step.Node1.Lat : step.Node2.Lat); + Step maxLonStep = Steps.MaxBy(step => step.Node1.Lon > step.Node2.Lon ? step.Node1.Lon : step.Node2.Lon); + maxLat = maxLatStep.Node1.Lat > maxLatStep.Node2.Lat ? maxLatStep.Node1.Lat : maxLatStep.Node2.Lat; + maxLon = maxLonStep.Node1.Lon > maxLonStep.Node2.Lon ? maxLonStep.Node1.Lon : maxLonStep.Node2.Lon; + } + else + { + maxLat = Graph.Nodes.MaxBy(node => node.Value.Lat).Value.Lat; + maxLon = Graph.Nodes.MaxBy(node => node.Value.Lon).Value.Lon; + } + return new KeyValuePair(maxLat, maxLon); } } - public struct Step + public struct Step(float distance, Node node1, Node node2) { - public Node start { get; } - public Edge edge { get; } + public readonly Node Node1 = node1, Node2 = node2; + public readonly float Distance = distance; - public float timeRequired { get; } - public float goalDistance { get; } - public Step(Node start, Edge route, float timeRequired, float goalDistance) + public override string ToString() { - this.start = start; - this.edge = route; - this.timeRequired = timeRequired; - this.goalDistance = goalDistance; + return $"{Node1.Lat:00.000000} {Node1.Lon:000.000000} --- {Distance:0000.00}m ---> {Node2.Lat:00.000000} {Node2.Lon:000.000000}"; } } } diff --git a/astar/astar.csproj b/astar/astar.csproj index 277e91a..81454e4 100644 --- a/astar/astar.csproj +++ b/astar/astar.csproj @@ -8,11 +8,19 @@ - - C:\Users\glax\source\repos\Geo-Graph\Geo-Graph\bin\Debug\net6.0\Geo-Graph.dll + + + + + + + ..\..\OSM_Graph\OSM_Graph\bin\Debug\net8.0\Graph.dll - - ..\..\Logging\Logging\bin\Debug\net6.0\Logging.dll + + ..\..\OSM_Graph\OSM_Graph\bin\Debug\net8.0\OSM_Graph.dll + + + ..\..\OSM_Regions\OSM_Regions\bin\Debug\net8.0\OSM_Regions.dll diff --git a/astar/astar.sln.DotSettings.user b/astar/astar.sln.DotSettings.user index 9f75dcd..be6cec7 100644 --- a/astar/astar.sln.DotSettings.user +++ b/astar/astar.sln.DotSettings.user @@ -1,2 +1,8 @@  - True \ No newline at end of file + True + True + True + True + True + True + True \ No newline at end of file