int normalizeMultiPolygon()

in src/h3lib/lib/linkedGeo.c [293:367]


int normalizeMultiPolygon(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) {
        return NORMALIZATION_ERR_MULTIPLE_POLYGONS;
    }

    // Count loops, exiting early if there's only one
    int loopCount = countLinkedLoops(root);
    if (loopCount <= 1) {
        return NORMALIZATION_SUCCESS;
    }

    int resultCode = NORMALIZATION_SUCCESS;
    LinkedGeoPolygon* polygon = NULL;
    LinkedGeoLoop* next;
    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.
    LinkedGeoLoop** innerLoops =
        H3_MEMORY(malloc)(loopCount * sizeof(LinkedGeoLoop*));
    assert(innerLoops != NULL);

    // Create an array to hold the bounding boxes for the outer loops
    BBox* bboxes = H3_MEMORY(malloc)(loopCount * sizeof(BBox));
    assert(bboxes != NULL);

    // Get the first loop and unlink it from root
    LinkedGeoLoop* loop = root->first;
    *root = (LinkedGeoPolygon){0};

    // Iterate over all loops, moving inner loops into an array and
    // assigning outer loops to new polygons
    while (loop) {
        if (isClockwiseLinkedGeoLoop(loop)) {
            innerLoops[innerCount] = loop;
            innerCount++;
        } else {
            polygon = polygon == NULL ? root : addNewLinkedPolygon(polygon);
            addLinkedLoop(polygon, loop);
            bboxFromLinkedGeoLoop(loop, &bboxes[outerCount]);
            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++) {
        polygon = (LinkedGeoPolygon*)findPolygonForHole(innerLoops[i], root,
                                                        bboxes, outerCount);
        if (polygon) {
            addLinkedLoop(polygon, 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.
            destroyLinkedGeoLoop(innerLoops[i]);
            H3_MEMORY(free)(innerLoops[i]);
            resultCode = NORMALIZATION_ERR_UNASSIGNED_HOLES;
        }
    }

    // Free allocated memory
    H3_MEMORY(free)(innerLoops);
    H3_MEMORY(free)(bboxes);

    return resultCode;
}