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) { double speed = GetSpeedForEdge(node1, edge.wayId, type); if (speed != 0) return true; return false; } 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 = false; foreach (OsmEdge edge in node.edges) { double 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 double 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)!; switch (vehicle) { case Tag.SpeedType.pedestrian: byte speed = Tag.defaultSpeedPedestrian[wayType]; if (speed is not 0) return speed; return 0; case Tag.SpeedType.car: case Tag.SpeedType.road: byte? maxSpeed = (byte?)tags.GetTag(wayId, Tag.TagType.maxspeed); if (maxSpeed is not null) return (double)maxSpeed; maxSpeed = Tag.defaultSpeedCar[wayType]; if(maxSpeed is not 0) return (byte)maxSpeed; return 0; default: return 0; } } } }