/// <summary> /// Gets the node with given id. /// </summary> public Node GetNode(long id) { var tile = new Tile(0, 0, 0); var index = LoadIndex(OsmGeoType.Node, tile); while (index != null && index.TryGetMask(id, out var mask)) { var subTiles = tile.SubTilesForMask2(mask); var subTile = subTiles.First(); if (subTile.Zoom == _zoom) { // load data and find node. var stream = DatabaseCommon.LoadTile(_path, OsmGeoType.Node, subTile, _compressed); if (stream == null) { Log.Warning($"Could not find subtile, it should be there: {subTile}"); return(null); } using (stream) { var source = new OsmSharp.Streams.BinaryOsmStreamSource(stream); while (source.MoveNext(false, true, true)) { var current = source.Current(); if (current.Id == id) { return(current as Node); } } } } tile = subTile; index = LoadIndex(OsmGeoType.Node, tile); } return(null); }
/// <summary> /// Gets a complete tile with complete ways and complete first level relations. /// </summary> internal IEnumerable <OsmGeo> GetRouteableTile(Tile tile, Stream stream) { // build a hashset of all nodes in the tile. var nodesInTile = new Dictionary <long, Node>(); using (stream) { if (stream == null) { yield break; } var source = new OsmSharp.Streams.BinaryOsmStreamSource(stream); while (source.MoveNext(false, true, true)) { var current = source.Current(); if (!(current is Node n)) { continue; } if (n.Id == null) { continue; } nodesInTile.Add(n.Id.Value, n); } } // go over all ways and also include all nodes between the first/last node in the tile. // also include one node before or after the first/last node in the tile. var nodesToInclude = new SortedDictionary <long, Node>(); using (stream = DatabaseCommon.LoadTile(_path, OsmGeoType.Way, tile, _compressed)) { if (stream != null) { var source = new OsmSharp.Streams.BinaryOsmStreamSource(stream); while (source.MoveNext(true, false, true)) { var current = source.Current(); var w = current as Way; if (w?.Nodes == null) { continue; } var first = int.MaxValue; var last = -1; for (var n = 0; n < w.Nodes.Length; n++) { var nodeId = w.Nodes[n]; if (!nodesInTile.ContainsKey(nodeId)) { continue; } if (n < first) { first = n; } if (n > last) { last = n; } } if (first == int.MaxValue) { continue; } if (first > 0) { first--; } if (last < w.Nodes.Length - 1) { last++; } for (var n = first; n < last + 1; n++) { var nodeId = w.Nodes[n]; // get node from the nodes in the tile. if (nodesInTile.TryGetValue(nodeId, out var node)) { // node already there. nodesToInclude[nodeId] = node; continue; } // node is not in the tile, get it from the db if it's not included already.. if (!nodesToInclude.ContainsKey(nodeId)) { // not not yet there, get it. node = this.GetNode(nodeId); nodesToInclude[nodeId] = node; } } } } } var hasData = nodesToInclude.Count > 0; if (!hasData) { yield break; } // return all the nodes. foreach (var node in nodesToInclude.Values) { yield return(node); } // returns all the ways that have at least one node. using (stream = DatabaseCommon.LoadTile(_path, OsmGeoType.Way, tile, _compressed)) { if (stream != null) { var source = new OsmSharp.Streams.BinaryOsmStreamSource(stream); while (source.MoveNext(true, false, true)) { var current = source.Current(); var w = current as Way; if (w == null) { continue; } // trim nodes. var trimmedNodes = new List <long>(); foreach (var n in w.Nodes) { if (!nodesToInclude.TryGetValue(n, out _)) { continue; } trimmedNodes.Add(n); } w.Nodes = trimmedNodes.ToArray(); if (w.Nodes.Length == 0) { continue; } yield return(w); } } } // return all relations. using (stream = DatabaseCommon.LoadTile(_path, OsmGeoType.Relation, tile, _compressed)) { if (stream != null) { var source = new OsmSharp.Streams.BinaryOsmStreamSource(stream); while (source.MoveNext(true, true, false)) { var current = source.Current(); var r = current as Relation; yield return(r); } } } }
/// <summary> /// Builds the database and writes the structure to the given by by splitting the given zoom level. /// </summary> private static List <Tile> Build(string path, uint maxZoom, Tile tile, bool compressed = false) { // split nodes and return index and non-empty tiles. List <Tile> nonEmptyTiles = null; Index nodeIndex = null; var nodeFile = DatabaseCommon.BuildPathToTile(path, OsmGeoType.Node, tile, compressed); if (!FileSystemFacade.FileSystem.Exists(nodeFile)) { Log.Logger.Warning("Tile {0}/{1}/{2} not found: {3}", tile.Zoom, tile.X, tile.Y, nodeFile); return(new List <Tile>()); } using (var nodeStream = DatabaseCommon.LoadTile(path, OsmGeoType.Node, tile, compressed)) { var nodeSource = new OsmSharp.Streams.BinaryOsmStreamSource(nodeStream); // split nodes and return nodes index and non-empty tiles. nodeIndex = NodeProcessor.Process(nodeSource, path, maxZoom, tile, out nonEmptyTiles, out _, compressed); } // build the ways index. Index wayIndex = null; var wayFile = DatabaseCommon.BuildPathToTile(path, OsmGeoType.Way, tile, compressed); if (FileSystemFacade.FileSystem.Exists(wayFile)) { using (var wayStream = DatabaseCommon.LoadTile(path, OsmGeoType.Way, tile, compressed)) { var waySource = new OsmSharp.Streams.BinaryOsmStreamSource(wayStream); if (waySource.MoveNext()) { wayIndex = WayProcessor.Process(waySource, path, maxZoom, tile, nodeIndex, compressed); } } } // build the relations index. Index relationIndex = null; var relationFile = DatabaseCommon.BuildPathToTile(path, OsmGeoType.Relation, tile, compressed); if (FileSystemFacade.FileSystem.Exists(relationFile)) { using (var relationStream = DatabaseCommon.LoadTile(path, OsmGeoType.Relation, tile, compressed)) { var relationSource = new OsmSharp.Streams.BinaryOsmStreamSource(relationStream); if (relationSource.MoveNext()) { relationIndex = RelationProcessor.Process(relationSource, path, maxZoom, tile, nodeIndex, wayIndex, compressed); } } } // write the indexes to disk. nodeIndex.Write(FileSystemFacade.FileSystem.Combine(path, tile.Zoom.ToString(), tile.X.ToString(), tile.Y.ToString() + ".nodes.idx")); wayIndex?.Write(FileSystemFacade.FileSystem.Combine(path, tile.Zoom.ToString(), tile.X.ToString(), tile.Y.ToString() + ".ways.idx")); relationIndex?.Write(FileSystemFacade.FileSystem.Combine(path, tile.Zoom.ToString(), tile.X.ToString(), tile.Y.ToString() + ".relations.idx")); // var actions = new List<Action> // { // () => nodeIndex.Write(FileSystemFacade.FileSystem.Combine(path, tile.Zoom.ToString(), // tile.X.ToString(), tile.Y.ToString() + ".nodes.idx")), // () => wayIndex?.Write(FileSystemFacade.FileSystem.Combine(path, tile.Zoom.ToString(), // tile.X.ToString(), tile.Y.ToString() + ".ways.idx")), // () => relationIndex?.Write(FileSystemFacade.FileSystem.Combine(path, tile.Zoom.ToString(), // tile.X.ToString(), tile.Y.ToString() + ".relations.idx")) // }; // System.Threading.Tasks.Parallel.ForEach(actions, (a) => a()); if (FileSystemFacade.FileSystem.Exists(nodeFile)) { FileSystemFacade.FileSystem.Delete(nodeFile); } if (FileSystemFacade.FileSystem.Exists(wayFile)) { FileSystemFacade.FileSystem.Delete(wayFile); } if (FileSystemFacade.FileSystem.Exists(relationFile)) { FileSystemFacade.FileSystem.Delete(relationFile); } return(nonEmptyTiles); }