Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import React from 'react';
import PropTypes from 'prop-types';
import { FormGroup, ControlLabel, InputGroup } from 'react-bootstrap';
import { FormGroup, ControlLabel, InputGroup, Checkbox } from 'react-bootstrap';
import DebouncedFormControl from '../../../misc/DebouncedFormControl';
import Message from '../../../I18N/Message';
import PointCloudShadingSettings from './PointCloudShadingSettings';
Expand All @@ -29,6 +29,15 @@ function ThreeDTilesSettings({
}
return (
<div style={{ margin: '0 -8px' }}>
<FormGroup className="form-group-flex">
<Checkbox
key="enableImageryOverlay"
checked={layer.enableImageryOverlay === undefined ? false : layer.enableImageryOverlay}
onChange={(event) => onChange("enableImageryOverlay", event.target.checked)}
>
<Message msgId="layerProperties.3dTiles.enableImageryOverlay"/>
</Checkbox>
</FormGroup>
<FormGroup className="form-group-flex">
<ControlLabel><Message msgId="layerProperties.3dTiles.format"/></ControlLabel>
<InputGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('ThreeDTilesSettings', () => {
}}/>, document.getElementById('container'));
const checkboxNodes = document.querySelectorAll('.checkbox');
expect([...checkboxNodes].map(node => node.innerText)).toEqual([
'layerProperties.3dTiles.enableImageryOverlay',
'layerProperties.3dTiles.pointCloudShading.attenuation',
'layerProperties.3dTiles.pointCloudShading.eyeDomeLighting'
]);
Expand Down
42 changes: 28 additions & 14 deletions web/client/components/map/cesium/Layer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ class CesiumLayer extends React.Component {
onCreationError: PropTypes.func,
position: PropTypes.number,
securityToken: PropTypes.string,
zoom: PropTypes.number
zoom: PropTypes.number,
imageryLayersTreeUpdatedCount: PropTypes.number,
onImageryLayersTreeUpdate: PropTypes.func
};

componentDidMount() {
Expand All @@ -33,6 +35,9 @@ class CesiumLayer extends React.Component {
if (this.props.options && this.layer && visibility) {
this.addLayer(this.props);
this.updateZIndex();
if (this.provider) {
this.props.onImageryLayersTreeUpdate();
}
}
}

Expand All @@ -48,6 +53,7 @@ class CesiumLayer extends React.Component {
if (this.provider) {
this.provider._position = newProps.position;
}
this.props.onImageryLayersTreeUpdate();
}
if (this.props.options && this.props.options.params && this.layer.updateParams && newProps.options.visibility) {
const changed = Object.keys(this.props.options.params).reduce((found, param) => {
Expand All @@ -64,7 +70,6 @@ class CesiumLayer extends React.Component {
setTimeout(() => {
this.removeLayer(oldProvider);
}, 1000);

}
}
this.updateLayer(newProps, this.props);
Expand All @@ -77,11 +82,7 @@ class CesiumLayer extends React.Component {
if (this.layer.detached && this.layer?.remove) {
this.layer.remove();
} else {
if (this.layer.destroy) {
this.layer.destroy();
}

this.props.map.imageryLayers.remove(this.provider);
this.removeLayer();
}
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
Expand Down Expand Up @@ -159,12 +160,17 @@ class CesiumLayer extends React.Component {

setImageryLayerVisibility = (visibility, props) => {
// this type of layer will be added and removed from the imageryLayers array of Cesium
if (visibility) {
this.addLayer(props);
this.updateZIndex();
if (!this.provider) {
if (visibility) {
this.addLayer(props);
this.updateZIndex();
return;
}
this.removeLayer();
return;
}
this.removeLayer();
// use the native show property to avoid re-creation of an imagery layer
this.provider.show = !!visibility;
return;
}

Expand Down Expand Up @@ -205,7 +211,7 @@ class CesiumLayer extends React.Component {
};

setLayerOpacity = (opacity) => {
var oldOpacity = this.props.options && this.props.options.opacity !== undefined ? this.props.options.opacity : 1.0;
const oldOpacity = this.props.options && this.props.options.opacity !== undefined ? this.props.options.opacity : 1.0;
if (opacity !== oldOpacity && this.layer && this.provider) {
this.provider.alpha = opacity;
this.props.map.scene.requestRender();
Expand Down Expand Up @@ -244,12 +250,16 @@ class CesiumLayer extends React.Component {
{
...newProps.options,
securityToken: newProps.securityToken,
forceProxy: this._isProxy
forceProxy: this._isProxy,
imageryLayersTreeUpdatedCount: newProps.imageryLayersTreeUpdatedCount,
position: newProps.position
},
{
...oldProps.options,
securityToken: oldProps.securityToken,
forceProxy: this._prevIsProxy
forceProxy: this._prevIsProxy,
imageryLayersTreeUpdatedCount: oldProps.imageryLayersTreeUpdatedCount,
position: oldProps.position
},
this.props.map);
if (newLayer) {
Expand Down Expand Up @@ -311,9 +321,13 @@ class CesiumLayer extends React.Component {
}

removeLayer = (provider) => {
if (this.layer.destroy) {
this.layer.destroy();
}
const toRemove = provider || this.provider;
if (toRemove) {
this.props.map.imageryLayers.remove(toRemove);
this.props.onImageryLayersTreeUpdate();
}
// detached layers are layers that do not work through a provider
// for this reason they cannot be added or removed from the map imageryProviders
Expand Down
14 changes: 11 additions & 3 deletions web/client/components/map/cesium/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
getResolutions
} from '../../../utils/MapUtils';
import { reprojectBbox } from '../../../utils/CoordinatesUtils';
import { throttle, isEqual } from 'lodash';
import { throttle, isEqual, debounce } from 'lodash';

class CesiumMap extends React.Component {
static propTypes = {
Expand Down Expand Up @@ -81,7 +81,8 @@ class CesiumMap extends React.Component {
};

state = {
renderError: null
renderError: null,
imageryLayersTreeUpdatedCount: 0
};

UNSAFE_componentWillMount() {
Expand Down Expand Up @@ -194,6 +195,7 @@ class CesiumMap extends React.Component {
this.updateLighting({}, this.props);
this.forceUpdate();
map.scene.requestRender();

}

UNSAFE_componentWillReceiveProps(newProps) {
Expand Down Expand Up @@ -451,7 +453,13 @@ class CesiumMap extends React.Component {
map: map,
projection: mapProj,
onCreationError: this.props.onCreationError,
zoom: this.props.zoom
zoom: this.props.zoom,
imageryLayersTreeUpdatedCount: this.state.imageryLayersTreeUpdatedCount,
onImageryLayersTreeUpdate: debounce(() =>
this.setState(({ imageryLayersTreeUpdatedCount }) => ({
imageryLayersTreeUpdatedCount: imageryLayersTreeUpdatedCount + 1
})),
50)
}) : null;
}) : null;
const ErrorPanel = this.props.errorPanel;
Expand Down
103 changes: 70 additions & 33 deletions web/client/components/map/cesium/plugins/ThreeDTilesLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@ function clip3DTiles(tileSet, options, map) {
});
}

const applyImageryLayers = (tileSet, options, map) => {
if (!options.enableImageryOverlay || !tileSet || tileSet.isDestroyed()) return;
// Collect map layers that should be applied to primitive
const mapLayers = [];
for (let i = 0; i < map.imageryLayers.length; i++) {
const layer = map.imageryLayers.get(i);
if (layer._position > options.position) {
mapLayers.push(layer);
}
}
// Add layers in the correct order
mapLayers.forEach((layer, idx) => {
const current = tileSet.imageryLayers.get(idx);
if (current !== layer) {
tileSet.imageryLayers.add(layer);
}
});
map.scene.requestRender();
};

let pendingCallbacks = {};

function ensureReady(layer, callback, eventKey) {
Expand Down Expand Up @@ -130,53 +150,66 @@ const createLayer = (options, map) => {
let promise;
const removeTileset = () => {
updateGooglePhotorealistic3DTilesBrandLogo(map, options, tileSet);
tileSet.imageryLayers.removeAll(false);
map.scene.primitives.remove(tileSet);
tileSet = undefined;
};
const layer = {
getTileSet: () => tileSet,
getResource: () => resource
};

let timeout = undefined;

return {
detached: true,
...layer,
add: () => {
resource = new Cesium.Resource({
url: options.url,
proxy: options.forceProxy ? new Cesium.DefaultProxy(getProxyUrl()) : undefined
// TODO: axios supports also adding access tokens or credentials (e.g. authkey, Authentication header ...).
// if we want to use internal cesium functionality to retrieve data
// we need to create a utility to set a CesiumResource that applies also this part.
// in addition to this proxy.
});
promise = Cesium.Cesium3DTileset.fromUrl(resource,
{
showCreditsOnScreen: true
}
).then((_tileSet) => {
tileSet = _tileSet;
updateGooglePhotorealistic3DTilesBrandLogo(map, options, tileSet);
map.scene.primitives.add(tileSet);
// assign the original mapstore id of the layer
tileSet.msId = options.id;
ensureReady(layer, () => {
updateModelMatrix(tileSet, options);
clip3DTiles(tileSet, options, map);
updateShading(tileSet, options, map);
getStyle(options)
.then((style) => {
if (style) {
tileSet.style = new Cesium.Cesium3DTileStyle(style);
}
Object.keys(pendingCallbacks).forEach((eventKey) => {
pendingCallbacks[eventKey](tileSet);
// delay creation of tileset when frequents recreation are requested
timeout = setTimeout(() => {
timeout = undefined;
resource = new Cesium.Resource({
url: options.url,
proxy: options.forceProxy ? new Cesium.DefaultProxy(getProxyUrl()) : undefined
// TODO: axios supports also adding access tokens or credentials (e.g. authkey, Authentication header ...).
// if we want to use internal cesium functionality to retrieve data
// we need to create a utility to set a CesiumResource that applies also this part.
// in addition to this proxy.
});
promise = Cesium.Cesium3DTileset.fromUrl(resource,
{
showCreditsOnScreen: true
}
).then((_tileSet) => {
tileSet = _tileSet;
updateGooglePhotorealistic3DTilesBrandLogo(map, options, tileSet);
map.scene.primitives.add(tileSet);
// assign the original mapstore id of the layer
tileSet.msId = options.id;
ensureReady(layer, () => {
updateModelMatrix(tileSet, options);
clip3DTiles(tileSet, options, map);
updateShading(tileSet, options, map);
getStyle(options)
.then((style) => {
if (style) {
tileSet.style = new Cesium.Cesium3DTileStyle(style);
}
Object.keys(pendingCallbacks).forEach((eventKey) => {
pendingCallbacks[eventKey](tileSet);
});
pendingCallbacks = {};
applyImageryLayers(tileSet, options, map);
});
pendingCallbacks = {};
});
});
});
});
}, 50);
},
remove: () => {
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
if (tileSet) {
removeTileset();
return;
Expand All @@ -194,7 +227,11 @@ const createLayer = (options, map) => {
Layers.registerType('3dtiles', {
create: createLayer,
update: function(layer, newOptions, oldOptions, map) {
if (newOptions.forceProxy !== oldOptions.forceProxy) {
if (newOptions.forceProxy !== oldOptions.forceProxy
// recreate the tileset when the imagery has been updated and the layer has enableImageryOverlay set to true
|| newOptions.enableImageryOverlay && (newOptions.imageryLayersTreeUpdatedCount !== oldOptions.imageryLayersTreeUpdatedCount)
|| (newOptions.enableImageryOverlay && !oldOptions.enableImageryOverlay)
) {
return createLayer(newOptions, map);
}
if (
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.ca-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@
"eyeDomeLighting": "Activa la il\u00b7luminaci\u00f3",
"eyeDomeLightingStrength": "For\u00e7a d\u2019il\u00b7luminaci\u00f3",
"eyeDomeLightingRadius": "Radi d\u2019il\u00b7luminaci\u00f3"
}
},
"enableImageryOverlay": "Habilita la superposició d’imatges"
},
"modelLayer": {
"modelCenterLat": "Latitude Center (DD)",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"eyeDomeLighting": "Beleuchtung aktivieren",
"eyeDomeLightingStrength": "Lichtstärke",
"eyeDomeLightingRadius": "Beleuchtungsradius"
}
},
"enableImageryOverlay": "Bildüberlagerung aktivieren"
},
"modelLayer": {
"modelCenterLat": "Breitengrad des Zentrums (DD)",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"eyeDomeLighting": "Enable lighting",
"eyeDomeLightingStrength": "Lighting strength",
"eyeDomeLightingRadius": "Lighting radius"
}
},
"enableImageryOverlay": "Enable imagery overlay"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should explain a bit more, e.g.

Suggested change
"enableImageryOverlay": "Enable imagery overlay"
"enableImageryOverlay": "Enable imagery layers overlay"

I think we should add an inline question mark icon info with additional information explaining that all the imagery layers such as WMS, TMS, WMTS, ... positioned above the 3D Tiles will be rendered in order on top of it.

Please use the same component already used for other checkbox in settings, e.g. this is visible for WMS

image

},
"modelLayer": {
"modelCenterLat": "Center's Latitude (DD)",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@
"eyeDomeLighting": "Habilitar iluminación",
"eyeDomeLightingStrength": "Intensidad de iluminación",
"eyeDomeLightingRadius": "Radio de iluminación"
}
},
"enableImageryOverlay": "Habilitar la superposición de imágenes"
},
"modelLayer": {
"modelCenterLat": "Latitud del centro (DD)",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"eyeDomeLighting": "Activer l'éclairage",
"eyeDomeLightingStrength": "Force d'éclairage",
"eyeDomeLightingRadius": "Rayon d'éclairage"
}
},
"enableImageryOverlay": "Activer la superposition d’images"
},
"modelLayer": {
"modelCenterLat": "Latitude du centre (DD)",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"eyeDomeLighting": "Abilita illuminazione",
"eyeDomeLightingStrength": "Intensità luminosa",
"eyeDomeLightingRadius": "Raggio di illuminazione"
}
},
"enableImageryOverlay": "Abilita la sovrapposizione delle immagini"
},
"modelLayer": {
"modelCenterLat": "Latitudine del centro (DD)",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
"eyeDomeLighting": "Activeer belichting",
"eyeDomeLightingStrength": "Belichtingssterkte",
"eyeDomeLightingRadius": "Belichtingsradius"
}
},
"enableImageryOverlay": "Beeldoverlay inschakelen"
},
"modelLayer": {
"modelCenterLat": "Breedtegraad centrum (DD)",
Expand Down
Loading
Loading