< 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:172
Uncovered lines:1
Coverable lines:173
Total lines:276
Line coverage:99.4% (172 of 173)
Covered branches:81
Total branches:86
Branch coverage:94.1% (81 of 86)
Tag:251_23667616543

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%18100%

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{
 4119    private readonly Dictionary<long, VertexId> _vertices = new();
 20    private readonly RoutingNetworkMutator _mutableRouterDb;
 21    private readonly IElevationHandler? _elevationHandler;
 4122    private readonly OsmTurnRestrictionParser _restrictionParser = new();
 4123    private readonly Dictionary<long, Way?> _restrictionMembers = new();
 4124    private readonly OsmBarrierParser _barrierParser = new();
 4125    private readonly Dictionary<long, List<Way>> _barrierNodes = new();
 4126    private readonly Dictionary<long, Node> _barrierNodeObjects = new();
 4127    private readonly Dictionary<long, (double longitude, double latitude)> _nodeLocations = new();
 4128    private readonly HashSet<long> _usedNodes = new();
 4129    private readonly Dictionary<GlobalEdgeId, EdgeId> _globalEdgeIds = new();
 30
 31    /// <inheritdoc />
 4132    public RouterDbStreamTarget(RoutingNetworkMutator mutableRouterDb,
 4133        IElevationHandler? elevationHandler = null)
 4134    {
 4135        _mutableRouterDb = mutableRouterDb;
 4136        _elevationHandler = elevationHandler;
 4137    }
 38
 4139    private bool _firstPass = true;
 40
 41    public override void Initialize()
 8242    {
 8243        _firstPass = true;
 8244    }
 45
 46    public override bool OnBeforePull()
 4147    {
 48        // execute the first pass (skip nodes, process ways and relations).
 4149        this.DoPull(true, false, false);
 50
 51        // move to second pass.
 4152        _firstPass = false;
 4153        this.Source.Reset();
 4154        this.DoPull();
 55
 56        // add barriers as turn costs after all edges exist.
 487957        foreach (var (nodeId, ways) in _barrierNodes)
 237858        {
 237859            if (!_barrierNodeObjects.TryGetValue(nodeId, out var node)) continue;
 237860            if (!_barrierParser.TryParse(node, ways, out var barrier)) continue;
 61
 237862            this.ResolveAndAddTurnCosts(barrier.ToGlobalNetworkRestrictions());
 237863        }
 64
 4165        return false;
 4166    }
 67
 68    /// <inheritdoc />
 69    public override void AddNode(Node node)
 53504970    {
 53504971        if (!node.Id.HasValue) return;
 53504972        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.
 53504977        _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.
 53504981        if (_barrierParser.IsBarrier(node))
 237882        {
 237883            _vertices[node.Id.Value] = VertexId.Empty;
 237884            _barrierNodes[node.Id.Value] = [];
 237885            _barrierNodeObjects[node.Id.Value] = node;
 237886        }
 53504987    }
 88
 89    /// <inheritdoc />
 90    public override void AddWay(Way way)
 5686891    {
 5686892        if (way.Nodes == null || way.Nodes.Length == 0 || !way.Id.HasValue) return;
 93
 5686894        if (_firstPass)
 2843495        {
 96            // FIRST PASS: keep track of nodes that are used as routing nodes.
 2843497            _vertices[way.Nodes[0]] = VertexId.Empty;
 36020698            for (var i = 0; i < way.Nodes.Length; i++)
 15166999            {
 151669100                var node = way.Nodes[i];
 101
 151669102                if (_usedNodes.Contains(node))
 41674103                {
 41674104                    _vertices[node] = VertexId.Empty;
 41674105                    continue;
 106                }
 107
 109995108                _usedNodes.Add(node);
 109995109            }
 110
 28434111            _vertices[way.Nodes[^1]] = VertexId.Empty;
 28434112            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.
 360206118        for (var i = 0; i < way.Nodes.Length; i++)
 151669119        {
 151669120            if (_barrierNodes.TryGetValue(way.Nodes[i], out var barrierWays))
 3557121            {
 3557122                barrierWays.Add(way);
 3557123                _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.
 3557126                _vertices.TryAdd(way.Nodes[i], VertexId.Empty);
 3557127            }
 151669128        }
 129
 130        // if way is a member of restriction, queue for later.
 28434131        var saveEdge = _restrictionMembers.ContainsKey(way.Id.Value);
 31277132        if (saveEdge) _restrictionMembers[way.Id.Value] = way;
 133
 134        // process the way into edges.
 28434135        var vertex1 = VertexId.Empty;
 28434136        var vertex1Idx = -1;
 28434137        var shape = new List<(double longitude, double latitude, float? e)>();
 345802138        for (var n = 0; n < way.Nodes.Length; n++)
 145341139        {
 145341140            var node = way.Nodes[n];
 145341141            if (!_nodeLocations.TryGetValue(node, out var location))
 874142            {
 143                // an incomplete way, node not in source.
 874144                break;
 145            }
 146
 144467147            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
 77287156            if (vertex2.IsEmpty())
 36435157            {
 158                // node is core and not present yet.
 36435159                var coordinate = location.AddElevation(
 36435160                    elevationHandler: _elevationHandler);
 36435161                vertex2 = _mutableRouterDb.AddVertex(coordinate);
 36435162                _vertices[node] = vertex2;
 36435163            }
 164
 77287165            if (vertex1.IsEmpty())
 27950166            {
 27950167                vertex1 = vertex2;
 27950168                vertex1Idx = n;
 27950169                continue;
 170            }
 171
 172            // add edge.
 500962173            var filteredTags = way.Tags?.Select(x => (x.Key, x.Value));
 49337174            var edgeId = _mutableRouterDb.AddEdge(vertex1, vertex2,
 49337175                shape,
 49337176                filteredTags);
 177
 178            // register GlobalEdgeId → EdgeId for restriction resolution.
 49337179            if (saveEdge)
 5965180            {
 5965181                var globalEdgeId = way.CreateGlobalEdgeId(vertex1Idx, n);
 5965182                _globalEdgeIds[globalEdgeId] = edgeId;
 5965183            }
 184
 185            // move to next part.
 49337186            vertex1 = vertex2;
 49337187            vertex1Idx = n;
 49337188            shape.Clear();
 49337189        }
 56868190    }
 191
 192    /// <inheritdoc />
 193    public override void AddRelation(Relation relation)
 5136194    {
 5136195        if (relation.Members == null || relation.Members.Length == 0) return;
 5136196        if (_firstPass)
 2568197        {
 5062198            if (!_restrictionParser.IsRestriction(relation, out _)) return;
 199
 200            // log member ways.
 554201            foreach (var relationMember in relation.Members)
 166202            {
 226203                if (relationMember.Type != OsmGeoType.Way) continue;
 204
 106205                _restrictionMembers[relationMember.Id] = null;
 106206            }
 74207            return;
 208        }
 209
 210        // try to parse restriction.
 2568211        var result = _restrictionParser.TryParse(relation,
 106212            k => !_restrictionMembers.TryGetValue(k, out var osmGeo) ? null : osmGeo,
 2568213            out var restriction);
 214
 2582215        if (result.IsError) return;
 5048216        if (!result.Value) return;
 60217        if (restriction == null)
 0218            throw new Exception("restriction parsing was successful but restriction is null");
 219
 60220        this.ResolveAndAddTurnCosts(restriction.ToGlobalNetworkRestrictions());
 5136221    }
 222
 223    private void ResolveAndAddTurnCosts(IEnumerable<GlobalRestriction> globalRestrictions)
 2438224    {
 2438225        var enumerator = _mutableRouterDb.GetEdgeEnumerator();
 16818226        foreach (var globalRestriction in globalRestrictions)
 4752227        {
 4752228            if (!globalRestriction.TryBuildNetworkRestriction(GetEdge, out var networkRestriction))
 3720229                continue;
 230
 1032231            if (networkRestriction!.Count < 2) continue;
 232
 233            // get last edge and turn cost vertex.
 1032234            var last = networkRestriction[^1];
 1032235            if (!enumerator.MoveTo(last.edge, last.forward)) continue;
 1032236            var turnCostVertex = enumerator.Tail;
 237
 1032238            var secondToLast = networkRestriction[^2];
 1032239            if (networkRestriction.IsProhibitory)
 1002240            {
 1002241                var costs = new uint[,] { { 0, 1 }, { 0, 0 } };
 1002242                _mutableRouterDb.AddTurnCosts(turnCostVertex, networkRestriction.Attributes,
 1002243                    new[] { secondToLast.edge, last.edge }, costs,
 1002244                    networkRestriction.Take(networkRestriction.Count - 2).Select(x => x.edge));
 1002245            }
 246            else
 30247            {
 30248                if (!enumerator.MoveTo(secondToLast.edge, secondToLast.forward)) continue;
 30249                var to = enumerator.Head;
 30250                enumerator.MoveTo(to);
 251
 107252                while (enumerator.MoveNext())
 77253                {
 77254                    if (enumerator.EdgeId == secondToLast.edge ||
 137255                        enumerator.EdgeId == last.edge) continue;
 256
 17257                    var costs = new uint[,] { { 0, 1 }, { 0, 0 } };
 17258                    _mutableRouterDb.AddTurnCosts(turnCostVertex, networkRestriction.Attributes,
 17259                        new[] { secondToLast.edge, enumerator.EdgeId }, costs,
 17260                        networkRestriction.Take(networkRestriction.Count - 2).Select(x => x.edge));
 17261                }
 30262            }
 1032263        }
 264
 2438265        return;
 266
 267        (EdgeId edge, bool forward)? GetEdge(GlobalEdgeId geid)
 7196268        {
 7196269            if (_globalEdgeIds.TryGetValue(geid, out var edgeId))
 1766270                return (edgeId, true);
 5430271            if (_globalEdgeIds.TryGetValue(geid.GetInverted(), out edgeId))
 1710272                return (edgeId, false);
 3720273            return null;
 7196274        }
 2438275    }
 276}