How would I mask a geojson
that looks like this
{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[102,2],[103,2],[103,3],[102,3],[102,2]]],[[[100,0],[101,0],[101,1],[100,1],[100,0]],[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]]],[[[100.3,0.3],[100.7,0.3],[100.7,0.7],[100.3,0.7],[100.3,0.3]],[[100.4305160192801,0.67817296142852],[100.43926588878527,0.6777431305923907],[100.44793148784716,0.6764577778174132],[100.45642935778174,0.6743292824257617],[100.46467765559704,0.6713781440787653],[100.47259694234847,0.667632785305691],[100.48011094831709,0.6631292777150927],[100.48714730763562,0.6579109945286341],[100.49363825528266,0.6520281927874464],[100.49952127973005,0.6455375292587178],[100.50473972495757,0.6385015147088778],[100.50924333603814,0.6309879118031904],[100.5129887430422,0.6230690824341719],[100.51593987860606,0.6148212907677792],[100.51806832514795,0.6063239687221135],[100.51935358839506,0.5976589509544159],[100.51978329459449,0.5889096867249723],[100.51935330951578,0.5801604362283926],[100.51806777810651,0.5714954591315431],[100.51593908442491,0.56299820313176],[100.51298773224117,0.5547505003481902],[100.50924214746165,0.5468317792832317],[100.50473840428187,0.5393182999407914],[100.49951987770788,0.5322824194649319],[100.4936368257929,0.5257918953685365],[100.48714590561279,0.5199092330597317],[100.48010962764015,0.5146910839473947],[100.47259575377038,0.5101876999202546],[100.46467664479428,0.5064424494514895],[100.45642856359898,0.503491399987565],[100.4479309408045,0.5013629706420072],[100.43926560990533,0.5000776585380188],[100.4305160192801,0.49964784143480295],[100.42176642865488,0.5000776585380188],[100.41310109775573,0.5013629706420072],[100.40460347496123,0.503491399987565],[100.39635539376593,0.5064424494514895],[100.38843628478985,0.5101876999202546],[100.38092241092006,0.5146910839473947],[100.37388613294743,0.5199092330597317],[100.3673952127673,0.5257918953685367],[100.36151216085236,0.5322824194649319],[100.35629363427834,0.5393182999407915],[100.35178989109856,0.5468317792832317],[100.34804430631903,0.5547505003481902],[100.34509295413531,0.56299820313176],[100.34296426045371,0.5714954591315431],[100.34167872904445,0.5801604362283926],[100.34124874396572,0.5889096867249723],[100.34167845016515,0.5976589509544159],[100.34296371341229,0.6063239687221135],[100.34509215995416,0.6148212907677792],[100.34804329551801,0.6230690824341718],[100.35178870252209,0.6309879118031904],[100.35629231360264,0.6385015147088778],[100.36151075883018,0.6455375292587178],[100.36739378327755,0.6520281927874465],[100.37388473092459,0.6579109945286342],[100.3809210902431,0.6631292777150927],[100.38843509621175,0.667632785305691],[100.39635438296318,0.6713781440787653],[100.40460268077847,0.6743292824257617],[100.41310055071305,0.6764577778174132],[100.42176614977494,0.6777431305923907],[100.4305160192801,0.67817296142852]]],[[[101.2,0.2],[101.8,0.2],[101.8,0.8],[101.2,0.8],[101.2,0.2]],[[101.3,0.3],[101.3,0.7],[101.7,0.7],[101.7,0.3],[101.3,0.3]]]]},"properties":{"name":"Dinagat Islands"}}]}
As you can see, the bottom left polygon is in the shape of a 'nested donut'.
This is what I have so far (which I have adapted from this answere)
const maskWithPossibleInnerRings = (geometry, cover) => {
const coords = turf.getCoords(geometry);
const outerRings = [];
const innerRings = [];
coords.forEach(function (polyCoords) {
polyCoords.forEach(function (linearRing, i) {
if (i == 0) {
outerRings.push([linearRing]);
} else {
var poly = turf.rewind(turf.polygon([linearRing]));
innerRings.push(turf.getCoords(poly)[0]);
}
});
});
const outerRingsPoly = turf.multiPolygon(outerRings);
const maskedOuterRingsPoly = turf.mask(outerRingsPoly, cover);
const maskedOuterRings = turf.getCoords(maskedOuterRingsPoly);
const allRings = [maskedOuterRings];
innerRings.forEach(innerRing => allRings.push([innerRing]));
const finalPoly = turf.multiPolygon(allRings);
console.log('RESULT')
console.log(JSON.stringify(finalPoly))
return finalPoly;
};
The result looks like this
Not quite what I want. I think the problem starts here:
const outerRingsPoly = turf.multiPolygon(outerRings);
outerRingsPoly
looks like this
which is a problem for the next line
const maskedOuterRingsPoly = turf.mask(outerRingsPoly, cover);
maskedOuterRingsPoly
looks like this
So only the largest polygon gets used for mask()
. I want the result to look like this though
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"MultiPolygon","coordinates":[[[[180,90],[-180,90],[-180,-90],[180,-90],[180,90]],[[100,0],[101,0],[101,1],[100,1],[100,0]],[[101.2,0.2],[101.8,0.2],[101.8,0.8],[101.2,0.8],[101.2,0.2]],[[102,2],[103,2],[103,3],[102,3],[102,2]]],[[[100.2,0.2],[100.2,0.8],[100.8,0.8],[100.8,0.2],[100.2,0.2]],[[100.3,0.3],[100.7,0.3],[100.7,0.7],[100.3,0.7],[100.3,0.3]]],[[[100.4305160192801,0.67817296142852],[100.43926588878527,0.6777431305923907],[100.44793148784716,0.6764577778174132],[100.45642935778174,0.6743292824257617],[100.46467765559704,0.6713781440787653],[100.47259694234847,0.667632785305691],[100.48011094831709,0.6631292777150927],[100.48714730763562,0.6579109945286341],[100.49363825528266,0.6520281927874464],[100.49952127973005,0.6455375292587178],[100.50473972495757,0.6385015147088778],[100.50924333603814,0.6309879118031904],[100.5129887430422,0.6230690824341719],[100.51593987860606,0.6148212907677792],[100.51806832514795,0.6063239687221135],[100.51935358839506,0.5976589509544159],[100.51978329459449,0.5889096867249723],[100.51935330951578,0.5801604362283926],[100.51806777810651,0.5714954591315431],[100.51593908442491,0.56299820313176],[100.51298773224117,0.5547505003481902],[100.50924214746165,0.5468317792832317],[100.50473840428187,0.5393182999407914],[100.49951987770788,0.5322824194649319],[100.4936368257929,0.5257918953685365],[100.48714590561279,0.5199092330597317],[100.48010962764015,0.5146910839473947],[100.47259575377038,0.5101876999202546],[100.46467664479428,0.5064424494514895],[100.45642856359898,0.503491399987565],[100.4479309408045,0.5013629706420072],[100.43926560990533,0.5000776585380188],[100.4305160192801,0.49964784143480295],[100.42176642865488,0.5000776585380188],[100.41310109775573,0.5013629706420072],[100.40460347496123,0.503491399987565],[100.39635539376593,0.5064424494514895],[100.38843628478985,0.5101876999202546],[100.38092241092006,0.5146910839473947],[100.37388613294743,0.5199092330597317],[100.3673952127673,0.5257918953685367],[100.36151216085236,0.5322824194649319],[100.35629363427834,0.5393182999407915],[100.35178989109856,0.5468317792832317],[100.34804430631903,0.5547505003481902],[100.34509295413531,0.56299820313176],[100.34296426045371,0.5714954591315431],[100.34167872904445,0.5801604362283926],[100.34124874396572,0.5889096867249723],[100.34167845016515,0.5976589509544159],[100.34296371341229,0.6063239687221135],[100.34509215995416,0.6148212907677792],[100.34804329551801,0.6230690824341718],[100.35178870252209,0.6309879118031904],[100.35629231360264,0.6385015147088778],[100.36151075883018,0.6455375292587178],[100.36739378327755,0.6520281927874465],[100.37388473092459,0.6579109945286342],[100.3809210902431,0.6631292777150927],[100.38843509621175,0.667632785305691],[100.39635438296318,0.6713781440787653],[100.40460268077847,0.6743292824257617],[100.41310055071305,0.6764577778174132],[100.42176614977494,0.6777431305923907],[100.4305160192801,0.67817296142852]]],[[[101.3,0.3],[101.3,0.7],[101.7,0.7],[101.7,0.3],[101.3,0.3]]]]}}]}
How would I go on about masking polygons with a varying deep number of outer- and innerrings when I must do it in GeoJson? What kind of "rule" should I follow?
- Find outer most rings (how)?
- Apply proposed code (see above) to all most outer rings
- Do some winding to all the other outer- and inner rings
- Put everything together
Here is a fiddle to play with: http://jsfiddle.net/86x0bj5t/2/
Best Answer
Problem when masking complex multipolygon is with polygons which are inside hole of another polygon. These polygons have to be treated a bit differently:
Proof of concept code for the multipolygon from the question could then look something like this:
This is the result (using Leaflet for display):