public void testUnionSloppySuccess()
        {
            var polygons = new List <S2Polygon>();

            polygons.Add(adj0);
            polygons.Add(adj1);
            var union = S2Polygon.DestructiveUnionSloppy(polygons, S1Angle.FromDegrees(0.1));

            assertEquals(1, union.NumLoops);
            if (union.NumLoops != 1)
            {
                return;
            }
            var s2Loop = union.Loop(0);

            assertEquals(8, s2Loop.NumVertices);
            if (s2Loop.NumVertices != 8)
            {
                return;
            }
            assertPointApproximatelyEquals(s2Loop, 0, 2.0, 0.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 1, 1.0, 0.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 2, 0.0, 0.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 3, 0.0, 1.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 4, 0.0, 2.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 5, 1.0, 2.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 6, 2.0, 2.0, 0.01);
            assertPointApproximatelyEquals(s2Loop, 7, 2.0, 1.0, 0.01);
        }
Esempio n. 2
0
        private static void TestS2Polygon(string[] input_strs, string expected_str, EdgeType edge_type)
        {
            S2Builder builder = new(new Options());
            S2Polygon output  = new();

            builder.StartLayer(new S2PolygonLayer(
                                   output, new S2PolygonLayer.Options(edge_type)));
            bool is_full = false;

            foreach (var input_str in input_strs)
            {
                if (input_str == "full")
                {
                    is_full = true;
                }
                builder.AddPolygon(MakeVerbatimPolygonOrDie(input_str));
            }
            builder.AddIsFullPolygonPredicate(IsFullPolygon(is_full));
            Assert.True(builder.Build(out var error));
            // The input strings in tests may not be in normalized form, so we build an
            // S2Polygon and convert it back to a string.
            S2Polygon expected = MakePolygonOrDie(expected_str);

            Assert.Equal(expected.ToDebugString(),
                         output.ToDebugString());
        }
Esempio n. 3
0
    private static bool InternalMakePolygon(string str, bool normalize_loops, out S2Polygon polygon)
    {
        polygon = null;
        if (str == "empty")
        {
            str = "";
        }
        var loop_strs = SplitString(str, ';');
        var loops     = new List <S2Loop>();

        foreach (var loop_str in loop_strs)
        {
            if (!MakeLoop(loop_str, out var loop))
            {
                return(false);
            }
            // Don't normalize loops that were explicitly specified as "full".
            if (normalize_loops && !loop.IsFull())
            {
                loop.Normalize();
            }
            loops.Add(loop);
        }
        polygon = new S2Polygon(loops);
        return(true);
    }
        public void testUnionSloppyFailure()
        {
            var polygons = new List <S2Polygon>();

            polygons.Add(adj0);
            polygons.Add(unAdj);
            // The polygons are sufficiently far apart that this angle will not
            // bring them together:
            var union = S2Polygon.DestructiveUnionSloppy(polygons, S1Angle.FromDegrees(0.1));

            assertEquals(2, union.NumLoops);
        }
Esempio n. 5
0
 // Add a polygon to the input geometry.
 public void AddPolygon(S2Polygon polygon)
 {
     for (int i = 0; i < polygon.NumLoops(); ++i)
     {
         var loop = polygon.Loop(i);
         // Only loops at depth 0 can contribute to the convex hull.
         if (loop.Depth == 0)
         {
             AddLoop(loop);
         }
     }
 }
Esempio n. 6
0
    public void Test_MakePolygon_ValidInput()
    {
        Assert.True(MakePolygon("-20:150, -20:151, -19:150", out var polygon));
        var vertices = new[]
        {
            S2LatLng.FromDegrees(-20, 150).ToPoint(),
            S2LatLng.FromDegrees(-20, 151).ToPoint(),
            S2LatLng.FromDegrees(-19, 150).ToPoint(),
        };
        var expected = new S2Polygon(new S2Loop(vertices));

        Assert.True(polygon == expected);
    }
Esempio n. 7
0
    public void Test_MakeVerbatimPolygon_ValidInput()
    {
        Assert.True(MakeVerbatimPolygon("-20:150, -20:151, -19:150", out var polygon));
        var vertices = new[]
        {
            new [] { -20, 150 },
            new [] { -20, 151 },
            new [] { -19, 150 },
        }.Select(t => S2LatLng.FromDegrees(t[0], t[1]).ToPoint());
        var expected = new S2Polygon(new S2Loop(vertices));

        Assert.Equal(polygon, expected);
    }
Esempio n. 8
0
    public static string ToDebugString(this S2Polygon polygon, string loop_separator = ";\n")
    {
        if (polygon.IsEmpty())
        {
            return("empty");
        }
        else if (polygon.IsFull())
        {
            return("full");
        }
        var loops = polygon.Loops().Select(t => AppendVertices(t.Vertices, t.NumVertices));

        return(string.Join(loop_separator, loops));
    }
        public void tryUnion(S2Polygon a, S2Polygon b)
        {
            var union = new S2Polygon();

            union.InitToUnion(a, b);

            var polygons = new List <S2Polygon>();

            polygons.Add(new S2Polygon(a));
            polygons.Add(new S2Polygon(b));
            var destructiveUnion = S2Polygon.DestructiveUnion(polygons);

            checkEqual(union, destructiveUnion);
        }
Esempio n. 10
0
        public void Test_IndexedS2PolygonLayer_AddsShape()
        {
            S2Builder           builder = new(new Options());
            MutableS2ShapeIndex index   = new();

            builder.StartLayer(new IndexedS2PolygonLayer(index));
            string polygon_str = "0:0, 0:10, 10:0";

            builder.AddPolygon(MakePolygonOrDie(polygon_str));
            Assert.True(builder.Build(out _));
            Assert.Equal(1, index.NumShapeIds());
            S2Polygon polygon = ((S2Polygon.Shape)index.Shape(0)).Polygon;

            Assert.Equal(polygon_str, polygon.ToDebugString());
        }
Esempio n. 11
0
    // Converts a 2-dimensional S2Shape into an S2Polygon. Each chain is converted
    // to an S2Loop and the vector of loops is used to construct the S2Polygon.
    public static S2Polygon ShapeToS2Polygon(S2Shape poly)
    {
        if (poly.IsFull())
        {
            return new S2Polygon(S2Loop.kFull);
        }
        System.Diagnostics.Debug.Assert(poly.Dimension() == 2);
        List<S2Loop> loops = new();
        for (int i = 0; i < poly.NumChains(); ++i)
        {
            S2.GetChainVertices(poly, i, out var vertices);
            loops.Add(new S2Loop(vertices));
        }
        var output_poly = new S2Polygon(loops, initOriented: true);

        return output_poly;
    }
        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 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;
        }
Esempio n. 15
0
        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 assertRelation(S2Polygon a, S2Polygon b, int contains, bool intersects)
 {
     assertEquals(a.Contains(b), contains > 0);
     assertEquals(b.Contains(a), contains < 0);
     assertEquals(a.Intersects(b), intersects);
 }
Esempio n. 17
0
    public void Test_FullPolygon()
    {
        var full = new S2Polygon(S2Loop.kFull);

        Assert.Equal("full", full.ToDebugString());
    }
Esempio n. 18
0
    public void Test_EmptyPolygon()
    {
        var empty = new S2Polygon();

        Assert.Equal("empty", empty.ToDebugString());
    }
        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));
            }
        }
Esempio n. 20
0
 // As above, but does not Debug.Assert-fail on invalid input. Returns true if
 // conversion is successful.
 public static bool MakeVerbatimPolygon(string str, out S2Polygon polygon)
 {
     return(InternalMakePolygon(str, false, out polygon));
 }
Esempio n. 21
0
 // As above, but does not Debug.Assert-fail on invalid input. Returns true if
 // conversion is successful.
 public static bool MakePolygon(string str, out S2Polygon polygon)
 {
     return(InternalMakePolygon(str, true, out polygon));
 }
        public void tryUnion(S2Polygon a, S2Polygon b)
        {
            var union = new S2Polygon();
            union.InitToUnion(a, b);

            var polygons = new List<S2Polygon>();
            polygons.Add(new S2Polygon(a));
            polygons.Add(new S2Polygon(b));
            var destructiveUnion = S2Polygon.DestructiveUnion(polygons);

            checkEqual(union, destructiveUnion);
        }
        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 assertRelation(S2Polygon a, S2Polygon b, int contains, bool intersects)
 {
     assertEquals(a.Contains(b), contains > 0);
     assertEquals(b.Contains(a), contains < 0);
     assertEquals(a.Intersects(b), intersects);
 }