2

I have need to split a polygon into multiple polygons based on the line strings drawn on the polygon. I have come across another post that splits a polygon into two based one line string. If a new line is drawn then the existing lines are ignored and the polygon is split into two based on the new line. What I want to achieve is 'split a polygon into multiple polygons based on multiple line.

 var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
  var osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors';
  var osm = L.tileLayer(osmUrl, { maxZoom: 18, attribution: osmAttrib });
  var drawnItems = L.featureGroup();

  var map = new L.Map('map', { center: new L.LatLng(51.505, -0.04), zoom: 13 });

  osm.addTo(map);
  drawnItems.addTo(map);

  map.addControl(new L.Control.Draw({
    draw: {
      marker: false,
      circle: false,
      circlemarker: false,
      rectangle: false,
      polygon: {
        allowIntersection: false,
        showArea: true
      }
    }
  }));

  function cutPolygon(polygon, line, direction, id) {
    var i = -1;
    var j;
    var polyCoords = [];
    var retVal = null;

    if ((polygon.type != 'Polygon') || (line.type != 'LineString')) return retVal;
    if (line.coordinates.length != 2) return retVal;

    var intersectPoints = turf.lineIntersect(polygon, line);
    var nPoints = intersectPoints.features.length;
    if ((nPoints == 0) || ((nPoints % 2) != 0)) return retVal;

    var offsetLine = turf.lineOffset(line, (0.01 * direction), {units: 'kilometers'});
    var thickLineCorners = turf.featureCollection([line, offsetLine]);
    var thickLinePolygon = turf.convex(turf.explode(thickLineCorners));

    var clipped = turf.difference(polygon, thickLinePolygon);

    for (j = 0; j < clipped.geometry.coordinates.length; j++) {
      var polyg = turf.polygon(clipped.geometry.coordinates[j]);
      var overlap = turf.lineOverlap(polyg, line, {tolerance: 0.005});
      if (overlap.features.length > 0) {
        polyCoords[++i] = turf.coordAll(polyg);
      };
    };

    if (i == 0)
      retVal = turf.polygon(polyCoords, {id: id});
    else if (i > 0) {
      retVal = turf.multiPolygon([polyCoords], {id: id});
    }

    return retVal;
  };

  var polygons = [];
  var layers = [];

  map.on(L.Draw.Event.CREATED, function (event) {
    var layer = event.layer;
    drawnItems.addLayer(layer);

    var geojson = layer.toGeoJSON();
    var geom = turf.getGeom(geojson);

    if (geom.type == 'Polygon')
      polygons.push(geom);
    else if (geom.type == 'LineString') {
      var line = geom;
      layers.forEach(function (layer, index) {
        layer.remove();
      });
      layers = [];
      polygons.forEach(function (polygon, index) {
        var layer;
        var upperCut = cutPolygon(polygon, line, 1, 'upper');
        if (upperCut != null) {
          layer = L.geoJSON(upperCut, {
            style: function(feature) {
              return {color: 'green' };
            }
          }).addTo(map);   
          layers.push(layer);
        };
        var lowerCut = cutPolygon(polygon, line, -1, 'lower');
        if (lowerCut != null) {
          layer = L.geoJSON(lowerCut, {
            style: function(feature) {
              return {color: 'yellow' };
            }
          }).addTo(map);
          layers.push(layer);
        };
      });
    };
  });

I want the polygon split into 12 polygons. now it's just two(green & yellow).

I got this from this here

Example of what I am looking for

New contributor
Arul Rozario is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • Welcome to GIS SE! We're a little different from other sites. We're a Q&A site, not a discussion forum. For questions that involve code we ask that you show us where you are stuck with your own code by including a code snippet in your question. There is an edit button beneath your question which will enable you to do that and a {} button that enables you to format any highlighted code nicely. Please check out our short tour for more about how the site works. Thanks. – PolyGeo Oct 10 at 9:07
1

Code mentioned in the question was produced as kind of a proof of concept that polygons can be splitted with Turf.js library (see Client-Side Polygon split) It's not very robust and thoroughly tested.

Below is modified code which allows to split polygons multiple times with lines that have multiple points. Again it not robust and thoroughly tested, just a basic proof of concept.

At each step (split) the following layers and arrays are updated:

  • Layer drawnPolygons contains all polygons, split and unsplit
  • Layer drawnLines contains all lines used for splitting
  • Array polygons contains all polygons that correspond to drawnPolygons layer

The main part of the code:

function cutPolygon(polygon, line, direction, id) {
  var j;
  var polyCoords = [];
  var cutPolyGeoms = [];
  var retVal = null;

  if ((polygon.type != 'Polygon') || (line.type != 'LineString')) return retVal;

  var intersectPoints = turf.lineIntersect(polygon, line);
  var nPoints = intersectPoints.features.length;
  if ((nPoints == 0) || ((nPoints % 2) != 0)) return retVal;

  var offsetLine = turf.lineOffset(line, (0.01 * direction), {units: 'kilometers'});

  for (j = 0; j < line.coordinates.length; j++) {
    polyCoords.push(line.coordinates[j]);
  }
   for (j = (offsetLine.geometry.coordinates.length - 1); j >= 0; j--) {
    polyCoords.push(offsetLine.geometry.coordinates[j]);
  }
  polyCoords.push(line.coordinates[0]);
  var thickLineString = turf.lineString(polyCoords);
  var thickLinePolygon = turf.lineToPolygon(thickLineString);   

  var clipped = turf.difference(polygon, thickLinePolygon);  
  for (j = 0; j < clipped.geometry.coordinates.length; j++) {
    var polyg = turf.polygon(clipped.geometry.coordinates[j]);
    var overlap = turf.lineOverlap(polyg, line, {tolerance: 0.005});
    if (overlap.features.length > 0) {
      cutPolyGeoms.push(polyg.geometry.coordinates);
    };
  };

  if (cutPolyGeoms.length == 1)
    retVal = turf.polygon(cutPolyGeoms[0], {id: id});
  else if (cutPolyGeoms.length > 1) {
    retVal = turf.multiPolygon(cutPolyGeoms, {id: id});
  }

  return retVal;
};

var polygons = [];

map.on(L.Draw.Event.CREATED, function (event) {
  var layer = event.layer;

  var geojson = layer.toGeoJSON();
  var geom = turf.getGeom(geojson);

  if (geom.type == 'Polygon') {
    polygons.push(geom);
    drawnPolygons.addLayer(layer);
    }
  else if (geom.type == 'LineString') {
    var line = geom;
    drawnLines.addLayer(layer);
    drawnPolygons.clearLayers();
    var newPolygons = [];
    polygons.forEach(function (polygon, index) {
      var cutDone = false;
      var layer;
      var upperCut = cutPolygon(polygon, line, 1, 'upper');
      var lowerCut = cutPolygon(polygon, line, -1, 'lower');
      if ((upperCut != null) && (lowerCut != null)) {
        layer = L.geoJSON(upperCut, {
          style: function(feature) {
            return {color: 'green' };
          }
        }).addTo(drawnPolygons);   
        layer = L.geoJSON(lowerCut, {
          style: function(feature) {
            return {color: 'yellow' };
          }
        }).addTo(drawnPolygons);
        cutDone = true;
      };
      if (cutDone) {
        newPolygons.push(upperCut.geometry);
        newPolygons.push(lowerCut.geometry);
        }
      else {
        newPolygons.push(polygon);
        layer = L.geoJSON(polygon, {
          style: function(feature) {
            return {color: '#3388ff' };
          }
        }).addTo(drawnPolygons);   
      }
    });
    polygons = newPolygons;
  };
});

Working JSFiddle is available at https://jsfiddle.net/TomazicM/x1a4d9ho/.

1

I have managed to split a polygon by multiple linestrings with a little tweaking. Here is the Code.

Rendering the split polygons.

this.map.on('draw:created', (event) => {
      this.multiSelectByclick = false;
      if (this.selectedParcelId && event.layerType === 'polyline') {
        let layer = event.layer;
        this.drawnItems.addLayer(layer);

        let geojson = layer.toGeoJSON();
        let geom = turf.getGeom(geojson);
        this.curPly = turf.getGeom(this.samplePoly);
        console.log(geom.type, 'type', this.samplePoly);
        // if (geom.type === 'Polygon')
        //   this.samplePoly.push(geom);

        if (geom.type === 'LineString') {
          let line = geom;
          this.polyLineString.push(line);

          this.layers.forEach((layer, index) => {
            layer.remove();
          });
          console.log(line, 'line split - from new')
        };
      }
    });

Splitting the Polygons

splitParcels() {
    const parcelsArray = [];
    parcelsArray.push({ localId: UUID.UUID(), polygon: this.curPly });
    console.log('parcelsArray: ', parcelsArray);
    console.log('polyLineString: ', this.polyLineString);
    this.polyLineString.forEach(line => {
      const resultsArray = [];
      parcelsArray.forEach(polygon => {
        console.log('polygon: ', polygon);
        const result = this.splitPolygon(polygon, line);
        console.log('result: ', result);
        resultsArray.push(result);
      });
      console.log('resultsArray: ', resultsArray);
      resultsArray
        .filter(result => result.upperChild && result.lowerChild)
        .forEach(result => {
          const index = parcelsArray.findIndex(parcel => parcel.localId === result.parent.localId);
          parcelsArray.splice(index, 1, result.upperChild);
          parcelsArray.splice(index, 0, result.lowerChild);
        });
    });
    console.log('parcelsArray: ', parcelsArray);
    const splitPolygons = parcelsArray.map(parcel => parcel.polygon);
    console.log('splitPolygons: ', splitPolygons);
    this.showSplitedPolygons(splitPolygons);
    return splitPolygons;

  }



  showSplitedPolygons(polygons) {
    let shows = [polygons]
    if (shows) {
      let style;
      this.updateGeomLyr.clearLayers();
      shows.forEach(element => {
        console.log(element, 'sshowSplitedPolygons')
        element.map(el => {
          new L.Polygon(this.mapService.invertCoordinatesArray(el.coordinates[0]),
            style = {
              fillColor: 'green'
            },
          ).addTo(this.polyLineSplitlyr);
        })
      });
    }
  }




  splitPolygon(polygon, line) {
    console.log('In Split Polygon');
    console.log('polygon: ', polygon);
    const result = {
      parent: polygon, upperChild: undefined, lowerChild: undefined
    };
    const upperPolygon = this.cutPolygon(polygon.polygon, line, 1, 'upper');
    console.log('upperPolygon: ', upperPolygon);
    const lowerPolygon = this.cutPolygon(polygon.polygon, line, -1, 'lower');
    console.log('lowerPolygon: ', lowerPolygon);
    if (upperPolygon && lowerPolygon) {
      result.lowerChild = { localId: UUID.UUID(), polygon: lowerPolygon };
      result.upperChild = { localId: UUID.UUID(), polygon: upperPolygon };
    }
    console.log('result: ', result);
    return result;
  }

  cutPolygon(polygon, line, direction, id) {
    let i = -1;
    let j;
    let polyCoords = [];
    let retVal = null;

    if ((polygon.type != 'Polygon') || (line.type != 'LineString')) return retVal;
    if (line.coordinates.length != 2) return retVal;

    let intersectPoints = turf.lineIntersect(polygon, line);
    let nPoints = intersectPoints.features.length;
    if ((nPoints == 0) || ((nPoints % 2) != 0)) return retVal;

    let offsetLine = turf.lineOffset(line, (0.01 * direction), { units: 'kilometers' });
    let thickLineCorners = turf.featureCollection([line, offsetLine]);
    let thickLinePolygon = turf.convex(turf.explode(thickLineCorners));

    let clipped = turf.difference(polygon, thickLinePolygon);

    for (j = 0; j < clipped.geometry.coordinates.length; j++) {
      let polyg = turf.polygon(clipped.geometry.coordinates[j]);
      let overlap = turf.lineOverlap(polyg, line, { tolerance: 0.005 });
      if (overlap.features.length > 0) {
        polyCoords[++i] = turf.coordAll(polyg);
      };
    };

    if (i == 0)
      retVal = turf.polygon(polyCoords, { id: id });
    else if (i > 0) {
      retVal = turf.multiPolygon([polyCoords], { id: id });
    }

    return turf.getGeom(retVal);
  }

Before splitting

enter image description here

After Splitting

enter image description here

New contributor
Arul Rozario is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • This supports only linestrings with two points, not more – Arul Rozario Oct 11 at 14:04
  • If someone has a solution to support linestrings with multiple points that would be great. – Arul Rozario Oct 11 at 14:05

Your Answer

Arul Rozario is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.