Reputation: 217
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?
Upvotes: 1
Views: 2177
Reputation: 49
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
Upvotes: 1
Reputation: 17872
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');
}
Upvotes: 3