Skip to content

Commit

Permalink
Merge pull request #740 from geoadmin/bug-PB-361-external-layer
Browse files Browse the repository at this point in the history
PB-361: Divers External Layers bug fixes
  • Loading branch information
ltshb authored Mar 27, 2024
2 parents ef4ccae + eb37dd9 commit c0b9916
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 120 deletions.
3 changes: 3 additions & 0 deletions src/api/layers/ExternalWMTSLayer.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default class ExternalWMTSLayer extends ExternalLayer {
* (e.g. metadata) are still loading. Default is `true`
* @param {CoordinateSystem[]} [externalWmtsData.availableProjections=[]] All projection that
* can be used to request this layer. Default is `[]`
* @param {ol/WMTS/Options} [externalWmtsData.options] WMTS Get Capabilities options
* @throws InvalidLayerDataError if no `externalWmtsData` is given or if it is invalid
*/
constructor(externalWmtsData) {
Expand All @@ -56,6 +57,7 @@ export default class ExternalWMTSLayer extends ExternalLayer {
legends = [],
isLoading = true,
availableProjections = [],
options = null,
} = externalWmtsData
super({
name,
Expand All @@ -75,5 +77,6 @@ export default class ExternalWMTSLayer extends ExternalLayer {
isLoading,
availableProjections,
})
this.options = options
}
}
18 changes: 13 additions & 5 deletions src/api/layers/WMSCapabilitiesParser.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,21 @@ export default class WMSCapabilitiesParser {
let availableProjections = [WGS84]
if (layer.CRS) {
availableProjections = layer.CRS.filter((crs) =>
allCoordinateSystems.some((projection) => projection.epsg === crs)
).map((crs) => allCoordinateSystems.find((projection) => projection.epsg === crs))
allCoordinateSystems.some((projection) => projection.epsg === crs.toUpperCase())
).map((crs) =>
allCoordinateSystems.find((projection) => projection.epsg === crs.toUpperCase())
)
}
// filtering out double inputs
availableProjections = availableProjections.filter(
(projection, index) => availableProjections.indexOf(projection) !== index
)
availableProjections = [...new Set(availableProjections)]
if (availableProjections.length === 0) {
const msg = `No projections found for layer ${layerId}`
if (!ignoreError) {
throw new CapabilitiesError(msg)
} else {
log.error(msg, layer)
}
}

return {
layerId,
Expand Down
40 changes: 40 additions & 0 deletions src/api/layers/WMTSCapabilitiesParser.class.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import WMTSCapabilities from 'ol/format/WMTSCapabilities'
import { optionsFromCapabilities } from 'ol/source/WMTS'
import proj4 from 'proj4'

import { LayerAttribution } from '@/api/layers/AbstractLayer.class'
Expand Down Expand Up @@ -102,6 +103,11 @@ export default class WMTSCapabilitiesParser {
return null
}

const options = optionsFromCapabilities(this, {
layer: attributes.layerId,
projection: projection.epsg,
})

return new ExternalWMTSLayer({
name: attributes.title,
opacity,
Expand All @@ -113,6 +119,8 @@ export default class WMTSCapabilitiesParser {
extent: attributes.extent,
legends: attributes.legends,
isLoading: false,
availableProjections: attributes.availableProjections,
options,
})
}

Expand Down Expand Up @@ -145,6 +153,7 @@ export default class WMTSCapabilitiesParser {
attributions: this._getLayerAttribution(layerId),
extent: this._getLayerExtent(layerId, layer, projection),
legends: this._getLegends(layerId, layer),
availableProjections: this._getAvailableProjections(layerId, layer, ignoreError),
}
}

Expand All @@ -161,6 +170,37 @@ export default class WMTSCapabilitiesParser {
return tileMatrixSet
}

_getAvailableProjections(layerId, layer, ignoreError) {
let availableProjections = []
if (layer.WGS84BoundingBox?.length) {
availableProjections.push(WGS84)
}

// Take the projections defined in BoundingBox
availableProjections.push(
...(layer.BoundingBox?.map((bbox) => parseCrs(bbox.crs)).filter(
(projection) => !!projection
) ?? [])
)

// Take the available projections from the tile matrix set
availableProjections.push(
parseCrs(this._findTileMatrixSetFromLinks(layer.TileMatrixSetLink)?.SupportedCRS)
)

// Remove duplicates
availableProjections = [...new Set(availableProjections)]

if (availableProjections.length === 0) {
const msg = `No projections found for layer ${layerId}`
if (!ignoreError) {
throw new CapabilitiesError(msg)
}
log.error(msg, layer)
}
return availableProjections
}

_getLayerExtent(layerId, layer, projection) {
// TODO PB-243 handling of extent out of projection bound (currently not properly handled)
let layerExtent = null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<script setup>
/** Renders a WMTS layer on the map by configuring it through a getCapabilities XML file */
import WMTSCapabilities from 'ol/format/WMTSCapabilities'
import { Tile as TileLayer } from 'ol/layer'
import WMTS, { optionsFromCapabilities } from 'ol/source/WMTS'
import WMTS from 'ol/source/WMTS'
import { computed, inject, onMounted, toRefs, watch } from 'vue'
import { useStore } from 'vuex'
Expand Down Expand Up @@ -34,9 +33,8 @@ const projection = computed(() => store.state.position.projection)
// extracting useful info from what we've linked so far
const layerId = computed(() => externalWmtsLayerConfig.value.externalLayerId)
const opacity = computed(() => parentLayerOpacity.value || externalWmtsLayerConfig.value.opacity)
const getCapabilitiesUrl = computed(() => externalWmtsLayerConfig.value.baseUrl)
const options = computed(() => externalWmtsLayerConfig.value.options)
const wmtsGetCapParser = new WMTSCapabilities()
const layer = new TileLayer({
id: layerId.value,
opacity: opacity.value,
Expand All @@ -47,6 +45,7 @@ useAddLayerToMap(layer, olMap, zIndex)
watch(opacity, (newOpacity) => layer.setOpacity(newOpacity))
watch(projection, setSourceForProjection)
watch(options, setSourceForProjection)
onMounted(() => {
setSourceForProjection()
Expand All @@ -60,38 +59,16 @@ onMounted(() => {
* it)
*/
function setSourceForProjection() {
// fetching getCapabilities information in order to generate a proper layer config
fetch(getCapabilitiesUrl.value)
// parsing as text (as OL helper function want a string as input)
.then((response) => response.text())
.then((textResponse) => {
const getCapabilities = wmtsGetCapParser.read(textResponse)
if (getCapabilities.version) {
// filtering the whole getCap XML with the given layer ID
const options = optionsFromCapabilities(getCapabilities, {
layer: layerId.value,
projection: projection.value.epsg,
})
if (options) {
// finally setting the source with the options drawn from the getCapabilities helper function
// the layer might be shown on the map a little later than all the others because of that
layer.setSource(new WMTS(options))
} else {
log.error(
`Layer ${layerId.value} not found in WMTS Capabilities:`,
getCapabilities
)
}
} else {
log.error(`Invalid WMTS Capabilities:`, textResponse)
}
})
.catch((error) => {
log.error(
`Failed to fetch external WMTS layer from ${getCapabilitiesUrl.value}: ${error}`,
error
)
})
if (options.value) {
log.debug(
`Set WMTS source for layer ${layerId.value} with options ${JSON.stringify(options.value)}`
)
// finally setting the source with the options drawn from the getCapabilities helper function
// the layer might be shown on the map a little later than all the others because of that
layer.setSource(new WMTS(options.value))
} else {
log.debug(`No WMTS options for layer ${layerId.value} available yet`)
}
}
</script>

Expand Down
5 changes: 0 additions & 5 deletions src/modules/map/components/openlayers/OpenLayersMap.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<script setup>
import Map from 'ol/Map'
import { get as getProjection } from 'ol/proj'
import { register } from 'ol/proj/proj4'
import proj4 from 'proj4'
import { computed, onMounted, provide, ref } from 'vue'
import { useStore } from 'vuex'
Expand All @@ -24,9 +22,6 @@ import log from '@/utils/logging'
const dispatcher = { dispatcher: 'OpenLayersMap.vue' }
// register any custom projection in OpenLayers
register(proj4)
// setting the boundaries for projection, in the OpenLayers context, whenever bounds are defined
// this will help OpenLayers know when tiles shouldn't be requested because coordinates are out of bounds
allCoordinateSystems
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useStore } from 'vuex'

import {
CapabilitiesError,
EXTERNAL_SERVER_TIMEOUT,
parseWmsCapabilities,
parseWmtsCapabilities,
} from '@/api/layers/layers-external.api'
Expand Down Expand Up @@ -62,7 +63,7 @@ export function useCapabilities(newUrl) {
async function loadCapabilities() {
const fullUrl = guessExternalLayerUrl(url.value, lang.value).toString()
try {
const response = await axios.get(fullUrl, { timeout: 5000 })
const response = await axios.get(fullUrl, { timeout: EXTERNAL_SERVER_TIMEOUT })
if (response.status !== 200) {
throw new CapabilitiesError(
`Failed to fetch ${fullUrl}; status_code=${response.status}`,
Expand Down
7 changes: 7 additions & 0 deletions src/utils/coordinates/coordinateSystems.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { register } from 'ol/proj/proj4'
import proj4 from 'proj4'

import LV03CoordinateSystem from '@/utils/coordinates/LV03CoordinateSystem.class'
import LV95CoordinateSystem from '@/utils/coordinates/LV95CoordinateSystem.class'
import WebMercatorCoordinateSystem from '@/utils/coordinates/WebMercatorCoordinateSystem.class'
Expand All @@ -12,4 +15,8 @@ export const WEBMERCATOR = new WebMercatorCoordinateSystem()
/** Representation of many (available in this app) projection systems */
const allCoordinateSystems = [LV95, LV03, WGS84, WEBMERCATOR]
setupProj4(allCoordinateSystems)

// register any custom projection in OpenLayers
register(proj4)

export default allCoordinateSystems
2 changes: 0 additions & 2 deletions tests/cypress/fixtures/external-wms-getcap-2.fixture.xml
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,6 @@
<KeywordList>
<Keyword>ch.swisstopo-vd.spannungsarme-gebiete.wms_ows_keywordlist</Keyword>
</KeywordList>
<CRS>EPSG:2056</CRS>
<CRS>EPSG:21781</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:3857</CRS>
<CRS>EPSG:3034</CRS>
Expand Down
Loading

0 comments on commit c0b9916

Please sign in to comment.