< Summary

Class:Itinero.Routes.Paths.PathExtensions
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Routes/Paths/PathExtensions.cs
Covered lines:37
Uncovered lines:106
Coverable lines:143
Total lines:259
Line coverage:25.8% (37 of 143)
Covered branches:17
Total branches:72
Branch coverage:23.6% (17 of 72)
Tag:232_15462506344

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
Weight(...)0%20%
Weight(...)0%80%
LengthInMeters(...)0%80%
IsNext(...)0%80%
Merge(...)100%10%
<Merge()0%60%
Merge(...)0%200%
Append(...)75%488.88%
Trim(...)100%8100%
HasLength(...)0%20%
InvertDirection()100%6100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using Itinero.Network;
 5using Itinero.Network.Enumerators.Edges;
 6
 7namespace Itinero.Routes.Paths;
 8
 9/// <summary>
 10/// Extensions for path.
 11/// </summary>
 12public static class PathExtensions
 13{
 14    /// <summary>
 15    /// Calculates the weight of the path given the weight function.
 16    /// </summary>
 17    /// <param name="path">The path.</param>
 18    /// <param name="getWeight">The weight function.</param>
 19    /// <returns>The total weight.</returns>
 20    public static double? Weight(this Result<Path> path, Func<RoutingNetworkEdgeEnumerator, double> getWeight)
 021    {
 022        if (path.IsError)
 023        {
 024            return null;
 25        }
 26
 027        return path.Value.Weight(getWeight);
 028    }
 29
 30    /// <summary>
 31    /// Calculates the weight of the path given the weight function.
 32    /// </summary>
 33    /// <param name="path">The path.</param>
 34    /// <param name="getWeight">The weight function.</param>
 35    /// <returns>The total weight.</returns>
 36    public static double Weight(this Path path, Func<RoutingNetworkEdgeEnumerator, double> getWeight)
 037    {
 038        var weight = 0.0;
 39
 040        var edgeEnumerator = path.RoutingNetwork.GetEdgeEnumerator();
 041        foreach (var (edge, direction, offset1, offset2) in path)
 042        {
 043            if (!edgeEnumerator.MoveTo(edge, direction))
 044            {
 045                throw new InvalidDataException("An edge in the path is not found!");
 46            }
 47
 048            var edgeWeight = getWeight(edgeEnumerator);
 049            if (offset1 != 0 || offset2 != ushort.MaxValue)
 050            {
 051                edgeWeight *= (double)(offset2 - offset1) / ushort.MaxValue;
 052            }
 53
 054            weight += edgeWeight;
 055        }
 56
 057        return weight;
 058    }
 59
 60    /// <summary>
 61    /// Calculates the length in meters of this path.
 62    /// </summary>
 63    /// <param name="path">The path.</param>
 64    /// <returns>The length in meters.</returns>
 65    /// <exception cref="InvalidDataException"></exception>
 66    public static double LengthInMeters(this Path path)
 067    {
 068        var weight = 0.0;
 69
 070        var edgeEnumerator = path.RoutingNetwork.GetEdgeEnumerator();
 071        foreach (var (edge, direction, offset1, offset2) in path)
 072        {
 073            if (!edgeEnumerator.MoveTo(edge, direction))
 074            {
 075                throw new InvalidDataException("An edge in the path is not found!");
 76            }
 77
 078            var edgeWeight = edgeEnumerator.EdgeLength();
 079            if (offset1 != 0 || offset2 != ushort.MaxValue)
 080            {
 081                edgeWeight *= (double)(offset2 - offset1) / ushort.MaxValue;
 082            }
 83
 084            weight += edgeWeight;
 085        }
 86
 087        return weight;
 088    }
 89
 90    /// <summary>
 91    /// Returns true if the path is next.
 92    /// </summary>
 93    /// <param name="path">The path.</param>
 94    /// <param name="next">The next path.</param>
 95    /// <returns>True if the next path</returns>
 96    public static bool IsNext(this Path path, Path next)
 097    {
 098        var last = path.Last;
 099        var first = next.First;
 100
 101        // check if the same edge and if the offsets match.
 0102        if (last.edge == first.edge &&
 0103            last.direction == first.direction)
 0104        {
 0105            return path.Offset2 == next.Offset1;
 106        }
 107
 108        // check if the same vertices at the end.
 0109        if (next.Offset1 != 0 ||
 0110            path.Offset2 != ushort.MaxValue)
 0111        {
 0112            return false;
 113        }
 114
 0115        var edgeEnumerator = path.RoutingNetwork.GetEdgeEnumerator();
 0116        edgeEnumerator.MoveTo(last.edge, last.direction);
 0117        var lastVertex = edgeEnumerator.Head;
 0118        edgeEnumerator.MoveTo(first.edge, first.direction);
 0119        var firstVertex = edgeEnumerator.Tail;
 120
 0121        return lastVertex == firstVertex;
 0122    }
 123
 124    /// <summary>
 125    /// Merges the paths.
 126    /// </summary>
 127    /// <param name="path">The first part.</param>
 128    /// <param name="paths">The next parts.</param>
 129    /// <returns>The merged path.</returns>
 130    public static Path? Merge(this Path path, params Path[] paths)
 0131    {
 132        IEnumerable<Path> Enumerate()
 0133        {
 0134            yield return path;
 135
 0136            foreach (var p in paths)
 0137            {
 0138                yield return p;
 0139            }
 0140        }
 141
 0142        return Enumerate().Merge();
 0143    }
 144
 145    /// <summary>
 146    /// Merges the paths.
 147    /// </summary>
 148    /// <param name="paths">The paths.</param>
 149    /// <returns>The merged path.</returns>
 150    public static Path? Merge(this IEnumerable<Path> paths)
 0151    {
 0152        Path? merged = null;
 0153        RoutingNetworkEdgeEnumerator? enumerator = null;
 0154        foreach (var path in paths)
 0155        {
 0156            merged ??= new Path(path.RoutingNetwork);
 0157            enumerator ??= path.RoutingNetwork.GetEdgeEnumerator();
 158
 0159            if (merged.Count == 0)
 0160            {
 0161                merged.Offset1 = path.Offset1;
 0162            }
 0163            else if (!merged.IsNext(path))
 0164            {
 0165                throw new InvalidDataException(
 0166                    $"Paths cannot be concatenated.");
 167            }
 168
 0169            var isFirst = true;
 0170            foreach (var (edge, direction, _, _) in path)
 0171            {
 0172                if (isFirst)
 0173                {
 0174                    isFirst = false;
 0175                    if (merged.Count > 0 &&
 0176                        merged.Last.edge == edge &&
 0177                        merged.Last.direction == direction)
 0178                    {
 179                        // first edge may be the same edge as
 180                        // previous path, don't add it again.
 0181                        continue;
 182                    }
 0183                }
 184
 0185                merged.Append(edge, direction);
 0186            }
 187
 0188            merged.Offset2 = path.Offset2;
 0189        }
 190
 0191        return merged;
 0192    }
 193
 194    public static void Append(this Path path, IEnumerable<(EdgeId edge, bool forward, ushort offset1, ushort offset2)> o
 2195    {
 2196        if (path.Offset2 != ushort.MaxValue)
 0197            throw new Exception("Cannot append another hop to a path not ending at a vertex");
 198
 10199        foreach (var hop in other)
 2200        {
 2201            path.Append(hop.edge, hop.forward);
 202
 2203            path.Offset2 = hop.offset2;
 2204        }
 2205    }
 206
 207    /// <summary>
 208    /// Removes the first and/or last edge if they are not part of the path via the offset properties.
 209    /// </summary>
 210    /// <param name="path">The path.</param>
 211    public static void Trim(this Path path)
 8212    {
 8213        if (path.Count <= 1)
 2214        {
 2215            return;
 216        }
 217
 6218        if (path.Offset1 == ushort.MaxValue)
 4219        {
 4220            path.RemoveFirst();
 4221        }
 222
 6223        if (path.Count <= 1)
 1224        {
 1225            return;
 226        }
 227
 5228        if (path.Offset2 == 0)
 4229        {
 4230            path.RemoveLast();
 4231        }
 8232    }
 233
 234    public static bool HasLength(this Path path)
 0235    {
 0236        if (path.Count > 1) return true;
 237
 0238        return path.Offset1 != path.Offset2;
 0239    }
 240
 241    public static IEnumerable<(EdgeId edge, bool forward, ushort offset1, ushort offset2)> InvertDirection(
 242        this Path path)
 7243    {
 7244        var pathOffset1 = (ushort)(ushort.MaxValue - path.Offset2);
 7245        var pathOffset2 = (ushort)(ushort.MaxValue - path.Offset1);
 246
 34247        for (var i = 0; i < path.Count; i++)
 10248        {
 10249            var s = path[path.Count - i - 1];
 250
 10251            ushort offset1 = 0;
 10252            ushort offset2 = ushort.MaxValue;
 17253            if (i == 0) offset1 = pathOffset1;
 17254            if (i == path.Count - 1) offset2 = pathOffset2;
 255
 10256            yield return (s.edge, !s.forward, offset1, offset2);
 10257        }
 7258    }
 259}