itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
338 lines (272 loc) • 12.3 kB
JavaScript
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];
}
};
}
;