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