< Summary

Class:Itinero.Network.Writer.RoutingNetworkWriter
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Network/Writer/RoutingNetworkWriter.cs
Covered lines:31
Uncovered lines:44
Coverable lines:75
Total lines:188
Line coverage:41.3% (31 of 75)
Covered branches:9
Total branches:36
Branch coverage:25% (9 of 36)
Tag:251_23667616543

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
GetEdgeEnumerator()100%10%
AddVertex(...)100%1100%
ComputeEdgeLength(...)50%460%
AddEdge(...)87.5%8100%
AddTurnCosts(...)0%240%
AddTile(...)100%10%
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
 4124    internal RoutingNetworkWriter(IRoutingNetworkWritable network)
 4125    {
 4126        _network = network;
 4127    }
 28
 29    /// <summary>
 30    /// Gets an edge enumerator.
 31    /// </summary>
 32    /// <returns>The enumerator.</returns>
 33    internal RoutingNetworkEdgeEnumerator GetEdgeEnumerator()
 034    {
 035        return _network.GetEdgeEnumerator();
 036    }
 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)
 4362    {
 4363        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
 4368        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
 4373        return (uint)((lon1, lat1, e1).DistanceEstimateInMeterShape(
 4374            (lon2, lat2, e2), shape) * 100);
 4375    }
 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)
 4394    {
 95        // get the tile (or create it).
 4396        var (tile, edgeTypeMap) = _network.GetTileForWrite(tail.TileId);
 4397        if (tile == null) throw new ArgumentException($"Cannot add edge with a vertex that doesn't exist.");
 98
 99        // get the edge type id.
 43100        edgeTypeId ??= attributes != null ? edgeTypeMap(attributes) : null;
 101
 43102        var edge1 = tile.AddEdge(tail, head, shape, attributes, null, edgeTypeId, length, globalEdgeId);
 43103        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.
 3109        (tile, _) = _network.GetTileForWrite(head.TileId);
 3110        tile.AddEdge(tail, head, shape, attributes, edge1, edgeTypeId, length, globalEdgeId);
 111
 3112        return edge1;
 43113    }
 114
 115    public void AddTurnCosts(VertexId vertex, IEnumerable<(string key, string value)> attributes,
 116        EdgeId[] edges, uint[,] costs, IEnumerable<EdgeId>? prefix, uint? turnCostType = null)
 0117    {
 0118        prefix ??= ArraySegment<EdgeId>.Empty;
 119
 120        // get the tile (or create it).
 0121        var (tile, _) = _network.GetTileForWrite(vertex.TileId);
 0122        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.
 0128        var turnCostMap = _network.RouterDb.GetTurnCostTypeMap();
 0129        turnCostType ??= turnCostMap.func(attributes);
 130
 131        // add the turn cost table using the type id.
 0132        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.
 0136        var enumerator = new NetworkTileEnumerator();
 0137        enumerator.MoveTo(tile);
 0138        if (enumerator.MoveTo(vertex))
 0139        {
 0140            while (enumerator.MoveNext())
 0141            {
 142                // only cross-tile edges need syncing.
 0143                if (enumerator.Tail.TileId == enumerator.Head.TileId) continue;
 144
 145                // Head is always the other vertex (Tail = turn cost vertex we enumerated from).
 0146                var (otherTile, _) = _network.GetTileForWrite(enumerator.Head.TileId);
 0147                if (otherTile == null) continue;
 148
 149                // find the same edge in the other tile by iterating from the other vertex.
 0150                var otherEnumerator = new NetworkTileEnumerator();
 0151                otherEnumerator.MoveTo(otherTile);
 0152                if (!otherEnumerator.MoveTo(enumerator.Head)) continue;
 153
 0154                while (otherEnumerator.MoveNext())
 0155                {
 0156                    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
 0164                    otherTile.SetTailHeadOrder(otherEnumerator.EdgePointer,
 0165                        otherEnumerator.Forward ? enumerator.HeadOrder : enumerator.TailOrder,
 0166                        otherEnumerator.Forward ? enumerator.TailOrder : enumerator.HeadOrder);
 0167                    break;
 168                }
 0169            }
 0170        }
 0171    }
 172
 173    internal void AddTile(NetworkTile tile)
 0174    {
 0175        _network.SetTile(tile);
 0176    }
 177
 178    internal bool HasTile(uint localTileId)
 0179    {
 0180        return _network.HasTile(localTileId);
 0181    }
 182
 183    /// <inheritdoc/>
 184    public void Dispose()
 41185    {
 41186        _network.ClearWriter();
 41187    }
 188}