| | | 1 | | using System; |
| | | 2 | | using System.Collections.Generic; |
| | | 3 | | using System.Linq; |
| | | 4 | | using Itinero.Network.Tiles.Standalone.Global; |
| | | 5 | | |
| | | 6 | | namespace Itinero.IO.Osm.Restrictions.Turns; |
| | | 7 | | |
| | | 8 | | public static class OsmTurnRestrictionExtensions |
| | | 9 | | { |
| | | 10 | | /// <summary> |
| | | 11 | | /// Converts the given OSM turn restriction into one or more sequences on the network. |
| | | 12 | | /// </summary> |
| | | 13 | | /// <param name="osmTurnRestriction">The OSM turn restriction.</param> |
| | | 14 | | /// <returns>The restriction using network edges and vertices.</returns> |
| | | 15 | | public static IEnumerable<GlobalRestriction> ToGlobalNetworkRestrictions(this OsmTurnRestriction osmTurnRestriction) |
| | 69 | 16 | | { |
| | 69 | 17 | | var viaSequences = osmTurnRestriction.GetViaHops(); |
| | 69 | 18 | | if (viaSequences == null) yield break; |
| | | 19 | | |
| | 319 | 20 | | foreach (var tailEdge in osmTurnRestriction.GetTailHops()) |
| | 282 | 21 | | foreach (var headEdge in osmTurnRestriction.GetHeadHops()) |
| | 57 | 22 | | { |
| | 57 | 23 | | IEnumerable<GlobalEdgeId> edges = [tailEdge]; |
| | 57 | 24 | | edges = edges.Concat(viaSequences).Concat([headEdge]); |
| | | 25 | | |
| | 57 | 26 | | yield return new GlobalRestriction(edges, |
| | 57 | 27 | | osmTurnRestriction.IsProbibitory, osmTurnRestriction.Attributes); |
| | 57 | 28 | | } |
| | 69 | 29 | | } |
| | | 30 | | |
| | | 31 | | private static long? GetViaTail(this OsmTurnRestriction osmTurnRestriction) |
| | 138 | 32 | | { |
| | | 33 | | // assume the restriction has a via-node like most of them. |
| | 138 | 34 | | var node = osmTurnRestriction.ViaNodeId; |
| | 272 | 35 | | if (node != null) return node.Value; |
| | | 36 | | |
| | | 37 | | // but some have via-ways, so get the node from the first via-way. |
| | 4 | 38 | | var viaWay = osmTurnRestriction.Via.FirstOrDefault(); |
| | 4 | 39 | | if (viaWay == null) return null; |
| | 16 | 40 | | foreach (var fromWay in osmTurnRestriction.From) |
| | 4 | 41 | | { |
| | 4 | 42 | | if (fromWay.Nodes[^1] == viaWay.Nodes[0] || |
| | 4 | 43 | | fromWay.Nodes[^1] == viaWay.Nodes[^1]) |
| | 4 | 44 | | { |
| | 4 | 45 | | return fromWay.Nodes[^1]; |
| | | 46 | | } |
| | | 47 | | |
| | 0 | 48 | | if (fromWay.Nodes[0] == viaWay.Nodes[0] || |
| | 0 | 49 | | fromWay.Nodes[0] == viaWay.Nodes[^1]) |
| | 0 | 50 | | { |
| | 0 | 51 | | return fromWay.Nodes[0]; |
| | | 52 | | } |
| | 0 | 53 | | } |
| | | 54 | | |
| | | 55 | | // not cool, probably restriction not mapped correctly. |
| | 0 | 56 | | return null; |
| | 138 | 57 | | } |
| | | 58 | | |
| | | 59 | | private static IEnumerable<GlobalEdgeId> GetTailHops( |
| | | 60 | | this OsmTurnRestriction osmTurnRestriction) |
| | 69 | 61 | | { |
| | 69 | 62 | | var node = osmTurnRestriction.GetViaTail(); |
| | 69 | 63 | | if (node == null) yield break; |
| | | 64 | | |
| | 319 | 65 | | foreach (var fromWay in osmTurnRestriction.From) |
| | 56 | 66 | | { |
| | 56 | 67 | | if (fromWay.Nodes[^1] == node) |
| | 55 | 68 | | { |
| | 55 | 69 | | yield return GlobalEdgeId.Create(fromWay.Id!.Value, 0, fromWay.Nodes.Length - 1); |
| | 55 | 70 | | continue; |
| | | 71 | | } |
| | | 72 | | |
| | 1 | 73 | | if (fromWay.Nodes[0] == node) |
| | 1 | 74 | | { |
| | 1 | 75 | | yield return GlobalEdgeId.Create(fromWay.Id!.Value, fromWay.Nodes.Length - 1, 0); |
| | 1 | 76 | | } |
| | 1 | 77 | | } |
| | 69 | 78 | | } |
| | | 79 | | |
| | | 80 | | private static long? GetViaHead(this OsmTurnRestriction osmTurnRestriction) |
| | 125 | 81 | | { |
| | | 82 | | // assume the restriction has a via-node like most of them. |
| | 125 | 83 | | var node = osmTurnRestriction.ViaNodeId; |
| | 246 | 84 | | if (node != null) return node.Value; |
| | | 85 | | |
| | | 86 | | // but some have via-ways, so get the node from the first via-way. |
| | 4 | 87 | | var viaWay = osmTurnRestriction.Via.FirstOrDefault(); |
| | 4 | 88 | | if (viaWay == null) return null; |
| | 16 | 89 | | foreach (var toWay in osmTurnRestriction.To) |
| | 4 | 90 | | { |
| | 4 | 91 | | if (toWay.Nodes[^1] == viaWay.Nodes[0] || |
| | 4 | 92 | | toWay.Nodes[^1] == viaWay.Nodes[^1]) |
| | 0 | 93 | | { |
| | 0 | 94 | | return toWay.Nodes[^1]; |
| | | 95 | | } |
| | | 96 | | |
| | 4 | 97 | | if (toWay.Nodes[0] == viaWay.Nodes[0] || |
| | 4 | 98 | | toWay.Nodes[0] == viaWay.Nodes[^1]) |
| | 4 | 99 | | { |
| | 4 | 100 | | return toWay.Nodes[0]; |
| | | 101 | | } |
| | 0 | 102 | | } |
| | | 103 | | |
| | 0 | 104 | | return null; |
| | 125 | 105 | | } |
| | | 106 | | |
| | | 107 | | private static IEnumerable<GlobalEdgeId> GetHeadHops( |
| | | 108 | | this OsmTurnRestriction osmTurnRestriction) |
| | 56 | 109 | | { |
| | 56 | 110 | | var node = osmTurnRestriction.GetViaHead(); |
| | 56 | 111 | | if (node == null) yield break; |
| | | 112 | | |
| | | 113 | | // assume the restriction has a via-node like most of them. |
| | 282 | 114 | | foreach (var toWay in osmTurnRestriction.To) |
| | 57 | 115 | | { |
| | 57 | 116 | | if (toWay.Nodes[0] == node) |
| | 42 | 117 | | { |
| | 42 | 118 | | yield return GlobalEdgeId.Create(toWay.Id!.Value, 0, toWay.Nodes.Length - 1); |
| | 42 | 119 | | continue; |
| | | 120 | | } |
| | | 121 | | |
| | 15 | 122 | | if (toWay.Nodes[^1] == node) |
| | 15 | 123 | | { |
| | 15 | 124 | | yield return GlobalEdgeId.Create(toWay.Id!.Value, toWay.Nodes.Length - 1, 0); |
| | 15 | 125 | | } |
| | 15 | 126 | | } |
| | 56 | 127 | | } |
| | | 128 | | |
| | | 129 | | private static IReadOnlyList<GlobalEdgeId>? GetViaHops( |
| | | 130 | | this OsmTurnRestriction osmTurnRestriction) |
| | 69 | 131 | | { |
| | 69 | 132 | | var tailNode = osmTurnRestriction.GetViaTail(); |
| | 69 | 133 | | if (tailNode == null) return null; |
| | 69 | 134 | | var headNode = osmTurnRestriction.GetViaHead(); |
| | 69 | 135 | | if (headNode == null) return null; |
| | | 136 | | |
| | | 137 | | // via is a node if true. |
| | 136 | 138 | | if (tailNode.Value == headNode.Value) return ArraySegment<GlobalEdgeId>.Empty; |
| | | 139 | | |
| | | 140 | | // there have to be via ways at this point. |
| | | 141 | | // it is assumed ways are split to follow along the sequence. |
| | 2 | 142 | | var currentNode = tailNode.Value; |
| | 2 | 143 | | var edges = new List<GlobalEdgeId>(); |
| | 10 | 144 | | foreach (var viaWay in osmTurnRestriction.Via) |
| | 2 | 145 | | { |
| | 2 | 146 | | if (viaWay.Nodes[0] == currentNode) |
| | 1 | 147 | | { |
| | 1 | 148 | | edges.Add(GlobalEdgeId.Create(viaWay.Id!.Value, 0, viaWay.Nodes.Length - 1)); |
| | 1 | 149 | | currentNode = viaWay.Nodes[^1]; |
| | 1 | 150 | | } |
| | 1 | 151 | | else if (viaWay.Nodes[^1] == currentNode) |
| | 1 | 152 | | { |
| | 1 | 153 | | edges.Add(GlobalEdgeId.Create(viaWay.Id!.Value, viaWay.Nodes.Length - 1, 0)); |
| | 1 | 154 | | currentNode = viaWay.Nodes[0]; |
| | 1 | 155 | | } |
| | | 156 | | else |
| | 0 | 157 | | { |
| | 0 | 158 | | return null; |
| | | 159 | | } |
| | 2 | 160 | | } |
| | | 161 | | |
| | 2 | 162 | | if (currentNode != headNode) |
| | 0 | 163 | | return null; |
| | | 164 | | |
| | 2 | 165 | | return edges; |
| | 69 | 166 | | } |
| | | 167 | | } |