< Summary

Class:Itinero.MapMatching.MapMatcherExtensions
Assembly:Itinero.MapMatching
File(s):/home/runner/work/routing2/routing2/src/Itinero.MapMatching/MapMatcherExtensions.cs
Covered lines:65
Uncovered lines:55
Coverable lines:120
Total lines:195
Line coverage:54.1% (65 of 120)
Covered branches:24
Total branches:48
Branch coverage:50% (24 of 48)
Tag:251_23667616543

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
Routes(...)0%40%
Routes()100%4100%
Route(...)75%4100%
MergedPaths(...)83.33%6100%
MergedPathsWithTrackPoints(...)0%80%
MergePathsWithIndices(...)0%100%
MergePaths(...)100%10100%
TryAppend(...)100%2100%

File(s)

/home/runner/work/routing2/routing2/src/Itinero.MapMatching/MapMatcherExtensions.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Itinero.Network;
 5using Itinero.Routes;
 6using Itinero.Routes.Builders;
 7using Itinero.Routes.Paths;
 8
 9namespace Itinero.MapMatching;
 10
 11/// <summary>
 12/// Contains extensions
 13/// </summary>
 14public static class MapMatcherExtensions
 15{
 16    /// <summary>
 17    /// Returns a route for each segment of the track matched.
 18    /// </summary>
 19    /// <param name="matcher">The matcher.</param>
 20    /// <param name="match">The match.</param>
 21    /// <returns>The resulting route(s).</returns>
 22    public static Result<IEnumerable<Route>> Routes(this MapMatcher matcher, MapMatch match)
 023    {
 024        if (matcher.Settings.Profile == null) throw new Exception("Cannot build routes without a profile");
 25
 026        var routes = new List<Route>();
 027        foreach (var path in match)
 028        {
 029            var route = RouteBuilder.Default.Build(matcher.RoutingNetwork, matcher.Settings.Profile, path);
 030            routes.Add(route);
 031        }
 32
 033        return routes;
 034    }
 35
 36    public static IEnumerable<Route> Routes(this MapMatcher matcher, IEnumerable<MapMatch> matches)
 1937    {
 10338        foreach (var match in matches)
 2339        {
 11740            foreach (var r in matcher.Route(match))
 2441            {
 2442                yield return r;
 2443            }
 2344        }
 1945    }
 46
 47    public static IEnumerable<Route> Route(this MapMatcher matcher, MapMatch match)
 2348    {
 2349        if (matcher.Settings.Profile == null) throw new Exception("Cannot build routes without a profile");
 50
 2351        var paths = matcher.MergedPaths(match);
 52
 2353        var routes = new List<Route>();
 11754        foreach (var path in paths)
 2455        {
 2456            var route = RouteBuilder.Default.Build(matcher.RoutingNetwork, matcher.Settings.Profile, path);
 2457            routes.Add(route);
 2458        }
 59
 2360        return routes;
 2361    }
 62
 63    public static IEnumerable<Path> MergedPaths(this MapMatcher matcher, MapMatch match)
 2364    {
 2365        if (matcher.Settings.Profile == null) throw new Exception("Cannot build routes without a profile");
 66
 2367        IEnumerable<Path> current = match;
 4768        while (true)
 4769        {
 4770            var (merged1, hasMerges1) = MapMatcherExtensions.MergePaths(current,
 202071                (p1, p2) => p1.TryAppend(p2));
 72
 4773            var (merged2, hasMerges2) = MapMatcherExtensions.MergePaths(merged1,
 8374                (p1, p2) => p1.TryMergeAsUTurn(p2));
 4775            current = merged2;
 76
 7077            if (!hasMerges1 && !hasMerges2) break;
 2478        }
 79
 2380        return current;
 2381    }
 82
 83    /// <summary>
 84    /// Returns merged paths with the from/to track point indices preserved through merging.
 85    /// Each returned tuple contains the merged path and the original track point index range it spans.
 86    /// </summary>
 87    public static IEnumerable<(Path path, int fromTrackPointIndex, int toTrackPointIndex)> MergedPathsWithTrackPoints(
 88        this MapMatcher matcher, MapMatch match)
 089    {
 090        if (matcher.Settings.Profile == null) throw new Exception("Cannot build routes without a profile");
 91
 92        // Build initial list pairing each raw path with its track point index range.
 093        var items = new List<(Path path, int from, int to)>();
 094        for (var i = 0; i < match.Count; i++)
 095        {
 096            items.Add((match[i], match.MatchedTrackPointIndices[i], match.MatchedTrackPointIndices[i + 1]));
 097        }
 98
 099        while (true)
 0100        {
 0101            var (merged1, hasMerges1) = MergePathsWithIndices(items,
 0102                (p1, p2) => p1.TryAppend(p2));
 103
 0104            var (merged2, hasMerges2) = MergePathsWithIndices(merged1,
 0105                (p1, p2) => p1.TryMergeAsUTurn(p2));
 0106            items = merged2;
 107
 0108            if (!hasMerges1 && !hasMerges2) break;
 0109        }
 110
 0111        return items;
 0112    }
 113
 114    private static (List<(Path path, int from, int to)> paths, bool merged) MergePathsWithIndices(
 115        List<(Path path, int from, int to)> items, Func<Path, Path, Path?> merge)
 0116    {
 0117        var result = new List<(Path path, int from, int to)>();
 118
 0119        (Path path, int from, int to)? current = null;
 0120        var hasMerges = false;
 0121        foreach (var item in items)
 0122        {
 0123            item.path.Trim();
 0124            if (!item.path.HasLength()) continue;
 125
 0126            if (current == null)
 0127            {
 0128                current = item;
 0129                continue;
 130            }
 131
 0132            var merged = merge(current.Value.path, item.path);
 0133            if (merged == null)
 0134            {
 0135                result.Add(current.Value);
 0136                current = item;
 0137                continue;
 138            }
 139
 0140            hasMerges = true;
 0141            current = (merged, current.Value.from, item.to);
 0142        }
 143
 0144        if (current != null)
 0145        {
 0146            result.Add(current.Value);
 0147        }
 148
 0149        return (result, hasMerges);
 0150    }
 151
 152    private static (IEnumerable<Path> paths, bool merged) MergePaths(IEnumerable<Path> paths, Func<Path, Path, Path?> me
 94153    {
 94154        var mergedPaths = new List<Path>();
 155
 94156        Path? currentPath = null;
 94157        var hasMerges = false;
 4570158        foreach (var path in paths)
 2144159        {
 2144160            path.Trim();
 2185161            if (!path.HasLength()) continue;
 162
 2103163            if (currentPath == null)
 94164            {
 94165                currentPath = path;
 94166                continue;
 167            }
 168
 2009169            var merged = merge(currentPath, path);
 2009170            if (merged == null)
 50171            {
 50172                mergedPaths.Add(currentPath);
 50173                currentPath = path;
 50174                continue;
 175            }
 176
 1959177            hasMerges = true;
 1959178            currentPath = merged;
 1959179        }
 180
 94181        if (currentPath != null)
 94182        {
 94183            mergedPaths.Add(currentPath);
 94184        }
 185
 94186        return (mergedPaths, hasMerges);
 94187    }
 188
 189    private static Path? TryAppend(this Path path, Path next)
 1973190    {
 2009191        if (!path.IsNext(next)) return null;
 192
 1937193        return new[] { path, next }.Merge();
 1973194    }
 195}