using System.Text.Json; using OSMDatastructure; using OSMDatastructure.Graph; namespace Pathfinding { public class RegionManager { private string workingDirectory { get; } private readonly Dictionary _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(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) { byte speed = GetSpeedForEdge(node, edge.wayId, vehicle); if (speed != 0) hasConnectionUsingVehicle = true; } } double nodeDistance = Utils.DistanceBetween(node, coordinates); if (nodeDistance < distance && hasConnectionUsingVehicle) { 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 is not 0 ? speed : (byte)0; 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; } } } }