Exemplo n.º 1
0
    public void Test_S2LatLngRect_CellOps()
    {
        // Contains(S2Cell), MayIntersect(S2Cell), Intersects(S2Cell)

        // Special cases.
        TestCellOps(S2LatLngRect.Empty, S2Cell.FromFacePosLevel(3, 0, 0), 0);
        TestCellOps(S2LatLngRect.Full, S2Cell.FromFacePosLevel(2, 0, 0), 4);
        TestCellOps(S2LatLngRect.Full, S2Cell.FromFacePosLevel(5, 0, 25), 4);

        // This rectangle includes the first quadrant of face 0.  It's expanded
        // slightly because cell bounding rectangles are slightly conservative.
        S2LatLngRect r4 = RectFromDegrees(-45.1, -45.1, 0.1, 0.1);

        TestCellOps(r4, S2Cell.FromFacePosLevel(0, 0, 0), 3);
        TestCellOps(r4, S2Cell.FromFacePosLevel(0, 0, 1), 4);
        TestCellOps(r4, S2Cell.FromFacePosLevel(1, 0, 1), 0);

        // This rectangle intersects the first quadrant of face 0.
        S2LatLngRect r5 = RectFromDegrees(-10, -45, 10, 0);

        TestCellOps(r5, S2Cell.FromFacePosLevel(0, 0, 0), 3);
        TestCellOps(r5, S2Cell.FromFacePosLevel(0, 0, 1), 3);
        TestCellOps(r5, S2Cell.FromFacePosLevel(1, 0, 1), 0);

        // Rectangle consisting of a single point.
        TestCellOps(RectFromDegrees(4, 4, 4, 4), S2Cell.FromFace(0), 3);

        // Rectangles that intersect the bounding rectangle of a face
        // but not the face itself.
        TestCellOps(RectFromDegrees(41, -87, 42, -79), S2Cell.FromFace(2), 1);
        TestCellOps(RectFromDegrees(-41, 160, -40, -160), S2Cell.FromFace(5), 1);

        // This is the leaf cell at the top right hand corner of face 0.
        // It has two angles of 60 degrees and two of 120 degrees.
        S2Cell cell0tr = new(new S2Point(1 + 1e-12, 1, 1));

        _ = cell0tr.GetRectBound();
        S2LatLng v0 = new(cell0tr.VertexRaw(0));

        TestCellOps(RectFromDegrees(v0.Lat().GetDegrees() - 1e-8,
                                    v0.Lng().GetDegrees() - 1e-8,
                                    v0.Lat().GetDegrees() - 2e-10,
                                    v0.Lng().GetDegrees() + 1e-10), cell0tr, 1);

        // Rectangles that intersect a face but where no vertex of one region
        // is contained by the other region.  The first one passes through
        // a corner of one of the face cells.
        TestCellOps(RectFromDegrees(-37, -70, -36, -20), S2Cell.FromFace(5), 2);

        // These two intersect like a diamond and a square.
        S2Cell       cell202  = S2Cell.FromFacePosLevel(2, 0, 2);
        S2LatLngRect bound202 = cell202.GetRectBound();

        TestCellOps(RectFromDegrees(bound202.Lo().Lat().GetDegrees() + 3,
                                    bound202.Lo().Lng().GetDegrees() + 3,
                                    bound202.Hi().Lat().GetDegrees() - 3,
                                    bound202.Hi().Lng().GetDegrees() - 3), cell202, 2);
    }
Exemplo n.º 2
0
        static void TestSubdivide(S2Cell cell)
        {
            GatherStats(cell);
            if (cell.IsLeaf())
            {
                return;
            }

            var children = new S2Cell[4];

            Assert.True(cell.Subdivide(children));
            S2CellId child_id     = cell.Id.ChildBegin();
            double   exact_area   = 0;
            double   approx_area  = 0;
            double   average_area = 0;

            for (int i = 0; i < 4; ++i, child_id = child_id.Next())
            {
                exact_area   += children[i].ExactArea();
                approx_area  += children[i].ApproxArea();
                average_area += children[i].AverageArea();

                // Check that the child geometry is consistent with its cell ID.
                Assert.Equal(child_id, children[i].Id);
                Assert.True(S2.ApproxEquals(children[i].Center(), child_id.ToPoint()));
                S2Cell direct = new(child_id);
                Assert.Equal(direct.Face, children[i].Face);
                Assert.Equal(direct.Level, children[i].Level);
                Assert.Equal(direct.Orientation, children[i].Orientation);
                Assert.Equal(direct.CenterRaw(), children[i].CenterRaw());
                for (int k = 0; k < 4; ++k)
                {
                    Assert.Equal(direct.VertexRaw(k), children[i].VertexRaw(k));
                    Assert.Equal(direct.EdgeRaw(k), children[i].EdgeRaw(k));
                }

                // Test Contains() and MayIntersect().
                Assert.True(cell.Contains(children[i]));
                Assert.True(cell.MayIntersect(children[i]));
                Assert.False(children[i].Contains(cell));
                Assert.True(cell.Contains(children[i].CenterRaw()));
                for (int j = 0; j < 4; ++j)
                {
                    Assert.True(cell.Contains(children[i].VertexRaw(j)));
                    if (j != i)
                    {
                        Assert.False(children[i].Contains(children[j].CenterRaw()));
                        Assert.False(children[i].MayIntersect(children[j]));
                    }
                }

                // Test GetCapBound and GetRectBound.
                S2Cap        parent_cap  = cell.GetCapBound();
                S2LatLngRect parent_rect = cell.GetRectBound();
                if (cell.Contains(new S2Point(0, 0, 1)) || cell.Contains(new S2Point(0, 0, -1)))
                {
                    Assert.True(parent_rect.Lng.IsFull());
                }
                S2Cap        child_cap  = children[i].GetCapBound();
                S2LatLngRect child_rect = children[i].GetRectBound();
                Assert.True(child_cap.Contains(children[i].Center()));
                Assert.True(child_rect.Contains(children[i].CenterRaw()));
                Assert.True(parent_cap.Contains(children[i].Center()));
                Assert.True(parent_rect.Contains(children[i].CenterRaw()));
                for (int j = 0; j < 4; ++j)
                {
                    Assert.True(child_cap.Contains(children[i].Vertex(j)));
                    Assert.True(child_rect.Contains(children[i].Vertex(j)));
                    Assert.True(child_rect.Contains(children[i].VertexRaw(j)));
                    Assert.True(parent_cap.Contains(children[i].Vertex(j)));
                    Assert.True(parent_rect.Contains(children[i].Vertex(j)));
                    Assert.True(parent_rect.Contains(children[i].VertexRaw(j)));
                    if (j != i)
                    {
                        // The bounding caps and rectangles should be tight enough so that
                        // they exclude at least two vertices of each adjacent cell.
                        int cap_count  = 0;
                        int rect_count = 0;
                        for (int k = 0; k < 4; ++k)
                        {
                            if (child_cap.Contains(children[j].Vertex(k)))
                            {
                                ++cap_count;
                            }
                            if (child_rect.Contains(children[j].VertexRaw(k)))
                            {
                                ++rect_count;
                            }
                        }
                        Assert.True(cap_count <= 2);
                        if (child_rect.LatLo().Radians > -S2.M_PI_2 &&
                            child_rect.LatHi().Radians < S2.M_PI_2)
                        {
                            // Bounding rectangles may be too large at the poles because the
                            // pole itself has an arbitrary fixed longitude.
                            Assert.True(rect_count <= 2);
                        }
                    }
                }

                // Check all children for the first few levels, and then sample randomly.
                // We also always subdivide the cells containing a few chosen points so
                // that we have a better chance of sampling the minimum and maximum metric
                // values.  kMaxSizeUV is the absolute value of the u- and v-coordinate
                // where the cell size at a given level is maximal.
                double    kMaxSizeUV = 0.3964182625366691;
                R2Point[] special_uv =
                {
                    new R2Point(S2.DoubleEpsilon, S2.DoubleEpsilon), // Face center
                    new R2Point(S2.DoubleEpsilon, 1),                // Edge midpoint
                    new R2Point(1, 1),                               // Face corner
                    new R2Point(kMaxSizeUV, kMaxSizeUV),             // Largest cell area
                    new R2Point(S2.DoubleEpsilon, kMaxSizeUV),       // Longest edge/diagonal
                };
                bool force_subdivide = false;
                foreach (R2Point uv in special_uv)
                {
                    if (children[i].BoundUV.Contains(uv))
                    {
                        force_subdivide = true;
                    }
                }

                var debugFlag =
#if s2debug
                    true;
#else
                    false;
#endif

                if (force_subdivide ||
                    cell.Level < (debugFlag ? 5 : 6) ||
                    S2Testing.Random.OneIn(debugFlag ? 5 : 4))
                {
                    TestSubdivide(children[i]);
                }
            }

            // Check sum of child areas equals parent area.
            //
            // For ExactArea(), the best relative error we can expect is about 1e-6
            // because the precision of the unit vector coordinates is only about 1e-15
            // and the edge length of a leaf cell is about 1e-9.
            //
            // For ApproxArea(), the areas are accurate to within a few percent.
            //
            // For AverageArea(), the areas themselves are not very accurate, but
            // the average area of a parent is exactly 4 times the area of a child.

            Assert.True(Math.Abs(Math.Log(exact_area / cell.ExactArea())) <= Math.Abs(Math.Log((1 + 1e-6))));
            Assert.True(Math.Abs(Math.Log((approx_area / cell.ApproxArea()))) <= Math.Abs(Math.Log((1.03))));
            Assert.True(Math.Abs(Math.Log((average_area / cell.AverageArea()))) <= Math.Abs(Math.Log((1 + 1e-15))));
        }