< Summary

Class:Itinero.IO.Osm.RouterDbStreamTarget
Assembly:Itinero.IO.Osm
File(s):/home/runner/work/routing2/routing2/src/Itinero.IO.Osm/RouterDbStreamTarget.cs
Covered lines:180
Uncovered lines:2
Coverable lines:182
Total lines:289
Line coverage:98.9% (180 of 182)
Covered branches:83
Total branches:88
Branch coverage:94.3% (83 of 88)
Tag:263_26948838820

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
Initialize()100%1100%
OnBeforePull()100%6100%
AddNode(...)87.5%8100%
AddWay(...)93.75%32100%
AddRelation(...)88.88%1895%
ResolveAndAddTurnCosts(...)100%1897.14%

File(s)

/home/runner/work/routing2/routing2/src/Itinero.IO.Osm/RouterDbStreamTarget.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Itinero.Geo.Elevation;
 5using Itinero.IO.Osm.Restrictions.Barriers;
 6using Itinero.IO.Osm.Restrictions.Turns;
 7using Itinero.IO.Osm.Tiles;
 8using Itinero.Network;
 9using Itinero.Network.Mutation;
 10using Itinero.Network.Tiles.Standalone.Global;
 11using OsmSharp;
 12using OsmSharp.Streams;
 13
 14namespace Itinero.IO.Osm;
 15
 16/// <inheritdoc />
 17public class RouterDbStreamTarget : OsmStreamTarget
 18{
 4719    private readonly Dictionary<long, VertexId> _vertices = new();
 20    private readonly RoutingNetworkMutator _mutableRouterDb;
 21    private readonly IElevationHandler? _elevationHandler;
 4722    private readonly OsmTurnRestrictionParser _restrictionParser = new();
 4723    private readonly Dictionary<long, Way?> _restrictionMembers = new();
 4724    private readonly OsmBarrierParser _barrierParser = new();
 4725    private readonly Dictionary<long, List<Way>> _barrierNodes = new();
 4726    private readonly Dictionary<long, Node> _barrierNodeObjects = new();
 4727    private readonly Dictionary<long, (double longitude, double latitude)> _nodeLocations = new();
 4728    private readonly HashSet<long> _usedNodes = new();
 4729    private readonly Dictionary<GlobalEdgeId, EdgeId> _globalEdgeIds = new();
 30
 31    /// <inheritdoc />
 4732    public RouterDbStreamTarget(RoutingNetworkMutator mutableRouterDb,
 4733        IElevationHandler? elevationHandler = null)
 4734    {
 4735        _mutableRouterDb = mutableRouterDb;
 4736        _elevationHandler = elevationHandler;
 4737    }
 38
 4739    private bool _firstPass = true;
 40
 41    public override void Initialize()
 9442    {
 9443        _firstPass = true;
 9444    }
 45
 46    public override bool OnBeforePull()
 4747    {
 48        // execute the first pass (skip nodes, process ways and relations).
 4749        this.DoPull(true, false, false);
 50
 51        // move to second pass.
 4752        _firstPass = false;
 4753        this.Source.Reset();
 4754        this.DoPull();
 55
 56        // add barriers as turn costs after all edges exist.
 489957        foreach (var (nodeId, ways) in _barrierNodes)
 237958        {
 237959            if (!_barrierNodeObjects.TryGetValue(nodeId, out var node)) continue;
 237960            if (!_barrierParser.TryParse(node, ways, out var barrier)) continue;
 61
 237962            this.ResolveAndAddTurnCosts(barrier.ToGlobalNetworkRestrictions());
 237963        }
 64
 4765        return false;
 4766    }
 67
 68    /// <inheritdoc />
 69    public override void AddNode(Node node)
 53547670    {
 53547671        if (!node.Id.HasValue) return;
 53547672        if (!node.Longitude.HasValue || !node.Latitude.HasValue) return;
 73
 74        // first pass skips nodes (DoPull(true, false, false)), so this is always the second pass.
 75
 76        // keep node locations.
 53547677        _nodeLocations[node.Id.Value] = (node.Longitude.Value, node.Latitude.Value);
 78
 79        // detect barriers — nodes come before ways in the stream, so when AddWay
 80        // runs it can check _barrierNodes to track which ways pass through barriers.
 53547681        if (_barrierParser.IsBarrier(node))
 237982        {
 237983            _vertices[node.Id.Value] = VertexId.Empty;
 237984            _barrierNodes[node.Id.Value] = [];
 237985            _barrierNodeObjects[node.Id.Value] = node;
 237986        }
 53547687    }
 88
 89    /// <inheritdoc />
 90    public override void AddWay(Way way)
 5842491    {
 5842492        if (way.Nodes == null || way.Nodes.Length == 0 || !way.Id.HasValue) return;
 93
 5842494        if (_firstPass)
 2921295        {
 96            // FIRST PASS: keep track of nodes that are used as routing nodes.
 2921297            _vertices[way.Nodes[0]] = VertexId.Empty;
 36488298            for (var i = 0; i < way.Nodes.Length; i++)
 15322999            {
 153229100                var node = way.Nodes[i];
 101
 153229102                if (_usedNodes.Contains(node))
 42807103                {
 42807104                    _vertices[node] = VertexId.Empty;
 42807105                    continue;
 106                }
 107
 110422108                _usedNodes.Add(node);
 110422109            }
 110
 29212111            _vertices[way.Nodes[^1]] = VertexId.Empty;
 29212112            return;
 113        }
 114
 115        // SECOND PASS: track barrier ways, add edges, register GlobalEdgeIds.
 116
 117        // track ways for barrier nodes and mark for edge registration.
 364882118        for (var i = 0; i < way.Nodes.Length; i++)
 153229119        {
 153229120            if (_barrierNodes.TryGetValue(way.Nodes[i], out var barrierWays))
 3559121            {
 3559122                barrierWays.Add(way);
 3559123                _restrictionMembers.TryAdd(way.Id!.Value, null);
 124                // barrier nodes must be vertices for turn costs,
 125                // but don't overwrite if already created by a previous way.
 3559126                _vertices.TryAdd(way.Nodes[i], VertexId.Empty);
 3559127            }
 153229128        }
 129
 130        // if way is a member of restriction, queue for later.
 29212131        var saveEdge = _restrictionMembers.ContainsKey(way.Id.Value);
 32065132        if (saveEdge) _restrictionMembers[way.Id.Value] = way;
 133
 134        // process the way into edges.
 29212135        var vertex1 = VertexId.Empty;
 29212136        var vertex1Idx = -1;
 29212137        var shape = new List<(double longitude, double latitude, float? e)>();
 350478138        for (var n = 0; n < way.Nodes.Length; n++)
 146901139        {
 146901140            var node = way.Nodes[n];
 146901141            if (!_nodeLocations.TryGetValue(node, out var location))
 874142            {
 143                // an incomplete way, node not in source.
 874144                break;
 145            }
 146
 146027147            if (!_vertices.TryGetValue(node, out var vertex2))
 67180148            {
 149                // node is shape.
 67180150                var coordinate = location.AddElevation(
 67180151                    elevationHandler: _elevationHandler);
 67180152                shape.Add(coordinate);
 67180153                continue;
 154            }
 155
 78847156            if (vertex2.IsEmpty())
 36862157            {
 158                // node is core and not present yet.
 36862159                var coordinate = location.AddElevation(
 36862160                    elevationHandler: _elevationHandler);
 36862161                vertex2 = _mutableRouterDb.AddVertex(coordinate);
 36862162                _vertices[node] = vertex2;
 36862163            }
 164
 78847165            if (vertex1.IsEmpty())
 28728166            {
 28728167                vertex1 = vertex2;
 28728168                vertex1Idx = n;
 28728169                continue;
 170            }
 171
 172            // add edge.
 503387173            var filteredTags = way.Tags?.Select(x => (x.Key, x.Value));
 50119174            var edgeId = _mutableRouterDb.AddEdge(vertex1, vertex2,
 50119175                shape,
 50119176                filteredTags);
 177
 178            // register GlobalEdgeId → EdgeId for restriction resolution.
 50119179            if (saveEdge)
 5979180            {
 5979181                var globalEdgeId = way.CreateGlobalEdgeId(vertex1Idx, n);
 5979182                _globalEdgeIds[globalEdgeId] = edgeId;
 5979183            }
 184
 185            // move to next part.
 50119186            vertex1 = vertex2;
 50119187            vertex1Idx = n;
 50119188            shape.Clear();
 50119189        }
 58424190    }
 191
 192    /// <inheritdoc />
 193    public override void AddRelation(Relation relation)
 5144194    {
 5144195        if (relation.Members == null || relation.Members.Length == 0) return;
 5144196        if (_firstPass)
 2572197        {
 5066198            if (!_restrictionParser.IsRestriction(relation, out _)) return;
 199
 200            // log member ways.
 590201            foreach (var relationMember in relation.Members)
 178202            {
 242203                if (relationMember.Type != OsmGeoType.Way) continue;
 204
 114205                _restrictionMembers[relationMember.Id] = null;
 114206            }
 78207            return;
 208        }
 209
 210        // try to parse restriction.
 2572211        var result = _restrictionParser.TryParse(relation,
 114212            k => !_restrictionMembers.TryGetValue(k, out var osmGeo) ? null : osmGeo,
 2572213            out var restriction);
 214
 2586215        if (result.IsError) return;
 5052216        if (!result.Value) return;
 64217        if (restriction == null)
 0218            throw new Exception("restriction parsing was successful but restriction is null");
 219
 64220        this.ResolveAndAddTurnCosts(restriction.ToGlobalNetworkRestrictions());
 5144221    }
 222
 223    private void ResolveAndAddTurnCosts(IEnumerable<GlobalRestriction> globalRestrictions)
 2443224    {
 2443225        var enumerator = _mutableRouterDb.GetEdgeEnumerator();
 16845226        foreach (var globalRestriction in globalRestrictions)
 4758227        {
 4758228            if (!globalRestriction.TryBuildNetworkRestriction(GetEdge, out var networkRestriction))
 0229                continue;
 230
 4758231            if (networkRestriction!.Count < 2) continue;
 232
 233            // get last edge and turn cost vertex.
 4758234            var last = networkRestriction[^1];
 4758235            if (!enumerator.MoveTo(last.edge, last.forward)) continue;
 4758236            var turnCostVertex = enumerator.Tail;
 237
 4758238            var secondToLast = networkRestriction[^2];
 4758239            if (networkRestriction.IsProhibitory)
 4711240            {
 4711241                var costs = new uint[,] { { 0, 1 }, { 0, 0 } };
 4711242                _mutableRouterDb.AddTurnCosts(turnCostVertex, networkRestriction.Attributes,
 4711243                    new[] { secondToLast.edge, last.edge }, costs,
 4711244                    networkRestriction.Take(networkRestriction.Count - 2).Select(x => x.edge));
 4711245            }
 246            else
 47247            {
 47248                if (!enumerator.MoveTo(secondToLast.edge, secondToLast.forward)) continue;
 47249                var to = enumerator.Head;
 47250                enumerator.MoveTo(to);
 251
 176252                while (enumerator.MoveNext())
 129253                {
 129254                    if (enumerator.EdgeId == secondToLast.edge ||
 223255                        enumerator.EdgeId == last.edge) continue;
 256
 35257                    var costs = new uint[,] { { 0, 1 }, { 0, 0 } };
 35258                    _mutableRouterDb.AddTurnCosts(turnCostVertex, networkRestriction.Attributes,
 35259                        new[] { secondToLast.edge, enumerator.EdgeId }, costs,
 35260                        networkRestriction.Take(networkRestriction.Count - 2).Select(x => x.edge));
 35261                }
 47262            }
 4758263        }
 264
 2443265        return;
 266
 267        (EdgeId edge, bool forward)? GetEdge(GlobalEdgeId geid, bool isFirst)
 9516268        {
 9516269            if (_globalEdgeIds.TryGetValue(geid, out var edgeId))
 2482270                return (edgeId, true);
 7034271            if (_globalEdgeIds.TryGetValue(geid.GetInverted(), out edgeId))
 2427272                return (edgeId, false);
 273
 4607274            return Itinero.Network.Tiles.Standalone.Global.GlobalRestrictionExtensions
 4607275                .WalkFromAnchor(geid, isFirst, TryGet);
 276
 277            bool TryGet(GlobalEdgeId q, out EdgeId result)
 13116278            {
 13116279                if (_globalEdgeIds.TryGetValue(q, out var v))
 4607280                {
 4607281                    result = v;
 4607282                    return true;
 283                }
 8509284                result = default;
 8509285                return false;
 13116286            }
 9516287        }
 2443288    }
 289}