Example #1
0
        internal SectorConstrainedOSMAreaGraph GetCoastAreaMap(string key, string value)
        {
            // remember: "If you regard this as tracing around an area of land, then the coastline way should be running counterclockwise."
            // gather ways with matching starts/ends to form a super-way, coast ways should always run the same direction, so this becomes easier
            SuperWayCollection            superWays = GenerateSuperWayCollection(EnumerateWays().Where(x => x.keyValues.ContainsKey(key) && x.keyValues[key] == value), false);
            SectorConstrainedOSMAreaGraph map       = DoMultipolygon(superWays);

            if (OSMMetaFinal.IsPixelLand(sector) || borderWay.refs.Count > 5) // just return a big ol' square
            {
                SectorConstrainedOSMAreaGraph temp = new SectorConstrainedOSMAreaGraph();
                for (int i = 1; i < borderWay.refs.Count; i++)
                {
                    if (!temp.nodes.ContainsKey(borderWay.refs[i]))
                    {
                        temp.nodes[borderWay.refs[i]] = new List <AreaNode>();
                        temp.nodes[borderWay.refs[i]].Add(new AreaNode()
                        {
                            id = borderWay.refs[i]
                        });
                    }
                }
                for (int i = 1; i < borderWay.refs.Count; i++)
                {
                    AreaNode prev = temp.nodes[borderWay.refs[i - 1]].Single();
                    AreaNode next = temp.nodes[borderWay.refs[i]].Single();
                    if (prev.id != next.id)
                    {
                        prev.next = next;
                        next.prev = prev;
                    }
                }
                map = map.Intersect(temp, this);
            }
            BlobsIntersector.FixLoops(new List <SectorConstrainedOSMAreaGraph>()
            {
                map
            }, this);
            if (Constants.DEBUG_MODE)
            {
                map.CheckValid();
            }
            return(map);
        }
Example #2
0
        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);
        }