1

I have some polygon features on a map layer in OpenLayers. They are contained within a 'boundary' polygon (a field boundary, for context) and fit together perfectly with no 'holes' inside of the boundary polygon (these are soil type 'zones' within the field boundary).

I need to be able to draw a new polygon and have it be trimmed by the boundary polygon and then trim the polygons it overlaps so there are no overlapping polygons, like a puzzle. I have successfully done this in steps but there's one element of the outcome I'm not happy with and I can't see how to change it. This is the way it currently works:

enter image description here

  1. This is the starting point.The 'zone' polygons (2 of them) within the field boundary (red).

enter image description here

  1. I draw a polygon that overlaps the field boundary and the zones. At this point I trim this newly drawn 'zone' polygon to the field boundary using JSTS intersection, and then with the resulting geometry loop through the existing 'zone' features and perform a JSTS difference on each to create new features based on the original 'zone' polygons. Then I remove the original features from the layer and add the new drawn polygon and the edited 'zone' polygons. And this is the result:

enter image description here

...which is exactly what I need it to be, except for one thing. You'll notice that the zone the new polygon split in half (zone #2) is still one zone, just in two parts. If I click on it, it becomes obvious that it's one polygon:

enter image description here

...but zone #1 is correctly edited:

enter image description here

How do I detect when a polygon has been entirely divided by a JSTS difference and return two polygons, rather than the one shown here?

Here is the code I have to achieve what the images demonstrate:

// end drawing if clicked save rather than double click
drawTool.finishDrawing();
// save the drawn feature
drawnFeature = drawing_source.getFeatures()[0];
if(drawnFeature === undefined)
{
    // nothing drawn
    map.removeInteraction(drawTool);
    addSelectAndModifyForZones(highlighted_zone.getId());
}
else
{
    // check if zones of the field are greater than 0
    if(allSubZones.length > 0)
    {
        var containingZone;
        try {
            // read drawn geometry in jsts format
            var b = parser.read(drawnFeature.getGeometry());
            var drawn_area = get_area(drawnFeature);

            // first check the intersection/trim with the field boundary
            var field;
            $.each(field_hotspot_layer.getSource().getFeatures(), function(index, this_feature) {
                if(this_feature.getId().toString() === current_live_field.toString())
                {
                    field = this_feature;
                }
            });

            var a = parser.read(field.getGeometry());
            var common_ground = a.intersection(b);
            if(parser.write(common_ground).flatCoordinates.length === 0)
            {
                // drawn area is entirely outside the field boundary!
                // warn the user and stop here
                map.removeInteraction(drawTool);
                addSelectAndModifyForZones(highlighted_zone.getId());

                // clear our drawing source
                drawing_source.clear();
            }
            else
            {
                var temp_feature = new ol.Feature({
                    geometry: parser.write(common_ground),
                    description: "TEMP"
                });
                temp_feature.setStyle(TEMP_style);

                // get area
                var overlap_area = get_area(temp_feature);
                if(drawn_area.toFixed(2) === overlap_area.toFixed(2))
                {
                    // drawn area is inside field boundary
                    console.log("drawn area is inside field boundary");
                }
                else
                {
                    // drawn area is at least partially outside the field boundary
                    console.log("drawn area is at least partially outside the field boundary");
                }

                // either way the intersection should be the geometry to move forward with
                // convert drawn geometry to OL feature and attach default style, white opaque bg and black border
                var newPoly = new ol.Feature({
                    geometry: parser.write(common_ground),
                    z_index: '1',
                    zone_border: 'rgba(0,0,0,1)',
                    zone_border_width: '2',
                    zone_colour: 'rgba(255,255,255,0.5)',
                    zone_number: allSubZones.length+1
                });
                newPoly.setStyle(visible_zone_style);
                
                // add it to the source
                currentZoneLayer.getSource().addFeature(newPoly);

                // loop through all the zones and find difference with the drawn polygon
                for(p = 0; p < allSubZones.length; p++)
                {
                    containingZone = allSubZones[p];
                    var a = parser.read(containingZone.getGeometry());
                    var difference = a.difference(common_ground);
                    // convert difference to OL feature, original geom minus the drawn geom
                    
                    olPolygon = new ol.Feature({
                        geometry: parser.write(difference),
                        description: containingZone.get('description'),
                        z_index: containingZone.get('z_index'),
                        zone_border: containingZone.get('zone_border'),
                        zone_border_width: containingZone.get('zone_border_width'),
                        zone_colour: containingZone.get('zone_colour'),
                        zone_number: containingZone.get('zone_number'),
                        zone_value: containingZone.get('zone_value')
                    });
                    olPolygon.setStyle(visible_zone_style);
                    
                    // add it to the source
                    currentZoneLayer.getSource().addFeature(olPolygon);
                    selectZoneControl.setActive(true);
                    
                    // clear our drawing source
                    drawing_source.clear();
                    
                    // remove original old geometry
                    currentZoneLayer.getSource().removeFeature(containingZone);
                }
            }
        } catch (e) {
            console.log(e);
        } finally {

        }
    }
}
7
  • 1
    Coding questions on GIS SE site require relevant existing code to be part of the question, otherwise question is most likely to be closed as not compliant with the site policy. Please edit your question and add relevant code.
    – TomazicM
    Jan 29, 2021 at 19:58
  • 1
    Fair enough, I'll edit and add my code, I just thought, since I had it working fine, that I could just explain the principle of what I was after, but I can add code no problem. Thanks Jan 29, 2021 at 21:05
  • @TomazicM edited, my apologies. Jan 29, 2021 at 21:14
  • If I understand you correctly you want Zone #2 to be split to two separate features?
    – TomazicM
    Jan 30, 2021 at 10:28
  • Exactly. Yes. But I don’t know how to ‘detect’ that the result of the jsts difference has left two completely separate polygons Jan 30, 2021 at 13:43

1 Answer 1

1

When JSTS ends up splitting a geometry via difference, the geometry that gets returned may return a value other than 1 when you call getNumGeometries(). If it does, you can call getGeometryN to retrieve the individual geometries from the collection.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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