Exemplo n.º 1
0
        public void testFaceUVtoXYZ()
        {
            // Check that each face appears exactly once.
            var sum = new S2Point();

            for (var face = 0; face < 6; ++face)
            {
                var center = S2Projections.FaceUvToXyz(face, 0, 0);
                assertEquals(S2Projections.GetNorm(face), center);
                assertEquals(Math.Abs(center[center.LargestAbsComponent]), 1.0);
                sum = sum + S2Point.Fabs(center);
            }
            assertEquals(sum, new S2Point(2, 2, 2));

            // Check that each face has a right-handed coordinate system.
            for (var face = 0; face < 6; ++face)
            {
                assertEquals(
                    S2Point.CrossProd(S2Projections.GetUAxis(face), S2Projections.GetVAxis(face)).DotProd(
                        S2Projections.FaceUvToXyz(face, 0, 0)), 1.0);
            }

            // Check that the Hilbert curves on each face combine to form a
            // continuous curve over the entire cube.
            for (var face = 0; face < 6; ++face)
            {
                // The Hilbert curve on each face starts at (-1,-1) and terminates
                // at either (1,-1) (if axes not swapped) or (-1,1) (if swapped).
                var sign = ((face & S2.SwapMask) != 0) ? -1 : 1;
                assertEquals(S2Projections.FaceUvToXyz(face, sign, -sign),
                             S2Projections.FaceUvToXyz((face + 1) % 6, -1, -1));
            }
        }
Exemplo n.º 2
0
        public void testCells()
        {
            // For each cube face, we construct some cells on
            // that face and some caps whose positions are relative to that face,
            // and then check for the expected intersection/containment results.

            // The distance from the center of a face to one of its vertices.
            var kFaceRadius = Math.Atan(S2.Sqrt2);

            for (var face = 0; face < 6; ++face)
            {
                // The cell consisting of the entire face.
                var rootCell = S2Cell.FromFacePosLevel(face, (byte)0, 0);

                // A leaf cell at the midpoint of the v=1 edge.
                var edgeCell = new S2Cell(S2Projections.FaceUvToXyz(face, 0, 1 - EPS));

                // A leaf cell at the u=1, v=1 corner.
                var cornerCell = new S2Cell(S2Projections.FaceUvToXyz(face, 1 - EPS, 1 - EPS));

                // Quick check for full and empty caps.
                Assert.True(S2Cap.Full.Contains(rootCell));
                Assert.True(!S2Cap.Empty.MayIntersect(rootCell));

                // Check intersections with the bounding caps of the leaf cells that are
                // adjacent to 'corner_cell' along the Hilbert curve. Because this corner
                // is at (u=1,v=1), the curve stays locally within the same cube face.
                var first = cornerCell.Id.Previous.Previous.Previous;
                var last  = cornerCell.Id.Next.Next.Next.Next;
                for (var id = first; id < last; id = id.Next)
                {
                    var cell = new S2Cell(id);
                    JavaAssert.Equal(cell.CapBound.Contains(cornerCell), id.Equals(cornerCell.Id));
                    JavaAssert.Equal(
                        cell.CapBound.MayIntersect(cornerCell), id.Parent.Contains(cornerCell.Id));
                }

                var antiFace = (face + 3) % 6; // Opposite face.
                for (var capFace = 0; capFace < 6; ++capFace)
                {
                    // A cap that barely contains all of 'cap_face'.
                    var center   = S2Projections.GetNorm(capFace);
                    var covering = S2Cap.FromAxisAngle(center, S1Angle.FromRadians(kFaceRadius + EPS));
                    JavaAssert.Equal(covering.Contains(rootCell), capFace == face);
                    JavaAssert.Equal(covering.MayIntersect(rootCell), capFace != antiFace);
                    JavaAssert.Equal(covering.Contains(edgeCell), center.DotProd(edgeCell.Center) > 0.1);
                    JavaAssert.Equal(covering.Contains(edgeCell), covering.MayIntersect(edgeCell));
                    JavaAssert.Equal(covering.Contains(cornerCell), capFace == face);
                    JavaAssert.Equal(
                        covering.MayIntersect(cornerCell), center.DotProd(cornerCell.Center) > 0);

                    // A cap that barely intersects the edges of 'cap_face'.
                    var bulging = S2Cap.FromAxisAngle(center, S1Angle.FromRadians(S2.PiOver4 + EPS));
                    Assert.True(!bulging.Contains(rootCell));
                    JavaAssert.Equal(bulging.MayIntersect(rootCell), capFace != antiFace);
                    JavaAssert.Equal(bulging.Contains(edgeCell), capFace == face);
                    JavaAssert.Equal(bulging.MayIntersect(edgeCell), center.DotProd(edgeCell.Center) > 0.1);
                    Assert.True(!bulging.Contains(cornerCell));
                    Assert.True(!bulging.MayIntersect(cornerCell));

                    // A singleton cap.
                    var singleton = S2Cap.FromAxisAngle(center, S1Angle.FromRadians(0));
                    JavaAssert.Equal(singleton.MayIntersect(rootCell), capFace == face);
                    Assert.True(!singleton.MayIntersect(edgeCell));
                    Assert.True(!singleton.MayIntersect(cornerCell));
                }
            }
        }
        public void testSubdivide(S2Cell cell)
        {
            gatherStats(cell);
            if (cell.IsLeaf)
            {
                return;
            }

            var children = new S2Cell[4];

            for (var i = 0; i < children.Length; ++i)
            {
                children[i] = new S2Cell();
            }
            Assert.True(cell.Subdivide(children));
            var    childId     = cell.Id.ChildBegin;
            double exactArea   = 0;
            double approxArea  = 0;
            double averageArea = 0;

            for (var i = 0; i < 4; ++i, childId = childId.Next)
            {
                exactArea   += children[i].ExactArea();
                approxArea  += children[i].ApproxArea();
                averageArea += children[i].AverageArea();

                // Check that the child geometry is consistent with its cell id.
                JavaAssert.Equal(children[i].Id, childId);
                Assert.True(children[i].Center.ApproxEquals(childId.ToPoint(), 1e-15));
                var direct = new S2Cell(childId);
                JavaAssert.Equal(children[i].Face, direct.Face);
                JavaAssert.Equal(children[i].Level, direct.Level);
                JavaAssert.Equal(children[i].Orientation, direct.Orientation);
                JavaAssert.Equal(children[i].CenterRaw, direct.CenterRaw);
                for (var k = 0; k < 4; ++k)
                {
                    JavaAssert.Equal(children[i].GetVertexRaw(k), direct.GetVertexRaw(k));
                    JavaAssert.Equal(children[i].GetEdgeRaw(k), direct.GetEdgeRaw(k));
                }

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

                // Test GetCapBound and GetRectBound.
                var parentCap  = cell.CapBound;
                var parentRect = cell.RectBound;
                if (cell.Contains(new S2Point(0, 0, 1)) ||
                    cell.Contains(new S2Point(0, 0, -1)))
                {
                    Assert.True(parentRect.Lng.IsFull);
                }
                var childCap  = children[i].CapBound;
                var childRect = children[i].RectBound;
                Assert.True(childCap.Contains(children[i].Center));
                Assert.True(childRect.Contains(children[i].CenterRaw));
                Assert.True(parentCap.Contains(children[i].Center));
                Assert.True(parentRect.Contains(children[i].CenterRaw));
                for (var j = 0; j < 4; ++j)
                {
                    Assert.True(childCap.Contains(children[i].GetVertex(j)));
                    Assert.True(childRect.Contains(children[i].GetVertex(j)));
                    Assert.True(childRect.Contains(children[i].GetVertexRaw(j)));
                    Assert.True(parentCap.Contains(children[i].GetVertex(j)));
                    if (!parentRect.Contains(children[i].GetVertex(j)))
                    {
                        Console.WriteLine("cell: " + cell + " i: " + i + " j: " + j);
                        Console.WriteLine("Children " + i + ": " + children[i]);
                        Console.WriteLine("Parent rect: " + parentRect);
                        Console.WriteLine("Vertex raw(j) " + children[i].GetVertex(j));
                        Console.WriteLine("Latlng of vertex: " + new S2LatLng(children[i].GetVertex(j)));
                        Console.WriteLine("RectBound: " + cell.RectBound);
                    }
                    Assert.True(parentRect.Contains(children[i].GetVertex(j)));
                    if (!parentRect.Contains(children[i].GetVertexRaw(j)))
                    {
                        Console.WriteLine("cell: " + cell + " i: " + i + " j: " + j);
                        Console.WriteLine("Children " + i + ": " + children[i]);
                        Console.WriteLine("Parent rect: " + parentRect);
                        Console.WriteLine("Vertex raw(j) " + children[i].GetVertexRaw(j));
                        Console.WriteLine("Latlng of vertex: " + new S2LatLng(children[i].GetVertexRaw(j)));
                        Console.WriteLine("RectBound: " + cell.RectBound);
                    }
                    Assert.True(parentRect.Contains(children[i].GetVertexRaw(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.
                        var capCount  = 0;
                        var rectCount = 0;
                        for (var k = 0; k < 4; ++k)
                        {
                            if (childCap.Contains(children[j].GetVertex(k)))
                            {
                                ++capCount;
                            }
                            if (childRect.Contains(children[j].GetVertexRaw(k)))
                            {
                                ++rectCount;
                            }
                        }
                        Assert.True(capCount <= 2);
                        if (childRect.LatLo.Radians > -S2.PiOver2 &&
                            childRect.LatHi.Radians < S2.PiOver2)
                        {
                            // Bounding rectangles may be too large at the poles because the
                            // pole itself has an arbitrary fixed longitude.
                            Assert.True(rectCount <= 2);
                        }
                    }
                }

                // Check all children for the first few levels, and then sample randomly.
                // Also subdivide one corner cell, one edge cell, and one center cell
                // so that we have a better chance of sample the minimum metric values.
                var forceSubdivide = false;
                var center         = S2Projections.GetNorm(children[i].Face);
                var edge           = center + S2Projections.GetUAxis(children[i].Face);
                var corner         = edge + S2Projections.GetVAxis(children[i].Face);
                for (var j = 0; j < 4; ++j)
                {
                    var p = children[i].GetVertexRaw(j);
                    if (p.Equals(center) || p.Equals(edge) || p.Equals(corner))
                    {
                        forceSubdivide = true;
                    }
                }
                if (forceSubdivide || cell.Level < (DEBUG_MODE ? 5 : 6) ||
                    random(DEBUG_MODE ? 10 : 4) == 0)
                {
                    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(exactArea / cell.ExactArea())) <= Math
                        .Abs(Math.Log(1 + 1e-6)));
            Assert.True(Math.Abs(Math.Log(approxArea / cell.ApproxArea())) <= Math
                        .Abs(Math.Log(1.03)));
            Assert.True(Math.Abs(Math.Log(averageArea / cell.AverageArea())) <= Math
                        .Abs(Math.Log(1 + 1e-15)));
        }