Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PB-995: group all 3D background and visible layer into one component each #1127

Merged
merged 1 commit into from
Nov 15, 2024
Merged
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
26 changes: 26 additions & 0 deletions src/modules/map/components/cesium/CesiumBackgroundLayer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

import CesiumInternalLayer from '@/modules/map/components/cesium/CesiumInternalLayer.vue'

const store = useStore()

const backgroundLayersFor3D = computed(() => store.getters.backgroundLayersFor3D)
const projection = computed(() => store.state.position.projection)
</script>

<template>
<!--
z-index can be set to zero for all, as only the WMTS
background layer is an imagery layer (and requires one), all other BG layer are
primitive layer and will ignore this prop
-->
<CesiumInternalLayer
v-for="(bgLayer, index) in backgroundLayersFor3D"
:key="bgLayer.id"
:layer-config="bgLayer"
:projection="projection"
:z-index="index"
/>
</template>
73 changes: 6 additions & 67 deletions src/modules/map/components/cesium/CesiumMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,8 @@
@touchcancel="clearLongPressTimer"
@contextmenu="onContextMenu"
>
<div v-if="viewerCreated">
<!--
Adding background layer, z-index can be set to zero for all, as only the WMTS
background layer is an imagery layer (and requires one), all other BG layer are
primitive layer and will ignore this prop
-->
<CesiumInternalLayer
v-for="bgLayer in backgroundLayersFor3D"
:key="bgLayer.id"
:layer-config="bgLayer"
:projection="projection"
:z-index="0"
/>
<!--
Adding all other layers
Layers split between imagery and primitive type for correct zIndex ordering.
Only imagery layers require a z-index, we start to count them at 1 because of the
background WMTS layer
-->
<CesiumInternalLayer
v-for="(layer, index) in visibleImageryLayers"
:key="layer.id"
:layer-config="layer"
:projection="projection"
:z-index="index + startingZIndexForImageryLayers"
:is-time-slider-active="isTimeSliderActive"
/>
<CesiumInternalLayer
v-for="layer in visiblePrimitiveLayers"
:key="layer.id"
:layer-config="layer"
:projection="projection"
/>
</div>
<CesiumBackgroundLayer v-if="viewerCreated" />
<CesiumVisibleLayers v-if="viewerCreated" />
pakb marked this conversation as resolved.
Show resolved Hide resolved
<CesiumPopover
v-if="viewerCreated && showFeaturesPopover"
:coordinates="popoverCoordinates"
Expand Down Expand Up @@ -102,22 +70,18 @@ import proj4 from 'proj4'
import { mapActions, mapGetters, mapState } from 'vuex'

import { extractOlFeatureGeodesicCoordinates } from '@/api/features/features.api'
import ExternalLayer from '@/api/layers/ExternalLayer.class'
import GeoAdminAggregateLayer from '@/api/layers/GeoAdminAggregateLayer.class'
import GeoAdminGeoJsonLayer from '@/api/layers/GeoAdminGeoJsonLayer.class'
import GeoAdminWMSLayer from '@/api/layers/GeoAdminWMSLayer.class'
import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class'
import GPXLayer from '@/api/layers/GPXLayer.class'
import KMLLayer from '@/api/layers/KMLLayer.class'
import LayerTypes from '@/api/layers/LayerTypes.enum'
import { get3dTilesBaseUrl, getWmsBaseUrl, getWmtsBaseUrl } from '@/config/baseUrl.config'
import { DEFAULT_PROJECTION } from '@/config/map.config'
import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config'
import FeatureEdit from '@/modules/infobox/components/FeatureEdit.vue'
import FeatureList from '@/modules/infobox/components/FeatureList.vue'
import CesiumBackgroundLayer from '@/modules/map/components/cesium/CesiumBackgroundLayer.vue'
import CesiumGeolocationFeedback from '@/modules/map/components/cesium/CesiumGeolocationFeedback.vue'
import CesiumInternalLayer from '@/modules/map/components/cesium/CesiumInternalLayer.vue'
import CesiumPopover from '@/modules/map/components/cesium/CesiumPopover.vue'
import CesiumVisibleLayers from '@/modules/map/components/cesium/CesiumVisibleLayers.vue'
import {
CAMERA_MAX_PITCH,
CAMERA_MAX_ZOOM_DISTANCE,
Expand Down Expand Up @@ -145,12 +109,13 @@ import { wrapDegrees } from '@/utils/numberUtils.js'
const dispatcher = { dispatcher: 'CesiumMap.vue' }
export default {
components: {
CesiumVisibleLayers,
CesiumBackgroundLayer,
CesiumGeolocationFeedback,
FontAwesomeIcon,
CesiumPopover,
FeatureEdit,
FeatureList,
CesiumInternalLayer,
},
provide() {
return {
Expand All @@ -172,7 +137,6 @@ export default {
cameraPosition: (state) => state.position.camera,
uiMode: (state) => state.ui.mode,
projection: (state) => state.position.projection,
isFullScreenMode: (state) => state.ui.fullscreenMode,
isTimeSliderActive: (state) => state.ui.isTimeSliderActive,
layersConfig: (state) => state.layers.config,
}),
Expand All @@ -182,7 +146,6 @@ export default {
'resolution',
'hasDevSiteWarning',
'visibleLayers',
'backgroundLayersFor3D',
'showFeatureInfoInTooltip',
]),
isProjectionWebMercator() {
Expand All @@ -191,25 +154,6 @@ export default {
isDesktopMode() {
return this.uiMode === UIModes.DESKTOP
},
visibleImageryLayers() {
return this.visibleLayers
.filter(
(l) =>
l instanceof GeoAdminWMTSLayer ||
l instanceof GeoAdminWMSLayer ||
l instanceof GeoAdminAggregateLayer ||
l instanceof ExternalLayer
)
.map((visibleLayer) => {
if (visibleLayer.idIn3d) {
return (
this.layersConfig.find((layer) => layer.id === visibleLayer.idIn3d) ??
visibleLayer
)
}
return visibleLayer
})
},
isFeatureInfoInTooltip() {
return this.showFeatureInfoInTooltip
},
Expand All @@ -227,11 +171,6 @@ export default {
editFeature() {
return this.selectedFeatures.find((feature) => feature.isEditable)
},
startingZIndexForImageryLayers() {
return this.backgroundLayersFor3D.find((layer) => layer.type === LayerTypes.WMTS)
? 1
: 0
},
},
watch: {
selectedFeatures: {
Expand Down
21 changes: 5 additions & 16 deletions src/modules/map/components/cesium/CesiumVectorLayer.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script setup>
import { computed, inject, onBeforeUnmount, onMounted, toRefs } from 'vue'
import { Cesium3DTileset } from 'cesium'
import { computed, inject, toRefs } from 'vue'

import GeoAdmin3DLayer from '@/api/layers/GeoAdmin3DLayer.class'
import { loadTileSetAndApplyStyle } from '@/modules/map/components/cesium/utils/primitiveLayerUtils'
import useAddPrimitiveLayer from '@/modules/map/components/cesium/utils/useAddPrimitiveLayer.composable'

const props = defineProps({
layerConfig: {
Expand All @@ -29,20 +30,8 @@ const url = computed(() => {
return `${baseUrl.value}${rootFolder}${layerId.value}${timeFolder}/tileset.json`
})

let layer

onMounted(async () => {
layer = getViewer().scene.primitives.add(
await loadTileSetAndApplyStyle(url.value, {
withEnhancedLabelStyle: layerId.value === 'ch.swisstopo.swissnames3d.3d',
})
)
})
onBeforeUnmount(() => {
const viewer = getViewer()
layer.show = false
viewer.scene.primitives.remove(layer)
viewer.scene.requestRender()
useAddPrimitiveLayer(getViewer(), Cesium3DTileset.fromUrl(url.value), {
withEnhancedLabelStyle: layerId.value === 'ch.swisstopo.swissnames3d.3d',
})
</script>

Expand Down
74 changes: 74 additions & 0 deletions src/modules/map/components/cesium/CesiumVisibleLayers.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

import ExternalLayer from '@/api/layers/ExternalLayer.class'
import GeoAdminAggregateLayer from '@/api/layers/GeoAdminAggregateLayer.class'
import GeoAdminGeoJsonLayer from '@/api/layers/GeoAdminGeoJsonLayer.class'
import GeoAdminWMSLayer from '@/api/layers/GeoAdminWMSLayer.class'
import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class'
import GPXLayer from '@/api/layers/GPXLayer.class'
import KMLLayer from '@/api/layers/KMLLayer.class'
import CesiumInternalLayer from '@/modules/map/components/cesium/CesiumInternalLayer.vue'

const store = useStore()

const visibleLayers = computed(() => store.getters.visibleLayers)
const layersConfig = computed(() => store.state.layers.config)
const projection = computed(() => store.state.position.projection)
const backgroundLayersFor3D = computed(() => store.getters.backgroundLayersFor3D)

const visibleImageryLayers = computed(() =>
visibleLayers.value.filter(isImageryLayer).map((imageryLayer) => {
if (imageryLayer.idIn3d) {
return (
layersConfig.value.find((layer) => layer.id === imageryLayer.idIn3d) ?? imageryLayer
)
}
return imageryLayer
})
)
const visiblePrimitiveLayers = computed(() => visibleLayers.value.filter(isPrimitiveLayer))

const startingZIndexForImageryLayers = computed(
() => backgroundLayersFor3D.value.filter(isImageryLayer).length
)

function isImageryLayer(layer) {
return (
layer instanceof GeoAdminWMTSLayer ||
layer instanceof GeoAdminWMSLayer ||
layer instanceof GeoAdminAggregateLayer ||
layer instanceof ExternalLayer
)
}

function isPrimitiveLayer(layer) {
return (
layer instanceof GeoAdminGeoJsonLayer ||
layer instanceof KMLLayer ||
layer instanceof GPXLayer
)
}
</script>

<template>
<!--
Layers split between imagery and primitive type for correct zIndex ordering.
Only imagery layers require a z-index, we start to count them at 1 or 0 depending on the
background WMTS layer
-->
<CesiumInternalLayer
v-for="(layer, index) in visibleImageryLayers"
:key="layer.id"
:layer-config="layer"
:projection="projection"
:z-index="index + startingZIndexForImageryLayers"
/>
<CesiumInternalLayer
v-for="layer in visiblePrimitiveLayers"
:key="layer.id"
:layer-config="layer"
:projection="projection"
/>
</template>
83 changes: 83 additions & 0 deletions src/modules/map/components/cesium/utils/enhanceLabelStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Cesium3DTileStyle } from 'cesium'

/**
* Style to apply to our labels in 3D. It is a complete rip-off of
* https://github.com/geoadmin/mf-geoadmin3/blob/6a7b99a2cc9980eec27b394ee709305a239549f1/src/components/StylesService.js#L159-L233
*
* @type {Cesium3DTileStyle}
*/
export default new Cesium3DTileStyle({
show: true,
labelStyle: 2,
labelText: '${DISPLAY_TEXT}',
disableDepthTestDistance: Number.POSITIVE_INFINITY,
anchorLineEnabled: true,
anchorLineColor: "color('white')",
heightOffset: {
conditions: [
['${LOD} === "7"', 20],
['${LOD} === "6"', 40],
['${LOD} === "5"', 60],
['${LOD} === "4"', 80],
['${LOD} === "3"', 100],
['${LOD} === "2"', 120],
['${LOD} === "1"', 150],
['${LOD} === "0"', 200],
['true', '200'],
],
},
labelColor: {
conditions: [
['${OBJEKTART} === "See"', 'color("blue")'],
['true', 'color("black")'],
],
},
labelOutlineColor: 'color("white", 1)',
labelOutlineWidth: 5,
font: {
conditions: [
['${OBJEKTART} === "See"', '"bold 32px arial"'],
['${OBJEKTART} === "Alpiner Gipfel"', '"italic 32px arial"'],
['true', '" 32px arial"'],
],
},
scaleByDistance: {
conditions: [
['${LOD} === "7"', 'vec4(1000, 1, 5000, 0.4)'],
['${LOD} === "6"', 'vec4(1000, 1, 5000, 0.4)'],
['${LOD} === "5"', 'vec4(1000, 1, 8000, 0.4)'],
['${LOD} === "4"', 'vec4(1000, 1, 10000, 0.4)'],
['${LOD} === "3"', 'vec4(1000, 1, 20000, 0.4)'],
['${LOD} === "2"', 'vec4(1000, 1, 30000, 0.4)'],
['${LOD} === "1"', 'vec4(1000, 1, 50000, 0.4)'],
['${LOD} === "0"', 'vec4(1000, 1, 500000, 0.4)'],
['true', 'vec4(1000, 1, 10000, 0.4)'],
],
},
translucencyByDistance: {
conditions: [
['${LOD} === "7"', 'vec4(5000, 1, 5001, 1)'],
['${LOD} === "6"', 'vec4(5000, 1, 5001, 1)'],
['${LOD} === "5"', 'vec4(5000, 1, 8000, 0.4)'],
['${LOD} === "4"', 'vec4(5000, 1, 10000, 0.4)'],
['${LOD} === "3"', 'vec4(5000, 1, 20000, 0.4)'],
['${LOD} === "2"', 'vec4(5000, 1, 30000, 0.4)'],
['${LOD} === "1"', 'vec4(5000, 1, 50000, 0.4)'],
['${LOD} === "0"', 'vec4(5000, 1, 500000, 1)'],
['true', 'vec4(5000, 1, 10000, 0.5)'],
],
},
distanceDisplayCondition: {
conditions: [
['${LOD} === "7"', 'vec2(0, 5000)'],
['${LOD} === "6"', 'vec2(0, 5000)'],
['${LOD} === "5"', 'vec2(0, 8000)'],
['${LOD} === "4"', 'vec2(0, 10000)'],
['${LOD} === "3"', 'vec2(0, 20000)'],
['${LOD} === "2"', 'vec2(0, 30000)'],
['${LOD} === "1"', 'vec2(0, 50000)'],
['${LOD} === "0"', 'vec2(0, 500000)'],
['${OBJEKTART} === "Alpiner Gipfel"', 'vec2(0, 100000)'],
],
},
})
Loading
Loading