public void testDisjoint() { var builder = new S2PolygonBuilder(S2PolygonBuilderOptions.UndirectedXor); builder.AddPolygon(adj0); builder.AddPolygon(unAdj); var ab = new S2Polygon(); assertTrue(builder.AssemblePolygon(ab, null)); var union = new S2Polygon(); union.InitToUnion(adj0, unAdj); assertEquals(2, union.NumLoops); checkEqual(ab, union); tryUnion(adj0, unAdj); }
private void checkEqual(S2Polygon a, S2Polygon b) { var MAX_ERROR = 1e-31; if (a.IsNormalized && b.IsNormalized) { var r = a.BoundaryApproxEquals(b, MAX_ERROR); assertTrue(r); } else { var builder = new S2PolygonBuilder(S2PolygonBuilderOptions.UndirectedXor); var a2 = new S2Polygon(); var b2 = new S2Polygon(); builder.AddPolygon(a); assertTrue(builder.AssemblePolygon(a2, null)); builder.AddPolygon(b); assertTrue(builder.AssemblePolygon(b2, null)); assertTrue(a2.BoundaryApproxEquals(b2, MAX_ERROR)); } }
private void addChain(Chain chain, S2Point x, S2Point y, S2Point z, double maxPerturbation, S2PolygonBuilder builder) { // Transform the given edge chain to the frame (x,y,z), perturb each vertex // up to the given distance, and add it to the builder. var vertices = new List <S2Point>(); getVertices(chain.str, x, y, z, maxPerturbation, vertices); if (chain.closed) { vertices.Add(vertices[0]); } for (var i = 1; i < vertices.Count; ++i) { builder.AddEdge(vertices[i - 1], vertices[i]); } }
private bool testBuilder(TestCase test) { for (var iter = 0; iter < 200; ++iter) { // Initialize to the default options, which are changed below var options = S2PolygonBuilderOptions.DirectedXor; options.UndirectedEdges = evalTristate(test.undirectedEdges); options.XorEdges = evalTristate(test.xorEdges); // Each test has a minimum and a maximum merge distance. The merge // distance must be at least the given minimum to ensure that all expected // merging will take place, and it must be at most the given maximum to // ensure that no unexpected merging takes place. // // If the minimum and maximum values are different, we have some latitude // to perturb the vertices as long as the merge distance is adjusted // appropriately. If "p" is the maximum perturbation distance, "min" and // "max" are the min/max merge distances, and "m" is the actual merge // distance for this test, we require that // // x >= min + 2*p and x <= max - 2*p . // // This implies that p <= 0.25 * (max - min). We choose "p" so that it is // zero half of the time, and otherwise chosen randomly up to this limit. var minMerge = S1Angle.FromDegrees(test.minMerge).Radians; var maxMerge = S1Angle.FromDegrees(test.maxMerge).Radians; var r = Math.Max(0.0, 2*rand.NextDouble() - 1); var maxPerturbation = r*0.25*(maxMerge - minMerge); // Now we set the merge distance chosen randomly within the limits above // (min + 2*p and max - 2*p). Half of the time we set the merge distance // to the minimum value. r = Math.Max(0.0, 2*rand.NextDouble() - 1); options.MergeDistance = S1Angle.FromRadians( minMerge + 2*maxPerturbation + r*(maxMerge - minMerge - 4*maxPerturbation)); options.Validate = true; var builder = new S2PolygonBuilder(options); // On each iteration we randomly rotate the test case around the sphere. // This causes the S2PolygonBuilder to choose different first edges when // trying to build loops. var x = randomPoint(); var y = S2Point.Normalize(S2Point.CrossProd(x, randomPoint())); var z = S2Point.Normalize(S2Point.CrossProd(x, y)); foreach (var chain in test.chainsIn) { addChain(chain, x, y, z, maxPerturbation, builder); } var loops = new List<S2Loop>(); var unusedEdges = new List<S2Edge>(); if (test.xorEdges < 0) { builder.AssembleLoops(loops, unusedEdges); } else { var polygon = new S2Polygon(); builder.AssemblePolygon(polygon, unusedEdges); polygon.Release(loops); } var expected = new List<S2Loop>(); foreach (var loop in test.loopsOut) { var vertices = new List<S2Point>(); getVertices(loop, x, y, z, 0, vertices); expected.Add(new S2Loop(vertices)); } // We assume that the vertex locations in the expected output polygon // are separated from the corresponding vertex locations in the input // edges by at most half of the minimum merge distance. Essentially // this means that the expected output vertices should be near the // centroid of the various input vertices. var maxError = 0.5*minMerge + maxPerturbation; // Note single "|" below so that we print both sets of loops. if (findMissingLoops(loops, expected, maxError, "Actual") | findMissingLoops(expected, loops, maxError, "Expected")) { Console.Error.WriteLine( "During iteration " + iter + ", undirected: " + options.UndirectedEdges + ", xor: " + options.XorEdges + "\n\n"); return false; } if (unusedEdges.Count != test.numUnusedEdges) { Console.Error.WriteLine("Wrong number of unused edges: " + unusedEdges.Count + " (should be " + test.numUnusedEdges + ")\n"); return false; } } return true; }
private void addChain(Chain chain, S2Point x, S2Point y, S2Point z, double maxPerturbation, S2PolygonBuilder builder) { // Transform the given edge chain to the frame (x,y,z), perturb each vertex // up to the given distance, and add it to the builder. var vertices = new List<S2Point>(); getVertices(chain.str, x, y, z, maxPerturbation, vertices); if (chain.closed) { vertices.Add(vertices[0]); } for (var i = 1; i < vertices.Count; ++i) { builder.AddEdge(vertices[i - 1], vertices[i]); } }
private bool testBuilder(TestCase test) { for (var iter = 0; iter < 200; ++iter) { // Initialize to the default options, which are changed below var options = S2PolygonBuilderOptions.DirectedXor; options.UndirectedEdges = evalTristate(test.undirectedEdges); options.XorEdges = evalTristate(test.xorEdges); // Each test has a minimum and a maximum merge distance. The merge // distance must be at least the given minimum to ensure that all expected // merging will take place, and it must be at most the given maximum to // ensure that no unexpected merging takes place. // // If the minimum and maximum values are different, we have some latitude // to perturb the vertices as long as the merge distance is adjusted // appropriately. If "p" is the maximum perturbation distance, "min" and // "max" are the min/max merge distances, and "m" is the actual merge // distance for this test, we require that // // x >= min + 2*p and x <= max - 2*p . // // This implies that p <= 0.25 * (max - min). We choose "p" so that it is // zero half of the time, and otherwise chosen randomly up to this limit. var minMerge = S1Angle.FromDegrees(test.minMerge).Radians; var maxMerge = S1Angle.FromDegrees(test.maxMerge).Radians; var r = Math.Max(0.0, 2 * rand.NextDouble() - 1); var maxPerturbation = r * 0.25 * (maxMerge - minMerge); // Now we set the merge distance chosen randomly within the limits above // (min + 2*p and max - 2*p). Half of the time we set the merge distance // to the minimum value. r = Math.Max(0.0, 2 * rand.NextDouble() - 1); options.MergeDistance = S1Angle.FromRadians( minMerge + 2 * maxPerturbation + r * (maxMerge - minMerge - 4 * maxPerturbation)); options.Validate = true; var builder = new S2PolygonBuilder(options); // On each iteration we randomly rotate the test case around the sphere. // This causes the S2PolygonBuilder to choose different first edges when // trying to build loops. var x = randomPoint(); var y = S2Point.Normalize(S2Point.CrossProd(x, randomPoint())); var z = S2Point.Normalize(S2Point.CrossProd(x, y)); foreach (var chain in test.chainsIn) { addChain(chain, x, y, z, maxPerturbation, builder); } var loops = new List <S2Loop>(); var unusedEdges = new List <S2Edge>(); if (test.xorEdges < 0) { builder.AssembleLoops(loops, unusedEdges); } else { var polygon = new S2Polygon(); builder.AssemblePolygon(polygon, unusedEdges); polygon.Release(loops); } var expected = new List <S2Loop>(); foreach (var loop in test.loopsOut) { var vertices = new List <S2Point>(); getVertices(loop, x, y, z, 0, vertices); expected.Add(new S2Loop(vertices)); } // We assume that the vertex locations in the expected output polygon // are separated from the corresponding vertex locations in the input // edges by at most half of the minimum merge distance. Essentially // this means that the expected output vertices should be near the // centroid of the various input vertices. var maxError = 0.5 * minMerge + maxPerturbation; // Note single "|" below so that we print both sets of loops. if (findMissingLoops(loops, expected, maxError, "Actual") | findMissingLoops(expected, loops, maxError, "Expected")) { Console.Error.WriteLine( "During iteration " + iter + ", undirected: " + options.UndirectedEdges + ", xor: " + options.XorEdges + "\n\n"); return(false); } if (unusedEdges.Count != test.numUnusedEdges) { Console.Error.WriteLine("Wrong number of unused edges: " + unusedEdges.Count + " (should be " + test.numUnusedEdges + ")\n"); return(false); } } return(true); }