< Summary

Class:Itinero.MapMatching.MapMatcher
Assembly:Itinero.MapMatching
File(s):/home/runner/work/routing2/routing2/src/Itinero.MapMatching/MapMatcher.cs
Covered lines:50
Uncovered lines:2
Coverable lines:52
Total lines:123
Line coverage:96.1% (50 of 52)
Covered branches:15
Total branches:22
Branch coverage:68.1% (15 of 22)
Tag:251_23667616543

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)50%2100%
get_Settings()100%1100%
get_RoutingNetwork()100%1100%
MatchAsync()70%2095.23%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Runtime.CompilerServices;
 5using System.Threading;
 6using System.Threading.Tasks;
 7using Itinero.MapMatching.Model;
 8using Itinero.MapMatching.Solver;
 9using Itinero.Network;
 10using Itinero.Profiles;
 11using Itinero.Routes.Paths;
 12using Itinero.Routing;
 13
 14[assembly: InternalsVisibleTo("Itinero.MapMatching.Tests")]
 15[assembly: InternalsVisibleTo("Itinero.MapMatching.Tests.Functional")]
 16
 17namespace Itinero.MapMatching;
 18
 19/// <summary>
 20/// The map matcher.
 21/// </summary>
 22public class MapMatcher
 23{
 24    private readonly RoutingNetwork _routingNetwork;
 25    private readonly Profile _profile;
 26    private readonly ModelBuilder _modelBuilder;
 27    private readonly ModelSolver _modelSolver;
 28
 29    /// <summary>
 30    /// Creates a new map matcher.
 31    /// </summary>
 32    /// <param name="routingNetwork">The routing network.</param>
 33    /// <param name="settings">The settings.</param>
 34    /// <exception cref="Exception"></exception>
 2235    public MapMatcher(RoutingNetwork routingNetwork, MapMatcherSettings settings)
 2236    {
 2237        this.Settings = settings;
 2238        _routingNetwork = routingNetwork;
 4439        _profile = settings.Profile ?? throw new Exception("No profile set"); ;
 40
 2241        _modelBuilder = new ModelBuilder(routingNetwork, settings.ModelBuilderSettings);
 2242        _modelSolver = new ModelSolver();
 2243    }
 44
 45    /// <summary>
 46    /// The settings.
 47    /// </summary>
 7048    public MapMatcherSettings Settings { get; }
 49
 50    /// <summary>
 51    /// Gets the routing network.
 52    /// </summary>
 2453    public RoutingNetwork RoutingNetwork => _routingNetwork;
 54
 55    /// <summary>
 56    /// Matches the given track.
 57    /// </summary>
 58    /// <param name="track">The track.</param>
 59    /// <param name="cancellationToken">The cancellation token.</param>
 60    /// <returns>One or more matched segments.</returns>
 61    /// <exception cref="Exception"></exception>
 62    public async Task<IEnumerable<MapMatch>> MatchAsync(Track track, CancellationToken cancellationToken = default)
 2263    {
 2264        var matches = new List<MapMatch>();
 65
 66        // build track model.
 2267        var trackModels = await _modelBuilder.BuildModels(track, _profile, cancellationToken);
 68
 11869        foreach (var trackModel in trackModels)
 2670        {
 71            // run solver.
 2672            var bestMatch = _modelSolver.Solve(trackModel).ToList();
 2673            if (cancellationToken.IsCancellationRequested) return ArraySegment<MapMatch>.Empty;
 74
 75            // calculate the paths between each matched point pair.
 2676            var rawPaths = new List<Path>();
 411277            for (var l = 2; l < bestMatch.Count - 1; l++)
 203078            {
 203079                if (cancellationToken.IsCancellationRequested) return ArraySegment<MapMatch>.Empty;
 80
 203081                var sourceNodeId = bestMatch[l - 1];
 203082                var targetNodeId = bestMatch[l];
 203083                var sourceNode = trackModel.GetNode(sourceNodeId);
 203084                var targetNode = trackModel.GetNode(targetNodeId);
 203085                var source = sourceNode.SnapPoint;
 203086                var target = targetNode.SnapPoint;
 87
 203088                if (source == null) throw new Exception("Track point should have a snap point");
 203089                if (target == null) throw new Exception("Track point should have a snap point");
 90
 91                // try to use the cached path from model building.
 203092                var edge = trackModel.GetEdge(sourceNodeId, targetNodeId);
 203093                if (edge?.CachedPath != null)
 199294                {
 199295                    rawPaths.Add(edge.CachedPath);
 199296                }
 97                else
 3898                {
 99                    // fallback: re-route if no cached path (e.g. same snap point).
 38100                    var path = await _routingNetwork.Route(new RoutingSettings() { Profile = _profile })
 38101                        .From(source.Value).To(target.Value).PathAsync(CancellationToken.None);
 38102                    if (path.IsError)
 0103                        throw new Exception(
 0104                            $"Raw path calculation failed, it shouldn't fail at this point because it succeeded on the s
 38105                    rawPaths.Add(path);
 38106                }
 2030107            }
 108
 109            // Collect the track point indices from the bestMatch sequence.
 110            // bestMatch[0] is a virtual start node, bestMatch[last] is a virtual end node.
 111            // The real matched nodes are bestMatch[1] through bestMatch[Count-2].
 26112            var trackPointIndices = new List<int>();
 4164113            for (var l = 1; l < bestMatch.Count - 1; l++)
 2056114            {
 2056115                trackPointIndices.Add(trackModel.GetNode(bestMatch[l]).TrackPoint!.Value);
 2056116            }
 117
 26118            matches.Add(new MapMatch(track, _profile, rawPaths, trackPointIndices));
 26119        }
 120
 22121        return matches;
 22122    }
 123}