< 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:91
Uncovered lines:8
Coverable lines:99
Total lines:185
Line coverage:91.9% (91 of 99)
Covered branches:37
Total branches:42
Branch coverage:88% (37 of 42)
Tag:263_26948838820

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
GetCompleteShape()100%2100%
EdgeLength(...)50%275%
GetShapeBetween()93.33%3093.54%
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)
 10515520    {
 10515521        yield return enumerator.TailLocation;
 22
 8243723        var shape = enumerator.Shape;
 57718624        foreach (var s in shape)
 16577225        {
 16577226            yield return s;
 16410327        }
 28
 8076829        yield return enumerator.HeadLocation;
 7851530    }
 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)
 75039938    {
 150079839        if (enumerator.Length != null) return enumerator.Length.Value / 100.0;
 40
 041        return enumerator.GetCompleteShape().DistanceEstimateInMeter();
 75039942    }
 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)
 4452755    {
 4452756        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.
 4452762        if (offset1 == 0 && offset2 == ushort.MaxValue)
 4448863        {
 48978764            foreach (var s in enumerator.GetCompleteShape())
 17851765            {
 17851766                yield return s;
 17780667            }
 68
 4377769            yield break;
 70        }
 71
 72        // get edge and shape details.
 3973        var shape = enumerator.Shape.ToList();
 74
 75        // calculate offsets in meters.
 3976        var edgeLength = enumerator.EdgeLength();
 3977        var offset1Length = offset1 / (double)ushort.MaxValue * edgeLength;
 3978        var offset2Length = offset2 / (double)ushort.MaxValue * edgeLength;
 79
 80        // TODO: can we make this easier with the complete shape enumeration?
 81        // calculate coordinate shape.
 3982        var before = offset1 > 0; // when there is a start offset.
 3983        var length = 0.0;
 3984        var previous = enumerator.TailLocation;
 3985        if (offset1 == 0 && includeVertices)
 2186        {
 2187            yield return previous;
 2188        }
 89
 27290        for (var i = 0; i < shape.Count + 1; i++)
 11991        {
 92            (double longitude, double latitude, float? e) next;
 11993            if (i < shape.Count)
 9394            {
 95                // the
 9396                next = shape[i];
 9397            }
 98            else
 2699            {
 100                // the last location.
 26101                next = enumerator.HeadLocation;
 26102            }
 103
 119104            var segmentLength = previous.DistanceEstimateInMeter(next);
 119105            if (before)
 36106            {
 107                // check if offset1 length has exceeded.
 36108                if (segmentLength + length >= offset1Length &&
 36109                    offset1 > 0)
 18110                {
 111                    // we are before, but not we have move to after.
 18112                    var segmentOffset = offset1Length - length;
 18113                    var location = (previous, next).PositionAlongLine(segmentOffset / segmentLength);
 18114                    previous = next;
 18115                    before = false;
 18116                    yield return location;
 18117                }
 36118            }
 119
 119120            if (!before)
 101121            {
 122                // check if offset2 length has exceeded.
 101123                if (segmentLength + length > offset2Length &&
 101124                    offset2 < ushort.MaxValue)
 22125                {
 126                    // we are after but now we are after.
 22127                    var segmentOffset = offset2Length - length;
 22128                    var location = (previous, next).PositionAlongLine(segmentOffset / segmentLength);
 22129                    yield return location;
 22130                    yield break;
 131                }
 132
 133                // the case where include vertices is false.
 79134                if (i == shape.Count && !includeVertices)
 0135                {
 0136                    yield break;
 137                }
 138
 79139                yield return next;
 79140            }
 141
 142            // move to the next segment.
 97143            previous = next;
 97144            length += segmentLength;
 97145        }
 17146    }
 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)
 43193156    {
 157        // TODO: this can be optimized, build a performance test.
 43193158        var shape = enumerator.GetShapeBetween().ToList();
 43193159        var length = enumerator.EdgeLength();
 43193160        var currentLength = 0.0;
 43193161        var targetLength = length * (offset / (double)ushort.MaxValue);
 176058162        for (var i = 1; i < shape.Count; i++)
 85155163        {
 85155164            var segmentLength = shape[i - 1].DistanceEstimateInMeter(shape[i]);
 85155165            if (segmentLength + currentLength > targetLength)
 40319166            {
 40319167                var segmentOffsetLength = segmentLength + currentLength - targetLength;
 40319168                var segmentOffset = 1 - (segmentOffsetLength / segmentLength);
 40319169                float? e = null;
 40319170                if (shape[i - 1].e.HasValue &&
 40319171                    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
 40319176                return (shape[i - 1].longitude + (segmentOffset * (shape[i].longitude - shape[i - 1].longitude)),
 40319177                    shape[i - 1].latitude + (segmentOffset * (shape[i].latitude - shape[i - 1].latitude)), e);
 178            }
 179
 44836180            currentLength += segmentLength;
 44836181        }
 182
 2874183        return shape[^1];
 43193184    }
 185}