H3Error normalizeMultiPolygon()

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


H3Error 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 E_FAILED;
    }

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

    H3Error resultCode = E_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 destroyLinkedMultiPolygon.
            destroyLinkedGeoLoop(innerLoops[i]);
            H3_MEMORY(free)(innerLoops[i]);
            resultCode = E_FAILED;
        }
    }

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

    return resultCode;
}