diff --git a/src/ol/source/WMTS.js b/src/ol/source/WMTS.js index e938f77d08..e378d9e02c 100644 --- a/src/ol/source/WMTS.js +++ b/src/ol/source/WMTS.js @@ -449,22 +449,41 @@ export function optionsFromCapabilities(wmtsCap, config) { } const wrapX = false; + const switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne'; + + let matrix = matrixSetObj.TileMatrix[0]; + + // create default matrixLimit + let selectedMatrixLimit = { + MinTileCol: 0, + MinTileRow: 0, + // substract one to end up at tile top left + MaxTileCol: matrix.MatrixWidth - 1, + MaxTileRow: matrix.MatrixHeight - 1, + }; + + //in case of matrix limits, use matrix limits to calculate extent + if (matrixLimits) { + selectedMatrixLimit = matrixLimits[matrixLimits.length - 1]; + matrix = matrixSetObj.TileMatrix.find( + (value) => value.Identifier === selectedMatrixLimit.TileMatrix + ); + } - const matrix0 = matrixSetObj.TileMatrix[0]; const resolution = - (matrix0.ScaleDenominator * 0.00028) / projection.getMetersPerUnit(); // WMTS 1.0.0: standardized rendering pixel size - const origin = - projection === getProjection('EPSG:4326') - ? [matrix0.TopLeftCorner[1], matrix0.TopLeftCorner[0]] - : matrix0.TopLeftCorner; - const tileSpanX = matrix0.TileWidth * resolution; - const tileSpanY = matrix0.TileHeight * resolution; + (matrix.ScaleDenominator * 0.00028) / projection.getMetersPerUnit(); // WMTS 1.0.0: standardized rendering pixel size + const origin = switchOriginXY + ? [matrix.TopLeftCorner[1], matrix.TopLeftCorner[0]] + : matrix.TopLeftCorner; + const tileSpanX = matrix.TileWidth * resolution; + const tileSpanY = matrix.TileHeight * resolution; const extent = [ - origin[0], - origin[1] - tileSpanY * matrix0.MatrixHeight, - origin[0] + tileSpanX * matrix0.MatrixWidth, - origin[1], + origin[0] + tileSpanX * selectedMatrixLimit.MinTileCol, + // add one to get proper bottom/right coordinate + origin[1] - tileSpanY * (1 + selectedMatrixLimit.MaxTileRow), + origin[0] + tileSpanX * (1 + selectedMatrixLimit.MaxTileCol), + origin[1] - tileSpanY * selectedMatrixLimit.MinTileRow, ]; if (projection.getExtent() === null) { diff --git a/test/spec/ol/format/wmts/capabilities_wgs84.xml b/test/spec/ol/format/wmts/capabilities_wgs84.xml index 489ff5f5c8..ff9fdbf968 100644 --- a/test/spec/ol/format/wmts/capabilities_wgs84.xml +++ b/test/spec/ol/format/wmts/capabilities_wgs84.xml @@ -39,100 +39,7 @@ image/png - inspire_quad - - - 0 - 0 - 1 - 0 - 2 - - - 1 - 0 - 2 - 0 - 4 - - - 2 - 0 - 4 - 0 - 8 - - - 3 - 0 - 8 - 0 - 16 - - - 4 - 0 - 16 - 0 - 32 - - - 5 - 0 - 32 - 0 - 64 - - - 6 - 0 - 64 - 0 - 128 - - - 7 - 0 - 128 - 0 - 256 - - - 8 - 0 - 256 - 0 - 512 - - - 9 - 0 - 512 - 0 - 1024 - - - 10 - 0 - 1024 - 0 - 2048 - - - 11 - 0 - 2048 - 0 - 4096 - - - 12 - 0 - 4096 - 0 - 8192 - - + inspire_quad diff --git a/test/spec/ol/format/wmts/capabilities_with_tilematrixsetlink.xml b/test/spec/ol/format/wmts/capabilities_with_tilematrixsetlink.xml new file mode 100644 index 0000000000..67bbc0cfc9 --- /dev/null +++ b/test/spec/ol/format/wmts/capabilities_with_tilematrixsetlink.xml @@ -0,0 +1,284 @@ + + + + Sample WMTS + OGC WMTS + 1.0.0 + None + none + + + + + + + + + + + + + + + + + + Baselayer + Baselayer + baselayer + + -180.0 -90.0 + 180.0 90.0 + + + -90.0 -180.0 + 90.0 180.0 + + + image/png + + inspire_quad + + + + + Mean depth full coverage with land coverage + + mean_atlas_land + + -36.0 15.0 + 43.0 90.0 + + + 14.999942759061003 -36.0 + 90.0 42.999938986416 + + + image/png + + inspire_quad + + + 0 + 0 + 0 + 0 + 1 + + + 1 + 0 + 0 + 1 + 2 + + + 2 + 0 + 1 + 3 + 4 + + + 3 + 0 + 3 + 6 + 9 + + + 4 + 0 + 6 + 12 + 19 + + + 5 + 0 + 13 + 25 + 39 + + + 6 + 0 + 26 + 51 + 79 + + + 7 + 0 + 53 + 102 + 158 + + + 8 + 0 + 106 + 204 + 317 + + + 9 + 0 + 213 + 409 + 634 + + + 10 + 0 + 426 + 819 + 1268 + + + 11 + 0 + 853 + 1638 + 2537 + + + 12 + 0 + 1706 + 3276 + 5074 + + + + + + + InspireCRS84Quad + inspire_quad + urn:ogc:def:crs:EPSG::4326 + + 0 + 279541132.014357 + 90.0 -180.0 + 256 + 256 + 2 + 1 + + + 1 + 1.3977056600717938E8 + 90.0 -180.0 + 256 + 256 + 4 + 2 + + + 2 + 6.988528300358969E7 + 90.0 -180.0 + 256 + 256 + 8 + 4 + + + 3 + 3.4942641501794845E7 + 90.0 -180.0 + 256 + 256 + 16 + 8 + + + 4 + 1.7471320750897422E7 + 90.0 -180.0 + 256 + 256 + 32 + 16 + + + 5 + 8735660.375448711 + 90.0 -180.0 + 256 + 256 + 64 + 32 + + + 6 + 4367830.187724356 + 90.0 -180.0 + 256 + 256 + 128 + 64 + + + 7 + 2183915.093862178 + 90.0 -180.0 + 256 + 256 + 256 + 128 + + + 8 + 1091957.546931089 + 90.0 -180.0 + 256 + 256 + 512 + 256 + + + 9 + 545978.7734655445 + 90.0 -180.0 + 256 + 256 + 1024 + 512 + + + 10 + 272989.3867327722 + 90.0 -180.0 + 256 + 256 + 2048 + 1024 + + + 11 + 136494.6933663861 + 90.0 -180.0 + 256 + 256 + 4096 + 2048 + + + 12 + 68247.34668319306 + 90.0 -180.0 + 256 + 256 + 8192 + 4096 + + + + + diff --git a/test/spec/ol/source/wmts.test.js b/test/spec/ol/source/wmts.test.js index 569ec55fd4..d6e47a405d 100644 --- a/test/spec/ol/source/wmts.test.js +++ b/test/spec/ol/source/wmts.test.js @@ -406,6 +406,69 @@ describe('ol.source.WMTS', function () { }); }); + describe('when creating options from capabilities with TileMatrixSetLink', function () { + const parser = new WMTSCapabilities(); + let capabilities; + before(function (done) { + afterLoadText( + 'spec/ol/format/wmts/capabilities_with_tilematrixsetlink.xml', + function (xml) { + try { + capabilities = parser.read(xml); + } catch (e) { + done(e); + } + done(); + } + ); + }); + + it('returns correct bounding box for a layer', function () { + const options = optionsFromCapabilities(capabilities, { + layer: 'mean_atlas_land', + matrixSet: 'inspire_quad', + requestEncoding: 'REST', + }); + + expect(options.urls).to.be.an('array'); + expect(options.urls).to.have.length(1); + expect(options.urls[0]).to.be.eql( + 'https://example.com/wmts/mean_atlas_land/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.png' + ); + + expect(options.layer).to.be.eql('mean_atlas_land'); + + expect(options.matrixSet).to.be.eql('inspire_quad'); + + expect(options.format).to.be.eql('image/png'); + + expect(options.projection).to.be.a(Projection); + expect(options.projection).to.be.eql(getProjection('EPSG:4326')); + + expect(options.requestEncoding).to.be.eql('REST'); + + expect(options.tileGrid).to.be.a(WMTSTileGrid); + expect(options.style).to.be.eql('default'); + + const extent = options.tileGrid.getExtent(); + + // calculate with of one tile, this will be used as tolerance for result extent + const tile_width = + ((68247.34668319306 * 0.00028) / + getProjection('EPSG:4326').getMetersPerUnit()) * + 256; + + // compare with delta, due to rounding not the exact bounding box is returned... + const expectDelta = (value, expected) => + expect(Math.abs(value - expected)).to.below(tile_width + 1e-10); + + expectDelta(extent[0], -36); + expectDelta(extent[1], 15); + expectDelta(extent[2], 43); + expectDelta(extent[3], 90); + }); + }); + describe('#setUrls()', function () { it('sets the URL for the source', function () { const source = new WMTS({});