OpenLayers: как принудительно обновить представление и плитки в цикле - PullRequest
0 голосов
/ 06 февраля 2019

В OpenLayers 4.6.5 мне нужно принудительно обновить представление карты в цикле и ждать завершения обновления, прежде чем перейти к следующей итерации цикла.

Для некоторого контекста: Я делаю повторяющиеся расчеты пикселей на маленьких ограниченных многоугольниками участках источника TileImage.Мне удалось заставить мою функцию расчета работать с одним полигоном за раз, но когда я пытаюсь поместить ее в цикл для прохождения всех полигонов, она не будет работать, если весь полигон не виден на картеи плитки внутри полигона загружены.

Итак, я сейчас пытаюсь заставить работать цикл, который для каждого полигона:

  1. Перемещает вид карты так, чтобы онцентрируется на многоугольнике с уровнем увеличения 14
  2. Обновляет представление, чтобы убедиться, что все плитки загружены
  3. Запускает вычисление для пикселей в многоугольнике

I 'мы пытались поиграться с асинхронными функциями и обещаниями, но не могли заставить его работать должным образом - независимо от того, что я пытаюсь, моя функция forceRefresh запускается 200 раз (у меня есть 200 полигонов), а затем все мои плитки загружаются для текущего представления,и затем выполняется попытка расчета для каждого многоугольника, включая те, которые не отображаются в текущем представлении.

К сожалению, я не могу просто увеличить масштаб всех многоугольников и запуститьвсе расчеты от этого уровня масштабирования.Из-за различий в размерах пикселей при разных уровнях масштабирования результаты значительно различаются, когда вычисление выполняется, скажем, на уровне масштабирования 8 против уровня масштабирования 14.

Это соответствующие части моего кода:

function forceRefresh(source,ms) {
    return new Promise(resolve => {
        source.refresh();
        map.updateSize();
        setTimeout(() => {
            resolve('Map should now be refreshed');
        }, ms);
    });
}

async function getCellAverage(featureID,equation,calcZoom=14) {
    return new Promise(resolve => {
        initialZoom = view.getZoom();
        initialCenter = view.getCenter();
        layerSource = window["layer" + featureID].getSource();
        window["allTilesLoaded"] = false;
        zoomToFit("source"+featureID);
        if(view.getZoom() > calcZoom) {
            view.setZoom(calcZoom);
        }
        layerSource.getFeatures().forEach(async function(feature) {
            var result = await forceRefresh(window['L8SourceNRG'],100);
            console.log(result);
            var geom = feature.getGeometry();
            var size = map.getSize();
            var ndviArray = [];
            map.addEventListener('postrender', function() {
                if(window['L8SourceNRG'].allTilesLoaded == true) {
                    console.log('Confirmed all L8SourceNRG tiles loaded');
                    map.removeEventListener('postrender');
                    if (geom.intersectsExtent(map.getView().calculateExtent(size))) {
                        for (var i=0; i<size[0]; i++) {
                            for (var j=0; j<size[1]; j++) {
                                var coordinate = map.getCoordinateFromPixel([i,j]);
                                if (geom.intersectsCoordinate(coordinate)) {
                                    let tileCoord = L8SourceTileGrid.getTileCoordForCoordAndResolution(coordinate, map.getView().getResolution());
                                    let key = tileCoord.join('-');
                                    if (key in window['tiles']) {
                                        let origin = L8SourceTileGrid.getOrigin(tileCoord[0]);
                                        let res = L8SourceTileGrid.getResolution(tileCoord[0]);
                                        let tileSize = L8SourceTileGrid.getTileSize(tileCoord[0]);
                                        var w = Math.floor(((coordinate[0] - origin[0]) / res) % (tileSize[0] | tileSize));
                                        var h = Math.floor(((origin[1] - coordinate[1]) / res) % (tileSize[1] | tileSize));

                                        var canvas = document.createElement("canvas");
                                        canvas.width = tiles[key].width;
                                        canvas.height = tiles[key].height;

                                        var ctx = canvas.getContext("2d");
                                        ctx.drawImage(tiles[key], 0, 0);

                                        let img = ctx.getImageData(0, 0, canvas.width, canvas.height);
                                        let imgData = img.data;

                                        let index = (w + h * 256) * 4;
                                        let pixel = [imgData[index + 0], imgData[index + 1], imgData[index + 2], imgData[index + 3]];
                                        ndviArray.push((( pixel[0] - pixel[1] ) / ( pixel[0] + pixel[1] )));

                                    }
                                }
                            }
                        }
                    }

                    var ndviSum = ndviArray.reduce((a, b) => a + b, 0);
                    var ndviAvg = ndviSum / ndviArray.length;

                    console.log("Average NDVI: "+ndviAvg);

                    makePolygonMask("avgNDVI",featureID,geom,ndviAvg);
                    window['cellAverageDone'] = true;
                }
            });
        });

        setTimeout(() => {
            resolve('resolved');
        }, 100);
    });
}

async function getAllAverages(equation) {
    map.getLayers().forEach(async function(layer) {
        window['cellAverageDone'] = false;
        if (layer.get('type') == "cell") {
            layerID = layer.get('name').substring(9);
            var result = await getCellAverage(layer.get('name').substring(5),'NDVI');
        }
    });
}

Обратите внимание, что свойство "allTilesLoaded" устанавливается вспомогательной функцией, которую я для краткости опущил, так как не думаю, что она имеет отношение к данному вопросу.

Вывод в консолиследующим образом:

(200x) Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.37295137830077313
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.38384215219470413
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.44356048105512613
...
Confirmed all L8SourceNRG tiles loaded
Average NDVI: NaN

Последняя строка выше показывает, что происходит при попытке расчета для многоугольника, который находится за пределами текущего представления.

Вместо этого я ожидаю увидеть следующее:

Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.37295137830077313
Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.38384215219470413
Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.44356048105512613
...

РЕДАКТИРОВАТЬ: обратите внимание, что я работаю в OL 4.6.5, поэтому 'rendercomplete', к сожалению, не работает.

1 Ответ

0 голосов
/ 06 февраля 2019

Используйте 'rendercomplete' вместо 'postrender'.Это новое событие, которое «запускается после завершения рендеринга, т. Е. Все источники и элементы мозаичного изображения закончили загрузку для текущего окна просмотра, а все элементы мозаичного изображения исчезли». *

https://openlayers.org/en/latest/apidoc/module-ol_render_Event-RenderEvent.html#event:rendercomplete

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...