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(); }
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); }