private static IEnumerable <uint> Add(this TiledBarrierGraph graph, IEnumerable <OsmGeo> osmGeos, Func <TagsCollectionBase, bool> isBarrier) { var uncoveredTiles = new HashSet <uint>(); // collect all nodes with more than one barrier way. var nodes = new Dictionary <long, (double longitude, double latitude)?>(); var vertexNodes = new Dictionary <long, int>(); foreach (var osmGeo in osmGeos) { if (!(osmGeo is Way way)) { continue; } if (way.Nodes == null) { continue; } if (!isBarrier(way.Tags)) { continue; } for (var n = 0; n < way.Nodes.Length; n++) { var nodeId = way.Nodes[n]; if (graph.TryGetVertex(nodeId, out var vertex)) { // node already there as a vertex. vertexNodes[nodeId] = vertex; } else { // not yet a vertex. // keep first, last and reused nodes are intersections. if (n == 0 || n == way.Nodes.Length - 1 || nodes.ContainsKey(nodeId)) { vertexNodes[nodeId] = int.MaxValue; } } nodes[nodeId] = null; } } // add all vertices new vertices and store node locations. using var enumerator = osmGeos.GetEnumerator(); var hasNext = true; while (hasNext) { hasNext = enumerator.MoveNext(); if (!hasNext) { break; } if (!(enumerator.Current is Node node)) { break; } if (node.Id == null || node.Latitude == null || node.Longitude == null) { continue; } if (graph.TryGetVertex(node.Id.Value, out _)) { continue; } if (!nodes.ContainsKey(node.Id.Value)) { continue; // not part of a barrier way. } nodes[node.Id.Value] = (node.Longitude.Value, node.Latitude.Value); var tile = TileStatic.WorldTileLocalId(node.Longitude.Value, node.Latitude.Value, graph.Zoom); if (!vertexNodes.ContainsKey(node.Id.Value) && graph.HasTile(tile)) { continue; // node is not a vertex and inside a loaded tile. } var vertex = graph.AddVertex(node.Longitude.Value, node.Latitude.Value, node.Id.Value); vertexNodes[node.Id.Value] = vertex; if (!graph.HasTile(tile)) { uncoveredTiles.Add(tile); } } // add all edges. var shape = new List <(double longitude, double latitude)>(); while (hasNext) { if (!hasNext) { break; } if (!(enumerator.Current is Way way)) { break; } if (way.Nodes == null || way.Tags == null || way.Id == null) { hasNext = enumerator.MoveNext(); continue; } if (!isBarrier(way.Tags)) { hasNext = enumerator.MoveNext(); continue; } if (graph.HasWay(way.Id.Value)) { hasNext = enumerator.MoveNext(); continue; } // way is a barrier, add it as one or more edges. shape.Clear(); var vertex1 = int.MaxValue; foreach (var node in way.Nodes) { if (!vertexNodes.TryGetValue(node, out var vertex)) { if (!nodes.TryGetValue(node, out var nodeLocation)) { throw new InvalidDataException( $"Node {node} in way {way.Id} not found!"); } if (nodeLocation == null) { OsmSharp.Logging.Logger.Log(nameof(TiledBarrierGraphBuilder), TraceEventType.Warning, $"Node location for node {node} in way {way.Id} not found!"); } else { shape.Add(nodeLocation.Value); } continue; } else if (vertex == int.MaxValue) { OsmSharp.Logging.Logger.Log(nameof(TiledBarrierGraphBuilder), TraceEventType.Warning, $"Node {node} in way {way.Id} not found in tile!"); continue; } if (vertex1 == int.MaxValue) { vertex1 = vertex; continue; } graph.AddEdgeFlattened(vertex1, vertex, shape, way.Tags, way.Id.Value); vertex1 = vertex; shape.Clear(); } hasNext = enumerator.MoveNext(); } return(uncoveredTiles); }