private SectorConstrainedOSMAreaGraph DoMultipolygon(SuperWayCollection superWays) { SectorConstrainedOSMAreaGraph map = new SectorConstrainedOSMAreaGraph(); foreach (var superWay in superWays.linkedWays) // we expect these to always start and end outside the sector { AddConstrainedPaths(map, superWay); } map.CloseLines(this); map.RemoveDuplicateLines(); if (Constants.DEBUG_MODE) { map.CheckValid(); } foreach (var superLoop in superWays.loopedWays) { double wayArea = GetArea(superLoop); if (Math.Abs(wayArea) < SMALLEST_ALLOWED_AREA) { continue; // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? } bool isCW = wayArea < 0; var temp = new SectorConstrainedOSMAreaGraph(); bool untouchedLoop = CheckIfUntouchedAndSpin(superLoop); if (untouchedLoop) { AddUntouchedLoop(temp, superLoop); } else { AddConstrainedPaths(temp, superLoop); } temp.CloseLines(this); temp.RemoveDuplicateLines(); if (Constants.DEBUG_MODE) { temp.CheckValid(); } map.Add(temp, this); } return(map); }
internal SectorConstrainedOSMAreaGraph GetAreaMap(string key, string value) { var simpleWays = EnumerateWays().Where(x => x.keyValues.ContainsKey(key) && x.keyValues[key] == value); // we expect all of these to be closed loops // copy this dang multipolygon way id gathering logic Dictionary <long, Way> wayLookup = new Dictionary <long, Way>(); foreach (var way in EnumerateWays()) { wayLookup[way.id] = way; } List <List <long> > inners = new List <List <long> >(); List <List <long> > outers = new List <List <long> >(); List <long> relationIds = new List <long>(); HashSet <long> otherInnerOuters = new HashSet <long>(); foreach (var blob in blobs) { if (blob.type != "OSMData") { continue; } int typeIndex = blob.pBlock.stringtable.vals.IndexOf("type"); int multipolygonIndex = blob.pBlock.stringtable.vals.IndexOf("multipolygon"); int outerIndex = blob.pBlock.stringtable.vals.IndexOf("outer"); int innerIndex = blob.pBlock.stringtable.vals.IndexOf("inner"); int keyIndex = blob.pBlock.stringtable.vals.IndexOf(key); int valueIndex = blob.pBlock.stringtable.vals.IndexOf(value); if (new[] { typeIndex, multipolygonIndex, outerIndex, innerIndex, keyIndex, valueIndex }.Contains(-1)) { continue; } foreach (var pGroup in blob.pBlock.primitivegroup) { foreach (var relation in pGroup.relations) { bool isKeyValue = false; bool isTypeMultipolygon = false; for (int i = 0; i < relation.keys.Count; i++) { if (relation.keys[i] == keyIndex && relation.vals[i] == valueIndex) { isKeyValue = true; } if (relation.keys[i] == typeIndex && relation.vals[i] == multipolygonIndex) { isTypeMultipolygon = true; } } if (isTypeMultipolygon) { if (isKeyValue) { List <long> innerWayIds = new List <long>(); List <long> outerWayIds = new List <long>(); for (int i = 0; i < relation.roles_sid.Count; i++) { // just outer for now if (relation.types[i] == 1) { if (relation.roles_sid[i] == 0 && innerIndex != 0 && outerIndex != 0) { // some ways are in a relation without any inner/outer tag // ex: 359181377 in relation 304768 outerWayIds.Add(relation.memids[i]); } else { if (relation.roles_sid[i] == innerIndex) { innerWayIds.Add(relation.memids[i]); } if (relation.roles_sid[i] == outerIndex) { outerWayIds.Add(relation.memids[i]); } } } } inners.Add(innerWayIds); outers.Add(outerWayIds); relationIds.Add(relation.id); } else { for (int i = 0; i < relation.roles_sid.Count; i++) { // just outer for now if (relation.types[i] == 1) { otherInnerOuters.Add(relation.memids[i]); } } } } } } } HashSet <long> innersAndOuters = new HashSet <long>(); foreach (var innerList in inners) { foreach (var inner in innerList) { innersAndOuters.Add(inner); } } foreach (var outerList in outers) { foreach (var outer in outerList) { innersAndOuters.Add(outer); } } // end gathering logic // add each simple way, flipping them where necessary List <SectorConstrainedOSMAreaGraph> addingMaps = new List <SectorConstrainedOSMAreaGraph>(); foreach (var way in simpleWays) { if (innersAndOuters.Contains(way.id)) { continue; // sometimes lake multipolygons also tag several pieces - at best this is redundant, and at worst causes errors } if (way.refs.Count < 3) { continue; // we -usually- only ever see lines with multipolygons, but I found a weird way like 43435045 } if (way.selfIntersects) { continue; // just ignore ways like 43410874 to keep you sane } SectorConstrainedOSMAreaGraph simpleMap = new SectorConstrainedOSMAreaGraph(); var superLoop = new List <Way>() { way }; if (way.refs.Last() != way.refs.First()) { if (otherInnerOuters.Contains(way.id)) { continue; // unsure of how else to ignore bad ways like 43815149 } way.refs.Add(way.refs.First()); // some folks forget to close a simple way, or perhaps the mistake is tagging subcomponents of a relation } if (!IsValid(superLoop)) { continue; // ignore relations like 512080985 which contain duplicate nodes } double wayArea = GetArea(superLoop); if (Math.Abs(wayArea) < SMALLEST_ALLOWED_AREA) { continue; // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? } bool isCW = wayArea < 0; if (isCW) { way.refs.Reverse(); // the simple polygons are always "outers" } bool untouchedLoop = CheckIfUntouchedAndSpin(superLoop); if (untouchedLoop) { AddUntouchedLoop(simpleMap, superLoop); } else { AddConstrainedPaths(simpleMap, superLoop); simpleMap.CloseLines(this); if (Constants.DEBUG_MODE) { simpleMap.CheckValid(); } } simpleMap.RemoveDuplicateLines(); if (Constants.DEBUG_MODE) { simpleMap.CheckValid(); } addingMaps.Add(simpleMap); } // construct each multipolygon to add separately for (int i = 0; i < inners.Count; i++) // foreach multipolygon, basically { if (OSMMetaFinal.GLOBAL_FINAL.badRelations.Contains(relationIds[i])) { continue; } // TODO: with islands inside of ponds inside of islands inside of ponds, etc. we wouldn't expect this to work // however, we're taking advantage of the fact that Add/Subtract doesn't check for that for now (until Finalize) SuperWayCollection superInnerWays = GenerateSuperWayCollection(inners[i].Where(x => wayLookup.ContainsKey(x)).Select(x => Copy(wayLookup[x])), true); SuperWayCollection superOuterWays = GenerateSuperWayCollection(outers[i].Where(x => wayLookup.ContainsKey(x)).Select(x => Copy(wayLookup[x])), true); superInnerWays.loopedWays = superInnerWays.loopedWays.Where(x => Math.Abs(GetArea(x)) >= SMALLEST_ALLOWED_AREA).ToList(); // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? superOuterWays.loopedWays = superOuterWays.loopedWays.Where(x => Math.Abs(GetArea(x)) >= SMALLEST_ALLOWED_AREA).ToList(); // ignore zero-area ways since it really messes with the tesselator (ex: way 43624681) TODO: maybe check for absolute zero via node duplication? if (!IsValid(superInnerWays)) { continue; } if (!IsValid(superOuterWays)) { continue; } OrientSuperWays(superInnerWays, superOuterWays, gridPointInfo.relations.Contains(relationIds[i])); SectorConstrainedOSMAreaGraph innerMap = DoMultipolygon(superInnerWays); SectorConstrainedOSMAreaGraph outerMap = DoMultipolygon(superOuterWays); if (Constants.DEBUG_MODE) { innerMap.CheckValid(); } if (Constants.DEBUG_MODE) { outerMap.CheckValid(); } SectorConstrainedOSMAreaGraph multiPolygon = outerMap.Subtract(innerMap, this); if (Constants.DEBUG_MODE) { multiPolygon.CheckValid(); } addingMaps.Add(multiPolygon); } SectorConstrainedOSMAreaGraph map = new SectorConstrainedOSMAreaGraph(); BlobsIntersector.FixLoops(addingMaps, this); foreach (var addingMap in addingMaps) { map.Add(addingMap, this); } if (Constants.DEBUG_MODE) { map.CheckValid(); } return(map); }