public static void FixAddrStreetFormat() { // or @"C:\Users\Alex\Downloads\Maine\maine-latest.osm\maine-latest.osm" var osm = OpenFile(@"C:\Users\Alex\Downloads\Maine\maine-latest-internal.osm.pbf"); var index = osm.ToDictionary(e => new OsmGeoKey(e)); var stringdex = index.Values.ToDictionary(e => e.Type.ToString() + e.Id); var canonNamesToCompleteWays = index.Values .OfType <Way>() .Where(e => e.Tags != null && e.Tags.ContainsKey("highway") && e.Tags.ContainsKey("name")) .Select(w => w.AsComplete(stringdex)) .GroupBy(e => Connonical(e.Tags["name"])) .ToDictionary(); var addrStreets = index.Values.Where(e => e.Tags != null && e.Tags.Contains("addr:state", "ME") && e.Tags.ContainsKey("addr:street")) .Select(element => new { element, addrStreet = element.Tags["addr:street"], canon = Connonical(element.Tags["addr:street"]), position = element.AsComplete(stringdex).AsPosition() }) .Where(e => canonNamesToCompleteWays.ContainsKey(e.canon)) .ToArray(); var changes = new List <OsmGeo>(); foreach (var addr in addrStreets) { var roadMatches = canonNamesToCompleteWays[addr.canon] .Where(r => Geometry.MinDistanceMeters(addr.position, r) < 1000).ToArray(); var roadNameMatches = roadMatches.Select(r => r.Tags["name"]).Distinct().ToArray(); if (roadNameMatches.Length == 0) { } else if (roadNameMatches.Length > 1) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("conflict " + addr.element.Type + " " + addr.element.Id + " -> " + string.Join(", ", roadNameMatches)); Console.ForegroundColor = ConsoleColor.White; roadMatches.First().Tags.Add("fixme", "Different road segments have name formats conflict. Check the street sign and fix: " + string.Join(" vs ", roadNameMatches.Select(n => '[' + n + ']'))); //changes.Add(roadMatches.First().AsSimple()); } else if (roadNameMatches[0] != addr.addrStreet) { //if (WhitespacesDiffers(addr.addrStreet, roadNameMatches[0]) && addr.element.UserName.StartsWith("blackboxlogic")) //{ // var did = false; // foreach (var road in roadMatches) // { // if (!road.Tags.Contains("official_name", addr.addrStreet)) // { // did = true; // road.Tags.AddOrReplace("official_name", addr.addrStreet); // changes.Add(road.AsOsmGeo()); // } // } // if (did) Console.WriteLine("O\t" + roadMatches.Length + "x " + roadNameMatches.First() + " -> " + addr.addrStreet); //} Console.WriteLine(addr.addrStreet + " -> " + roadNameMatches.First()); addr.element.Tags["addr:street"] = roadNameMatches.First(); changes.Add(addr.element); } } var change = Changes.FromGeos(null, changes, null); var ids = Subjects.UploadChange(change, GetCommitTags("Adjusting addr:street format to match nearby street name (case, punctuation, space)"), "Fix addrStreet Format").Result; //var streetNameConflicts = connonicalStreetNames.Where(c => c.Value.Length > 1) // .ToDictionary(c => c.Key, c => FightingWays(c.Value.SelectMany(n => streetNamesToWays[n].Ways))); //Console.WriteLine(string.Join(Environment.NewLine, // streetNameConflicts.Where(kvp => kvp.Value.Any()).Select(kvp => kvp.Key + ": " + "\n\t" + // string.Join("\n\t", kvp.Value.Select(w => "osm.org/way/" + w.Id + "\t" + wayIndex[w.Id].Tags["name"]))))); }
// nohousenumber=yes // consider just leaving out all addr:unit=* // option to moveNode or not. (Do you trust E911 locations more than OSM?) // MatchWidth list to handle multi-match // Maybe fix addr:street punctuation on elements that I didn't add or update // Maybe fix addr:street should be addr:place on elements that I didn't add or update // Maybe fix nodes merging into buildings on elements that I didn't add or update public void Main() { Static.Municipalities = FileSerializer.ReadJsonCacheOrSource("MaineMunicipalities.json", GetMunicipalities).Result; ShowProgress(); Municipality = Static.Municipalities.Values.First(m => !m.ChangeSetIds.Any()).Name; Console.WriteLine("Starting in " + Municipality); while (true) { Console.Write("> "); var userInput = Console.ReadLine(); if (Is(userInput, "reference")) { //Func<Feature, bool> filter = f => (f.Geometry as Point).Coordinates.Longitude >= -70.505; var reference = References.Fetch(Municipality).Result; FileSerializer.WriteXml(Municipality + "/Reference.osm", reference); File.Delete(Municipality + "/Conflated.osc"); } else if (Is(userInput, "review ref")) { var reference = GetReference(); References.Report(reference.GetElements().ToArray()); } else if (Is(userInput, "subject")) { var reference = GetReference(); var subject = Subjects.GetElementsInBoundingBox(reference.Bounds.ExpandBy(15)); FileSerializer.WriteXml(Municipality + "/Subject.osm", subject); File.Delete(Municipality + "/Conflated.osc"); Console.WriteLine("ChangeId high watermark: " + subject.GetHighestChangeSetId()); } else if (Is(userInput, "conflate")) { DoConflate(); } else if (Is(userInput, "review con")) { Conflate.Review(Municipality); } else if (Is(userInput, "review")) { OpenJosm(); } else if (Is(userInput, "list")) { var key = userInput.Split(" ")[1]; var reference = GetReference(); var values = reference.GetElements().Where(e => e.Tags.ContainsKey(key)).Select(e => "\n\t" + e.Tags[key]).GroupBy(n => n).ToArray(); Console.WriteLine(string.Concat(values.Select(v => v.Key + "\tx" + v.Count()))); } else if (Is(userInput, "filter")) { var key = userInput.Split(" ")[1]; var reference = GetReference(); DoFilter(key, reference.GetElements()); File.Delete(Municipality + "/Reference.osm"); File.Delete(Municipality + "/Conflated.osc"); } else if (Is(userInput, "note")) { Static.Municipalities[Municipality].Notes += "/n" + userInput.Split(' ', 2)[1]; FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); } else if (Is(userInput, "WhiteAll")) { var review = FileSerializer.ReadXml <Osm>(Municipality + "/Conflated.Review.osm"); var selection = review.GetElements() .Where(e => e.Tags != null && e.Tags.ContainsKey(Static.maineE911id)) .Select(e => e.Tags[Static.maineE911id]) .SelectMany(id => id.Split(new char[] { ' ', ',', ';', '-' }, StringSplitOptions.RemoveEmptyEntries)) .Select(long.Parse) .Except(Static.Municipalities[Municipality].WhiteList) .ToArray(); Static.Municipalities[Municipality].WhiteList.AddRange(selection); FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); File.Delete(Municipality + "/Conflated.osc"); } else if (Is(userInput, "white")) { var selection = userInput.Split(' ', 2)[1] .Split(new char[] { ' ', ',', ';', '-', '=' }, StringSplitOptions.RemoveEmptyEntries) .Where(c => long.TryParse(c, out _)) .Select(long.Parse) .Except(Static.Municipalities[Municipality].WhiteList) .ToArray(); Static.Municipalities[Municipality].WhiteList.AddRange(selection); FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); File.Delete(Municipality + "/Conflated.osc"); } else if (Is(userInput, "blacktag")) { var tag = userInput.Split(' ', 2)[1].Replace("maineE911id=", ""); Static.Municipalities[Municipality].BlackTags.Add(tag); Static.Municipalities[Municipality].BlackTags = Static.Municipalities[Municipality].BlackTags.Distinct().ToList(); FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); File.Delete(Municipality + "/Reference.osm"); File.Delete(Municipality + "/Conflated.osc"); } else if (Is(userInput, "black")) { AddToList(userInput.Split(' ', 2)[1], Static.Municipalities[Municipality].BlackList); FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); File.Delete(Municipality + "/Reference.osm"); File.Delete(Municipality + "/Conflated.osc"); } else if (Is(userInput, "ignore")) { AddToList(userInput.Split(' ', 2)[1], Static.Municipalities[Municipality].IgnoreList); FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); } else if (Is(userInput, "commit")) { var change = FileSerializer.ReadXml <OsmChange>(Municipality + "/Conflated.osc"); var results = Subjects.UploadChange(change, Municipality).Result; Static.Municipalities[Municipality].ChangeSetIds.AddRange(results); Static.Municipalities[Municipality].ImportDate = DateTime.UtcNow; FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); Console.WriteLine("Finished!"); Next(); } else if (Is(userInput, "skip")) { Static.Municipalities[Municipality].Notes += " SKIPPED"; Static.Municipalities[Municipality].ChangeSetIds.Add(-1); FileSerializer.WriteJson("MaineMunicipalities.json", Static.Municipalities); } else if (Is(userInput, "next")) { Next(); } else if (Is(userInput, "switch")) { Municipality = ChooseMunicipality(); ShowProgress(); } else if (Is(userInput, "folder")) { OpenExplorer(); } else if (Is(userInput, "remind")) { var parts = userInput.Split(' ', 3); var id = long.Parse(parts[1].Replace("maineE911id=", "")); var reference = GetReference(); var element = reference.Nodes.First(e => Math.Abs(e.Id.Value) == Math.Abs(id)); var message = parts.Length > 2 ? parts[2] : "The addresses imported on this neighborhood need to be aligned with the correct buildings"; Subjects.CreateNote(element.Latitude.Value, element.Longitude.Value, message).Wait(); } else if (Is(userInput, "help")) { Console.WriteLine("Options:"); Console.WriteLine("\tSwitch"); Console.WriteLine("\tNext"); Console.WriteLine("\tReference"); Console.WriteLine("\tReview Reference"); Console.WriteLine("\tSubject"); Console.WriteLine("\tConflate"); Console.WriteLine("\tReview Conflate"); Console.WriteLine("\tReview"); Console.WriteLine("\tList [key]"); Console.WriteLine("\tFilter [key]"); Console.WriteLine("\t\t[Y/N/AUnit/Descr/Build/Move]"); Console.WriteLine("\tNote [message]"); Console.WriteLine("\tWhitelist [###]<,[###]...>"); Console.WriteLine("\tWhiteAll"); Console.WriteLine("\tBlacklist [###]<,[###]...>"); Console.WriteLine("\tBlackTag [###].[key] || *.[key]=[value]"); Console.WriteLine("\tIgnore [###]<,[###]...>"); Console.WriteLine("\tRemind [ref###] <message>"); Console.WriteLine("\tCommit"); } else { Console.WriteLine("What?"); } Console.WriteLine("Done"); } }