1

I have some code by which I am checking places or coordinates inside in polygons or not. The problem is it may have 10000 places or more which is getting performance issue and map is getting slow. Please find my code below:

    places.forEach(p => {
       this.isInsidePolygons(p.latitude, p.longitude)
    })

    isInsidePolygons(latitude: number, longitude: number): boolean {
                let isInsidePolygon = false;

                var coordinate = OlHelper.transformToEPSG3857([Number(longitude), Number(latitude)]);
                var shapes = this.getShapes();
                for (let i = 0; i < shapes.length; i++) {
                    let features = shapes[i].getSource().getFeatures();
                    if (!features || features.length == 0) continue;

                    for (let j = 0; j < features.length; j++) {
                        var geometry = features[j].getGeometry();
                        isInsidePolygon = geometry.intersectsCoordinate(coordinate);
                        if (isInsidePolygon) break;
                    }
                    if (isInsidePolygon) break;
                }

                return isInsidePolygon;
            }

   getShapes(): ol.layer.Vector[] {
        var shapes = [];
        this.MapControl.getLayers().forEach((layer) => {
            if (layer instanceof ol.layer.Vector) shapes.push(layer);
        });
        return shapes;
    }

Is it possible to check all places are inside polygons in openlayers in a single check instead of looping for each one?

user10496245
  • 217
  • 3
  • 17

2 Answers2

3
    let features = shapes[i].getSource().getFeatures();
    if (!features || features.length == 0) continue;

    for (let j = 0; j < features.length; j++) {
        var geometry = features[j].getGeometry();
        isInsidePolygon = geometry.intersectsCoordinate(coordinate);
        if (isInsidePolygon) break;
    }

could be replaced by

    isInsidePolygon = (shapes[i].getSource().getFeaturesAtCoordinate(coordinate).length > 0);

which is less code but probably not much more efficient

To test shapes against the more numerous places you need need to create a vector source for your places. Use the extent of the shapes to get a shortlist of places, and only test those against the shape geometry

    let placesFeatures = [];
    places.forEach((p) => {
        placesFeatures.push(new Feature({
            geometry: new Point(fromLonLat[p.longitude, p.latitude]))
            id: [p.latitude, p.longitude].toString,
            isInsidePolygon: false
        }))
    })
    let placesSource = new VectorSource({features: placesFeatures});

    for (let i = 0; i < shapes.length; i++) {
        let features = shapes[i].getSource().getFeatures();
        if (!features || features.length == 0) continue;

        for (let j = 0; j < features.length; j++) {
            var geometry = features[j].getGeometry();
            let extent = features[j].getGeometry().getExtent();
            let candidates = placesSource.getFeaturesInExtent(geometry.getExtent());
            if (!candidates || candidates.length == 0) continue;

            for (let k = 0; k < candidates.length; k++) {
                isInsidePolygon = geometry.intersectsCoordinate(candidates[k].getGeometry().getCoordinates());
                if (isInsidePolygon) {
                    candidates[k].set('isInsidePolygon', true);
                }
            })
        }
    }

Then you can get results from the places features in the source

    isInsidePolygons(latitude: number, longitude: number): boolean {
        return placesSource.getFeatureById([latitude, longitude].toString()).get('isInsidePolygon');
    }
Mike
  • 16,042
  • 2
  • 14
  • 30
1

You can use turf.js, specifically the function pointsWithinPolygon. Starting from a multi-polygon or a polygon and a list of points the functions it returns all the points inside the polygon, but the complexity is linear with the number of the points. If we use turf.js you have to convert the features in GeoJSON.

let format = new ol.format.GeoJSON();
let pointsInsidePolygon = turf.pointsWithinPolygon(
         format.writeFeatureObject(points),
         format.writeFeatureObject(polygon)
    );

And then to read the GeoJson features

let features =  format.readFeatures(pointsInsidePolygon);

But if you want only now if there is some points inside or outside the polygon, but without knowing which one you can play with the extent of the polygon

SMattia
  • 51
  • 1
  • 1
  • 6
  • I did much the same as this. However I limited the polygons to be searched by creating bounding boxes from the clusterings of the data points (using one of the turf.js cluster functions). And then limiting the polygons to these with `featureEach(waterBodyFeatureCollection, async f => { const bboxClipped = bboxClip(f, pointsBbox) as TurfFeature;...` – HankCa Mar 20 '20 at 02:23
  • See https://github.com/csiro-aquatic-remote-sensing/eow-au-viewer/blob/20ce42b58cd17effadf45a2805320572cf56c954/src/app/gis-ops.ts#L173 (in case the code changes the method is `static async filterFromClusteredEOWDataBbox(waterBodyFeatures: Feature[], points: FeatureCollection, layers: ApplicationLayers, layerName: string): Promise>`) – HankCa Mar 20 '20 at 02:26