public void testRandomCaps()
        {
            Console.WriteLine("TestRandomCaps");

            var kMaxLevel = S2CellId.MaxLevel;
            var coverer   = new S2RegionCoverer();

            for (var i = 0; i < 1000; ++i)
            {
                do
                {
                    coverer.MinLevel = random(kMaxLevel + 1);
                    coverer.MaxLevel = random(kMaxLevel + 1);
                } while (coverer.MinLevel > coverer.MaxLevel);
                coverer.MaxCells = skewed(10);
                coverer.LevelMod = 1 + random(3);
                var maxArea = Math.Min(
                    4 * S2.Pi, (3 * coverer.MaxCells + 1) * S2Cell.AverageArea(coverer.MinLevel));
                var cap      = getRandomCap(0.1 * S2Cell.AverageArea(kMaxLevel), maxArea);
                var covering = new List <S2CellId>();
                var interior = new List <S2CellId>();

                coverer.GetCovering(cap, covering);
                checkCovering(coverer, cap, covering, false);

                coverer.GetInteriorCovering(cap, interior);
                checkCovering(coverer, cap, interior, true);


                // Check that GetCovering is deterministic.
                var covering2 = new List <S2CellId>();
                coverer.GetCovering(cap, covering2);
                assertTrue(covering.SequenceEqual(covering2));

                // Also check S2CellUnion.denormalize(). The denormalized covering
                // may still be different and smaller than "covering" because
                // S2RegionCoverer does not guarantee that it will not output all four
                // children of the same parent.
                var cells = new S2CellUnion();
                cells.InitFromCellIds(covering);
                var denormalized = new List <S2CellId>();
                cells.Denormalize(coverer.MinLevel, coverer.LevelMod, denormalized);
                checkCovering(coverer, cap, denormalized, false);
            }
        }
        public void testRandomCaps()
        {
            Console.WriteLine("TestRandomCaps");

            var kMaxLevel = S2CellId.MaxLevel;
            var coverer = new S2RegionCoverer();
            for (var i = 0; i < 1000; ++i)
            {
                do
                {
                    coverer.MinLevel = random(kMaxLevel + 1);
                    coverer.MaxLevel = random(kMaxLevel + 1);
                } while (coverer.MinLevel > coverer.MaxLevel);
                coverer.MaxCells = skewed(10);
                coverer.LevelMod = 1 + random(3);
                var maxArea = Math.Min(
                    4*S2.Pi, (3*coverer.MaxCells + 1)*S2Cell.AverageArea(coverer.MinLevel));
                var cap = getRandomCap(0.1*S2Cell.AverageArea(kMaxLevel), maxArea);
                var covering = new List<S2CellId>();
                var interior = new List<S2CellId>();

                coverer.GetCovering(cap, covering);
                checkCovering(coverer, cap, covering, false);

                coverer.GetInteriorCovering(cap, interior);
                checkCovering(coverer, cap, interior, true);


                // Check that GetCovering is deterministic.
                var covering2 = new List<S2CellId>();
                coverer.GetCovering(cap, covering2);
                assertTrue(covering.SequenceEqual(covering2));

                // Also check S2CellUnion.denormalize(). The denormalized covering
                // may still be different and smaller than "covering" because
                // S2RegionCoverer does not guarantee that it will not output all four
                // children of the same parent.
                var cells = new S2CellUnion();
                cells.InitFromCellIds(covering);
                var denormalized = new List<S2CellId>();
                cells.Denormalize(coverer.MinLevel, coverer.LevelMod, denormalized);
                checkCovering(coverer, cap, denormalized, false);
            }
        }
Exemple #3
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);
    }
Exemple #4
0
    public void CanonicalizeCovering(List <S2CellId> covering)
    {
        // We check this on each call because of Options().
        System.Diagnostics.Debug.Assert(Options_.MinLevel <= Options_.MaxLevel);

        // Note that when the covering parameters have their default values, almost
        // all of the code in this function is skipped.

        // If any cells are too small, or don't satisfy level_mod(), then replace
        // them with ancestors.
        if (Options_.MaxLevel < S2.kMaxCellLevel || Options_.LevelMod > 1)
        {
            for (var i = 0; i < covering.Count; i++)
            {
                var id        = covering[i];
                int level     = id.Level();
                int new_level = AdjustLevel(Math.Min(level, Options_.MaxLevel));
                if (new_level != level)
                {
                    covering[i] = id.Parent(new_level);
                }
            }
        }

        // Sort the cells and simplify them.
        S2CellUnion.Normalize(covering);

        // Make sure that the covering satisfies min_level() and level_mod(),
        // possibly at the expense of satisfying max_cells().
        if (Options_.MinLevel > 0 || Options_.LevelMod > 1)
        {
            var tmp = new List <S2CellId>();
            S2CellUnion.Denormalize(covering, Options_.MinLevel, Options_.LevelMod, tmp);
            covering.Clear();
            covering.AddRange(tmp);
        }

        // If there are too many cells and the covering is very large, use the
        // S2RegionCoverer to compute a new covering.  (This avoids possible O(n^2)
        // behavior of the simpler algorithm below.)
        var excess = covering.Count - Options_.MaxCells;

        if (excess <= 0 || IsCanonical(covering))
        {
            return;
        }
        if (excess * covering.Count > 10000)
        {
            GetCovering(new S2CellUnion(covering), out covering);
        }
        else
        {
            // Repeatedly replace two adjacent cells in S2CellId order by their lowest
            // common ancestor until the number of cells is acceptable.
            while (covering.Count > Options_.MaxCells)
            {
                int best_index = -1, best_level = -1;
                for (int i = 0; i + 1 < covering.Count; ++i)
                {
                    int level = covering[i].CommonAncestorLevel(covering[i + 1]);
                    level = AdjustLevel(level);
                    if (level > best_level)
                    {
                        best_level = level;
                        best_index = i;
                    }
                }
                if (best_level < Options_.MinLevel)
                {
                    break;
                }

                // Replace all cells contained by the new ancestor cell.
                S2CellId id = covering[best_index].Parent(best_level);
                ReplaceCellsWithAncestor(covering, id);

                // Now repeatedly check whether all children of the parent cell are
                // present, in which case we can replace those cells with their parent.
                while (best_level > Options_.MinLevel)
                {
                    best_level -= Options_.LevelMod;
                    id          = id.Parent(best_level);
                    if (!ContainsAllChildren(covering, id))
                    {
                        break;
                    }
                    ReplaceCellsWithAncestor(covering, id);
                }
            }
        }
        System.Diagnostics.Debug.Assert(IsCanonical(covering));
    }