< Summary

Class:Itinero.IO.Osm.Restrictions.OsmTurnRestrictionExtensions
Assembly:Itinero.IO.Osm
File(s):/home/runner/work/routing2/routing2/src/Itinero.IO.Osm/Restrictions/Turns/OsmTurnRestrictionExtensions.cs
Covered lines:115
Uncovered lines:95
Coverable lines:210
Total lines:342
Line coverage:54.7% (115 of 210)
Covered branches:56
Total branches:112
Branch coverage:50% (56 of 112)
Tag:224_14471318300

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
ToNetworkRestrictions(...)83.33%2476.08%
GetViaFrom(...)50%1466.66%
GetFromHops(...)87.5%885%
GetViaTo(...)64.28%1477.77%
GetToHops(...)50%860%
GetViaHops(...)21.42%1429.03%
GetFromHopEdge(...)30%1044.44%
GetViaHopEdges()0%100%
GetToHopEdge(...)30%1044.44%

File(s)

/home/runner/work/routing2/routing2/src/Itinero.IO.Osm/Restrictions/Turns/OsmTurnRestrictionExtensions.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Itinero.Network;
 5using OsmSharp;
 6
 7namespace Itinero.IO.Osm.Restrictions;
 8
 9public static class OsmTurnRestrictionExtensions
 10{
 11    /// <summary>
 12    /// The signature of a function to get edges for the given nodes pair along the given way.
 13    /// </summary>
 14    public delegate (EdgeId edge, bool forward)? GetEdgeFor(long wayId, int node1Idx, int node2Idx);
 15
 16    /// <summary>
 17    /// Converts the given OSM turn restriction into one or more sequences on the network.
 18    /// </summary>
 19    /// <param name="osmTurnRestriction">The OSM turn restriction.</param>
 20    /// <param name="getEdgeFor">A function to get edges for pairs of nodes for a given way.</param>
 21    /// <returns>The restriction using network edges and vertices.</returns>
 22    public static Result<IEnumerable<NetworkRestriction>> ToNetworkRestrictions(
 23        this OsmTurnRestriction osmTurnRestriction,
 24        GetEdgeFor getEdgeFor)
 125    {
 26        // get from edges.
 127        var fromEdges = new List<(EdgeId edge, bool forward)>();
 528        foreach (var hop in osmTurnRestriction.GetFromHops())
 129        {
 130            if (hop.IsError) continue;
 131            var (way, minStartNode, endNode) = hop.Value;
 32
 33            // get the from-hop from the two nodes and the way id.
 134            var edge = getEdgeFor.GetFromHopEdge(way.Id.Value, minStartNode, endNode);
 235            if (edge.HasValue) fromEdges.Add(edge.Value);
 136        }
 37
 138        if (fromEdges.Count == 0)
 039        {
 040            return new Result<IEnumerable<NetworkRestriction>>(
 041                "could not parse any part of the from-part of the restriction");
 42        }
 43
 44        // get to edges.
 145        var toEdges = new List<(EdgeId edge, bool forward)>();
 546        foreach (var hop in osmTurnRestriction.GetToHops())
 147        {
 148            if (hop.IsError) continue;
 149            var (way, startNode, maxEndNode) = hop.Value;
 50
 51            // get the from-hop from the two nodes and the way id.
 152            var edge = getEdgeFor.GetToHopEdge(way.Id.Value, startNode, maxEndNode);
 253            if (edge.HasValue) toEdges.Add(edge.Value);
 154        }
 55
 156        if (toEdges.Count == 0)
 057        {
 058            return new Result<IEnumerable<NetworkRestriction>>(
 059                "could not parse any part of the to-part of the restriction");
 60        }
 61
 62        // get the in between sequence.
 163        var viaEdges = new List<(EdgeId edgeId, bool forward)>();
 164        var viaSequences = osmTurnRestriction.GetViaHops();
 165        if (viaSequences.IsError) return viaSequences.ConvertError<IEnumerable<NetworkRestriction>>();
 366        foreach (var hop in viaSequences.Value)
 067        {
 068            var (way, startNode, endNode) = hop;
 69
 70            // get the from-hop from the two nodes and the way id.
 071            var edge = getEdgeFor.GetViaHopEdges(way.Id.Value, startNode, endNode);
 072            viaEdges.AddRange(edge);
 073        }
 74
 175        var networkRestrictions = new List<NetworkRestriction>();
 576        foreach (var fromEdge in fromEdges)
 577            foreach (var toEdge in toEdges)
 178            {
 179                var sequence = new List<(EdgeId edgeId, bool forward)> { fromEdge };
 180                sequence.AddRange(viaEdges);
 181                sequence.Add(toEdge);
 82
 183                networkRestrictions.Add(new NetworkRestriction(sequence, osmTurnRestriction.IsProbibitory,
 184                    osmTurnRestriction.Attributes));
 185            }
 86
 187        return networkRestrictions;
 188    }
 89
 90    /// <summary>
 91    /// Gets the node that connects the from ways to the via way(s) or nodes.
 92    /// </summary>
 93    /// <param name="osmTurnRestriction">The turn restriction.</param>
 94    /// <returns>The node where the from ways end.</returns>
 95    public static Result<long> GetViaFrom(this OsmTurnRestriction osmTurnRestriction)
 796    {
 97        // assume the restriction has a via-node like most of them.
 798        var node = osmTurnRestriction.ViaNodeId;
 1299        if (node != null) return node.Value;
 100
 101        // but some have via-ways, so get the node from the first via-way.
 2102        var viaWay = osmTurnRestriction.Via.FirstOrDefault();
 2103        if (viaWay == null) return new Result<long>("no via node or via way found");
 8104        foreach (var fromWay in osmTurnRestriction.From)
 2105        {
 2106            if (fromWay.Nodes[^1] == viaWay.Nodes[0] ||
 2107                fromWay.Nodes[^1] == viaWay.Nodes[^1])
 2108            {
 2109                return fromWay.Nodes[^1];
 110            }
 111
 0112            if (fromWay.Nodes[0] == viaWay.Nodes[0] ||
 0113                fromWay.Nodes[0] == viaWay.Nodes[^1])
 0114            {
 0115                return fromWay.Nodes[0];
 116            }
 0117        }
 118
 0119        return new Result<long>("no via node found to end the from ways");
 7120    }
 121
 122    /// <summary>
 123    /// Enumerates from ways and their nodes in the direction of the restricted sequence.
 124    /// </summary>
 125    /// <param name="osmTurnRestriction">The turn restriction.</param>
 126    /// <returns>The from ways and for each the start node index where the sequence starts at the earliest and the end n
 127    public static IEnumerable<Result<(Way way, int minStartNode, int endNode)>> GetFromHops(
 128        this OsmTurnRestriction osmTurnRestriction)
 3129    {
 3130        var node = osmTurnRestriction.GetViaFrom();
 131
 3132        var fromWayRestriction = new List<Result<(Way way, int minStartNode, int endNode)>>();
 15133        foreach (var fromWay in osmTurnRestriction.From)
 3134        {
 3135            if (node.IsError)
 0136            {
 0137                fromWayRestriction.Add(node.ConvertError<(Way way, int minStartNode, int endNode)>());
 0138                continue;
 139            }
 140
 3141            if (fromWay.Nodes[^1] == node)
 2142            {
 2143                fromWayRestriction.Add((fromWay, 0, fromWay.Nodes.Length - 1));
 2144                continue;
 145            }
 146
 1147            if (fromWay.Nodes[0] == node)
 1148            {
 1149                fromWayRestriction.Add((fromWay, fromWay.Nodes.Length - 1, 0));
 1150            }
 1151        }
 152
 3153        return fromWayRestriction;
 3154    }
 155
 156    /// <summary>
 157    /// Gets the node that connects the to ways to the via way(s) or nodes.
 158    /// </summary>
 159    /// <param name="osmTurnRestriction">The turn restriction.</param>
 160    /// <returns>The node where the to ways begin.</returns>
 161    public static Result<long> GetViaTo(this OsmTurnRestriction osmTurnRestriction)
 4162    {
 163        // assume the restriction has a via-node like most of them.
 4164        var node = osmTurnRestriction.ViaNodeId;
 6165        if (node != null) return node.Value;
 166
 167        // but some have via-ways, so get the node from the first via-way.
 2168        var viaWay = osmTurnRestriction.Via.FirstOrDefault();
 2169        if (viaWay == null) return new Result<long>("no via node or via way found");
 8170        foreach (var toWay in osmTurnRestriction.To)
 2171        {
 2172            if (toWay.Nodes[^1] == viaWay.Nodes[0] ||
 2173                toWay.Nodes[^1] == viaWay.Nodes[^1])
 0174            {
 0175                return toWay.Nodes[^1];
 176            }
 177
 2178            if (toWay.Nodes[0] == viaWay.Nodes[0] ||
 2179                toWay.Nodes[0] == viaWay.Nodes[^1])
 2180            {
 2181                return toWay.Nodes[0];
 182            }
 0183        }
 184
 0185        return new Result<long>("no via node found to start the to ways");
 4186    }
 187
 188    /// <summary>
 189    /// Enumerates to ways and their nodes in the direction of the restricted sequence.
 190    /// </summary>
 191    /// <param name="osmTurnRestriction">The turn restriction.</param>
 192    /// <returns>The to ways and for each the node where the to sequence starts and where it ends at the latest.</return
 193    public static IEnumerable<Result<(Way way, int startNode, int maxEndNode)>> GetToHops(
 194        this OsmTurnRestriction osmTurnRestriction)
 1195    {
 1196        var node = osmTurnRestriction.GetViaTo();
 197
 198        // assume the restriction has a via-node like most of them.
 1199        var toWayResults = new List<Result<(Way way, int startNode, int maxEndNode)>>();
 5200        foreach (var toWay in osmTurnRestriction.To)
 1201        {
 1202            if (node.IsError)
 0203            {
 0204                toWayResults.Add(node.ConvertError<(Way way, int startNode, int endNode)>());
 0205                continue;
 206            }
 207
 1208            if (toWay.Nodes[0] == node)
 1209            {
 1210                toWayResults.Add((toWay, 0, toWay.Nodes.Length - 1));
 1211                continue;
 212            }
 213
 0214            if (toWay.Nodes[^1] == node)
 0215            {
 0216                toWayResults.Add((toWay, toWay.Nodes.Length - 1, 0));
 0217            }
 0218        }
 219
 1220        return toWayResults;
 1221    }
 222
 223    /// <summary>
 224    /// Gets the via way segments.
 225    /// </summary>
 226    /// <param name="osmTurnRestriction">The OSM turn restrictions.</param>
 227    /// <returns>The ways and the two node indexes representing the via part.</returns>
 228    public static Result<IReadOnlyList<(Way via, int startNode, int endNode)>> GetViaHops(
 229        this OsmTurnRestriction osmTurnRestriction)
 1230    {
 1231        var node1 = osmTurnRestriction.GetViaFrom();
 1232        if (node1.IsError) return node1.ConvertError<IReadOnlyList<(Way via, int node1Idx, int node2Idx)>>();
 1233        var node2 = osmTurnRestriction.GetViaTo();
 1234        if (node2.IsError) return node2.ConvertError<IReadOnlyList<(Way via, int node1Idx, int node2Idx)>>();
 235
 1236        if (node1.Value == node2.Value)
 1237        {
 238            // the most default case, one via node.
 1239            return Array.Empty<(Way via, int node1Idx, int node2Idx)>();
 240        }
 241
 242        // there have to be via ways at this point.
 243        // it is assumed ways are split to follow along the sequence.
 0244        var currentNode = node1.Value;
 0245        var sequences = new List<(Way via, int node1Idx, int node2Idx)>();
 0246        foreach (var viaWay in osmTurnRestriction.Via)
 0247        {
 0248            if (viaWay.Nodes[0] == currentNode)
 0249            {
 0250                sequences.Add((viaWay, 0, viaWay.Nodes.Length - 1));
 0251                currentNode = viaWay.Nodes[^1];
 0252            }
 0253            else if (viaWay.Nodes[^1] == currentNode)
 0254            {
 0255                sequences.Add((viaWay, viaWay.Nodes.Length - 1, 0));
 0256                currentNode = viaWay.Nodes[0];
 0257            }
 258            else
 0259            {
 0260                return new Result<IReadOnlyList<(Way via, int startNode, int endNode)>>(
 0261                    "one of via ways does not fit in a sequence");
 262            }
 0263        }
 264
 0265        if (currentNode != node2)
 0266            return new Result<IReadOnlyList<(Way via, int startNode, int endNode)>>(
 0267                "last node of via sequence does not match");
 268
 0269        return sequences;
 1270    }
 271
 272    private static (EdgeId edge, bool forward)? GetFromHopEdge(this GetEdgeFor getEdgeFor, long wayId, int minStartNode,
 1273    {
 1274        if (minStartNode < endNode)
 1275        {
 2276            for (var n = endNode - 1; n >= minStartNode; n--)
 1277            {
 1278                var edge = getEdgeFor(wayId, n, endNode);
 2279                if (edge != null) return edge;
 0280            }
 0281        }
 282        else
 0283        {
 0284            for (var n = endNode + 1; n <= minStartNode; n++)
 0285            {
 0286                var edge = getEdgeFor(wayId, n, endNode);
 0287                if (edge != null) return edge;
 0288            }
 0289        }
 290
 0291        return null;
 1292    }
 293
 294    private static IEnumerable<(EdgeId edge, bool forward)> GetViaHopEdges(this GetEdgeFor getEdgeFor, long wayId,
 295        int startNode, int endNode)
 0296    {
 0297        if (startNode < endNode)
 0298        {
 0299            for (var n = startNode + 1; n <= endNode; n++)
 0300            {
 0301                var edge = getEdgeFor(wayId, startNode, n);
 0302                if (edge == null) continue;
 303
 0304                startNode = n;
 0305                yield return edge.Value;
 0306            }
 0307        }
 308        else
 0309        {
 0310            for (var n = startNode - 1; n >= endNode; n--)
 0311            {
 0312                var edge = getEdgeFor(wayId, startNode, n);
 0313                if (edge == null) continue;
 314
 0315                startNode = n;
 0316                yield return edge.Value;
 0317            }
 0318        }
 0319    }
 320
 321    private static (EdgeId edge, bool forward)? GetToHopEdge(this GetEdgeFor getEdgeFor, long wayId, int startNode, int 
 1322    {
 1323        if (startNode < maxEndNode)
 1324        {
 2325            for (var n = startNode + 1; n <= maxEndNode; n++)
 1326            {
 1327                var edge = getEdgeFor(wayId, startNode, n);
 2328                if (edge != null) return edge;
 0329            }
 0330        }
 331        else
 0332        {
 0333            for (var n = startNode - 1; n >= maxEndNode; n--)
 0334            {
 0335                var edge = getEdgeFor(wayId, startNode, n);
 0336                if (edge != null) return edge;
 0337            }
 0338        }
 339
 0340        return null;
 1341    }
 342}