< Summary

Class:Itinero.Routes.Paths.Path
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Routes/Paths/Path.cs
Covered lines:70
Uncovered lines:80
Coverable lines:150
Total lines:283
Line coverage:46.6% (70 of 150)
Covered branches:20
Total branches:56
Branch coverage:35.7% (20 of 56)
Tag:224_14471318300

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
.ctor(...)100%10%
get_RoutingNetwork()100%10%
get_Offset1()100%1100%
get_Offset2()100%1100%
get_First()100%1100%
get_Last()100%1100%
RemoveFirst()50%271.42%
RemoveLast()50%271.42%
get_Count()100%1100%
Append(...)60%1092.85%
Prepend(...)60%1092.85%
Clone()100%10%
AppendInternal(...)100%1100%
PrependInternal(...)100%1100%
GetEnumerator()100%6100%
System.Collections.IEnumerable.GetEnumerator()100%10%
ToString()0%260%

File(s)

/home/runner/work/routing2/routing2/src/Itinero/Routes/Paths/Path.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Text;
 5using Itinero.Network;
 6using Itinero.Network.Enumerators.Edges;
 7
 8namespace Itinero.Routes.Paths;
 9
 10/// <summary>
 11/// Represents a path in a graph as a collection of edges.
 12/// </summary>
 13public sealed class Path : IEnumerable<(EdgeId edge, bool forward, ushort offset1, ushort offset2)>
 14{
 15    private readonly List<(EdgeId edge, bool forward)> _edges;
 16    private readonly RoutingNetworkEdgeEnumerator _edgeEnumerator;
 17    private readonly RoutingNetwork _network;
 18
 6119    public Path(RoutingNetwork network)
 6120    {
 6121        _network = network;
 6122        _edgeEnumerator = network.GetEdgeEnumerator();
 23
 6124        _edges = new List<(EdgeId edge, bool forward)>();
 6125    }
 26
 027    internal Path(Path pathToClone)
 028    {
 029        _network = pathToClone._network;
 030        _edgeEnumerator = _network.GetEdgeEnumerator();
 31
 032        _edges = new List<(EdgeId edge, bool forward)>(pathToClone._edges);
 33
 034        this.Offset1 = pathToClone.Offset1;
 035        this.Offset2 = pathToClone.Offset2;
 036    }
 37
 38    /// <summary>
 39    /// Gets the network.
 40    /// </summary>
 041    public RoutingNetwork RoutingNetwork => _network;
 42
 43    /// <summary>
 44    /// Gets the offset at the start of the path.
 45    /// </summary>
 46    /// <remarks>
 47    /// This is independent of the the direction of the first edge:
 48    /// - 0   : means the edge is fully included.
 49    /// - max : means the edge is not included.
 50    /// </remarks>
 22251    public ushort Offset1 { get; set; } = 0;
 52
 53    /// <summary>
 54    /// Gets the offset at the end of the path, relative to the direction of the edge.
 55    /// </summary>
 56    /// <remarks>
 57    /// This is independent of the the direction of the last edge:
 58    /// - 0   : means the edge is not included.
 59    /// - max : means the edge is fully included.
 60    /// </remarks>
 22161    public ushort Offset2 { get; set; } = ushort.MaxValue;
 62
 63    /// <summary>
 64    /// Gets the first edge.
 65    /// </summary>
 4466    public (EdgeId edge, bool direction) First => _edges[0];
 67
 68    /// <summary>
 69    /// Gets the last edge.
 70    /// </summary>
 4071    public (EdgeId edge, bool direction) Last => _edges[this.Count - 1];
 72
 73    /// <summary>
 74    /// Remove the first edge.
 75    /// </summary>
 76    /// <exception cref="InvalidOperationException"></exception>
 77    public void RemoveFirst()
 478    {
 479        if (_edges.Count == 0)
 080        {
 081            throw new InvalidOperationException("Cannot remove first from an already empty path.");
 82        }
 83
 484        _edges.RemoveAt(0);
 485        this.Offset1 = 0;
 486    }
 87
 88    /// <summary>
 89    /// Remove the last edge.
 90    /// </summary>
 91    /// <exception cref="InvalidOperationException"></exception>
 92    public void RemoveLast()
 493    {
 494        if (_edges.Count == 0)
 095        {
 096            throw new InvalidOperationException("Cannot remove last from an already empty path.");
 97        }
 98
 499        _edges.RemoveAt(_edges.Count - 1);
 4100        this.Offset2 = ushort.MaxValue;
 4101    }
 102
 103    /// <summary>
 104    /// Returns the number of edges.
 105    /// </summary>
 413106    public int Count => _edges.Count;
 107
 108    /// <summary>
 109    /// Appends the given edge and calculates the proper direction.
 110    /// </summary>
 111    /// <param name="edge">The edge.</param>
 112    /// <param name="forward">The direction of the edge.</param>
 113    public void Append(EdgeId edge, bool forward)
 33114    {
 33115        if (!_edgeEnumerator.MoveTo(edge, forward)) throw new Exception($"Edge does not exist.");
 116
 117#if DEBUG
 33118        if (_edges.Count > 0)
 13119        {
 13120            var edgeEnumerator = _network.GetEdgeEnumerator();
 13121            if (!edgeEnumerator.MoveTo(edge, forward)) throw new Exception($"Edge does not exist.");
 13122            var tail = edgeEnumerator.Tail;
 13123            var previous = _edges[^1];
 26124            if (!edgeEnumerator.MoveTo(previous.edge, previous.forward)) throw new Exception($"Edge does not exist."); ;
 13125            if (edgeEnumerator.Head != tail)
 0126                throw new Exception("Cannot append edge, previous edge head does not match tail");
 13127        }
 128#endif
 129
 33130        this.AppendInternal(edge, forward);
 33131    }
 132
 133    /// <summary>
 134    /// Prepends the given edge and calculates the proper direction.
 135    /// </summary>
 136    /// <param name="edge">The edge.</param>
 137    /// <param name="forward">The direction of the edge.</param>
 138    public void Prepend(EdgeId edge, bool forward)
 76139    {
 76140        if (!_edgeEnumerator.MoveTo(edge, forward)) throw new Exception($"Edge does not exist.");
 141
 142#if DEBUG
 76143        if (_edges.Count > 0)
 36144        {
 36145            var edgeEnumerator = _network.GetEdgeEnumerator();
 36146            if (!edgeEnumerator.MoveTo(edge, forward)) throw new Exception($"Edge does not exist.");
 36147            var head = edgeEnumerator.Head;
 36148            var next = _edges[0];
 36149            if (!edgeEnumerator.MoveTo(next.edge, next.forward)) throw new Exception($"Edge does not exist.");
 36150            if (edgeEnumerator.Tail != head)
 0151                throw new Exception("Cannot append edge, next edge tail does not match head");
 36152        }
 153#endif
 154
 76155        this.PrependInternal(edge, forward);
 76156    }
 157
 158    /// <summary>
 159    /// Returns a copy of this path.
 160    /// </summary>
 161    /// <returns>A copy.</returns>
 162    public Path Clone()
 0163    {
 0164        return new Path(this);
 0165    }
 166
 167    internal void AppendInternal(EdgeId edge, bool forward)
 33168    {
 33169        _edges.Add((edge, forward));
 33170    }
 171
 172    internal void PrependInternal(EdgeId edge, bool forward)
 76173    {
 76174        _edges.Insert(0, (edge, forward));
 76175    }
 176
 177    public IEnumerator<(EdgeId edge, bool forward, ushort offset1, ushort offset2)> GetEnumerator()
 78178    {
 400179        for (var i = 0; i < this.Count; i++)
 125180        {
 125181            var edge = _edges[i];
 125182            var offset1 = (ushort)0;
 125183            var offset2 = ushort.MaxValue;
 184
 125185            if (i == 0)
 78186            {
 78187                offset1 = this.Offset1;
 78188            }
 189
 125190            if (i == this.Count - 1)
 78191            {
 78192                offset2 = this.Offset2;
 78193            }
 194
 125195            yield return (edge.edge, edge.forward, offset1, offset2);
 122196        }
 75197    }
 198
 199    IEnumerator IEnumerable.GetEnumerator()
 0200    {
 0201        return this.GetEnumerator();
 0202    }
 203
 204    /// <summary>
 205    /// Returns a description of this path.
 206    /// </summary>
 207    public override string ToString()
 0208    {
 209        // 1 edge without offsets:         [0]->21543F->[4]
 210        // 1 edge with offsets:            [0]->10%-21543F-20%->[4]
 0211        var builder = new StringBuilder();
 212
 0213        if (_edges.Count > 0)
 0214        { // there is a first edge.
 0215            var first = _edges[0];
 0216            _edgeEnumerator.MoveTo(first.edge, first.forward);
 0217            builder.Append($"[{_edgeEnumerator.Tail}]");
 0218            builder.Append("->");
 0219            if (this.Offset1 != 0)
 0220            {
 0221                builder.Append(OffsetPer(this.Offset1));
 0222                builder.Append("-");
 0223            }
 224
 0225            builder.Append($"{first.edge}");
 0226            builder.Append(first.forward ? "F" : "B");
 227
 0228            if (_edges.Count == 1)
 0229            {
 0230                if ((first.forward && this.Offset2 != ushort.MaxValue) ||
 0231                    (!first.forward && this.Offset2 != 0))
 0232                {
 0233                    builder.Append("-");
 0234                    builder.Append(OffsetPer(this.Offset2));
 0235                }
 236
 0237                builder.Append("->");
 0238                builder.Append($"[{_edgeEnumerator.Head}]");
 0239                return builder.ToString();
 240            }
 241
 0242            builder.Append("->");
 0243            builder.Append($"[{_edgeEnumerator.Head}]");
 0244        }
 245
 0246        for (var e = 1; e < _edges.Count - 1; e++)
 0247        {
 0248            var edgeAndDirection = _edges[e];
 0249            _edgeEnumerator.MoveTo(edgeAndDirection.edge, edgeAndDirection.forward);
 0250            builder.Append("->");
 0251            builder.Append($"{edgeAndDirection.edge}");
 0252            builder.Append(edgeAndDirection.forward ? "F" : "B");
 0253            builder.Append("->");
 0254            builder.Append($"[{_edgeEnumerator.Head}]");
 0255        }
 256
 0257        if (_edges.Count > 0)
 0258        { // there is a last edge.
 0259            var last = _edges[^1];
 0260            builder.Append("->");
 0261            builder.Append($"{last.edge}");
 0262            builder.Append(last.forward ? "F" : "B");
 0263            if (this.Offset2 != ushort.MaxValue)
 0264            {
 0265                builder.Append("-");
 0266                builder.Append(OffsetPer(this.Offset2));
 0267            }
 268
 0269            _edgeEnumerator.MoveTo(last.edge, last.forward);
 0270            builder.Append("->");
 0271            builder.Append($"[{_edgeEnumerator.Head}]");
 0272            return builder.ToString();
 273        }
 274
 0275        return builder.ToString();
 276
 277        // Declare a local function.
 278        static string OffsetPer(ushort offset)
 0279        {
 0280            return $"{(double)offset / ushort.MaxValue * 100:F1}%";
 0281        }
 0282    }
 283}