1

I have a map which consists of multipolygons and polygons. Firstly the user selects a polygon or multipolygon from the map by clicking on it then user selects a point on that multipolygon and then the line(split line) drawing should be started from that point and there should be an overlay to display the length of the line and the area of the two polygons divided by that line..

As I am new to openlayers 7 I don't have idea to how to achieve it? Any help can be appreciated.

Here is my code:

 //called the line draw interaction after user selects a point on the polygon
      startSubDivLineDrawInteraction  : function(gtype,source) {
 map.removeInteraction(interaction);
    editOperations.removeAllDrawInteractions(map);
    map.un('singleclick', editOperations.getfeaturesatpixelforsplit);
        pDrawInteraction = new ol.interaction.Draw({
            source: source,
            type: gtype,
            style: new ol.style.Style({
image: new ol.style.Circle({
    fill: new ol.style.Fill({
  color: '#69cfba'
}),
radius: 5,
stroke: new ol.style.Stroke({
  color: 'black',
  width: 2
})
}),
stroke: new ol.style.Stroke({
  color: 'navy',
  width: 3,
  lineDash: [4,8],
lineDashOffset: 6
}),
fill: new ol.style.Fill({
  color: 'rgba(0, 0, 255, 0.2)'
})
}),
        });
        map.addInteraction(pDrawInteraction);
        editOperations.createMeasureTooltip(map);
        var listener;
pDrawInteraction.on('drawstart',
        function(evt) {
// set sketch
            sketch = evt.feature;
            /** @type {ol.Coordinate|undefined} */
            var tooltipCoord = evt.coordinate;
            //var tooltipCoord = startCoordinates;
                listener = sketch.getGeometry().on('change', editOperations.ongeomchange) ;
            }, this);
        
        pDrawInteraction.on('drawend',
        function(e) {
   map.getOverlays().clear();
  vector_layer.setStyle(regularStyle);
    map.removeInteraction(pDrawInteraction);

    if(gtype === "Polygon") {
        vector_layer.getSource().addFeature(e.feature);
        polygon = e.feature;
    }

        }, this);
        map.addLayer(vector_layer);
        map.addLayer(splitlineLayer);
    },
    createMeasureTooltip: function(map)
     {
        if (measureTooltipElement) {
            measureTooltipElement.parentNode.removeChild(measureTooltipElement);
        }
        measureTooltipElement = document.createElement('div');
        measureTooltipElement.className = 'mtooltip mtooltip-measure';
        measureTooltip = new ol.Overlay({
            element: measureTooltipElement,
            offset: [0, -15],
            positioning: 'bottom-center'
        });
        map.addOverlay(measureTooltip);
        $('.ol-overlay-container').css({"z-index": 1000});
    },
        formatLength : function(line) { 
        var length = line.getLength();
        var length = length;
        var output;
    output = length >= 1000 ? (length / 1000).toFixed(3)+ 'KM' : length.toFixed(3) +   'Meter';
        return output;
    },

    formatArea : function (polygon) {
        var area = ol.sphere.getArea(polygon);
        let output;
        if (area >= 10000) {
        output = Math.round((area / 10000) * 100) / 100 + ' ' + 'HECT';
        } else {
            output = Math.round(area * 100) / 100 + ' ' + 'SQ M';
        }
        return output;
    },
   calDistance : function(overlay, overlayPosition, distance){  
    if(parseInt(distance) == 0) {    
        overlay.setPosition([0,0]);       
    }
    else {
        overlay.setPosition(overlayPosition);      
        if (distance >= 1000) {
            overlay.element.innerHTML = '<b>' + (distance/1000).toFixed(2) + ' km</b>';
        }
        else {
            overlay.element.innerHTML = '<b>' + distance.toFixed(2) + ' m</b>';
        }
        map.addOverlay(overlay);
    }    
     
   },

  calArea : function(overlay, overlayPosition, area) {    
    if(parseInt(area) == 0) {    
        overlay.setPosition([0,0]);  
    }
    else {
        overlay.setPosition(overlayPosition);  
        if (area >= 10000) {
   overlay.element.innerHTML = '<b>' + Math.round((area / 1000000) * 100) / 100  + 'km<sup>2<sup></b>';
        }
        else {
            overlay.element.innerHTML = '<b>' + Math.round(area * 100) / 100  + ' m<sup>2<sup></b>';
        }
         map.addOverlay(overlay);
    }
      
   },
   ongeomchange : function(evt){
   listener = sketch.getGeometry().on('change', function(evt) {
                ////////////////////////////////////////////////////////////////
                let parser = new jsts.io.OL3Parser();
    
    //Creating line geometry from draw intraction
    linestring = new ol.Feature({    
        geometry: new ol.geom.LineString(evt.target.getCoordinates())
    });        
    //Parse Polygon and Line geomtry to jsts type
    let a = parser.read(polygeom);
    let b = parser.read(linestring.getGeometry()) ; 
    //Perform union of Polygon and Line and use Polygonizer to split the polygon by line
  var polygongeom= reader.read(new ol.format.WKT().writeFeature(polygeom, {}));
     let union = polygongeom.union(b);
    let polygonizer = new jsts.operation.polygonize.Polygonizer();
    //Splitting polygon in two part
    polygonizer.getExteriorRing().add(union);
    //Get splitted polygons
    let polygons = polygonizer.getPolygons();
    //This will execute only if polygon is successfully splitted into two parts
    if(polygons.array.length == 2) {
        //Clear old splitted polygons and measurement ovelays
        vector_layer.getSource().clear();
        map.getOverlays().clear();  
        polygons.array.forEach(function(geom){                                                
            let splitted_polygon = new ol.Feature({    
                geometry: new ol.geom.Polygon(parser.write(geom).getCoordinates())
            });    
            //Add splitted polygon to vector layer    
          vector_layer.getSource().addFeature(splitted_polygon);
            //Add area measurement overlay to splitted polygon
            overlay = new ol.Overlay({
            offset: [0, -15],
            positioning: 'bottom-center'
        }); editOperations.calArea(overlay,  
                  splitted_polygon.getGeometry().getFlatInteriorPoint(),                  
                   splitted_polygon.getGeometry().getArea());                    
            
            //Add line measurement overlay to segment of polygon
            let polyCoords = splitted_polygon.getGeometry().getCoordinates()[0];
            polyCoords.forEach(function(coords, i){    
                if(i < polyCoords.length-1){                        
                    let line = new ol.geom.LineString([coords, polyCoords[i+1]]);                        
                    overlay = new ol.Overlay({
            offset: [0, -15],
            positioning: 'bottom-center'
        });
                    editOperations.calDistance(overlay, line.getFlatMidpoint(), line.getLength());    
                }
            });
        });
        
        //Change Style of Splitted polygons
        vector_layer.setStyle(editOperations.highlightStyle);
    }
    else {
        //Change style to normal if polgon is not splitted            
       vector_layer.setStyle(regularStyle);
        
        //Clear measurement overlays and splitted polygon if line is not completely intersected with            
          polygon
      map.getOverlays().clear();
        vector_layer.getSource().clear();
  • If you are going to display multiple lengths or areas it would be easier to do it via vector styles as in https://openlayers.org/en/latest/examples/measure-style.html instead of overlays. – Mike May 21 '23 at 22:18
  • An alternative way to split a polygon is to use turf.js extending your drawn line to a buffered extent avoiding any further contact with the target polygons (turf has a shortestPath method which is supposed to avoid obstructions but when balancing acceptable performance against resolution it is not 100% reliable) then completing another polygon which can be used for different/intersection methods to get the split geometry https://codesandbox.io/s/split-polygon-lkk7nb?file=/main.js – Mike May 21 '23 at 22:19

0 Answers0