Search code examples
openlayersopenlayers-3openlayers-5topologyturfjs

How to precisely check if one polygon overlaps another while ignoring boundary


I have one question regarding topology and relations between polygons in openlayers.

Situation is this: enter image description here

Using https://turfjs.org/ I'm using two methods to check if polygons are overlapping, https://turfjs.org/docs/#booleanOverlap and https://turfjs.org/docs/#booleanWithin but I'm getting some strange interaction.

As you can see, in blue rectangle, polygon is snapped to red polygon and that is fine behavior but problem is with polygons in yellow rectangle for them I'm getting true and automatically overlapping red style. Polygons in blue and polygons in yellow rectangle are only snapped to boundary of red polygon.

So, my question is this; is it possible to somehow ignore boundary of restrictive polygon (red one) or should i find another approach.

Code example that I'm checking if polygons are overlapping:

 vectorLayer.getSource().on(OpenLayersEvents.AddFeature, (evt: any) => {


            let feature = evt.feature;


            // clip area function with return geometry value
            let polygon = clipFieldArea(feature, this.myRestrictionVectorLayer);


            let isFeatureOverlappingFlag = false;
            //red polygons
            if (this.restrictiveLayer.getSource().getFeatures().length > 0) {
                isFeatureOverlappingFlag = arePolygonsOverlapping(feature, this.restrictiveLayer); 
            }

            // checks if features are overlapping then set new style
            feature.getGeometry().setCoordinates(polygon.getCoordinates());
            if (isFeatureOverlappingFlag) {
                feature.setStyle(this.featureOverlappingStyle);
            } else {
                feature.setStyle(this.fieldStyle);
            }....

And here is arePolygonsOverlapping() method that checks topology

   let geojsonFormat = new GeoJSON();

    let areOverlapping: boolean = false;

    let flagCheck: boolean = false;
    let restrictionFeatures = restrictionLayer.getSource().getFeatures();

    // create GeoJSON object and transform it in WGS84 for intersect method
    let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' });

    for (let featureRestrict of restrictionFeatures) {

        let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
            { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' });

        areOverlapping = booleanOverlap(firstGeometryObject as unknown as TurfPolygon, secondGeometryObject as unknown as TurfPolygon);

        if (areOverlapping) {
            flagCheck = true;
            break;
        }
    }
    return flagCheck;

UPDATE

I tried playing with solution that Mike proposed but I'm getting Uncaught TypeError: ol_proj__WEBPACK_IMPORTED_MODULE_3__.default.Projection is not a constructor

When trying to create new Projection. And here is updated method

export function arePolygonsOverlapping(feature: any, restrictionLayer: VectorLayer): boolean {

    let areOverlapping: boolean = false;

    let flagCheck: boolean = false;
    let restrictionFeatures = restrictionLayer.getSource().getFeatures();

    //#region "Parameters for scaling down coordinates"
        let viewProjection = Projection.get('EPSG:3857');
        let smallProjection = Projection.get('small');

    if (!smallProjection) {
        smallProjection = new Projection.Projection({
            code: 'small',
            units: 'm'
        });

        Projection.addProjection(smallProjection);

        let scale = Extent.getWidth(viewProjection.getExtent());

        let smallTransform = function (coordinate: [number, number]) {
            return [coordinate[0] / scale, coordinate[1] / scale];
        }

        let normalTransform = function (coordinate: [number, number]) {
            return [coordinate[0] * scale, coordinate[1] * scale];
        }

        Projection.addCoordinateTransforms(viewProjection, smallProjection, smallTransform as any, normalTransform as any);

    }
    //#endregion "Parameters for scaling down coordinates"


    // create GeoJSON object and transform it in WGS84 for intersect method
    let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: smallProjection, featureProjection: viewProjection  });

    for (let featureRestrict of restrictionFeatures) {

        let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
            { dataProjection: smallProjection, featureProjection: viewProjection  });

        areOverlapping = booleanOverlap(firstGeometryObject as unknown as TurfPolygon, secondGeometryObject as unknown as TurfPolygon);

        if (areOverlapping) {
            flagCheck = true;
            break;
        }
    }
    return flagCheck;
}

Here are my imports:

import Extent from 'ol/extent';
import Projection from 'ol/proj';

I forgot to say that I'm using v 4.6.2


Solution

  • Ok, I took a different route on that matter. Instead of "fixing" and tweaking coordinates (Nevertheless, It was nicely pointed out in Mike's answer that we should scale down coordinates)

    I just used Turf intersected method and check if there is any intersected feature with additional area check.

    This approach covers most of the cases that I've been trying

    let isIntersecting: boolean = false;
    
    let flagCheck: boolean = false;
    let restrictionFeatures = restrictionLayer.getSource().getFeatures();
    
    // create GeoJSON object and transform it in WGS84 for intersect method
    let firstGeometryObject = geojsonFormat.writeFeatureObject(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }) as unknown as TurfPolygon;
    
    for (let featureRestrict of restrictionFeatures) {
    
        let secondGeometryObject = geojsonFormat.writeFeatureObject(featureRestrict,
            { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }) as unknown as TurfPolygon;
    
        // get intersected polgon
        let intersectPolygon = intersect(firstGeometryObject, secondGeometryObject);
    
        if (intersectPolygon != null) {
            isIntersecting = true;
    
            // calculate value of intersected area
            let areaValue: number = area(intersectPolygon as unknown as AllGeoJSON);
    
            // area below 10 meters is considered overlapping
            if (areaValue < 10) {
                isIntersecting = false;
            }
        }
    
        if (isIntersecting) {
            flagCheck = true;
            break;
        }
    }
    return flagCheck;
    

    enter image description here