I have a polygon clipping function in my OpenLayers app which may return me a multipolygon.
Unfortunately, my app does not support multipolygons by design. So I need to convert a multipolygon to single polygons somehow.
The purpose of my function is to delete everything below a specific polygon the user can drag. I'm basically deleting the old version of the polygon and replace this with the result I get from the difference-function from the polygon-clipping library. "Punch-out" function is the better term, I think.
Some pictures to illustrate what I mean:
I have some overlapping polygons (black) and the red one is my "punch-out-tool". The result I want is on the right side (just moved them apart a bit). This works for most cases already.
But the user can move the red polygon everywhere he wants, so this can happen:
In this case, I will get a multipolygon, which is not supported in my application.
My idea is to cut this multipolygon in half, somehow like this:
But this is not that easy to do for every case, because I could end up with multiple "holes" in my multipolygon, f. e. top left and bottom right...
My code so far: just for clarification, the first loop in my punch function is to prepare the coordinates for the polygon-clipping library. I'm not sure why, but I need to wrap my coordinates in another array.
The Difference function down below is where I may get my multipolygon. You can see that I just take the first one. The "singlePolygon" term is misleading here because it could be a Multipolygon.
function start(layers: MyLayer[], punchPolygon: Polygon): PunchOutValue[] {
const punchOutValues: PunchOutValue[] = [];
for (const layer of layers) {
if (!layer.objects.items.length) {
continue;
}
const value = punch(layer.objects.items, punchPolygon);
punchOutValues.push({
layer: layer,
newObjects: value.newObjects,
deleteThisObjects: value.deleteThisObjects,
});
}
return punchOutValues;
}
function punch(
existingObjects: Object[],
punchPolygon: PolygonClippingMultiPolygon): ImportPunchOutValue {
const modifiedObjects: ModifiedObject[] = [];
const deleteThisObjects: Object[] = [];
const existingObjectCollection: PolygonClippingMultiPolygon = [];
for (const object of existingObjects) {
const shape = object.shape;
if (shape.type === ObjectType.POLYGON) {
const multiPolygon = [shape.coordinates];
existingObjectCollection.push(multiPolygon as []);
}
}
//###################################################################################
const intersectResult = PolygonClippingIntersection(existingObjectCollection, punchPolygon);
if (intersectResult.length) {
for (const object of existingObjects) {
if (object.shape.type !== ObjectType.POLYGON) {
continue;
}
const multiPolygon = [object.shape.coordinates];
const objectInterSection = PolygonClippingIntersection(multiPolygon as [], punchPolygon);
if (!objectInterSection.length) {
continue;
}
const result = PolygonClippingDifference(multiPolygon as [], punchPolygon);
for (const singlePolygon of result) {
const modifiedObject: ModifiedObject = {
shape: {
type: ObjectType.POLYGON,
coordinates: singlePolygon[0],
},
};
modifiedObjects.push(modifiedObject);
}
deleteThisObjects.push(object);
}
}
return {
newObjects: modifiedObjects,
deleteThisObjects: deleteThisObjects,
};
}