135 lines
4.5 KiB
C#
135 lines
4.5 KiB
C#
using System.Text.Json;
|
|
using OSMDatastructure;
|
|
using OSMDatastructure.Graph;
|
|
|
|
namespace Pathfinding
|
|
{
|
|
public class RegionManager
|
|
{
|
|
private string workingDirectory { get; }
|
|
private readonly Dictionary<ulong, Region> _regions = new();
|
|
|
|
public RegionManager(string workingDirectory)
|
|
{
|
|
this.workingDirectory = workingDirectory;
|
|
}
|
|
|
|
public Region? GetRegion(Coordinates coordinates)
|
|
{
|
|
return GetRegion(Coordinates.GetRegionHashCode(coordinates));
|
|
}
|
|
|
|
public Region? GetRegion(ulong id)
|
|
{
|
|
if(_regions.TryGetValue(id, out Region? value))
|
|
return value;
|
|
else
|
|
{
|
|
Region? loadedRegion = RegionFromId(id);
|
|
if(loadedRegion is not null)
|
|
_regions.Add(loadedRegion!.regionHash, value: loadedRegion);
|
|
return loadedRegion;
|
|
}
|
|
}
|
|
|
|
public Region[] GetAllRegions()
|
|
{
|
|
return this._regions.Values.ToArray();
|
|
}
|
|
|
|
private Region? RegionFromFile(string filePath)
|
|
{
|
|
Region? retRegion = null;
|
|
if (File.Exists(filePath))
|
|
{
|
|
FileStream regionFile = new FileStream(filePath, FileMode.Open);
|
|
retRegion = JsonSerializer.Deserialize<Region>(regionFile, Region.serializerOptions)!;
|
|
regionFile.Dispose();
|
|
}
|
|
return retRegion;
|
|
}
|
|
|
|
private Region? RegionFromId(ulong regionId)
|
|
{
|
|
string filePath = Path.Join(workingDirectory, $"{regionId}.region");
|
|
return RegionFromFile(filePath);
|
|
}
|
|
|
|
public OsmNode? GetNode(ulong nodeId, ulong regionId)
|
|
{
|
|
Region? r = GetRegion(regionId);
|
|
return r?.GetNode(nodeId);
|
|
}
|
|
|
|
public bool TestValidConnectionForType(OsmNode node1, OsmNode node2, Tag.SpeedType type)
|
|
{
|
|
foreach (OsmEdge edge in node1.edges)
|
|
{
|
|
if (edge.neighborId.Equals(node2.nodeId))
|
|
return TestValidConnectionForType(node1, edge, type);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool TestValidConnectionForType(OsmNode node1, OsmEdge edge, Tag.SpeedType type)
|
|
{
|
|
if (type == Tag.SpeedType.any)
|
|
return true;
|
|
byte speed = GetSpeedForEdge(node1, edge.wayId, type);
|
|
return (speed is not 0);
|
|
}
|
|
|
|
public OsmNode? ClosestNodeToCoordinates(Coordinates coordinates, Tag.SpeedType vehicle)
|
|
{
|
|
OsmNode? closest = null;
|
|
double distance = double.MaxValue;
|
|
Region? region = GetRegion(coordinates);
|
|
if (region is null)
|
|
return null;
|
|
foreach (OsmNode node in region.nodes)
|
|
{
|
|
bool hasConnectionUsingVehicle = true;
|
|
if (vehicle is not Tag.SpeedType.any)
|
|
{
|
|
hasConnectionUsingVehicle = false;
|
|
foreach (OsmEdge edge in node.edges)
|
|
{
|
|
if (TestValidConnectionForType(node, edge, vehicle))
|
|
hasConnectionUsingVehicle = true;
|
|
}
|
|
}
|
|
|
|
double nodeDistance = Utils.DistanceBetween(node, coordinates);
|
|
if (hasConnectionUsingVehicle && nodeDistance < distance)
|
|
{
|
|
closest = node;
|
|
distance = nodeDistance;
|
|
}
|
|
}
|
|
|
|
return closest;
|
|
}
|
|
|
|
public byte GetSpeedForEdge(OsmNode node1, ulong wayId, Tag.SpeedType vehicle)
|
|
{
|
|
TagManager tags = GetRegion(node1.coordinates)!.tagManager;
|
|
Tag.WayType wayType = (Tag.WayType)tags.GetTag(wayId, Tag.TagType.highway)!;
|
|
byte speed = 0;
|
|
switch (vehicle)
|
|
{
|
|
case Tag.SpeedType.pedestrian:
|
|
speed = Tag.defaultSpeedPedestrian[wayType];
|
|
return speed;
|
|
case Tag.SpeedType.car:
|
|
byte? maxSpeed = (byte?)tags.GetTag(wayId, Tag.TagType.maxspeed);
|
|
speed = Tag.defaultSpeedCar[wayType];
|
|
return maxSpeed < speed ? (byte)maxSpeed : speed;
|
|
case Tag.SpeedType.any:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
} |