< Summary

Class:Itinero.Network.Tiles.Standalone.Global.GlobalRestrictionExtensions
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/Standalone/Global/GlobalRestrictionExtensions.cs
Covered lines:35
Uncovered lines:0
Coverable lines:35
Total lines:103
Line coverage:100% (35 of 35)
Covered branches:19
Total branches:20
Branch coverage:95% (19 of 20)
Tag:263_26948838820

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
TryBuildNetworkRestriction(...)100%4100%
WalkFromAnchor(...)93.75%16100%

File(s)

/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/Standalone/Global/GlobalRestrictionExtensions.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Diagnostics.CodeAnalysis;
 4
 5namespace Itinero.Network.Tiles.Standalone.Global;
 6
 7public static class GlobalRestrictionExtensions
 8{
 9    /// <summary>
 10    /// Tries to build a network restriction from a global restriction.
 11    /// </summary>
 12    /// <remarks>
 13    /// Should always succeed if all edges are available but can fail if the data
 14    /// available is a tile and does not contain all edges yet.
 15    /// </remarks>
 16    /// <param name="globalNetworkRestriction">The global network restriction.</param>
 17    /// <param name="getEdge">
 18    /// Resolves a chain edge. The bool argument is <c>true</c> for the first edge
 19    /// in the chain (anchor with the next edge is at the geid's <see cref="GlobalEdgeId.Head"/>),
 20    /// <c>false</c> for any subsequent edge (anchor with the previous edge is at
 21    /// the geid's <see cref="GlobalEdgeId.Tail"/>). The chain-connectivity invariant
 22    /// emitted by the OSM converters is <c>previous.Head == current.Tail</c> at
 23    /// the same OSM node, so the anchor end is unambiguous from chain position.
 24    /// </param>
 25    /// <param name="networkRestriction">The resulting network restriction, if any.</param>
 26    /// <returns>True if success, false otherwise.</returns>
 27    public static bool TryBuildNetworkRestriction(this GlobalRestriction globalNetworkRestriction,
 28        Func<GlobalEdgeId, bool, (EdgeId edge, bool forward)?> getEdge,
 29        [MaybeNullWhen(false)] out NetworkRestriction? networkRestriction)
 482230    {
 482231        networkRestriction = null;
 32
 482233        var edges = new List<(EdgeId edge, bool forward)>();
 2884234        for (var i = 0; i < globalNetworkRestriction.Count; i++)
 962935        {
 962936            var globalId = globalNetworkRestriction[i];
 962937            var isFirst = i == 0;
 38
 962939            var e = getEdge(globalId, isFirst);
 965940            if (e == null) return false;
 41
 959942            edges.Add(e.Value);
 959943        }
 44
 479245        networkRestriction = new NetworkRestriction(edges, globalNetworkRestriction.IsProhibitory,
 479246            globalNetworkRestriction.Attributes);
 479247        return true;
 482248    }
 49
 50    /// <summary>
 51    /// Walks from the chain-anchor end of <paramref name="geid"/> toward the far end,
 52    /// returning the first sub-edge in the index whose endpoint matches the anchor.
 53    /// </summary>
 54    /// <remarks>
 55    /// Given the OSM converters' invariant that <c>previous.Head == current.Tail</c>
 56    /// at the shared via node, the anchor end is determined by chain position:
 57    /// the first edge anchors at <see cref="GlobalEdgeId.Head"/>, every subsequent
 58    /// edge anchors at <see cref="GlobalEdgeId.Tail"/>. The walk steps one sub-index
 59    /// at a time, trying both the canonical and inverted lookups; the returned
 60    /// <c>forward</c> reflects whether the matched stored edge runs in the chain's
 61    /// traversal direction (Tail → Head of <paramref name="geid"/>).
 62    /// </remarks>
 63    public static (EdgeId edge, bool forward)? WalkFromAnchor(GlobalEdgeId geid, bool isFirst,
 64        TryGetEdgeId tryGet)
 468165    {
 468166        var anchor = isFirst ? geid.Head : geid.Tail;
 468167        var farEnd = isFirst ? geid.Tail : geid.Head;
 468168        if (anchor == farEnd) return null;
 69
 70        // chainGoesAnchorToFar: chain enters the edge at the anchor and exits at far.
 71        // True when anchor == geid.Tail (i.e. not the first edge).
 468172        var chainGoesAnchorToFar = !isFirst;
 73
 468174        var step = farEnd > anchor ? 1 : -1;
 468175        for (int otherIdx = anchor + step;
 785176             step > 0 ? otherIdx <= farEnd : otherIdx >= farEnd;
 317077             otherIdx += step)
 780778        {
 780779            var sub = GlobalEdgeId.Create(geid.EdgeId, (ushort)anchor, (ushort)otherIdx);
 780780            if (tryGet(sub, out var eId))
 231181            {
 82                // canonical direction is anchor → otherIdx (toward far). Forward
 83                // matches when chain also goes anchor → far.
 231184                return (eId, chainGoesAnchorToFar);
 85            }
 549686            if (tryGet(sub.GetInverted(), out eId))
 232687            {
 88                // canonical direction is otherIdx → anchor (toward anchor).
 89                // Forward matches when chain goes far → anchor.
 232690                return (eId, !chainGoesAnchorToFar);
 91            }
 317092        }
 93
 4494        return null;
 468195    }
 96
 97    /// <summary>
 98    /// Lookup callback for <see cref="WalkFromAnchor"/>: returns whether the
 99    /// given <see cref="GlobalEdgeId"/> is registered and what
 100    /// <see cref="EdgeId"/> it maps to.
 101    /// </summary>
 102    public delegate bool TryGetEdgeId(GlobalEdgeId geid, out EdgeId edgeId);
 103}