Exemplo n.º 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();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Free all allocated memory for a linked geo structure. The caller is
        /// responsible for freeing memory allocated to input polygon struct.
        /// </summary>
        /// <param name="polygon">Pointer to the first polygon in the structure</param>
        /// <!-- Based off 3.1.1 -->
        public static void destroyLinkedPolygon(ref LinkedGeoPolygon polygon)
        {
            // flag to skip the input polygon
            bool             skip = true;
            LinkedGeoPolygon nextPolygon;
            LinkedGeoLoop    nextLoop;

            for (LinkedGeoPolygon currentPolygon = polygon; currentPolygon != null;
                 currentPolygon = nextPolygon)
            {
                for (LinkedGeoLoop currentLoop = currentPolygon.first;
                     currentLoop != null; currentLoop = nextLoop)
                {
                    destroyLinkedGeoLoop(ref currentLoop);
                    nextLoop = currentLoop.next;
                    // ReSharper disable once RedundantAssignment
                    currentLoop = null;
                }
                nextPolygon = currentPolygon.next;
                if (skip)
                {
                    // do not free the input polygon
                    skip = false;
                }
                else
                {
                    // ReSharper disable once RedundantAssignment
                    currentPolygon = null;
                }
            }
        }
Exemplo n.º 3
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();
        }
Exemplo n.º 4
0
        public void CreateLinkedGeo()
        {
            var polygon = new LinkedGeoPolygon();

            var loop = polygon.AddNewLinkedLoop();

            Assert.IsNotNull(loop);
            var coord = loop.AddLinkedCoord(Vertex1);

            Assert.IsNotNull(coord);
            coord = loop.AddLinkedCoord(Vertex2);
            Assert.IsNotNull(coord);
            coord = loop.AddLinkedCoord(Vertex3);
            Assert.IsNotNull(coord);

            loop = polygon.AddNewLinkedLoop();
            Assert.IsNotNull(loop);
            coord = loop.AddLinkedCoord(Vertex2);
            Assert.IsNotNull(coord);
            coord = loop.AddLinkedCoord(Vertex4);
            Assert.IsNotNull(coord);

            Assert.AreEqual(1, polygon.CountPolygons);
            Assert.AreEqual(2, polygon.CountLoops);
            Assert.AreEqual(3, polygon.First.Count);
            Assert.AreEqual(2, polygon.Last.Count);

            var nextPolygon = polygon.AddNewLinkedGeoPolygon();

            Assert.IsNotNull(nextPolygon);
            Assert.AreEqual(2, polygon.CountPolygons);

            polygon.Clear();
        }
Exemplo n.º 5
0
        /// <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);
        }
Exemplo n.º 6
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();
        }
Exemplo n.º 7
0
        /// <summary>
        /// Given a list of nested containers, find the one most deeply nested.
        /// </summary>
        /// <param name="polygons">Polygon containers to check</param>
        /// <param name="bboxes">Bounding boxes for polygons, used in point-in-poly check</param>
        /// <param name="polygonCount">Number of polygons in the list</param>
        /// <returns>Deepest container, or null if list is empty</returns>
        /// <!-- Based off 3.1.1 -->
        public static LinkedGeoPolygon findDeepestContainer(
            ref List <LinkedGeoPolygon> polygons, ref List <BBox> bboxes,
            int polygonCount)
        {
            // Set the initial return value to the first candidate
            LinkedGeoPolygon parent = polygonCount > 0 ? polygons[0] : null;

            // If we have multiple polygons, they must be nested inside each other.
            // Find the innermost polygon by taking the one with the most containers
            // in the list.
            if (polygonCount <= 1)
            {
                return(parent);
            }
            int max = -1;

            for (int i = 0; i < polygonCount; i++)
            {
                int count = countContainers(polygons[i].first, polygons, bboxes, polygonCount);
                if (count <= max)
                {
                    continue;
                }
                parent = polygons[i];
                max    = count;
            }
            return(parent);
        }
Exemplo n.º 8
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();
        }
Exemplo n.º 9
0
        /// <summary>
        /// Add a new linked loop to the current polygon
        /// </summary>
        /// <param name="polygon">Polygon to add loop to</param>
        /// <returns>Pointer to loop</returns>
        /// <!-- Based off 3.1.1 -->
        public static LinkedGeoLoop addNewLinkedLoop(ref LinkedGeoPolygon polygon)
        {
            LinkedGeoLoop loop = new LinkedGeoLoop();

            if (loop == null)
            {
                throw new Exception("FAIL: assert(loop != NULL)");
            }

            return(addLinkedLoop(ref polygon, ref loop));
        }
Exemplo n.º 10
0
        /// <summary>
        /// Add a linked polygon to the current polygon
        /// </summary>
        /// <param name="polygon">Polygon to add link to</param>
        /// <returns>Pointer to new polygon</returns>
        /// <!-- Based off 3.1.1 -->
        public static LinkedGeoPolygon addNewLinkedPolygon(ref LinkedGeoPolygon polygon)
        {
            if (polygon.next != null)
            {
                throw new Exception("assert(polygon->next == NULL);");
            }

            LinkedGeoPolygon next = new LinkedGeoPolygon();

            polygon.next = next;
            return(next);
        }
Exemplo n.º 11
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();
        }
Exemplo n.º 12
0
        /// <summary>
        /// Count the number of linked loops in a polygon
        /// </summary>
        /// <param name="polygon">Polygon to count loops for</param>
        /// <returns>Count</returns>
        /// <!-- Based off 3.1.1 -->
        public static int countLinkedLoops(ref LinkedGeoPolygon polygon)
        {
            LinkedGeoLoop loop  = polygon.first;
            int           count = 0;

            while (loop != null)
            {
                count++;
                loop = loop.next;
            }
            return(count);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Find the polygon to which a given hole should be allocated. Note that this
        /// function will return null if no parent is found.
        /// </summary>
        /// <param name="loop">Inner loop describing a hole</param>
        /// <param name="polygon">Head of a linked list of polygons to check</param>
        /// <param name="bboxes">Bounding boxes for polygons, used in point-in-poly check</param>
        /// <param name="polygonCount">Number of polygons to check</param>
        /// <returns>Pointer to parent polygon, or null if not found</returns>
        /// <!-- Based off 3.1.1 -->
        public static LinkedGeoPolygon findPolygonForHole(
            ref LinkedGeoLoop loop,
            ref LinkedGeoPolygon polygon,
            ref List <BBox> bboxes,
            int polygonCount)
        {
            // Early exit with no polygons
            if (polygonCount == 0)
            {
                return(null);
            }
            // Initialize arrays for candidate loops and their bounding boxes
            List <LinkedGeoPolygon> candidates      = new List <LinkedGeoPolygon>(polygonCount);
            List <BBox>             candidateBBoxes = new List <BBox>(polygonCount);

            for (var k = 0; k < polygonCount; k++)
            {
                candidates.Add(new LinkedGeoPolygon());
                candidateBBoxes.Add(new BBox());
            }

            // Find all polygons that contain the loop
            int candidateCount   = 0;
            int index            = 0;
            var polygonReference = polygon;

            while (polygonReference != null)
            {
                // We are guaranteed not to overlap, so just test the first point
                var bb = bboxes[index];
                if (
                    pointInsideLinkedGeoLoop(
                        ref polygonReference.first, ref bb, ref loop.first.vertex
                        )
                    )
                {
                    candidates[candidateCount]      = polygonReference;
                    candidateBBoxes[candidateCount] = bboxes[index];
                    candidateCount++;
                }
                polygonReference = polygonReference.next;
                index++;
            }

            // The most deeply nested container is the immediate parent
            LinkedGeoPolygon parent =
                findDeepestContainer(ref candidates, ref candidateBBoxes, candidateCount);

            // Free allocated memory
            candidates      = null;
            candidateBBoxes = null;
            return(parent);
        }
Exemplo n.º 14
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();
        }
Exemplo n.º 15
0
        /// <summary>
        /// Count the number of polygons in a linked list
        /// </summary>
        /// <param name="polygon">Starting polygon</param>
        /// <returns>Count</returns>
        /// <!-- Based off 3.1.1 -->
        public static int countLinkedPolygons(ref LinkedGeoPolygon polygon)
        {
            var polyIndex = polygon;
            int count     = 0;

            while (polyIndex != null)
            {
                count++;
                polyIndex = polyIndex.next;
            }
            return(count);
        }
Exemplo n.º 16
0
        public void Contiguous2()
        {
            List <H3Index> set = new List <H3Index> {
                0x8928308291bffff, 0x89283082957ffff
            };
            LinkedGeoPolygon polygon = set.ToLinkedGeoPolygon();

            Assert.AreEqual(1, polygon.CountLoops);
            Assert.IsNotNull(polygon.Loops.First());
            Assert.AreEqual(10, polygon.Loops.First().Count);

            polygon.Clear();
        }
Exemplo n.º 17
0
 public LinkedGeoPolygon(Code.LinkedGeo.LinkedGeoPolygon codeLinkedGeoPolygon)
 {
     if (codeLinkedGeoPolygon.first != null)
     {
         First = new LinkedGeoLoop(codeLinkedGeoPolygon.first);
     }
     if (codeLinkedGeoPolygon.last != null)
     {
         Last = new LinkedGeoLoop(codeLinkedGeoPolygon.last);
     }
     if (codeLinkedGeoPolygon.next != null)
     {
         Next = new LinkedGeoPolygon(codeLinkedGeoPolygon.next);
     }
 }
Exemplo n.º 18
0
        /// <summary>
        /// Add an existing linked loop to the current polygon
        /// </summary>
        /// <param name="polygon">Polygon to add loop to</param>
        /// <returns>Pointer to loop</returns>
        /// <!-- Based off 3.1.1 -->
        public static LinkedGeoLoop addLinkedLoop(ref LinkedGeoPolygon polygon, ref LinkedGeoLoop loop)
        {
            LinkedGeoLoop last = polygon.last;

            if (last == null)
            {
                if (polygon.first != null)
                {
                    throw new Exception("FAIL: assert(polygon->first == NULL)");
                }
                polygon.first = loop;
            }
            else
            {
                last.next = loop;
            }
            polygon.last = loop;
            return(loop);
        }
Exemplo n.º 19
0
        /// <summary>
        /// Find the polygon to which a given hole should be allocated. Note that this
        /// function will return null if no parent is found.
        /// </summary>
        /// <param name="loop">Inner loop describing a hole</param>
        /// <param name="polygon">Head of a linked list of polygons to check</param>
        /// <param name="boxes">Bounding boxes for polygons, used in point-in-poly check</param>
        /// <param name="polygonCount">Number of polygons to check</param>
        /// <returns>Pointer to parent polygon, or null if not found</returns>
        /// <!--
        /// linkedGeo.c
        /// static const LinkedGeoPolygon* findPolygonForHole
        /// -->
        private static LinkedGeoPolygon FindPolygonForHole(
            this LinkedGeoLoop loop, LinkedGeoPolygon polygon, List <BBox> boxes,
            int polygonCount
            )
        {
            // Early exit with no polygons
            if (polygonCount == 0)
            {
                return(null);
            }
            // Initialize arrays for candidate loops and their bounding boxes
            var candidates     = new List <LinkedGeoPolygon>();
            var candidateBoxes = new List <BBox>();

            // Find all polygons that contain the loop
            var index = 0;

            while (polygon != null)
            {
                // We are guaranteed not to overlap, so just test the first point
                if (polygon.Loops != null && loop.Nodes != null)
                {
                    if (polygon.Loops.First().PointInside(boxes[index], loop.Nodes.First().Vertex))
                    {
                        candidates.Add(polygon);
                        candidateBoxes.Add(boxes[index]);
                    }
                }
                polygon = polygon.Next;
                index++;
            }

            // The most deeply nested container is the immediate parent
            var parent = candidates.FindDeepestContainer(candidateBoxes);

            // Free allocated memory
            candidates.Clear();
            candidateBoxes.Clear();
            return((parent == null || parent.CountLoops == 0)
                       ? null
                       : parent);
        }
Exemplo n.º 20
0
            public void Clear()
            {
                if (First != null)
                {
                    First.Clear();
                    First = null;
                }

                if (Last != null)
                {
                    Last.Clear();
                    Last = null;
                }

                if (Next == null)
                {
                    return;
                }
                Next.Clear();
                Next = null;
            }
Exemplo n.º 21
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();
        }
Exemplo n.º 22
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();
        }
Exemplo n.º 23
0
        /// <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>0 on success, or an error code > 0 for invalid input</returns>
        /// <!-- Based off 3.1.1 -->
        public static int normalizeMultiPolygon(ref 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)
            {
                return(NORMALIZATION_ERR_MULTIPLE_POLYGONS);
            }

            // Count loops, exiting early if there's only one
            int loopCount = countLinkedLoops(ref root);

            if (loopCount <= 1)
            {
                return(NORMALIZATION_SUCCESS);
            }

            int resultCode           = NORMALIZATION_SUCCESS;
            LinkedGeoPolygon polygon = null;
            LinkedGeoLoop    next    = new LinkedGeoLoop();
            int innerCount           = 0;
            int 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.
            List <LinkedGeoLoop> innerLoops = new List <LinkedGeoLoop>(loopCount);

            for (var k = 0; k < loopCount; k++)
            {
                innerLoops.Add(new LinkedGeoLoop());
            }
            // Create an array to hold the bounding boxes for the outer loops
            List <BBox> bboxes = new List <BBox>(loopCount);

            for (var k = 0; k < loopCount; k++)
            {
                bboxes.Add(new BBox());
            }

            // Get the first loop and unlink it from root
            LinkedGeoLoop loop = root.first;

            root = new LinkedGeoPolygon();

            // Iterate over all loops, moving inner loops into an array and
            // assigning outer loops to new polygons
            while (loop != null)
            {
                if (isClockwiseLinkedGeoLoop(loop))
                {
                    innerLoops[innerCount] = loop;
                    innerCount++;
                }
                else
                {
                    polygon = polygon == null ? root : addNewLinkedPolygon(ref polygon);
                    addLinkedLoop(ref polygon, ref loop);
                    var bb = bboxes[outerCount];
                    bboxFromLinkedGeoLoop(ref loop, ref bb);
                    bboxes[outerCount] = bb;
                    outerCount++;
                }

                // get the next loop and unlink it from this one
                next      = loop.next;
                loop.next = null;
                loop      = next;
            }

            // Find polygon for each inner loop and assign the hole to it
            for (int i = 0; i < innerCount; i++)
            {
                var inner1 = innerLoops[i];
                polygon = findPolygonForHole(ref inner1, ref root, ref bboxes, outerCount);
                if (polygon != null)
                {
                    var inner2 = innerLoops[i];
                    addLinkedLoop(ref polygon, ref inner2);
                    innerLoops[i] = inner2;
                }
                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.
                    var inner2 = innerLoops[i];
                    destroyLinkedGeoLoop(ref inner2);
                    innerLoops[i] = null;
                    resultCode    = NORMALIZATION_ERR_UNASSIGNED_HOLES;
                }
            }
            return(resultCode);
        }
Exemplo n.º 24
0
        /// <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);
        }
Exemplo n.º 25
0
 public static void DestroyLinkedPolygon(ref LinkedGeoPolygon polygon)
 {
     polygon.Clear();
     polygon = null;
 }