0

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

Svinjica
  • 2,389
  • 2
  • 37
  • 66
  • Do you need to change projection in writeFeatureObject? What overlaps in one projection might not in another.- see https://gis.stackexchange.com/questions/308871/why-is-there-a-transformation-shift-distortion-of-1-5km-in-openlayers-5-3-0-goi – Mike Sep 24 '19 at 21:54
  • @Mike Hi, Mike, thank you for answering. I believe that i have to because Turf library expects the data to be standard WGS84 longitude, latitude coordinates. – Svinjica Sep 24 '19 at 22:25
  • That certainly is a problem with some turf functions (especially if they work with tolerances) while other simply work with the numbers provided. if necessary you can define a dummy projection which reduces your EPSG:3857 coordinates to small enough values that turf will treat them WGS84 without affecting the shape as normal a reprojection would - see https://gis.stackexchange.com/questions/317657/snap-to-crossing-between-lines-in-openlayers – Mike Sep 24 '19 at 23:28
  • @Mike Thank you. I was also thinking another approach,let's say using JSTS or somehow detect if border is overlapping – Svinjica Sep 25 '19 at 07:28
  • @Mike Mike, just put your comment into answer with some code example to accept it – Svinjica Sep 25 '19 at 08:33

2 Answers2

1

I've tested booleanOverlap and although it does seem to work with numbers from any projection, to comply with the turf specification it would be advisable to stick to small numbers by scaling down the EPSG:3857 coordinates without transforming to a projection which changes the polygon's shapes. The scaling transforms can also be simpler than those in the comment links.

import { getWidth } from 'ol/extent';
import { Projection, addCoordinateTransforms, addProjection, get as getProjection } from 'ol/proj';

....
....


let viewProjection = getProjection('EPSG:3857');
let smallProjection = getProjection('small');

if (!smallProjection) {

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

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

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

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

    addCoordinateTransforms(viewProjection, smallProjection, smallTransform, normalTransform);

}

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: 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;
Mike
  • 16,042
  • 2
  • 14
  • 30
0

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

Svinjica
  • 2,389
  • 2
  • 37
  • 66