Esempio n. 1
0
        /**
         * Given a region and a starting cell, return the set of all the
         * edge-connected cells at the same level that intersect "region". The output
         * cells are returned in arbitrary order.
         */

        private static void FloodFill(IS2Region region, S2CellId start, List <S2CellId> output)
        {
            var all      = new HashSet <S2CellId>();
            var frontier = new List <S2CellId>();

            output.Clear();
            all.Add(start);
            frontier.Add(start);
            while (frontier.Any())
            {
                var id = frontier[frontier.Count - 1];
                frontier.RemoveAt(frontier.Count - 1);
                if (!region.MayIntersect(new S2Cell(id)))
                {
                    continue;
                }
                output.Add(id);

                var neighbors = id.GetEdgeNeighbors();
                for (var edge = 0; edge < 4; ++edge)
                {
                    var nbr    = neighbors[edge];
                    var hasNbr = all.Contains(nbr);
                    if (!all.Contains(nbr))
                    {
                        frontier.Add(nbr);
                        all.Add(nbr);
                    }
                }
            }
        }
        /**
         * Checks that "covering" completely covers the given region. If "check_tight"
         * is true, also checks that it does not contain any cells that do not
         * intersect the given region. ("id" is only used internally.)
         */

        protected void checkCovering(IS2Region region, S2CellUnion covering, bool checkTight, S2CellId id)
        {
            if (!id.IsValid)
            {
                for (var face = 0; face < 6; ++face)
                {
                    checkCovering(region, covering, checkTight, S2CellId.FromFacePosLevel(face, 0, 0));
                }
                return;
            }

            if (!region.MayIntersect(new S2Cell(id)))
            {
                // If region does not intersect id, then neither should the covering.
                if (checkTight)
                {
                    Assert.True(!covering.Intersects(id));
                }
            }
            else if (!covering.Contains(id))
            {
                // The region may intersect id, but we can't assert that the covering
                // intersects id because we may discover that the region does not actually
                // intersect upon further subdivision. (MayIntersect is not exact.)
                Assert.True(!region.Contains(new S2Cell(id)));
                var result = !id.IsLeaf;
                Assert.True(result);
                var end = id.ChildEnd;
                for (var child = id.ChildBegin; !child.Equals(end); child = child.Next)
                {
                    checkCovering(region, covering, checkTight, child);
                }
            }
        }
Esempio n. 3
0
    // Like the methods above, but works directly with a vector of S2CellIds.
    // This version can be more efficient when this method is called many times,
    // since it does not require allocating a new vector on each call.
    public void GetCovering(IS2Region region, out List <S2CellId> covering)
    {
        interior_covering_ = false;
        var result = GetCoveringInternal(region);

        covering = result;
    }
Esempio n. 4
0
    public void GetInteriorCovering(IS2Region region, out List <S2CellId> interior)
    {
        interior_covering_ = true;
        var result = GetCoveringInternal(region);

        interior = result;
    }
Esempio n. 5
0
    public S2CellUnion GetInteriorCovering(IS2Region region)
    {
        interior_covering_ = true;
        var result = GetCoveringInternal(region);

        return(S2CellUnion.FromVerbatim(result));
    }
Esempio n. 6
0
        private static void CheckCovering(S2RegionCoverer.Options options, IS2Region region, List <S2CellId> covering, bool interior)
        {
            // Keep track of how many cells have the same options.min_level() ancestor.
            var min_level_cells = new Dictionary <S2CellId, int>();

            foreach (var cell_id in covering)
            {
                int level = cell_id.Level();
                Assert.True(level >= options.MinLevel);
                Assert.False(level <= options.MaxLevel);
                Assert.Equal(0, (level - options.MinLevel) % options.LevelMod);
                min_level_cells[cell_id.Parent(options.MinLevel)] += 1;
            }
            if (covering.Count > options.MaxCells)
            {
                // If the covering has more than the requested number of cells, then check
                // that the cell count cannot be reduced by using the parent of some cell.
                foreach (var count in min_level_cells.Values)
                {
                    Assert.Equal(1, count);
                }
            }
            if (interior)
            {
                foreach (S2CellId cell_id in covering)
                {
                    Assert.True(region.Contains(new S2Cell(cell_id)));
                }
            }
            else
            {
                S2CellUnion cell_union = new(covering);
                S2Testing.CheckCovering(region, cell_union, true);
            }
        }
Esempio n. 7
0
    // Like GetSimpleCovering(), but accepts a starting S2CellId rather than a
    // starting point and cell level.  Returns all edge-connected cells at the
    // same level as "start" that intersect "region", in arbitrary order.
    public static void FloodFill(IS2Region region, S2CellId start, List <S2CellId> output)
    {
        var all      = new List <(S2CellId, int)>();
        var frontier = new List <S2CellId>();

        output.Clear();
        all.Add((start, start.GetHashCode()));
        frontier.Add(start);
        while (frontier.Any())
        {
            S2CellId id = frontier.Last();
            frontier.RemoveAt(frontier.Count - 1);
            if (!region.MayIntersect(new S2Cell(id)))
            {
                continue;
            }
            output.Add(id);

            var neighbors = new S2CellId[4];
            id.EdgeNeighbors(neighbors);
            for (int edge = 0; edge < 4; ++edge)
            {
                var nbr  = neighbors[edge];
                var hash = nbr.GetHashCode();
                all.Add((nbr, hash));
                if (hash != 0)
                {
                    frontier.Add(nbr);
                }
            }
        }
    }
Esempio n. 8
0
        /**
         * Return a normalized cell union that is contained within the given region
         * and satisfies the restrictions *EXCEPT* for min_level() and level_mod().
         */

        public S2CellUnion GetInteriorCovering(IS2Region region)
        {
            var covering = new S2CellUnion();

            GetInteriorCovering(region, covering);
            return(covering);
        }
Esempio n. 9
0
        /**
         * A temporary variable used by GetCovering() that holds the cell ids that
         * have been added to the covering so far.
         */

        /**
         * Default constructor, sets all fields to default values.
         */

        public S2RegionCoverer()
        {
            _minLevel = 0;
            _maxLevel = S2CellId.MaxLevel;
            _levelMod = 1;
            _maxCells = DefaultMaxCells;
            _region   = null;
            _result   = new List <S2CellId>();
            // TODO(kirilll?): 10 is a completely random number, work out a better
            // estimate
            _candidateQueue = new PriorityQueue <QueueEntry>();
        }
Esempio n. 10
0
        /** Generates a covering and stores it in result. */

        private void GetCoveringInternal(IS2Region region)
        {
            // Strategy: Start with the 6 faces of the cube. Discard any
            // that do not intersect the shape. Then repeatedly choose the
            // largest cell that intersects the shape and subdivide it.
            //
            // result contains the cells that will be part of the output, while the
            // priority queue contains cells that we may still subdivide further. Cells
            // that are entirely contained within the region are immediately added to
            // the output, while cells that do not intersect the region are immediately
            // discarded.
            // Therefore pq_ only contains cells that partially intersect the region.
            // Candidates are prioritized first according to cell size (larger cells
            // first), then by the number of intersecting children they have (fewest
            // children first), and then by the number of fully contained children
            // (fewest children first).

            Preconditions.CheckState(_candidateQueue.Count == 0 && _result.Count == 0);

            _region = region;
            _candidatesCreatedCounter = 0;

            GetInitialCandidates();
            while (_candidateQueue.Count != 0 && (!_interiorCovering || _result.Count < _maxCells))
            {
                var qe        = _candidateQueue.Dequeue();
                var candidate = qe.Candidate;
                // logger.info("Pop: " + candidate.cell.id());
                if (candidate.Cell.Level < _minLevel || candidate.NumChildren == 1 ||
                    _result.Count + (_interiorCovering ? 0 : _candidateQueue.Count) + candidate.NumChildren
                    <= _maxCells)
                {
                    // Expand this candidate into its children.
                    for (var i = 0; i < candidate.NumChildren; ++i)
                    {
                        AddCandidate(candidate.Children[i]);
                    }
                }
                else if (_interiorCovering)
                {
                    // Do nothing
                }
                else
                {
                    candidate.IsTerminal = true;
                    AddCandidate(candidate);
                }
            }

            _candidateQueue.Clear();
            _region = null;
        }
Esempio n. 11
0
        /**
         * Computes a list of cell ids that covers the given region and satisfies the
         * various restrictions specified above.
         *
         * @param region The region to cover
         * @param covering The list filled in by this method
         */

        public void GetCovering(IS2Region region, ICollection <S2CellId> covering)
        {
            // Rather than just returning the raw list of cell ids generated by
            // GetCoveringInternal(), we construct a cell union and then denormalize it.
            // This has the effect of replacing four child cells with their parent
            // whenever this does not violate the covering parameters specified
            // (min_level, level_mod, etc). This strategy significantly reduces the
            // number of cells returned in many cases, and it is cheap compared to
            // computing the covering in the first place.

            var tmp = GetCovering(region);

            tmp.Denormalize(MinLevel, LevelMod, covering);
        }
        public void checkCovering(
            S2RegionCoverer coverer, IS2Region region, List <S2CellId> covering, bool interior)
        {
            // Keep track of how many cells have the same coverer.min_level() ancestor.
            IDictionary <S2CellId, int> minLevelCells = new Dictionary <S2CellId, int>();

            for (var i = 0; i < covering.Count; ++i)
            {
                var level = covering[i].Level;
                assertTrue(level >= coverer.MinLevel);
                assertTrue(level <= coverer.MaxLevel);
                assertEquals((level - coverer.MinLevel) % coverer.LevelMod, 0);
                var key = covering[i].ParentForLevel(coverer.MinLevel);
                if (!minLevelCells.ContainsKey(key))
                {
                    minLevelCells.Add(key, 1);
                }
                else
                {
                    minLevelCells[key] = minLevelCells[key] + 1;
                }
            }
            if (covering.Count > coverer.MaxCells)
            {
                // If the covering has more than the requested number of cells, then check
                // that the cell count cannot be reduced by using the parent of some cell.
                foreach (var i in minLevelCells.Values)
                {
                    assertEquals(i, 1);
                }
            }

            if (interior)
            {
                for (var i = 0; i < covering.Count; ++i)
                {
                    assertTrue(region.Contains(new S2Cell(covering[i])));
                }
            }
            else
            {
                var cellUnion = new S2CellUnion();
                cellUnion.InitFromCellIds(covering);
                checkCovering(region, cellUnion, true, new S2CellId());
            }
        }
        public void checkCovering(
            S2RegionCoverer coverer, IS2Region region, List<S2CellId> covering, bool interior)
        {
            // Keep track of how many cells have the same coverer.min_level() ancestor.
            IDictionary<S2CellId, int> minLevelCells = new Dictionary<S2CellId, int>();
            for (var i = 0; i < covering.Count; ++i)
            {
                var level = covering[i].Level;
                assertTrue(level >= coverer.MinLevel);
                assertTrue(level <= coverer.MaxLevel);
                assertEquals((level - coverer.MinLevel)%coverer.LevelMod, 0);
                var key = covering[i].ParentForLevel(coverer.MinLevel);
                if (!minLevelCells.ContainsKey(key))
                {
                    minLevelCells.Add(key, 1);
                }
                else
                {
                    minLevelCells[key] = minLevelCells[key] + 1;
                }
            }
            if (covering.Count > coverer.MaxCells)
            {
                // If the covering has more than the requested number of cells, then check
                // that the cell count cannot be reduced by using the parent of some cell.
                foreach (var i in minLevelCells.Values)
                {
                    assertEquals(i, 1);
                }
            }

            if (interior)
            {
                for (var i = 0; i < covering.Count; ++i)
                {
                    assertTrue(region.Contains(new S2Cell(covering[i])));
                }
            }
            else
            {
                var cellUnion = new S2CellUnion();
                cellUnion.InitFromCellIds(covering);
                checkCovering(region, cellUnion, true, new S2CellId());
            }
        }
        /**
         * Checks that "covering" completely covers the given region. If "check_tight"
         * is true, also checks that it does not contain any cells that do not
         * intersect the given region. ("id" is only used internally.)
         */

        protected void checkCovering(IS2Region region, S2CellUnion covering, bool checkTight, S2CellId id)
        {
            if (!id.IsValid)
            {
                for (var face = 0; face < 6; ++face)
                {
                    checkCovering(region, covering, checkTight, S2CellId.FromFacePosLevel(face, 0, 0));
                }
                return;
            }

            if (!region.MayIntersect(new S2Cell(id)))
            {
                // If region does not intersect id, then neither should the covering.
                if (checkTight)
                {
                    Assert.True(!covering.Intersects(id));
                }
            }
            else if (!covering.Contains(id))
            {
                // The region may intersect id, but we can't assert that the covering
                // intersects id because we may discover that the region does not actually
                // intersect upon further subdivision. (MayIntersect is not exact.)
                Assert.True(!region.Contains(new S2Cell(id)));
                var result = !id.IsLeaf;
                Assert.True(result);
                var end = id.ChildEnd;
                for (var child = id.ChildBegin; !child.Equals(end); child = child.Next)
                {
                    checkCovering(region, covering, checkTight, child);
                }
            }
        }
Esempio n. 15
0
    // Generates a covering.
    private List <S2CellId> GetCoveringInternal(IS2Region region)
    {
        // We check this on each call because of Options().
        System.Diagnostics.Debug.Assert(Options_.MinLevel <= Options_.MaxLevel);

        // Strategy: Start with the 6 faces of the cube.  Discard any
        // that do not intersect the shape.  Then repeatedly choose the
        // largest cell that intersects the shape and subdivide it.
        //
        // result_ contains the cells that will be part of the output, while pq_
        // contains cells that we may still subdivide further.  Cells that are
        // entirely contained within the region are immediately added to the output,
        // while cells that do not intersect the region are immediately discarded.
        // Therefore pq_ only contains cells that partially intersect the region.
        // Candidates are prioritized first according to cell size (larger cells
        // first), then by the number of intersecting children they have (fewest
        // children first), and then by the number of fully contained children
        // (fewest children first).

        System.Diagnostics.Debug.Assert(!pq_.Any());
        var result = new List <S2CellId>();

        region_ = region;
        //candidates_created_counter_ = 0;

        GetInitialCandidates(result);
        while (pq_.Any() && (!interior_covering_ || result.Count < Options_.MaxCells))
        {
            var top       = pq_.First();
            var candidate = top.Item2;
            pq_.Remove(top);
            // For interior coverings we keep subdividing no matter how many children
            // the candidate has.  If we reach max_cells() before expanding all
            // children, we will just use some of them.  For exterior coverings we
            // cannot do this, because the result has to cover the whole region, so
            // all children have to be used.  The (candidate.num_children == 1) case
            // takes care of the situation when we already have more than max_cells()
            // in results (min_level is too high).  Subdividing the candidate with one
            // child does no harm in this case.
            if (interior_covering_ ||
                candidate.Cell.Level < Options_.MinLevel ||
                candidate.NumChildren == 1 ||
                (result.Count + pq_.Count + candidate.NumChildren <=
                 Options_.MaxCells))
            {
                // Expand this candidate into its children.
                for (int i = 0; i < candidate.NumChildren; ++i)
                {
                    if (interior_covering_ && result.Count >= Options_.MaxCells)
                    {
                        DeleteCandidate(candidate.Children[i], true);
                    }
                    else
                    {
                        AddCandidate(candidate.Children[i], result);
                    }
                }
                DeleteCandidate(candidate, false);
            }
            else
            {
                candidate.IsTerminal = true;
                AddCandidate(candidate, result);
            }
        }
        while (pq_.Any())
        {
            var top = pq_.First();
            DeleteCandidate(top.Item2, true);
            pq_.Remove(top);
        }
        region_ = null;

        // Rather than just returning the raw list of cell ids, we construct a cell
        // union and then denormalize it.  This has the effect of replacing four
        // child cells with their parent whenever this does not violate the covering
        // parameters specified (min_level, level_mod, etc).  This significantly
        // reduces the number of cells returned in many cases, and it is cheap
        // compared to computing the covering in the first place.
        S2CellUnion.Normalize(result);
        if (Options_.MinLevel > 0 || Options_.LevelMod > 1)
        {
            var result_copy = result.ToList();
            S2CellUnion.Denormalize(result_copy, Options_.MinLevel, Options_.LevelMod, result);
        }
        System.Diagnostics.Debug.Assert(IsCanonical(result));
        return(result);
    }
Esempio n. 16
0
        /**
         * Computes a list of cell ids that is contained within the given region and
         * satisfies the various restrictions specified above.
         *
         * @param region The region to fill
         * @param interior The list filled in by this method
         */

        public void GetInteriorCovering(IS2Region region, List <S2CellId> interior)
        {
            var tmp = GetInteriorCovering(region);

            tmp.Denormalize(MinLevel, LevelMod, interior);
        }
Esempio n. 17
0
 // Like GetCovering(), except that this method is much faster and the
 // coverings are not as tight.  All of the usual parameters are respected
 // (max_cells, min_level, max_level, and level_mod), except that the
 // implementation makes no attempt to take advantage of large values of
 // max_cells().  (A small number of cells will always be returned.)
 //
 // This function is useful as a starting point for algorithms that
 // recursively subdivide cells.
 public void GetFastCovering(IS2Region region, List <S2CellId> covering)
 {
     region.GetCellUnionBound(covering);
     CanonicalizeCovering(covering);
 }
Esempio n. 18
0
 public void GetInteriorCovering(IS2Region region, S2CellUnion covering)
 {
     _interiorCovering = true;
     GetCoveringInternal(region);
     covering.InitSwap(_result);
 }
Esempio n. 19
0
        /**
         * Given a connected region and a starting point, return a set of cells at the
         * given level that cover the region.
         */

        public static void GetSimpleCovering(
            IS2Region region, S2Point start, int level, List <S2CellId> output)
        {
            FloodFill(region, S2CellId.FromPoint(start).ParentForLevel(level), output);
        }