< Summary

Class:Itinero.Network.Writer.RoutingNetworkWriter
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Network/Writer/RoutingNetworkWriter.cs
Covered lines:66
Uncovered lines:9
Coverable lines:75
Total lines:188
Line coverage:88% (66 of 75)
Covered branches:31
Total branches:36
Branch coverage:86.1% (31 of 36)
Tag:263_26948838820

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
GetEdgeEnumerator()100%1100%
AddVertex(...)100%1100%
ComputeEdgeLength(...)50%460%
AddEdge(...)87.5%8100%
AddTurnCosts(...)91.66%2493.54%
AddTile(...)100%1100%
HasTile(...)100%10%
Dispose()100%1100%

File(s)

/home/runner/work/routing2/routing2/src/Itinero/Network/Writer/RoutingNetworkWriter.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using Itinero.Geo;
 4using Itinero.Network.Enumerators.Edges;
 5using Itinero.Network.Tiles;
 6using Itinero.Network.Tiles.Standalone.Global;
 7// ReSharper disable PossibleMultipleEnumeration
 8
 9namespace Itinero.Network.Writer;
 10
 11/// <summary>
 12/// A writer to write to a network. This writer will never change existing data, only add new data.
 13///
 14/// This writer can:
 15/// - add new vertices
 16/// - add new edges.
 17///
 18/// This writer cannot mutate existing data, only add new.
 19/// </summary>
 20public class RoutingNetworkWriter : IDisposable
 21{
 22    private readonly IRoutingNetworkWritable _network;
 23
 6224    internal RoutingNetworkWriter(IRoutingNetworkWritable network)
 6225    {
 6226        _network = network;
 6227    }
 28
 29    /// <summary>
 30    /// Gets an edge enumerator.
 31    /// </summary>
 32    /// <returns>The enumerator.</returns>
 33    internal RoutingNetworkEdgeEnumerator GetEdgeEnumerator()
 1234    {
 1235        return _network.GetEdgeEnumerator();
 1236    }
 37
 38    /// <summary>
 39    /// Adds a new vertex.
 40    /// </summary>
 41    /// <param name="longitude">The longitude.</param>
 42    /// <param name="latitude">The latitude.</param>
 43    /// <param name="elevation">The elevation.</param>
 44    /// <returns>The vertex id.</returns>
 45    public VertexId AddVertex(double longitude, double latitude, float? elevation = null)
 8546    {
 47        // get the local tile id.
 8548        var (x, y) = TileStatic.WorldToTile(longitude, latitude, _network.Zoom);
 8549        var localTileId = TileStatic.ToLocalId(x, y, _network.Zoom);
 50
 51        // get the tile (or create it).
 8552        var (tile, _) = _network.GetTileForWrite(localTileId);
 53
 8554        return tile.AddVertex(longitude, latitude, elevation);
 8555    }
 56
 57    /// <summary>
 58    /// Computes the edge length in centimeters from vertex locations and shape.
 59    /// </summary>
 60    public uint ComputeEdgeLength(VertexId tail, VertexId head,
 61        IEnumerable<(double longitude, double latitude, float? e)>? shape = null)
 5162    {
 5163        if (!_network.TryGetVertex(tail, out var lon1, out var lat1, out var e1))
 064        {
 065            throw new ArgumentOutOfRangeException(nameof(tail), $"Vertex {tail} not found.");
 66        }
 67
 5168        if (!_network.TryGetVertex(head, out var lon2, out var lat2, out var e2))
 069        {
 070            throw new ArgumentOutOfRangeException(nameof(head), $"Vertex {head} not found.");
 71        }
 72
 5173        return (uint)((lon1, lat1, e1).DistanceEstimateInMeterShape(
 5174            (lon2, lat2, e2), shape) * 100);
 5175    }
 76
 77    /// <summary>
 78    /// Adds a new edge.
 79    /// </summary>
 80    /// <param name="tail">The tail vertex.</param>
 81    /// <param name="head">The head vertex.</param>
 82    /// <param name="shape">The shape, if any.</param>
 83    /// <param name="attributes">The attributes, if any.</param>
 84    /// <param name="edgeTypeId">The edge type id, if any.</param>
 85    /// <param name="length">The length in centimeters. Use <see cref="ComputeEdgeLength"/> if not known.</param>
 86    /// <param name="globalEdgeId">The global edge id, if any.</param>
 87    /// <returns></returns>
 88    /// <exception cref="ArgumentException"></exception>
 89    /// <exception cref="ArgumentOutOfRangeException"></exception>
 90    public EdgeId AddEdge(VertexId tail, VertexId head,
 91        IEnumerable<(double longitude, double latitude, float? e)>? shape,
 92        IEnumerable<(string key, string value)>? attributes, uint? edgeTypeId,
 93        uint length, GlobalEdgeId? globalEdgeId = null)
 5194    {
 95        // get the tile (or create it).
 5196        var (tile, edgeTypeMap) = _network.GetTileForWrite(tail.TileId);
 5197        if (tile == null) throw new ArgumentException($"Cannot add edge with a vertex that doesn't exist.");
 98
 99        // get the edge type id.
 51100        edgeTypeId ??= attributes != null ? edgeTypeMap(attributes) : null;
 101
 51102        var edge1 = tile.AddEdge(tail, head, shape, attributes, null, edgeTypeId, length, globalEdgeId);
 51103        if (tail.TileId == head.TileId)
 40104        {
 40105            return edge1;
 106        }
 107
 108        // this edge crosses tiles, also add an extra edge to the other tile.
 11109        (tile, _) = _network.GetTileForWrite(head.TileId);
 11110        tile.AddEdge(tail, head, shape, attributes, edge1, edgeTypeId, length, globalEdgeId);
 111
 11112        return edge1;
 51113    }
 114
 115    public void AddTurnCosts(VertexId vertex, IEnumerable<(string key, string value)> attributes,
 116        EdgeId[] edges, uint[,] costs, IEnumerable<EdgeId>? prefix, uint? turnCostType = null)
 12117    {
 12118        prefix ??= ArraySegment<EdgeId>.Empty;
 119
 120        // get the tile (or create it).
 12121        var (tile, _) = _network.GetTileForWrite(vertex.TileId);
 12122        if (tile == null)
 0123        {
 0124            throw new ArgumentException($"Cannot add turn costs to a vertex that doesn't exist.");
 125        }
 126
 127        // get the turn cost type id.
 12128        var turnCostMap = _network.RouterDb.GetTurnCostTypeMap();
 12129        turnCostType ??= turnCostMap.func(attributes);
 130
 131        // add the turn cost table using the type id.
 12132        tile.AddTurnCosts(vertex, turnCostType.Value, edges, costs, attributes, prefix);
 133
 134        // for cross-tile edges, the order was set on this tile's copy.
 135        // sync the order to the other tile's copy so routing from either side sees it.
 12136        var enumerator = new NetworkTileEnumerator();
 12137        enumerator.MoveTo(tile);
 12138        if (enumerator.MoveTo(vertex))
 12139        {
 36140            while (enumerator.MoveNext())
 24141            {
 142                // only cross-tile edges need syncing.
 36143                if (enumerator.Tail.TileId == enumerator.Head.TileId) continue;
 144
 145                // Head is always the other vertex (Tail = turn cost vertex we enumerated from).
 12146                var (otherTile, _) = _network.GetTileForWrite(enumerator.Head.TileId);
 12147                if (otherTile == null) continue;
 148
 149                // find the same edge in the other tile by iterating from the other vertex.
 12150                var otherEnumerator = new NetworkTileEnumerator();
 12151                otherEnumerator.MoveTo(otherTile);
 12152                if (!otherEnumerator.MoveTo(enumerator.Head)) continue;
 153
 12154                while (otherEnumerator.MoveNext())
 12155                {
 12156                    if (otherEnumerator.EdgeId != enumerator.EdgeId) continue;
 157
 158                    // found the same edge — copy the order bytes.
 159                    // SetTailHeadOrder takes STORED tail/head orders (for vertex1/vertex2 as encoded).
 160                    // enumerator.TailOrder = order at turn cost vertex, HeadOrder = order at other vertex.
 161                    // Map these to stored positions based on otherEnumerator.Forward:
 162                    // Forward=true: vertex1=otherVertex → stored tail=HeadOrder, stored head=TailOrder
 163                    // Forward=false: vertex1=turnCostVertex → stored tail=TailOrder, stored head=HeadOrder
 12164                    otherTile.SetTailHeadOrder(otherEnumerator.EdgePointer,
 12165                        otherEnumerator.Forward ? enumerator.HeadOrder : enumerator.TailOrder,
 12166                        otherEnumerator.Forward ? enumerator.TailOrder : enumerator.HeadOrder);
 12167                    break;
 168                }
 12169            }
 12170        }
 12171    }
 172
 173    internal void AddTile(NetworkTile tile)
 23174    {
 23175        _network.SetTile(tile);
 23176    }
 177
 178    internal bool HasTile(uint localTileId)
 0179    {
 0180        return _network.HasTile(localTileId);
 0181    }
 182
 183    /// <inheritdoc/>
 184    public void Dispose()
 62185    {
 62186        _network.ClearWriter();
 62187    }
 188}