Exemplo n.º 1
0
    public void Test_S2RegionTermIndexer_MaxLevelSetLoosely()
    {
        // Test that correct terms are generated even when (max_level - min_level)
        // is not a multiple of level_mod.
        var options = new S2RegionTermIndexer.Options();

        options.MinLevel = (1);
        options.LevelMod = (2);
        options.MaxLevel = (19);
        var indexer1 = new S2RegionTermIndexer(options);

        options.MaxLevel = (20);
        var indexer2 = new S2RegionTermIndexer(options);

        S2Point point = S2Testing.RandomPoint();

        Assert.Equal(indexer1.GetIndexTerms(point, ""),
                     indexer2.GetIndexTerms(point, ""));
        Assert.Equal(indexer1.GetQueryTerms(point, ""),
                     indexer2.GetQueryTerms(point, ""));

        S2Cap cap = S2Testing.GetRandomCap(0.0, 1.0);  // Area range.

        Assert.Equal(indexer1.GetIndexTerms(cap, ""),
                     indexer2.GetIndexTerms(cap, ""));
        Assert.Equal(indexer1.GetQueryTerms(cap, ""),
                     indexer2.GetQueryTerms(cap, ""));
    }
Exemplo n.º 2
0
    public void Test_S2ConvexHullQuery_PointsInsideHull()
    {
        // Repeatedly build the convex hull of a set of points, then add more points
        // inside that loop and build the convex hull again.  The result should
        // always be the same.
        int kIters = 1000;

        for (int iter = 0; iter < kIters; ++iter)
        {
            S2Testing.Random.Reset(iter + 1);  // Easier to reproduce a specific case.

            // Choose points from within a cap of random size, up to but not including
            // an entire hemisphere.
            S2Cap             cap   = S2Testing.GetRandomCap(S2.DoubleError, 1.999 * Math.PI);
            S2ConvexHullQuery query = new();
            int num_points1         = S2Testing.Random.Uniform(100) + 3;
            for (int i = 0; i < num_points1; ++i)
            {
                query.AddPoint(S2Testing.SamplePoint(cap));
            }
            var hull = query.GetConvexHull();

            // When the convex hull is nearly a hemisphere, the algorithm sometimes
            // returns a full cap instead.  This is because it first computes a
            // bounding rectangle for all the input points/edges and then converts it
            // to a bounding cap, which sometimes yields a non-convex cap (radius
            // larger than 90 degrees).  This should not be a problem in practice
            // (since most convex hulls are not hemispheres), but in order make this
            // test pass reliably it means that we need to reject convex hulls whose
            // bounding cap (when computed from a bounding rectangle) is not convex.
            //
            // TODO(b/203702905): This test can still fail (about 1 iteration in
            // 500,000) because the S2LatLngRect::GetCapBound implementation does not
            // guarantee that A.Contains(B) implies
            // A.GetCapBound().Contains(B.GetCapBound()).
            if (hull.GetCapBound().Height() >= 1)
            {
                continue;
            }

            // Otherwise, add more points inside the convex hull.
            int num_points2 = 1000;
            for (int i = 0; i < num_points2; ++i)
            {
                S2Point p = S2Testing.SamplePoint(cap);
                if (hull.Contains(p))
                {
                    query.AddPoint(p);
                }
            }
            // Finally, build a new convex hull and check that it hasn't changed.
            var hull2 = (query.GetConvexHull());
            _logger.WriteLine("Iteration: " + iter);
            Assert.True(hull2.BoundaryEquals(hull));
        }
    }
Exemplo n.º 3
0
        public void Test_S2CellUnion_Expand()
        {
            // This test generates coverings for caps of random sizes, expands
            // the coverings by a random radius, and then make sure that the new
            // covering covers the expanded cap.  It also makes sure that the
            // new covering is not too much larger than expected.

            var coverer = new S2RegionCoverer();

            for (var i = 0; i < 1000; ++i)
            {
                _logger.WriteLine($"Iteration {i}");
                var cap = S2Testing.GetRandomCap(
                    S2Cell.AverageArea(S2.kMaxCellLevel), S2.M_4_PI);

                // Expand the cap area by a random factor whose log is uniformly
                // distributed between 0 and log(1e2).
                var expanded_cap = S2Cap.FromCenterHeight(
                    cap.Center, Math.Min(2.0, Math.Pow(1e2, rnd.RandDouble()) * cap.Height()));

                var radius         = (expanded_cap.Radius - cap.Radius).Radians();
                var max_level_diff = rnd.Uniform(8);

                // Generate a covering for the original cap, and measure the maximum
                // distance from the cap center to any point in the covering.
                coverer.Options_.MaxCells = 1 + rnd.Skewed(10);
                var covering = coverer.GetCovering(cap);
                S2Testing.CheckCovering(cap, covering, true);
                var covering_radius = GetRadius(covering, cap.Center);

                // This code duplicates the logic in Expand(min_radius, max_level_diff)
                // that figures out an appropriate cell level to use for the expansion.
                int min_level = S2.kMaxCellLevel;
                foreach (var id in covering)
                {
                    min_level = Math.Min(min_level, id.Level());
                }
                var expand_level = Math.Min(min_level + max_level_diff,
                                            S2.kMinWidth.GetLevelForMinValue(radius));

                // Generate a covering for the expanded cap, and measure the new maximum
                // distance from the cap center to any point in the covering.
                covering.Expand(S1Angle.FromRadians(radius), max_level_diff);
                S2Testing.CheckCovering(expanded_cap, covering, false);
                double expanded_covering_radius = GetRadius(covering, cap.Center);

                // If the covering includes a tiny cell along the boundary, in theory the
                // maximum angle of the covering from the cap center can increase by up to
                // twice the maximum length of a cell diagonal.
                Assert.True(expanded_covering_radius - covering_radius <=
                            2 * S2.kMaxDiag.GetValue(expand_level));
            }
        }
Exemplo n.º 4
0
        public void Test_S2RegionCoverer_SimpleCoverings()
        {
            Assert.True(false); //TODO

            const int kMaxLevel = S2.kMaxCellLevel;
            var       options   = new S2RegionCoverer.Options
            {
                MaxCells = Int32.MaxValue
            };

            for (int i = 0; i < 1000; ++i)
            {
                int level = S2Testing.Random.Uniform(kMaxLevel + 1);
                options.MinLevel = (level);
                options.MaxLevel = (level);
                double max_area = Math.Min(S2.M_4_PI, 1000 * S2Cell.AverageArea(level));
                S2Cap  cap      = S2Testing.GetRandomCap(0.1 * S2Cell.AverageArea(kMaxLevel), max_area);
                var    covering = new List <S2CellId>();
                S2RegionCoverer.GetSimpleCovering(cap, cap.Center, level, covering);
                CheckCovering(options, cap, covering, false);
            }
        }
Exemplo n.º 5
0
        public void Test_S2RegionCoverer_RandomCaps()
        {
            const int kMaxLevel = S2.kMaxCellLevel;

            S2RegionCoverer.Options options = new();
            for (int i = 0; i < 1000; ++i)
            {
                do
                {
                    options.MinLevel = (S2Testing.Random.Uniform(kMaxLevel + 1));
                    options.MaxLevel = (S2Testing.Random.Uniform(kMaxLevel + 1));
                } while (options.MinLevel > options.MaxLevel);
                options.MaxCells = S2Testing.Random.Skewed(10);
                options.LevelMod = (1 + S2Testing.Random.Uniform(3));
                double max_area = Math.Min(S2.M_4_PI, (3 * options.MaxCells + 1) *
                                           S2Cell.AverageArea(options.MinLevel));
                S2Cap cap = S2Testing.GetRandomCap(0.1 * S2Cell.AverageArea(kMaxLevel),
                                                   max_area);
                S2RegionCoverer coverer = new(options);
                coverer.GetCovering(cap, out var covering);
                CheckCovering(options, cap, covering, false);
                coverer.GetInteriorCovering(cap, out var interior);
                CheckCovering(options, cap, interior, true);

                // Check that GetCovering is deterministic.
                coverer.GetCovering(cap, out var covering2);
                Assert.Equal(covering, 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.
                S2CellUnion cells        = new(covering);
                var         denormalized = new List <S2CellId>();
                cells.Denormalize(options.MinLevel, options.LevelMod, denormalized);
                CheckCovering(options, cap, denormalized, false);
            }
        }
Exemplo n.º 6
0
    private void TestRandomCaps(S2RegionTermIndexer.Options options, QueryType query_type)
    {
        // This function creates an index consisting either of points (if
        // options.index_contains_points_only() is true) or S2Caps of random size.
        // It then executes queries consisting of points (if query_type == POINT)
        // or S2Caps of random size (if query_type == CAP).
        var indexer = new S2RegionTermIndexer(options);
        var coverer = new S2RegionCoverer(options);
        var caps = new List <S2Cap>();
        var coverings = new List <S2CellUnion>();
        var index = new Dictionary <string, List <int> >();
        int index_terms = 0, query_terms = 0;

        for (int i = 0; i < iters; ++i)
        {
            // Choose the region to be indexed: either a single point or a cap
            // of random size (up to a full sphere).
            S2Cap         cap;
            List <string> terms;
            if (options.IndexContainsPointsOnly)
            {
                cap   = S2Cap.FromPoint(S2Testing.RandomPoint());
                terms = indexer.GetIndexTerms(cap.Center, "");
            }
            else
            {
                cap = S2Testing.GetRandomCap(
                    0.3 * S2Cell.AverageArea(options.MaxLevel),
                    4.0 * S2Cell.AverageArea(options.MinLevel));
                terms = indexer.GetIndexTerms(cap, "");
            }
            caps.Add(cap);
            coverings.Add(coverer.GetCovering(cap));
            foreach (var term in terms)
            {
                if (!index.ContainsKey(term))
                {
                    index.Add(term, new List <int>());
                }

                index[term].Add(i);
            }
            index_terms += terms.Count;
        }
        for (int i = 0; i < iters; ++i)
        {
            // Choose the region to be queried: either a random point or a cap of
            // random size.
            S2Cap         cap;
            List <string> terms;
            if (query_type == QueryType.CAP)
            {
                cap   = S2Cap.FromPoint(S2Testing.RandomPoint());
                terms = indexer.GetQueryTerms(cap.Center, "");
            }
            else
            {
                cap = S2Testing.GetRandomCap(
                    0.3 * S2Cell.AverageArea(options.MaxLevel),
                    4.0 * S2Cell.AverageArea(options.MinLevel));
                terms = indexer.GetQueryTerms(cap, "");
            }
            // Compute the expected results of the S2Cell query by brute force.
            S2CellUnion covering = coverer.GetCovering(cap);
            var         expected = new List <int>();
            var         actual   = new List <int>();
            for (int j = 0; j < caps.Count; ++j)
            {
                if (covering.Intersects(coverings[j]))
                {
                    expected.Add(j);
                }
            }
            foreach (var term in terms)
            {
                actual.AddRange(index[term]);
            }
            Assert.Equal(expected, actual);
            query_terms += terms.Count;
        }
        _logger.WriteLine($"Index terms/doc: {((double)index_terms) / iters:2f},  Query terms/doc: {((double)query_terms) / iters:2f}");
    }