< Summary

Class:Itinero.Network.Tiles.NetworkTile
Assembly:Itinero
File(s):/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.Attributes.cs
/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.cs
/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.Geo.cs
/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.Serialization.cs
/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.TurnCosts.cs
Covered lines:827
Uncovered lines:293
Coverable lines:1120
Total lines:1724
Line coverage:73.8% (827 of 1120)
Covered branches:240
Total branches:320
Branch coverage:75% (240 of 320)
Tag:251_23667616543

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
SetAttributes(...)75%1268.88%
GetGlobalEdgeId(...)0%40%
GetAttributes()87.5%880%
AddOrGetString(...)100%6100%
WriteAttributesTo(...)100%4100%
ReadAttributesFrom(...)100%4100%
ReadAttributesFrom(...)0%20%
WriteAttributesTo(...)0%20%
.ctor(...)100%2100%
.ctor(...)100%1100%
Clone()100%1100%
get_TileId()100%1100%
get_VertexCount()100%1100%
get_EdgeTypeMapId()100%1100%
AddVertex(...)100%1100%
HasVertex(...)100%2100%
TryGetVertex(...)100%2100%
AddEdge(...)80.76%2691.42%
DeleteEdge(...)100%2100%
IsEdgeDeleted(...)100%2100%
get_HasDeletedEdges()100%1100%
RemoveDeletedEdges()83.33%2488.73%
CloneForEdgeTypeMap(...)66.66%1283.07%
VertexEdgePointer(...)100%1100%
EncodeVertex(...)100%6100%
DecodeVertex(...)100%2100%
DecodeEdgeCrossId(...)100%1100%
GetEdgeCrossPointer(...)100%1100%
EncodePointer(...)100%2100%
DecodePointer(...)100%1100%
SetDynamicUIn32Nullable(...)100%2100%
GetTailHeadOrder(...)100%1100%
DecodeEdgePointerId(...)100%1100%
WriteEdgesAndVerticesTo(...)83.33%682.35%
ReadEdgesAndVerticesFrom(...)83.33%685%
ReadEdgesAndVerticesFrom(...)0%40%
WriteEdgesAndVerticesTo(...)0%40%
.ctor(...)100%1100%
SetCoordinate(...)77.77%1876.31%
GetCoordinate(...)100%4100%
SetShape(...)93.75%1696.77%
GetShape()86.36%2291.83%
WriteGeoTo(...)100%6100%
ReadGeoFrom(...)100%6100%
ReadGeoFrom(...)0%20%
WriteGeoTo(...)0%20%
WriteTo(...)100%1100%
ReadFrom(...)50%286.66%
ReadFromBuffer(...)0%20%
ReadFrom(...)100%10%
ToBytes()0%20%
WriteToBuffer(...)100%10%
GetSerializedSizeUpperBound()0%40%
.ctor(...)100%1100%
AddTurnCosts(...)85%4081.44%
GetTurnCosts()68.18%2263.79%
SetTailHeadOrder(...)78.57%1494.28%
WriteTurnCostsTo(...)50%450%
ReadTurnCostsFrom(...)50%457.14%
ReadTurnCostsFrom(...)0%20%
WriteTurnCostsTo(...)0%20%

File(s)

/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.Attributes.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using Itinero.Data;
 5using Itinero.IO;
 6using Itinero.Network.Storage;
 7using Itinero.Network.Tiles.Standalone.Global;
 8
 9namespace Itinero.Network.Tiles;
 10
 11internal partial class NetworkTile
 12{
 13    /// <summary>
 14    /// Stores the attributes, starting with the number of attributes and then alternating key-value pairs.
 15    /// </summary>
 16    private byte[] _attributes;
 17
 50218    private uint _nextAttributePointer = 0;
 19
 20    /// <summary>
 21    /// Stores each string once.
 22    /// </summary>
 23    private string[] _strings;
 24
 50225    private uint _nextStringId = 0;
 26
 27    private uint SetAttributes(IEnumerable<(string key, string value)> attributes, GlobalEdgeId? globalEdgeId)
 5274828    {
 29        // ensure enough space for the globalEdgeId header (up to 20 bytes).
 5274830        if (_attributes.Length <= _nextAttributePointer + 20)
 145831        {
 145832            Array.Resize(ref _attributes, _attributes.Length + 256);
 145833        }
 34
 35        // save position before globalEdgeId — GetAttributes/GetGlobalEdgeId read from here.
 5274836        var start = _nextAttributePointer;
 37
 5274838        if (globalEdgeId == null)
 5274839        {
 5274840            _nextAttributePointer += _attributes.SetDynamicInt64Nullable(_nextAttributePointer, null);
 5274841        }
 42        else
 043        {
 044            _nextAttributePointer += _attributes.SetDynamicInt64Nullable(_nextAttributePointer, globalEdgeId.Value.EdgeI
 045            _nextAttributePointer += _attributes.SetDynamicUInt32(_nextAttributePointer, globalEdgeId.Value.Tail);
 046            _nextAttributePointer += _attributes.SetDynamicUInt32(_nextAttributePointer, globalEdgeId.Value.Head);
 047        }
 48
 5274849        long cPos = _nextAttributePointer;
 5274850        long p = _nextAttributePointer + 1;
 5274851        var c = 0;
 62304452        foreach (var (key, value) in attributes)
 23240053        {
 23240054            if (_attributes.Length <= p + 16)
 124455            {
 124456                Array.Resize(ref _attributes, _attributes.Length + 256);
 124457            }
 58
 23240059            var id = this.AddOrGetString(key);
 23240060            p += _attributes.SetDynamicUInt32(p, id);
 23240061            id = this.AddOrGetString(value);
 23240062            p += _attributes.SetDynamicUInt32(p, id);
 63
 23240064            c++;
 23240065            if (c == 255)
 066            {
 067                _attributes[(int)cPos] = 255;
 068                c = 0;
 069                cPos = p;
 070                p++;
 071            }
 23240072        }
 73
 5274874        if (_attributes.Length <= cPos)
 075        {
 076            Array.Resize(ref _attributes, _attributes.Length + 256);
 077        }
 78
 5274879        _attributes[(int)cPos] = (byte)c;
 80
 5274881        _nextAttributePointer = (uint)p;
 82
 5274883        return start;
 5274884    }
 85
 86    internal GlobalEdgeId? GetGlobalEdgeId(uint? pointer)
 087    {
 088        if (pointer == null) return null;
 89
 090        var p = pointer.Value;
 091        p += _attributes.GetDynamicInt64Nullable(p, out var edgeId);
 092        if (edgeId == null) return null;
 093        p += _attributes.GetDynamicUInt32(p, out var tail);
 094        p += _attributes.GetDynamicUInt32(p, out var head);
 95
 096        return GlobalEdgeId.Create(edgeId.Value, tail, head);
 097    }
 98
 99    internal IEnumerable<(string key, string value)> GetAttributes(uint? pointer)
 1900100    {
 1910101        if (pointer == null) yield break;
 102
 1890103        var p = pointer.Value;
 1890104        p += _attributes.GetDynamicInt64Nullable(p, out var edgeId);
 1890105        if (edgeId != null)
 0106        {
 0107            p += _attributes.GetDynamicUInt32(p, out _);
 0108            p += _attributes.GetDynamicUInt32(p, out _);
 0109        }
 110
 111        int count;
 112        do
 1890113        {
 1890114            count = _attributes[(int)p];
 1890115            p++;
 116
 27470117            for (var i = 0; i < count; i++)
 11889118            {
 11889119                p += _attributes.GetDynamicUInt32(p, out var keyId);
 11889120                p += _attributes.GetDynamicUInt32(p, out var valId);
 121
 11889122                yield return (_strings[(int)keyId], _strings[(int)valId]);
 11845123            }
 3692124        } while (count == 255);
 1846125    }
 126
 127    private uint AddOrGetString(string s)
 464800128    {
 46735542129        for (uint i = 0; i < _nextStringId; i++)
 23351603130        {
 23351603131            var existing = _strings[(int)i];
 23351603132            if (existing == s)
 448632133            {
 448632134                return i;
 135            }
 22902971136        }
 137
 16168138        if (_strings.Length <= _nextStringId)
 315139        {
 315140            Array.Resize(ref _strings, _strings.Length + 256);
 315141        }
 142
 16168143        var id = _nextStringId;
 16168144        _nextStringId++;
 145
 16168146        _strings[(int)id] = s;
 16168147        return id;
 464800148    }
 149
 150    private void WriteAttributesTo(Stream stream)
 8151    {
 8152        stream.WriteVarUInt32(_nextAttributePointer);
 44153        for (var i = 0; i < _nextAttributePointer; i++)
 14154        {
 14155            stream.WriteByte(_attributes[i]);
 14156        }
 157
 8158        stream.WriteVarUInt32(_nextStringId);
 36159        for (var i = 0; i < _nextStringId; i++)
 10160        {
 10161            stream.WriteWithSize(_strings[i]);
 10162        }
 8163    }
 164
 165    private void ReadAttributesFrom(Stream stream)
 8166    {
 8167        _nextAttributePointer = stream.ReadVarUInt32();
 8168        Array.Resize(ref _attributes, (int)_nextAttributePointer);
 44169        for (var i = 0; i < _nextAttributePointer; i++)
 14170        {
 14171            _attributes[i] = (byte)stream.ReadByte();
 14172        }
 173
 8174        _nextStringId = stream.ReadVarUInt32();
 8175        Array.Resize(ref _strings, (int)_nextStringId);
 36176        for (var i = 0; i < _nextStringId; i++)
 10177        {
 10178            _strings[i] = stream.ReadWithSizeString();
 10179        }
 8180    }
 181
 182    private void ReadAttributesFrom(byte[] data, ref int offset)
 0183    {
 0184        _nextAttributePointer = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0185        Array.Resize(ref _attributes, (int)_nextAttributePointer);
 0186        Buffer.BlockCopy(data, offset, _attributes, 0, (int)_nextAttributePointer);
 0187        offset += (int)_nextAttributePointer;
 188
 0189        _nextStringId = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0190        Array.Resize(ref _strings, (int)_nextStringId);
 0191        for (var i = 0; i < _nextStringId; i++)
 0192        {
 0193            _strings[i] = BitCoderBuffer.GetWithSizeString(data, ref offset);
 0194        }
 0195    }
 196
 197    private void WriteAttributesTo(byte[] data, ref int offset)
 0198    {
 0199        BitCoderBuffer.SetVarUInt32(data, ref offset, _nextAttributePointer);
 0200        Buffer.BlockCopy(_attributes, 0, data, offset, (int)_nextAttributePointer);
 0201        offset += (int)_nextAttributePointer;
 202
 0203        BitCoderBuffer.SetVarUInt32(data, ref offset, _nextStringId);
 0204        for (var i = 0; i < _nextStringId; i++)
 0205        {
 0206            BitCoderBuffer.SetWithSizeString(data, ref offset, _strings[i]);
 0207        }
 0208    }
 209}

/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using Itinero.IO;
 5using Itinero.Network.Storage;
 6using Itinero.Network.Tiles.Standalone.Global;
 7using Itinero.Network.TurnCosts;
 8
 9namespace Itinero.Network.Tiles;
 10
 11internal partial class NetworkTile
 12{
 13    private const int DefaultSizeIncrease = 16;
 14
 15    private readonly uint _tileId;
 16    private readonly int _zoom; // the zoom level.
 17    private readonly Guid _edgeTypeMapId; // the edge type index id.
 18
 50219    private uint _nextVertexId = 0; // the next vertex id.
 20
 21    // the pointers, per vertex, to their first edge.
 22    // TODO: investigate if it's worth storing these with less precision, one tile will never contain this much data.
 23    // TODO: investigate if we can not use one-increasing vertex ids but also use their pointers like with the edges.
 24    private uint[] _pointers;
 25    private uint _nextCrossTileId; // the next id for an edge that crosses tile boundaries.
 26    private uint[] _crossEdgePointers; // points to the cross tile boundary edges.
 27
 28    // the next edge id.
 50229    private uint _nextEdgeId = 0;
 30
 31    // the edges.
 32    private byte[] _edges;
 33
 34    /// <summary>
 35    /// Creates a new tile.
 36    /// </summary>
 37    /// <param name="zoom">The zoom level.</param>
 38    /// <param name="tileId">The tile id.</param>
 39    /// <param name="edgeTypeMapId">The edge type index id.</param>
 48640    public NetworkTile(int zoom, uint tileId, Guid? edgeTypeMapId = null)
 48641    {
 48642        _zoom = zoom;
 48643        _tileId = tileId;
 48644        _edgeTypeMapId = edgeTypeMapId ?? Guid.Empty;
 48645        _nextCrossTileId = 0;
 46
 48647        _pointers = new uint[0];
 48648        _edges = new byte[0];
 48649        _crossEdgePointers = new uint[0];
 50
 48651        _coordinates = new byte[0];
 48652        _shapes = new byte[0];
 48653        _attributes = new byte[0];
 48654        _strings = new string[0];
 48655    }
 56
 1657    private NetworkTile(int zoom, uint tileId, Guid edgeTypeMapId, uint nextCrossTileId, uint[] pointers,
 1658        byte[] edges,
 1659        uint[] crossEdgePointers, byte[] coordinates, byte[] shapes,
 1660        byte[] attributes,
 1661        string[] strings, byte[] turnCosts, uint nextVertexId, uint nextEdgeId,
 1662        uint nextAttributePointer,
 1663        uint nextShapePointer, uint nextStringId)
 1664    {
 1665        _zoom = zoom;
 1666        _tileId = tileId;
 1667        _edgeTypeMapId = edgeTypeMapId;
 1668        _nextCrossTileId = nextCrossTileId;
 1669        _pointers = pointers;
 1670        _edges = edges;
 1671        _crossEdgePointers = crossEdgePointers;
 72
 1673        _coordinates = coordinates;
 1674        _shapes = shapes;
 1675        _attributes = attributes;
 1676        _strings = strings;
 1677        _turnCosts = turnCosts;
 78
 1679        _nextVertexId = nextVertexId;
 1680        _nextEdgeId = nextEdgeId;
 1681        _nextAttributePointer = nextAttributePointer;
 1682        _nextShapePointer = nextShapePointer;
 1683        _nextStringId = nextStringId;
 1684    }
 85
 86    /// <summary>
 87    /// Clones this graph tile.
 88    /// </summary>
 89    /// <returns>The copy of this tile.</returns>
 90    public NetworkTile Clone()
 1091    {
 1092        return new(_zoom, _tileId, _edgeTypeMapId, _nextCrossTileId, (uint[])_pointers.Clone(), (byte[])_edges.Clone(),
 1093            (uint[])_crossEdgePointers.Clone(),
 1094            (byte[])_coordinates.Clone(), (byte[])_shapes.Clone(), (byte[])_attributes.Clone(), (string[])_strings.Clone
 1095            _nextVertexId,
 1096            _nextEdgeId, _nextAttributePointer, _nextShapePointer, _nextStringId);
 1097    }
 98
 99    /// <summary>
 100    /// Gets the tile id.
 101    /// </summary>
 15906891102    public uint TileId => _tileId;
 103
 104    /// <summary>
 105    /// Gets the number of vertices.
 106    /// </summary>
 1142293107    public uint VertexCount => _nextVertexId;
 108
 109    /// <summary>
 110    /// Gets the edge type map id.
 111    /// </summary>
 4300623112    public Guid EdgeTypeMapId => _edgeTypeMapId;
 113
 114    /// <summary>
 115    /// Adds a new vertex and returns its id.
 116    /// </summary>
 117    /// <param name="longitude">The longitude.</param>
 118    /// <param name="latitude">The latitude.</param>
 119    /// <param name="e">The elevation in meters.</param>
 120    /// <returns>The ID of the new vertex.</returns>
 121    public VertexId AddVertex(double longitude, double latitude, float? e = null)
 36922122    {
 123        // set coordinate.
 36922124        this.SetCoordinate(_nextVertexId, longitude, latitude, e);
 125
 126        // create id.
 36922127        var vertexId = new VertexId(_tileId, _nextVertexId);
 36922128        _nextVertexId++;
 129
 130        // make room.
 36922131        ArrayBaseExtensions.EnsureMinimumSize(ref _pointers, vertexId.LocalId, DefaultSizeIncrease);
 132
 36922133        return vertexId;
 36922134    }
 135
 136    /// <summary>
 137    /// Returns true if the vertex exists.
 138    /// </summary>
 139    /// <param name="vertex"></param>
 140    /// <returns></returns>
 141    public bool HasVertex(VertexId vertex)
 41142    {
 41143        if (vertex.LocalId >= _nextVertexId)
 13144        {
 13145            return false;
 146        }
 147
 28148        return true;
 41149    }
 150
 151    /// <summary>
 152    /// Gets the vertex with the given id.
 153    /// </summary>
 154    /// <param name="vertex">The vertex.</param>
 155    /// <param name="longitude">The longitude.</param>
 156    /// <param name="latitude">The latitude.</param>
 157    /// <param name="elevation">The elevation.</param>
 158    /// <returns>True if the vertex exists.</returns>
 159    public bool TryGetVertex(VertexId vertex, out double longitude, out double latitude, out float? elevation)
 5824631160    {
 5824631161        longitude = default;
 5824631162        latitude = default;
 5824631163        elevation = null;
 5824631164        if (vertex.LocalId >= _nextVertexId)
 5327165        {
 5327166            return false;
 167        }
 168
 5819304169        this.GetCoordinate(vertex.LocalId, out longitude, out latitude, out elevation);
 5819304170        return true;
 5824631171    }
 172
 173    /// <summary>
 174    /// Adds a new edge and returns its id.
 175    /// </summary>
 176    /// <param name="vertex1">The first vertex.</param>
 177    /// <param name="vertex2">The second vertex.</param>
 178    /// <param name="shape">The shape."</param>
 179    /// <param name="attributes">The attributes."</param>
 180    /// <param name="edgeId">The edge id if this edge is a part of another tile.</param>
 181    /// <param name="edgeTypeId">The edge type id, if any.</param>
 182    /// <param name="length">The length in centimeters.</param>
 183    /// <param name="globalEdgeId">The global edge id, if any.</param>
 184    /// <returns>The new edge id.</returns>
 185    public EdgeId AddEdge(VertexId vertex1, VertexId vertex2,
 186        IEnumerable<(double longitude, double latitude, float? e)>? shape = null,
 187        IEnumerable<(string key, string value)>? attributes = null, EdgeId? edgeId = null, uint? edgeTypeId = null,
 188        uint? length = null, GlobalEdgeId? globalEdgeId = null)
 51904189    {
 51904190        if (vertex2.TileId != _tileId)
 2275191        {
 192            // this edge crosses tiles boundaries, it need special treatment and a stable id.
 193            // because the edge originates in this tile, this tile is responsible for generating the id.
 2275194            if (edgeId != null) throw new ArgumentException(
 0195                    "The edge id shouldn't be a given, it should be generated by the originating tile.",
 0196                    nameof(edgeId));
 2275197            if (vertex1.TileId != _tileId) throw new ArgumentException("None of the two vertices in this edge are in thi
 0198                    nameof(vertex1));
 199
 200            // generate a new cross tile id and store pointer to edge.
 2275201            edgeId = EdgeId.CrossEdgeId(_tileId, _nextCrossTileId);
 2275202            ArrayBaseExtensions.EnsureMinimumSize(ref _crossEdgePointers, _nextCrossTileId + 1);
 2275203            _crossEdgePointers[_nextCrossTileId] = _nextEdgeId;
 2275204            _nextCrossTileId++;
 2275205        }
 49629206        else if (vertex1.TileId != _tileId)
 2274207        {
 208            // this edge crosses tiles boundaries, it need special treatment and a stable id.
 209            // because the edge originates in another tile it should already have an id.
 2274210            if (edgeId == null) throw new ArgumentException(
 0211                    "Cannot add an edge that doesn't start in this tile without a proper edge id.",
 0212                    nameof(edgeId));
 2274213            if (edgeId.Value.TileId != vertex1.TileId) throw new ArgumentException("The edge id doesn't match the tile i
 0214                    nameof(edgeId));
 2274215        }
 216        else
 47355217        {
 218            // this edge starts in this tile, it get an id from this tile.
 47355219            edgeId = new EdgeId(_tileId, _nextEdgeId);
 47355220        }
 221
 222        // write the edge data.
 51904223        var newEdgePointer = _nextEdgeId;
 51904224        var size = EncodeVertex(ref _edges, _tileId, _nextEdgeId, vertex1);
 51904225        _nextEdgeId += size;
 51904226        size = EncodeVertex(ref _edges, _tileId, _nextEdgeId, vertex2);
 51904227        _nextEdgeId += size;
 228
 229        // get previous pointers if vertex already has edges
 230        // set the new pointers.
 51904231        uint? v1p = null;
 51904232        if (vertex1.TileId == _tileId)
 49630233        {
 49630234            v1p = _pointers[vertex1.LocalId].DecodeNullableData();
 49630235            _pointers[vertex1.LocalId] = newEdgePointer.EncodeToNullableData();
 49630236        }
 237
 51904238        uint? v2p = null;
 51904239        if (vertex2.TileId == _tileId)
 49629240        {
 49629241            v2p = _pointers[vertex2.LocalId].DecodeNullableData();
 49629242            _pointers[vertex2.LocalId] = newEdgePointer.EncodeToNullableData();
 49629243        }
 244
 245        // set next pointers.
 51904246        size = EncodePointer(ref _edges, _nextEdgeId, v1p);
 51904247        _nextEdgeId += size;
 51904248        size = EncodePointer(ref _edges, _nextEdgeId, v2p);
 51904249        _nextEdgeId += size;
 250
 251        // write edge id explicitly if not in this edge.
 51904252        if (vertex1.TileId != vertex2.TileId)
 4549253        {
 254            // this data will only be there for edges crossing tile boundaries.
 4549255            _nextEdgeId += (uint)_edges.SetDynamicUInt32(_nextEdgeId,
 4549256                edgeId.Value.LocalId - EdgeId.MinCrossId);
 4549257        }
 258
 259        // write edge profile id.
 51904260        _nextEdgeId += SetDynamicUIn32Nullable(ref _edges, _nextEdgeId, edgeTypeId);
 261
 262        // write length.
 51904263        _nextEdgeId += SetDynamicUIn32Nullable(ref _edges, _nextEdgeId, length);
 264
 265        // set tail and head order.
 51904266        _edges.SetTailHeadOrder(_nextEdgeId, null, null);
 51904267        _nextEdgeId++;
 268
 269        // take care of shape if any.
 51904270        uint? shapePointer = null;
 51904271        if (shape != null)
 51687272        {
 51687273            shapePointer = this.SetShape(shape);
 51687274        }
 275
 51904276        size = EncodePointer(ref _edges, _nextEdgeId, shapePointer);
 51904277        _nextEdgeId += size;
 278
 279        // take care of attributes if any.
 51904280        uint? attributesPointer = null;
 51904281        if (attributes != null || globalEdgeId != null)
 51719282        {
 51719283            attributesPointer = this.SetAttributes(attributes ?? [], globalEdgeId);
 51719284        }
 285
 51904286        size = EncodePointer(ref _edges, _nextEdgeId, attributesPointer);
 51904287        _nextEdgeId += size;
 288
 51904289        return edgeId.Value;
 51904290    }
 291
 292    private HashSet<EdgeId>? _deletedEdges;
 293
 294    /// <summary>
 295    /// Marks the given edge as deleted.
 296    /// </summary>
 297    /// <param name="edge">The edge to delete.</param>
 298    internal void DeleteEdge(EdgeId edge)
 10299    {
 10300        _deletedEdges ??= [];
 10301        _deletedEdges.Add(edge);
 10302    }
 303
 304    /// <summary>
 305    /// Returns true if the edge is deleted.
 306    /// </summary>
 307    /// <param name="edge">The edge.</param>
 308    /// <returns>True if the edge was deleted.</returns>
 309    internal bool IsEdgeDeleted(EdgeId edge)
 6541976310    {
 13083946311        if (_deletedEdges == null) return false;
 312
 6313        return _deletedEdges.Contains(edge);
 6541976314    }
 315
 316    /// <summary>
 317    /// Returns true if there are deleted edges.
 318    /// </summary>
 405319    internal bool HasDeletedEdges => _deletedEdges != null;
 320
 321    /// <summary>
 322    /// Removes all the deleted edges.
 323    /// </summary>
 324    /// <remarks>This changes all the edges if all edges written after a deleted edge.</remarks>
 325    internal void RemoveDeletedEdges()
 10326    {
 10327        if (_deletedEdges == null) return;
 328
 329        // reset vertex pointers.
 340330        for (var i = 0; i < _pointers.Length; i++)
 160331        {
 160332            _pointers[i] = 0;
 160333        }
 334
 335        // redo edges, skipping deleted edges.
 10336        var nextEdgeId = _nextEdgeId;
 10337        var p = 0U;
 10338        var newP = 0U;
 24339        while (p < nextEdgeId)
 14340        {
 341            // read edge data.
 14342            var currentEdgeId = p;
 14343            p += this.DecodeVertex(p, out var local1Id, out var tile1Id);
 14344            var vertex1 = new VertexId(tile1Id, local1Id);
 14345            p += this.DecodeVertex(p, out var local2Id, out var tile2Id);
 14346            var vertex2 = new VertexId(tile2Id, local2Id);
 14347            p += this.DecodePointer(p, out _);
 14348            p += this.DecodePointer(p, out _);
 14349            uint? crossEdgeId = null;
 14350            if (tile1Id != tile2Id)
 4351            {
 4352                p += _edges.GetDynamicUInt32(p, out var c);
 4353                crossEdgeId = c;
 4354            }
 355
 14356            p += _edges.GetDynamicUInt32Nullable(p, out var edgeTypeId);
 14357            p += _edges.GetDynamicUInt32Nullable(p, out var length);
 14358            var tailHeadOrder = _edges[p];
 14359            p++;
 14360            p += this.DecodePointer(p, out var shapePointer);
 14361            p += this.DecodePointer(p, out var attributePointer);
 362
 363            // check if edge was deleted.
 20364            if (_deletedEdges.Contains(new EdgeId(_tileId, currentEdgeId))) continue;
 8365            if (crossEdgeId.HasValue)
 4366            {
 8367                if (_deletedEdges.Contains(EdgeId.CrossEdgeId(vertex1.TileId, crossEdgeId.Value))) continue;
 0368            }
 369
 370            // no need to overwrite identical data.
 4371            if (p == newP) continue;
 372
 373            // write edge data again.
 4374            var newEdgePointer = newP;
 4375            newP += EncodeVertex(ref _edges, _tileId, newP, vertex1);
 4376            newP += EncodeVertex(ref _edges, _tileId, newP, vertex2);
 4377            uint? v1p = null;
 4378            if (vertex1.TileId == _tileId)
 4379            {
 4380                v1p = _pointers[vertex1.LocalId].DecodeNullableData();
 4381                _pointers[vertex1.LocalId] = newEdgePointer.EncodeToNullableData();
 4382            }
 383
 4384            uint? v2P = null;
 4385            if (vertex2.TileId == _tileId)
 4386            {
 4387                v2P = _pointers[vertex2.LocalId].DecodeNullableData();
 4388                _pointers[vertex2.LocalId] = newEdgePointer.EncodeToNullableData();
 4389            }
 390
 4391            newP += EncodePointer(ref _edges, newP, v1p);
 4392            newP += EncodePointer(ref _edges, newP, v2P);
 4393            if (crossEdgeId != null)
 0394            {
 0395                newP += (uint)_edges.SetDynamicUInt32(newP, crossEdgeId.Value);
 0396                if (vertex1.TileId == _tileId)
 0397                {
 0398                    _crossEdgePointers[crossEdgeId.Value] = newEdgePointer;
 0399                }
 0400            }
 401
 4402            newP += _edges.SetDynamicUInt32Nullable(newP, edgeTypeId);
 4403            newP += _edges.SetDynamicUInt32Nullable(newP, length);
 4404            _edges[newP] = tailHeadOrder;
 4405            newP++;
 4406            newP += EncodePointer(ref _edges, newP, shapePointer);
 4407            newP += EncodePointer(ref _edges, newP, attributePointer);
 4408        }
 409
 10410        _nextEdgeId = newP;
 10411        _deletedEdges = null;
 10412    }
 413
 414    internal NetworkTile CloneForEdgeTypeMap(
 415        (Guid id, Func<IEnumerable<(string key, string value)>, uint> func) edgeTypeMap)
 6416    {
 6417        var edges = new byte[_edges.Length];
 6418        var pointers = new uint[_pointers.Length];
 6419        var crossEdgePointers = new uint[_crossEdgePointers.Length];
 6420        var nextEdgeId = _nextEdgeId;
 6421        var p = 0U;
 6422        var newP = 0U;
 16423        while (p < nextEdgeId)
 10424        {
 425            // read edge data.
 10426            p += this.DecodeVertex(p, out var local1Id, out var tile1Id);
 10427            var vertex1 = new VertexId(tile1Id, local1Id);
 10428            p += this.DecodeVertex(p, out var local2Id, out var tile2Id);
 10429            var vertex2 = new VertexId(tile2Id, local2Id);
 10430            p += this.DecodePointer(p, out _);
 10431            p += this.DecodePointer(p, out _);
 10432            uint? crossEdgeId = null;
 10433            if (tile1Id != tile2Id)
 0434            {
 0435                p += (uint)_edges.GetDynamicUInt32(p, out var c);
 0436                crossEdgeId = c;
 0437            }
 438
 10439            p += _edges.GetDynamicUInt32Nullable(p, out var _);
 10440            p += _edges.GetDynamicUInt32Nullable(p, out var length);
 10441            var tailHeadOrder = _edges[p];
 10442            p++;
 10443            p += this.DecodePointer(p, out var shapePointer);
 10444            p += this.DecodePointer(p, out var attributePointer);
 445
 446            // generate new edge type id.
 10447            var newEdgeTypeId = edgeTypeMap.func(this.GetAttributes(attributePointer));
 448
 449            // write edge data again.
 10450            var newEdgePointer = newP;
 10451            newP += EncodeVertex(ref edges, _tileId, newP, vertex1);
 10452            newP += EncodeVertex(ref edges, _tileId, newP, vertex2);
 10453            uint? v1p = null;
 10454            if (vertex1.TileId == _tileId)
 10455            {
 10456                v1p = pointers[vertex1.LocalId].DecodeNullableData();
 10457                pointers[vertex1.LocalId] = newEdgePointer.EncodeToNullableData();
 10458            }
 459
 10460            uint? v2p = null;
 10461            if (vertex2.TileId == _tileId)
 10462            {
 10463                v2p = pointers[vertex2.LocalId].DecodeNullableData();
 10464                pointers[vertex2.LocalId] = newEdgePointer.EncodeToNullableData();
 10465            }
 466
 10467            newP += EncodePointer(ref edges, newP, v1p);
 10468            newP += EncodePointer(ref edges, newP, v2p);
 10469            if (crossEdgeId != null)
 0470            {
 0471                newP += edges.SetDynamicUInt32(newP, crossEdgeId.Value);
 0472                if (vertex1.TileId == _tileId)
 0473                {
 0474                    crossEdgePointers[crossEdgeId.Value] = newEdgePointer;
 0475                }
 0476            }
 477
 10478            newP += edges.SetDynamicUInt32Nullable(newP, newEdgeTypeId);
 10479            newP += edges.SetDynamicUInt32Nullable(newP, length);
 10480            edges[newP] = tailHeadOrder;
 10481            newP++;
 10482            newP += EncodePointer(ref edges, newP, shapePointer);
 10483            newP += EncodePointer(ref edges, newP, attributePointer);
 10484        }
 485
 6486        return new NetworkTile(_zoom, _tileId, edgeTypeMap.id, _nextCrossTileId, pointers, edges, crossEdgePointers,
 6487            _coordinates,
 6488            _shapes, _attributes, _strings, _turnCosts, _nextVertexId, _nextEdgeId,
 6489            _nextAttributePointer, _nextShapePointer, _nextStringId);
 6490    }
 491
 492    internal uint VertexEdgePointer(uint vertex)
 1143302493    {
 1143302494        return _pointers[vertex];
 1143302495    }
 496
 497    internal static byte EncodeVertex(ref byte[] edges, uint localTileId, uint location, VertexId vertexId)
 103836498    {
 103836499        if (vertexId.TileId == localTileId)
 99287500        {
 501            // same tile, only store local id.
 99287502            if (edges.Length <= location + 5)
 12608503            {
 12608504                Array.Resize(ref edges, edges.Length + DefaultSizeIncrease);
 12608505            }
 506
 99287507            return edges.SetDynamicUInt32(location, vertexId.LocalId);
 508        }
 509
 510        // other tile, store full id.
 4549511        if (edges.Length <= location + 10)
 1959512        {
 1959513            Array.Resize(ref edges, edges.Length + DefaultSizeIncrease);
 1959514        }
 515
 4549516        var encodedId = vertexId.Encode();
 4549517        return edges.SetDynamicUInt64(location, encodedId);
 103836518    }
 519
 520    internal byte DecodeVertex(uint location, out uint localId, out uint tileId)
 13086088521    {
 13086088522        var size = _edges.GetDynamicUInt64(location, out var encodedId);
 13086088523        if (encodedId < uint.MaxValue)
 12974130524        {
 12974130525            localId = (uint)encodedId;
 12974130526            tileId = _tileId;
 12974130527            return size;
 528        }
 529
 111958530        VertexId.Decode(encodedId, out tileId, out localId);
 111958531        return size;
 13086088532    }
 533
 534    internal byte DecodeEdgeCrossId(uint location, out uint edgeCrossId)
 111913535    {
 111913536        var s = _edges.GetDynamicUInt32(location, out var c);
 111913537        edgeCrossId = EdgeId.MinCrossId + c;
 111913538        return s;
 111913539    }
 540
 541    internal uint GetEdgeCrossPointer(uint edgeCrossId)
 49248542    {
 49248543        return _crossEdgePointers[edgeCrossId];
 49248544    }
 545
 546    internal static byte EncodePointer(ref byte[] edges, uint location, uint? pointer)
 207672547    {
 548        // TODO: save the diff instead of the full pointer.
 207672549        if (edges.Length <= location + 5)
 27457550        {
 27457551            Array.Resize(ref edges, edges.Length + DefaultSizeIncrease);
 27457552        }
 553
 207672554        return edges.SetDynamicUInt32(location,
 207672555            pointer.EncodeAsNullableData());
 207672556    }
 557
 558    internal byte DecodePointer(uint location, out uint? pointer)
 14390085559    {
 14390085560        var size = _edges.GetDynamicUInt32(location, out var data);
 14390085561        pointer = data.DecodeNullableData();
 14390085562        return size;
 14390085563    }
 564
 565    internal static byte SetDynamicUIn32Nullable(ref byte[] edges, uint pointer, uint? data)
 103808566    {
 114572567        while (edges.Length <= pointer + 5)
 10764568        {
 10764569            Array.Resize(ref edges, edges.Length + DefaultSizeIncrease);
 10764570        }
 571
 103808572        return edges.SetDynamicUInt32Nullable(pointer, data);
 103808573    }
 574
 575    internal void GetTailHeadOrder(uint location, ref byte? tail, ref byte? head)
 6543019576    {
 6543019577        _edges.GetTailHeadOrder(location, ref tail, ref head);
 6543019578    }
 579
 580    internal byte DecodeEdgePointerId(uint location, out uint? edgeProfileId)
 13086038581    {
 13086038582        return _edges.GetDynamicUInt32Nullable(location, out edgeProfileId);
 13086038583    }
 584
 585    private void WriteEdgesAndVerticesTo(Stream stream)
 8586    {
 587        // write vertex pointers.
 8588        stream.WriteVarUInt32(_nextVertexId);
 42589        for (var i = 0; i < _nextVertexId; i++)
 13590        {
 13591            stream.WriteVarUInt32(_pointers[i]);
 13592        }
 593
 594        // write edges.
 8595        stream.WriteVarUInt32(_nextEdgeId);
 106596        for (var i = 0; i < _nextEdgeId; i++)
 45597        {
 45598            stream.WriteByte(_edges[i]);
 45599        }
 600
 601        // write cross edge pointers.
 8602        stream.WriteVarUInt32(_nextCrossTileId);
 16603        for (var i = 0; i < _nextCrossTileId; i++)
 0604        {
 0605            stream.WriteVarUInt32(_crossEdgePointers[i]);
 0606        }
 8607    }
 608
 609    private void ReadEdgesAndVerticesFrom(Stream stream)
 8610    {
 611        // read vertex pointers.
 8612        _nextVertexId = stream.ReadVarUInt32();
 8613        Array.Resize(ref _pointers, (int)_nextVertexId);
 42614        for (var i = 0; i < _nextVertexId; i++)
 13615        {
 13616            _pointers[i] = stream.ReadVarUInt32();
 13617        }
 618
 619        // read edges.
 8620        _nextEdgeId = stream.ReadVarUInt32();
 8621        Array.Resize(ref _edges, (int)_nextEdgeId);
 106622        for (var i = 0; i < _nextEdgeId; i++)
 45623        {
 45624            _edges[i] = (byte)stream.ReadByte();
 45625        }
 626
 627        // read cross tile edge pointers.
 8628        _nextCrossTileId = stream.ReadVarUInt32();
 8629        Array.Resize(ref _crossEdgePointers, (int)_nextCrossTileId);
 16630        for (var i = 0; i < _nextCrossTileId; i++)
 0631        {
 0632            _crossEdgePointers[i] = stream.ReadVarUInt32();
 0633        }
 8634    }
 635
 636    private void ReadEdgesAndVerticesFrom(byte[] data, ref int offset)
 0637    {
 0638        _nextVertexId = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0639        Array.Resize(ref _pointers, (int)_nextVertexId);
 0640        for (var i = 0; i < _nextVertexId; i++)
 0641        {
 0642            _pointers[i] = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0643        }
 644
 0645        _nextEdgeId = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0646        Array.Resize(ref _edges, (int)_nextEdgeId);
 0647        Buffer.BlockCopy(data, offset, _edges, 0, (int)_nextEdgeId);
 0648        offset += (int)_nextEdgeId;
 649
 0650        _nextCrossTileId = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0651        Array.Resize(ref _crossEdgePointers, (int)_nextCrossTileId);
 0652        for (var i = 0; i < _nextCrossTileId; i++)
 0653        {
 0654            _crossEdgePointers[i] = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0655        }
 0656    }
 657
 658    private void WriteEdgesAndVerticesTo(byte[] data, ref int offset)
 0659    {
 0660        BitCoderBuffer.SetVarUInt32(data, ref offset, _nextVertexId);
 0661        for (var i = 0; i < _nextVertexId; i++)
 0662        {
 0663            BitCoderBuffer.SetVarUInt32(data, ref offset, _pointers[i]);
 0664        }
 665
 0666        BitCoderBuffer.SetVarUInt32(data, ref offset, _nextEdgeId);
 0667        Buffer.BlockCopy(_edges, 0, data, offset, (int)_nextEdgeId);
 0668        offset += (int)_nextEdgeId;
 669
 0670        BitCoderBuffer.SetVarUInt32(data, ref offset, _nextCrossTileId);
 0671        for (var i = 0; i < _nextCrossTileId; i++)
 0672        {
 0673            BitCoderBuffer.SetVarUInt32(data, ref offset, _crossEdgePointers[i]);
 0674        }
 0675    }
 676}

/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.Geo.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using Itinero.IO;
 5using Itinero.Network.Storage;
 6
 7namespace Itinero.Network.Tiles;
 8
 9internal partial class NetworkTile
 10{
 11    private const int CoordinateSizeInBytes = 3; // 3 bytes = 24 bits = 4096 x 4096.
 12    private const int TileResolutionInBits = CoordinateSizeInBytes * 8 / 2;
 13    private const int ElevationSizeInBytes = 2; // 2 bytes = 16 bits = [-32768, 32767], using dm as resolution
 14
 15    // the vertex coordinates.
 16    private byte[] _coordinates;
 17    private int? _elevation; // the tile elevation.
 18
 19    // the shapes.
 50220    private uint _nextShapePointer = 0;
 21    private byte[] _shapes;
 22
 23    private void SetCoordinate(uint localId, double longitude, double latitude, float? e)
 3692224    {
 25        // set elevation if needed.
 3692226        if (_elevation != null && e == null)
 027        {
 028            throw new ArgumentNullException(nameof(e),
 029                "Elevation was set before, either always set elevation or never set elevation.");
 30        }
 31
 3692232        if (_elevation == null && e != null)
 1333        {
 1334            if (localId != 0)
 035            {
 036                throw new ArgumentNullException(nameof(e),
 037                    "Elevation was not set before, either always set elevation or never set elevation.");
 38            }
 39
 1340            _elevation = (int)(e * 10);
 1341        }
 42
 43        // make sure coordinates fit.
 44        uint tileCoordinatePointer;
 3692245        if (_elevation == null)
 3688446        {
 47            // don't store elevation.
 3688448            tileCoordinatePointer = localId * CoordinateSizeInBytes * 2;
 3688449            ArrayBaseExtensions.EnsureMinimumSize(ref _coordinates, tileCoordinatePointer + (CoordinateSizeInBytes * 2),
 3688450                DefaultSizeIncrease);
 3688451        }
 52        else
 3853        {
 54            // store elevation.
 3855            tileCoordinatePointer = localId * ((CoordinateSizeInBytes * 2) + ElevationSizeInBytes);
 3856            ArrayBaseExtensions.EnsureMinimumSize(ref _coordinates, tileCoordinatePointer + (CoordinateSizeInBytes * 2) 
 3857                DefaultSizeIncrease);
 3858        }
 59
 60        // write coordinates.
 61        const int resolution = (1 << TileResolutionInBits) - 1;
 3692262        var (x, y) = TileStatic.ToLocalTileCoordinates(_zoom, _tileId, longitude, latitude, resolution);
 3692263        _coordinates.SetFixed(tileCoordinatePointer, CoordinateSizeInBytes, x);
 3692264        _coordinates.SetFixed(tileCoordinatePointer + CoordinateSizeInBytes, CoordinateSizeInBytes, y);
 65
 66        // write elevation.
 3692267        if (_elevation != null)
 3868        {
 3869            if (e == null)
 070            {
 071                throw new ArgumentNullException(nameof(e),
 072                    "Elevation was set before, either always set elevation or never set elevation.");
 73            }
 74
 3875            var offset = (int)(e.Value * 10) - _elevation.Value;
 3876            _coordinates.SetFixed(tileCoordinatePointer + CoordinateSizeInBytes + CoordinateSizeInBytes,
 3877                ElevationSizeInBytes, offset);
 3878        }
 3692279    }
 80
 81    private void GetCoordinate(uint localId, out double longitude, out double latitude, out float? elevation)
 581930482    {
 581930483        var tileCoordinatePointer = _elevation == null
 581930484            ? localId * CoordinateSizeInBytes * 2
 581930485            : localId * ((CoordinateSizeInBytes * 2) + ElevationSizeInBytes);
 86
 87        const int resolution = (1 << TileResolutionInBits) - 1;
 581930488        _coordinates.GetFixed(tileCoordinatePointer, CoordinateSizeInBytes, out var x);
 581930489        _coordinates.GetFixed(tileCoordinatePointer + CoordinateSizeInBytes, CoordinateSizeInBytes, out var y);
 581930490        elevation = null;
 581930491        if (_elevation != null)
 8992        {
 8993            _coordinates.GetFixed(tileCoordinatePointer + CoordinateSizeInBytes + CoordinateSizeInBytes,
 8994                ElevationSizeInBytes, out var offset);
 8995            elevation = (_elevation.Value + offset) / 10.0f;
 8996        }
 97
 581930498        TileStatic.FromLocalTileCoordinates(_zoom, _tileId, x, y, resolution, out longitude, out latitude);
 581930499    }
 100
 101    private uint SetShape(IEnumerable<(double longitude, double latitude, float? e)> shape)
 51687102    {
 103        const int resolution = (1 << TileResolutionInBits) - 1;
 51687104        var originalPointer = _nextShapePointer;
 51687105        var blockPointer = originalPointer;
 51687106        var pointer = blockPointer + 1;
 107
 108        // make sure there is space for the block pointer.
 51687109        ArrayBaseExtensions.EnsureMinimumSize(ref _shapes, blockPointer);
 110
 51687111        var coordinateBlockSize = 8;
 51687112        if (_elevation != null)
 24113        {
 24114            coordinateBlockSize += 4;
 24115        }
 116
 51687117        using var enumerator = shape.GetEnumerator();
 51687118        var count = 0;
 51687119        (int x, int y, int? eOffset) previous = (int.MaxValue, int.MaxValue, null);
 126361120        while (enumerator.MoveNext())
 74674121        {
 74674122            var current = enumerator.Current;
 74674123            var (x, y) =
 74674124                TileStatic.ToLocalTileCoordinates(_zoom, _tileId, current.longitude, current.latitude, resolution);
 74674125            int? eOffset = null;
 74674126            var e = current.e ?? 0;
 74674127            if (_elevation != null)
 15128            {
 15129                eOffset = (int)(e * 10) - _elevation.Value;
 15130            }
 131
 132            // make sure there is space for this coordinate.
 74674133            ArrayBaseExtensions.EnsureMinimumSize(ref _shapes, pointer + coordinateBlockSize);
 134
 135            // store coordinate.
 74674136            if (count == 0)
 21035137            {
 138                // first coordinate.
 21035139                pointer += (uint)_shapes.SetDynamicInt32(pointer, x);
 21035140                pointer += (uint)_shapes.SetDynamicInt32(pointer, y);
 21035141                if (eOffset != null)
 7142                {
 7143                    pointer += (uint)_shapes.SetDynamicInt32(pointer, eOffset.Value);
 7144                }
 21035145            }
 146            else
 53639147            {
 148                // calculate diff and then store.
 53639149                var diffX = x - previous.x;
 53639150                var diffY = y - previous.y;
 53639151                pointer += (uint)_shapes.SetDynamicInt32(pointer, diffX);
 53639152                pointer += (uint)_shapes.SetDynamicInt32(pointer, diffY);
 53639153                if (eOffset != null)
 8154                {
 8155                    if (previous.eOffset == null)
 0156                    {
 0157                        throw new ArgumentException("Not all points have elevation set.");
 158                    }
 159
 8160                    var diffE = eOffset.Value - previous.eOffset.Value;
 8161                    pointer += (uint)_shapes.SetDynamicInt32(pointer, diffE);
 8162                }
 53639163            }
 164
 74674165            count++;
 166
 74674167            if (count == 255)
 1168            {
 169                // start a new block, assign 255.
 1170                _shapes[(int)blockPointer] = 255;
 1171                blockPointer = pointer;
 1172                pointer = blockPointer + 1;
 1173                count = 0;
 1174            }
 175
 74674176            previous = (x, y, eOffset);
 74674177        }
 178
 179        // a block is still open, close it.
 51687180        _shapes[(int)blockPointer] = (byte)count;
 51687181        _nextShapePointer = pointer;
 182
 51687183        return originalPointer;
 51687184    }
 185
 186    internal IEnumerable<(double longitude, double latitude, float? e)> GetShape(uint? pointer)
 1295378187    {
 1295378188        if (pointer == null)
 119189        {
 119190            yield break;
 191        }
 192
 1295259193        var p = pointer.Value;
 194
 195        const int resolution = (1 << TileResolutionInBits) - 1;
 1295259196        var count = -1;
 1295259197        (int x, int y, int? eOffset) previous = (int.MaxValue, int.MaxValue, null);
 1295260198        while (true)
 1295260199        {
 1295260200            count = _shapes[(int)p];
 1295260201            p++;
 202
 5305896203            for (var i = 0; i < count; i++)
 1358711204            {
 1358711205                p += (uint)_shapes.GetDynamicInt32(p, out var x);
 1358711206                p += (uint)_shapes.GetDynamicInt32(p, out var y);
 1358711207                int? eOffset = null;
 1358711208                if (_elevation != null)
 16209                {
 16210                    p += (uint)_shapes.GetDynamicInt32(p, out var e);
 16211                    eOffset = e;
 16212                }
 213
 1358711214                if (i > 0)
 939846215                {
 939846216                    x = previous.x + x;
 939846217                    y = previous.y + y;
 939846218                    if (_elevation != null)
 8219                    {
 8220                        if (previous.eOffset == null)
 0221                        {
 0222                            throw new ArgumentException("Not all points have elevation set.");
 223                        }
 224
 8225                        eOffset = previous.eOffset.Value + eOffset;
 8226                    }
 939846227                }
 228
 1358711229                int? elevation = null;
 1358711230                if (_elevation != null)
 16231                {
 16232                    if (eOffset == null)
 0233                    {
 0234                        throw new ArgumentException("Not all points have elevation set.");
 235                    }
 236
 16237                    elevation = _elevation.Value + eOffset.Value;
 16238                }
 239
 1358711240                TileStatic.FromLocalTileCoordinates(_zoom, _tileId, x, y, resolution, out var longitude,
 1358711241                    out var latitude);
 1358711242                yield return (longitude, latitude, elevation / 10.0f);
 243
 1357688244                previous = (x, y, eOffset);
 1357688245            }
 246
 2588473247            if (count < 255) break;
 1248        }
 1294236249    }
 250
 251    private void WriteGeoTo(Stream stream)
 8252    {
 8253        stream.WriteVarInt32Nullable(_elevation);
 254
 255        // write vertex locations.
 8256        var coordinateSize = CoordinateSizeInBytes * 2;
 8257        if (_elevation != null)
 2258        {
 2259            coordinateSize += ElevationSizeInBytes;
 2260        }
 261
 8262        var coordinateBytes = _nextVertexId * coordinateSize;
 184263        for (var i = 0; i < coordinateBytes; i++)
 84264        {
 84265            stream.WriteByte(_coordinates[i]);
 84266        }
 267
 268        // write shape locations.
 8269        stream.WriteVarUInt32(_nextShapePointer);
 74270        for (var i = 0; i < _nextShapePointer; i++)
 29271        {
 29272            stream.WriteByte(_shapes[i]);
 29273        }
 8274    }
 275
 276    private void ReadGeoFrom(Stream stream)
 8277    {
 8278        _elevation = stream.ReadVarInt32Nullable();
 279
 280        // read vertex locations.
 8281        var coordinateSize = CoordinateSizeInBytes * 2;
 8282        if (_elevation != null)
 2283        {
 2284            coordinateSize += ElevationSizeInBytes;
 2285        }
 286
 8287        var coordinateBytes = _nextVertexId * coordinateSize;
 8288        Array.Resize(ref _coordinates, (int)coordinateBytes);
 184289        for (var i = 0; i < coordinateBytes; i++)
 84290        {
 84291            _coordinates[i] = (byte)stream.ReadByte();
 84292        }
 293
 8294        _nextShapePointer = stream.ReadVarUInt32();
 8295        Array.Resize(ref _shapes, (int)_nextShapePointer);
 74296        for (var i = 0; i < _nextShapePointer; i++)
 29297        {
 29298            _shapes[i] = (byte)stream.ReadByte();
 29299        }
 8300    }
 301
 302    private void ReadGeoFrom(byte[] data, ref int offset)
 0303    {
 0304        _elevation = BitCoderBuffer.GetVarInt32Nullable(data, ref offset);
 305
 0306        var coordinateSize = CoordinateSizeInBytes * 2;
 0307        if (_elevation != null)
 0308        {
 0309            coordinateSize += ElevationSizeInBytes;
 0310        }
 311
 0312        var coordinateBytes = (int)(_nextVertexId * coordinateSize);
 0313        Array.Resize(ref _coordinates, coordinateBytes);
 0314        Buffer.BlockCopy(data, offset, _coordinates, 0, coordinateBytes);
 0315        offset += coordinateBytes;
 316
 0317        _nextShapePointer = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0318        Array.Resize(ref _shapes, (int)_nextShapePointer);
 0319        Buffer.BlockCopy(data, offset, _shapes, 0, (int)_nextShapePointer);
 0320        offset += (int)_nextShapePointer;
 0321    }
 322
 323    private void WriteGeoTo(byte[] data, ref int offset)
 0324    {
 0325        BitCoderBuffer.SetVarInt32Nullable(data, ref offset, _elevation);
 326
 0327        var coordinateSize = CoordinateSizeInBytes * 2;
 0328        if (_elevation != null)
 0329        {
 0330            coordinateSize += ElevationSizeInBytes;
 0331        }
 332
 0333        var coordinateBytes = (int)(_nextVertexId * coordinateSize);
 0334        Buffer.BlockCopy(_coordinates, 0, data, offset, coordinateBytes);
 0335        offset += coordinateBytes;
 336
 0337        BitCoderBuffer.SetVarUInt32(data, ref offset, _nextShapePointer);
 0338        Buffer.BlockCopy(_shapes, 0, data, offset, (int)_nextShapePointer);
 0339        offset += (int)_nextShapePointer;
 0340    }
 341}

/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.Serialization.cs

#LineLine coverage
 1using System;
 2using System.IO;
 3using Itinero.IO;
 4
 5namespace Itinero.Network.Tiles;
 6
 7internal partial class NetworkTile
 8{
 9    public void WriteTo(Stream stream)
 810    {
 11        const int version = 1;
 812        stream.WriteVarInt32(version);
 13
 14        // write tile id/zoom.
 815        stream.WriteVarInt32(_zoom);
 816        stream.WriteVarUInt32(_tileId);
 817        stream.WriteGuid(_edgeTypeMapId);
 18
 19        // write vertices and edges.
 820        this.WriteEdgesAndVerticesTo(stream);
 21
 22        // write attributes.
 823        this.WriteAttributesTo(stream);
 24
 25        // write shapes.
 826        this.WriteGeoTo(stream);
 27
 28        // write turn costs.
 829        this.WriteTurnCostsTo(stream);
 830    }
 31
 32    public static NetworkTile ReadFrom(Stream stream)
 833    {
 834        var version = stream.ReadVarInt32();
 835        if (version != 1)
 036        {
 037            throw new InvalidDataException("Cannot deserialize tiles: Invalid version #.");
 38        }
 39
 40        // read tile id.
 841        var zoom = stream.ReadVarInt32();
 842        var tileId = stream.ReadVarUInt32();
 843        var edgeTypeMapId = stream.ReadGuid();
 44
 45        // create the tile.
 846        var graphTile = new NetworkTile(zoom, tileId, edgeTypeMapId);
 47
 48        // read vertices and edges.
 849        graphTile.ReadEdgesAndVerticesFrom(stream);
 50
 51        // read attributes.
 852        graphTile.ReadAttributesFrom(stream);
 53
 54        // read shapes.
 855        graphTile.ReadGeoFrom(stream);
 56
 57        // read turn costs.
 858        graphTile.ReadTurnCostsFrom(stream);
 59
 860        return graphTile;
 861    }
 62
 63    internal static NetworkTile ReadFromBuffer(byte[] data, ref int offset)
 064    {
 065        var version = BitCoderBuffer.GetVarInt32(data, ref offset);
 066        if (version != 1)
 067        {
 068            throw new InvalidDataException("Cannot deserialize tiles: Invalid version #.");
 69        }
 70
 071        var zoom = BitCoderBuffer.GetVarInt32(data, ref offset);
 072        var tileId = BitCoderBuffer.GetVarUInt32(data, ref offset);
 073        var edgeTypeMapId = BitCoderBuffer.GetGuid(data, ref offset);
 74
 075        var graphTile = new NetworkTile(zoom, tileId, edgeTypeMapId);
 76
 077        graphTile.ReadEdgesAndVerticesFrom(data, ref offset);
 078        graphTile.ReadAttributesFrom(data, ref offset);
 079        graphTile.ReadGeoFrom(data, ref offset);
 080        graphTile.ReadTurnCostsFrom(data, ref offset);
 81
 082        return graphTile;
 083    }
 84
 85    public static NetworkTile ReadFrom(byte[] data, int offset)
 086    {
 087        return ReadFromBuffer(data, ref offset);
 088    }
 89
 90    public byte[] ToBytes()
 091    {
 092        var maxSize = this.GetSerializedSizeUpperBound();
 093        var buffer = new byte[maxSize];
 094        var offset = 0;
 095        this.WriteToBuffer(buffer, ref offset);
 096        if (offset == maxSize) return buffer;
 097        var result = new byte[offset];
 098        Buffer.BlockCopy(buffer, 0, result, 0, offset);
 099        return result;
 0100    }
 101
 102    internal void WriteToBuffer(byte[] data, ref int offset)
 0103    {
 104        const int version = 1;
 0105        BitCoderBuffer.SetVarInt32(data, ref offset, version);
 0106        BitCoderBuffer.SetVarInt32(data, ref offset, _zoom);
 0107        BitCoderBuffer.SetVarUInt32(data, ref offset, _tileId);
 0108        BitCoderBuffer.SetGuid(data, ref offset, _edgeTypeMapId);
 109
 0110        this.WriteEdgesAndVerticesTo(data, ref offset);
 0111        this.WriteAttributesTo(data, ref offset);
 0112        this.WriteGeoTo(data, ref offset);
 0113        this.WriteTurnCostsTo(data, ref offset);
 0114    }
 115
 116    internal int GetSerializedSizeUpperBound()
 0117    {
 0118        var size = 5 + 5 + 5 + 16;
 119
 0120        size += 5 + (int)_nextVertexId * 5;
 0121        size += 5 + (int)_nextEdgeId;
 0122        size += 5 + (int)_nextCrossTileId * 5;
 123
 0124        size += 5 + (int)_nextAttributePointer;
 0125        size += 5;
 0126        for (var i = 0; i < _nextStringId; i++)
 0127        {
 0128            size += 8 + System.Text.Encoding.Unicode.GetByteCount(_strings[i]);
 0129        }
 130
 0131        size += 5;
 0132        var coordinateSize = CoordinateSizeInBytes * 2;
 0133        if (_elevation != null) coordinateSize += ElevationSizeInBytes;
 0134        size += (int)(_nextVertexId * coordinateSize);
 0135        size += 5 + (int)_nextShapePointer;
 136
 0137        size += 5 + _turnCostPointers.Length * 5;
 0138        size += 5 + (int)_turnCostPointer;
 139
 0140        return size;
 0141    }
 142}

/home/runner/work/routing2/routing2/src/Itinero/Network/Tiles/NetworkTile.TurnCosts.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using System.Linq;
 5using Itinero.IO;
 6using Itinero.Network.Storage;
 7using Itinero.Network.TurnCosts;
 8
 9namespace Itinero.Network.Tiles;
 10
 11internal partial class NetworkTile
 12{
 50213    private uint _turnCostPointer = 0;
 50214    private uint[] _turnCostPointers = new uint[0];
 50215    private byte[] _turnCosts = new byte[0];
 16
 17    internal void AddTurnCosts(VertexId vertex, uint turnCostType,
 18        EdgeId[] edges, uint[,] costs, IEnumerable<(string key, string value)> attributes,
 19        IEnumerable<EdgeId>? prefix = null)
 102920    {
 102921        prefix ??= ArraySegment<EdgeId>.Empty;
 22
 102923        if (edges.Length > OrderCoder.MaxOrderHeadTail)
 024        {
 025            throw new ArgumentException(
 026                $"Cannot add turn costs for vertices with more than {OrderCoder.MaxOrderHeadTail} edges.");
 27        }
 28
 29        // enumerate the edges associated with the vertex.
 102930        var enumerator = new NetworkTileEnumerator();
 102931        enumerator.MoveTo(this);
 102932        if (!enumerator.MoveTo(vertex))
 033        {
 034            throw new ArgumentException($"Cannot add turn costs to a vertex that doesn't exist.",
 035                nameof(vertex));
 36        }
 37
 38        // determine max existing order, perhaps there are other turn costs already.
 102939        var orders = new byte?[edges.Length];
 102940        var max = -1;
 318341        while (enumerator.MoveNext())
 215442        {
 327243            if (!enumerator.TailOrder.HasValue) continue;
 106844            if (enumerator.TailOrder.Value <= max) continue;
 45
 100446            max = enumerator.TailOrder.Value;
 100447        }
 48
 49        // assign missing orders if any.
 102950        enumerator.Reset();
 102951        var next = max + 1;
 318352        while (enumerator.MoveNext())
 215453        {
 54            // only assign orders of edges that are used.
 215455            var i = Array.IndexOf(edges, enumerator.EdgeId);
 225056            if (i == -1) continue;
 57
 58            // edge is used, assign or reuse existing.
 205859            var order = enumerator.TailOrder;
 205860            if (order == null)
 104361            {
 62                // get next order.
 104363                order = (byte)next;
 104364                next++;
 65
 66                // set order, it's different.
 104367                if (enumerator.Forward)
 52968                {
 69                    // if the edge is forward the tail in the enumerator is also the tail in the edge.
 52970                    this.SetTailHeadOrder(enumerator.EdgePointer, order, enumerator.HeadOrder);
 52971                }
 72                else
 51473                {
 74                    // if the edge is backward the tail in the enumerator is head in the edge.
 51475                    this.SetTailHeadOrder(enumerator.EdgePointer, enumerator.TailOrder, order);
 51476                }
 104377            }
 78
 205879            orders[i] = order;
 205880        }
 81
 82        // reversed order array.
 102983        var count = next;
 102984        var reversedOrders = new byte?[count];
 617485        for (var i = 0; i < orders.Length; i++)
 205886        {
 205887            var order = orders[i];
 205888            if (order == null)
 089            {
 090                continue;
 91            }
 92
 205893            reversedOrders[order.Value] = (byte)i;
 205894        }
 95
 96        // make sure there is space in the pointers table.
 97        // and initialize new slots with null.
 112898        while (_turnCostPointers.Length <= vertex.LocalId)
 9999        {
 99100            Array.Resize(ref _turnCostPointers, (int)_nextVertexId);
 99101        }
 102
 103        // make sure there is space in the turn cost array.
 104        // and initialize new slots with null.
 1029105        var maxLength = _turnCostPointer + 5 + 1 + (count * count * 5) + 5;
 1913106        while (_turnCosts.Length <= maxLength)
 884107        {
 884108            Array.Resize(ref _turnCosts, _turnCosts.Length + DefaultSizeIncrease);
 884109        }
 110
 111        // update pointer to reflect new data.
 1029112        var previousPointer = _turnCostPointers[(int)vertex.LocalId].DecodeNullableData();
 1029113        _turnCostPointers[(int)vertex.LocalId] = _turnCostPointer.EncodeToNullableData();
 114
 115        // write turn cost types.
 1029116        _turnCostPointer += _turnCosts.SetDynamicUInt32(_turnCostPointer, turnCostType);
 117
 118        // write attributes.
 1029119        var a = this.SetAttributes(attributes, null);
 1029120        _turnCostPointer += _turnCosts.SetDynamicUInt32(_turnCostPointer, a);
 121
 122        // write prefix sequence.
 1029123        var prefixEdges = new List<EdgeId>(prefix);
 1029124        _turnCostPointer += _turnCosts.SetDynamicUInt32(_turnCostPointer, (uint)prefixEdges.Count);
 3087125        foreach (var prefixEdge in prefixEdges)
 0126        {
 0127            if (prefixEdge.TileId == _tileId)
 0128            {
 0129                _turnCostPointer += _turnCosts.SetDynamicInt32(_turnCostPointer, (int)prefixEdge.LocalId);
 0130            }
 131            else
 0132            {
 0133                _turnCostPointer += _turnCosts.SetDynamicInt32(_turnCostPointer, (int)-(prefixEdge.LocalId + 1));
 0134                _turnCostPointer += _turnCosts.SetDynamicUInt32(_turnCostPointer, prefixEdge.TileId);
 0135            }
 0136        }
 137
 138        // write turn costs.
 1029139        _turnCosts[(int)_turnCostPointer] = (byte)count;
 1029140        _turnCostPointer++;
 6216141        for (var x = 0; x < count; x++)
 2079142        {
 2079143            var xOrder = reversedOrders[x];
 12600144            for (var y = 0; y < count; y++)
 4221145            {
 4221146                var yOrder = reversedOrders[y];
 147
 148                // get cost from original matrix.
 4221149                uint cost = 0;
 4221150                if (xOrder != null && yOrder != null)
 4116151                {
 4116152                    cost = costs[xOrder.Value, yOrder.Value];
 4116153                }
 154
 155                // write cost.
 4221156                _turnCostPointer += (uint)_turnCosts.SetDynamicUInt32(_turnCostPointer, cost);
 4221157            }
 2079158        }
 159
 160        // write previous turn cost pointer at the end.
 1029161        _turnCostPointer +=
 1029162            (uint)_turnCosts.SetDynamicUInt32(_turnCostPointer, previousPointer.EncodeAsNullableData());
 1029163    }
 164
 165    internal IEnumerable<(uint turnCostType, IEnumerable<(string key, string value)> attributes, uint cost,
 166            IEnumerable<EdgeId> prefixEdges)>
 167        GetTurnCosts(VertexId vertex, byte fromOrder, byte toOrder)
 2038168    {
 2038169        if (_turnCostPointers.Length <= vertex.LocalId)
 0170        {
 0171            yield break;
 172        }
 173
 2038174        var pointerNullable = _turnCostPointers[(int)vertex.LocalId].DecodeNullableData();
 2038175        if (pointerNullable == null)
 0176        {
 0177            yield break;
 178        }
 179
 2038180        var pointer = pointerNullable.Value;
 4051181        while (true)
 4051182        {
 183            // return turn cost type.
 4051184            pointer += (uint)_turnCosts.GetDynamicUInt32(pointer, out var turnCostType);
 185
 186            // read attributes.
 4051187            pointer += (uint)_turnCosts.GetDynamicUInt32(pointer, out var a);
 4051188            var attributes = this.GetAttributes(a);
 189
 190            // read prefix edges.
 4051191            IEnumerable<EdgeId> prefixEdges = ArraySegment<EdgeId>.Empty;
 4051192            pointer += (uint)_turnCosts.GetDynamicUInt32(pointer, out var prefixEdgeCount);
 4051193            if (prefixEdgeCount > 0)
 0194            {
 0195                var prefixEdgesList = new List<EdgeId>();
 0196                while (prefixEdgeCount > 0)
 0197                {
 0198                    pointer += (uint)_turnCosts.GetDynamicInt32(pointer, out var signedLocalId);
 0199                    if (signedLocalId >= 0)
 0200                    {
 0201                        prefixEdgesList.Add(new EdgeId(this.TileId, (uint)signedLocalId));
 0202                    }
 203                    else
 0204                    {
 0205                        pointer += (uint)_turnCosts.GetDynamicUInt32(pointer, out var tileId);
 0206                        prefixEdgesList.Add(new EdgeId(tileId, (uint)-signedLocalId - 1));
 0207                    }
 208
 0209                    prefixEdgeCount--;
 0210                }
 211
 0212                prefixEdges = prefixEdgesList;
 0213            }
 214
 215            // read turn cost table.
 4051216            var max = _turnCosts[(int)pointer];
 4051217            pointer++;
 218
 24250219            for (var x = 0; x < max; x++)
 8101220            {
 48514221                for (var y = 0; y < max; y++)
 16183222                {
 16183223                    pointer += (uint)_turnCosts.GetDynamicUInt32(pointer, out var cost);
 16183224                    if (fromOrder != x || toOrder != y)
 12132225                    {
 12132226                        continue;
 227                    }
 228
 4051229                    if (cost != 0)
 2040230                    {
 2040231                        yield return (turnCostType, attributes, cost, prefixEdges);
 2013232                    }
 4024233                }
 8074234            }
 235
 236            // get pointer to next turn cost table.
 4024237            _turnCosts.GetDynamicUInt32(pointer, out var p);
 4024238            pointerNullable = p.DecodeNullableData();
 4024239            if (pointerNullable == null)
 2011240            {
 2011241                break;
 242            }
 243
 2013244            pointer = pointerNullable.Value;
 2013245        }
 2011246    }
 247
 248    internal void SetTailHeadOrder(uint pointer, byte? tailOrder, byte? headOrder)
 1043249    {
 250        // skip over vertices and next-pointers.
 1043251        uint size = this.DecodeVertex(pointer, out _, out var t1);
 1043252        pointer += size;
 1043253        size = this.DecodeVertex(pointer, out _, out var t2);
 1043254        pointer += size;
 1043255        size = this.DecodePointer(pointer, out _);
 1043256        pointer += size;
 1043257        size = this.DecodePointer(pointer, out _);
 1043258        pointer += size;
 259
 260        // skip edge id if needed.
 1043261        if (t1 != t2)
 40262        {
 40263            size = _edges.GetDynamicUInt32(pointer, out _);
 40264            pointer += size;
 40265        }
 266
 267        // skip over length/type.
 1043268        size = this.DecodeEdgePointerId(pointer, out _);
 1043269        pointer += size;
 1043270        size = this.DecodeEdgePointerId(pointer, out _);
 1043271        pointer += size;
 272
 273        // get existing head/tail order.
 1043274        byte? existingTailOrder = null;
 1043275        byte? existingHeadOrder = null;
 1043276        this.GetTailHeadOrder(pointer, ref existingTailOrder, ref existingHeadOrder);
 277
 278        // set tail order if there is a value.
 1043279        if (tailOrder.HasValue)
 529280        {
 529281            if (existingTailOrder.HasValue && existingTailOrder.Value != tailOrder.Value)
 0282                throw new InvalidOperationException("An edge tail or head order can only be set once.");
 529283            existingTailOrder = tailOrder;
 529284        }
 285
 286        // set head order if there is a value.
 1043287        if (headOrder.HasValue)
 518288        {
 518289            if (existingHeadOrder.HasValue && existingHeadOrder.Value != headOrder.Value)
 0290                throw new InvalidOperationException("An edge tail or head order can only be set once.");
 518291            existingHeadOrder = headOrder;
 518292        }
 293
 1043294        _edges.SetTailHeadOrder(pointer, existingTailOrder, existingHeadOrder);
 1043295    }
 296
 297    private void WriteTurnCostsTo(Stream stream)
 8298    {
 8299        stream.WriteVarUInt32((uint)_turnCostPointers.Length);
 16300        for (var i = 0; i < _turnCostPointers.Length; i++)
 0301        {
 0302            stream.WriteVarUInt32(_turnCostPointers[i]);
 0303        }
 304
 8305        stream.WriteVarUInt32(_turnCostPointer);
 16306        for (var i = 0; i < _turnCostPointer; i++)
 0307        {
 0308            stream.WriteByte(_turnCosts[i]);
 0309        }
 8310    }
 311
 312    private void ReadTurnCostsFrom(Stream stream)
 8313    {
 8314        var turnCostPointersSize = stream.ReadVarUInt32();
 8315        Array.Resize(ref _turnCostPointers, (int)turnCostPointersSize);
 16316        for (var i = 0; i < turnCostPointersSize; i++)
 0317        {
 0318            _turnCostPointers[i] = stream.ReadVarUInt32();
 0319        }
 320
 8321        _turnCostPointer = stream.ReadVarUInt32();
 8322        Array.Resize(ref _turnCosts, (int)_turnCostPointer);
 16323        for (var i = 0; i < _turnCostPointer; i++)
 0324        {
 0325            _turnCosts[i] = (byte)stream.ReadByte();
 0326        }
 8327    }
 328
 329    private void ReadTurnCostsFrom(byte[] data, ref int offset)
 0330    {
 0331        var turnCostPointersSize = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0332        Array.Resize(ref _turnCostPointers, (int)turnCostPointersSize);
 0333        for (var i = 0; i < turnCostPointersSize; i++)
 0334        {
 0335            _turnCostPointers[i] = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0336        }
 337
 0338        _turnCostPointer = BitCoderBuffer.GetVarUInt32(data, ref offset);
 0339        Array.Resize(ref _turnCosts, (int)_turnCostPointer);
 0340        Buffer.BlockCopy(data, offset, _turnCosts, 0, (int)_turnCostPointer);
 0341        offset += (int)_turnCostPointer;
 0342    }
 343
 344    private void WriteTurnCostsTo(byte[] data, ref int offset)
 0345    {
 0346        BitCoderBuffer.SetVarUInt32(data, ref offset, (uint)_turnCostPointers.Length);
 0347        for (var i = 0; i < _turnCostPointers.Length; i++)
 0348        {
 0349            BitCoderBuffer.SetVarUInt32(data, ref offset, _turnCostPointers[i]);
 0350        }
 351
 0352        BitCoderBuffer.SetVarUInt32(data, ref offset, _turnCostPointer);
 0353        Buffer.BlockCopy(_turnCosts, 0, data, offset, (int)_turnCostPointer);
 0354        offset += (int)_turnCostPointer;
 0355    }
 356}