/// <summary>
        /// Processes the relations in the given stream. Assumed the current stream position already contains a relation.
        /// </summary>
        /// <param name="source">The source stream.</param>
        /// <param name="path">The based path of the db.</param>
        /// <param name="maxZoom">The maximum zoom.</param>
        /// <param name="tile">The tile being split.</param>
        /// <param name="nodeIndex">The node index.</param>
        /// <param name="wayIndex">The way index.</param>
        /// <param name="compressed">A flag to allow compression of target files.</param>
        /// <returns>The indexed node id's with a masked zoom.</returns>
        public static Index Process(OsmStreamSource source, string path, uint maxZoom, Tile tile,
                                    Index nodeIndex, Index wayIndex, bool compressed = false)
        {
            try
            {
                // split relations.
                var subtiles = new Dictionary <ulong, Stream>();
                foreach (var subTile in tile.GetSubtilesAt(tile.Zoom + 2))
                {
                    subtiles.Add(subTile.LocalId, null);
                }

                // build the relations index.
                var relationIndex = new Index();
                do
                {
                    var current = source.Current();
                    if (current.Type != OsmGeoType.Relation)
                    {
                        break;
                    }

                    // calculate tile.
                    var r = (current as Relation);
                    if (r?.Members == null)
                    {
                        continue;
                    }

                    int?mask = 0;
                    foreach (var member in r.Members)
                    {
                        if (member == null)
                        {
                            Log.Warning($"Member of relation {r.Id} is null!");
                            continue;
                        }

                        switch (member.Type)
                        {
                        case OsmGeoType.Node:
                            if (nodeIndex != null &&
                                nodeIndex.TryGetMask(member.Id, out var nodeMask))
                            {
                                mask |= nodeMask;
                            }

                            break;

                        case OsmGeoType.Way:
                            if (wayIndex != null &&
                                wayIndex.TryGetMask(member.Id, out var wayMask))
                            {
                                mask |= wayMask;
                            }

                            break;

                        case OsmGeoType.Relation:
                            //mask = null;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }

                        if (mask == null)
                        {
                            // fail fast.
                            break;
                        }
                    }

                    if (mask == null)
                    {
                        // could not determine mask.
                        continue;
                    }

                    // add relation to output(s).
                    foreach (var relationTile in tile.SubTilesForMask2(mask.Value))
                    {
                        // is tile a subtile.
                        if (!subtiles.TryGetValue(relationTile.LocalId, out var stream))
                        {
                            continue;
                        }


                        // initialize stream if needed.
                        if (stream == null)
                        {
                            stream = DatabaseCommon.CreateTile(path, OsmGeoType.Relation, relationTile, compressed);
                            subtiles[relationTile.LocalId] = stream;
                        }

                        // write way.
                        stream.Append(r);
                    }

                    // add way to index.
                    relationIndex.Add(r.Id.Value, mask.Value);
                } while (source.MoveNext());

                // flush/dispose all subtile streams.
                foreach (var subtile in subtiles)
                {
                    if (subtile.Value == null)
                    {
                        continue;
                    }
                    subtile.Value.Flush();
                    subtile.Value.Dispose();
                }

                return(relationIndex);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Unhandled exception in {nameof(RelationProcessor)}.{nameof(Process)}: {ex}");
                throw;
            }
        }
        /// <summary>
        /// Processes the nodes in the given stream until the first on-node object is reached.
        /// </summary>
        /// <param name="source">The source stream.</param>
        /// <param name="path">The based path of the db.</param>
        /// <param name="maxZoom">The maximum zoom.</param>
        /// <param name="tile">The tile being split.</param>
        /// <param name="nonEmptyTiles">The subtiles that have data in them.</param>
        /// <param name="hasNext">A flag indicating if there is still more data.</param>
        /// <param name="compressed">A flag to allow compression of target files.</param>
        /// <returns>The indexed node id's with a masked zoom.</returns>
        public static Index Process(OsmStreamSource source, string path, uint maxZoom, Tile tile,
                                    out List <Tile> nonEmptyTiles, out bool hasNext, bool compressed = false)
        {
            try
            {
                // build the set of possible subtiles.
                var subtiles = new Dictionary <ulong, Stream>();
                foreach (var subTile in tile.GetSubtilesAt(tile.Zoom + 2))
                {
                    subtiles.Add(subTile.LocalId, null);
                }

                // go over all nodes.
                var nodeIndex = new Index();
                hasNext = false;
                while (source.MoveNext())
                {
                    var current = source.Current();
                    if (current.Type != OsmGeoType.Node)
                    {
                        hasNext = true;
                        break;
                    }

                    // calculate tile.
                    var n        = (current as Node);
                    var nodeTile = Tiles.Tile.WorldToTileIndex(n.Latitude.Value, n.Longitude.Value, tile.Zoom + 2);

                    // is tile a subtile.
                    if (!subtiles.TryGetValue(nodeTile.LocalId, out var stream))
                    {
                        continue;
                    }

                    // initialize stream if needed.
                    if (stream == null)
                    {
                        stream = DatabaseCommon.CreateTile(path, OsmGeoType.Node, nodeTile, compressed);
                        subtiles[nodeTile.LocalId] = stream;
                    }

                    // write node.
                    stream.Append(n);

                    // add node to index.
                    nodeIndex.Add(n.Id.Value, nodeTile.BuildMask2());
                }

                // flush/dispose all subtile streams.
                // keep all non-empty tiles.
                nonEmptyTiles = new List <Tile>();
                foreach (var subtile in subtiles)
                {
                    if (subtile.Value == null)
                    {
                        continue;
                    }
                    subtile.Value.Flush();
                    subtile.Value.Dispose();

                    if (tile.Zoom + 2 < maxZoom)
                    {
                        nonEmptyTiles.Add(Tile.FromLocalId(tile.Zoom + 2, subtile.Key));
                    }
                }

                return(nodeIndex);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Unhandled exception in {nameof(NodeProcessor)}.{nameof(Process)}: {ex}");
                throw;
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Processes the ways in the given stream until the first on-way object is reached. Assumed the current stream position already contains a way.
        /// </summary>
        /// <param name="source">The source stream.</param>
        /// <param name="path">The based path of the db.</param>
        /// <param name="maxZoom">The maximum zoom.</param>
        /// <param name="tile">The tile being split.</param>
        /// <param name="nodeIndex">The node index.</param>
        /// <param name="compressed">A flag to allow compression of target files.</param>
        /// <returns>The indexed node id's with a masked zoom.</returns>
        public static Index Process(OsmStreamSource source, string path, uint maxZoom, Tile tile,
                                    Index nodeIndex, bool compressed = false)
        {
            try
            {
                // split ways.
                var subtiles = new Dictionary <ulong, Stream>();
                foreach (var subTile in tile.GetSubtilesAt(tile.Zoom + 2))
                {
                    subtiles.Add(subTile.LocalId, null);
                }

                // build the ways index.
                var wayIndex = new Index();
                do
                {
                    var current = source.Current();
                    if (current.Type != OsmGeoType.Way)
                    {
                        break;
                    }

                    // calculate tile.
                    var w = (current as Way);
                    if (w.Nodes == null)
                    {
                        continue;
                    }

                    var mask = 0;
                    foreach (var node in w.Nodes)
                    {
                        if (nodeIndex.TryGetMask(node, out var nodeMask))
                        {
                            mask |= nodeMask;
                        }
                    }

                    // add way to output(s).
                    foreach (var wayTile in tile.SubTilesForMask2(mask))
                    {
                        // is tile a subtile.
                        if (!subtiles.TryGetValue(wayTile.LocalId, out var stream))
                        {
                            continue;
                        }

                        // initialize stream if needed.
                        if (stream == null)
                        {
                            stream = DatabaseCommon.CreateTile(path, OsmGeoType.Way, wayTile, compressed);
                            subtiles[wayTile.LocalId] = stream;
                        }

                        // write way.
                        stream.Append(w);
                    }

                    // add way to index.
                    wayIndex.Add(w.Id.Value, mask);
                } while (source.MoveNext());

                // flush/dispose all subtile streams.
                foreach (var subtile in subtiles)
                {
                    if (subtile.Value == null)
                    {
                        continue;
                    }
                    subtile.Value.Flush();
                    subtile.Value.Dispose();
                }

                return(wayIndex);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Unhandled exception in {nameof(WayProcessor)}.{nameof(Process)}: {ex}");
                throw;
            }
        }