Turf.js Error – How to Create Polygons from Existing GeoJSON Polygon Rings

geojsonleafletnode-jsturf

I'm getting the following error:

Uncaught (in promise) Error: Each LinearRing of a Polygon must have 4
or more Positions.

when trying to use @turf/turf module:

async function selectSubregion(e) {
        e.preventDefault();

        const subRegion = e.target.value;
        const geoJsonData = await GeoJSON();

        subFilterResults(subRegion);

        if (geojsonLayer) {
            map.removeLayer(geojsonLayer);
        }

        console.log(subRegion);
        console.log(geoJsonData);

        geoJsonData.features.forEach((feature) => {
            console.log(feature.properties.COUNTRY);
        });
        // Find corresponding feature in geojsonData
        const feature = geoJsonData.features
            .filter((feature) => {
                if (feature.geometry.type === 'Polygon') {
                    return feature.geometry.coordinates.every((ring) => ring.length >= 4);
                }

                if (feature.geometry.type === 'MultiPolygon') {
                    return feature.geometry.coordinates.every((polygon) =>
                        polygon.every((ring) => ring.length >= 4)
                    );
                }

                return false;
            })
            .find((feature) => feature.properties.COUNTRY === subRegion);
            // .find((feature) => feature.properties.NAME_EN === subRegion);

        console.log('feature:', feature);

        if (feature) {
            // Highlight the feature on the map
            geojsonLayer = L.geoJSON(feature, {
                style: {
                    color: '#06c',
                    weight: 1,
                    fillOpacity: 0.3
                }
            }).addTo(map);

            // Remove markers outside the selected region
            allMarkers.forEach((marker) => {
                // Using turf to check if the marker is outside the selected feature
                const point = turf.point([marker.getLatLng().lng, marker.getLatLng().lat]);
                
                const polygon = turf.polygon(feature.geometry.coordinates);

                console.log('point:', point, 'polygon:', polygon);
                if (!turf.booleanPointInPolygon(point.geometry.coordinates, polygon)) {
                    // Remove marker if it's outside
                    map.removeLayer(marker);
                }
            });
        }
    }

Best Answer

When you create polygon from selected feature coordinates with turf.polygon function, you have to take into account that selected feature might be polygon or multipolygon.

You have to check geometry type of the feature and then create either polygon with the turf.polygon function or multipolygon with the turf.multiPolygon function.

Relevant part of the code would then look something like this:

allMarkers.forEach((marker) => {
  const point = turf.point([marker.getLatLng().lng, marker.getLatLng().lat]);
  var polygon;
  if (feature.geometry.type == 'MultiPolygon')
    polygon = turf.multiPolygon(feature.geometry.coordinates);
  else {
    polygon = turf.polygon(feature.geometry.coordinates);
  }
  if (!turf.booleanPointInPolygon(point.geometry.coordinates, polygon)) {
    map.removeLayer(marker);
  }
});