< 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:87
Uncovered lines:95
Coverable lines:182
Total lines:284
Line coverage:47.8% (87 of 182)
Covered branches:34
Total branches:82
Branch coverage:41.4% (34 of 82)
Tag:224_14471318300

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
Initialize()100%1100%
OnBeforePull()25%852.38%
AddNode(...)71.42%1447.05%
AddWay(...)75%2881.81%
AddRelation(...)0%200%
AddNetworkRestrictions(...)8.33%1211.76%

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;
 6using Itinero.IO.Osm.Restrictions.Barriers;
 7using Itinero.Network;
 8using Itinero.Network.Mutation;
 9using OsmSharp;
 10using OsmSharp.Streams;
 11
 12namespace Itinero.IO.Osm;
 13
 14/// <inheritdoc />
 15public class RouterDbStreamTarget : OsmStreamTarget
 16{
 317    private readonly Dictionary<long, VertexId> _vertices = new();
 18    private readonly RoutingNetworkMutator _mutableRouterDb;
 19    private readonly IElevationHandler? _elevationHandler;
 320    private readonly OsmTurnRestrictionParser _restrictionParser = new();
 321    private readonly Dictionary<long, Way?> _restrictionMembers = new();
 322    private readonly OsmBarrierParser _barrierParser = new();
 323    private readonly List<OsmBarrier> _osmBarriers = new();
 324    private readonly Dictionary<long, (double longitude, double latitude)> _nodeLocations = new();
 325    private readonly HashSet<long> _usedNodes = new();
 326    private readonly List<OsmTurnRestriction> _osmTurnRestrictions = new();
 327    private readonly Dictionary<(long wayId, int node1Idx, int node2Idx), EdgeId> _restrictedEdges = new();
 28
 29    /// <inheritdoc />
 330    public RouterDbStreamTarget(RoutingNetworkMutator mutableRouterDb,
 331        IElevationHandler? elevationHandler = null)
 332    {
 333        _mutableRouterDb = mutableRouterDb;
 334        _elevationHandler = elevationHandler;
 335    }
 36
 337    private bool _firstPass = true;
 38
 39    public override void Initialize()
 640    {
 641        _firstPass = true;
 642    }
 43
 44    public override bool OnBeforePull()
 345    {
 46        // execute the first pass.
 347        this.DoPull(true, false, false);
 48
 49        // add barriers as turn weights.
 350        var tileEnumerator = _mutableRouterDb.GetEdgeEnumerator();
 351        var networkRestrictions = new List<NetworkRestriction>();
 952        foreach (var osmBarrier in _osmBarriers)
 053        {
 054            var networkBarriersResult = osmBarrier.ToNetworkRestrictions(n =>
 055            {
 056                if (!_vertices.TryGetValue(n, out var v)) throw new Exception("Node should exist as vertex");
 057                tileEnumerator.MoveTo(v);
 058                return tileEnumerator;
 059            });
 060            if (networkBarriersResult.IsError) continue;
 61
 062            networkRestrictions.AddRange(networkBarriersResult.Value);
 063        }
 64
 365        this.AddNetworkRestrictions(networkRestrictions);
 66
 67        // move to second pass.
 368        _firstPass = false;
 369        this.Source.Reset();
 370        this.DoPull();
 71
 372        return false;
 373    }
 74
 75    /// <inheritdoc />
 76    public override void AddNode(Node node)
 1077    {
 1078        if (!node.Id.HasValue) return;
 1079        if (!node.Longitude.HasValue || !node.Latitude.HasValue) return;
 80
 81        // FIRST PASS: ignore nodes.
 1082        if (_firstPass)
 083        {
 084            if (_barrierParser.IsBarrier(node))
 085            {
 86                // make sure the barriers are core nodes, they need a turn cost.
 87                // log nodes are barriers to be able to detect their ways,
 88                //      only take nodes in the tile to mark as barrier.
 089                _vertices[node.Id.Value] = VertexId.Empty;
 090            }
 091            return;
 92        }
 93
 94        // SECOND PASS: keep node locations.
 1095        _nodeLocations[node.Id.Value] = (node.Longitude.Value, node.Latitude.Value);
 1496        if (!_vertices.TryGetValue(node.Id.Value, out _)) return;
 97
 98        // a vertex can be a barrier, check here.
 699        if (_barrierParser.TryParse(node, out var barrier))
 0100        {
 0101            _osmBarriers.Add(barrier);
 0102        }
 10103    }
 104
 105    /// <inheritdoc />
 106    public override void AddWay(Way way)
 6107    {
 6108        if (way.Nodes == null || way.Nodes.Length == 0 || !way.Id.HasValue) return;
 109
 6110        if (_firstPass)
 3111        {
 112            // FIRST PASS: keep track of nodes that are used as routing nodes.
 3113            _vertices[way.Nodes[0]] = VertexId.Empty;
 18114            for (var i = 0; i < way.Nodes.Length; i++)
 6115            {
 6116                var node = way.Nodes[i];
 6117                if (_usedNodes.Contains(node))
 0118                {
 0119                    _vertices[node] = VertexId.Empty;
 0120                    continue;
 121                }
 122
 6123                _usedNodes.Add(node);
 6124            }
 125
 3126            _vertices[way.Nodes[^1]] = VertexId.Empty;
 3127            return;
 128        }
 129
 130        // SECOND PASS: keep restricted ways and add edges.
 131
 132        // if way is a member of restriction, queue for later.
 3133        var saveEdge = _restrictionMembers.ContainsKey(way.Id.Value);
 3134        if (saveEdge) _restrictionMembers[way.Id.Value] = way;
 135
 136        // process the way into edges.
 3137        var vertex1 = VertexId.Empty;
 3138        var vertex1Idx = -1;
 3139        var shape = new List<(double longitude, double latitude, float? e)>();
 18140        for (var n = 0; n < way.Nodes.Length; n++)
 6141        {
 6142            var node = way.Nodes[n];
 6143            if (!_nodeLocations.TryGetValue(node, out var location))
 0144            {
 145                // an incomplete way, node not in source.
 0146                break;
 147            }
 148
 6149            if (!_vertices.TryGetValue(node, out var vertex2))
 0150            {
 151                // node is shape.
 0152                var coordinate = location.AddElevation(
 0153                    elevationHandler: _elevationHandler);
 0154                shape.Add(coordinate);
 0155                continue;
 156            }
 157
 6158            if (vertex2.IsEmpty())
 6159            {
 160                // node is core and not present yet.
 6161                var coordinate = location.AddElevation(
 6162                    elevationHandler: _elevationHandler);
 6163                vertex2 = _mutableRouterDb.AddVertex(coordinate);
 6164                _vertices[node] = vertex2;
 6165            }
 166
 6167            if (vertex1.IsEmpty())
 3168            {
 3169                vertex1 = vertex2;
 3170                vertex1Idx = n;
 3171                continue;
 172            }
 173
 174            // add edges.
 5175            var filteredTags = way.Tags?.Select(x => (x.Key, x.Value));
 3176            var edgeId = _mutableRouterDb.AddEdge(vertex1, vertex2,
 3177                shape,
 3178                filteredTags);
 179
 180            // check if this edge needs saving for restriction.
 3181            var edgeIdKey = (way.Id.Value, vertex1Idx, n);
 3182            if (saveEdge) _restrictedEdges[edgeIdKey] = edgeId;
 183
 184            // move to next part.
 3185            vertex1 = vertex2;
 3186            shape.Clear();
 3187        }
 6188    }
 189
 190    /// <inheritdoc />
 191    public override void AddRelation(Relation relation)
 0192    {
 0193        if (relation.Members == null || relation.Members.Length == 0) return;
 0194        if (_firstPass)
 0195        {
 0196            if (!_restrictionParser.IsRestriction(relation, out _)) return;
 197
 198            // log member ways.
 0199            foreach (var relationMember in relation.Members)
 0200            {
 0201                if (relationMember.Type != OsmGeoType.Way) continue;
 202
 0203                _restrictionMembers[relationMember.Id] = null;
 0204            }
 0205            return;
 206        }
 207
 208        // try to parse restriction.
 0209        var result = _restrictionParser.TryParse(relation,
 0210            k => !_restrictionMembers.TryGetValue(k, out var osmGeo) ? null : osmGeo,
 0211            out var restriction);
 212
 0213        if (result.IsError) return;
 0214        if (!result.Value) return;
 0215        if (restriction == null)
 0216            throw new Exception("restriction parsing was successful but restriction is null");
 217
 0218        var networkRestrictionResult = restriction.ToNetworkRestrictions((long wayId, int startNode, int endNode) =>
 0219        {
 0220            if (startNode < endNode)
 0221            {
 0222                if (!_restrictedEdges.TryGetValue((wayId, startNode, endNode), out var edgeId)) return null;
 0223
 0224                return (edgeId, true);
 0225            }
 0226            else
 0227            {
 0228                if (!_restrictedEdges.TryGetValue((wayId, endNode, startNode), out var edgeId)) return null;
 0229
 0230                return (edgeId, false);
 0231            }
 0232        });
 0233        if (networkRestrictionResult.IsError) return;
 234
 0235        this.AddNetworkRestrictions(networkRestrictionResult.Value);
 0236    }
 237
 238    private void AddNetworkRestrictions(IEnumerable<NetworkRestriction> networkRestrictions)
 3239    {
 3240        var enumerator = _mutableRouterDb.GetEdgeEnumerator();
 9241        foreach (var networkRestriction in networkRestrictions)
 0242        {
 0243            if (networkRestriction.Count < 2)
 0244            {
 245                // TODO: log something?
 0246                continue;
 247            }
 248
 249            // get last edge and turn cost vertex.
 0250            var last = networkRestriction[^1];
 0251            var lastEdge = _mutableRouterDb.GetEdge(last.edge, last.forward);
 0252            var turnCostVertex = lastEdge.Tail;
 253
 0254            var secondToLast = networkRestriction[^2];
 0255            if (networkRestriction.IsProhibitory)
 0256            {
 257                // easy, we only add a single cost.
 0258                var costs = new uint[,] { { 0, 1 }, { 0, 0 } };
 0259                _mutableRouterDb.AddTurnCosts(turnCostVertex, networkRestriction.Attributes,
 0260                    new[] { secondToLast.edge, last.edge }, costs,
 0261                    networkRestriction.Take(networkRestriction.Count - 2).Select(x => x.edge));
 0262            }
 263            else
 0264            {
 265                // hard, we need to add a cost for every *other* edge than then one in the restriction.
 0266                enumerator.MoveTo(secondToLast.edge, secondToLast.forward);
 0267                var to = enumerator.Head;
 0268                enumerator.MoveTo(to);
 269
 0270                while (enumerator.MoveNext())
 0271                {
 0272                    if (enumerator.EdgeId == secondToLast.edge ||
 0273                        enumerator.EdgeId == lastEdge.EdgeId) continue;
 274
 275                    // easy, we only add a single cost.
 0276                    var costs = new uint[,] { { 0, 1 }, { 0, 0 } };
 0277                    _mutableRouterDb.AddTurnCosts(turnCostVertex, networkRestriction.Attributes,
 0278                        new[] { secondToLast.edge, enumerator.EdgeId }, costs,
 0279                        networkRestriction.Take(networkRestriction.Count - 2).Select(x => x.edge));
 0280                }
 0281            }
 0282        }
 3283    }
 284}