namespace OSMDatastructure; public class OsmEdge { public Coordinates neighborCoordinates { get; } public readonly Dictionary tags = new(); public OsmEdge(float lat, float lon) { this.neighborCoordinates = new Coordinates(lat, lon); this.tags = new(); } public OsmEdge(Coordinates neighborCoordinates) { this.neighborCoordinates = neighborCoordinates; this.tags = new(); } public OsmEdge(float lat, float lon, Dictionary tags) { this.neighborCoordinates = new Coordinates(lat, lon); //To prevent "EMPTY" tags foreach (KeyValuePair tag in tags) { if(tag.Key != tagType.EMPTY) this.tags.Add(tag.Key, tag.Value); } } public OsmEdge(Coordinates neighborCoordinates, Dictionary tags) { this.neighborCoordinates = neighborCoordinates; //To prevent "EMPTY" tags foreach (KeyValuePair tag in tags) { if(tag.Key != tagType.EMPTY) this.tags.Add(tag.Key, tag.Value); } } public enum tagType : byte { highway, oneway, footway, sidewalk, cycleway, busway, forward, maxspeed, name, surface, lanes, access, tracktype, id, EMPTY } private static readonly Dictionary defaultSpeedCar = new() { { wayType.NONE, 0 }, { wayType.motorway, 110 }, { wayType.trunk, 100 }, { wayType.primary, 80 }, { wayType.secondary, 80 }, { wayType.tertiary, 70 }, { wayType.unclassified, 20 }, { wayType.residential, 10 }, { wayType.motorway_link, 50 }, { wayType.trunk_link, 50 }, { wayType.primary_link, 30 }, { wayType.secondary_link, 25 }, { wayType.tertiary_link, 25 }, { wayType.living_street, 10 }, { wayType.service, 0 }, { wayType.pedestrian, 0 }, { wayType.track, 0 }, { wayType.bus_guideway, 0 }, { wayType.escape, 0 }, { wayType.raceway, 0 }, { wayType.road, 25 }, { wayType.busway, 0 }, { wayType.footway, 0 }, { wayType.bridleway, 0 }, { wayType.steps, 0 }, { wayType.corridor, 0 }, { wayType.path, 0 }, { wayType.cycleway, 0 }, { wayType.construction, 0 } }; private static readonly Dictionary defaultSpeedPedestrian = new() { { wayType.NONE, 0 }, { wayType.motorway, 0 }, { wayType.trunk, 0 }, { wayType.primary, 0 }, { wayType.secondary, 0 }, { wayType.tertiary, 0 }, { wayType.unclassified, 1 }, { wayType.residential, 3 }, { wayType.motorway_link, 0 }, { wayType.trunk_link, 0 }, { wayType.primary_link, 0 }, { wayType.secondary_link, 0 }, { wayType.tertiary_link, 0 }, { wayType.living_street, 5 }, { wayType.service, 2 }, { wayType.pedestrian, 5 }, { wayType.track, 0 }, { wayType.bus_guideway, 0 }, { wayType.escape, 0 }, { wayType.raceway, 0 }, { wayType.road, 3 }, { wayType.busway, 0 }, { wayType.footway, 4 }, { wayType.bridleway, 1 }, { wayType.steps, 2 }, { wayType.corridor, 3 }, { wayType.path, 4 }, { wayType.cycleway, 2 }, { wayType.construction, 0 } }; public enum wayType : byte { NONE, motorway, trunk, primary, secondary, tertiary, unclassified, residential, motorway_link, trunk_link, primary_link, secondary_link, tertiary_link, living_street, service, pedestrian, track, bus_guideway, escape, raceway, road, busway, footway, bridleway, steps, corridor, path, cycleway, construction } public enum speedType { pedestrian, car, road } public void AddTag(string key, string value) { KeyValuePair tag = ConvertToTag(key, value); if(tag.Key != tagType.EMPTY) tags.Add(tag.Key, tag.Value); } public static KeyValuePair ConvertToTag(string key, string value) { switch (key) { case "highway": try { return new KeyValuePair(tagType.highway, (wayType)Enum.Parse(typeof(wayType), value, true)); } catch (ArgumentException) { return new KeyValuePair(tagType.highway, wayType.unclassified); } case "maxspeed": try { byte speed = Convert.ToByte(value); if(speed == 255) return new KeyValuePair(tagType.EMPTY, 0); else return new KeyValuePair(tagType.maxspeed, speed); } catch (Exception) { //Console.WriteLine(e); //Console.WriteLine("Continuing..."); return new KeyValuePair(tagType.maxspeed, byte.MaxValue); } case "oneway": switch (value) { case "yes": return new KeyValuePair(tagType.oneway, true); case "-1": return new KeyValuePair(tagType.forward, false); case "no": return new KeyValuePair(tagType.oneway, false); } break; case "id": return new KeyValuePair(tagType.id, Convert.ToUInt64(value)); } return new KeyValuePair(tagType.EMPTY, 0); } public ulong GetId() { return tags.ContainsKey(tagType.id) ? (ulong)tags[tagType.id] : 0; } public wayType GetHighwayType() { if (!tags.ContainsKey(tagType.highway)) throw new Exception("Not a road?"); return (wayType)tags[tagType.highway]; } public bool IsOneWay() { return tags.ContainsKey(tagType.oneway) && (bool)tags[tagType.oneway]; } public byte GetMaxSpeed(speedType type) { switch (type) { case speedType.road: return tags.ContainsKey(tagType.maxspeed) ? (byte)tags[tagType.maxspeed] : (byte)0; case speedType.car: return tags.ContainsKey(tagType.maxspeed) ? (byte)tags[tagType.maxspeed] : defaultSpeedCar[GetHighwayType()]; case speedType.pedestrian: return defaultSpeedPedestrian[GetHighwayType()]; default: return 0; } } public bool IsForward() { return this.tags.ContainsKey(tagType.forward) && (bool)this.tags[tagType.forward]; } public double GetWeight(OsmNode parentNode, speedType vehicle) { double distance = Utils.DistanceBetween(parentNode, neighborCoordinates); byte speedByte = GetMaxSpeed(vehicle); if (speedByte > 0) { double speed = Convert.ToDouble(speedByte); return distance / speed; } else { return double.MaxValue; } } public override string ToString() { string tagsString = ""; foreach (KeyValuePair tag in tags) { tagsString += string.Format("\n\t{0}: {1}", tag.Key, tag.Value); } return string.Format("EDGE neighborCoordinates: {0} {1}", neighborCoordinates.ToString(), tagsString); } }