[GIS] Client-Side Polygon split

algorithmgeometryleafletsplitting

I wanted to know if there is a way to split a polygon using JavaScript.
So I have a web map which uses Leaflet API, and the user needs to cut polygons which are shown in the map using a straight line. I was hoping there would be a JavaScript library something JSTS or Turf but if that isn't possible an algorithm would do just fine.

Best Answer

Below is one possible solution using Turf library. Solution is not exact since Turf does not have method to split polygon with line and get as result two split polygons.

The closest method is turf.difference(poly1, poly2), which cuts out second polygon from first. If second polygon is very thin and long rectangle (line with small 'height'), this can be used as split method, where first polygon is split by second.

This is done in two steps. First step is to 'fatten' dividing line to one side (let's call it upper), cut polygon by it and take into account split polygon one the other (lower) side of the line. Then dividing line is 'fattened' to the other side (lower), polygon is cut by it and split polygon on upper side is taken into account.

Code below has been tested, but is more or less proof of concept and not very robust. Parameters polygon and line are considered to be geometries.

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 upperCut = cutPolygon(polygon, line, 1, 'upper');
var lowerCut = cutPolygon(polygon, line, -1, 'lower');

Working fiddle is available at https://jsfiddle.net/TomazicM/2rdbcmL0/. If line is drawn across polygon, it will be split along line.

Related Question