From c2514ea127f1b20a1de25899e50436bde84426ba Mon Sep 17 00:00:00 2001 From: gchoqueux Date: Tue, 16 Jun 2026 12:39:13 +0200 Subject: [PATCH 1/4] refacto(RasterTile): simplify raster layer loading BREACKING CHANGES: remove pdateLayeredMaterialNodeImagery, updateLayeredMaterialNodeElevation --- packages/Main/src/Converter/convertToTile.ts | 53 ++-- .../Main/src/Core/Prefab/Globe/GlobeLayer.js | 4 +- packages/Main/src/Core/Prefab/TileBuilder.ts | 50 ++-- packages/Main/src/Core/Scheduler/Scheduler.js | 4 +- packages/Main/src/Core/TileGeometry.ts | 5 +- packages/Main/src/Core/TileMesh.ts | 4 +- packages/Main/src/Layer/ColorLayer.js | 11 +- packages/Main/src/Layer/ElevationLayer.js | 25 +- packages/Main/src/Layer/Layer.js | 22 +- .../Main/src/Layer/LayerUpdateStrategy.ts | 16 +- packages/Main/src/Layer/RasterLayer.js | 74 ++++- packages/Main/src/Layer/TiledGeometryLayer.js | 133 ++------- packages/Main/src/Main.js | 1 - .../Process/LayeredMaterialNodeProcessing.js | 262 ------------------ packages/Main/src/Provider/TileProvider.js | 21 -- packages/Main/src/Renderer/LayeredMaterial.ts | 56 ++-- packages/Main/src/Renderer/RasterTile.js | 100 +++++-- 17 files changed, 316 insertions(+), 525 deletions(-) delete mode 100644 packages/Main/src/Process/LayeredMaterialNodeProcessing.js delete mode 100644 packages/Main/src/Provider/TileProvider.js diff --git a/packages/Main/src/Converter/convertToTile.ts b/packages/Main/src/Converter/convertToTile.ts index 46adb7af18..cef5ea5716 100644 --- a/packages/Main/src/Converter/convertToTile.ts +++ b/packages/Main/src/Converter/convertToTile.ts @@ -47,38 +47,37 @@ export default { hideSkirt: layer.hideSkirt, }; - return newTileGeometry(builder, paramsGeometry).then((result) => { - // build tile mesh - result.geometry.increaseRefCount(); - const crsCount = layer.tileMatrixSets.length; - const material = new LayeredMaterial(layer.materialOptions, crsCount); - ReferLayerProperties(material, layer); + const { geometry, quaternion, position } = newTileGeometry(builder, paramsGeometry); + // build tile mesh + geometry.increaseRefCount(); + const crsCount = layer.tileMatrixSets.length; + const material = new LayeredMaterial(layer.materialOptions, crsCount); + ReferLayerProperties(material, layer); - const tile = new TileMesh(result.geometry, material, layer, extent, level); + const tile = new TileMesh(geometry, material, layer, extent, level); - if (parent && parent.isTileMesh) { - // get parent extent transformation - const pTrans = builder.computeShareableExtent(parent.extent); - // place relative to his parent - result.position.sub(pTrans.position).applyQuaternion(pTrans.quaternion.invert()); - result.quaternion.premultiply(pTrans.quaternion); - } + if (parent && parent.isTileMesh) { + // get parent extent transformation + const pTrans = builder.computeShareableExtent(parent.extent); + // place relative to his parent + position.sub(pTrans.position).applyQuaternion(pTrans.quaternion.invert()); + quaternion.premultiply(pTrans.quaternion); + } - tile.position.copy(result.position); - tile.quaternion.copy(result.quaternion); - tile.visible = false; - tile.updateMatrix(); + tile.position.copy(position); + tile.quaternion.copy(quaternion); + tile.visible = false; + tile.updateMatrix(); - setTileFromTiledLayer(tile, layer); + setTileFromTiledLayer(tile, layer); - if (parent) { - tile.geoidHeight = parent.geoidHeight; - const geoidHeight = geoidLayerIsVisible(layer) ? tile.geoidHeight : 0; - tile.setBBoxZ({ min: parent.obb.z.min, max: parent.obb.z.max, geoidHeight }); - tile.material.setUniform('geoidHeight', geoidHeight); - } + if (parent) { + tile.geoidHeight = parent.geoidHeight; + const geoidHeight = geoidLayerIsVisible(layer) ? tile.geoidHeight : 0; + tile.setBBoxZ({ min: parent.obb.z.min, max: parent.obb.z.max, geoidHeight }); + tile.material.setUniform('geoidHeight', geoidHeight); + } - return tile; - }); + return tile; }, }; diff --git a/packages/Main/src/Core/Prefab/Globe/GlobeLayer.js b/packages/Main/src/Core/Prefab/Globe/GlobeLayer.js index 02123e2495..fced5a01a7 100644 --- a/packages/Main/src/Core/Prefab/Globe/GlobeLayer.js +++ b/packages/Main/src/Core/Prefab/Globe/GlobeLayer.js @@ -112,7 +112,7 @@ class GlobeLayer extends TiledGeometryLayer { return super.preUpdate(context, changeSources); } - subdivision(context, layer, node) { + subdivision(context, node) { if (node.level == 5) { const row = node.getExtentsByProjection('EPSG:4326')[0].row; if (row == 31 || row == 0) { @@ -120,7 +120,7 @@ class GlobeLayer extends TiledGeometryLayer { return false; } } - return super.subdivision(context, layer, node); + return super.subdivision(context, node); } culling(node, camera) { diff --git a/packages/Main/src/Core/Prefab/TileBuilder.ts b/packages/Main/src/Core/Prefab/TileBuilder.ts index c5e65097b5..02c60c98b1 100644 --- a/packages/Main/src/Core/Prefab/TileBuilder.ts +++ b/packages/Main/src/Core/Prefab/TileBuilder.ts @@ -10,7 +10,7 @@ const cacheBuffer = new Map(); -const cacheTile = new LRUCache>({ max: 500 }); +const cacheTile = new LRUCache({ max: 500 }); export interface GpuBufferAttributes { index: THREE.BufferAttribute | null; @@ -89,35 +89,27 @@ export function newTileGeometry( `${builder.crs}_${params.disableSkirt ? 0 : 1}_${params.segments}`; const key = `s${south}l${params.level}bK${bufferKey}`; - let promiseGeometry = cacheTile.get(key); + let geometry = cacheTile.get(key); // build geometry if doesn't exist - if (!promiseGeometry) { - let resolve: ((value: TileGeometry) => void) | undefined; - promiseGeometry = new Promise((r) => { resolve = r; }); - cacheTile.set(key, promiseGeometry); - + if (!geometry) { params.extent = shareableExtent; const center = builder.center(params.extent).clone(); // Read previously cached values (index and uv.wgs84 only // depend on the # of triangles) let cachedBuffers = cacheBuffer.get(bufferKey); - let buffers; - try { - buffers = computeBuffers( - builder, - { ...params, center }, - cachedBuffers !== undefined - ? { - index: cachedBuffers.index.array as UintArray, - uv: cachedBuffers.uv.array as Float32Array, - } - : undefined, - ); - } catch (e) { - return Promise.reject(e); - } + const buffers = computeBuffers( + builder, + { ...params, center }, + cachedBuffers !== undefined + ? { + index: cachedBuffers.index.array as + Uint8Array | Uint16Array | Uint32Array, + uv: cachedBuffers.uv.array as Float32Array, + } + : undefined, + ); if (!cachedBuffers) { // We know the fields will exist due to the condition @@ -146,15 +138,15 @@ export function newTileGeometry( normal: new THREE.BufferAttribute(buffers.normal, 3), }; - const geometry = new TileGeometry(builder, params, gpuBuffers); - const bbox = geometry.boundingBox as THREE.Box3; - geometry.OBB = new OBB(bbox.min, bbox.max); + geometry = new TileGeometry(builder, params, gpuBuffers); + geometry.OBB = + new OBB(geometry.boundingBox.min, geometry.boundingBox.max); geometry.initRefCount(cacheTile, key); - (resolve as (value: TileGeometry) => void)(geometry); - return Promise.resolve({ geometry, quaternion, position }); + cacheTile.set(key, geometry); + + return { geometry, quaternion, position }; } - return (promiseGeometry as Promise) - .then(geometry => ({ geometry, quaternion, position })); + return { geometry, quaternion, position }; } diff --git a/packages/Main/src/Core/Scheduler/Scheduler.js b/packages/Main/src/Core/Scheduler/Scheduler.js index 0154025972..a043d5ea98 100644 --- a/packages/Main/src/Core/Scheduler/Scheduler.js +++ b/packages/Main/src/Core/Scheduler/Scheduler.js @@ -6,7 +6,6 @@ import PriorityQueue from 'js-priority-queue'; import DataSourceProvider from 'Provider/DataSourceProvider'; -import TileProvider from 'Provider/TileProvider'; import $3dTilesProvider from 'Provider/3dTilesProvider'; import PointCloudProvider from 'Provider/PointCloudProvider'; import URLBuilder from 'Provider/URLBuilder'; @@ -128,7 +127,6 @@ Scheduler.prototype.constructor = Scheduler; Scheduler.prototype.initDefaultProviders = function initDefaultProviders() { // Register all providers - this.addProtocolProvider('tile', TileProvider); this.addProtocolProvider('3d-tiles', $3dTilesProvider); this.addProtocolProvider('pointcloud', PointCloudProvider); }; @@ -239,7 +237,7 @@ Scheduler.prototype.execute = function execute(command) { * @returns {Promise} The {@link Scheduler} always expect a Promise as a result, * resolving to an object containing sufficient information for the associated * processing to the current layer. For example, see the - * [LayeredMaterialNodeProcessing#updateLayeredMaterialNodeElevation]{@link + * [LayeredMaterialNodeProcessing#updateRasterTile]{@link * https://github.com/iTowns/itowns/blob/master/src/Process/LayeredMaterialNodeProcessing.js} * class or other processing class. */ diff --git a/packages/Main/src/Core/TileGeometry.ts b/packages/Main/src/Core/TileGeometry.ts index bf18e3693f..8440f85577 100644 --- a/packages/Main/src/Core/TileGeometry.ts +++ b/packages/Main/src/Core/TileGeometry.ts @@ -57,6 +57,8 @@ export class TileGeometry extends THREE.BufferGeometry { /** Resolution of the tile geometry in segments per side. */ public segments: number; + public boundingBox: THREE.Box3; + /** * [TileGeometry] instances are shared between tiles. Since a geometry * handles its own GPU resource, it needs a reference counter to dispose of @@ -87,6 +89,7 @@ export class TileGeometry extends THREE.BufferGeometry { this.setAttribute(`uv_${i}`, bufferAttributes.uvs[i]); } + this.boundingBox = new THREE.Box3(); this.computeBoundingBox(); this.OBB = null; this.hideSkirt = params.hideSkirt ?? false; @@ -110,7 +113,7 @@ export class TileGeometry extends THREE.BufferGeometry { * @param key - The [south, level, epsg] key of this geometry. */ public initRefCount( - cacheTile: LRUCache>, + cacheTile: LRUCache, key: string, ): void { if (this._refCount !== null) { diff --git a/packages/Main/src/Core/TileMesh.ts b/packages/Main/src/Core/TileMesh.ts index 33aa931a56..c9b5401767 100644 --- a/packages/Main/src/Core/TileMesh.ts +++ b/packages/Main/src/Core/TileMesh.ts @@ -161,9 +161,7 @@ class TileMesh extends THREE.Mesh { * @param renderer - The renderer used to render textures. */ override onBeforeRender(renderer: THREE.WebGLRenderer) { - if (this.material.layersNeedUpdate) { - this.material.updateLayersUniforms(renderer); - } + this.material.updateLayersUniforms(renderer); // Track actual usage every time this mesh is rendered // Use global current rendering view ID set by MainLoop diff --git a/packages/Main/src/Layer/ColorLayer.js b/packages/Main/src/Layer/ColorLayer.js index da56d87873..6c6c31fd06 100644 --- a/packages/Main/src/Layer/ColorLayer.js +++ b/packages/Main/src/Layer/ColorLayer.js @@ -1,5 +1,4 @@ import RasterLayer from 'Layer/RasterLayer'; -import { updateLayeredMaterialNodeImagery } from 'Process/LayeredMaterialNodeProcessing'; import { RasterColorTile } from 'Renderer/RasterTile'; import { deprecatedColorLayerOptions } from 'Core/Deprecated/Undeprecator'; import Style from 'Core/Style'; @@ -164,7 +163,11 @@ class ColorLayer extends RasterLayer { * @returns {RasterColorTile} The raster color node added. */ setupRasterNode(node) { - const rasterColorTile = new RasterColorTile(this); + const tiles = node.getExtentsByProjection(this.crs); + + const rasterColorTile = new RasterColorTile(this, tiles); + + rasterColorTile.initFromParent(node.parent.material?.getColorTile(this.id)); node.material.addColorTile(rasterColorTile); // set up ColorLayer ordering. @@ -172,10 +175,6 @@ class ColorLayer extends RasterLayer { return rasterColorTile; } - - update(context, layer, node, parent) { - return updateLayeredMaterialNodeImagery(context, this, node, parent); - } } export default ColorLayer; diff --git a/packages/Main/src/Layer/ElevationLayer.js b/packages/Main/src/Layer/ElevationLayer.js index 276f36966b..a5ec7ce861 100644 --- a/packages/Main/src/Layer/ElevationLayer.js +++ b/packages/Main/src/Layer/ElevationLayer.js @@ -1,5 +1,4 @@ import RasterLayer from 'Layer/RasterLayer'; -import { updateLayeredMaterialNodeElevation } from 'Process/LayeredMaterialNodeProcessing'; import { RasterElevationTile } from 'Renderer/RasterTile'; /** @@ -115,7 +114,9 @@ class ElevationLayer extends RasterLayer { * @returns {RasterElevationTile} The raster elevation node added. */ setupRasterNode(node) { - const rasterElevationNode = new RasterElevationTile(this); + const tiles = node.getExtentsByProjection(this.crs); + + const rasterElevationNode = new RasterElevationTile(this, tiles); node.material.setElevationTile(rasterElevationNode); node.material.setElevationTileId(this.id); @@ -123,7 +124,6 @@ class ElevationLayer extends RasterLayer { const updateBBox = () => node.setBBoxZ({ min: rasterElevationNode.min, max: rasterElevationNode.max, scale: this.scale, }); - updateBBox(); // listen elevation updating rasterElevationNode.addEventListener('rasterElevationLevelChanged', updateBBox); @@ -135,11 +135,26 @@ class ElevationLayer extends RasterLayer { this.removeEventListener('scale-property-changed', updateBBox); }); + // Init the node by parent + rasterElevationNode.initFromParent(node.parent.material?.getElevationTile()); + return rasterElevationNode; } - update(context, layer, node, parent) { - return updateLayeredMaterialNodeElevation(context, this, node, parent); + getRasterTile(node) { + return node.material.getElevationTile(); + } + + /** + * Compares source zoom ranges to detect whether the new source can provide + * more precise data than the source currently attached to this tile. + * If so, the raster tile is recreated to reload elevation with finer detail. + * + * @param {RasterElevationTile} rasterTile - Existing elevation raster tile on the node. + * @returns {boolean} `true` when the new source is more precise and tile reload is required. + */ + overloadRasterTile(rasterTile) { + return this.source.zoom.min > rasterTile.layer.source.zoom.max; } } diff --git a/packages/Main/src/Layer/Layer.js b/packages/Main/src/Layer/Layer.js index 08a0313d75..235638fa6a 100644 --- a/packages/Main/src/Layer/Layer.js +++ b/packages/Main/src/Layer/Layer.js @@ -254,17 +254,19 @@ class Layer extends THREE.EventDispatcher { } getData(from, to) { - const key = this.source.getDataKey(this.source.isVectorSource ? to : from); - let data = this.cache.get(key); - if (!data) { - data = this.source.loadData(from, this) - .then(feat => this.convert(feat, to)) - .catch((err) => { - this.source.handlingError(err); - }); - this.cache.set(key, data); + if (from) { + const key = this.source.getDataKey(this.source.isVectorSource ? to : from); + let data = this.cache.get(key); + if (!data) { + data = this.source.loadData(from, this) + .then(feat => this.convert(feat, to)) + .catch((err) => { + this.source.handlingError(err); + }); + this.cache.set(key, data); + } + return data; } - return data; } /** diff --git a/packages/Main/src/Layer/LayerUpdateStrategy.ts b/packages/Main/src/Layer/LayerUpdateStrategy.ts index 34a1fc9c62..f62c257cde 100644 --- a/packages/Main/src/Layer/LayerUpdateStrategy.ts +++ b/packages/Main/src/Layer/LayerUpdateStrategy.ts @@ -1,4 +1,4 @@ -import { EMPTY_TEXTURE_ZOOM } from 'Renderer/RasterTile'; +import { EMPTY_TEXTURE_ZOOM, type RasterTile } from 'Renderer/RasterTile'; /** * This modules implements various layer update strategies. * @@ -112,3 +112,17 @@ export function chooseNextLevelToFetch( } return nextLevelToFetch; } + +export const nextLevelToFetch = (t: RasterTile) => { + const zoom = { + min: Math.max(t.layer.zoom.min, t.layer.source.zoom?.min), + max: Math.min(t.layer.zoom.max, t.layer.source.zoom?.max), + }; + return chooseNextLevelToFetch( + t.layer.updateStrategy, + t.tiles[0].zoom, + t.level, + t.state.failureParams, + zoom, + ); +}; diff --git a/packages/Main/src/Layer/RasterLayer.js b/packages/Main/src/Layer/RasterLayer.js index 75c93002ff..2bdfe199bf 100644 --- a/packages/Main/src/Layer/RasterLayer.js +++ b/packages/Main/src/Layer/RasterLayer.js @@ -1,9 +1,25 @@ import Layer from 'Layer/Layer'; import { STRATEGY_MIN_NETWORK_TRAFFIC } from 'Layer/LayerUpdateStrategy'; -import { removeLayeredMaterialNodeTile } from 'Process/LayeredMaterialNodeProcessing'; import textureConverter from 'Converter/textureConverter'; import { CACHE_POLICIES } from 'Core/Scheduler/Cache'; +export function removeLayeredMaterialNodeTile(tileId) { + /** + * @param {TileMesh} node - The node to udpate. + */ + return function removeLayeredMaterialNodeTile(node) { + if (node.material?.removeTile) { + if (node.material.elevationTile !== undefined) { + node.setBBoxZ({ min: 0, max: 0 }); + } + node.material.removeTile(tileId); + } + if (node.layerUpdateState && node.layerUpdateState[tileId]) { + delete node.layerUpdateState[tileId]; + } + }; +} + class RasterLayer extends Layer { constructor(id, config) { const { @@ -19,6 +35,7 @@ class RasterLayer extends Layer { cacheLifeTime, }); + this.visible = true; this.minFilter = minFilter; this.magFilter = magFilter; @@ -44,6 +61,61 @@ class RasterLayer extends Layer { root.traverse(removeLayeredMaterialNodeTile(this.id)); } } + + hasData(node) { + const minZoom = Math.max(this.source.zoom.min, this.zoom.min); + + const tiles = node.getExtentsByProjection(this.crs) + .map(e => e.tiledExtentParent(minZoom)); + + return tiles.some(e => e.zoom >= minZoom && this.source.hasData(e)); + } + + /** + * Indicates whether an existing raster tile must be recreated. + * Subclasses can override this to force rebuilding tiles based on tile state. + * + * @param {RasterTile} rasterTile - Current raster tile attached to the node. + * @returns {boolean} `true` to recreate the raster tile, `false` to keep it. + */ + // eslint-disable-next-line no-unused-vars + overloadRasterTile(rasterTile) { + return false; + } + + /** + * Returns the raster tile associated with this layer for a given node. + * + * @param {TileMesh} node - The tile mesh carrying layered material tiles. + * @returns {?RasterTile} The matching raster tile, or `undefined` when none exists. + */ + getRasterTile(node) { + return node.material.getTile(this.id); + } + + /** + * Updates raster data for a node if the layer is active and data is available. + * Creates or recreates the raster tile when needed, then triggers loading. + * + * @param {object} context - Update context. + * @param {View} context.view - Active view used to schedule loading. + * @param {RasterLayer} layer - Current raster layer. + * @param {TileMesh} node - Tile node to update. + * @returns {Promise|undefined} A loading promise when an update is scheduled. + */ + update(context, layer, node) { + if (layer.visible && !layer.freeze && this.hasData(node)) { + let rasterTile = this.getRasterTile(node); + + if (!rasterTile || this.overloadRasterTile(rasterTile)) { + rasterTile = this.setupRasterNode(node); + } + + if (rasterTile && (!rasterTile.hasData() || (node.visible && node.material.visible))) { + return rasterTile.load(node, context.view); + } + } + } } export default RasterLayer; diff --git a/packages/Main/src/Layer/TiledGeometryLayer.js b/packages/Main/src/Layer/TiledGeometryLayer.js index 3e19051ad3..53036be708 100644 --- a/packages/Main/src/Layer/TiledGeometryLayer.js +++ b/packages/Main/src/Layer/TiledGeometryLayer.js @@ -313,51 +313,30 @@ class TiledGeometryLayer extends GeometryLayer { if (!node.parent) { return ObjectRemovalHelper.removeChildrenAndCleanup(this, node); } - // early exit if parent' subdivision is in progress - if (node.parent.pendingSubdivision) { - node.visible = false; - node.material.visible = false; - this.info.update(node); - return undefined; - } - // do proper culling node.visible = !this.culling(node, context.camera); - if (node.visible) { - let requestChildrenUpdate = false; - - node.material.visible = true; - node.material.layersNeedUpdate = true; + if (node.visible && this.subdivision(context, node)) { + node.material.visible = false; this.info.update(node); - if (node.pendingSubdivision || (TiledGeometryLayer.hasEnoughTexturesToSubdivide(context, node) && this.subdivision(context, this, node))) { - this.subdivideNode(context, node); - // display iff children aren't ready - node.material.visible = node.pendingSubdivision; - this.info.update(node); - requestChildrenUpdate = true; - } + return this.subdivideNode(context, node); + } - if (node.material.visible) { - if (!requestChildrenUpdate) { - return ObjectRemovalHelper.removeChildren(this, node); - } - } + node.material.visible = node.visible; - return requestChildrenUpdate ? node.children.filter(n => n.layer == this) : undefined; - } + // RasterTile.needsUpdate has been removed + // TODO: optimize uniforms update + node.material.layersNeedUpdate = node.material.visible; - node.material.visible = false; this.info.update(node); return ObjectRemovalHelper.removeChildren(this, node); } convert(requester, extent) { - return convertToTile.convert(requester, extent, this).then((tileMesh) => { - tileMesh.material.renderTargetCache = this.renderTargetCache; - return tileMesh; - }); + const tileMesh = convertToTile.convert(requester, extent, this); + tileMesh.material.renderTargetCache = this.renderTargetCache; + return tileMesh; } /** @@ -379,56 +358,6 @@ class TiledGeometryLayer extends GeometryLayer { return false; } - /** - * Tell if a node has enough elevation or color textures to subdivide. - * Subdivision is prevented if: - *
    - *
  • the node is covered by at least one elevation layer and if the node - * doesn't have an elevation texture yet
  • - *
  • a color texture is missing
  • - *
- * - * @param {object} context - The context of the update; see the {@link - * MainLoop} for more informations. - * @param {TileMesh} node - The node to subdivide. - * - * @returns {boolean} False if the node can not be subdivided, true - * otherwise. - */ - static hasEnoughTexturesToSubdivide(context, node) { - const layerUpdateState = node.layerUpdateState || {}; - let nodeLayer = node.material.getElevationTile(); - - for (const e of context.elevationLayers) { - const tiles = node.getExtentsByProjection(e.crs); - - if (!e.frozen && e.ready && tiles.some(t => e.source.hasData(t)) && (!nodeLayer || nodeLayer.level < 0)) { - // no stop subdivision in the case of a loading error - if (layerUpdateState[e.id] && layerUpdateState[e.id].inError()) { - continue; - } - return false; - } - } - - for (const c of context.colorLayers) { - if (c.frozen || !c.visible || !c.ready) { - continue; - } - const tiles = node.getExtentsByProjection(c.crs); - - // no stop subdivision in the case of a loading error - if (layerUpdateState[c.id] && layerUpdateState[c.id].inError()) { - continue; - } - nodeLayer = node.material.getColorTile(c.id); - if (tiles.some(t => c.source.hasData(t)) && (!nodeLayer || nodeLayer.level < 0)) { - return false; - } - } - return true; - } - /** * Subdivides a node of this layer. If the node is currently in the process * of subdivision, it will not do anything here. The subdivision of a node @@ -442,38 +371,21 @@ class TiledGeometryLayer extends GeometryLayer { * @param {TileMesh} node - The node to subdivide. * @returns {Promise} { description_of_the_return_value } */ + subdivideNode(context, node) { - if (!node.pendingSubdivision && !node.children.some(n => n.layer == this)) { + if (node.children.length === 0) { const extents = node.extent.subdivision(); - // TODO: pendingSubdivision mechanism is fragile, get rid of it - node.pendingSubdivision = true; - - const command = { - /* mandatory */ - view: context.view, - requester: node, - layer: this, - priority: 10000, - /* specific params */ - extentsSource: extents, - redraw: false, - }; - - return context.scheduler.execute(command).then((children) => { - for (const child of children) { - node.add(child); - child.updateMatrixWorld(true); - } - node.pendingSubdivision = false; - context.view.notifyChange(node, false); - }, (err) => { - node.pendingSubdivision = false; - if (!err.isCancelledCommandException) { - throw new Error(err); - } + extents.forEach((extent) => { + const child = this.convert(node, extent); + node.add(child); + child.updateMatrixWorld(true); }); + context.view.notifyChange(node, true); } + + + return node.children; } /** @@ -481,12 +393,11 @@ class TiledGeometryLayer extends GeometryLayer { * * @param {object} context - The context of the update; see the {@link * MainLoop} for more informations. - * @param {PlanarLayer} layer - This layer, parameter to be removed. * @param {TileMesh} node - The node to test. * * @returns {boolean} - True if the node is subdivisable, otherwise false. */ - subdivision(context, layer, node) { + subdivision(context, node) { if (node.level < this.minSubdivisionLevel) { return true; } diff --git a/packages/Main/src/Main.js b/packages/Main/src/Main.js index 5261034d8a..9b00618594 100644 --- a/packages/Main/src/Main.js +++ b/packages/Main/src/Main.js @@ -16,7 +16,6 @@ export { default as View } from 'Core/View'; export { VIEW_EVENTS } from 'Core/View'; export { default as FeatureProcessing } from 'Process/FeatureProcessing'; export { default as ObjectRemovalHelper } from 'Process/ObjectRemovalHelper'; -export { updateLayeredMaterialNodeImagery, updateLayeredMaterialNodeElevation } from 'Process/LayeredMaterialNodeProcessing'; export { default as OrientedImageCamera } from 'Renderer/OrientedImageCamera'; export { default as PointsMaterial, PNTS_MODE, PNTS_SHAPE, PNTS_SIZE_MODE, ClassificationScheme } from 'Renderer/PointsMaterial'; export { default as GlobeControls } from 'Controls/GlobeControls'; diff --git a/packages/Main/src/Process/LayeredMaterialNodeProcessing.js b/packages/Main/src/Process/LayeredMaterialNodeProcessing.js deleted file mode 100644 index a7684c8a43..0000000000 --- a/packages/Main/src/Process/LayeredMaterialNodeProcessing.js +++ /dev/null @@ -1,262 +0,0 @@ -import { chooseNextLevelToFetch } from 'Layer/LayerUpdateStrategy'; -import LayerUpdateState from 'Layer/LayerUpdateState'; -import handlingError from 'Process/handlerNodeError'; - -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.getElevationTile() && - cmd.targetLevel <= cmd.requester.material.getElevationTile().level) { - return true; - } - - // Cancel the command if the layer was removed between command scheduling and command execution - if (!cmd.requester.layerUpdateState[cmd.layer.id] - || !cmd.layer.source._featuresCaches[cmd.layer.crs]) { - return true; - } - - return !cmd.requester.material.visible; -} - -function buildCommand(view, layer, extentsSource, extentsDestination, requester) { - return { - view, - layer, - extentsSource, - extentsDestination, - requester, - priority: materialCommandQueuePriorityFunction(requester.material), - earlyDropFunction: refinementCommandCancellationFn, - partialLoading: true, - }; -} - -function computePitchs(textures, extentsDestination) { - return extentsDestination - .map((ext, i) => (ext.offsetToParent(textures[i].extent))); -} - -export function updateLayeredMaterialNodeImagery(context, layer, node, parent) { - const material = node.material; - if (!parent || !material) { - return; - } - const extentsDestination = node.getExtentsByProjection(layer.crs); - - const zoom = extentsDestination[0].zoom; - if (zoom > layer.zoom.max || zoom < layer.zoom.min) { - return; - } - - let nodeLayer = material.getTile(layer.id); - - // Initialisation - if (node.layerUpdateState[layer.id] === undefined) { - node.layerUpdateState[layer.id] = new LayerUpdateState(); - - if (!extentsDestination.some(t => layer.source.hasData(t))) { - // 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.getTile && - parent.material.getTile(layer.id)) { - // ok, we're going to inherit our parent's texture - } else { - node.layerUpdateState[layer.id].noMoreUpdatePossible(); - return; - } - } - - if (!nodeLayer) { - // Create new raster node - nodeLayer = layer.setupRasterNode(node); - - // Init the node by parent - const parentLayer = parent.material?.getTile(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; - } - - // 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; - } - - const failureParams = node.layerUpdateState[layer.id].failureParams; - const destinationLevel = extentsDestination[0].zoom || node.level; - const targetLevel = chooseNextLevelToFetch(layer.updateStrategy, destinationLevel, nodeLayer.level, failureParams, layer.source.zoom); - - if ((!layer.source.isVectorSource && targetLevel <= nodeLayer.level) || targetLevel > destinationLevel) { - if (failureParams.lowestLevelError != Infinity) { - // this is the highest level found in case of error. - node.layerUpdateState[layer.id].noMoreUpdatePossible(); - } - return; - } else if (!extentsDestination.some(t => layer.source.hasData(t))) { - node.layerUpdateState[layer.id].noData({ targetLevel }); - context.view.notifyChange(node, false); - return; - } - - const extentsSource = extentsDestination.map(e => e.tiledExtentParent(targetLevel)); - node.layerUpdateState[layer.id].newTry(); - const command = buildCommand(context.view, layer, extentsSource, extentsDestination, node); - - return context.scheduler.execute(command) - .then( - (results) => { - // Does nothing if the layer has been removed while command was being or waiting to be executed - if (!node.layerUpdateState[layer.id]) { - return; - } - const textures = results.map((texture, index) => (texture != null ? texture : - { isTexture: false, extent: extentsDestination[index] })); - - // TODO: Handle error : result is undefined in provider. throw error - const pitchs = computePitchs(textures, extentsDestination); - nodeLayer.setTextures(textures, pitchs); - node.layerUpdateState[layer.id].success(); - }) - .catch((err) => { - handlingError(err, node, layer, targetLevel, context.view); - }); -} - -export function updateLayeredMaterialNodeElevation(context, layer, node, parent) { - const 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) - const extentsDestination = node.getExtentsByProjection(layer.crs); - const zoom = extentsDestination[0].zoom; - if (zoom > layer.zoom.max || zoom < layer.zoom.min) { - return; - } - // Init elevation layer, and inherit from parent if possible - let nodeLayer = material.getElevationTile(); - if (!nodeLayer) { - nodeLayer = layer.setupRasterNode(node); - } - - if (node.layerUpdateState[layer.id] === undefined) { - node.layerUpdateState[layer.id] = new LayerUpdateState(); - - const parentLayer = parent.material?.getTile(layer.id); - nodeLayer.initFromParent(parentLayer, extentsDestination); - - 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; - } - - const failureParams = node.layerUpdateState[layer.id].failureParams; - const targetLevel = chooseNextLevelToFetch(layer.updateStrategy, extentsDestination[0].zoom, nodeLayer.level, failureParams, layer.source.zoom); - - if (targetLevel <= nodeLayer.level || targetLevel > extentsDestination[0].zoom) { - node.layerUpdateState[layer.id].noMoreUpdatePossible(); - return; - } else if (!extentsDestination.some(t => layer.source.hasData(t))) { - node.layerUpdateState[layer.id].noData({ targetLevel }); - context.view.notifyChange(node, false); - return; - } - - const extentsSource = extentsDestination.map(e => e.tiledExtentParent(targetLevel)); - node.layerUpdateState[layer.id].newTry(); - const command = buildCommand(context.view, layer, extentsSource, extentsDestination, node); - - return context.scheduler.execute(command).then( - (results) => { - // Does nothing if the layer has been removed while command was being or waiting to be executed - if (!node.layerUpdateState[layer.id]) { - return; - } - - // 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; - } - const pitchs = computePitchs(results, extentsDestination); - nodeLayer.setTextures(results, pitchs); - node.layerUpdateState[layer.id].success(); - }, - err => handlingError(err, node, layer, targetLevel, context.view)); -} - -export function removeLayeredMaterialNodeTile(tileId) { - /** - * @param {TileMesh} node - The node to udpate. - */ - return function removeLayeredMaterialNodeTile(node) { - if (node.material?.removeTile) { - if (node.material.elevationTile !== undefined) { - node.setBBoxZ({ min: 0, max: 0 }); - } - node.material.removeTile(tileId); - } - if (node.layerUpdateState && node.layerUpdateState[tileId]) { - delete node.layerUpdateState[tileId]; - } - }; -} diff --git a/packages/Main/src/Provider/TileProvider.js b/packages/Main/src/Provider/TileProvider.js deleted file mode 100644 index 65ebffcd56..0000000000 --- a/packages/Main/src/Provider/TileProvider.js +++ /dev/null @@ -1,21 +0,0 @@ -import CancelledCommandException from 'Core/Scheduler/CancelledCommandException'; - -export default { - executeCommand(command) { - const promises = []; - const layer = command.layer; - const requester = command.requester; - const extentsSource = command.extentsSource; - - if (requester && - !requester.material) { - return Promise.reject(new CancelledCommandException(command)); - } - - for (const extent of extentsSource) { - promises.push(layer.convert(requester, extent)); - } - - return Promise.all(promises); - }, -}; diff --git a/packages/Main/src/Renderer/LayeredMaterial.ts b/packages/Main/src/Renderer/LayeredMaterial.ts index 58cc3938ef..081373cad8 100644 --- a/packages/Main/src/Renderer/LayeredMaterial.ts +++ b/packages/Main/src/Renderer/LayeredMaterial.ts @@ -129,7 +129,7 @@ function updateLayersUniformsForType( if (!texture.isTexture) { continue; } textureSetId += `${texture.id}.`; - uOffsetScales[count] = tile.offsetScales[i]; + uOffsetScales[count] = tile.offsetScales[i] || uOffsetScales[count]; uLayers[count] = tile; const img = texture.image; @@ -500,35 +500,39 @@ export class LayeredMaterial extends THREE.ShaderMaterial { * @param renderer - The renderer used to render textures into arrays. */ public updateLayersUniforms(renderer: THREE.WebGLRenderer): void { - const colorlayers = this.colorTiles - .filter(rt => rt.visible && rt.opacity > 0); - colorlayers.sort((a, b) => - this.colorTileIds.indexOf(a.id) - this.colorTileIds.indexOf(b.id), - ); + if (!this.layersNeedUpdate) { + return; + } else { + const colorlayers = this.colorTiles + .filter(rt => rt.visible && rt.opacity > 0); + colorlayers.sort((a, b) => + this.colorTileIds.indexOf(a.id) - this.colorTileIds.indexOf(b.id), + ); - updateLayersUniformsForType( - this.getLayerUniforms('color'), - colorlayers, - this.defines.NUM_FS_TEXTURES, - 'c', - renderer, - this.renderTargetCache, - ); + updateLayersUniformsForType( + this.getLayerUniforms('color'), + colorlayers, + this.defines.NUM_FS_TEXTURES, + 'c', + renderer, + this.renderTargetCache, + ); - if (this.elevationTileId !== undefined && this.getElevationTile()) { - if (this.elevationTile !== undefined) { - updateLayersUniformsForType( - this.getLayerUniforms('elevation'), - [this.elevationTile], - this.defines.NUM_VS_TEXTURES, - 'e', - renderer, - this.renderTargetCache, - ); + if (this.elevationTileId !== undefined && this.getElevationTile()) { + if (this.elevationTile !== undefined) { + updateLayersUniformsForType( + this.getLayerUniforms('elevation'), + [this.elevationTile], + this.defines.NUM_VS_TEXTURES, + 'e', + renderer, + this.renderTargetCache, + ); + } } - } - this.layersNeedUpdate = false; + this.layersNeedUpdate = false; + } } /** diff --git a/packages/Main/src/Renderer/RasterTile.js b/packages/Main/src/Renderer/RasterTile.js index ccc5393fae..be37d18a8b 100644 --- a/packages/Main/src/Renderer/RasterTile.js +++ b/packages/Main/src/Renderer/RasterTile.js @@ -1,9 +1,41 @@ import * as THREE from 'three'; import { ELEVATION_MODES } from 'Renderer/LayeredMaterial'; +import LayerUpdateState from 'Layer/LayerUpdateState'; +import { nextLevelToFetch } from 'Layer/LayerUpdateStrategy'; +import handlingError from 'Process/handlerNodeError'; import { checkNodeElevationTextureValidity, insertSignificantValuesFromParent, computeMinMaxElevation } from 'Parser/XbilParser'; export const EMPTY_TEXTURE_ZOOM = -1; +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) { + const { requester } = cmd; + const { children } = requester; + + return !cmd.force && !requester.visible && (!requester.parent || !requester.material.visible || children.find(c => c.visible)); +} + +function buildCommand(tile, extentsSource, requester, view) { + return { + view, + layer: tile.layer, + extentsSource: extentsSource.map(t => (tile.layer.source.hasData(t) ? t : undefined)), + extentsDestination: tile.tiles, + requester, + priority: materialCommandQueuePriorityFunction(requester.material), + earlyDropFunction: refinementCommandCancellationFn, + partialLoading: true, + force: !tile.hasData(), + }; +} + const pitch = new THREE.Vector4(); function getIndiceWithPitch(i, pitch, w) { @@ -28,7 +60,7 @@ function getIndiceWithPitch(i, pitch, w) { * @class RasterTile */ export class RasterTile extends THREE.EventDispatcher { - constructor(layer) { + constructor(layer, tiles) { super(); this.layer = layer; this.crs = layer.parent.tileMatrixSets.indexOf(layer.crs); @@ -37,9 +69,12 @@ export class RasterTile extends THREE.EventDispatcher { } this.textures = []; + this.tiles = tiles; this.offsetScales = []; this.level = EMPTY_TEXTURE_ZOOM; this.needsUpdate = false; + this.state = new LayerUpdateState(); + this.lowestLevelError = Infinity; this._handlerCBEvent = () => { this.needsUpdate = true; }; layer.addEventListener('visible-property-changed', this._handlerCBEvent); @@ -58,11 +93,39 @@ export class RasterTile extends THREE.EventDispatcher { return this.layer.visible; } - initFromParent(parent, extents) { + load(requester, view) { + if (this.state.canTryUpdate()) { + this.state.newTry(); + + const nextLevel = nextLevelToFetch(this); + const nextTiles = this.tiles.map(tile => tile.tiledExtentParent(nextLevel)); + + const command = buildCommand(this, nextTiles, requester, view); + + return view.mainLoop.scheduler.execute(command).then((textures) => { + this.setTextures(textures); + + if (nextLevelToFetch(this) == this.level) { + this.state.noMoreUpdatePossible(); + } else { + this.state.success(); + } + + return textures; + }, () => this.state.success()) + .catch(err => handlingError(err, requester, this.layer, nextLevel, view)); + } + } + + hasData() { + return this.level > EMPTY_TEXTURE_ZOOM; + } + + initFromParent(parent) { if (parent && parent.level > this.level) { let index = 0; const sortedParentTextures = this.sortBestParentTextures(parent.textures); - for (const childExtent of extents) { + for (const childExtent of this.tiles) { const matchingParentTexture = sortedParentTextures .find(parentTexture => parentTexture && childExtent.isInside(parentTexture.extent)); if (matchingParentTexture) { @@ -71,9 +134,13 @@ export class RasterTile extends THREE.EventDispatcher { } } + if (nextLevelToFetch(this) == this.level) { + this.state.noMoreUpdatePossible(); + } + if (__DEBUG__) { - if (index != extents.length) { - console.error(`non-coherent result ${index} vs ${extents.length}.`, extents); + if (index != this.tiles.length) { + console.error(`non-coherent result ${index} vs ${this.tiles.length}.`, this.tiles); } } } @@ -131,18 +198,19 @@ export class RasterTile extends THREE.EventDispatcher { } setTexture(index, texture, offsetScale) { - if (this.shouldWriteTextureAtIndex(index, texture)) { - this.level = (texture && texture.extent) ? texture.extent.zoom : this.level; - this.textures[index] = texture || null; + if (texture && this.shouldWriteTextureAtIndex(index, texture)) { + this.level = texture.extent ? texture.extent.zoom : this.level; + this.textures[index] = texture; this.offsetScales[index] = offsetScale; this.needsUpdate = true; + return texture; } } - setTextures(textures, pitchs) { + setTextures(textures) { this.disposeRedrawnTextures(textures); for (let i = 0, il = textures.length; i < il; ++i) { - this.setTexture(i, textures[i], pitchs[i]); + this.setTexture(i, textures[i], this.tiles[i].offsetToParent(textures[i].extent)); } } @@ -165,8 +233,8 @@ export class RasterColorTile extends RasterTile { } export class RasterElevationTile extends RasterTile { - constructor(layer) { - super(layer); + constructor(layer, tiles) { + super(layer, tiles); const defaultEle = { bias: 0, mode: ELEVATION_MODES.DATA, @@ -210,23 +278,23 @@ export class RasterElevationTile extends RasterTile { } } - initFromParent(parent, extents) { + initFromParent(parent) { const currentLevel = this.level; - super.initFromParent(parent, extents); + super.initFromParent(parent); this.updateMinMaxElevation(); if (currentLevel !== this.level) { this.dispatchEvent({ type: 'rasterElevationLevelChanged', node: this }); } } - setTextures(textures, offsetScales) { + setTextures(textures) { const anyValidTexture = textures.find(texture => texture != null); if (!anyValidTexture) { return; } const currentLevel = this.level; this.replaceNoDataValueFromTexture(anyValidTexture); - super.setTextures(textures, offsetScales); + super.setTextures(textures); this.updateMinMaxElevation(); if (currentLevel !== this.level) { this.dispatchEvent({ type: 'rasterElevationLevelChanged', node: this }); From 78e9038e39b69e7675d7d04583d695e17839a512 Mon Sep 17 00:00:00 2001 From: gchoqueux Date: Wed, 29 Apr 2026 15:59:55 +0200 Subject: [PATCH 2/4] fix(test): issues from refactoring and rebasing --- examples/misc_clamp_ground.html | 9 +- packages/Main/test/unit/dataSourceProvider.js | 93 ++++++++++--------- packages/Main/test/unit/demutils.js | 32 ++----- packages/Main/test/unit/layeredmaterial.js | 3 +- .../unit/layeredmaterialnodeprocessing.js | 43 +++++---- packages/Main/test/unit/obb.js | 44 ++++----- packages/Main/test/unit/tiledGeometryLayer.js | 4 +- packages/Main/test/unit/tilemesh.js | 65 +++++-------- test/functional/GlobeControls.js | 1 + test/functional/view_25d_map.js | 2 +- 10 files changed, 135 insertions(+), 161 deletions(-) diff --git a/examples/misc_clamp_ground.html b/examples/misc_clamp_ground.html index 60a49b4830..583bf27a31 100644 --- a/examples/misc_clamp_ground.html +++ b/examples/misc_clamp_ground.html @@ -66,10 +66,13 @@ config.source = new itowns.WMTSSource(config.source); var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); + + return layer; } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); + const p = itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + function addMeshToScene() { // creation of the new mesh (a cylinder) var geometry = new THREE.CylinderGeometry(0, 10, 60, 8); @@ -100,9 +103,7 @@ } // Listen for globe full initialisation event - view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function globeInitialized() { - // eslint-disable-next-line no-console - console.info('Globe initialized'); + p.then((layer) => { addMeshToScene(); }); window.view = view; diff --git a/packages/Main/test/unit/dataSourceProvider.js b/packages/Main/test/unit/dataSourceProvider.js index 80f1821839..863e43ed5d 100644 --- a/packages/Main/test/unit/dataSourceProvider.js +++ b/packages/Main/test/unit/dataSourceProvider.js @@ -1,6 +1,5 @@ import * as THREE from 'three'; import assert from 'assert'; -import { updateLayeredMaterialNodeImagery, updateLayeredMaterialNodeElevation } from 'Process/LayeredMaterialNodeProcessing'; import FeatureProcessing from 'Process/FeatureProcessing'; import TileMesh from 'Core/TileMesh'; import { Extent } from '@itowns/geographic'; @@ -8,7 +7,6 @@ import { globalExtentTMS } from 'Core/Tile/TileGrid'; import OBB from 'Renderer/OBB'; import DataSourceProvider from 'Provider/DataSourceProvider'; import Fetcher from 'Provider/Fetcher'; -import TileProvider from 'Provider/TileProvider'; import WMTSSource from 'Source/WMTSSource'; import WMSSource from 'Source/WMSSource'; import WFSSource from 'Source/WFSSource'; @@ -46,21 +44,28 @@ describe('Provide in Sources', function () { let nodeLayer; let nodeLayerElevation; let featureLayer; + let tile; // Mock scheduler const context = { view: { notifyChange: () => true, - }, - scheduler: { - commands: [], - execute: (cmd) => { - context.scheduler.commands.push(cmd); - return new Promise(() => { /* no-op */ }); + mainLoop: { + scheduler: { + commands: [], + execute: (cmd) => { + context.view.mainLoop.scheduler.commands.push(cmd); + return new Promise(() => { /* no-op */ }); + }, + }, }, }, }; + const { scheduler } = context.view.mainLoop; + + context.scheduler = scheduler; + before(function () { stubFetcherJson = sinon.stub(Fetcher, 'json') .callsFake(() => Promise.resolve(JSON.parse(holes))); @@ -80,9 +85,11 @@ describe('Provide in Sources', function () { planarlayer.attach(colorlayer); planarlayer.attach(elevationlayer); - const fakeNode = { material, setBBoxZ: () => { }, addEventListener: () => { } }; - colorlayer.setupRasterNode(fakeNode); - elevationlayer.setupRasterNode(fakeNode); + tile = new TileMesh(geom, material, planarlayer, extent); + tile.parent = { material }; + + colorlayer.setupRasterNode(tile); + elevationlayer.setupRasterNode(tile); nodeLayer = material.getColorTile(colorlayer.id); nodeLayerElevation = material.getElevationTile(); @@ -124,7 +131,7 @@ describe('Provide in Sources', function () { beforeEach('reset state', function () { // clear commands array - context.scheduler.commands = []; + scheduler.commands = []; }); it('should get wmts texture with DataSourceProvider', (done) => { @@ -142,15 +149,12 @@ describe('Provide in Sources', function () { }); colorlayer.source.onLayerAdded({ out: colorlayer }); - - const tile = new TileMesh(geom, material, planarlayer, extent); material.visible = true; nodeLayer.level = EMPTY_TEXTURE_ZOOM; tile.parent = {}; - updateLayeredMaterialNodeImagery(context, colorlayer, tile, tile.parent); - updateLayeredMaterialNodeImagery(context, colorlayer, tile, tile.parent); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + colorlayer.update(context, colorlayer, tile); + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((textures) => { assert.equal(textures.length, 1); assert.equal(textures[0].isTexture, true); @@ -172,21 +176,18 @@ describe('Provide in Sources', function () { }); elevationlayer.source.onLayerAdded({ out: elevationlayer }); - const tile = new TileMesh(geom, material, planarlayer, extent, zoom); material.visible = true; nodeLayerElevation.level = EMPTY_TEXTURE_ZOOM; tile.parent = {}; - updateLayeredMaterialNodeElevation(context, elevationlayer, tile, tile.parent); - updateLayeredMaterialNodeElevation(context, elevationlayer, tile, tile.parent); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + elevationlayer.update(context, elevationlayer, tile); + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((textures) => { assert.equal(textures.length, 1); assert.equal(textures[0].isTexture, true); done(); }).catch(done); }); - it('should get wms texture with DataSourceProvider', (done) => { colorlayer.source = new WMSSource({ url: 'http://domain.com', @@ -204,12 +205,14 @@ describe('Provide in Sources', function () { const tile = new TileMesh(geom, material, planarlayer, extent, zoom); material.visible = true; + material.setColorTileIds([]); + material.removeTile(colorlayer.id); nodeLayer.level = EMPTY_TEXTURE_ZOOM; tile.parent = {}; - updateLayeredMaterialNodeImagery(context, colorlayer, tile, tile.parent); - updateLayeredMaterialNodeImagery(context, colorlayer, tile, tile.parent); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + colorlayer.update(context, colorlayer, tile); + + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((textures) => { assert.equal(textures.length, 1); assert.equal(textures[0].isTexture, true); @@ -224,15 +227,13 @@ describe('Provide in Sources', function () { tile.parent = {}; planarlayer.subdivideNode(context, tile); - TileProvider.executeCommand(context.scheduler.commands[0]) - .then((tiles) => { - assert.equal(tiles.length, 4); - assert.equal(tiles[0].extent.west, tile.extent.east * 0.5); - assert.equal(tiles[0].extent.east, tile.extent.east); - assert.equal(tiles[0].extent.north, tile.extent.north); - assert.equal(tiles[0].extent.south, tile.extent.north * 0.5); - done(); - }).catch(done); + const tiles = tile.children; + assert.equal(tiles.length, 4); + assert.equal(tiles[0].extent.west, tile.extent.east * 0.5); + assert.equal(tiles[0].extent.east, tile.extent.east); + assert.equal(tiles[0].extent.north, tile.extent.north); + assert.equal(tiles[0].extent.south, tile.extent.north * 0.5); + done(); }); it('should get 3 meshs with WFS source and DataSourceProvider', (done) => { @@ -246,7 +247,7 @@ describe('Provide in Sources', function () { featureLayer.source.onLayerAdded({ out: featureLayer }); featureLayer.update(context, featureLayer, tile); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((features) => { assert.equal(features[0].meshes.children.length, 4); done(); @@ -268,7 +269,7 @@ describe('Provide in Sources', function () { featureLayer.source._featuresCaches = {}; featureLayer.source.onLayerAdded({ out: featureLayer }); featureLayer.update(context, featureLayer, tile); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((features) => { assert.ok(features[0].meshes.children[0].isMesh); assert.ok(features[0].meshes.children[1].isPoints); @@ -290,7 +291,7 @@ describe('Provide in Sources', function () { nodeLayer.level = EMPTY_TEXTURE_ZOOM; tile.material.visible = true; featureLayer.source.uid = 22; - const colorlayerWfs = new ColorLayer('color', { + const colorlayerWfs = new ColorLayer('colorWfs', { crs: 'EPSG:3857', source: featureLayer.source, style: { @@ -308,10 +309,14 @@ describe('Provide in Sources', function () { }, }, }); + + planarlayer.attach(colorlayerWfs); + colorlayerWfs.source.onLayerAdded({ out: colorlayerWfs }); - updateLayeredMaterialNodeImagery(context, colorlayerWfs, tile, tile.parent); - updateLayeredMaterialNodeImagery(context, colorlayerWfs, tile, tile.parent); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + + colorlayerWfs.update(context, colorlayerWfs, tile); + + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((textures) => { assert.equal(textures.length, 1); assert.ok(textures[0].isTexture); @@ -335,12 +340,14 @@ describe('Provide in Sources', function () { const tile = new TileMesh(geom, new LayeredMaterial(), planarlayer, extent); tile.material.visible = true; + material.setColorTileIds([]); + material.removeTile(colorlayer.id); nodeLayer.level = EMPTY_TEXTURE_ZOOM; tile.parent = {}; - updateLayeredMaterialNodeImagery(context, colorlayer, tile, tile.parent); - updateLayeredMaterialNodeImagery(context, colorlayer, tile, tile.parent); - DataSourceProvider.executeCommand(context.scheduler.commands[0]) + colorlayer.update(context, colorlayer, tile); + + DataSourceProvider.executeCommand(scheduler.commands[0]) .then((result) => { tile.material.setColorTileIds([colorlayer.id]); tile.material.getColorTile(colorlayer.id).setTextures(result, [new THREE.Vector4()]); diff --git a/packages/Main/test/unit/demutils.js b/packages/Main/test/unit/demutils.js index f47abe2b62..a2b879ce4e 100644 --- a/packages/Main/test/unit/demutils.js +++ b/packages/Main/test/unit/demutils.js @@ -5,12 +5,9 @@ import Fetcher from 'Provider/Fetcher'; import assert from 'assert'; import GlobeView from 'Core/Prefab/GlobeView'; import { Coordinates, Extent } from '@itowns/geographic'; -import { updateLayeredMaterialNodeElevation } from 'Process/LayeredMaterialNodeProcessing'; import TileMesh from 'Core/TileMesh'; import OBB from 'Renderer/OBB'; -import LayerUpdateState from 'Layer/LayerUpdateState'; import DEMUtils from 'Utils/DEMUtils'; -import { RasterElevationTile } from 'Renderer/RasterTile'; import { LayeredMaterial } from 'Renderer/LayeredMaterial'; import * as sinon from 'sinon'; import Renderer from './bootstrap'; @@ -27,7 +24,6 @@ describe('DemUtils', function () { const viewer = new GlobeView(renderer.domElement, placement, { renderer }); let elevationlayer; - let context; let stubFetcherTextFloat; const ELEVATION = 300; @@ -50,18 +46,6 @@ describe('DemUtils', function () { }); source.url = 'https://github.com/iTowns/iTowns2-sample-data/blob/master/dem3_3_8.bil?raw=true'; elevationlayer = new ElevationLayer('worldelevation', { source }); - - context = { - camera: viewer.camera, - engine: viewer.mainLoop.gfxEngine, - scheduler: { - execute: (command) => { - const provider = viewer.mainLoop.scheduler.getProtocolProvider(command.layer.protocol); - return provider.executeCommand(command); - }, - }, - view: viewer, - }; }); after(() => { @@ -83,16 +67,16 @@ describe('DemUtils', function () { const geom = new THREE.BufferGeometry(); geom.OBB = new OBB(new THREE.Vector3(), new THREE.Vector3(1, 1, 1)); const material = new LayeredMaterial(); - const nodeLayer = new RasterElevationTile(elevationlayer); - material.getElevationTile = () => nodeLayer; const tile = new TileMesh(geom, material, viewer.tileLayer, extent, 5); - tile.layerUpdateState[elevationlayer.id] = new LayerUpdateState(); + tile.parent = {}; tiles.push(tile); - updateLayeredMaterialNodeElevation(context, elevationlayer, tile, {}) - .then(() => { - assert.equal(nodeLayer.textures[0].image.data[0], ELEVATION); - done(); - }).catch(done); + const nodeLayer = elevationlayer.setupRasterNode(tile); + + material.getElevationTile = () => nodeLayer; + nodeLayer.load(tile, viewer).then(() => { + assert.equal(nodeLayer.textures[0].image.data[0], ELEVATION); + done(); + }).catch(done); }); it('get elevation value at center with PRECISE_READ_Z', () => { diff --git a/packages/Main/test/unit/layeredmaterial.js b/packages/Main/test/unit/layeredmaterial.js index 16a1e7ef02..e441ea81fd 100644 --- a/packages/Main/test/unit/layeredmaterial.js +++ b/packages/Main/test/unit/layeredmaterial.js @@ -1,7 +1,6 @@ import assert from 'assert'; import ColorLayer from 'Layer/ColorLayer'; import TMSSource from 'Source/TMSSource'; -import { updateLayeredMaterialNodeImagery } from 'Process/LayeredMaterialNodeProcessing'; import GlobeView from 'Core/Prefab/GlobeView'; import { Coordinates } from '@itowns/geographic'; import TileMesh from 'Core/TileMesh'; @@ -50,7 +49,7 @@ describe('material state vs layer state', function () { }); it('should correctly initialize opacity & visibility', () => { - updateLayeredMaterialNodeImagery(context, layer, node, node.parent); + layer.update(context, layer, node, node.parent); const nodeLayer = material.getTile(layer.id); nodeLayer.textures.push(new THREE.Texture()); assert.equal(nodeLayer.opacity, layer.opacity); diff --git a/packages/Main/test/unit/layeredmaterialnodeprocessing.js b/packages/Main/test/unit/layeredmaterialnodeprocessing.js index 294f5fa769..eeaec56fa1 100644 --- a/packages/Main/test/unit/layeredmaterialnodeprocessing.js +++ b/packages/Main/test/unit/layeredmaterialnodeprocessing.js @@ -1,10 +1,9 @@ import * as THREE from 'three'; import assert from 'assert'; -import { updateLayeredMaterialNodeImagery } from 'Process/LayeredMaterialNodeProcessing'; import TileMesh from 'Core/TileMesh'; import { Extent } from '@itowns/geographic'; import OBB from 'Renderer/OBB'; -import Layer from 'Layer/Layer'; +import ColorLayer from 'Layer/ColorLayer'; import Source from 'Source/Source'; import { STRATEGY_MIN_NETWORK_TRAFFIC } from 'Layer/LayerUpdateStrategy'; import { RasterColorTile } from 'Renderer/RasterTile'; @@ -26,18 +25,22 @@ describe('updateLayeredMaterialNodeImagery', function () { commands: [], execute: (cmd) => { context.scheduler.commands.push(cmd); - return new Promise(() => { /* no-op */ }); + return new Promise(() => { }); }, }, }; + context.view.mainLoop = { + scheduler: context.scheduler, + }; + const source = new Source({ url: 'http://', crs: 'EPSG:4326', extent, }); - const layer = new Layer('foo', { + const layer = new ColorLayer('foo', { source, crs: 'EPSG:4326', info: { update: () => { } }, @@ -53,7 +56,11 @@ describe('updateLayeredMaterialNodeImagery', function () { ], }; - const nodeLayer = new RasterColorTile(layer); + const node = new TileMesh(geom, material, layer, extent, 0); + const tiles = node.getExtentsByProjection(layer.crs); + + const nodeLayer = new RasterColorTile(layer, tiles); + material.getTile = () => nodeLayer; beforeEach('reset state', function () { @@ -72,22 +79,21 @@ describe('updateLayeredMaterialNodeImagery', function () { source.extent = new Extent('EPSG:4326'); }); - it('hidden tile should not execute commands', () => { const tile = new TileMesh(geom, material, layer, extent, 0); material.visible = false; nodeLayer.level = 0; tile.parent = {}; - updateLayeredMaterialNodeImagery(context, layer, tile, tile.parent); + layer.update(context, layer, tile); assert.equal(context.scheduler.commands.length, 0); }); it('tile with best texture should not execute commands', () => { - const tile = new TileMesh(geom, material, layer, extent, 3); + const tile = new TileMesh(geom, material, layer, extent); material.visible = true; - nodeLayer.level = 3; + nodeLayer.state.state = 4; tile.parent = {}; - updateLayeredMaterialNodeImagery(context, layer, tile, tile.parent); + layer.update(context, layer, tile); assert.equal(context.scheduler.commands.length, 0); }); @@ -95,24 +101,22 @@ describe('updateLayeredMaterialNodeImagery', function () { const tile = new TileMesh(geom, material, layer, extent, 2); material.visible = true; nodeLayer.level = 1; + nodeLayer.state.state = 0; tile.parent = {}; - // FIRST PASS: init Node From Parent and get out of the function - // without any network fetch - updateLayeredMaterialNodeImagery(context, layer, tile, tile.parent); - assert.equal(context.scheduler.commands.length, 0); - // SECOND PASS: Fetch best texture - updateLayeredMaterialNodeImagery(context, layer, tile, tile.parent); + layer.update(context, layer, tile); assert.equal(context.scheduler.commands.length, 1); }); it('tile should not request texture with level > layer.source.zoom.max', () => { const countTexture = 2 ** 15; const newExtent = new Extent('EPSG:4326', 0, 180 / countTexture, 0, 180 / countTexture); - const tile = new TileMesh(geom, material, layer, newExtent, 15); + const tile = new TileMesh(geom, material, layer, newExtent); // Emulate a situation where tile inherited a level 1 texture material.visible = true; nodeLayer.level = 1; + nodeLayer.tiles = tile.getExtentsByProjection(layer.crs); + nodeLayer.state.state = 0; tile.parent = {}; source.isWMTSSource = true; source.tileMatrixSet = 'WGS84G'; @@ -123,11 +127,12 @@ describe('updateLayeredMaterialNodeImagery', function () { tile.material.getLayerTextures = () => [{}]; // Since layer is using STRATEGY_MIN_NETWORK_TRAFFIC, we should emit // a single command, requesting a texture at layer.source.zoom.max level - updateLayeredMaterialNodeImagery(context, layer, tile, tile.parent); - updateLayeredMaterialNodeImagery(context, layer, tile, tile.parent); + layer.update(context, layer, tile); + assert.equal(context.scheduler.commands.length, 1); assert.equal( context.scheduler.commands[0].extentsSource[0].zoom, layer.source.zoom.max); }); }); + diff --git a/packages/Main/test/unit/obb.js b/packages/Main/test/unit/obb.js index 212e0f240f..13d3f1cc29 100644 --- a/packages/Main/test/unit/obb.js +++ b/packages/Main/test/unit/obb.js @@ -53,46 +53,42 @@ function assertVerticesAreInOBB(builder, extent) { segments: 1, }; - return newTileGeometry(builder, params) - .then((result) => { - const geom = result.geometry; - const inverse = new THREE.Matrix4().copy(geom.OBB.matrix).invert(); + const { geometry } = newTileGeometry(builder, params); - let failing = 0; - const vec = new THREE.Vector3(); - for (let i = 0; i < geom.attributes.position.count; i++) { - vec.fromArray(geom.attributes.position.array, 3 * i); + const geom = geometry; + const inverse = new THREE.Matrix4().copy(geom.OBB.matrix).invert(); - vec.applyMatrix4(inverse); - if (!geom.OBB.box3D.containsPoint(vec)) { - failing++; - } - } - assert.equal(geom.attributes.position.count - failing, geom.attributes.position.count, 'All points should be inside OBB'); - }); + let failing = 0; + const vec = new THREE.Vector3(); + for (let i = 0; i < geom.attributes.position.count; i++) { + vec.fromArray(geom.attributes.position.array, 3 * i); + + vec.applyMatrix4(inverse); + if (!geom.OBB.box3D.containsPoint(vec)) { + failing++; + } + } + assert.equal(geom.attributes.position.count - failing, geom.attributes.position.count, 'All points should be inside OBB'); } describe('Planar tiles OBB computation', function () { const builder = new PlanarTileBuilder({ crs: 'EPSG:3946', uvCount: 1 }); - it('should compute OBB correctly', function (done) { + it('should compute OBB correctly', function () { const extent = new Extent('EPSG:3946', -100, 100, -50, 50); - assertVerticesAreInOBB(builder, extent) - .then(done, done); + assertVerticesAreInOBB(builder, extent); }); }); describe('Ellipsoid tiles OBB computation', function () { const builder = new GlobeTileBuilder({ uvCount: 1 }); - it('should compute globe-level 0 OBB correctly', function (done) { + it('should compute globe-level 0 OBB correctly', function () { const extent = new Extent('EPSG:4326', -180, 0, -90, 90); - assertVerticesAreInOBB(builder, extent) - .then(done, done); + assertVerticesAreInOBB(builder, extent); }); - it('should compute globe-level 2 OBB correctly', function (done) { + it('should compute globe-level 2 OBB correctly', function () { const extent = new Extent('EPSG:4326', 0, 45, -45, 0); - assertVerticesAreInOBB(builder, extent) - .then(done, done); + assertVerticesAreInOBB(builder, extent); }); }); diff --git a/packages/Main/test/unit/tiledGeometryLayer.js b/packages/Main/test/unit/tiledGeometryLayer.js index 562c74515e..264efb5bf4 100644 --- a/packages/Main/test/unit/tiledGeometryLayer.js +++ b/packages/Main/test/unit/tiledGeometryLayer.js @@ -19,11 +19,11 @@ describe('TiledGeometryLayer', function () { it('subdivide should compute a screenSize', function () { // perspective camera - viewPerspective.tileLayer.subdivision(viewPerspective, viewPerspective.tileLayer, viewPerspective.tileLayer.level0Nodes[0]); + viewPerspective.tileLayer.subdivision({ camera: viewPerspective.camera }, viewPerspective.tileLayer.level0Nodes[0]); assert.notEqual(viewPerspective.tileLayer.level0Nodes[0].screenSize, undefined); // orthographic camera - viewOrtho.tileLayer.subdivision(viewOrtho, viewOrtho.tileLayer, viewOrtho.tileLayer.level0Nodes[0]); + viewOrtho.tileLayer.subdivision({ camera: viewOrtho.camera }, viewOrtho.tileLayer.level0Nodes[0]); assert.notEqual(viewOrtho.tileLayer.level0Nodes[0].screenSize, undefined); }); diff --git a/packages/Main/test/unit/tilemesh.js b/packages/Main/test/unit/tilemesh.js index 22b684bf31..82cd63b381 100644 --- a/packages/Main/test/unit/tilemesh.js +++ b/packages/Main/test/unit/tilemesh.js @@ -1,11 +1,9 @@ import * as THREE from 'three'; import assert from 'assert'; import TileMesh from 'Core/TileMesh'; -// import PlanarView from 'Core/Prefab/PlanarView'; import PlanarLayer from 'Core/Prefab/Planar/PlanarLayer'; import Tile from 'Core/Tile/Tile'; import { globalExtentTMS } from 'Core/Tile/TileGrid'; -import TileProvider from 'Provider/TileProvider'; import { newTileGeometry } from 'Core/Prefab/TileBuilder'; import OBB from 'Renderer/OBB'; import ElevationLayer from 'Layer/ElevationLayer'; @@ -66,18 +64,13 @@ describe('TileMesh', function () { assert.equal(res, tree[1][0]); }); - it('subdivide tile by 4 tiles', function (done) { + it('subdivide tile by 4 tiles', function () { const tile = planarlayer.object3d.children[0]; planarlayer.subdivideNode(context, tile); - const command = context.scheduler.commands[0]; - TileProvider.executeCommand(command).then((tiles) => { - context.scheduler.commands = []; - assert.equal(tiles.length, 4); - done(); - }); + assert.equal(tile.children.length, 4); }); - it('Choose the right typed Array', function (done) { + it('Choose the right typed Array', function () { const paramsGeometry = { extent: planarlayer.object3d.children[0].extent, level: 0, @@ -85,10 +78,10 @@ describe('TileMesh', function () { disableSkirt: true, }; - const a = newTileGeometry(planarlayer.builder, paramsGeometry).then((r) => { - const position = r.geometry.attributes.position; - assert.ok(position.array.constructor.name == 'Float32Array'); - }); + const { geometry } = newTileGeometry(planarlayer.builder, paramsGeometry); + + const position = geometry.attributes.position; + assert.ok(position.array.constructor.name == 'Float32Array'); const paramsGeometry2 = { extent: planarlayer.object3d.children[0].extent, @@ -97,20 +90,7 @@ describe('TileMesh', function () { disableSkirt: true, }; - const b = assert.rejects(newTileGeometry(planarlayer.builder, paramsGeometry2), Error); - Promise.all([a, b]).then(() => done()); - }); - - it('catch error when subdivide tile without material', function (done) { - const tile = planarlayer.object3d.children[0]; - tile.pendingSubdivision = false; - tile.material = undefined; - planarlayer.subdivideNode(context, tile); - const command = context.scheduler.commands[0]; - TileProvider.executeCommand(command).catch((error) => { - assert.ok(error.isCancelledCommandException); - done(); - }); + assert.throws(() => newTileGeometry(planarlayer.builder, paramsGeometry2), new Error('Tile segments count is too big')); }); it('should find the correct common ancestor between two tiles of different level', function () { @@ -128,7 +108,7 @@ describe('TileMesh', function () { assert.equal(res, tree[0][0]); }); - it('Cache tile geometry', function (done) { + it('Cache tile geometry', function () { const paramsGeometry = { extent: planarlayer.object3d.children[0].extent, level: 0, @@ -136,16 +116,15 @@ describe('TileMesh', function () { disableSkirt: true, }; - newTileGeometry(planarlayer.builder, paramsGeometry).then((r) => { - r.geometry.increaseRefCount(); - return newTileGeometry(planarlayer.builder, paramsGeometry).then((r) => { - assert.equal(r.geometry.refCount, 1); - done(); - }); - }); + const { geometry } = newTileGeometry(planarlayer.builder, paramsGeometry); + geometry.increaseRefCount(); + + const r = newTileGeometry(planarlayer.builder, paramsGeometry); + + assert.equal(r.geometry.refCount, 1); }); - it('Dispose tile geometry', function (done) { + it('Dispose tile geometry', function () { const paramsGeometry = { extent: planarlayer.object3d.children[0].extent, level: 0, @@ -153,11 +132,9 @@ describe('TileMesh', function () { disableSkirt: true, }; - newTileGeometry(planarlayer.builder, paramsGeometry).then((r) => { - r.geometry.dispose(); - assert.equal(r.geometry.index, null); - done(); - }); + const { geometry } = newTileGeometry(planarlayer.builder, paramsGeometry); + geometry.dispose(); + assert.equal(geometry.index, null); }); it('throw error if there\'s not extent in constructor', () => { @@ -182,6 +159,7 @@ describe('TileMesh', function () { it('event rasterElevationLevelChanged RasterElevationTile sets TileMesh bounding box ', () => { const tileMesh = new TileMesh(geom, material, planarlayer, tile.toExtent('EPSG:3857'), 0); + tileMesh.parent = {}; const rasterNode = elevationLayer.setupRasterNode(tileMesh); const min = 50; const max = 500; @@ -201,6 +179,7 @@ describe('TileMesh', function () { it('RasterElevationTile throws error if ElevationLayer.useRgbaTextureElevation is true', () => { elevationLayer.useRgbaTextureElevation = true; const tileMesh = new TileMesh(geom, material, planarlayer, tile.toExtent('EPSG:3857'), 0); + tileMesh.parent = {}; assert.throws(() => { elevationLayer.setupRasterNode(tileMesh); }); @@ -213,6 +192,7 @@ describe('TileMesh', function () { elevationLayer.colorTextureElevationMinZ = 10; elevationLayer.colorTextureElevationMaxZ = 100; const tileMesh = new TileMesh(geom, material, planarlayer, tile.toExtent('EPSG:3857'), 0); + tileMesh.parent = {}; const rasterNode = elevationLayer.setupRasterNode(tileMesh); assert.equal(rasterNode.min, elevationLayer.colorTextureElevationMinZ); assert.equal(rasterNode.max, elevationLayer.colorTextureElevationMaxZ); @@ -221,6 +201,7 @@ describe('TileMesh', function () { it('RasterElevationTile min and max are set by xbil texture', () => { delete elevationLayer.useColorTextureElevation; const tileMesh = new TileMesh(geom, material, planarlayer, tile.toExtent('EPSG:3857'), 0); + tileMesh.parent = {}; const rasterNode = elevationLayer.setupRasterNode(tileMesh); const texture = new THREE.Texture(); texture.extent = new Tile('EPSG:3857', 4, 10, 10); diff --git a/test/functional/GlobeControls.js b/test/functional/GlobeControls.js index 1331cb4716..20db2a6c56 100644 --- a/test/functional/GlobeControls.js +++ b/test/functional/GlobeControls.js @@ -147,6 +147,7 @@ describe('GlobeControls with globe example', function _() { assert.ok(initialPosition.tilt - endTilt > 20); }); + // Doesn't work in master it('should change heading like expected', async () => { await page.evaluate(() => { view.controls.enableDamping = false; }); await page.keyboard.down('Control'); diff --git a/test/functional/view_25d_map.js b/test/functional/view_25d_map.js index 0d44ae6ec6..b0dd5a0037 100644 --- a/test/functional/view_25d_map.js +++ b/test/functional/view_25d_map.js @@ -28,7 +28,7 @@ describe('view_25d_map', function _() { }); assert.equal(displayedTiles['1'], 1); assert.equal(displayedTiles['2'], 6); - assert.equal(displayedTiles['3'], 6); + assert.equal(displayedTiles['3'], 5); }); it('should get picking position from depth', async function __() { From fd50220425c80cd218d03d8f29aa06b29a8ff0a3 Mon Sep 17 00:00:00 2001 From: Gerald Choqueux Date: Tue, 16 Jun 2026 12:29:12 +0200 Subject: [PATCH 3/4] refacto(examples): use await top level to fetch --- examples/3dtiles_loader.html | 17 +++--- examples/copc_3d_loader.html | 15 ++--- examples/effects_postprocessing.html | 18 +++--- examples/effects_split.html | 27 ++++----- examples/effects_stereo.html | 15 ++--- examples/entwine_3d_loader.html | 15 ++--- examples/geoid_geoidLayer.html | 17 +++--- examples/itowns-potree.html | 19 +++--- examples/misc_camera_animation.html | 17 +++--- examples/misc_camera_traveling.html | 15 ++--- examples/misc_clamp_ground.html | 18 +++--- examples/misc_colorlayer_visibility.html | 12 ++-- examples/misc_compare_25d_3d.html | 67 ++++++++++----------- examples/misc_custom_controls.html | 17 +++--- examples/misc_custom_label.html | 13 ++-- examples/misc_georeferenced_images.html | 15 ++--- examples/misc_geotiff.html | 19 +++--- examples/misc_instancing.html | 13 ++-- examples/plugins_drag_n_drop.html | 15 ++--- examples/plugins_pyramidal_tiff.html | 3 +- examples/plugins_vrt.html | 9 ++- examples/potree_3d_map.html | 18 +++--- examples/source_file_from_fetched_data.html | 9 ++- examples/source_file_from_format.html | 9 ++- examples/source_file_from_methods.html | 9 ++- examples/source_file_from_parsed_data.html | 9 ++- examples/source_file_geojson_3d.html | 15 ++--- examples/source_file_geojson_raster.html | 19 +++--- examples/source_file_gpx_3d.html | 15 ++--- examples/source_file_gpx_raster.html | 19 +++--- examples/source_file_kml_raster.html | 19 +++--- examples/source_file_kml_raster_usgs.html | 19 +++--- examples/source_file_shapefile.html | 9 ++- examples/source_stream_wfs_3d.html | 15 ++--- examples/source_stream_wfs_raster.html | 15 ++--- examples/vector_tile_3d_mesh.html | 19 +++--- examples/vector_tile_3d_mesh_mapbox.html | 14 ++--- examples/vector_tile_raster_3d.html | 15 ++--- examples/view_3d_map.html | 17 +++--- examples/view_3d_map_webxr.html | 17 +++--- examples/view_3d_mns_map.html | 14 ++--- examples/view_immersive.html | 12 ++-- examples/view_multiglobe.html | 18 +++--- examples/vpc_3d_loader.html | 15 ++--- examples/widgets_minimap.html | 17 +++--- examples/widgets_navigation.html | 17 +++--- examples/widgets_scale.html | 17 +++--- examples/widgets_searchbar.html | 17 +++--- 48 files changed, 395 insertions(+), 389 deletions(-) diff --git a/examples/3dtiles_loader.html b/examples/3dtiles_loader.html index 56ae5b01f1..44cb652a26 100644 --- a/examples/3dtiles_loader.html +++ b/examples/3dtiles_loader.html @@ -119,13 +119,12 @@ // Add one imagery layer to the scene. This layer's properties are // defined in a json file, but it cou ld be defined as a plain js // object. See `Layer` documentation for more info. - Fetcher.json('./layers/JSONLayers/OPENSM.json').then((config) => { - const colorLayer = new ColorLayer('Ortho', { - ...config, - source: new TMSSource(config.source), - }); - view.addLayer(colorLayer); + const openSmConfig = await Fetcher.json('./layers/JSONLayers/OPENSM.json'); + const colorLayer = new ColorLayer('Ortho', { + ...openSmConfig, + source: new TMSSource(openSmConfig.source), }); + view.addLayer(colorLayer); // ---- Add 3D terrain ---- @@ -136,8 +135,10 @@ var elevationLayer = new itowns.ElevationLayer(config.id, config); view.addLayer(elevationLayer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // ---------- 3D Tiles loading diff --git a/examples/copc_3d_loader.html b/examples/copc_3d_loader.html index d572fe86c5..b695582cd0 100644 --- a/examples/copc_3d_loader.html +++ b/examples/copc_3d_loader.html @@ -60,11 +60,10 @@ // Add one imagery layer to the scene and the miniView // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. function addElevationLayerFromConfig(config) { @@ -72,8 +71,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); var layer; diff --git a/examples/effects_postprocessing.html b/examples/effects_postprocessing.html index e2f9870ad9..ee4c976e80 100644 --- a/examples/effects_postprocessing.html +++ b/examples/effects_postprocessing.html @@ -118,16 +118,14 @@ r.render(postprocessScene, cam); }; - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ElevationLayer(config.id, config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); + const ignMntConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT.json'); + ignMntConfig.source = new itowns.WMTSSource(ignMntConfig.source); + var elevationLayer = new itowns.ElevationLayer(ignMntConfig.id, ignMntConfig); + view.addLayer(elevationLayer); window.view = view; window.itowns = itowns; window.THREE = THREE; diff --git a/examples/effects_split.html b/examples/effects_split.html index 265423e5ac..e9949fccf0 100644 --- a/examples/effects_split.html +++ b/examples/effects_split.html @@ -82,17 +82,15 @@ // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - const pOrtho = itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - orthoLayer = new itowns.ColorLayer('Ortho', config); - view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - const pOsm = itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json').then(function _(config) { - config.source = new itowns.TMSSource(config.source); - osmLayer = new itowns.ColorLayer('OSM', config); - view.addLayer(osmLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const osmConfig = await itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json'); + osmConfig.source = new itowns.TMSSource(osmConfig.source); + osmLayer = new itowns.ColorLayer('OSM', osmConfig); + view.addLayer(osmLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -101,8 +99,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // Slide handling function splitSliderMove(evt) { @@ -155,8 +155,7 @@ } // Override default rendering method when color layers are ready - Promise.all([pOrtho, pOsm]).then( - function _() { view.render = splitRendering; }).catch(console.error); + view.render = splitRendering; window.view = view; window.itowns = itowns; window.THREE = THREE; diff --git a/examples/effects_stereo.html b/examples/effects_stereo.html index ffed5d9d09..2a825375d1 100644 --- a/examples/effects_stereo.html +++ b/examples/effects_stereo.html @@ -78,11 +78,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - const source = new itowns.WMTSSource(config.source); - const layer = new itowns.ColorLayer(config.id, { source }); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + const orthoSource = new itowns.WMTSSource(orthoConfig.source); + const orthoLayer = new itowns.ColorLayer(orthoConfig.id, { source: orthoSource }); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. function addElevationLayerFromConfig(config) { @@ -90,8 +89,10 @@ const layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); /* eslint-disable no-unused-vars */ function updateEyeSep(value) { diff --git a/examples/entwine_3d_loader.html b/examples/entwine_3d_loader.html index 27e155f23f..a392729089 100644 --- a/examples/entwine_3d_loader.html +++ b/examples/entwine_3d_loader.html @@ -61,11 +61,10 @@ // Add one imagery layer to the scene and the miniView // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -74,8 +73,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // Check if an url had been given as an argument // and parse to get url and options. diff --git a/examples/geoid_geoidLayer.html b/examples/geoid_geoidLayer.html index 5e3295f507..952e6109ef 100644 --- a/examples/geoid_geoidLayer.html +++ b/examples/geoid_geoidLayer.html @@ -62,12 +62,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('layers/JSONLayers/Ortho.json').then((config) => { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer(config.id, config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer(orthoConfig.id, orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); // Add two elevaion layers, each with a different level of detail. Here again, each layer's properties are // defined in a json file. @@ -77,8 +76,10 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); diff --git a/examples/itowns-potree.html b/examples/itowns-potree.html index 3d9cbdcf02..5b59e82bc4 100644 --- a/examples/itowns-potree.html +++ b/examples/itowns-potree.html @@ -195,13 +195,12 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - config.source.zoom = { max: 19, min: 3 }; - itownsViewer.addLayer( - new itowns.ColorLayer(config.id, config), - ); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + orthoConfig.source.zoom = { max: 19, min: 3 }; + itownsViewer.addLayer( + new itowns.ColorLayer(orthoConfig.id, orthoConfig), + ); // Add two elevaion layers, each with a different level of detail. Here again, each layer's properties are // defined in a json file. @@ -211,8 +210,10 @@ new itowns.ElevationLayer(config.id, config), ); } - itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); diff --git a/examples/misc_camera_animation.html b/examples/misc_camera_animation.html index e400c16869..2e08866f85 100644 --- a/examples/misc_camera_animation.html +++ b/examples/misc_camera_animation.html @@ -57,12 +57,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer('Ortho', config), - ); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer('Ortho', orthoConfig), + ); @@ -76,8 +75,10 @@ new itowns.ElevationLayer(config.id, config), ); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); diff --git a/examples/misc_camera_traveling.html b/examples/misc_camera_traveling.html index 0434fe5643..d4ffe9f1a5 100644 --- a/examples/misc_camera_traveling.html +++ b/examples/misc_camera_traveling.html @@ -71,11 +71,10 @@ // Add one imagery layer to the scene and the miniView. // This layer is defined in a json file but it could be defined as a plain js // object. See Layer for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - const orthoLayer = new itowns.ColorLayer('Ortho', config); - view.addLayer(orthoLayer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + const orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -84,8 +83,10 @@ let layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // ---------- Select camera positions and travel through these positions : ---------- diff --git a/examples/misc_clamp_ground.html b/examples/misc_clamp_ground.html index 583bf27a31..234a3b29c2 100644 --- a/examples/misc_clamp_ground.html +++ b/examples/misc_clamp_ground.html @@ -55,11 +55,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. function addElevationLayerFromConfig(config) { @@ -69,8 +68,10 @@ return layer; } - const p = itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); function addMeshToScene() { @@ -103,7 +104,8 @@ } // Listen for globe full initialisation event - p.then((layer) => { + view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function init() { + console.log('GLOBE_INITIALIZED'); addMeshToScene(); }); window.view = view; diff --git a/examples/misc_colorlayer_visibility.html b/examples/misc_colorlayer_visibility.html index dbbc622333..54400c84f0 100644 --- a/examples/misc_colorlayer_visibility.html +++ b/examples/misc_colorlayer_visibility.html @@ -57,10 +57,14 @@ view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(addColorLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/Cada.json').then(addColorLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + addColorLayerFromConfig(orthoConfig); + const cadaConfig = await itowns.Fetcher.json('./layers/JSONLayers/Cada.json'); + addColorLayerFromConfig(cadaConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function _() { // eslint-disable-next-line no-console diff --git a/examples/misc_compare_25d_3d.html b/examples/misc_compare_25d_3d.html index d102d5bdd0..925c3624aa 100644 --- a/examples/misc_compare_25d_3d.html +++ b/examples/misc_compare_25d_3d.html @@ -104,11 +104,10 @@ overGlobe = false; }, false); - promises.push(itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer(config.id, config); - view.addLayer(layer); - })); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer(orthoConfig.id, orthoConfig); + view.addLayer(orthoLayer); // Listen for globe full initialisation event view @@ -116,38 +115,36 @@ function globeInitialized() { // eslint-disable-next-line no-console console.info('Globe initialized'); - Promise.all(promises).then(function init() { - var planarCamera = planarView.camera3D; - var globeCamera = view.camera3D; - var params; - menuGlobe.addImageryLayersGUI(view.getLayers(function filterColor(l) { return l.isColorLayer; })); - menuGlobe.addElevationLayersGUI(view.getLayers(function filterElevation(l) { return l.isElevationLayer; })); - - function sync() { - if (overGlobe) { - params = itowns.CameraUtils - .getTransformCameraLookingAtTarget( - view, globeCamera); - itowns.CameraUtils + var planarCamera = planarView.camera3D; + var globeCamera = view.camera3D; + var params; + menuGlobe.addImageryLayersGUI(view.getLayers(function filterColor(l) { return l.isColorLayer; })); + menuGlobe.addElevationLayersGUI(view.getLayers(function filterElevation(l) { return l.isElevationLayer; })); + + function sync() { + if (overGlobe) { + params = itowns.CameraUtils + .getTransformCameraLookingAtTarget( + view, globeCamera); + itowns.CameraUtils + .transformCameraToLookAtTarget( + planarView, planarCamera, params); + } else { + params = itowns.CameraUtils + .getTransformCameraLookingAtTarget( + planarView, planarCamera); + itowns.CameraUtils .transformCameraToLookAtTarget( - planarView, planarCamera, params); - } else { - params = itowns.CameraUtils - .getTransformCameraLookingAtTarget( - planarView, planarCamera); - itowns.CameraUtils - .transformCameraToLookAtTarget( - view, globeCamera, params); - } + view, globeCamera, params); } - sync(); - view - .addFrameRequester(itowns - .MAIN_LOOP_EVENTS.AFTER_CAMERA_UPDATE, sync); - planarView - .addFrameRequester(itowns - .MAIN_LOOP_EVENTS.AFTER_CAMERA_UPDATE, sync); - }).catch(console.error); + } + sync(); + view + .addFrameRequester(itowns + .MAIN_LOOP_EVENTS.AFTER_CAMERA_UPDATE, sync); + planarView + .addFrameRequester(itowns + .MAIN_LOOP_EVENTS.AFTER_CAMERA_UPDATE, sync); }); var wmsImagerySource = new itowns.WMSSource({ diff --git a/examples/misc_custom_controls.html b/examples/misc_custom_controls.html index 5a482877fe..847c9dadb9 100644 --- a/examples/misc_custom_controls.html +++ b/examples/misc_custom_controls.html @@ -57,20 +57,21 @@ setupLoadingScreen(viewerDiv, view); // Add imagery and elevation layers - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function (config) { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer('Ortho', config), - ); - }) + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer('Ortho', orthoConfig), + ); function addElevationLayerFromConfig(config) { config.source = new itowns.WMTSSource(config.source); view.addLayer( new itowns.ElevationLayer(config.id, config), ); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); const customControls = { // Disable pan movement diff --git a/examples/misc_custom_label.html b/examples/misc_custom_label.html index e410f03e54..fca04b7e80 100644 --- a/examples/misc_custom_label.html +++ b/examples/misc_custom_label.html @@ -62,16 +62,17 @@ const viewerDiv = document.getElementById('viewerDiv'); const view = new itowns.GlobeView(viewerDiv, placement); var menuGlobe = new GuiTools('menuDiv', view); - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - view.addLayer(new itowns.ColorLayer('Ortho', config)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer(new itowns.ColorLayer('Ortho', orthoConfig)); function addElevationLayerFromConfig(config) { config.source = new itowns.WMTSSource(config.source); view.addLayer(new itowns.ElevationLayer(config.id, config)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); debug.createTileDebugUI(menuGlobe.gui, view); // Create a custom div which will be displayed as a label diff --git a/examples/misc_georeferenced_images.html b/examples/misc_georeferenced_images.html index 8ba0b95422..4b097f1c83 100644 --- a/examples/misc_georeferenced_images.html +++ b/examples/misc_georeferenced_images.html @@ -78,11 +78,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -91,8 +90,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); pictureInfos = { panoramic: { diff --git a/examples/misc_geotiff.html b/examples/misc_geotiff.html index 53bd43dd3d..2db3bb29e0 100644 --- a/examples/misc_geotiff.html +++ b/examples/misc_geotiff.html @@ -57,16 +57,15 @@ // ---------- DISPLAY ORTHO IMAGES: ---------- - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then((config) => { - const colorLayer = new itowns.ColorLayer( - 'Ortho', - { - ...config, - source: new itowns.WMTSSource(config.source), - }, - ); - view.addLayer(colorLayer).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + const colorLayer = new itowns.ColorLayer( + 'Ortho', + { + ...orthoConfig, + source: new itowns.WMTSSource(orthoConfig.source), + }, + ); + view.addLayer(colorLayer).then(debugMenu.addLayerGUI.bind(debugMenu)); diff --git a/examples/misc_instancing.html b/examples/misc_instancing.html index 7fec14f906..dcc3cdbcb6 100644 --- a/examples/misc_instancing.html +++ b/examples/misc_instancing.html @@ -62,14 +62,11 @@ view.scene.add(ambLight); // Add one imagery layer to the scene - itowns.Fetcher.json("./layers/JSONLayers/Ortho.json").then( - function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer("Ortho", config); - view.addLayer(layer).then( - debugMenu.addLayerGUI.bind(debugMenu) - ); - } + const orthoConfig = await itowns.Fetcher.json("./layers/JSONLayers/Ortho.json"); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer("Ortho", orthoConfig); + view.addLayer(orthoLayer).then( + debugMenu.addLayerGUI.bind(debugMenu) ); //Tree diff --git a/examples/plugins_drag_n_drop.html b/examples/plugins_drag_n_drop.html index 17afe43b06..16faa5fe27 100644 --- a/examples/plugins_drag_n_drop.html +++ b/examples/plugins_drag_n_drop.html @@ -58,11 +58,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -71,8 +70,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); DragNDrop.setView(view); DragNDrop.register('geojson', DragNDrop.JSON, itowns.GeoJsonParser.parse, DragNDrop.COLOR); diff --git a/examples/plugins_pyramidal_tiff.html b/examples/plugins_pyramidal_tiff.html index 5a0a39f980..5f5ac9155a 100644 --- a/examples/plugins_pyramidal_tiff.html +++ b/examples/plugins_pyramidal_tiff.html @@ -80,7 +80,8 @@ menuGlobe.elevationGui.__folders.GEOIDMNT.open(); }); } - itowns.Fetcher.json('./layers/JSONLayers/GeoidMNT.json').then(addElevationLayerFromConfig); + const geoidMntConfig = await itowns.Fetcher.json('./layers/JSONLayers/GeoidMNT.json'); + addElevationLayerFromConfig(geoidMntConfig); const d = new debug.Debug(view, menuGlobe.gui); debug.createTileDebugUI(menuGlobe.gui, view, view.tileLayer, d); diff --git a/examples/plugins_vrt.html b/examples/plugins_vrt.html index 196763996d..8dfd82e61c 100644 --- a/examples/plugins_vrt.html +++ b/examples/plugins_vrt.html @@ -58,11 +58,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json').then(function _(config) { - config.source = new itowns.TMSSource(config.source); - var layer = new itowns.ColorLayer('OPENSM', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const openSmConfig = await itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json'); + openSmConfig.source = new itowns.TMSSource(openSmConfig.source); + var openSmLayer = new itowns.ColorLayer('OPENSM', openSmConfig); + view.addLayer(openSmLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // In this case, a VRT is associated to a CSV itowns.Fetcher.multiple('https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/vrt/velib-disponibilite-en-temps-reel', { diff --git a/examples/potree_3d_map.html b/examples/potree_3d_map.html index 9971dce5af..8b2534aeeb 100644 --- a/examples/potree_3d_map.html +++ b/examples/potree_3d_map.html @@ -71,16 +71,14 @@ view.controls.minDistance = 50; - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ElevationLayer(config.id, config); - view.addLayer(layer); - }); - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer(config.id, config); - view.addLayer(layer); - }); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + ignMntHighResConfig.source = new itowns.WMTSSource(ignMntHighResConfig.source); + var elevationLayer = new itowns.ElevationLayer(ignMntHighResConfig.id, ignMntHighResConfig); + view.addLayer(elevationLayer); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer(orthoConfig.id, orthoConfig); + view.addLayer(orthoLayer); /* OTHER dataset Donnees geocentrique -> probleme pour le placement camera diff --git a/examples/source_file_from_fetched_data.html b/examples/source_file_from_fetched_data.html index 54f91d5fc2..25bc863cd7 100644 --- a/examples/source_file_from_fetched_data.html +++ b/examples/source_file_from_fetched_data.html @@ -62,11 +62,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(debugMenu.addLayerGUI.bind(debugMenu)); diff --git a/examples/source_file_from_format.html b/examples/source_file_from_format.html index 1fbc9890c5..2d635ff534 100644 --- a/examples/source_file_from_format.html +++ b/examples/source_file_from_format.html @@ -60,11 +60,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(debugMenu.addLayerGUI.bind(debugMenu)); diff --git a/examples/source_file_from_methods.html b/examples/source_file_from_methods.html index 34026a0952..387c259c85 100644 --- a/examples/source_file_from_methods.html +++ b/examples/source_file_from_methods.html @@ -60,11 +60,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(debugMenu.addLayerGUI.bind(debugMenu)); diff --git a/examples/source_file_from_parsed_data.html b/examples/source_file_from_parsed_data.html index 9dab6c5776..fd6d766838 100644 --- a/examples/source_file_from_parsed_data.html +++ b/examples/source_file_from_parsed_data.html @@ -61,11 +61,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(debugMenu.addLayerGUI.bind(debugMenu)); diff --git a/examples/source_file_geojson_3d.html b/examples/source_file_geojson_3d.html index 3400159bbd..0aed91a132 100644 --- a/examples/source_file_geojson_3d.html +++ b/examples/source_file_geojson_3d.html @@ -48,11 +48,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -61,8 +60,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // Add a geometry layer, which will contain the multipolygon to display var marne = new itowns.FeatureGeometryLayer('Marne', { diff --git a/examples/source_file_geojson_raster.html b/examples/source_file_geojson_raster.html index fd93807314..97137844c3 100644 --- a/examples/source_file_geojson_raster.html +++ b/examples/source_file_geojson_raster.html @@ -58,13 +58,12 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(function _() { - menuGlobe.addLayerGUI.bind(menuGlobe); - itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(function _() { + menuGlobe.addLayerGUI.bind(menuGlobe); + itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); }); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -73,8 +72,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // Display the content of two GeoJSON files on terrain with ColorLayer and FileSource. diff --git a/examples/source_file_gpx_3d.html b/examples/source_file_gpx_3d.html index 86c2e9a6b7..57b0c0424a 100644 --- a/examples/source_file_gpx_3d.html +++ b/examples/source_file_gpx_3d.html @@ -52,11 +52,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. function addElevationLayerFromConfig(config) { @@ -64,8 +63,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // update the waypoint var distance, scale, point = new THREE.Vector3(); diff --git a/examples/source_file_gpx_raster.html b/examples/source_file_gpx_raster.html index 3ef62fa8dd..5772d5ca37 100644 --- a/examples/source_file_gpx_raster.html +++ b/examples/source_file_gpx_raster.html @@ -55,13 +55,12 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(function _() { - menuGlobe.addLayerGUI.bind(menuGlobe); - itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(function _() { + menuGlobe.addLayerGUI.bind(menuGlobe); + itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); }); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -70,8 +69,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); const gpxSource = new itowns.FileSource({ diff --git a/examples/source_file_kml_raster.html b/examples/source_file_kml_raster.html index 832d591a5f..6ac82cf2a8 100644 --- a/examples/source_file_kml_raster.html +++ b/examples/source_file_kml_raster.html @@ -57,13 +57,12 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(function _() { - menuGlobe.addLayerGUI.bind(menuGlobe); - itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(function _() { + menuGlobe.addLayerGUI.bind(menuGlobe); + itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); }); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -72,8 +71,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // Fetch, Parse and Convert by iTowns var kmlSource = new itowns.FileSource({ diff --git a/examples/source_file_kml_raster_usgs.html b/examples/source_file_kml_raster_usgs.html index dfcbb663ce..37fc022576 100644 --- a/examples/source_file_kml_raster_usgs.html +++ b/examples/source_file_kml_raster_usgs.html @@ -54,13 +54,12 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(function _() { - menuGlobe.addLayerGUI.bind(menuGlobe); - itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(function _() { + menuGlobe.addLayerGUI.bind(menuGlobe); + itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); }); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -69,8 +68,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); // Fetch, Parse and Convert by iTowns var kmlSource = new itowns.FileSource({ diff --git a/examples/source_file_shapefile.html b/examples/source_file_shapefile.html index bb5745cd3b..f8fb8efe43 100644 --- a/examples/source_file_shapefile.html +++ b/examples/source_file_shapefile.html @@ -54,11 +54,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json').then(function _(config) { - config.source = new itowns.TMSSource(config.source); - var layer = new itowns.ColorLayer('OPENSM', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const openSmConfig = await itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json'); + openSmConfig.source = new itowns.TMSSource(openSmConfig.source); + var openSmLayer = new itowns.ColorLayer('OPENSM', openSmConfig); + view.addLayer(openSmLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); diff --git a/examples/source_stream_wfs_3d.html b/examples/source_stream_wfs_3d.html index 0682ef1891..4bbbac59e0 100644 --- a/examples/source_stream_wfs_3d.html +++ b/examples/source_stream_wfs_3d.html @@ -69,11 +69,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -82,8 +81,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); var color = new THREE.Color(); var tile; diff --git a/examples/source_stream_wfs_raster.html b/examples/source_stream_wfs_raster.html index ae89cca030..a3bae45f6a 100644 --- a/examples/source_stream_wfs_raster.html +++ b/examples/source_stream_wfs_raster.html @@ -56,11 +56,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -69,8 +68,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); var wfsBuildingSource = new itowns.WFSSource({ url: 'https://data.geopf.fr/wfs/ows?', diff --git a/examples/vector_tile_3d_mesh.html b/examples/vector_tile_3d_mesh.html index c2cabd2a33..28f7f9b964 100644 --- a/examples/vector_tile_3d_mesh.html +++ b/examples/vector_tile_3d_mesh.html @@ -73,16 +73,17 @@ view.addLayer(new itowns.ElevationLayer(config.id, config)) .then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // ---------- DISPLAY ORTHO-IMAGES : ---------- - const ortho = itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - return view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // ---------- DISPLAY VECTOR TILED MAP DATA AS A ColorLayer : ---------- @@ -158,9 +159,7 @@ debug.createTileDebugUI(debugMenu.gui, view); view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function () { - ortho.then(function () { - itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); - }).catch(console.error); + itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); }); window.view = view; diff --git a/examples/vector_tile_3d_mesh_mapbox.html b/examples/vector_tile_3d_mesh_mapbox.html index 6500d85674..74391dee9b 100644 --- a/examples/vector_tile_3d_mesh_mapbox.html +++ b/examples/vector_tile_3d_mesh_mapbox.html @@ -80,12 +80,10 @@ // Add one imagery layer to the scene. This layer's properties are // defined in a json file, but it could be defined as a plain js // object. See `Layer` documentation for more info. - const ortho = itowns.Fetcher.json('./layers/JSONLayers/Ortho.json') - .then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - return view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add an elevation layer, whose properties are defined in a json // file. @@ -94,8 +92,8 @@ view.addLayer(new itowns.ElevationLayer(config.id, config)) .then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json') - .then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); diff --git a/examples/vector_tile_raster_3d.html b/examples/vector_tile_raster_3d.html index f046d81129..58df7fce4f 100644 --- a/examples/vector_tile_raster_3d.html +++ b/examples/vector_tile_raster_3d.html @@ -55,11 +55,10 @@ setupLoadingScreen(viewerDiv, view); - promises.push(itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - return view.addLayer(layer); - })); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Define a VectorTilesSource to load Vector Tiles data from the geoportail var mvtSource = new itowns.VectorTilesSource({ @@ -80,10 +79,8 @@ var menuGlobe = new GuiTools('menuDiv', view, 300); // Listen for globe full initialisation event view.addEventListener(itowns.GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, function () { - Promise.all(promises).then(function () { - menuGlobe.addImageryLayersGUI(view.getLayers(function (l) { return l.isColorLayer; })); - itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); - }).catch(console.error); + menuGlobe.addImageryLayersGUI(view.getLayers(function (l) { return l.isColorLayer; })); + itowns.ColorLayersOrdering.moveLayerToIndex(view, 'Ortho', 0); }); debug.createTileDebugUI(menuGlobe.gui, view); diff --git a/examples/view_3d_map.html b/examples/view_3d_map.html index 5a5b99544c..e9aa185f78 100644 --- a/examples/view_3d_map.html +++ b/examples/view_3d_map.html @@ -62,12 +62,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer('Ortho', config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer('Ortho', orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); @@ -81,8 +80,10 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); // ---------- ADD SOME WIDGETS : ---------- diff --git a/examples/view_3d_map_webxr.html b/examples/view_3d_map_webxr.html index 9de40fe104..aa4fd20ebc 100644 --- a/examples/view_3d_map_webxr.html +++ b/examples/view_3d_map_webxr.html @@ -73,11 +73,10 @@ // Add one imagery layer to the scene. This layer's properties are // defined in a json file, but it could be defined as a plain js // object. See `Layer` documentation for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then((config) => { - config.source = new itowns.WMTSSource(config.source); - view.addLayer(new itowns.ColorLayer('Ortho', config), - ); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer(new itowns.ColorLayer('Ortho', orthoConfig), + ); // ---------- DISPLAY A DIGITAL ELEVATION MODEL : ---------- @@ -89,10 +88,10 @@ new itowns.ElevationLayer(config.id, config), ); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json') - .then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json') - .then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); window.view = view; window.itowns = itowns; window.THREE = THREE; diff --git a/examples/view_3d_mns_map.html b/examples/view_3d_mns_map.html index aaae1fe583..089538f17d 100644 --- a/examples/view_3d_mns_map.html +++ b/examples/view_3d_mns_map.html @@ -69,12 +69,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer('Ortho', config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer('Ortho', orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); // ---------- DISPLAY A DIGITAL ELEVATION MODEL : ---------- @@ -87,7 +86,8 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNS_HIGHRES.json').then(addElevationLayerFromConfig); + const ignMnsHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNS_HIGHRES.json'); + addElevationLayerFromConfig(ignMnsHighResConfig); // ---------- ADD SOME WIDGETS : ---------- diff --git a/examples/view_immersive.html b/examples/view_immersive.html index f9cd1a0d33..4e632f054c 100644 --- a/examples/view_immersive.html +++ b/examples/view_immersive.html @@ -78,11 +78,10 @@ // Add one imagery layer to the scene // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -91,7 +90,8 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe)); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); function altitudeBuildings(properties) { // I set altitude building 3 meters down, to be sure building is anchored in the ground diff --git a/examples/view_multiglobe.html b/examples/view_multiglobe.html index c48ea60b38..de3fe44d86 100644 --- a/examples/view_multiglobe.html +++ b/examples/view_multiglobe.html @@ -71,11 +71,10 @@ setupLoadingScreen(viewerDiv, view); object3ds.push(object3d); - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Create a second smaller globe object3d = new THREE.Object3D(); @@ -90,11 +89,10 @@ // add globe2 to the view so it gets updated itowns.View.prototype.addLayer.call(view, globe2); - itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json').then(function _(osm) { - osm.source = new itowns.TMSSource(osm.source); - var layer = new itowns.ColorLayer(osm.id, osm); - itowns.View.prototype.addLayer.call(view, layer, globe2); - }); + const openSmConfig = await itowns.Fetcher.json('./layers/JSONLayers/OPENSM.json'); + openSmConfig.source = new itowns.TMSSource(openSmConfig.source); + var globe2Layer = new itowns.ColorLayer(openSmConfig.id, openSmConfig); + itowns.View.prototype.addLayer.call(view, globe2Layer, globe2); // Globe animation // Exchange postion and scale of globes in a 1 second animation diff --git a/examples/vpc_3d_loader.html b/examples/vpc_3d_loader.html index 50f050403b..d6fb919c9b 100644 --- a/examples/vpc_3d_loader.html +++ b/examples/vpc_3d_loader.html @@ -57,11 +57,10 @@ // Add one imagery layer to the scene and the miniView // This layer is defined in a json file but it could be defined as a plain js // object. See Layer* for more info. - itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) { - config.source = new itowns.WMTSSource(config.source); - var layer = new itowns.ColorLayer('Ortho', config); - view.addLayer(layer); - }); + const orthoConfig = await itowns.Fetcher.json('./layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + var orthoLayer = new itowns.ColorLayer('Ortho', orthoConfig); + view.addLayer(orthoLayer); // Add two elevation layers. // These will deform iTowns globe geometry to represent terrain elevation. @@ -70,8 +69,10 @@ var layer = new itowns.ElevationLayer(config.id, config); view.addLayer(layer); } - itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); const url = 'https://data.geopf.fr/chunk/telechargement/download/lidarhd_fxx_ept/vpc/index.vpc'; loadVPC(url); diff --git a/examples/widgets_minimap.html b/examples/widgets_minimap.html index d3f1b0ed06..17098de115 100644 --- a/examples/widgets_minimap.html +++ b/examples/widgets_minimap.html @@ -76,12 +76,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('layers/JSONLayers/Ortho.json').then((config) => { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer(config.id, config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer(orthoConfig.id, orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); // Add two elevation layers, each with a different level of detail. Here again, each layer's properties are // defined in a json file. @@ -91,8 +90,10 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); diff --git a/examples/widgets_navigation.html b/examples/widgets_navigation.html index efd37ae108..3d3a57cd51 100644 --- a/examples/widgets_navigation.html +++ b/examples/widgets_navigation.html @@ -67,12 +67,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('layers/JSONLayers/Ortho.json').then((config) => { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer(config.id, config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer(orthoConfig.id, orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); // Add two elevation layers, each with a different level of detail. Here again, each layer's properties are // defined in a json file. @@ -82,8 +81,10 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); diff --git a/examples/widgets_scale.html b/examples/widgets_scale.html index 68d0ccb075..216657bb5b 100644 --- a/examples/widgets_scale.html +++ b/examples/widgets_scale.html @@ -68,12 +68,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('layers/JSONLayers/Ortho.json').then((config) => { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer(config.id, config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer(orthoConfig.id, orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); // Add two elevation layers, each with a different level of detail. Here again, each layer's properties are // defined in a json file. @@ -83,8 +82,10 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); diff --git a/examples/widgets_searchbar.html b/examples/widgets_searchbar.html index 9d3063ac1d..1ba137d8c4 100644 --- a/examples/widgets_searchbar.html +++ b/examples/widgets_searchbar.html @@ -66,12 +66,11 @@ // Add one imagery layer to the scene. This layer's properties are defined in a json file, but it could be // defined as a plain js object. See `Layer` documentation for more info. - itowns.Fetcher.json('layers/JSONLayers/Ortho.json').then((config) => { - config.source = new itowns.WMTSSource(config.source); - view.addLayer( - new itowns.ColorLayer(config.id, config), - ).then(debugMenu.addLayerGUI.bind(debugMenu)); - }); + const orthoConfig = await itowns.Fetcher.json('layers/JSONLayers/Ortho.json'); + orthoConfig.source = new itowns.WMTSSource(orthoConfig.source); + view.addLayer( + new itowns.ColorLayer(orthoConfig.id, orthoConfig), + ).then(debugMenu.addLayerGUI.bind(debugMenu)); // Add two elevation layers, each with a different level of detail. Here again, each layer's properties are // defined in a json file. @@ -81,8 +80,10 @@ new itowns.ElevationLayer(config.id, config), ).then(debugMenu.addLayerGUI.bind(debugMenu)); } - itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig); - itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig); + const ignMntHighResConfig = await itowns.Fetcher.json('layers/JSONLayers/IGN_MNT_HIGHRES.json'); + addElevationLayerFromConfig(ignMntHighResConfig); + const worldDtmConfig = await itowns.Fetcher.json('layers/JSONLayers/WORLD_DTM.json'); + addElevationLayerFromConfig(worldDtmConfig); From f49e3f36991fe067e6965d3a6a5385d58b2c74c3 Mon Sep 17 00:00:00 2001 From: gchoqueux Date: Tue, 16 Jun 2026 17:49:48 +0200 Subject: [PATCH 4/4] fix(TiledGeometryLayer): [WIP][PROPOSAL] avoid to subdivide node mesh if raster tiles aren't loaded --- packages/Main/src/Layer/TiledGeometryLayer.js | 14 ++++++++++---- packages/Main/src/Renderer/LayeredMaterial.ts | 12 ++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/Main/src/Layer/TiledGeometryLayer.js b/packages/Main/src/Layer/TiledGeometryLayer.js index 53036be708..d481fc63f5 100644 --- a/packages/Main/src/Layer/TiledGeometryLayer.js +++ b/packages/Main/src/Layer/TiledGeometryLayer.js @@ -405,15 +405,21 @@ class TiledGeometryLayer extends GeometryLayer { if (this.maxSubdivisionLevel <= node.level) { return false; } + + // avoid subdision if tile + if (!node.material.dataHasLoaded()) { + return false; + } + + const camera3D = context.camera.camera3D; + subdivisionVector.setFromMatrixScale(node.matrixWorld); boundingSphereCenter.copy(node.boundingSphere.center).applyMatrix4(node.matrixWorld); const distance = Math.max( - 0.0, - context.camera.camera3D.position.distanceTo(boundingSphereCenter) - node.boundingSphere.radius * subdivisionVector.x); + 0.0, camera3D.position.distanceTo(boundingSphereCenter) - node.boundingSphere.radius * subdivisionVector.x); // Size projection on pixel of bounding - if (context.camera.camera3D.isOrthographicCamera) { - const camera3D = context.camera.camera3D; + if (camera3D.isOrthographicCamera) { const preSSE = context.camera._preSSE * 2 * camera3D.zoom / (camera3D.top - camera3D.bottom); node.screenSize = preSSE * node.boundingSphere.radius * subdivisionVector.x; } else { diff --git a/packages/Main/src/Renderer/LayeredMaterial.ts b/packages/Main/src/Renderer/LayeredMaterial.ts index 081373cad8..d64cc8673f 100644 --- a/packages/Main/src/Renderer/LayeredMaterial.ts +++ b/packages/Main/src/Renderer/LayeredMaterial.ts @@ -626,6 +626,18 @@ export class LayeredMaterial extends THREE.ShaderMaterial { ? this.elevationTile : this.colorTiles.find(l => l.id === id); } + public colorDataHasLoaded() { + return this.colorTiles.length == 0 || !this.colorTiles.some(colorTile => !colorTile.hasData()); + } + + public elevationDataHasLoaded() { + return !this.elevationTile || this.elevationTile.hasData(); + } + + public dataHasLoaded() { + return this.colorDataHasLoaded() && this.elevationDataHasLoaded(); + } + public getTiles(ids: string[]): RasterTile[] { // NOTE: this could instead be a mapping with an undefined in place of // unfound IDs. Need to identify a use case for it though as it would