Exemple #1
0
        public void NormalizeMultiPolygonOneHole()
        {
            var verts = MakeGeoCoordArray(new decimal[, ] {
                { 0, 0 }, { 0, 3 }, { 3, 3 }, { 3, 0 }
            });
            var outer = CreateLinkedLoop(verts);

            var verts2 = MakeGeoCoordArray(new decimal[, ] {
                { 1, 1 }, { 2, 2 }, { 1, 2 }
            });
            var inner = CreateLinkedLoop(verts2);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(inner);
            polygon.AddLinkedLoop(outer);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(result, Constants.LinkedGeo.NormalizationSuccess);
            Assert.AreEqual(polygon.CountPolygons, 1);
            Assert.AreEqual(polygon.CountLoops, 2);

            Assert.IsNotNull(polygon.Loops.First());
            Assert.AreEqual(polygon.Loops.First(), outer);

            Assert.IsNotNull(polygon.Loops[1]);
            Assert.AreEqual(polygon.Loops[1], inner);

            polygon.Clear();
        }
Exemple #2
0
        public void NormalizeMultiPolygonNoOuterLoops()
        {
            var verts = MakeGeoCoordArray(new  decimal[, ] {
                { 0, 0 }, { 1, 1 }, { 0, 1 }
            });
            var outer1 = CreateLinkedLoop(verts);

            var verts2 = MakeGeoCoordArray(new  decimal[, ] {
                { 2, 2 }, { 3, 3 }, { 2, 3 }
            });
            var outer2 = CreateLinkedLoop(verts2);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(outer1);
            polygon.AddLinkedLoop(outer2);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(H3Lib.Constants.LinkedGeo.NormalizationErrUnassignedHoles, result);

            Assert.AreEqual(1, polygon.CountPolygons);
            Assert.AreEqual(0, polygon.CountLoops);

            //polygon.Clear();
        }
Exemple #3
0
        public void NormalizeMultiPolygonTwoOuterLoops()
        {
            var verts1 = MakeGeoCoordArray(new decimal[, ] {
                { 0, 0 }, { 0, 1 }, { 1, 1 }
            });
            var outer1 = CreateLinkedLoop(verts1);

            var verts2 = MakeGeoCoordArray(new decimal[, ] {
                { 2, 2 }, { 2, 3 }, { 3, 3 }
            });
            var outer2 = CreateLinkedLoop(verts2);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(outer1);
            polygon.AddLinkedLoop(outer2);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(result, Constants.LinkedGeo.NormalizationSuccess);
            Assert.AreEqual(polygon.CountPolygons, 2);
            Assert.AreEqual(polygon.CountLoops, 1);
            Assert.AreEqual(polygon.Next.CountLoops, 1);

            polygon.Clear();
        }
Exemple #4
0
        public void NormalizeMultiPolygonNestedDonuts()
        {
            var verts = MakeGeoCoordArray(new[, ] {
                { 0.2m, 0.2m }, { 0.2m, -0.2m }, { -0.2m, -0.2m }, { -0.2m, 0.2m }
            });
            var outer = CreateLinkedLoop(verts);

            var verts2 = MakeGeoCoordArray(new[, ] {
                { 0.1m, 0.1m }, { -0.1m, 0.1m }, { -0.1m, -0.1m }, { 0.1m, -0.1m }
            });
            var inner = CreateLinkedLoop(verts2);

            var verts3 = MakeGeoCoordArray(new[, ] {
                { 0.6m, 0.6m }, { 0.6m, -0.6m }, { -0.6m, -0.6m }, { -0.6m, 0.6m }
            });
            var outerBig = CreateLinkedLoop(verts3);

            var verts4 = MakeGeoCoordArray(new[, ] {
                { 0.5m, 0.5m }, { -0.5m, 0.5m }, { -0.5m, -0.5m }, { 0.5m, -0.5m }
            });
            var innerBig = CreateLinkedLoop(verts4);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(inner);
            polygon.AddLinkedLoop(outerBig);
            polygon.AddLinkedLoop(innerBig);
            polygon.AddLinkedLoop(outer);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(result, Constants.LinkedGeo.NormalizationSuccess);
            Assert.AreEqual(polygon.CountPolygons, 2);
            Assert.AreEqual(polygon.CountLoops, 2);

            Assert.IsNotNull(polygon.Loops.First());
            Assert.AreEqual(polygon.Loops.First(), outerBig);

            Assert.IsNotNull(polygon.Loops[1]);
            Assert.AreEqual(polygon.Loops[1], innerBig);

            Assert.AreEqual(polygon.Next.CountLoops, 2);

            Assert.IsNotNull(polygon.Next.Loops.First());
            Assert.AreEqual(polygon.Next.Loops.First(), outer);

            Assert.IsNotNull(polygon.Next.Loops[1]);
            Assert.AreEqual(polygon.Next.Loops[1], inner);

            polygon.Clear();
        }
Exemple #5
0
        public void NormalizeMultiPolygonTwoDonuts()
        {
            var verts = MakeGeoCoordArray(new decimal[, ] {
                { 0, 0 }, { 0, 3 }, { 3, 3 }, { 3, 0 }
            });
            var outer = CreateLinkedLoop(verts);

            var verts2 = MakeGeoCoordArray(new decimal[, ] {
                { 1, 1 }, { 2, 2 }, { 1, 2 }
            });
            var inner = CreateLinkedLoop(verts2);

            var verts3 = MakeGeoCoordArray(new decimal[, ] {
                { 0, 0 }, { 0, -3 }, { -3, -3 }, { -3, 0 }
            });
            var outer2 = CreateLinkedLoop(verts3);

            var verts4 = MakeGeoCoordArray(new decimal[, ] {
                { -1, -1 }, { -2, -2 }, { -1, -2 }
            });
            var inner2 = CreateLinkedLoop(verts4);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(inner2);
            polygon.AddLinkedLoop(inner);
            polygon.AddLinkedLoop(outer);
            polygon.AddLinkedLoop(outer2);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(result, Constants.LinkedGeo.NormalizationSuccess);
            Assert.AreEqual(polygon.CountPolygons, 2);
            Assert.AreEqual(polygon.CountLoops, 2);

            Assert.IsNotNull(polygon.Loops.First());
            Assert.AreEqual(polygon.Loops.First().Count, 4);

            Assert.IsNotNull(polygon.Loops[1]);
            Assert.AreEqual(polygon.Loops[1].Count, 3);

            Assert.AreEqual(polygon.Next.CountLoops, 2);

            Assert.IsNotNull(polygon.Next.Loops.First());
            Assert.AreEqual(polygon.Next.Loops.First().Count, 4);

            Assert.IsNotNull(polygon.Next.Loops[1]);
            Assert.AreEqual(polygon.Next.Loops[1].Count, 3);

            polygon.Clear();
        }
        /// <summary>
        /// Internal: Create a LinkedGeoPolygon from a vertex graph. It is the
        /// responsibility of the caller to call destroyLinkedPolygon on the populated
        /// linked geo structure, or the memory for that structure will not be freed.
        /// </summary>
        /// <param name="graph">Input graph</param>
        /// <returns>Output polygon</returns>
        /// <!--
        /// algos.c
        /// void _vertexGraphToLinkedGeo
        /// -->
        public static LinkedGeoPolygon ToLinkedGeoPolygon(this VertexGraph graph)
        {
            var result = new LinkedGeoPolygon();

            while (graph.Count > 0)
            {
                var edge = graph.FirstNode();
                var loop = new LinkedGeoLoop();
                while (edge.HasValue)
                {
                    loop.AddLinkedCoord(edge.Value.From);
                    //loop.GeoCoordList.AddLast(edge.Value.From);
                    var nextVertex = edge.Value.To;
                    graph.RemoveNode(edge.Value);
                    edge = graph.FindVertex(nextVertex);
                }

                if (loop.Count > 0)
                {
                    result.AddLinkedLoop(loop);
                }
            }

            return(result);
        }
Exemple #7
0
        public void NormalizeMultiPolygonSingle()
        {
            var verts = MakeGeoCoordArray(new decimal[, ] {
                { 0, 0 }, { 0, 1 }, { 1, 1 }
            });

            var outer = CreateLinkedLoop(verts);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(outer);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(result, Constants.LinkedGeo.NormalizationSuccess);
            Assert.AreEqual(polygon.CountPolygons, 1);
            Assert.AreEqual(polygon.CountLoops, 1);
            if (polygon.Loops.First() != null)
            {
                Assert.AreEqual(polygon.Loops.First(), outer);
            }

            polygon.Clear();
        }
Exemple #8
0
        public void NormalizeMultiPolygonTwoHoles()
        {
            var verts = MakeGeoCoordArray(new decimal[, ] {
                { 0, 0 }, { 0, 0.4m }, { 0.4m, 0.4m }, { 0.4m, 0 }
            });
            var outer = CreateLinkedLoop(verts);

            var verts2 = MakeGeoCoordArray(new decimal[, ] {
                { 0.1m, 0.1m }, { 0.2m, 0.2m }, { 0.1m, 0.2m }
            });
            var inner1 = CreateLinkedLoop(verts2);

            var verts3 = MakeGeoCoordArray(new decimal[, ] {
                { 0.2m, 0.2m }, { 0.3m, 0.3m }, { 0.2m, 0.3m }
            });
            var inner2 = CreateLinkedLoop(verts3);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(inner2);
            polygon.AddLinkedLoop(outer);
            polygon.AddLinkedLoop(inner1);

            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(result, Constants.LinkedGeo.NormalizationSuccess);
            Assert.AreEqual(polygon.CountPolygons, 1);

            Assert.IsNotNull(polygon.Loops.First());
            Assert.AreEqual(polygon.Loops.First(), outer);

            Assert.AreEqual(polygon.CountLoops, 3);

            polygon.Clear();
        }
Exemple #9
0
        public void NormalizeMultiPolygonAlreadyNormalized()
        {
            var verts1 = MakeGeoCoordArray(new  decimal[, ] {
                { 0, 0 }, { 0, 1 }, { 1, 1 }
            });
            var outer1 = CreateLinkedLoop(verts1);

            var verts2 = MakeGeoCoordArray(new  decimal[, ] {
                { 2, 2 }, { 2, 3 }, { 3, 3 }
            });
            var outer2 = CreateLinkedLoop(verts2);

            var polygon = new LinkedGeoPolygon();

            polygon.AddLinkedLoop(outer1);
            var next = polygon.AddNewLinkedGeoPolygon();

            next.AddLinkedLoop(outer2);

            // Should be a no-op
            int result;

            (result, polygon) = polygon.NormalizeMultiPolygon();

            Assert.AreEqual(H3Lib.Constants.LinkedGeo.NormalizationErrMultiplePolygons, result);

            Assert.AreEqual(2, polygon.CountPolygons);
            Assert.AreEqual(1, polygon.CountLoops);

            Assert.IsNotNull(polygon.Loops.First());
            Assert.AreEqual(outer1, polygon.Loops.First());

            Assert.AreEqual(1, polygon.Next.CountLoops);
            Assert.IsNotNull(polygon.Next.Loops.First());
            Assert.AreEqual(outer2, polygon.Next.Loops.First());

            polygon.Clear();
        }
        /// <summary>
        /// Normalize a LinkedGeoPolygon in-place into a structure following GeoJSON
        /// MultiPolygon rules: Each polygon must have exactly one outer loop, which
        /// must be first in the list, followed by any holes. Holes in this algorithm
        /// are identified by winding order (holes are clockwise), which is guaranteed
        /// by the h3SetToVertexGraph algorithm.
        ///
        /// Input to this function is assumed to be a single polygon including all
        /// loops to normalize. It's assumed that a valid arrangement is possible.
        /// </summary>
        /// <param name="root">Root polygon including all loops</param>
        /// <returns>
        /// Tuple
        /// Item1 - 0 on success, or an error code > 0 for invalid input
        /// Item2 - Normalized LinkedGeoPolygon
        /// </returns>
        /// <!--
        /// linkedGeo.c
        /// int normalizeMultiPolygon
        /// -->
        public static (int, LinkedGeoPolygon) NormalizeMultiPolygon(this LinkedGeoPolygon root)
        {
            // We assume that the input is a single polygon with loops;
            // if it has multiple polygons, don't touch it
            if (root.Next != null)
            {
                //  TODO: Check the constant location and update
                return(Constants.LinkedGeo.NormalizationErrMultiplePolygons, root);
            }

            // Count loops, exiting early if there's only one
            int loopCount = root.CountLoops;

            if (loopCount <= 1)
            {
                return(Constants.LinkedGeo.NormalizationSuccess, root);
            }

            int resultCode           = Constants.LinkedGeo.NormalizationSuccess;
            LinkedGeoPolygon polygon = null;
            var innerCount           = 0;
            var outerCount           = 0;


            // Create an array to hold all of the inner loops. Note that
            // this array will never be full, as there will always be fewer
            // inner loops than outer loops.
            var innerLoops = new List <LinkedGeoLoop>();
            // Create an array to hold the bounding boxes for the outer loops
            var bboxes = new List <BBox>();

            // Get the first loop and unlink it from root
            var testLoops = root.Loops;//.GeoLoopList.First;

            root = new LinkedGeoPolygon();

            foreach (var geoLoop in testLoops)
            {
                if (geoLoop.IsClockwise())
                {
                    innerLoops.Add(geoLoop);
                    innerCount++;
                }
                else
                {
                    polygon = polygon == null
                                  ? root
                                  : polygon.AddNewLinkedGeoPolygon();
                    polygon.AddLinkedLoop(geoLoop);
                    bboxes.Add(geoLoop.ToBBox());
                    outerCount++;
                }
            }

            // Find polygon for each inner loop and assign the hole to it
            for (var i = 0; i < innerCount; i++)
            {
                polygon = innerLoops[i].FindPolygonForHole(root, bboxes, outerCount);
                if (polygon != null)
                {
                    polygon.AddLinkedLoop(innerLoops[i]);
                }
                else
                {
                    // If we can't find a polygon (possible with invalid input), then
                    // we need to release the memory for the hole, because the loop has
                    // been unlinked from the root and the caller will no longer have
                    // a way to destroy it with destroyLinkedPolygon.
                    innerLoops[i].Clear();
                    resultCode = Constants.LinkedGeo.NormalizationErrUnassignedHoles;
                }
            }
            // Free allocated memory
            innerLoops.Clear();
            bboxes.Clear();

            return(resultCode, root);
        }