/// <summary>
        /// Move to the next object.
        /// </summary>
        public override bool MoveNext(bool ignoreNodes, bool ignoreWays, bool ignoreRelations)
        {
            if (_mergedSource == null)
            {
                var mergedSource = new OsmStreamFilterMerge();
                mergedSource.RegisterSource(this.Source);
                mergedSource.RegisterSource(_creations);
                _mergedSource = mergedSource;
            }

            OsmGeo modified;

            while (_mergedSource.MoveNext(ignoreNodes, ignoreWays, ignoreRelations))
            {
                // returns the next out of the merged source of the creations and the source.
                _current = _mergedSource.Current();

                // check for deletions or modifications.
                var key = new OsmGeoKey(_current);
                if (_deletions.Contains(key))
                {
                    // move next.
                    _current = null;
                    continue;
                }
                else if (_modifications.TryGetValue(key, out modified))
                {
                    _current = modified;
                }
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// Gets the member for the given key. Returns null if member is not present.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns>The member if there.</returns>
        public OsmGeo GetMember(OsmGeoKey key)
        {
            if (!_members.TryGetValue(key, out var osmGeo))
            {
                return(null);
            }

            return(osmGeo);
        }
Example #3
0
      public void OsmGeoKey_NodeAndWay_CompareId()
      {
          var n1 = new OsmGeoKey(OsmGeoType.Node, 42);

          var n2 = new OsmGeoKey(OsmGeoType.Way, 0);

          Assert.AreEqual(-1, n1.CompareTo(n2));
          Assert.AreEqual(1, n2.CompareTo(n1));
      }
Example #4
0
      public void OsmGeoKey_Ways_CompareId()
      {
          var n1 = new OsmGeoKey(OsmGeoType.Way, 42);

          var n2 = new OsmGeoKey(OsmGeoType.Way, 43);

          Assert.AreEqual(-1, n1.CompareTo(n2));
          Assert.AreEqual(1, n2.CompareTo(n1));
      }
Example #5
0
        private static OsmGeo[] ApplyTags(IEnumerable <OsmGeo> elements,
                                          Dictionary <OsmGeoKey, TagsCollection> tagsCollections)
        {
            var results = new List <OsmGeo>(tagsCollections.Count);

            foreach (var element in elements)
            {
                var key = new OsmGeoKey(element);
                if (tagsCollections.TryGetValue(key, out var tags))
                {
                    element.Tags = tags;
                    results.Add(element);
                }
            }

            return(results.ToArray());
        }
Example #6
0
        /// <summary>
        /// Gets all relations with at least one member in the given key set.
        /// </summary>
        public IEnumerable<Relation> GetRelations(IEnumerable<OsmGeoKey> keys)
        {
            var set = new HashSet<OsmGeoKey>(keys);
            
            return _relations.Values.Where(x =>
            {
                if (x.Members == null)
                {
                    return false;
                }

                foreach (var member in x.Members)
                {
                    var key = new OsmGeoKey(member.Type, member.Id);
                    if (set.Contains(key))
                    {
                        return true;
                    }
                }
                return false;
            });
        }
Example #7
0
        // Recursive, safe against circular references, may return duplciate nodes.
        private static IEnumerable <OsmGeo> ToSimpleWithChildrenCircularSafe(
            this CompleteRelation complete, HashSet <OsmGeoKey> seenGeoKeys)
        {
            if (complete.Members == null)
            {
                return(new[] { complete.ToSimple() });
            }

            var children = new List <OsmGeo>();

            foreach (var completeMember in complete.Members.Where(m => m != null))
            {
                var key = new OsmGeoKey(completeMember.Member.Type, completeMember.Member.Id);

                if (seenGeoKeys.Add(key)) // Returns true if element was not already present
                {
                    switch (completeMember.Member)
                    {
                    case Node node:
                        children.Add(node);
                        break;

                    case CompleteWay way:
                        children.AddRange(way.ToSimpleWithChildren());
                        break;

                    case CompleteRelation relation:
                        children.AddRange(relation.ToSimpleWithChildrenCircularSafe(seenGeoKeys));
                        break;

                    default:
                        throw new Exception("Unknown Complete Element Type.");
                    }
                }
            }

            return(children.Append(complete.ToSimple()));
        }
Example #8
0
        private Dictionary <OsmGeoKey, TagsCollection> QueryTags(string sql)
        {
            var results = new Dictionary <OsmGeoKey, TagsCollection>();
            var records = Query(sql).ToArray();
            var keys    = records[0];

            if (string.Join(",", keys.Take(2)).ToLower() != $"{ElementKeyId},{ElementKeyType}".ToLower())
            {
                throw new Exception($"The first two field in the query must be [{ElementTableName}.{ElementKeyId}] and [{ElementTableName}.{ElementKeyType}].");
            }

            foreach (var record in records.Skip(1))
            {
                var osmGeoKey = new OsmGeoKey((OsmGeoType)Enum.Parse(typeof(OsmGeoType), record[1]), long.Parse(record[0]));
                var tags      = Enumerable.Range(2, record.Length - 2)
                                .Where(i => !string.IsNullOrEmpty(record[i]) && keys[i] != LookupId)
                                .Select(i => new Tag(keys[i], record[i]));
                var tagsCollection = new TagsCollection(tags);
                results.Add(osmGeoKey, tagsCollection);
            }

            return(results);
        }
        /// <inheritdoc/>
        public override bool MoveNext(bool ignoreNodes, bool ignoreWays, bool ignoreRelations)
        {
            if (!this.Source.MoveNext(ignoreNodes, ignoreWays, ignoreRelations))
            {
                return(false);
            }

            var current = this.Current();

            if (current?.Id == null)
            {
                return(true);
            }
            if (current.Type == OsmGeoType.Node)
            {
                _firstPass = false;

                var key = new OsmGeoKey(current.Type, current.Id.Value);
                if (!_members.ContainsKey(key))
                {
                    return(true);
                }

                _members[key] = current;
            }
            else if (current.Type == OsmGeoType.Way)
            {
                var key = new OsmGeoKey(current.Type, current.Id.Value);
                if (!_members.ContainsKey(key))
                {
                    return(true);
                }

                _members[key] = current;
            }
            else if (current.Type == OsmGeoType.Relation)
            {
                if (!_firstPass)
                {
                    return(true);
                }

                var relation = current as Relation;
                if (relation?.Id == null)
                {
                    return(true);
                }
                if (relation.Tags == null || !relation.Tags.Contains("type", "route"))
                {
                    return(true);
                }
                if (!relation.Tags.TryGetValue("route", out var routeType))
                {
                    return(true);
                }
                if (relation.Members == null || relation.Members.Length == 0)
                {
                    return(true);
                }

                // apply extra filter.
                if (_filter != null && !_filter.Invoke(relation))
                {
                    return(true);
                }

                _relations[relation.Id.Value] = relation;

                foreach (var member in relation.Members)
                {
                    var key = new OsmGeoKey(member.Type, member.Id);
                    _members[key] = null;
                }
            }

            return(true);
        }
Example #10
0
        private async Task RunAsync(CancellationToken stoppingToken)
        {
            // download file (if md5 files don't match).
            var local = Path.Combine(_configuration.DataPath, Local);

            if (!await _downloader.Get(_configuration.SourceUrl, local, _configuration.TempPath, cancellationToken: stoppingToken))
            {
                return;
            }

            _logger.LogInformation("Downloaded new file, refreshing tiles");

            if (!File.Exists(local))
            {
                _logger.LogCritical("Local file not found: {Local}", local);
                return;
            }

            try
            {
                bool IsRelevant(Relation current)
                {
                    var networks = new HashSet <string> {
                        "lcn", "rcn", "ncn"
                    };

                    if (!current.Tags.TryGetValue("type", out var type))
                    {
                        return(false);
                    }

                    switch (type)
                    {
                    case "network":
                    {
                        if (current.Tags.TryGetValue("network", out var network) &&
                            networks.Contains(network))
                        {
                            return(true);
                        }

                        break;
                    }

                    case "route":
                    {
                        if (current.Tags.Contains("route", "bicycle"))
                        {
                            return(true);
                        }

                        break;
                    }
                    }

                    return(false);
                }

                var localStream = File.OpenRead(local);
                var pbfSource   = new PBFOsmStreamSource(localStream);
                var source      = new OsmSharp.Streams.Filters.OsmStreamFilterProgress();
                source.RegisterSource(pbfSource);

                // pass over source stream and:
                // - determine all members of route relations where are interested in.
                // - keep master relations relationships.
                var membersInRelations  = new Dictionary <OsmGeoKey, List <Relation> >();
                var foundRouteRelations = 0;
                while (true)
                {
                    if (stoppingToken.IsCancellationRequested)
                    {
                        break;
                    }
                    if (!source.MoveNext(true, true, false))
                    {
                        break;
                    }
                    if (source.Current() is not Relation current)
                    {
                        continue;
                    }
                    if (current.Members == null)
                    {
                        continue;
                    }
                    if (current.Tags == null)
                    {
                        continue;
                    }
                    if (!IsRelevant(current))
                    {
                        continue;
                    }

                    // this is a network relation.
                    foundRouteRelations++;
                    foreach (var member in current.Members)
                    {
                        var memberKey = new OsmGeoKey
                        {
                            Id   = member.Id,
                            Type = member.Type
                        };
                        if (!membersInRelations.TryGetValue(memberKey, out var masters))
                        {
                            masters = new List <Relation>(1);
                            membersInRelations[memberKey] = masters;
                        }

                        masters.Add(current);
                    }
                }

                if (stoppingToken.IsCancellationRequested)
                {
                    this.CancelledWhenProcessing();
                    return;
                }

                _logger.LogInformation("Found {Relation} with {MembersCount} members",
                                       foundRouteRelations, membersInRelations.Count);

                // filter stream, keeping only the relevant objects.
                IEnumerable <OsmGeo> FilterSource()
                {
                    foreach (var x in source)
                    {
                        if (stoppingToken.IsCancellationRequested)
                        {
                            yield break;
                        }
                        if (!x.Id.HasValue)
                        {
                            yield break;
                        }

                        var key = new OsmGeoKey
                        {
                            Id   = x.Id.Value,
                            Type = x.Type
                        };

                        switch (x.Type)
                        {
                        case OsmGeoType.Node:
                            yield return(x);

                            break;

                        case OsmGeoType.Way:
                            if (membersInRelations.ContainsKey(key))
                            {
                                yield return(x);
                            }

                            break;

                        case OsmGeoType.Relation:
                            if (x is Relation r && IsRelevant(r))
                            {
                                yield return(x);
                            }

                            break;
                        }
                    }
                }

                var filteredSource = FilterSource();
                if (stoppingToken.IsCancellationRequested)
                {
                    this.CancelledWhenProcessing();
                    return;
                }

                // convert this to complete objects.
                var features = new FeatureCollection();
                foreach (var osmComplete in filteredSource.ToComplete())
                {
                    if (stoppingToken.IsCancellationRequested)
                    {
                        break;
                    }
                    switch (osmComplete)
                    {
                    case Node {
                            Id: null
                    } :
                        continue;

                    case Node node:
                    {
                        var key = new OsmGeoKey
                        {
                            Id   = node.Id.Value,
                            Type = node.Type
                        };

                        if (membersInRelations.TryGetValue(key, out var masters))
                        {
                            foreach (var master in masters)
                            {
                                var nodeFeatures = node.ToFeatureCollection(master.Tags);
                                foreach (var feature in nodeFeatures)
                                {
                                    features.Add(feature);
                                }
                            }
                        }

                        break;
                    }
Example #11
0
        /// <summary>
        /// Squashes the given changesets into one that has the same effect.
        /// </summary>
        public static OsmChange Squash(this IEnumerable <OsmChange> changes)
        {
            // keep mutations:
            // type:
            // - null: DELETE
            // - true: CREATE
            // - false: MODIFY.

            // - deletes overrules everything, any create or modify is ignored.
            // - we keep the object with the highest version #.

            var mutations = new Dictionary <OsmGeoKey, (OsmGeo osmGeo, bool create, bool delete)>();

            foreach (var change in changes)
            {
                if (change.Delete == null)
                {
                    continue;
                }

                foreach (var del in change.Delete)
                {
                    mutations[new OsmGeoKey(del)] = (del, false, true);
                }
            }

            foreach (var change in changes)
            {
                if (change.Create == null)
                {
                    continue;
                }

                foreach (var create in change.Create)
                {
                    var key = new OsmGeoKey(create);
                    if (mutations.TryGetValue(key, out var _))
                    {
                        // was deleted already, set the create flag.
                        mutations[key] = (create, true, true);
                        continue;
                    }

                    mutations.Add(key, (create, true, false));
                }
            }

            foreach (var change in changes)
            {
                if (change.Modify == null)
                {
                    continue;
                }

                foreach (var mod in change.Modify)
                {
                    var key = new OsmGeoKey(mod);
                    if (mutations.TryGetValue(key, out var current))
                    {
                        if (current.delete)
                        {
                            // was deleted already, ignore modification.
                            continue;
                        }

                        if (current.create)
                        {
                            // was already modified/created.
                            if (current.osmGeo.Version < mod.Version)
                            {
                                // create created, replace by modification.
                                mutations[key] = (mod, true, false);
                            }
                        }
                        else
                        {
                            // was already modified.
                            if (current.osmGeo.Version < mod.Version)
                            {
                                // this version is higher, replace the current one.
                                mutations[key] = (mod, false, false);
                            }
                        }
                    }
                    else
                    {
                        mutations[key] = (mod, false, false);
                    }
                }
            }

            return(new OsmChange()
            {
                Create = mutations.Values.Where(x => x.create == true && x.delete == false).Select(x => x.osmGeo).ToArray(),
                Delete = mutations.Values.Where(x => x.create == false && x.delete == true).Select(x => x.osmGeo).ToArray(),
                Modify = mutations.Values.Where(x => x.create == false && x.delete == false).Select(x => x.osmGeo).ToArray(),
                Generator = "OsmSharp",
                Version = 6
            });
        }
Example #12
0
        /// <summary>
        /// Adds the public transport data in the relations to add the public transport data to the routerdb.
        /// </summary>
        /// <param name="routerDb">The router db.</param>
        /// <param name="transitOsm">The transit osm data.</param>
        /// <param name="profiles">The profiles to resolve stops for.</param>
        public static void AddPublicTransport(this RouterDb routerDb, IEnumerable <OsmGeo> transitOsm, IProfileInstance[] profiles)
        {
            var members = new Dictionary <OsmGeoKey, OsmGeo>();

            // collect all relations.
            var relations = new List <Relation>();

            foreach (var osmGeo in transitOsm)
            {
                if (osmGeo.Type != OsmGeoType.Relation)
                {
                    continue;
                }
                var relation = osmGeo as Relation;
                if (relation?.Tags == null || !relation.Tags.Contains("type", "route"))
                {
                    continue;
                }
                if (!relation.Tags.TryGetValue("route", out var routeType))
                {
                    continue;
                }
                if (relation.Members == null || relation.Members.Length == 0)
                {
                    continue;
                }

                relations.Add(relation);

                foreach (var member in relation.Members)
                {
                    var key = new OsmGeoKey(member.Type, member.Id);
                    members[key] = null;
                }
            }

            // collection members.
            foreach (var osmGeo in transitOsm)
            {
                if (osmGeo.Id == null)
                {
                    continue;
                }

                var key = new OsmGeoKey(osmGeo.Type, osmGeo.Id.Value);

                if (!members.ContainsKey(key))
                {
                    continue;
                }

                members[key] = osmGeo;
            }

            routerDb.AddPublicTransport(relations,
                                        (key) =>
            {
                if (!members.TryGetValue(key, out var value))
                {
                    return(null);
                }

                return(value);
            }, profiles);
        }