diff --git a/src/ol/format/wmtscapabilities.js b/src/ol/format/wmtscapabilities.js index e2d6369b59..4b47829cc9 100644 --- a/src/ol/format/wmtscapabilities.js +++ b/src/ol/format/wmtscapabilities.js @@ -251,6 +251,32 @@ ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) { }; +/** + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} TileMatrixSetLimits Object. + */ +ol.format.WMTSCapabilities.readTileMatrixLimitsList_ = function(node, + objectStack) { + return ol.xml.pushParseAndPop([], + ol.format.WMTSCapabilities.TMS_LIMITS_LIST_PARSERS_, node, + objectStack); +}; + + +/** + * @private + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @return {Object|undefined} TileMatrixLimits Array. + */ +ol.format.WMTSCapabilities.readTileMatrixLimits_ = function(node, objectStack) { + return ol.xml.pushParseAndPop({}, + ol.format.WMTSCapabilities.TMS_LIMITS_PARSERS_, node, objectStack); +}; + + /** * @const * @private @@ -353,7 +379,40 @@ ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS( ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS( ol.format.WMTSCapabilities.NAMESPACE_URIS_, { 'TileMatrixSet': ol.xml.makeObjectPropertySetter( - ol.format.XSD.readString) + ol.format.XSD.readString), + 'TileMatrixSetLimits': ol.xml.makeObjectPropertySetter( + ol.format.WMTSCapabilities.readTileMatrixLimitsList_) + }); + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.WMTSCapabilities.TMS_LIMITS_LIST_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'TileMatrixLimits': ol.xml.makeArrayPusher( + ol.format.WMTSCapabilities.readTileMatrixLimits_) + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.WMTSCapabilities.TMS_LIMITS_PARSERS_ = ol.xml.makeStructureNS( + ol.format.WMTSCapabilities.NAMESPACE_URIS_, { + 'TileMatrix': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readString), + 'MinTileRow': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MaxTileRow': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MinTileCol': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'MaxTileCol': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger) }); diff --git a/src/ol/source/wmts.js b/src/ol/source/wmts.js index f88935677c..dc93580883 100644 --- a/src/ol/source/wmts.js +++ b/src/ol/source/wmts.js @@ -309,7 +309,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { ol.DEBUG && console.assert(l['TileMatrixSetLink'].length > 0, 'layer has TileMatrixSetLink'); var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet']; - var idx, matrixSet; + var idx, matrixSet, matrixLimits; if (l['TileMatrixSetLink'].length > 1) { if ('projection' in config) { idx = ol.array.findIndex(l['TileMatrixSetLink'], @@ -340,6 +340,8 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { } matrixSet = /** @type {string} */ (l['TileMatrixSetLink'][idx]['TileMatrixSet']); + matrixLimits = /** @type {Array.} */ + (l['TileMatrixSetLink'][idx]['TileMatrixSetLimits']); ol.DEBUG && console.assert(matrixSet, 'TileMatrixSet must not be null'); @@ -409,7 +411,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { } var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( - matrixSetObj, extent); + matrixSetObj, extent, matrixLimits); /** @type {!Array.} */ var urls = []; diff --git a/src/ol/tilegrid/wmts.js b/src/ol/tilegrid/wmts.js index b4af4bbb7c..339c61bcd6 100644 --- a/src/ol/tilegrid/wmts.js +++ b/src/ol/tilegrid/wmts.js @@ -65,15 +65,19 @@ ol.tilegrid.WMTS.prototype.getMatrixIds = function() { /** - * Create a tile grid from a WMTS capabilities matrix set. + * Create a tile grid from a WMTS capabilities matrix set and an + * optional TileMatrixSetLimits. * @param {Object} matrixSet An object representing a matrixSet in the * capabilities document. * @param {ol.Extent=} opt_extent An optional extent to restrict the tile * ranges the server provides. + * @param {Array.=} opt_matrixLimits An optional object representing + * the available matrices for tileGrid. * @return {ol.tilegrid.WMTS} WMTS tileGrid instance. * @api */ -ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_extent) { +ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_extent, + opt_matrixLimits) { /** @type {!Array.} */ var resolutions = []; @@ -86,6 +90,8 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_exten /** @type {!Array.} */ var sizes = []; + var matrixLimits = opt_matrixLimits !== undefined ? opt_matrixLimits : []; + var supportedCRSPropName = 'SupportedCRS'; var matrixIdsPropName = 'TileMatrix'; var identifierPropName = 'Identifier'; @@ -106,21 +112,36 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_exten }); matrixSet[matrixIdsPropName].forEach(function(elt, index, array) { - matrixIds.push(elt[identifierPropName]); - var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit; - var tileWidth = elt[tileWidthPropName]; - var tileHeight = elt[tileHeightPropName]; - if (switchOriginXY) { - origins.push([elt[topLeftCornerPropName][1], - elt[topLeftCornerPropName][0]]); + + var matrixAvailable; + // use of matrixLimits to filter TileMatrices from GetCapabilities + // TileMatrixSet from unavailable matrix levels. + if (matrixLimits.length > 0) { + matrixAvailable = ol.array.find(matrixLimits, + function(elt_ml, index_ml, array_ml) { + return elt[identifierPropName] == elt_ml[matrixIdsPropName]; + }); } else { - origins.push(elt[topLeftCornerPropName]); + matrixAvailable = true; + } + + if (matrixAvailable) { + matrixIds.push(elt[identifierPropName]); + var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit; + var tileWidth = elt[tileWidthPropName]; + var tileHeight = elt[tileHeightPropName]; + if (switchOriginXY) { + origins.push([elt[topLeftCornerPropName][1], + elt[topLeftCornerPropName][0]]); + } else { + origins.push(elt[topLeftCornerPropName]); + } + resolutions.push(resolution); + tileSizes.push(tileWidth == tileHeight ? + tileWidth : [tileWidth, tileHeight]); + // top-left origin, so height is negative + sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]); } - resolutions.push(resolution); - tileSizes.push(tileWidth == tileHeight ? - tileWidth : [tileWidth, tileHeight]); - // top-left origin, so height is negative - sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]); }); return new ol.tilegrid.WMTS({ diff --git a/test/spec/ol/format/wmts/ign.xml b/test/spec/ol/format/wmts/ign.xml new file mode 100644 index 0000000000..083c685976 --- /dev/null +++ b/test/spec/ol/format/wmts/ign.xml @@ -0,0 +1,455 @@ + + + + Service de visualisation WMTS + +Ce service permet la visualisation de couches de données raster IGN au travers d'un flux WMTS + + + Unités administratives + Limites administratives + Surfaces bâties + Réseaux de transport + Routes + Réseaux ferroviaires + Aérodromes + Réseau hydrographique + Parcelles cadastrales + Bâtiments + Services d'utilité publique et services publics + Réseaux de transport + Hydrographie + Photographies aériennes + Cartes + Cartes historiques + Altitude + + OGC WMTS + 1.0.0 + licences + +Conditions Générales d'Utilisation disponibles ici : http://professionnels.ign.fr/doc/Conditions_d_utilisation_des_licences_et_des_services_en_ligne.pdf + + + + IGN + + + Géoportail SAV + custodian + + + + + + + 73 avenue de Paris + Saint Mandé + + 94160 + France + geop_services@geoportail.fr + + + + + + + + + + + + KVP + + + + + + + + + + + + + KVP + + + + + + + + + + Photographies aériennes + Photographies aériennes + + Photographies + + + -180 -86 + 180 84 + + ORTHOIMAGERY.ORTHOPHOTOS + + image/jpeg + + PM + + + 0 + 0 + 1 + 0 + 1 + + + 1 + 0 + 2 + 0 + 2 + + + 10 + 31 + 1024 + 0 + 1024 + + + 11 + 62 + 2048 + 0 + 2048 + + + 12 + 125 + 4096 + 0 + 4096 + + + 13 + 2739 + 4628 + 41 + 7917 + + + 14 + 5478 + 9256 + 82 + 15835 + + + 15 + 10956 + 18513 + 165 + 31670 + + + 16 + 21912 + 37026 + 330 + 63341 + + + 17 + 43825 + 74052 + 660 + 126683 + + + 18 + 87651 + 148105 + 1320 + 253366 + + + 19 + 175302 + 294060 + 170159 + 343473 + + + 2 + 0 + 4 + 0 + 4 + + + 3 + 0 + 8 + 0 + 8 + + + 4 + 0 + 16 + 0 + 16 + + + 5 + 0 + 32 + 0 + 32 + + + 6 + 1 + 64 + 0 + 64 + + + 7 + 3 + 128 + 0 + 128 + + + 8 + 7 + 256 + 0 + 256 + + + 9 + 15 + 512 + 0 + 512 + + + + + + PM + EPSG:3857 + + 0 + 559082264.0287178958533332 + -20037508 20037508 + 256 + 256 + 1 + 1 + + + 1 + 279541132.0143588959472254 + -20037508 20037508 + 256 + 256 + 2 + 2 + + + 10 + 545978.7734655447186469 + -20037508 20037508 + 256 + 256 + 1024 + 1024 + + + 11 + 272989.3867327723085907 + -20037508 20037508 + 256 + 256 + 2048 + 2048 + + + 12 + 136494.6933663861796617 + -20037508 20037508 + 256 + 256 + 4096 + 4096 + + + 13 + 68247.3466831930771477 + -20037508 20037508 + 256 + 256 + 8192 + 8192 + + + 14 + 34123.6733415965449154 + -20037508 20037508 + 256 + 256 + 16384 + 16384 + + + 15 + 17061.8366707982724577 + -20037508 20037508 + 256 + 256 + 32768 + 32768 + + + 16 + 8530.9183353991362289 + -20037508 20037508 + 256 + 256 + 65536 + 65536 + + + 17 + 4265.4591676995681144 + -20037508 20037508 + 256 + 256 + 131072 + 131072 + + + 18 + 2132.7295838497840572 + -20037508 20037508 + 256 + 256 + 262144 + 262144 + + + 19 + 1066.3647919248918304 + -20037508 20037508 + 256 + 256 + 524288 + 524288 + + + 2 + 139770566.0071793960087234 + -20037508 20037508 + 256 + 256 + 4 + 4 + + + 20 + 533.1823959624461134 + -20037508 20037508 + 256 + 256 + 1048576 + 1048576 + + + 21 + 266.5911979812228585 + -20037508 20037508 + 256 + 256 + 2097152 + 2097152 + + + 3 + 69885283.0035897239868063 + -20037508 20037508 + 256 + 256 + 8 + 8 + + + 4 + 34942641.5017948619934032 + -20037508 20037508 + 256 + 256 + 16 + 16 + + + 5 + 17471320.7508974309967016 + -20037508 20037508 + 256 + 256 + 32 + 32 + + + 6 + 8735660.3754487154983508 + -20037508 20037508 + 256 + 256 + 64 + 64 + + + 7 + 4367830.1877243577491754 + -20037508 20037508 + 256 + 256 + 128 + 128 + + + 8 + 2183915.0938621788745877 + -20037508 20037508 + 256 + 256 + 256 + 256 + + + 9 + 1091957.5469310886252288 + -20037508 20037508 + 256 + 256 + 512 + 512 + + + + diff --git a/test/spec/ol/format/wmtscapabilities.test.js b/test/spec/ol/format/wmtscapabilities.test.js index e27120b135..373d41a665 100644 --- a/test/spec/ol/format/wmtscapabilities.test.js +++ b/test/spec/ol/format/wmtscapabilities.test.js @@ -115,4 +115,78 @@ describe('ol.format.WMTSCapabilities', function() { }); }); + + describe('when parsing ign.xml', function() { + + var parser = new ol.format.WMTSCapabilities(); + var capabilities; + before(function(done) { + afterLoadText('spec/ol/format/wmts/ign.xml', function(xml) { + try { + capabilities = parser.read(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('can read Capability.Contents.Layer', function() { + expect(capabilities.Contents.Layer).to.be.an('array'); + expect(capabilities.Contents.Layer).to.have.length(1); + + + var layer = capabilities.Contents.Layer[0]; + expect(layer.TileMatrixSetLink).to.be.an('array'); + expect(layer.TileMatrixSetLink).to.have.length(1); + expect(layer.TileMatrixSetLink[0].TileMatrixSet).to.be + .eql('PM'); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits).to.be.an('array'); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits).to.have.length(20); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits[0].TileMatrix) + .to.be.eql('0'); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits[0].MinTileRow) + .to.be.eql(0); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits[0].MaxTileRow) + .to.be.eql(1); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits[0].MinTileCol) + .to.be.eql(0); + expect(layer.TileMatrixSetLink[0].TileMatrixSetLimits[0].MaxTileCol) + .to.be.eql(1); + + }); + + it('Can read Capabilities.Content.TileMatrixSet', function() { + expect(capabilities.Contents.TileMatrixSet).to.be.ok(); + + var pm = capabilities.Contents.TileMatrixSet[0]; + expect(pm).to.be.ok(); + expect(pm.Identifier).to.be.eql('PM'); + expect(pm.SupportedCRS).to.be.eql('EPSG:3857'); + expect(pm.TileMatrix).to.have.length(22); + expect(pm.TileMatrix[0].Identifier).to.be.eql('0'); + expect(pm.TileMatrix[0].MatrixHeight).to.be.eql(1); + expect(pm.TileMatrix[0].MatrixWidth).to.be.eql(1); + expect(pm.TileMatrix[0].ScaleDenominator) + .to.be.eql(559082264.0287178958533332); + expect(pm.TileMatrix[0].TileWidth).to.be.eql(256); + expect(pm.TileMatrix[0].TileHeight).to.be.eql(256); + expect(pm.TileMatrix[0].TopLeftCorner).to.be.a('array'); + expect(pm.TileMatrix[0].TopLeftCorner[0]).to.be.eql(-20037508); + expect(pm.TileMatrix[0].TopLeftCorner[1]).to.be.eql(20037508); + expect(pm.TileMatrix[1].Identifier).to.be.eql('1'); + expect(pm.TileMatrix[1].MatrixHeight).to.be.eql(2); + expect(pm.TileMatrix[1].MatrixWidth).to.be.eql(2); + expect(pm.TileMatrix[1].ScaleDenominator) + .to.be.eql(279541132.0143588959472254); + expect(pm.TileMatrix[1].TileWidth).to.be.eql(256); + expect(pm.TileMatrix[1].TileHeight).to.be.eql(256); + expect(pm.TileMatrix[1].TopLeftCorner).to.be.a('array'); + expect(pm.TileMatrix[1].TopLeftCorner[0]).to.be.eql(-20037508); + expect(pm.TileMatrix[1].TopLeftCorner[1]).to.be.eql(20037508); + + + }); + + }); }); diff --git a/test/spec/ol/tilegrid/wmts.test.js b/test/spec/ol/tilegrid/wmts.test.js index 3dfb3f14fd..4434741f16 100644 --- a/test/spec/ol/tilegrid/wmts.test.js +++ b/test/spec/ol/tilegrid/wmts.test.js @@ -58,4 +58,100 @@ describe('ol.tilegrid.WMTS', function() { }); }); + + + describe('when creating tileGrid from capabilities with and without TileMatrixSetLimits', + function() { + var parser = new ol.format.WMTSCapabilities(); + var capabilities; + before(function(done) { + afterLoadText('spec/ol/format/wmts/ign.xml', function(xml) { + try { + capabilities = parser.read(xml); + } catch (e) { + done(e); + } + done(); + }); + }); + + it('can create tileGrid for EPSG:3857 without matrixLimits', + function() { + var matrixSetObj = capabilities.Contents.TileMatrixSet[0]; + var tileGrid; + tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( + matrixSetObj); + expect(tileGrid.matrixIds_).to.be.an('array'); + expect(tileGrid.matrixIds_).to.have.length(22); + expect(tileGrid.matrixIds_).to.eql([ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', + '12', '13', '14', '15', '16', '17', '18', '19', '20', '21' + ]); + + expect(tileGrid.resolutions_).to.be.an('array'); + expect(tileGrid.resolutions_).to.have.length(22); + expect(tileGrid.resolutions_).to.eql([ + 156543.033928041, 78271.51696402048, 39135.758482010235, + 19567.87924100512, 9783.93962050256, 4891.96981025128, + 2445.98490512564, 1222.99245256282, 611.49622628141, + 305.7481131407048, 152.8740565703525, 76.43702828517624, + 38.21851414258813, 19.10925707129406, 9.554628535647032, + 4.777314267823516, 2.388657133911758, 1.194328566955879, + 0.5971642834779395, 0.2985821417389697, 0.1492910708694849, + 0.0746455354347424 + ]); + + expect(tileGrid.origins_).to.be.an('array'); + expect(tileGrid.origins_).to.have.length(22); + expect(tileGrid.origins_).to.eql( + Array.apply(null, Array(22)).map(Array.prototype.valueOf, + [-20037508, 20037508])); + + expect(tileGrid.tileSizes_).to.be.an('array'); + expect(tileGrid.tileSizes_).to.have.length(22); + expect(tileGrid.tileSizes_).to.eql( + Array.apply(null, Array(22)).map(Number.prototype.valueOf, 256)); + + }); + + it('can create tileGrid for EPSG:3857 with matrixLimits', + function() { + var matrixSetObj = capabilities.Contents.TileMatrixSet[0]; + var matrixLimitArray = capabilities.Contents.Layer[0] + .TileMatrixSetLink[0].TileMatrixSetLimits; + var tileGrid; + tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( + matrixSetObj, undefined, matrixLimitArray); + expect(tileGrid.matrixIds_).to.be.an('array'); + expect(tileGrid.matrixIds_).to.have.length(20); + expect(tileGrid.matrixIds_).to.eql([ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', + '12', '13', '14', '15', '16', '17', '18', '19' + ]); + + expect(tileGrid.resolutions_).to.be.an('array'); + expect(tileGrid.resolutions_).to.have.length(20); + expect(tileGrid.resolutions_).to.eql([ + 156543.033928041, 78271.51696402048, 39135.758482010235, + 19567.87924100512, 9783.93962050256, 4891.96981025128, + 2445.98490512564, 1222.99245256282, 611.49622628141, + 305.7481131407048, 152.8740565703525, 76.43702828517624, + 38.21851414258813, 19.10925707129406, 9.554628535647032, + 4.777314267823516, 2.388657133911758, 1.194328566955879, + 0.5971642834779395, 0.2985821417389697 + ]); + + expect(tileGrid.origins_).to.be.an('array'); + expect(tileGrid.origins_).to.have.length(20); + expect(tileGrid.origins_).to.eql( + Array.apply(null, Array(20)).map(Array.prototype.valueOf, + [-20037508, 20037508])); + + expect(tileGrid.tileSizes_).to.be.an('array'); + expect(tileGrid.tileSizes_).to.have.length(20); + expect(tileGrid.tileSizes_).to.eql( + Array.apply(null, Array(20)).map(Number.prototype.valueOf, 256)); + + }); + }); });