/// <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); }
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)); }
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)); }
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()); }
/// <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; }); }
// 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())); }
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); }
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; }
/// <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 }); }
/// <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); }