TransWikia.com

Large number of multi-geometric features do not appear when using Cluster

Geographic Information Systems Asked by leonardofmed on January 30, 2021

I’m trying to use a method to display a cluster for a large number of geometries, based initially on this question. The method consists of transforming the geometries into points when the zoom is far, so that it can work with the Cluster, and return the original geometry when the zoom is close enough.

The purpose of using this method is to optimize the efficiency of the application during the loading and manipulation of these features, because if you load a large amount of geometries at once the application becomes slow. What I did was create 2 layers, one to show the clusters and the other to return the original geometry, both with resolution limits to work as expected, so when one is on display the other is not. I did this based on suggestions of a previous question. It is important to note that I am using this methodology to load KML files, which in my case vary from a few KBs to a few MBs, with thousands of features. For small files with few geometries the method is working perfectly as expected, however when loading a larger file (8MB with 8300+ features) only the layer that returns the original geometries with approximate zoom is working, the cluster layer does not.

I tried to use the method to leave the cluster style in cache to optimize memory consumption, as used in OL example of clusters. I tried to change the distance parameter to different values, but it didn’t work either. Even if I wait a while, the cluster layer does not appear for large files.

I’m having trouble debugging this problem, because no error is displayed, it’s working for small files and I can see that the layer was loaded if I use map.getLayers(). The only thing I found different between these cluster layers, but I don’t know if it is related, is that the smaller and working cluster layer has the VectorLayer.values_.source.undefIdIndex_ attribute with the Feature object, containing the features included in the cluster, while the larger layer has no object in that attribute.

If I do newVectorLayerCluster.getSource().getSource().getFeatures()[0] I can see the first feature without problem.

let newVectorSource = new VectorSource({})
let newVectorLayer = new VectorLayer({
    source: newVectorSource,
    name: layer['layer_id'],
    visible: false,
    maxResolution: 10
});
let styleCache = {};
let newVectorLayerCluster = new VectorLayer({
    source: new Cluster({
        distance: 50,
        source: newVectorSource,
        geometryFunction: (feature) => {
            let resolution = this.map.getView().getResolution();
            if (resolution > 10) {
                let type = feature.getGeometry().getType();
                if (type === 'Polygon') {
                    return feature.getGeometry().getInteriorPoint();

                } else if (type === 'LineString') {
                    return feature.getGeometry().getCoordinateAt(0.5);

                } else if (type === 'Point') {
                    return feature.getGeometry();
                }
            }
        }
    }),
    style: (feature) => {
        let size = feature.get('features').length;
        let style = styleCache[size];
        if (!style) {
            style = new Style({
                image: new CircleStyle({
                    radius: 10,
                    stroke: new Stroke({
                        color: '#fff',
                    }),
                    fill: new Fill({
                        color: '#3399CC',
                    }),
                }),
                text: new Text({
                    text: size.toString(),
                    fill: new Fill({
                        color: '#fff',
                    }),
                })
            });
            styleCache[size] = style;
        }
        return style;
    },
    name: layer['layer_id'],
    visible: false
});

this.file.readAsText(this.file.externalDataDirectory + 'projects/' + this.projectId + '/layers/', filename).then(layer_file => {
    let format = new KML({});                                   
    newVectorSource.addFeatures(format.readFeatures(layer_file, {
        featureProjection:"EPSG:3857",
        dataProjection: "EPSG:4326"
    }));
    this.map.addLayer(newVectorLayer);
    this.map.addLayer(newVectorLayerCluster);                                   
});

I’m using OpenLayers v5.3.3.

2 Answers

I found out what the problem was, the large KML layer contained a geometry that was not included in the geometryFunction, in this case MultiPolygon.

So the geometryFunction looks like this now:

geometryFunction: (feature) => {
    let resolution = this.map.getView().getResolution();
    if (resolution > 5) {
        let type = feature.getGeometry().getType();
        if (type === 'Polygon') {
            return feature.getGeometry().getInteriorPoint();

        } else if (type === 'LineString') {
            return feature.getGeometry().getCoordinateAt(0.5);

        } else if (type === 'Point') {
            return feature.getGeometry();

        } else if (type === 'MultiPolygon') {
            return new Point(getCenter(feature.getGeometry().getExtent()), 'XY');
        }
    }
}

If you know a more efficient way to return the point coordinates of this geometry, please let me know.

Answered by leonardofmed on January 30, 2021

It is not more efficient but would perhaps be more accurate to use the interior point of the polygon formed by the component polygons interior points

let coordinates = feature.getGeometry().getInteriorPoints().getCoordinates();
/* close the ring and get overall interior point */
return new Polygon([coodinates.concat([coordinates[0]])]).getInteriorPoint();

Answered by Mike on January 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP