UNPKG

itowns

Version:

A JS/WebGL framework for 3D geospatial data visualization

338 lines (272 loc) 12.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.updateLayeredMaterialNodeImagery = updateLayeredMaterialNodeImagery; exports.updateLayeredMaterialNodeElevation = updateLayeredMaterialNodeElevation; exports.removeLayeredMaterialNodeLayer = removeLayeredMaterialNodeLayer; exports.SIZE_DIAGONAL_TEXTURE = exports.SIZE_TEXTURE_TILE = void 0; var _LayerUpdateStrategy = require("../Layer/LayerUpdateStrategy"); var _LayerUpdateState = _interopRequireDefault(require("../Layer/LayerUpdateState")); var _XbilParser = require("../Parser/XbilParser"); var _handlerNodeError = _interopRequireDefault(require("./handlerNodeError")); var SIZE_TEXTURE_TILE = 256; exports.SIZE_TEXTURE_TILE = SIZE_TEXTURE_TILE; var SIZE_DIAGONAL_TEXTURE = Math.pow(2 * (SIZE_TEXTURE_TILE * SIZE_TEXTURE_TILE), 0.5); exports.SIZE_DIAGONAL_TEXTURE = SIZE_DIAGONAL_TEXTURE; function materialCommandQueuePriorityFunction(material) { // We know that 'node' is visible because commands can only be // issued for visible nodes. // TODO: need priorization of displayed nodes // Then prefer displayed node over non-displayed one return material.visible ? 100 : 10; } function refinementCommandCancellationFn(cmd) { if (!cmd.requester.parent || !cmd.requester.material) { return true; } // Cancel the command if the tile already has a better texture. // This is only needed for elevation layers, because we may have several // concurrent layers but we can only use one texture. if (cmd.layer.isElevationLayer && cmd.requester.material.getElevationLayer() && cmd.targetLevel <= cmd.requester.material.getElevationLayer().level) { return true; } return !cmd.requester.material.visible; } function buildCommand(view, layer, extentsSource, extentsDestination, requester, parsedData) { return { view: view, layer: layer, extentsSource: extentsSource, extentsDestination: extentsDestination, requester: requester, parsedData: parsedData, priority: materialCommandQueuePriorityFunction(requester.material), earlyDropFunction: refinementCommandCancellationFn }; } function updateLayeredMaterialNodeImagery(context, layer, node, parent) { var material = node.material; if (!parent || !material) { return; } var extentsDestination = node.getExtentsByProjection(layer.projection); var nodeLayer = material.getLayer(layer.id); // Initialisation if (node.layerUpdateState[layer.id] === undefined) { node.layerUpdateState[layer.id] = new _LayerUpdateState["default"](); if (!layer.source.extentsInsideLimit(extentsDestination)) { // we also need to check that tile's parent doesn't have a texture for this layer, // because even if this tile is outside of the layer, it could inherit it's // parent texture if (!(!layer.noTextureParentOutsideLimit && parent.material && parent.material.getLayer && parent.material.getLayer(layer.id))) { node.layerUpdateState[layer.id].noMoreUpdatePossible(); return; } } if (!nodeLayer) { // Create new MaterialLayer nodeLayer = material.addLayer(layer); // Init the new MaterialLayer by parent var parentLayer = parent.material && parent.material.getLayer(layer.id); nodeLayer.initFromParent(parentLayer, extentsDestination); } // Proposed new process, two separate processes: // * FIRST PASS: initNodeXXXFromParent and get out of the function // * SECOND PASS: Fetch best texture // The two-step allows you to filter out unnecessary requests // Indeed in the second pass, their state (not visible or not displayed) can block them to fetch if (nodeLayer.level >= layer.source.zoom.min) { context.view.notifyChange(node, false); return; } } // Node is hidden, no need to update it if (!material.visible) { return; } // TODO: move this to defineLayerProperty() declaration // to avoid mixing layer's network updates and layer's params // Update material parameters if (nodeLayer) { nodeLayer.visible = layer.visible; nodeLayer.opacity = layer.opacity; } // An update is pending / or impossible -> abort if (!layer.visible || !node.layerUpdateState[layer.id].canTryUpdate()) { return; } if (nodeLayer.level >= extentsDestination[0].zoom) { // default decision method node.layerUpdateState[layer.id].noMoreUpdatePossible(); return; } // is fetching data from this layer disabled? if (layer.frozen) { return; } var failureParams = node.layerUpdateState[layer.id].failureParams; var destinationLevel = extentsDestination[0].zoom || node.level; var targetLevel = (0, _LayerUpdateStrategy.chooseNextLevelToFetch)(layer.updateStrategy.type, node, destinationLevel, nodeLayer.level, layer, failureParams); if (targetLevel <= nodeLayer.level || targetLevel > destinationLevel) { return; } // Get equivalent of extent destination in source var extentsSource = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = extentsDestination[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var extentDestination = _step.value; var extentSource = extentDestination.tiledExtentParent(targetLevel); if (!layer.source.extentInsideLimit(extentSource)) { // Retry extentInsideLimit because you must check with the targetLevel // if the first test extentInsideLimit returns that it is out of limits // and the node inherits from its parent, then it'll still make a command to fetch texture. node.layerUpdateState[layer.id].noMoreUpdatePossible(); return; } extentsSource.push(extentSource); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } node.layerUpdateState[layer.id].newTry(); var parsedData = nodeLayer.textures.map(function (t) { return t.parsedData; }); var command = buildCommand(context.view, layer, extentsSource, extentsDestination, node, parsedData); return context.scheduler.execute(command).then(function (result) { // TODO: Handle error : result is undefined in provider. throw error var pitchs = extentsDestination.map(function (ext, i) { return ext.offsetToParent(result[i].extent, nodeLayer.offsetScales[i]); }); nodeLayer.setTextures(result, pitchs); node.layerUpdateState[layer.id].success(); }, function (err) { return (0, _handlerNodeError["default"])(err, node, layer, targetLevel, context.view); }); } function updateLayeredMaterialNodeElevation(context, layer, node, parent) { var material = node.material; if (!parent || !material) { return; } // TODO: we need either // - compound or exclusive layers // - support for multiple elevation layers // Elevation is currently handled differently from color layers. // This is caused by a LayeredMaterial limitation: only 1 elevation texture // can be used (where a tile can have N textures x M layers) var extentsDestination = node.getExtentsByProjection(layer.projection); // Init elevation layer, and inherit from parent if possible var nodeLayer = material.getElevationLayer(); if (!nodeLayer) { nodeLayer = material.addLayer(layer); } if (node.layerUpdateState[layer.id] === undefined) { node.layerUpdateState[layer.id] = new _LayerUpdateState["default"](); var parentLayer = parent.material && parent.material.getLayer(layer.id); nodeLayer.initFromParent(parentLayer, extentsDestination); // If the texture resolution has a poor precision for this node, we don't // extract min-max from the texture (too few information), we instead chose // to use parent's min-max. var useMinMaxFromParent = extentsDestination[0].zoom - nodeLayer.zoom > 6; if (nodeLayer.textures[0]) { if (!useMinMaxFromParent) { var _computeMinMaxElevati = (0, _XbilParser.computeMinMaxElevation)(nodeLayer.textures[0].image.data, SIZE_TEXTURE_TILE, SIZE_TEXTURE_TILE, nodeLayer.offsetScales[0]), min = _computeMinMaxElevati.min, max = _computeMinMaxElevati.max; node.setBBoxZ(min, max, layer.scale); } } if (nodeLayer.level >= layer.source.zoom.min) { context.view.notifyChange(node, false); return; } } // Possible conditions to *not* update the elevation texture if (layer.frozen || !material.visible || !node.layerUpdateState[layer.id].canTryUpdate()) { return; } var targetLevel = (0, _LayerUpdateStrategy.chooseNextLevelToFetch)(layer.updateStrategy.type, node, extentsDestination[0].zoom, nodeLayer.level, layer); if (targetLevel <= nodeLayer.level || targetLevel > extentsDestination[0].zoom) { node.layerUpdateState[layer.id].noMoreUpdatePossible(); return Promise.resolve(); } var extentsSource = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = extentsDestination[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var nodeExtent = _step2.value; var extentSource = nodeExtent.tiledExtentParent(targetLevel); if (!layer.source.extentInsideLimit(extentSource)) { node.layerUpdateState[layer.id].noMoreUpdatePossible(); return; } extentsSource.push(extentSource); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { _iterator2["return"](); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } node.layerUpdateState[layer.id].newTry(); var command = buildCommand(context.view, layer, extentsSource, extentsDestination, node); return context.scheduler.execute(command).then(function (textures) { // Do not apply the new texture if its level is < than the current // one. This is only needed for elevation layers, because we may // have several concurrent layers but we can only use one texture. if (targetLevel <= nodeLayer.level) { node.layerUpdateState[layer.id].noMoreUpdatePossible(); return; } var elevation = { texture: textures[0], pitch: extentsDestination[0].offsetToParent(textures[0].extent, nodeLayer.offsetScales[0]) }; node.layerUpdateState[layer.id].success(); if (elevation.texture) { if (layer.useColorTextureElevation) { elevation.min = layer.colorTextureElevationMinZ; elevation.max = layer.colorTextureElevationMaxZ; } else { var _computeMinMaxElevati2 = (0, _XbilParser.computeMinMaxElevation)(elevation.texture.image.data, SIZE_TEXTURE_TILE, SIZE_TEXTURE_TILE, elevation.pitch), _min = _computeMinMaxElevati2.min, _max = _computeMinMaxElevati2.max; elevation.min = !_min ? 0 : _min; elevation.max = !_max ? 0 : _max; } } node.setBBoxZ(elevation.min, elevation.max, layer.scale); nodeLayer.setTexture(0, elevation.texture, elevation.pitch); var nodeParent = parent.material && parent.material.getElevationLayer(); nodeLayer.replaceNoDataValueFromParent(nodeParent, layer.noDataValue); }, function (err) { return (0, _handlerNodeError["default"])(err, node, layer, targetLevel, context.view); }); } function removeLayeredMaterialNodeLayer(layerId) { return function (node) { if (node.material && node.material.removeLayer) { node.material.removeLayer(layerId); if (node.material.elevationLayerIds[0] == layerId) { node.setBBoxZ(0, 0); } } if (node.layerUpdateState && node.layerUpdateState[layerId]) { delete node.layerUpdateState[layerId]; } }; }