< Summary

Class:Itinero.Network.Enumerators.Edges.IEdgeEnumeratorExtensions
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Network/Enumerators/Edges/IEdgeEnumeratorExtensions.cs
Covered lines:43
Uncovered lines:56
Coverable lines:99
Total lines:185
Line coverage:43.4% (43 of 99)
Covered branches:14
Total branches:42
Branch coverage:33.3% (14 of 42)
Tag:224_14471318300

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
GetCompleteShape()100%2100%
EdgeLength(...)50%2100%
GetShapeBetween()16.66%3014.51%
LocationOnEdge(...)75%887.5%

File(s)

/home/runner/work/routing2/routing2/src/Itinero/Network/Enumerators/Edges/IEdgeEnumeratorExtensions.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Itinero.Geo;
 5
 6namespace Itinero.Network.Enumerators.Edges;
 7
 8/// <summary>
 9/// Contains edge enumerator extensions.
 10/// </summary>
 11public static class IEdgeEnumeratorExtensions
 12{
 13    /// <summary>
 14    /// Gets the complete shape, including start end end vertices.
 15    /// </summary>
 16    /// <param name="enumerator">The enumerator.</param>
 17    /// <returns>The complete shape.</returns>
 18    public static IEnumerable<(double longitude, double latitude, float? e)> GetCompleteShape(
 19        this IEdgeEnumerator enumerator)
 33820    {
 33821        yield return enumerator.TailLocation;
 22
 33823        var shape = enumerator.Shape;
 133424        foreach (var s in shape)
 16025        {
 16026            yield return s;
 16027        }
 28
 33829        yield return enumerator.HeadLocation;
 33030    }
 31
 32    /// <summary>
 33    /// Gets the length of an edge in centimeters.
 34    /// </summary>
 35    /// <param name="enumerator">The enumerator.</param>
 36    /// <returns>The length in meters.</returns>
 37    public static double EdgeLength(this IEdgeEnumerator enumerator)
 24138    {
 24139        if (enumerator.Length != null) return enumerator.Length.Value / 100.0;
 40
 24141        return enumerator.GetCompleteShape().DistanceEstimateInMeter();
 24142    }
 43
 44    /// <summary>
 45    /// Returns the part of the edge between the two offsets not including the vertices at the start or the end.
 46    /// </summary>
 47    /// <param name="enumerator">The enumerator.</param>
 48    /// <param name="offset1">The start offset.</param>
 49    /// <param name="offset2">The end offset.</param>
 50    /// <param name="includeVertices">Include vertices in case the range start at min offset or ends at max.</param>
 51    /// <returns>The shape points between the given offsets. Includes the vertices by default when offsets at min/max.</
 52    public static IEnumerable<(double longitude, double latitude, float? e)> GetShapeBetween(
 53        this IEdgeEnumerator enumerator,
 54        ushort offset1 = 0, ushort offset2 = ushort.MaxValue, bool includeVertices = true)
 5755    {
 5756        if (offset1 > offset2)
 057        {
 058            throw new ArgumentException($"{nameof(offset1)} has to smaller than or equal to {nameof(offset2)}");
 59        }
 60
 61        // return the entire edge if requested.
 5762        if (offset1 == 0 && offset2 == ushort.MaxValue)
 5763        {
 47564            foreach (var s in enumerator.GetCompleteShape())
 15665            {
 15666                yield return s;
 14867            }
 68
 4969            yield break;
 70        }
 71
 72        // get edge and shape details.
 073        var shape = enumerator.Shape.ToList();
 74
 75        // calculate offsets in meters.
 076        var edgeLength = enumerator.EdgeLength();
 077        var offset1Length = offset1 / (double)ushort.MaxValue * edgeLength;
 078        var offset2Length = offset2 / (double)ushort.MaxValue * edgeLength;
 79
 80        // TODO: can we make this easier with the complete shape enumeration?
 81        // calculate coordinate shape.
 082        var before = offset1 > 0; // when there is a start offset.
 083        var length = 0.0;
 084        var previous = enumerator.TailLocation;
 085        if (offset1 == 0 && includeVertices)
 086        {
 087            yield return previous;
 088        }
 89
 090        for (var i = 0; i < shape.Count + 1; i++)
 091        {
 92            (double longitude, double latitude, float? e) next;
 093            if (i < shape.Count)
 094            {
 95                // the
 096                next = shape[i];
 097            }
 98            else
 099            {
 100                // the last location.
 0101                next = enumerator.HeadLocation;
 0102            }
 103
 0104            var segmentLength = previous.DistanceEstimateInMeter(next);
 0105            if (before)
 0106            {
 107                // check if offset1 length has exceeded.
 0108                if (segmentLength + length >= offset1Length &&
 0109                    offset1 > 0)
 0110                {
 111                    // we are before, but not we have move to after.
 0112                    var segmentOffset = offset1Length - length;
 0113                    var location = (previous, next).PositionAlongLine(segmentOffset / segmentLength);
 0114                    previous = next;
 0115                    before = false;
 0116                    yield return location;
 0117                }
 0118            }
 119
 0120            if (!before)
 0121            {
 122                // check if offset2 length has exceeded.
 0123                if (segmentLength + length > offset2Length &&
 0124                    offset2 < ushort.MaxValue)
 0125                {
 126                    // we are after but now we are after.
 0127                    var segmentOffset = offset2Length - length;
 0128                    var location = (previous, next).PositionAlongLine(segmentOffset / segmentLength);
 0129                    yield return location;
 0130                    yield break;
 131                }
 132
 133                // the case where include vertices is false.
 0134                if (i == shape.Count && !includeVertices)
 0135                {
 0136                    yield break;
 137                }
 138
 0139                yield return next;
 0140            }
 141
 142            // move to the next segment.
 0143            previous = next;
 0144            length += segmentLength;
 0145        }
 0146    }
 147
 148    /// <summary>
 149    /// Returns the location on the given edge using the given offset.
 150    /// </summary>
 151    /// <param name="enumerator">The enumerator.</param>
 152    /// <param name="offset">The offset.</param>
 153    /// <returns>The location on the network.</returns>
 154    internal static (double longitude, double latitude, float? e) LocationOnEdge(this IEdgeEnumerator enumerator,
 155        in ushort offset)
 19156    {
 157        // TODO: this can be optimized, build a performance test.
 19158        var shape = enumerator.GetShapeBetween().ToList();
 19159        var length = enumerator.EdgeLength();
 19160        var currentLength = 0.0;
 19161        var targetLength = length * (offset / (double)ushort.MaxValue);
 56162        for (var i = 1; i < shape.Count; i++)
 25163        {
 25164            var segmentLength = shape[i - 1].DistanceEstimateInMeter(shape[i]);
 25165            if (segmentLength + currentLength > targetLength)
 16166            {
 16167                var segmentOffsetLength = segmentLength + currentLength - targetLength;
 16168                var segmentOffset = 1 - (segmentOffsetLength / segmentLength);
 16169                float? e = null;
 16170                if (shape[i - 1].e.HasValue &&
 16171                    shape[i].e.HasValue)
 0172                {
 0173                    e = (float)(shape[i - 1].e.Value + (segmentOffset * (shape[i].e.Value - shape[i - 1].e.Value)));
 0174                }
 175
 16176                return (shape[i - 1].longitude + (segmentOffset * (shape[i].longitude - shape[i - 1].longitude)),
 16177                    shape[i - 1].latitude + (segmentOffset * (shape[i].latitude - shape[i - 1].latitude)), e);
 178            }
 179
 9180            currentLength += segmentLength;
 9181        }
 182
 3183        return shape[^1];
 19184    }
 185}