diff --git a/src/Core/Layer/Layer.js b/src/Core/Layer/Layer.js deleted file mode 100644 index f6ae6a233a..0000000000 --- a/src/Core/Layer/Layer.js +++ /dev/null @@ -1,182 +0,0 @@ -import { EventDispatcher } from 'three'; -import Picking from '../Picking'; - -/** - * Fires when layer sequence change (meaning when the order of the layer changes in the view) - * @event Layer#sequence-property-changed - * @property new {object} - * @property new.sequence {number} the new value of the layer sequence - * @property previous {object} - * @property previous.sequence {number} the previous value of the layer sequence - * @property target {Layer} dispatched on layer - * @property type {string} sequence-property-changed -*/ -/** - * Fires when layer opacity change - * @event Layer#opacity-property-changed - * @property new {object} - * @property new.opacity {object} the new value of the layer opacity - * @property previous {object} - * @property previous.opacity {object} the previous value of the layer opacity - * @property target {Layer} dispatched on layer - * @property type {string} opacity-property-changed -*/ -/** - * Fires when layer visibility change - * @event Layer#visible-property-changed - * @property new {object} - * @property new.visible {object} the new value of the layer visibility - * @property previous {object} - * @property previous.visible {object} the previous value of the layer visibility - * @property target {Layer} dispatched on layer - * @property type {string} visible-property-changed -*/ - -export const defineLayerProperty = function defineLayerProperty(layer, propertyName, defaultValue, onChange) { - const existing = Object.getOwnPropertyDescriptor(layer, propertyName); - if (!existing || !existing.set) { - var property = layer[propertyName] == undefined ? defaultValue : layer[propertyName]; - Object.defineProperty(layer, - propertyName, - { get: () => property, - set: (newValue) => { - if (property !== newValue) { - const event = { type: `${propertyName}-property-changed`, previous: {}, new: {} }; - event.previous[propertyName] = property; - event.new[propertyName] = newValue; - property = newValue; - if (onChange) { - onChange(layer, propertyName); - } - layer.dispatchEvent(event); - } - } }); - } -}; - -function GeometryLayer(id, object3d) { - if (!id) { - throw new Error('Missing id parameter (GeometryLayer must have a unique id defined)'); - } - if (!object3d || !object3d.isObject3D) { - throw new Error('Missing/Invalid object3d parameter (must be a three.js Object3D instance)'); - } - this._attachedLayers = []; - - if (object3d && object3d.type === 'Group' && object3d.name === '') { - object3d.name = id; - } - - Object.defineProperty(this, 'object3d', { - value: object3d, - writable: false, - }); - - Object.defineProperty(this, 'id', { - value: id, - writable: false, - }); - - // Setup default picking method - this.pickObjectsAt = (view, mouse, radius) => Picking.pickObjectsAt(view, mouse, radius, this.object3d); - - this.postUpdate = () => {}; -} - -GeometryLayer.prototype = Object.create(EventDispatcher.prototype); -GeometryLayer.prototype.constructor = GeometryLayer; - -GeometryLayer.prototype.attach = function attach(layer) { - if (!layer.update) { - throw new Error(`Missing 'update' function -> can't attach layer ${layer.id}`); - } - this._attachedLayers.push(layer); -}; - -GeometryLayer.prototype.detach = function detach(layer) { - const count = this._attachedLayers.length; - this._attachedLayers = this._attachedLayers.filter(attached => attached.id != layer.id); - return this._attachedLayers.length < count; -}; - -/** - * Don't use directly constructor to instance a new Layer - * use addLayer in {@link View} - * @example - * // add and create a new Layer - * const newLayer = view.addLayer({options}); - * - * // Change layer's visibilty - * const layerToChange = view.getLayers(layer => layer.id == 'idLayerToChange')[0]; - * layerToChange.visible = false; - * view.notifyChange(); // update viewer - * - * // Change layer's opacity - * const layerToChange = view.getLayers(layer => layer.id == 'idLayerToChange')[0]; - * layerToChange.opacity = 0.5; - * view.notifyChange(); // update viewer - * - * // Listen properties - * const layerToListen = view.getLayers(layer => layer.id == 'idLayerToListen')[0]; - * layerToListen.addEventListener('visible-property-changed', (event) => console.log(event)); - * layerToListen.addEventListener('opacity-property-changed', (event) => console.log(event)); - * @constructor - * @protected - * @param {String} id - */ -function Layer(id) { - Object.defineProperty(this, 'id', { - value: id, - writable: false, - }); -} - -Layer.prototype = Object.create(EventDispatcher.prototype); -Layer.prototype.constructor = Layer; - -const ImageryLayers = { - // move layer to new index - // After the modification : - // * the minimum sequence will always be 0 - // * the maximum sequence will always be layers.lenght - 1 - // the ordering of all layers (Except that specified) doesn't change - moveLayerToIndex: function moveLayerToIndex(layer, newIndex, imageryLayers) { - newIndex = Math.min(newIndex, imageryLayers.length - 1); - newIndex = Math.max(newIndex, 0); - const oldIndex = layer.sequence; - - for (const imagery of imageryLayers) { - if (imagery.id === layer.id) { - // change index of specified layer - imagery.sequence = newIndex; - } else if (imagery.sequence > oldIndex && imagery.sequence <= newIndex) { - // down all layers between the old index and new index (to compensate the deletion of the old index) - imagery.sequence--; - } else if (imagery.sequence >= newIndex && imagery.sequence < oldIndex) { - // up all layers between the new index and old index (to compensate the insertion of the new index) - imagery.sequence++; - } - } - }, - - moveLayerDown: function moveLayerDown(layer, imageryLayers) { - if (layer.sequence > 0) { - this.moveLayerToIndex(layer, layer.sequence - 1, imageryLayers); - } - }, - - moveLayerUp: function moveLayerUp(layer, imageryLayers) { - const m = imageryLayers.length - 1; - if (layer.sequence < m) { - this.moveLayerToIndex(layer, layer.sequence + 1, imageryLayers); - } - }, - - getColorLayersIdOrderedBySequence: function getColorLayersIdOrderedBySequence(imageryLayers) { - const copy = Array.from(imageryLayers); - copy.sort((a, b) => a.sequence - b.sequence); - return copy.map(l => l.id); - }, -}; - -export { GeometryLayer, Layer, ImageryLayers }; diff --git a/src/Core/MainLoop.js b/src/Core/MainLoop.js index bd7a1f7a3a..b722bed346 100644 --- a/src/Core/MainLoop.js +++ b/src/Core/MainLoop.js @@ -1,5 +1,6 @@ import { EventDispatcher } from 'three'; -import { GeometryLayer, Layer } from './Layer/Layer'; +import Layer from '../Layer/Layer'; +import GeometryLayer from '../Layer/GeometryLayer'; import Cache from '../Core/Scheduler/Cache'; export const RENDERING_PAUSED = 0; @@ -116,7 +117,7 @@ MainLoop.prototype._update = function _update(view, updateSources, dt) { const srcs = filterChangeSources(updateSources, geometryLayer); if (srcs.size > 0) { // `preUpdate` returns an array of elements to update - const elementsToUpdate = geometryLayer.preUpdate(context, geometryLayer, srcs); + const elementsToUpdate = geometryLayer.preUpdate(context, srcs); // `update` is called in `updateElements`. updateElements(context, geometryLayer, elementsToUpdate); // `postUpdate` is called when this geom layer update process is finished diff --git a/src/Core/Prefab/Globe/GlobeLayer.js b/src/Core/Prefab/Globe/GlobeLayer.js new file mode 100644 index 0000000000..900e8b8454 --- /dev/null +++ b/src/Core/Prefab/Globe/GlobeLayer.js @@ -0,0 +1,62 @@ +import * as THREE from 'three'; + +import TiledGeometryLayer from '../../../Layer/TiledGeometryLayer'; + +import { processTiledGeometryNode } from '../../../Process/TiledNodeProcessing'; +import { globeCulling, preGlobeUpdate, globeSubdivisionControl, globeSchemeTileWMTS, globeSchemeTile1 } from '../../../Process/GlobeTileProcessing'; +import BuilderEllipsoidTile from './BuilderEllipsoidTile'; +import SubdivisionControl from '../../../Process/SubdivisionControl'; +import Picking from '../../Picking'; + +class GlobeLayer extends TiledGeometryLayer { + /** + * A geometry layer to be used only with a {@link GlobeView}. + * + * @constructor + * + * @param {string} id + * @param {Object} options + * @param {THREE.Object3D} options.object3d + * @param {number} [options.maxSubdivisionLevel=18] + * @param {number} [options.sseSubdivisionThreshold=1] + * @param {number} [options.maxDeltaElevationLevel=4] + */ + constructor(id, options) { + super(id, options.object3d || new THREE.Group()); + + // Configure tiles + this.schemeTile = globeSchemeTileWMTS(globeSchemeTile1); + this.extent = this.schemeTile[0].clone(); + for (let i = 1; i < this.schemeTile.length; i++) { + this.extent.union(this.schemeTile[i]); + } + function subdivision(context, layer, node) { + if (SubdivisionControl.hasEnoughTexturesToSubdivide(context, layer, node)) { + return globeSubdivisionControl(2, + options.maxSubdivisionLevel || 18, + options.sseSubdivisionThreshold || 1.0, + options.maxDeltaElevationLevel || 4)(context, layer, node); + } + return false; + } + + this.update = processTiledGeometryNode(globeCulling(2), subdivision); + this.builder = new BuilderEllipsoidTile(); + // provide custom pick function + this.pickObjectsAt = (_view, mouse, radius = 5) => Picking.pickTilesAt(_view, mouse, radius, this); + } + + preUpdate(context, changeSources) { + SubdivisionControl.preUpdate(context, this); + + if (__DEBUG__) { + this._latestUpdateStartingLevel = 0; + } + + preGlobeUpdate(context, this); + + return super.preUpdate(context, changeSources); + } +} + +export default GlobeLayer; diff --git a/src/Core/Prefab/GlobeView.js b/src/Core/Prefab/GlobeView.js index 27aab463c8..f5961e1359 100644 --- a/src/Core/Prefab/GlobeView.js +++ b/src/Core/Prefab/GlobeView.js @@ -6,17 +6,11 @@ import { COLOR_LAYERS_ORDER_CHANGED } from '../../Renderer/ColorLayersOrdering'; import RendererConstant from '../../Renderer/RendererConstant'; import GlobeControls from '../../Renderer/ThreeExtended/GlobeControls'; -import { GeometryLayer } from '../Layer/Layer'; - +import GlobeLayer from './Globe/GlobeLayer'; import Atmosphere from './Globe/Atmosphere'; import CoordStars from '../Geographic/CoordStars'; import Coordinates, { C, ellipsoidSizes } from '../Geographic/Coordinates'; -import { processTiledGeometryNode } from '../../Process/TiledNodeProcessing'; -import { globeCulling, preGlobeUpdate, globeSubdivisionControl, globeSchemeTileWMTS, globeSchemeTile1 } from '../../Process/GlobeTileProcessing'; -import BuilderEllipsoidTile from './Globe/BuilderEllipsoidTile'; -import SubdivisionControl from '../../Process/SubdivisionControl'; -import Picking from '../Picking'; /** * Fires when the view is completely loaded. Controls and view's functions can be called then. @@ -71,92 +65,9 @@ export const GLOBE_VIEW_EVENTS = { COLOR_LAYERS_ORDER_CHANGED, }; -export function createGlobeLayer(id, options) { - // Configure tiles - const nodeInitFn = function nodeInitFn(layer, parent, node) { - node.material.setLightingOn(layer.lighting.enable); - node.material.uniforms.lightPosition.value = layer.lighting.position; - if (layer.noTextureColor) { - node.material.uniforms.noTextureColor.value.copy(layer.noTextureColor); - } - - if (__DEBUG__) { - node.material.uniforms.showOutline = { value: layer.showOutline || false }; - node.material.wireframe = layer.wireframe || false; - } - }; - - const wgs84TileLayer = new GeometryLayer(id, options.object3d || new THREE.Group()); - wgs84TileLayer.schemeTile = globeSchemeTileWMTS(globeSchemeTile1); - wgs84TileLayer.extent = wgs84TileLayer.schemeTile[0].clone(); - for (let i = 1; i < wgs84TileLayer.schemeTile.length; i++) { - wgs84TileLayer.extent.union(wgs84TileLayer.schemeTile[i]); - } - wgs84TileLayer.preUpdate = (context, layer, changeSources) => { - SubdivisionControl.preUpdate(context, layer); - - if (__DEBUG__) { - layer._latestUpdateStartingLevel = 0; - } - - preGlobeUpdate(context, layer); - - let commonAncestor; - for (const source of changeSources.values()) { - if (source.isCamera) { - // if the change is caused by a camera move, no need to bother - // to find common ancestor: we need to update the whole tree: - // some invisible tiles may now be visible - return layer.level0Nodes; - } - if (source.layer === layer) { - if (!commonAncestor) { - commonAncestor = source; - } else { - commonAncestor = source.findCommonAncestor(commonAncestor); - if (!commonAncestor) { - return layer.level0Nodes; - } - } - if (commonAncestor.material == null) { - commonAncestor = undefined; - } - } - } - if (commonAncestor) { - if (__DEBUG__) { - layer._latestUpdateStartingLevel = commonAncestor.level; - } - return [commonAncestor]; - } else { - return layer.level0Nodes; - } - }; - - function subdivision(context, layer, node) { - if (SubdivisionControl.hasEnoughTexturesToSubdivide(context, layer, node)) { - return globeSubdivisionControl(2, - options.maxSubdivisionLevel || 18, - options.sseSubdivisionThreshold || 1.0, - options.maxDeltaElevationLevel || 4)(context, layer, node); - } - return false; - } - - wgs84TileLayer.update = processTiledGeometryNode(globeCulling(2), subdivision); - wgs84TileLayer.builder = new BuilderEllipsoidTile(); - wgs84TileLayer.onTileCreated = nodeInitFn; - wgs84TileLayer.type = 'geometry'; - wgs84TileLayer.protocol = 'tile'; - wgs84TileLayer.visible = true; - wgs84TileLayer.lighting = { - enable: false, - position: { x: -0.5, y: 0.0, z: 1.0 }, - }; - // provide custom pick function - wgs84TileLayer.pickObjectsAt = (_view, mouse, radius = 5) => Picking.pickTilesAt(_view, mouse, radius, wgs84TileLayer); - - return wgs84TileLayer; +export function createGlobeLayer(id, extent, options) { + console.warn('createGlobeLayer is deprecated, use the GlobeLayer class instead.'); + return new GlobeLayer(id, extent, options); } /** @@ -190,7 +101,7 @@ function GlobeView(viewerDiv, coordCarto, options = {}) { this.camera.camera3D.updateProjectionMatrix(); this.camera.camera3D.updateMatrixWorld(true); - const wgs84TileLayer = createGlobeLayer('globe', options); + const wgs84TileLayer = new GlobeLayer('globe', options); const sun = new THREE.DirectionalLight(); sun.position.set(-0.5, 0, 1); diff --git a/src/Core/Prefab/Panorama/PanoramaLayer.js b/src/Core/Prefab/Panorama/PanoramaLayer.js new file mode 100644 index 0000000000..01e9e17da0 --- /dev/null +++ b/src/Core/Prefab/Panorama/PanoramaLayer.js @@ -0,0 +1,118 @@ +import * as THREE from 'three'; + +import TiledGeometryLayer from '../../../Layer/TiledGeometryLayer'; +import Extent from '../../Geographic/Extent'; +import { processTiledGeometryNode } from '../../../Process/TiledNodeProcessing'; +import { panoramaCulling, panoramaSubdivisionControl } from '../../../Process/PanoramaTileProcessing'; +import PanoramaTileBuilder from './PanoramaTileBuilder'; +import SubdivisionControl from '../../../Process/SubdivisionControl'; +import ProjectionType from './Constants'; +import Picking from '../../Picking'; + +class PanoramaLayer extends TiledGeometryLayer { + /** + * A geometry layer to be used only with a {@link PanoramaView}. + * + * @constructor + * + * @param {string} id + * @param {Coordinates} coordinates + * @param {string} type + * @param {Object} options + * @param {THREE.Object3D} options.object3d + * @param {number} options.ratio=1 + * @param {number} [options.maxSubdivisionLevel=10] + */ + constructor(id, coordinates, type, options) { + super(id, options.object3d || new THREE.Group()); + + coordinates.xyz(this.object3d.position); + this.object3d.quaternion.setFromUnitVectors( + new THREE.Vector3(0, 0, 1), coordinates.geodesicNormal); + this.object3d.updateMatrixWorld(true); + + // FIXME: add CRS = '0' support + this.extent = new Extent('EPSG:4326', { + west: -180, + east: 180, + north: 90, + south: -90, + }); + + if (type === ProjectionType.SPHERICAL) { + // equirectangular -> spherical geometry + this.schemeTile = [ + new Extent('EPSG:4326', { + west: -180, + east: 0, + north: 90, + south: -90, + }), new Extent('EPSG:4326', { + west: 0, + east: 180, + north: 90, + south: -90, + })]; + } else if (type === ProjectionType.CYLINDRICAL) { + // cylindrical geometry + this.schemeTile = [ + new Extent('EPSG:4326', { + west: -180, + east: -90, + north: 90, + south: -90, + }), new Extent('EPSG:4326', { + west: -90, + east: 0, + north: 90, + south: -90, + }), new Extent('EPSG:4326', { + west: 0, + east: 90, + north: 90, + south: -90, + }), new Extent('EPSG:4326', { + west: 90, + east: 180, + north: 90, + south: -90, + })]; + } else { + throw new Error(`Unsupported panorama projection type ${type}. + Only ProjectionType.SPHERICAL and ProjectionType.CYLINDRICAL are supported`); + } + this.disableSkirt = true; + + function subdivision(context, layer, node) { + if (SubdivisionControl.hasEnoughTexturesToSubdivide(context, layer, node)) { + return panoramaSubdivisionControl( + options.maxSubdivisionLevel || 10, new THREE.Vector2(512, 256))(context, layer, node); + } + return false; + } + + this.update = processTiledGeometryNode(panoramaCulling, subdivision); + this.builder = new PanoramaTileBuilder(type, options.ratio); + this.segments = 8; + this.quality = 0.5; + // provide custom pick function + this.pickObjectsAt = (_view, mouse, radius) => Picking.pickTilesAt(_view, mouse, radius, this); + } + + + preUpdate(context, changeSources) { + SubdivisionControl.preUpdate(context, this); + + if (__DEBUG__) { + this._latestUpdateStartingLevel = 0; + } + + if (changeSources.has(undefined) || changeSources.size == 0) { + return this.level0Nodes; + } + + return super.preUpdate(context, changeSources); + } +} + +export default PanoramaLayer; diff --git a/src/Core/Prefab/PanoramaView.js b/src/Core/Prefab/PanoramaView.js index 20b6ea7323..59286e1d9b 100644 --- a/src/Core/Prefab/PanoramaView.js +++ b/src/Core/Prefab/PanoramaView.js @@ -1,158 +1,11 @@ import * as THREE from 'three'; import View from '../View'; - -import { GeometryLayer } from '../Layer/Layer'; -import Extent from '../Geographic/Extent'; -import { processTiledGeometryNode } from '../../Process/TiledNodeProcessing'; -import { panoramaCulling, panoramaSubdivisionControl } from '../../Process/PanoramaTileProcessing'; -import PanoramaTileBuilder from './Panorama/PanoramaTileBuilder'; -import SubdivisionControl from '../../Process/SubdivisionControl'; -import ProjectionType from './Panorama/Constants'; -import Picking from '../Picking'; +import PanoramaLayer from './Panorama/PanoramaLayer'; export function createPanoramaLayer(id, coordinates, type, options = {}) { - const tileLayer = new GeometryLayer(id, options.object3d || new THREE.Group()); - - coordinates.xyz(tileLayer.object3d.position); - tileLayer.object3d.quaternion.setFromUnitVectors( - new THREE.Vector3(0, 0, 1), coordinates.geodesicNormal); - tileLayer.object3d.updateMatrixWorld(true); - - // FIXME: add CRS = '0' support - tileLayer.extent = new Extent('EPSG:4326', { - west: -180, - east: 180, - north: 90, - south: -90, - }); - - if (type === ProjectionType.SPHERICAL) { - // equirectangular -> spherical geometry - tileLayer.schemeTile = [ - new Extent('EPSG:4326', { - west: -180, - east: 0, - north: 90, - south: -90, - }), new Extent('EPSG:4326', { - west: 0, - east: 180, - north: 90, - south: -90, - })]; - } else if (type === ProjectionType.CYLINDRICAL) { - // cylindrical geometry - tileLayer.schemeTile = [ - new Extent('EPSG:4326', { - west: -180, - east: -90, - north: 90, - south: -90, - }), new Extent('EPSG:4326', { - west: -90, - east: 0, - north: 90, - south: -90, - }), new Extent('EPSG:4326', { - west: 0, - east: 90, - north: 90, - south: -90, - }), new Extent('EPSG:4326', { - west: 90, - east: 180, - north: 90, - south: -90, - })]; - } else { - throw new Error(`Unsupported panorama projection type ${type}. - Only ProjectionType.SPHERICAL and ProjectionType.CYLINDRICAL are supported`); - } - tileLayer.disableSkirt = true; - - // Configure tiles - const nodeInitFn = function nodeInitFn(layer, parent, node) { - if (layer.noTextureColor) { - node.material.uniforms.noTextureColor.value.copy(layer.noTextureColor); - } - node.material.depthWrite = false; - - if (__DEBUG__) { - node.material.uniforms.showOutline = { value: layer.showOutline || false }; - node.material.wireframe = layer.wireframe || false; - } - }; - - tileLayer.preUpdate = (context, layer, changeSources) => { - SubdivisionControl.preUpdate(context, layer); - - if (__DEBUG__) { - layer._latestUpdateStartingLevel = 0; - } - - if (changeSources.has(undefined) || changeSources.size == 0) { - return layer.level0Nodes; - } - - let commonAncestor; - for (const source of changeSources.values()) { - if (source.isCamera) { - // if the change is caused by a camera move, no need to bother - // to find common ancestor: we need to update the whole tree: - // some invisible tiles may now be visible - return layer.level0Nodes; - } - if (source.layer === layer.id) { - if (!commonAncestor) { - commonAncestor = source; - } else { - commonAncestor = source.findCommonAncestor(commonAncestor); - if (!commonAncestor) { - return layer.level0Nodes; - } - } - if (commonAncestor.material == null) { - commonAncestor = undefined; - } - } - } - if (commonAncestor) { - if (__DEBUG__) { - layer._latestUpdateStartingLevel = commonAncestor.level; - } - return [commonAncestor]; - } else { - return layer.level0Nodes; - } - }; - - - function subdivision(context, layer, node) { - if (SubdivisionControl.hasEnoughTexturesToSubdivide(context, layer, node)) { - return panoramaSubdivisionControl( - options.maxSubdivisionLevel || 10, new THREE.Vector2(512, 256))(context, layer, node); - } - return false; - } - - tileLayer.update = processTiledGeometryNode(panoramaCulling, subdivision); - tileLayer.builder = new PanoramaTileBuilder(type, options.ratio); - tileLayer.onTileCreated = nodeInitFn; - tileLayer.type = 'geometry'; - tileLayer.protocol = 'tile'; - tileLayer.visible = true; - tileLayer.segments = 8; - tileLayer.quality = 0.5; - tileLayer.lighting = { - enable: false, - position: { x: -0.5, y: 0.0, z: 1.0 }, - }; - // provide custom pick function - tileLayer.pickObjectsAt = (_view, mouse, radius) => Picking.pickTilesAt(_view, mouse, radius, tileLayer); - - - return tileLayer; + console.warn('createPanoramaLayer is deprecated, use the PanoramaLayer class instead.'); + return new PanoramaLayer(id, coordinates, type, options); } function PanoramaView(viewerDiv, coordinates, type, options = {}) { @@ -177,7 +30,7 @@ function PanoramaView(viewerDiv, coordinates, type, options = {}) { } camera.updateMatrixWorld(); - const tileLayer = createPanoramaLayer('panorama', coordinates, type, options); + const tileLayer = new PanoramaLayer('panorama', coordinates, type, options); View.prototype.addLayer.call(this, tileLayer); diff --git a/src/Core/Prefab/Planar/PlanarLayer.js b/src/Core/Prefab/Planar/PlanarLayer.js new file mode 100644 index 0000000000..7f412b4e79 --- /dev/null +++ b/src/Core/Prefab/Planar/PlanarLayer.js @@ -0,0 +1,62 @@ +import * as THREE from 'three'; + +import TiledGeometryLayer from '../../../Layer/TiledGeometryLayer'; + +import { processTiledGeometryNode } from '../../../Process/TiledNodeProcessing'; +import { planarCulling, planarSubdivisionControl, prePlanarUpdate } from '../../../Process/PlanarTileProcessing'; +import PlanarTileBuilder from './PlanarTileBuilder'; +import SubdivisionControl from '../../../Process/SubdivisionControl'; +import Picking from '../../Picking'; + +class PlanarLayer extends TiledGeometryLayer { + /** + * A geometry layer to be used only with a {@link PlanarView}. + * + * @constructor + * + * @param {string} id + * @param {Extent} extent - the extent to define the layer within + * @param {Object} options + * @param {THREE.Object3D} options.object3d + * @param {number} [options.maxSubdivisionLevel=5] + * @param {number} [options.maxDeltaElevationLevel=4] + */ + constructor(id, extent, options) { + super(id, options.object3d || new THREE.Group()); + + this.extent = extent; + this.schemeTile = [extent]; + + function subdivision(context, layer, node) { + if (SubdivisionControl.hasEnoughTexturesToSubdivide(context, layer, node)) { + return planarSubdivisionControl( + options.maxSubdivisionLevel || 5, + options.maxDeltaElevationLevel || 4)(context, layer, node); + } + return false; + } + + this.update = processTiledGeometryNode(planarCulling, subdivision); + this.builder = new PlanarTileBuilder(); + // provide custom pick function + this.pickObjectsAt = (_view, mouse, radius) => Picking.pickTilesAt(_view, mouse, radius, this); + } + + preUpdate(context, changeSources) { + SubdivisionControl.preUpdate(context, this); + + prePlanarUpdate(context, this); + + if (__DEBUG__) { + this._latestUpdateStartingLevel = 0; + } + + if (changeSources.has(undefined) || changeSources.size == 0) { + return this.level0Nodes; + } + + return super.preUpdate(context, changeSources); + } +} + +export default PlanarLayer; diff --git a/src/Core/Prefab/PlanarView.js b/src/Core/Prefab/PlanarView.js index 2b76f1446e..b153eba13d 100644 --- a/src/Core/Prefab/PlanarView.js +++ b/src/Core/Prefab/PlanarView.js @@ -4,102 +4,11 @@ import View from '../View'; import { RENDERING_PAUSED, MAIN_LOOP_EVENTS } from '../MainLoop'; import RendererConstant from '../../Renderer/RendererConstant'; -import { GeometryLayer } from '../Layer/Layer'; - -import { processTiledGeometryNode } from '../../Process/TiledNodeProcessing'; -import { planarCulling, planarSubdivisionControl, prePlanarUpdate } from '../../Process/PlanarTileProcessing'; -import PlanarTileBuilder from './Planar/PlanarTileBuilder'; -import SubdivisionControl from '../../Process/SubdivisionControl'; -import Picking from '../Picking'; +import PlanarLayer from './Planar/PlanarLayer'; export function createPlanarLayer(id, extent, options) { - const tileLayer = new GeometryLayer(id, options.object3d || new THREE.Group()); - tileLayer.extent = extent; - tileLayer.schemeTile = [extent]; - - // Configure tiles - const nodeInitFn = function nodeInitFn(layer, parent, node) { - node.material.setLightingOn(layer.lighting.enable); - node.material.uniforms.lightPosition.value = layer.lighting.position; - - if (layer.noTextureColor) { - node.material.uniforms.noTextureColor.value.copy(layer.noTextureColor); - } - - if (__DEBUG__) { - node.material.uniforms.showOutline = { value: layer.showOutline || false }; - node.material.wireframe = layer.wireframe || false; - } - }; - - tileLayer.preUpdate = (context, layer, changeSources) => { - SubdivisionControl.preUpdate(context, layer); - - prePlanarUpdate(context, layer); - - if (__DEBUG__) { - layer._latestUpdateStartingLevel = 0; - } - - if (changeSources.has(undefined) || changeSources.size == 0) { - return layer.level0Nodes; - } - - let commonAncestor; - for (const source of changeSources.values()) { - if (source.isCamera) { - // if the change is caused by a camera move, no need to bother - // to find common ancestor: we need to update the whole tree: - // some invisible tiles may now be visible - return layer.level0Nodes; - } - if (source.layer === layer) { - if (!commonAncestor) { - commonAncestor = source; - } else { - commonAncestor = source.findCommonAncestor(commonAncestor); - if (!commonAncestor) { - return layer.level0Nodes; - } - } - if (commonAncestor.material == null) { - commonAncestor = undefined; - } - } - } - if (commonAncestor) { - if (__DEBUG__) { - layer._latestUpdateStartingLevel = commonAncestor.level; - } - return [commonAncestor]; - } else { - return layer.level0Nodes; - } - }; - - - function subdivision(context, layer, node) { - if (SubdivisionControl.hasEnoughTexturesToSubdivide(context, layer, node)) { - return planarSubdivisionControl(options.maxSubdivisionLevel || 5, - options.maxDeltaElevationLevel || 4)(context, layer, node); - } - return false; - } - - tileLayer.update = processTiledGeometryNode(planarCulling, subdivision); - tileLayer.builder = new PlanarTileBuilder(); - tileLayer.onTileCreated = nodeInitFn; - tileLayer.type = 'geometry'; - tileLayer.protocol = 'tile'; - tileLayer.visible = true; - tileLayer.lighting = { - enable: false, - position: { x: -0.5, y: 0.0, z: 1.0 }, - }; - // provide custom pick function - tileLayer.pickObjectsAt = (_view, mouse, radius) => Picking.pickTilesAt(_view, mouse, radius, tileLayer); - - return tileLayer; + console.warn('createPlanarLayer is deprecated, use the PlanarLayer class instead.'); + return new PlanarLayer(id, extent, options); } function PlanarView(viewerDiv, extent, options = {}) { @@ -122,7 +31,7 @@ function PlanarView(viewerDiv, extent, options = {}) { this.camera.camera3D.updateProjectionMatrix(); this.camera.camera3D.updateMatrixWorld(true); - const tileLayer = createPlanarLayer('planar', extent, options); + const tileLayer = new PlanarLayer('planar', extent, options); this.addLayer(tileLayer); diff --git a/src/Core/View.js b/src/Core/View.js index 6de58a5a3a..2bf9c14af5 100644 --- a/src/Core/View.js +++ b/src/Core/View.js @@ -1,10 +1,15 @@ /* global window */ -import { Scene, EventDispatcher, Vector2, Object3D } from 'three'; +import * as THREE from 'three'; import Camera from '../Renderer/Camera'; import MainLoop, { MAIN_LOOP_EVENTS, RENDERING_PAUSED } from './MainLoop'; import c3DEngine from '../Renderer/c3DEngine'; -import { STRATEGY_MIN_NETWORK_TRAFFIC } from './Layer/LayerUpdateStrategy'; -import { GeometryLayer, Layer, defineLayerProperty } from './Layer/Layer'; + +import { STRATEGY_MIN_NETWORK_TRAFFIC } from '../Layer/LayerUpdateStrategy'; +import Layer from '../Layer/Layer'; +import ColorLayer from '../Layer/ColorLayer'; +import ElevationLayer from '../Layer/ElevationLayer'; +import GeometryLayer from '../Layer/GeometryLayer'; + import Scheduler from './Scheduler/Scheduler'; import Picking from './Picking'; import { updateLayeredMaterialNodeImagery, updateLayeredMaterialNodeElevation } from '../Process/LayeredMaterialNodeProcessing'; @@ -59,7 +64,7 @@ function View(crs, viewerDiv, options = {}) { this.mainLoop = options.mainLoop || new MainLoop(new Scheduler(), engine); - this.scene = options.scene3D || new Scene(); + this.scene = options.scene3D || new THREE.Scene(); if (!options.scene3D) { this.scene.autoUpdate = false; } @@ -76,7 +81,7 @@ function View(crs, viewerDiv, options = {}) { window.addEventListener('resize', () => { // If the user gave us a container (
) then itowns' size is // the container's size. Otherwise we use window' size. - const newSize = new Vector2(viewerDiv.clientWidth, viewerDiv.clientHeight); + const newSize = new THREE.Vector2(viewerDiv.clientWidth, viewerDiv.clientHeight); this.mainLoop.gfxEngine.onWindowResize(newSize.x, newSize.y); this.notifyChange(this.camera.camera3D); }, false); @@ -101,9 +106,43 @@ function View(crs, viewerDiv, options = {}) { }; } -View.prototype = Object.create(EventDispatcher.prototype); +View.prototype = Object.create(THREE.EventDispatcher.prototype); View.prototype.constructor = View; +function _createLayerFromConfig(config) { + let layer; + + switch (config.type) { + case 'color': + layer = new ColorLayer(config.id); + break; + case 'elevation': + layer = new ElevationLayer(config.id); + break; + case 'geometry': + layer = new GeometryLayer(config.id, new THREE.Group()); + break; + case 'debug': + layer = new Layer(config.id, 'debug'); + break; + default: + throw new Error(`Unknown layer type ${config.type}: please + specify a valid one`); + } + + // nlayer.id and type are read-only so delete them from layer before + // Object.assign + const tmp = config; + delete tmp.id; + delete tmp.type; + layer = Object.assign(layer, config); + // restore layer.id and type in user provider layer object + tmp.id = config.id; + tmp.type = config.type; + + return layer; +} + const _syncGeometryLayerVisibility = function _syncGeometryLayerVisibility(layer, view) { if (layer.object3d) { layer.object3d.visible = layer.visible; @@ -119,14 +158,8 @@ const _syncGeometryLayerVisibility = function _syncGeometryLayerVisibility(layer }; function _preprocessLayer(view, layer, provider, parentLayer) { - if (!(layer instanceof Layer) && !(layer instanceof GeometryLayer)) { - const nlayer = new Layer(layer.id); - // nlayer.id is read-only so delete it from layer before Object.assign - const tmp = layer; - delete tmp.id; - layer = Object.assign(nlayer, layer); - // restore layer.id in user provider layer object - tmp.id = layer.id; + if (!(layer instanceof Layer)) { + layer = _createLayerFromConfig(layer); } layer.options = layer.options || {}; @@ -175,17 +208,9 @@ function _preprocessLayer(view, layer, provider, parentLayer) { }); } - // probably not the best place to do this - if (layer.type == 'color') { - defineLayerProperty(layer, 'frozen', false); - defineLayerProperty(layer, 'visible', true); - defineLayerProperty(layer, 'opacity', 1.0); - defineLayerProperty(layer, 'sequence', 0); - } else if (layer.type == 'elevation') { - defineLayerProperty(layer, 'frozen', false); - } else if (layer.type == 'geometry' || layer.type == 'debug') { - defineLayerProperty(layer, 'visible', true, () => _syncGeometryLayerVisibility(layer, view)); - defineLayerProperty(layer, 'frozen', false); + if (layer.type == 'geometry' || layer.type == 'debug') { + layer.defineLayerProperty('visible', true, () => _syncGeometryLayerVisibility(layer, view)); + layer.defineLayerProperty('frozen', false); _syncGeometryLayerVisibility(layer, view); const changeOpacity = (o) => { @@ -201,7 +226,7 @@ function _preprocessLayer(view, layer, provider, parentLayer) { } } }; - defineLayerProperty(layer, 'opacity', 1.0, () => { + layer.defineLayerProperty('opacity', 1.0, () => { if (layer.object3d) { layer.object3d.traverse((o) => { if (o.layer !== layer) { @@ -216,6 +241,7 @@ function _preprocessLayer(view, layer, provider, parentLayer) { } }); } + return layer; } @@ -396,12 +422,12 @@ View.prototype.notifyChange = function notifyChange(changeSource = undefined, ne */ View.prototype.getLayers = function getLayers(filter) { const result = []; - for (const geometryLayer of this._layers) { - if (!filter || filter(geometryLayer)) { - result.push(geometryLayer); + for (const layer of this._layers) { + if (!filter || filter(layer)) { + result.push(layer); } - for (const attached of geometryLayer._attachedLayers) { - if (!filter || filter(attached, geometryLayer)) { + for (const attached of layer._attachedLayers) { + if (!filter || filter(attached, layer)) { result.push(attached); } } @@ -537,7 +563,7 @@ View.prototype.execFrameRequesters = function execFrameRequesters(when, dt, upda } }; -const _eventCoords = new Vector2(); +const _eventCoords = new THREE.Vector2(); /** * Extract view coordinates from a mouse-event / touch-event * @param {event} event - event can be a MouseEvent or a TouchEvent @@ -567,7 +593,7 @@ View.prototype.eventToNormalizedCoords = function eventToNormalizedCoords(event, /** * Convert view coordinates to normalized coordinates (NDC) - * @param {Vector2} viewCoords (in pixels, 0-0 = top-left of the View) + * @param {THREE.Vector2} viewCoords (in pixels, 0-0 = top-left of the View) * @return {THREE.Vector2} - NDC coordinates (x and y are [-1, 1]) */ View.prototype.viewToNormalizedCoords = function viewToNormalizedCoords(viewCoords) { @@ -578,7 +604,7 @@ View.prototype.viewToNormalizedCoords = function viewToNormalizedCoords(viewCoor /** * Convert NDC coordinates to view coordinates - * @param {Vector2} ndcCoords + * @param {THREE.Vector2} ndcCoords * @return {THREE.Vector2} - view coordinates (in pixels, 0-0 = top-left of the View) */ View.prototype.normalizedToViewCoords = function normalizedToViewCoords(ndcCoords) { @@ -663,7 +689,7 @@ View.prototype.pickObjectsAt = function pickObjectsAt(mouseOrEvt, radius, ...whe } } } - } else if (source instanceof Object3D) { + } else if (source instanceof THREE.Object3D) { Picking.pickObjectsAt( this, mouse, diff --git a/src/Layer/ColorLayer.js b/src/Layer/ColorLayer.js new file mode 100644 index 0000000000..b3e8cc896d --- /dev/null +++ b/src/Layer/ColorLayer.js @@ -0,0 +1,14 @@ +import Layer from './Layer'; + +class ColorLayer extends Layer { + constructor(id) { + super(id, 'color'); + + this.defineLayerProperty('frozen', false); + this.defineLayerProperty('visible', true); + this.defineLayerProperty('opacity', 1.0); + this.defineLayerProperty('sequence', 0); + } +} + +export default ColorLayer; diff --git a/src/Layer/ElevationLayer.js b/src/Layer/ElevationLayer.js new file mode 100644 index 0000000000..1dab372131 --- /dev/null +++ b/src/Layer/ElevationLayer.js @@ -0,0 +1,11 @@ +import Layer from './Layer'; + +class ElevationLayer extends Layer { + constructor(id) { + super(id, 'elevation'); + + this.defineLayerProperty('frozen', false); + } +} + +export default ElevationLayer; diff --git a/src/Layer/GeometryLayer.js b/src/Layer/GeometryLayer.js new file mode 100644 index 0000000000..ac8eeed700 --- /dev/null +++ b/src/Layer/GeometryLayer.js @@ -0,0 +1,42 @@ +import Layer from './Layer'; +import Picking from '../Core/Picking'; + +class GeometryLayer extends Layer { + constructor(id, object3d) { + if (!object3d || !object3d.isObject3D) { + throw new Error('Missing/Invalid object3d parameter (must be a three.js Object3D instance)'); + } + + super(id, 'geometry'); + + this._attachedLayers = []; + if (object3d.type === 'Group' && object3d.name === '') { + object3d.name = id; + } + + Object.defineProperty(this, 'object3d', { + value: object3d, + writable: false, + }); + + // Setup default picking method + this.pickObjectsAt = (view, mouse, radius) => Picking.pickObjectsAt(view, mouse, radius, this.object3d); + + this.postUpdate = () => {}; + } + + attach(layer) { + if (!layer.update) { + throw new Error(`Missing 'update' function -> can't attach layer ${layer.id}`); + } + this._attachedLayers.push(layer); + } + + detach(layer) { + const count = this._attachedLayers.length; + this._attachedLayers = this._attachedLayers.filter(attached => attached.id != layer.id); + return this._attachedLayers.length < count; + } +} + +export default GeometryLayer; diff --git a/src/Layer/Layer.js b/src/Layer/Layer.js new file mode 100644 index 0000000000..b6f3c1de46 --- /dev/null +++ b/src/Layer/Layer.js @@ -0,0 +1,148 @@ +import * as THREE from 'three'; + +/** + * Fires when layer sequence change (meaning when the order of the layer changes in the view) + * @event Layer#sequence-property-changed + * @property new {object} + * @property new.sequence {number} the new value of the layer sequence + * @property previous {object} + * @property previous.sequence {number} the previous value of the layer sequence + * @property target {Layer} dispatched on layer + * @property type {string} sequence-property-changed +*/ +/** + * Fires when layer opacity change + * @event Layer#opacity-property-changed + * @property new {object} + * @property new.opacity {object} the new value of the layer opacity + * @property previous {object} + * @property previous.opacity {object} the previous value of the layer opacity + * @property target {Layer} dispatched on layer + * @property type {string} opacity-property-changed +*/ +/** + * Fires when layer visibility change + * @event Layer#visible-property-changed + * @property new {object} + * @property new.visible {object} the new value of the layer visibility + * @property previous {object} + * @property previous.visible {object} the previous value of the layer visibility + * @property target {Layer} dispatched on layer + * @property type {string} visible-property-changed +*/ + +class Layer extends THREE.EventDispatcher { + /** + * Don't use directly constructor to instance a new Layer + * use addLayer in {@link View} + * @example + * // add and create a new Layer + * const newLayer = view.addLayer({options}); + * + * // Change layer's visibilty + * const layerToChange = view.getLayers(layer => layer.id == 'idLayerToChange')[0]; + * layerToChange.visible = false; + * view.notifyChange(); // update viewer + * + * // Change layer's opacity + * const layerToChange = view.getLayers(layer => layer.id == 'idLayerToChange')[0]; + * layerToChange.opacity = 0.5; + * view.notifyChange(); // update viewer + * + * // Listen properties + * const layerToListen = view.getLayers(layer => layer.id == 'idLayerToListen')[0]; + * layerToListen.addEventListener('visible-property-changed', (event) => console.log(event)); + * layerToListen.addEventListener('opacity-property-changed', (event) => console.log(event)); + * @constructor + * @protected + * @param {string} id + * @param {string} type + */ + constructor(id, type) { + super(); + + Object.defineProperty(this, 'id', { + value: id, + writable: false, + }); + + Object.defineProperty(this, 'type', { + value: type, + writable: false, + }); + } + + defineLayerProperty(propertyName, defaultValue, onChange) { + const existing = Object.getOwnPropertyDescriptor(this, propertyName); + if (!existing || !existing.set) { + let property = this[propertyName] == undefined ? defaultValue : this[propertyName]; + + Object.defineProperty( + this, + propertyName, + { + get: () => property, + set: (newValue) => { + if (property !== newValue) { + const event = { type: `${propertyName}-property-changed`, previous: {}, new: {} }; + event.previous[propertyName] = property; + event.new[propertyName] = newValue; + property = newValue; + if (onChange) { + onChange(this, propertyName); + } + this.dispatchEvent(event); + } + }, + }); + } + } +} + +export default Layer; + +export const ImageryLayers = { + // move layer to new index + // After the modification : + // * the minimum sequence will always be 0 + // * the maximum sequence will always be layers.lenght - 1 + // the ordering of all layers (Except that specified) doesn't change + moveLayerToIndex: function moveLayerToIndex(layer, newIndex, imageryLayers) { + newIndex = Math.min(newIndex, imageryLayers.length - 1); + newIndex = Math.max(newIndex, 0); + const oldIndex = layer.sequence; + + for (const imagery of imageryLayers) { + if (imagery.id === layer.id) { + // change index of specified layer + imagery.sequence = newIndex; + } else if (imagery.sequence > oldIndex && imagery.sequence <= newIndex) { + // down all layers between the old index and new index (to compensate the deletion of the old index) + imagery.sequence--; + } else if (imagery.sequence >= newIndex && imagery.sequence < oldIndex) { + // up all layers between the new index and old index (to compensate the insertion of the new index) + imagery.sequence++; + } + } + }, + + moveLayerDown: function moveLayerDown(layer, imageryLayers) { + if (layer.sequence > 0) { + this.moveLayerToIndex(layer, layer.sequence - 1, imageryLayers); + } + }, + + moveLayerUp: function moveLayerUp(layer, imageryLayers) { + const m = imageryLayers.length - 1; + if (layer.sequence < m) { + this.moveLayerToIndex(layer, layer.sequence + 1, imageryLayers); + } + }, + + getColorLayersIdOrderedBySequence: function getColorLayersIdOrderedBySequence(imageryLayers) { + const copy = Array.from(imageryLayers); + copy.sort((a, b) => a.sequence - b.sequence); + return copy.map(l => l.id); + }, +}; + diff --git a/src/Core/Layer/LayerUpdateState.js b/src/Layer/LayerUpdateState.js similarity index 100% rename from src/Core/Layer/LayerUpdateState.js rename to src/Layer/LayerUpdateState.js diff --git a/src/Core/Layer/LayerUpdateStrategy.js b/src/Layer/LayerUpdateStrategy.js similarity index 97% rename from src/Core/Layer/LayerUpdateStrategy.js rename to src/Layer/LayerUpdateStrategy.js index c4a5b43e04..32c77291d9 100644 --- a/src/Core/Layer/LayerUpdateStrategy.js +++ b/src/Layer/LayerUpdateStrategy.js @@ -1,4 +1,4 @@ -import { EMPTY_TEXTURE_ZOOM } from '../../Renderer/LayeredMaterialConstants'; +import { EMPTY_TEXTURE_ZOOM } from '../Renderer/LayeredMaterialConstants'; /** * This modules implements various layer update strategies. * diff --git a/src/Layer/TiledGeometryLayer.js b/src/Layer/TiledGeometryLayer.js new file mode 100644 index 0000000000..d4bb98d35e --- /dev/null +++ b/src/Layer/TiledGeometryLayer.js @@ -0,0 +1,63 @@ +import GeometryLayer from './GeometryLayer'; + +class TiledGeometryLayer extends GeometryLayer { + constructor(id, object3d) { + super(id, object3d); + + this.protocol = 'tile'; + this.visible = true; + this.lighting = { + enable: false, + position: { x: -0.5, y: 0.0, z: 1.0 }, + }; + } + + preUpdate(context, changeSources) { + let commonAncestor; + for (const source of changeSources.values()) { + if (source.isCamera) { + // if the change is caused by a camera move, no need to bother + // to find common ancestor: we need to update the whole tree: + // some invisible tiles may now be visible + return this.level0Nodes; + } + if (source.this === this) { + if (!commonAncestor) { + commonAncestor = source; + } else { + commonAncestor = source.findCommonAncestor(commonAncestor); + if (!commonAncestor) { + return this.level0Nodes; + } + } + if (commonAncestor.material == null) { + commonAncestor = undefined; + } + } + } + if (commonAncestor) { + if (__DEBUG__) { + this._latestUpdateStartingLevel = commonAncestor.level; + } + return [commonAncestor]; + } else { + return this.level0Nodes; + } + } + + onTileCreated(node) { + node.material.setLightingOn(this.lighting.enable); + node.material.uniforms.lightPosition.value = this.lighting.position; + + if (this.noTextureColor) { + node.material.uniforms.noTextureColor.value.copy(this.noTextureColor); + } + + if (__DEBUG__) { + node.material.uniforms.showOutline = { value: this.showOutline || false }; + node.material.wireframe = this.wireframe || false; + } + } +} + +export default TiledGeometryLayer; diff --git a/src/Main.js b/src/Main.js index c95a00627e..a68bcab255 100644 --- a/src/Main.js +++ b/src/Main.js @@ -1,7 +1,8 @@ export { default as Coordinates, UNIT } from './Core/Geographic/Coordinates'; export { default as Extent } from './Core/Geographic/Extent'; -export { GeometryLayer, ImageryLayers } from './Core/Layer/Layer'; -export { STRATEGY_MIN_NETWORK_TRAFFIC, STRATEGY_GROUP, STRATEGY_PROGRESSIVE, STRATEGY_DICHOTOMY } from './Core/Layer/LayerUpdateStrategy'; +export { ImageryLayers } from './Layer/Layer'; +export { default as GeometryLayer } from './Layer/GeometryLayer'; +export { STRATEGY_MIN_NETWORK_TRAFFIC, STRATEGY_GROUP, STRATEGY_PROGRESSIVE, STRATEGY_DICHOTOMY } from './Layer/LayerUpdateStrategy'; export { default as GlobeView, GLOBE_VIEW_EVENTS, createGlobeLayer } from './Core/Prefab/GlobeView'; export { default as PlanarView, createPlanarLayer } from './Core/Prefab/PlanarView'; export { default as PanoramaView, createPanoramaLayer } from './Core/Prefab/PanoramaView'; diff --git a/src/Process/3dTilesProcessing.js b/src/Process/3dTilesProcessing.js index 01231ea5cb..413075523a 100644 --- a/src/Process/3dTilesProcessing.js +++ b/src/Process/3dTilesProcessing.js @@ -187,8 +187,8 @@ function _cleanupObject3D(n) { n.remove(...n.children); } -export function pre3dTilesUpdate(context, layer) { - if (!layer.visible) { +export function pre3dTilesUpdate(context) { + if (!this.visible) { return []; } @@ -204,20 +204,20 @@ export function pre3dTilesUpdate(context, layer) { // once in a while, garbage collect if (Math.random() > 0.98) { // Make sure we don't clean root tile - layer.root.cleanableSince = undefined; + this.root.cleanableSince = undefined; // Browse const now = Date.now(); - for (const elt of layer._cleanableTiles) { - if ((now - elt.cleanableSince) > layer.cleanupDelay) { - cleanup3dTileset(layer, elt); + for (const elt of this._cleanableTiles) { + if ((now - elt.cleanableSince) > this.cleanupDelay) { + cleanup3dTileset(this, elt); } } - layer._cleanableTiles = layer._cleanableTiles.filter(n => (layer.tileIndex.index[n.tileId].loaded && n.cleanableSince)); + this._cleanableTiles = this._cleanableTiles.filter(n => (this.tileIndex.index[n.tileId].loaded && n.cleanableSince)); } - return [layer.root]; + return [this.root]; } const cameraLocalPosition = new THREE.Vector3(); diff --git a/src/Process/FeatureProcessing.js b/src/Process/FeatureProcessing.js index d9f9f05d5b..ebe2a5b1fa 100644 --- a/src/Process/FeatureProcessing.js +++ b/src/Process/FeatureProcessing.js @@ -1,5 +1,5 @@ import * as THREE from 'three'; -import LayerUpdateState from '../Core/Layer/LayerUpdateState'; +import LayerUpdateState from '../Layer/LayerUpdateState'; import CancelledCommandException from '../Core/Scheduler/CancelledCommandException'; import ObjectRemovalHelper from './ObjectRemovalHelper'; diff --git a/src/Process/LayeredMaterialNodeProcessing.js b/src/Process/LayeredMaterialNodeProcessing.js index 9af513f9c5..93c41ec0b2 100644 --- a/src/Process/LayeredMaterialNodeProcessing.js +++ b/src/Process/LayeredMaterialNodeProcessing.js @@ -1,7 +1,7 @@ import { l_ELEVATION, l_COLOR, EMPTY_TEXTURE_ZOOM } from '../Renderer/LayeredMaterialConstants'; -import { chooseNextLevelToFetch } from '../Core/Layer/LayerUpdateStrategy'; -import LayerUpdateState from '../Core/Layer/LayerUpdateState'; -import { ImageryLayers } from '../Core/Layer/Layer'; +import { chooseNextLevelToFetch } from '../Layer/LayerUpdateStrategy'; +import LayerUpdateState from '../Layer/LayerUpdateState'; +import { ImageryLayers } from '../Layer/Layer'; import CancelledCommandException from '../Core/Scheduler/CancelledCommandException'; import { SIZE_TEXTURE_TILE } from '../Provider/OGCWebServiceHelper'; import { computeMinMaxElevation } from '../Parser/XbilParser'; diff --git a/src/Process/PointCloudProcessing.js b/src/Process/PointCloudProcessing.js index 92d7183873..77c4af6828 100644 --- a/src/Process/PointCloudProcessing.js +++ b/src/Process/PointCloudProcessing.js @@ -87,9 +87,9 @@ function markForDeletion(elt) { } export default { - preUpdate(context, layer, changeSources) { + preUpdate(context, changeSources) { // Bail-out if not ready - if (!layer.root) { + if (!this.root) { return []; } @@ -99,27 +99,27 @@ export default { context.camera.height / (2 * Math.tan(THREE.Math.degToRad(context.camera.camera3D.fov) * 0.5)); - if (layer.material) { - layer.material.visible = layer.visible; - layer.material.opacity = layer.opacity; - layer.material.transparent = layer.opacity < 1; - layer.material.size = layer.pointSize; + if (this.material) { + this.material.visible = this.visible; + this.material.opacity = this.opacity; + this.material.transparent = this.opacity < 1; + this.material.size = this.pointSize; } // lookup lowest common ancestor of changeSources let commonAncestorName; for (const source of changeSources.values()) { - if (source.isCamera || source == layer) { + if (source.isCamera || source == this) { // if the change is caused by a camera move, no need to bother // to find common ancestor: we need to update the whole tree: // some invisible tiles may now be visible - return [layer.root]; + return [this.root]; } if (source.obj === undefined) { continue; } // filter sources that belong to our layer - if (source.obj.isPoints && source.obj.layer == layer) { + if (source.obj.isPoints && source.obj.layer == this) { if (!commonAncestorName) { commonAncestorName = source.name; } else { @@ -137,11 +137,11 @@ export default { } } if (commonAncestorName) { - return [layer.root.findChildrenByName(commonAncestorName)]; + return [this.root.findChildrenByName(commonAncestorName)]; } // Start updating from hierarchy root - return [layer.root]; + return [this.root]; }, update(context, layer, elt) { diff --git a/src/Process/TiledNodeProcessing.js b/src/Process/TiledNodeProcessing.js index d3817bac7b..e921430c04 100644 --- a/src/Process/TiledNodeProcessing.js +++ b/src/Process/TiledNodeProcessing.js @@ -40,7 +40,7 @@ export function requestNewTile(view, scheduler, geometryLayer, extent, parent, l return scheduler.execute(command).then((node) => { node.add(node.OBB()); - geometryLayer.onTileCreated(geometryLayer, parent, node); + geometryLayer.onTileCreated(node); return node; }); } diff --git a/src/Provider/PointCloudProvider.js b/src/Provider/PointCloudProvider.js index 20601899cd..96b32a2505 100644 --- a/src/Provider/PointCloudProvider.js +++ b/src/Provider/PointCloudProvider.js @@ -165,7 +165,6 @@ export default { layer.pointBudget = layer.pointBudget || 2000000; layer.pointSize = layer.pointSize === 0 || !isNaN(layer.pointSize) ? layer.pointSize : 4; layer.sseThreshold = layer.sseThreshold || 2; - layer.type = 'geometry'; layer.material = layer.material || {}; layer.material = layer.material.isMaterial ? layer.material : new PointsMaterial(layer.material); diff --git a/src/Renderer/ColorLayersOrdering.js b/src/Renderer/ColorLayersOrdering.js index bca62979fa..0df3348fff 100644 --- a/src/Renderer/ColorLayersOrdering.js +++ b/src/Renderer/ColorLayersOrdering.js @@ -1,4 +1,4 @@ -import { ImageryLayers } from '../Core/Layer/Layer'; +import { ImageryLayers } from '../Layer/Layer'; function updateLayersOrdering(geometryLayer, imageryLayers) { var sequence = ImageryLayers.getColorLayersIdOrderedBySequence(imageryLayers); diff --git a/test/pointcloudprocessing_unit_test.js b/test/pointcloudprocessing_unit_test.js index 537a7f32be..731ba1bac8 100644 --- a/test/pointcloudprocessing_unit_test.js +++ b/test/pointcloudprocessing_unit_test.js @@ -11,7 +11,7 @@ describe('preUpdate', function () { const sources = new Set(); assert.equal( layer.root, - PointCloudProcessing.preUpdate(context, layer, sources)[0]); + PointCloudProcessing.preUpdate.call(layer, context, sources)[0]); }); it('should return root if no common ancestors', () => { @@ -23,7 +23,7 @@ describe('preUpdate', function () { sources.add(elt2); assert.equal( layer.root, - PointCloudProcessing.preUpdate(context, layer, sources)[0]); + PointCloudProcessing.preUpdate.call(layer, context, sources)[0]); }); it('should return common ancestor', () => {