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)); } }
public void testUVAxes() { // Check that axes are consistent with FaceUVtoXYZ. for (var face = 0; face < 6; ++face) { assertEquals(S2Projections.GetUAxis(face), S2Projections.FaceUvToXyz(face, 1, 0) - S2Projections.FaceUvToXyz(face, 0, 0)); assertEquals(S2Projections.GetVAxis(face), S2Projections.FaceUvToXyz(face, 0, 1) - S2Projections.FaceUvToXyz(face, 0, 0)); } }
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))); }