Compare commits
16 Commits
b87d8a0300
...
95c0088b73
Author | SHA1 | Date | |
---|---|---|---|
95c0088b73 | |||
cd3905915b | |||
dd37430761 | |||
42e915ee05 | |||
7d769a064f | |||
93a448e189 | |||
750ba5c624 | |||
1facca84ba | |||
8b7cfcbd77 | |||
28ab2b2bb8 | |||
7201b9c993 | |||
d1f311a76b | |||
2b252e2b06 | |||
d456275fc1 | |||
2bd6c5d9c4 | |||
90a09e84c5 |
@ -1,4 +1,3 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
using Pathfinding;
|
using Pathfinding;
|
||||||
@ -14,11 +13,11 @@ builder.Services.AddSwaggerGen();
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.MapGet("/getRoute", (float latStart, float lonStart, float latEnd, float lonEnd, Tag.SpeedType vehicle, double stayOnSameRoadPriority, double useHigherLevelRoadsPriority, double useRoadsWithLessJunctionsPriority) =>
|
app.MapGet("/getRoute", (float latStart, float lonStart, float latEnd, float lonEnd, Tag.SpeedType vehicle, double stayOnSameRoadPriority, double useHigherLevelRoadsPriority, double useRoadsWithLessJunctionsPriority, double angleFactor) =>
|
||||||
{
|
{
|
||||||
Pathfinder result = new Pathfinder("D:/stuttgart-regbez-latest").AStar(new Coordinates(latStart, lonStart),
|
Pathfinder result = new Pathfinder("D:/stuttgart-regbez-latest").AStar(new Coordinates(latStart, lonStart),
|
||||||
new Coordinates(latEnd, lonEnd), vehicle, useHigherLevelRoadsPriority, stayOnSameRoadPriority,
|
new Coordinates(latEnd, lonEnd), vehicle, useHigherLevelRoadsPriority, stayOnSameRoadPriority,
|
||||||
useRoadsWithLessJunctionsPriority);
|
useRoadsWithLessJunctionsPriority, angleFactor);
|
||||||
return result.pathResult;
|
return result.pathResult;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -27,7 +26,7 @@ app.MapGet("/getShortestRoute", (float latStart, float lonStart, float latEnd, f
|
|||||||
{
|
{
|
||||||
Pathfinder result = new Pathfinder("D:/stuttgart-regbez-latest").AStar(new Coordinates(latStart, lonStart),
|
Pathfinder result = new Pathfinder("D:/stuttgart-regbez-latest").AStar(new Coordinates(latStart, lonStart),
|
||||||
new Coordinates(latEnd, lonEnd), Tag.SpeedType.any, 0, 0,
|
new Coordinates(latEnd, lonEnd), Tag.SpeedType.any, 0, 0,
|
||||||
0);
|
0, 0);
|
||||||
return result.pathResult;
|
return result.pathResult;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -12,15 +12,15 @@ public class OsmNode
|
|||||||
public OsmNode(ulong nodeId, float lat, float lon)
|
public OsmNode(ulong nodeId, float lat, float lon)
|
||||||
{
|
{
|
||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
this.edges = new();
|
edges = new();
|
||||||
this.coordinates = new Coordinates(lat, lon);
|
coordinates = new Coordinates(lat, lon);
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public OsmNode(ulong nodeId, Coordinates coordinates)
|
public OsmNode(ulong nodeId, Coordinates coordinates)
|
||||||
{
|
{
|
||||||
this.nodeId = nodeId;
|
this.nodeId = nodeId;
|
||||||
this.edges = new();
|
edges = new();
|
||||||
this.coordinates = coordinates;
|
this.coordinates = coordinates;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,8 @@ public class OsmNode
|
|||||||
HashSet<OsmEdge> e = edges.Where(edge => edge.neighborId == n.nodeId).ToHashSet();
|
HashSet<OsmEdge> e = edges.Where(edge => edge.neighborId == n.nodeId).ToHashSet();
|
||||||
if (e.Count > 0)
|
if (e.Count > 0)
|
||||||
return e.First();
|
return e.First();
|
||||||
else return null;
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
|
@ -47,16 +47,12 @@ public class Region
|
|||||||
|
|
||||||
public OsmNode? GetNode(ulong id)
|
public OsmNode? GetNode(ulong id)
|
||||||
{
|
{
|
||||||
if (ContainsNode(id))
|
return ContainsNode(id) ? nodes.First(node => node.nodeId == id) : null;
|
||||||
return nodes.First(node => node.nodeId == id);
|
|
||||||
else return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OsmNode? GetNode(Coordinates coordinates)
|
public OsmNode? GetNode(Coordinates coordinates)
|
||||||
{
|
{
|
||||||
if (ContainsNode(coordinates))
|
return ContainsNode(coordinates) ? nodes.First(node => node.coordinates.Equals(coordinates)) : null;
|
||||||
return nodes.First(node => node.coordinates.Equals(coordinates));
|
|
||||||
else return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using OSMDatastructure.Graph;
|
|
||||||
|
|
||||||
namespace OSMDatastructure;
|
namespace OSMDatastructure;
|
||||||
|
|
||||||
|
@ -65,12 +65,12 @@ namespace OSMDatastructure
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double DegreesToRadians(double deg)
|
public static double DegreesToRadians(double deg)
|
||||||
{
|
{
|
||||||
return deg * Math.PI / 180.0;
|
return deg * Math.PI / 180.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double RadiansToDegrees(double rad)
|
public static double RadiansToDegrees(double rad)
|
||||||
{
|
{
|
||||||
return rad * 180.0 / Math.PI;
|
return rad * 180.0 / Math.PI;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using System.Diagnostics.Tracing;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
|
@ -6,11 +6,15 @@ public class PathResult
|
|||||||
{
|
{
|
||||||
[JsonInclude]public TimeSpan calcTime;
|
[JsonInclude]public TimeSpan calcTime;
|
||||||
[JsonInclude]public List<PathNode> pathNodes;
|
[JsonInclude]public List<PathNode> pathNodes;
|
||||||
|
[JsonInclude]public double distance;
|
||||||
|
[JsonInclude]public double weight;
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes)
|
public PathResult(TimeSpan calcTime, List<PathNode> pathNodes, double distance, double weight)
|
||||||
{
|
{
|
||||||
this.calcTime = calcTime;
|
this.calcTime = calcTime;
|
||||||
this.pathNodes = pathNodes;
|
this.pathNodes = pathNodes;
|
||||||
|
this.distance = distance;
|
||||||
|
this.weight = weight;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,11 +2,9 @@
|
|||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
using static OSMDatastructure.Tag;
|
using static OSMDatastructure.Tag;
|
||||||
using WayType = OSMDatastructure.Tag.WayType;
|
|
||||||
|
|
||||||
namespace Pathfinding;
|
namespace Pathfinding;
|
||||||
|
|
||||||
//TODO check parameters for all functions and determine global fields
|
|
||||||
public class Pathfinder
|
public class Pathfinder
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -14,6 +12,8 @@ public class Pathfinder
|
|||||||
public readonly string workingDir;
|
public readonly string workingDir;
|
||||||
public PathResult? pathResult;
|
public PathResult? pathResult;
|
||||||
public Dictionary<OsmNode, double>? gScore;
|
public Dictionary<OsmNode, double>? gScore;
|
||||||
|
private Dictionary<OsmNode, OsmNode>? _cameFromDict;
|
||||||
|
private SpeedType _speedType;
|
||||||
|
|
||||||
public Pathfinder(string workingDirectory)
|
public Pathfinder(string workingDirectory)
|
||||||
{
|
{
|
||||||
@ -25,30 +25,32 @@ public class Pathfinder
|
|||||||
|
|
||||||
public Pathfinder AStar(Coordinates startCoordinates, Coordinates goalCoordinates,
|
public Pathfinder AStar(Coordinates startCoordinates, Coordinates goalCoordinates,
|
||||||
SpeedType vehicle, double heuristicRoadLevelPriority, double heuristicSameRoadPriority,
|
SpeedType vehicle, double heuristicRoadLevelPriority, double heuristicSameRoadPriority,
|
||||||
double heuristicFewJunctionsPriority)
|
double heuristicFewJunctionsPriority, double angleWeightFactor)
|
||||||
{
|
{
|
||||||
DateTime startCalc = DateTime.Now;
|
DateTime startCalc = DateTime.Now;
|
||||||
regionManager = new RegionManager(workingDir);
|
regionManager = new RegionManager(workingDir);
|
||||||
OsmNode? startNode = regionManager.ClosestNodeToCoordinates(startCoordinates, vehicle);
|
_speedType = vehicle;
|
||||||
OsmNode? goalNode = regionManager.ClosestNodeToCoordinates(goalCoordinates, vehicle);
|
OsmNode? startNode = regionManager.ClosestNodeToCoordinates(startCoordinates, _speedType);
|
||||||
|
OsmNode? goalNode = regionManager.ClosestNodeToCoordinates(goalCoordinates, _speedType);
|
||||||
if (startNode is null || goalNode is null)
|
if (startNode is null || goalNode is null)
|
||||||
{
|
{
|
||||||
pathResult = new(DateTime.Now - startCalc, new List<PathNode>());
|
pathResult = new(DateTime.Now - startCalc, new List<PathNode>(),0 ,0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PriorityQueue<OsmNode, double> openSetfScore = new();
|
PriorityQueue<OsmNode, double> openSetfScore = new();
|
||||||
openSetfScore.Enqueue(startNode, 0);
|
openSetfScore.Enqueue(startNode, 0);
|
||||||
Dictionary<OsmNode, OsmNode> cameFromDict = new();
|
|
||||||
gScore = new() { { startNode, 0 } };
|
gScore = new() { { startNode, 0 } };
|
||||||
|
_cameFromDict = new();
|
||||||
|
|
||||||
while (openSetfScore.Count > 0)
|
while (openSetfScore.Count > 0)
|
||||||
{
|
{
|
||||||
OsmNode currentNode = openSetfScore.Dequeue();
|
OsmNode currentNode = openSetfScore.Dequeue();
|
||||||
if (currentNode.Equals(goalNode))
|
if (currentNode.Equals(goalNode))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Path found.");
|
TimeSpan calcTime = DateTime.Now - startCalc;
|
||||||
this.pathResult = GetPath(cameFromDict, goalNode, DateTime.Now - startCalc);
|
pathResult = GetPath(goalNode, calcTime);
|
||||||
|
Console.WriteLine($"Path found. {calcTime} PathLength {pathResult.pathNodes.Count} VisitedNodes {gScore.Count} Distance {pathResult.distance} Duration {pathResult.weight}");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,20 +60,15 @@ public class Pathfinder
|
|||||||
if (neighbor is not null)
|
if (neighbor is not null)
|
||||||
{
|
{
|
||||||
double tentativeGScore =
|
double tentativeGScore =
|
||||||
gScore[currentNode] + Weight(currentNode, neighbor, edge, vehicle);
|
gScore[currentNode] + Weight(currentNode, neighbor, edge, angleWeightFactor);
|
||||||
gScore.TryAdd(neighbor, double.MaxValue);
|
gScore.TryAdd(neighbor, double.MaxValue);
|
||||||
if (tentativeGScore < gScore[neighbor])
|
if (tentativeGScore < gScore[neighbor])
|
||||||
{
|
{
|
||||||
if (cameFromDict.ContainsKey(neighbor))
|
if(!_cameFromDict.TryAdd(neighbor, currentNode))
|
||||||
cameFromDict[neighbor] = currentNode;
|
_cameFromDict[neighbor] = currentNode;
|
||||||
else
|
gScore[neighbor] = tentativeGScore;
|
||||||
cameFromDict.Add(neighbor, currentNode);
|
double h = Heuristic(currentNode, neighbor, goalNode, edge,
|
||||||
if (gScore.ContainsKey(neighbor))
|
heuristicRoadLevelPriority, heuristicFewJunctionsPriority, heuristicSameRoadPriority, angleWeightFactor);
|
||||||
gScore[neighbor] = tentativeGScore;
|
|
||||||
else
|
|
||||||
gScore.Add(neighbor, tentativeGScore);
|
|
||||||
double h = Heuristic(currentNode, neighbor, goalNode, edge, vehicle,
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -79,51 +76,37 @@ public class Pathfinder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathResult = new(DateTime.Now - startCalc, new List<PathNode>());
|
pathResult = new(DateTime.Now - startCalc, new List<PathNode>(),0 ,0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveResult(string path)
|
private double Weight(OsmNode currentNode, OsmNode neighborNode, OsmEdge edge, double angleWeightFactor)
|
||||||
{
|
{
|
||||||
FileStream fs = new (path, FileMode.CreateNew);
|
double distance = Utils.DistanceBetween(currentNode, neighborNode);
|
||||||
JsonSerializer.Serialize(fs, pathResult, JsonSerializerOptions.Default);
|
double speed = regionManager.GetSpeedForEdge(currentNode, edge.wayId, _speedType);
|
||||||
fs.Dispose();
|
|
||||||
Console.WriteLine($"Saved result to {path}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private PathResult GetPath(Dictionary<OsmNode, OsmNode> cameFromDict, OsmNode goalNode, TimeSpan calcFinished)
|
|
||||||
{
|
|
||||||
List<PathNode> path = new();
|
|
||||||
OsmNode currentNode = goalNode;
|
|
||||||
while (cameFromDict.ContainsKey(cameFromDict[currentNode]))
|
|
||||||
{
|
|
||||||
OsmEdge? currentEdge = cameFromDict[currentNode].edges.First(edge => edge.neighborId == currentNode.nodeId);
|
|
||||||
HashSet<Tag>? tags =
|
|
||||||
regionManager.GetRegion(currentNode.coordinates)!.tagManager.GetTagsForWayId(currentEdge.wayId);
|
|
||||||
PathNode? newNode = PathNode.FromOsmNode(currentNode, tags);
|
|
||||||
if(newNode is not null)
|
|
||||||
path.Add(newNode);
|
|
||||||
currentNode = cameFromDict[currentNode];
|
|
||||||
}
|
|
||||||
|
|
||||||
path.Reverse();
|
|
||||||
|
|
||||||
return new PathResult(calcFinished, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double Weight(OsmNode fromNode, OsmNode neighborNode, OsmEdge edge, SpeedType vehicle)
|
|
||||||
{
|
|
||||||
double distance = Utils.DistanceBetween(fromNode, neighborNode);
|
|
||||||
double speed = regionManager.GetSpeedForEdge(fromNode, edge.wayId, vehicle);
|
|
||||||
//double prio = GetPriorityVehicleRoad(edge, vehicle, regionManager.GetRegion(fromNode.coordinates)!);
|
|
||||||
return distance / speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double Heuristic(OsmNode fromNode, OsmNode neighborNode, OsmNode goalNode, OsmEdge edge, SpeedType vehicle, double roadPriorityFactor, double junctionFactor, double sameRoadFactor)
|
|
||||||
{
|
|
||||||
double roadPriority = GetPriorityVehicleRoad(edge, vehicle, regionManager.GetRegion(fromNode.coordinates)!) * roadPriorityFactor;
|
|
||||||
|
|
||||||
TagManager curTags = regionManager.GetRegion(fromNode.coordinates)!.tagManager;
|
double angle = 1;
|
||||||
|
if (_cameFromDict!.ContainsKey(currentNode))
|
||||||
|
{
|
||||||
|
OsmNode previousNode = _cameFromDict[currentNode];
|
||||||
|
Vector v1 = new(previousNode, currentNode);
|
||||||
|
Vector v2 = new(currentNode, neighborNode);
|
||||||
|
double nodeAngle = v1.Angle(v2);
|
||||||
|
angle = ((180 - nodeAngle) / 180) * angleWeightFactor;
|
||||||
|
}
|
||||||
|
double prio = regionManager.GetPriorityForVehicle(_speedType,edge, currentNode);
|
||||||
|
return distance / (1 + speed + angle + prio);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double Heuristic(OsmNode currentNode, OsmNode neighborNode, OsmNode goalNode, OsmEdge edge, double roadPriorityFactor, double junctionFactor, double sameRoadFactor, double nodeAngleFactor)
|
||||||
|
{
|
||||||
|
double roadPriority = regionManager.GetPriorityForVehicle(_speedType, edge, currentNode) * roadPriorityFactor;
|
||||||
|
if (roadPriority == 0)
|
||||||
|
return double.MaxValue;
|
||||||
|
|
||||||
|
double speed = regionManager.GetSpeedForEdge(currentNode, edge.wayId, _speedType) * 0.0003;
|
||||||
|
|
||||||
|
TagManager curTags = regionManager.GetRegion(currentNode.coordinates)!.tagManager;
|
||||||
TagManager nextTags = regionManager.GetRegion(neighborNode.coordinates)!.tagManager;
|
TagManager nextTags = regionManager.GetRegion(neighborNode.coordinates)!.tagManager;
|
||||||
|
|
||||||
bool sameName = false;
|
bool sameName = false;
|
||||||
@ -142,70 +125,82 @@ public class Pathfinder
|
|||||||
|
|
||||||
double junctionCount = (neighborNode.edges.Count > 2 ? 0 : 1) * junctionFactor;
|
double junctionCount = (neighborNode.edges.Count > 2 ? 0 : 1) * junctionFactor;
|
||||||
|
|
||||||
return Utils.DistanceBetween(neighborNode, goalNode) / (1 + roadPriority + sameRoadName + junctionCount);
|
double angle = 0;
|
||||||
}
|
if (_cameFromDict!.ContainsKey(currentNode))
|
||||||
|
|
||||||
private static double GetPriorityVehicleRoad(OsmEdge edge, SpeedType vehicle, Region region)
|
|
||||||
{
|
|
||||||
if (vehicle == SpeedType.any)
|
|
||||||
return 1;
|
|
||||||
WayType? wayType = (WayType?)region.tagManager.GetTag(edge.wayId, TagType.highway);
|
|
||||||
if(wayType is null)
|
|
||||||
return 0;
|
|
||||||
if (vehicle == SpeedType.car)
|
|
||||||
{
|
{
|
||||||
switch (wayType)
|
OsmNode previousNode = _cameFromDict[currentNode];
|
||||||
{
|
Vector v1 = new(previousNode, currentNode);
|
||||||
case WayType.motorway:
|
Vector v2 = new(currentNode, neighborNode);
|
||||||
case WayType.motorway_link:
|
double nodeAngle = v1.Angle(v2);
|
||||||
case WayType.motorroad:
|
angle = ((180 - nodeAngle) / 180) * nodeAngleFactor;
|
||||||
case WayType.trunk:
|
|
||||||
case WayType.trunk_link:
|
|
||||||
case WayType.primary:
|
|
||||||
case WayType.primary_link:
|
|
||||||
return 10;
|
|
||||||
case WayType.secondary:
|
|
||||||
case WayType.secondary_link:
|
|
||||||
return 7;
|
|
||||||
case WayType.tertiary:
|
|
||||||
case WayType.tertiary_link:
|
|
||||||
return 5;
|
|
||||||
case WayType.unclassified:
|
|
||||||
case WayType.residential:
|
|
||||||
case WayType.road:
|
|
||||||
case WayType.living_street:
|
|
||||||
return 2;
|
|
||||||
case WayType.service:
|
|
||||||
case WayType.track:
|
|
||||||
return 0.0001;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (vehicle == SpeedType.pedestrian)
|
return Utils.DistanceBetween(neighborNode, goalNode) / (roadPriority + sameRoadName + junctionCount + angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveResult(string path)
|
||||||
|
{
|
||||||
|
FileStream fs = new (path, FileMode.CreateNew);
|
||||||
|
JsonSerializer.Serialize(fs, pathResult, JsonSerializerOptions.Default);
|
||||||
|
fs.Dispose();
|
||||||
|
Console.WriteLine($"Saved result to {path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private PathResult GetPath(OsmNode goalNode, TimeSpan calcFinished)
|
||||||
|
{
|
||||||
|
List<PathNode> path = new();
|
||||||
|
OsmNode currentNode = goalNode;
|
||||||
|
double retDistance = 0;
|
||||||
|
double weight = 0;
|
||||||
|
while (_cameFromDict!.ContainsKey(_cameFromDict[currentNode]))
|
||||||
{
|
{
|
||||||
switch (wayType)
|
OsmEdge? currentEdge = _cameFromDict[currentNode].edges.FirstOrDefault(edge => edge.neighborId == currentNode.nodeId);
|
||||||
{
|
HashSet<Tag>? tags =
|
||||||
case WayType.pedestrian:
|
regionManager.GetRegion(currentNode.coordinates)!.tagManager.GetTagsForWayId(currentEdge!.wayId);
|
||||||
case WayType.corridor:
|
PathNode? newNode = PathNode.FromOsmNode(currentNode, tags);
|
||||||
case WayType.footway:
|
if(newNode is not null)
|
||||||
case WayType.path:
|
path.Add(newNode);
|
||||||
case WayType.steps:
|
|
||||||
case WayType.residential:
|
double distance = Utils.DistanceBetween(currentNode, _cameFromDict[currentNode]);
|
||||||
case WayType.living_street:
|
retDistance += distance;
|
||||||
return 10;
|
weight += regionManager.GetSpeedForEdge(_cameFromDict[currentNode], currentEdge.wayId, _speedType);
|
||||||
case WayType.service:
|
|
||||||
case WayType.cycleway:
|
currentNode = _cameFromDict[currentNode];
|
||||||
case WayType.bridleway:
|
|
||||||
case WayType.road:
|
|
||||||
case WayType.track:
|
|
||||||
case WayType.unclassified:
|
|
||||||
return 5;
|
|
||||||
case WayType.tertiary:
|
|
||||||
case WayType.tertiary_link:
|
|
||||||
case WayType.escape:
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.01;
|
path.Reverse();
|
||||||
|
|
||||||
|
return new PathResult(calcFinished, path, retDistance, retDistance / (weight / path.Count));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Vector
|
||||||
|
{
|
||||||
|
public readonly float x, y;
|
||||||
|
|
||||||
|
public Vector(float x, float y)
|
||||||
|
{
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector(OsmNode n1, OsmNode n2)
|
||||||
|
{
|
||||||
|
this.x = n1.coordinates.longitude - n2.coordinates.longitude;
|
||||||
|
this.y = n1.coordinates.latitude - n2.coordinates.latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Angle(Vector v2)
|
||||||
|
{
|
||||||
|
return Angle(this, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Angle(Vector v1, Vector v2)
|
||||||
|
{
|
||||||
|
double dotProd = v1.x * v2.x + v1.y * v2.y;
|
||||||
|
double v1L = Math.Sqrt(v1.x * v1.x + v1.y * v1.y);
|
||||||
|
double v2L = Math.Sqrt(v2.x * v2.x + v2.y * v2.y);
|
||||||
|
double ang = Math.Acos(dotProd / (v1L * v2L));
|
||||||
|
double angle = Utils.RadiansToDegrees(ang);
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using OSMDatastructure;
|
using OSMDatastructure;
|
||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
|
using SpeedType = OSMDatastructure.Tag.SpeedType;
|
||||||
|
using WayType = OSMDatastructure.Tag.WayType;
|
||||||
|
|
||||||
namespace Pathfinding
|
namespace Pathfinding
|
||||||
{
|
{
|
||||||
@ -23,29 +25,26 @@ namespace Pathfinding
|
|||||||
{
|
{
|
||||||
if(_regions.TryGetValue(id, out Region? value))
|
if(_regions.TryGetValue(id, out Region? value))
|
||||||
return value;
|
return value;
|
||||||
else
|
|
||||||
{
|
Region? loadedRegion = RegionFromId(id);
|
||||||
Region? loadedRegion = RegionFromId(id);
|
if(loadedRegion is not null)
|
||||||
if(loadedRegion is not null)
|
_regions.Add(loadedRegion!.regionHash, value: loadedRegion);
|
||||||
_regions.Add(loadedRegion!.regionHash, value: loadedRegion);
|
return loadedRegion;
|
||||||
return loadedRegion;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Region[] GetAllRegions()
|
public Region[] GetAllRegions()
|
||||||
{
|
{
|
||||||
return this._regions.Values.ToArray();
|
return _regions.Values.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Region? RegionFromFile(string filePath)
|
private Region? RegionFromFile(string filePath)
|
||||||
{
|
{
|
||||||
Region? retRegion = null;
|
if (!File.Exists(filePath))
|
||||||
if (File.Exists(filePath))
|
return null;
|
||||||
{
|
|
||||||
FileStream regionFile = new FileStream(filePath, FileMode.Open);
|
FileStream regionFile = new (filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
retRegion = JsonSerializer.Deserialize<Region>(regionFile, Region.serializerOptions)!;
|
Region retRegion = JsonSerializer.Deserialize<Region>(regionFile, Region.serializerOptions)!;
|
||||||
regionFile.Dispose();
|
regionFile.Dispose();
|
||||||
}
|
|
||||||
return retRegion;
|
return retRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,5 +130,69 @@ namespace Pathfinding
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double GetPriorityForVehicle(SpeedType speedType, OsmEdge edge, OsmNode node)
|
||||||
|
{
|
||||||
|
if (speedType == SpeedType.any)
|
||||||
|
return 1;
|
||||||
|
Region region = GetRegion(node.coordinates)!;
|
||||||
|
WayType? wayType = (WayType?)region.tagManager.GetTag(edge.wayId, Tag.TagType.highway);
|
||||||
|
if(wayType is null)
|
||||||
|
return 0;
|
||||||
|
if (speedType == SpeedType.car)
|
||||||
|
{
|
||||||
|
switch (wayType)
|
||||||
|
{
|
||||||
|
case WayType.motorway:
|
||||||
|
case WayType.motorway_link:
|
||||||
|
case WayType.motorroad:
|
||||||
|
return 17;
|
||||||
|
case WayType.trunk:
|
||||||
|
case WayType.trunk_link:
|
||||||
|
case WayType.primary:
|
||||||
|
case WayType.primary_link:
|
||||||
|
return 10;
|
||||||
|
case WayType.secondary:
|
||||||
|
case WayType.secondary_link:
|
||||||
|
return 7;
|
||||||
|
case WayType.tertiary:
|
||||||
|
case WayType.tertiary_link:
|
||||||
|
return 5;
|
||||||
|
case WayType.unclassified:
|
||||||
|
case WayType.residential:
|
||||||
|
case WayType.road:
|
||||||
|
case WayType.living_street:
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedType == SpeedType.pedestrian)
|
||||||
|
{
|
||||||
|
switch (wayType)
|
||||||
|
{
|
||||||
|
case WayType.pedestrian:
|
||||||
|
case WayType.corridor:
|
||||||
|
case WayType.footway:
|
||||||
|
case WayType.path:
|
||||||
|
case WayType.steps:
|
||||||
|
case WayType.residential:
|
||||||
|
case WayType.living_street:
|
||||||
|
return 10;
|
||||||
|
case WayType.service:
|
||||||
|
case WayType.cycleway:
|
||||||
|
case WayType.bridleway:
|
||||||
|
case WayType.road:
|
||||||
|
case WayType.track:
|
||||||
|
case WayType.unclassified:
|
||||||
|
return 5;
|
||||||
|
case WayType.tertiary:
|
||||||
|
case WayType.tertiary_link:
|
||||||
|
case WayType.escape:
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.Text.Json;
|
|
||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
using Pathfinding;
|
using Pathfinding;
|
||||||
|
|
||||||
@ -45,7 +44,7 @@ public static class Renderer
|
|||||||
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
|
[SuppressMessage("Interoperability", "CA1416:Plattformkompatibilität überprüfen")]
|
||||||
public static ValueTuple<Image, Bounds> DrawArea(RegionManager rm)
|
public static ValueTuple<Image, Bounds> DrawArea(RegionManager rm)
|
||||||
{
|
{
|
||||||
HashSet<OsmNode> nodes = new HashSet<OsmNode>();
|
HashSet<OsmNode> nodes = new();
|
||||||
foreach (OSMDatastructure.Region r in rm.GetAllRegions())
|
foreach (OSMDatastructure.Region r in rm.GetAllRegions())
|
||||||
nodes = nodes.Concat(r.nodes).ToHashSet();
|
nodes = nodes.Concat(r.nodes).ToHashSet();
|
||||||
|
|
||||||
@ -79,7 +78,7 @@ public static class Renderer
|
|||||||
OsmNode nNode = rm.GetNode(edge.neighborId, edge.neighborRegion)!;
|
OsmNode nNode = rm.GetNode(edge.neighborId, edge.neighborRegion)!;
|
||||||
Coordinates c2 = nNode.coordinates;
|
Coordinates c2 = nNode.coordinates;
|
||||||
|
|
||||||
Pen p = new Pen(GradientPick(0, start, center, end), PenThickness);
|
Pen p = new(GradientPick(0, start, center, end), PenThickness);
|
||||||
float x1 = (c1.longitude - minLon) * scaleFactor;
|
float x1 = (c1.longitude - minLon) * scaleFactor;
|
||||||
float y1 = (maxLat - c1.latitude) * scaleFactor;
|
float y1 = (maxLat - c1.latitude) * scaleFactor;
|
||||||
float x2 = (c2.longitude - minLon) * scaleFactor;
|
float x2 = (c2.longitude - minLon) * scaleFactor;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using System.Globalization;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Server;
|
namespace Server;
|
||||||
|
@ -4,6 +4,7 @@ using OSMDatastructure;
|
|||||||
using OSMDatastructure.Graph;
|
using OSMDatastructure.Graph;
|
||||||
using Pathfinding;
|
using Pathfinding;
|
||||||
using RenderPath;
|
using RenderPath;
|
||||||
|
using Region = OSMDatastructure.Region;
|
||||||
|
|
||||||
namespace Server;
|
namespace Server;
|
||||||
|
|
||||||
@ -24,18 +25,93 @@ public class Server
|
|||||||
|
|
||||||
Coordinates start = new (48.7933798f, 9.8275859f);
|
Coordinates start = new (48.7933798f, 9.8275859f);
|
||||||
Coordinates finish = new (48.795918f, 9.021618f);
|
Coordinates finish = new (48.795918f, 9.021618f);
|
||||||
Pathfinder result = new Pathfinder(workingDir).AStar(start,
|
|
||||||
finish, Tag.SpeedType.car, 0.01, 0.0001,
|
|
||||||
0);
|
|
||||||
|
|
||||||
|
TestVariables(workingDir, start, finish);
|
||||||
|
|
||||||
|
|
||||||
string parentFolder = new DirectoryInfo(workingDir).Parent!.FullName;
|
string parentFolder = new DirectoryInfo(workingDir).Parent!.FullName;
|
||||||
string resultFileName = $"{new DirectoryInfo(workingDir).Name}-{DateTime.Now.ToFileTime()}.result";
|
|
||||||
|
/*
|
||||||
|
Console.WriteLine("Preparing BaseRender");
|
||||||
|
RegionManager allRegions = new(workingDir);
|
||||||
|
for (float lat = 48.78f - Region.RegionSize / 2; lat < 48.87f + Region.RegionSize / 2; lat += Region.RegionSize / 2)
|
||||||
|
{
|
||||||
|
for (float lon = 9f - Region.RegionSize / 2; lon < 9.9f + Region.RegionSize / 2; lon += Region.RegionSize / 2)
|
||||||
|
{
|
||||||
|
allRegions.GetRegion(new Coordinates(lat, lon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine("Regions Loaded. Rendering.");
|
||||||
|
ValueTuple<Image, Renderer.Bounds> baseRender = Renderer.DrawArea(allRegions);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pathfinder result = new Pathfinder(workingDir).AStar(start,
|
||||||
|
finish, Tag.SpeedType.car, 0.034, 0.012,
|
||||||
|
0, 0.18);
|
||||||
|
|
||||||
|
Console.WriteLine($"Calc-time {result.pathResult!.calcTime} Path-length: {result.pathResult.pathNodes.Count} Visited-nodes: {result.gScore!.Count}");
|
||||||
|
|
||||||
|
string fileName = DateTime.Now.ToFileTime().ToString();
|
||||||
|
|
||||||
|
string resultFileName = $"{new DirectoryInfo(workingDir).Name}-{fileName}.result";
|
||||||
result.SaveResult(Path.Join(parentFolder, resultFileName));
|
result.SaveResult(Path.Join(parentFolder, resultFileName));
|
||||||
|
|
||||||
string renderFileName = $"{new DirectoryInfo(workingDir).Name}-{DateTime.Now.ToFileTime()}.render.png";
|
string renderFileName = $"{new DirectoryInfo(workingDir).Name}-{fileName}.render.png";
|
||||||
Image render = Renderer.DrawPathfinder(result);
|
Image render = Renderer.DrawPathfinder(result);
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
render.Save(Path.Join(parentFolder, renderFileName), ImageFormat.Png);
|
render.Save(Path.Join(parentFolder, renderFileName), ImageFormat.Png);
|
||||||
#pragma warning restore CA1416
|
#pragma warning restore CA1416*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TestVariables(string workingDir, Coordinates start, Coordinates finish)
|
||||||
|
{
|
||||||
|
string parentFolder = new DirectoryInfo(workingDir).Parent!.FullName;
|
||||||
|
|
||||||
|
Queue<Thread> CalcThreads = new();
|
||||||
|
|
||||||
|
for (double sameRoadPriority = 0.002; sameRoadPriority < 0.4; sameRoadPriority += 0.02)
|
||||||
|
{
|
||||||
|
for (double roadLevelPriority = 0.4; roadLevelPriority > 0; roadLevelPriority -= 0.02)
|
||||||
|
{
|
||||||
|
for (double angleWeightFactor = 0.01; angleWeightFactor < 0.25; angleWeightFactor += 0.01)
|
||||||
|
{
|
||||||
|
double priority = roadLevelPriority;
|
||||||
|
double roadPriority = sameRoadPriority;
|
||||||
|
double factor = angleWeightFactor;
|
||||||
|
CalcThreads.Enqueue(new Thread(() =>
|
||||||
|
{
|
||||||
|
Pathfinder testresult = new Pathfinder(workingDir).AStar(start,
|
||||||
|
finish, Tag.SpeedType.car, priority, roadPriority,
|
||||||
|
0, factor);
|
||||||
|
string fileName =
|
||||||
|
$"angle{factor:0.000}_level{priority:0.000}_same{roadPriority:0.000}.result";
|
||||||
|
testresult.SaveResult(Path.Join(parentFolder, fileName));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalTasks = CalcThreads.Count;
|
||||||
|
int completed = 0;
|
||||||
|
DateTime startTime = DateTime.Now;
|
||||||
|
|
||||||
|
HashSet<Thread> runningThreads = new();
|
||||||
|
while (CalcThreads.Count > 0)
|
||||||
|
{
|
||||||
|
while (runningThreads.Count < 16 && CalcThreads.Count > 0)
|
||||||
|
{
|
||||||
|
Thread t = CalcThreads.Dequeue();
|
||||||
|
runningThreads.Add(t);
|
||||||
|
t.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
int newCompleted = runningThreads.RemoveWhere(thread => !thread.IsAlive);
|
||||||
|
completed += newCompleted;
|
||||||
|
if(newCompleted > 0)
|
||||||
|
Console.WriteLine($"To calculate: {CalcThreads.Count}/{totalTasks} Average Time: {(DateTime.Now - startTime)/(completed)} Elapsed: {DateTime.Now - startTime} Remaining: {(DateTime.Now - startTime)/(completed)*CalcThreads.Count}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user