From 6d78a8340a97b2f889c906a4e451fc8fa4057f73 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 14:54:34 +0100 Subject: [PATCH 01/14] Add a WMTS tilegrid --- src/objectliterals.exports | 8 +++++ src/ol/tilegrid/wmtstilegrid.exports | 1 + src/ol/tilegrid/wmtstilegrid.js | 53 ++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 src/ol/tilegrid/wmtstilegrid.exports create mode 100644 src/ol/tilegrid/wmtstilegrid.js diff --git a/src/objectliterals.exports b/src/objectliterals.exports index 2e348ad82d..c90a6c0a85 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -157,6 +157,14 @@ @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.tileSize ol.Size|undefined @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.tileSizes Array.|undefined +@exportObjectLiteral ol.tilegrid.WMTSOptions +@exportObjectLiteralProperty ol.tilegrid.WMTSOptions.origin ol.Coordinate|undefined +@exportObjectLiteralProperty ol.tilegrid.WMTSOptions.origins Array.|undefined +@exportObjectLiteralProperty ol.tilegrid.WMTSOptions.resolutions !Array. +@exportObjectLiteralProperty ol.tilegrid.WMTSOptions.matrixIds !Array. +@exportObjectLiteralProperty ol.tilegrid.WMTSOptions.tileSize ol.Size|undefined +@exportObjectLiteralProperty ol.tilegrid.WMTSOptions.tileSizes Array.|undefined + @exportObjectLiteral ol.tilegrid.XYZOptions @exportObjectLiteralProperty ol.tilegrid.XYZOptions.maxZoom number diff --git a/src/ol/tilegrid/wmtstilegrid.exports b/src/ol/tilegrid/wmtstilegrid.exports new file mode 100644 index 0000000000..bf723f3d17 --- /dev/null +++ b/src/ol/tilegrid/wmtstilegrid.exports @@ -0,0 +1 @@ +@exportClass ol.tilegrid.WMTS ol.tilegrid.WMTSOptions diff --git a/src/ol/tilegrid/wmtstilegrid.js b/src/ol/tilegrid/wmtstilegrid.js new file mode 100644 index 0000000000..81f2c01adf --- /dev/null +++ b/src/ol/tilegrid/wmtstilegrid.js @@ -0,0 +1,53 @@ +goog.provide('ol.tilegrid.WMTS'); + +goog.require('ol.Size'); +goog.require('ol.projection'); +goog.require('ol.tilegrid.TileGrid'); + + + +/** + * @constructor + * @extends {ol.tilegrid.TileGrid} + * @param {ol.tilegrid.WMTSOptions} wmtsOptions WMTS options. + */ +ol.tilegrid.WMTS = function(wmtsOptions) { + + goog.asserts.assert( + wmtsOptions.resolutions.length == wmtsOptions.matrixIds.length); + + /** + * @private + * @type {!Array.} + */ + this.matrixIds_ = wmtsOptions.matrixIds; + // FIXME: should the matrixIds become optionnal? + + goog.base(this, { + origin: wmtsOptions.origin, + origins: wmtsOptions.origins, + resolutions: wmtsOptions.resolutions, + tileSize: wmtsOptions.tileSize, + tileSizes: wmtsOptions.tileSizes + }); + +}; +goog.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid); + + +/** + * @param {number} z Z. + * @return {string} MatrixId.. + */ +ol.tilegrid.WMTS.prototype.getMatrixId = function(z) { + goog.asserts.assert(0 <= z && z < this.matrixIds_.length); + return this.matrixIds_[z]; +}; + + +/** + * @return {Array.} MatrixIds. + */ +ol.tilegrid.WMTS.prototype.getMatrixIds = function() { + return this.matrixIds_; +}; From 877ce3adcf10b42bef04946062a169a36825dace Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 17:17:43 +0100 Subject: [PATCH 02/14] Add a WMTS source --- src/objectliterals.exports | 16 +++ src/ol/source/wmtssource.exports | 1 + src/ol/source/wmtssource.js | 168 +++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/ol/source/wmtssource.exports create mode 100644 src/ol/source/wmtssource.js diff --git a/src/objectliterals.exports b/src/objectliterals.exports index c90a6c0a85..b2a4019bce 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -150,6 +150,22 @@ @exportObjectLiteralProperty ol.source.TiledWMSOptions.url string|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.urls Array.|undefined +@exportObjectLiteral ol.source.WMTSOptions +@exportObjectLiteralProperty ol.source.WMTSOptions.attributions Array.|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.crossOrigin string|null|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.extent ol.Extent|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.tileGrid ol.tilegrid.WMTS +@exportObjectLiteralProperty ol.source.WMTSOptions.projection ol.Projection|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.requestEncoding ol.source.WMTSRequestEncoding|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.layer string +@exportObjectLiteralProperty ol.source.WMTSOptions.style string +@exportObjectLiteralProperty ol.source.WMTSOptions.format string|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.matrixSet string +@exportObjectLiteralProperty ol.source.WMTSOptions.dimensions Object|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.url string|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.maxZoom number|undefined +@exportObjectLiteralProperty ol.source.WMTSOptions.urls Array.|undefined + @exportObjectLiteral ol.tilegrid.TileGridOptions @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.origin ol.Coordinate|undefined @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.origins Array.|undefined diff --git a/src/ol/source/wmtssource.exports b/src/ol/source/wmtssource.exports new file mode 100644 index 0000000000..13ed62b207 --- /dev/null +++ b/src/ol/source/wmtssource.exports @@ -0,0 +1 @@ +@exportClass ol.source.WMTS ol.source.WMTSOptions diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js new file mode 100644 index 0000000000..657a9d65e2 --- /dev/null +++ b/src/ol/source/wmtssource.js @@ -0,0 +1,168 @@ +goog.provide('ol.source.WMTS'); +goog.provide('ol.source.WMTSRequestEncoding'); + +goog.require('ol.Attribution'); +goog.require('ol.Extent'); +goog.require('ol.Projection'); +goog.require('ol.TileCoord'); +goog.require('ol.TileUrlFunction'); +goog.require('ol.TileUrlFunctionType'); +goog.require('ol.projection'); +goog.require('ol.source.ImageTileSource'); +goog.require('ol.tilegrid.WMTS'); + + +/** + * @enum {string} + */ +ol.source.WMTSRequestEncoding = { + KVP: 'KVP', // see spec §8 + REST: 'REST' // see spec §10 +}; + + + +/** + * @constructor + * @extends {ol.source.ImageTileSource} + * @param {ol.source.WMTSOptions} wmtsOptions WMTS options. + */ +ol.source.WMTS = function(wmtsOptions) { + + // TODO: add support for TileMatrixLimits + + var version = goog.isDef(wmtsOptions.version) ? + wmtsOptions.version : '1.0.0'; + var format = goog.isDef(wmtsOptions.format) ? + wmtsOptions.format : 'image/jpeg'; + var dimensions = wmtsOptions.dimensions || {}; + + // FIXME: should we guess this requestEncoding from wmtsOptions.url(s) + // structure? that would mean KVP only if a template is not provided. + var requestEncoding = goog.isDef(wmtsOptions.requestEncoding) ? + wmtsOptions.requestEncoding : ol.source.WMTSRequestEncoding.KVP; + + // FIXME: should we create a default tileGrid? + // we could issue a getCapabilities xhr to retrieve missing configuration + var tileGrid = wmtsOptions.tileGrid; + + var context = { + 'Layer': wmtsOptions.layer, + 'style': wmtsOptions.style, + 'TileMatrixSet': wmtsOptions.matrixSet + }; + goog.object.extend(context, dimensions); + var kvpParams; + if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { + kvpParams = { + 'Service': 'WMTS', + 'Request': 'GetTile', + 'Version': version, + 'Format': format, + 'TileMatrix': '{TileMatrix}', + 'TileRow': '{TileRow}', + 'TileCol': '{TileCol}' + }; + goog.object.extend(kvpParams, context); + } + + // TODO: factorize the code below so that it is usable by all sources + var urls = wmtsOptions.urls; + if (!goog.isDef(urls)) { + urls = []; + var url = wmtsOptions.url; + goog.asserts.assert(goog.isDef(url)); + var match = /\{(\d)-(\d)\}/.exec(url) || /\{([a-z])-([a-z])\}/.exec(url); + if (match) { + var startCharCode = match[1].charCodeAt(0); + var stopCharCode = match[2].charCodeAt(0); + var charCode; + for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) { + urls.push(url.replace(match[0], String.fromCharCode(charCode))); + } + } else { + urls.push(url); + } + } + + /** + * @param {string} template Template. + * @return {ol.TileUrlFunctionType} Tile URL function. + */ + function createFromWMTSTemplate(template) { + return function(tileCoord) { + if (goog.isNull(tileCoord)) { + return undefined; + } else { + var localContext = { + 'TileMatrix': tileGrid.getMatrixId(tileCoord.z), + 'TileCol': tileCoord.x, + 'TileRow': tileCoord.y + }; + if (requestEncoding != ol.source.WMTSRequestEncoding.KVP) { + goog.object.extend(localContext, context); + } + var url = template; + for (var key in localContext) { + // FIXME: should we filter properties with hasOwnProperty? + url = url.replace('{' + key + '}', localContext[key]) + .replace('%7B' + key + '%7D', localContext[key]); + } + return url; + } + }; + } + + // TODO: update createFromTileUrlFunctions so that if + // tileUrlFunctions.length == 1, it returns the only tileUrlFunction + var tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( + goog.array.map(urls, function(url) { + if (goog.isDef(kvpParams)) { + // TODO: we may want to create our own appendParams function + // so that params order conforms to wmts spec guidance, + // and so that we can avoid to escape special template params + url = goog.uri.utils.appendParamsFromMap(url, kvpParams); + } + return createFromWMTSTemplate(url); + })); + + tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform( + function(tileCoord, tileGrid, projection) { + if (tileGrid.getResolutions().length <= tileCoord.z) { + return null; + } + var x = tileCoord.x; + var y = -tileCoord.y - 1; + var tileExtent = tileGrid.getTileCoordExtent(tileCoord); + var projectionExtent = projection.getExtent(); + var extent = goog.isDef(wmtsOptions.extent) ? + wmtsOptions.extent : projectionExtent; + + if (!goog.isNull(extent) && projection.isGlobal() && + extent.minX === projectionExtent.minX && + extent.maxX === projectionExtent.maxX) { + var numCols = Math.ceil( + (extent.maxX - extent.minX) / + (tileExtent.maxX - tileExtent.minX)); + x = goog.math.modulo(x, numCols); + tileExtent = tileGrid.getTileCoordExtent( + new ol.TileCoord(tileCoord.z, x, tileCoord.y)); + } + if (!tileExtent.intersects(extent)) { + return null; + } + return new ol.TileCoord(tileCoord.z, x, y); + }, + tileUrlFunction); + + goog.base(this, { + attributions: wmtsOptions.attributions, + crossOrigin: wmtsOptions.crossOrigin, + extent: wmtsOptions.extent, + projection: wmtsOptions.projection, + tileGrid: tileGrid, + tileUrlFunction: tileUrlFunction + }); + +}; +goog.inherits(ol.source.WMTS, ol.source.ImageTileSource); From 56ffb6146dec81f1774d79b4b03e20a4305d6647 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 19:40:39 +0100 Subject: [PATCH 03/14] Add example for WMTS source --- examples/wmts.html | 52 ++++++++++++++++++++++++++++++++++++++++++++ examples/wmts.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 examples/wmts.html create mode 100644 examples/wmts.js diff --git a/examples/wmts.html b/examples/wmts.html new file mode 100644 index 0000000000..07d0f69eda --- /dev/null +++ b/examples/wmts.html @@ -0,0 +1,52 @@ + + + + + + + + + + WMTS example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

WMTS example

+

Example of a WMTS source.

+
+

See the wmts.js source to see how this is done.

+
+
wmts
+
+ +
+ +
+ + + + + diff --git a/examples/wmts.js b/examples/wmts.js new file mode 100644 index 0000000000..9ac2d31a1b --- /dev/null +++ b/examples/wmts.js @@ -0,0 +1,54 @@ +goog.require('ol.Coordinate'); +goog.require('ol.Extent'); +goog.require('ol.Map'); +goog.require('ol.RendererHint'); +goog.require('ol.View2D'); +goog.require('ol.layer.TileLayer'); +goog.require('ol.projection'); +goog.require('ol.source.OpenStreetMap'); +goog.require('ol.source.WMTS'); +goog.require('ol.tilegrid.WMTS'); + + +var projection = ol.projection.get('EPSG:900913'); +var projectionExtent = projection.getExtent(); +var size = projectionExtent.getWidth() / 256; +var resolutions = new Array(26); +var matrixIds = new Array(26); +for (var z = 0; z < 26; ++z) { + // generate resolutions and matrixIds arrays for this WMTS + resolutions[z] = size / Math.pow(2, z); + matrixIds[z] = 'EPSG:900913:' + z; +} + +var map = new ol.Map({ + layers: [ + new ol.layer.TileLayer({ + source: new ol.source.OpenStreetMap(), + opacity: 0.7 + }), + new ol.layer.TileLayer({ + source: new ol.source.WMTS({ + url: 'http://v2.suite.opengeo.org/geoserver/gwc/service/wmts/', + layer: 'medford:buildings', + matrixSet: 'EPSG:900913', + format: 'image/png', + projection: projection, + tileGrid: new ol.tilegrid.WMTS({ + origin: projectionExtent.getTopLeft(), + resolutions: resolutions, + matrixIds: matrixIds + }), + style: '_null', + crossOrigin: null, // FIXME: this should be the default + extent: new ol.Extent(-13682835, 5204068, -13667473, 5221690) + }) + }) + ], + renderer: ol.RendererHint.CANVAS, + target: 'map', + view: new ol.View2D({ + center: new ol.Coordinate(-13677832, 5213272), + zoom: 13 + }) +}); From 0f9f5a25ae02b6352754a37f96e6691db79035e7 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 21:04:20 +0100 Subject: [PATCH 04/14] Export methods methods for ol.Extent so that wmts example work (it makes use of extent.getTopLeft() method) --- src/ol/extent.exports | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ol/extent.exports b/src/ol/extent.exports index b52ee8007a..838f8dd55d 100644 --- a/src/ol/extent.exports +++ b/src/ol/extent.exports @@ -1,3 +1,10 @@ @exportSymbol ol.Extent @exportProperty ol.Extent.prototype.getHeight @exportProperty ol.Extent.prototype.getWidth +@exportProperty ol.Extent.prototype.containsCoordinate +@exportProperty ol.Extent.prototype.containsExtent +@exportProperty ol.Extent.prototype.getBottomLeft +@exportProperty ol.Extent.prototype.getBottomRight +@exportProperty ol.Extent.prototype.getTopLeft +@exportProperty ol.Extent.prototype.getTopRight +@exportProperty ol.Extent.prototype.transform From dc440a66044a70af19f6df0dfcae71bb64068bef Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 22:20:55 +0100 Subject: [PATCH 05/14] Ensure supportedCRS property won't be renamed this property was renamed when using wmts parser when built with ADVANCED_OPTIMIZATIONS --- src/ol/parser/ogc/wmtscapabilities_v1_0_0.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js b/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js index 4c88cdd59f..11cf87949d 100644 --- a/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js +++ b/src/ol/parser/ogc/wmtscapabilities_v1_0_0.js @@ -67,7 +67,7 @@ ol.parser.ogc.WMTSCapabilities_v1_0_0 = function() { }, 'TileMatrix': function(node, obj) { var tileMatrix = { - 'supportedCRS': obj.supportedCRS + 'supportedCRS': obj['supportedCRS'] }; this.readChildNodes(node, tileMatrix); obj['matrixIds'].push(tileMatrix); From 13d0b36a08c03b7d925cc5be9d2737d50601625e Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 22:22:36 +0100 Subject: [PATCH 06/14] Add a ol.source.WMTS.createFromCapabilities function so that we can create a wmts source directly from a getCapabilities response (parsed by the wmts parser) --- src/ol/source/wmtssource.exports | 1 + src/ol/source/wmtssource.js | 130 +++++++++++++++++++++++++++++++ src/ol/tilegrid/wmtstilegrid.js | 30 +++++++ 3 files changed, 161 insertions(+) diff --git a/src/ol/source/wmtssource.exports b/src/ol/source/wmtssource.exports index 13ed62b207..be270d4103 100644 --- a/src/ol/source/wmtssource.exports +++ b/src/ol/source/wmtssource.exports @@ -1 +1,2 @@ @exportClass ol.source.WMTS ol.source.WMTSOptions +@exportSymbol ol.source.WMTS.createFromCapabilities diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js index 657a9d65e2..2f14199557 100644 --- a/src/ol/source/wmtssource.js +++ b/src/ol/source/wmtssource.js @@ -166,3 +166,133 @@ ol.source.WMTS = function(wmtsOptions) { }; goog.inherits(ol.source.WMTS, ol.source.ImageTileSource); + + +/** + * @param {Object} wmtsCap An object representing the capabilities document. + * @param {string} layer The layer identifier that we want the grid for. + * @param {string|null=} opt_crossOrigin Optional crossOrigin value. + * @param {string=} opt_matrixSet Optional tileMatrixSet name. If not provided, + * it defaults to the first matrixSet found. + * @param {ol.source.WMTSRequestEncoding=} opt_requestEncoding Optional + * requestEncoding. If not provided, it defaults to the first value found. + * @param {string=} opt_format Optional format name. If not provided, it + * defaults to the first format found. + * @param {string=} opt_style Optional style name. If not provided, it defaults + * to the first style found. + * @param {Object=} opt_dimensions Optional object for setting dimensions + * values. + * @param {ol.Extent=} opt_extent Optional extent. + * @return {ol.source.WMTS} TileGrid instance. + */ +ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, + opt_crossOrigin, opt_matrixSet, opt_requestEncoding, opt_format, + opt_style, opt_dimensions, opt_extent) { + + // TODO: add support for TileMatrixLimits + + var layers = wmtsCap['contents']['layers']; + var matrixSet = opt_matrixSet; + var l = goog.array.find(layers, function(elt, index, array) { + return elt['identifier'] == layer; + }); + goog.asserts.assert(!goog.isNull(l)); + + var format = goog.isDef(opt_format) ? + opt_format : /** @type {string} */ (l['formats'][0]); + var idx = goog.array.findIndex(l['styles'], function(elt, index, array) { + if (goog.isDef(opt_style)) { + return elt['identifier'] == opt_style; + } else { + return elt['isDefault']; + } + }); + if (idx < 0) { + goog.asserts.assert(!goog.isDef(opt_style)); // opt_style was not correct + idx = 0; + } + var style = /** @type {string} */ (l['styles'][idx]['identifier']); + + var dimensions = {}; + goog.array.forEach(l['dimensions'], function(elt, index, array) { + var key = elt['identifier']; + // With the special value 'default', the server should automatically + // select the default value for this dimension. + var value = (goog.isDef(opt_dimensions) && + opt_dimensions.hasOwnProperty(key)) ? + opt_dimensions[key] : elt['default']; + if (goog.isDef(value)) { + goog.asserts.assert(goog.array.indexOf(elt['values'], value) >= 0); + } else { + value = elt['values'][0]; + } + goog.asserts.assert(goog.isDef(value)); + dimensions[key] = value; + }); + + if (goog.isDef(matrixSet)) { + goog.asserts.assert(0 < goog.array.findIndex( + l['tileMatrixSetLinks'], function(elt, index, arr) { + return elt['tileMatrixSet'] == matrixSet; + })); + } else { + goog.asserts.assert(l['tileMatrixSetLinks'].length > 0); + matrixSet = /** @type {string} */ + (l['tileMatrixSetLinks'][0]['tileMatrixSet']); + } + var matrixSets = wmtsCap['contents']['tileMatrixSets']; + goog.asserts.assert(matrixSet in matrixSets); + var matrixSetObj = matrixSets[matrixSet]; + + var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( + matrixSetObj); + + var projection = ol.projection.get(matrixSetObj['supportedCRS']); + + var gets = wmtsCap['operationsMetadata']['GetTile']['dcp']['http']['get']; + var encodings = goog.object.getKeys( + gets[0]['constraints']['GetEncoding']['allowedValues']); + goog.asserts.assert(encodings.length > 0); + var requestEncoding = goog.isDef(opt_requestEncoding) ? + opt_requestEncoding : /** @type {ol.source.WMTSRequestEncoding} */ + (encodings[0]); + // TODO: arcgis support, quote from ol2: + // The OGC documentation is not clear if we should use REST or RESTful, + // ArcGis use RESTful, and OpenLayers use REST. + + var urls; + switch (requestEncoding) { + case ol.source.WMTSRequestEncoding.REST: + goog.asserts.assert(l['resourceUrls'].hasOwnProperty('tile')); + goog.asserts.assert(l['resourceUrls']['tile'].hasOwnProperty(format)); + urls = /** @type {Array.} */ + (l['resourceUrls']['tile'][format]); + break; + case ol.source.WMTSRequestEncoding.KVP: + urls = []; + goog.array.forEach(gets, function(elt, index, array) { + if (elt['constraints']['GetEncoding']['allowedValues'].hasOwnProperty( + ol.source.WMTSRequestEncoding.KVP)) { + urls.push(/** @type {string} */ (elt['url'])); + } + }); + goog.asserts.assert(urls.length > 0); + break; + default: + goog.asserts.assert(false); + } + + return new ol.source.WMTS({ + urls: urls, + layer: layer, + matrixSet: matrixSet, + format: format, + projection: projection, + requestEncoding: requestEncoding, + tileGrid: tileGrid, + style: style, + crossOrigin: opt_crossOrigin, + extent: opt_extent, + dimensions: dimensions + }); +}; diff --git a/src/ol/tilegrid/wmtstilegrid.js b/src/ol/tilegrid/wmtstilegrid.js index 81f2c01adf..d7a3f36131 100644 --- a/src/ol/tilegrid/wmtstilegrid.js +++ b/src/ol/tilegrid/wmtstilegrid.js @@ -51,3 +51,33 @@ ol.tilegrid.WMTS.prototype.getMatrixId = function(z) { ol.tilegrid.WMTS.prototype.getMatrixIds = function() { return this.matrixIds_; }; + + +/** + * @param {Object} matrixSet An object representing a matrixSet in the + * capabilities document. + * @return {ol.tilegrid.WMTS} WMTS tileGrid instance. + */ +ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = + function(matrixSet) { + + var resolutions = []; + var matrixIds = []; + var origins = []; + var tileSizes = []; + var projection = ol.projection.get(matrixSet['supportedCRS']); + var meters_per_unit = projection.getMetersPerUnit(); + goog.array.forEach(matrixSet['matrixIds'], function(elt, index, array) { + matrixIds.push(elt['identifier']); + origins.push(elt['topLeftCorner']); + resolutions.push(elt['scaleDenominator'] * 0.28E-3 / meters_per_unit); + tileSizes.push(new ol.Size(elt['tileWidth'], elt['tileHeight'])); + }); + + return new ol.tilegrid.WMTS({ + origins: origins, + resolutions: resolutions, + matrixIds: matrixIds, + tileSizes: tileSizes + }); +}; From 14d5916e67a175a206645276674bd13f4d9a1eed Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 22:25:13 +0100 Subject: [PATCH 07/14] Add wmts-from-capabilities example it demonstrates how to create a wmts source by retrieving its configuration from a wmts getCapabilities. --- examples/wmts-from-capabilities.html | 53 ++++++++++++++++++++++ examples/wmts-from-capabilities.js | 66 ++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 examples/wmts-from-capabilities.html create mode 100644 examples/wmts-from-capabilities.js diff --git a/examples/wmts-from-capabilities.html b/examples/wmts-from-capabilities.html new file mode 100644 index 0000000000..5a7844a548 --- /dev/null +++ b/examples/wmts-from-capabilities.html @@ -0,0 +1,53 @@ + + + + + + + + + + WMTS from capabilities example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

WMTS from capabilities example

+

Example of a WMTS source built from a WMTS getCapabilities response.

+
+

See the wmts-from-capabilities.js source to see how this is done.

+
+
wmts
+
+ +
+ +
+ + + + + + diff --git a/examples/wmts-from-capabilities.js b/examples/wmts-from-capabilities.js new file mode 100644 index 0000000000..766e64e015 --- /dev/null +++ b/examples/wmts-from-capabilities.js @@ -0,0 +1,66 @@ +goog.require('ol.Attribution'); +goog.require('ol.Coordinate'); +goog.require('ol.Extent'); +goog.require('ol.Map'); +goog.require('ol.RendererHint'); +goog.require('ol.View2D'); +goog.require('ol.layer.ImageLayer'); +goog.require('ol.layer.TileLayer'); +goog.require('ol.parser.ogc.WMTSCapabilities'); +goog.require('ol.projection'); +goog.require('ol.source.SingleImageWMS'); +goog.require('ol.source.WMTS'); + + +Proj4js['defs']['EPSG:21781'] = + '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 ' + + '+k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' + + '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs'; +var projection = ol.projection.configureProj4jsProjection({ + code: 'EPSG:21781', + extent: new ol.Extent(485869.5728, 76443.1884, 837076.5648, 299941.7864) +}); + +var map, capabilities; +var parser = new ol.parser.ogc.WMTSCapabilities(); + +var xhr = new XMLHttpRequest(); +xhr.open('GET', 'http://wmts.geo.admin.ch/1.0.0/WMTSCapabilities.xml', true); + + +/** + * onload handler for the XHR request. + */ +xhr.onload = function() { + if (xhr.status == 200) { + capabilities = parser.read(xhr.responseXML); + map = new ol.Map({ + layers: [ + new ol.layer.TileLayer({ + source: ol.source.WMTS.createFromCapabilities( + capabilities, 'ch.swisstopo.pixelkarte-farbe', null) + }), + new ol.layer.ImageLayer({ + source: new ol.source.SingleImageWMS({ + url: 'http://wms.geo.admin.ch/', + attributions: [new ol.Attribution( + '© ' + + 'National parks / geo.admin.ch')], + params: { + 'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung' + } + }) + }) + ], + renderer: ol.RendererHint.CANVAS, + target: 'map', + view: new ol.View2D({ + center: projection.getExtent().getCenter(), + projection: projection, + zoom: 1 + }) + }); + } +}; +xhr.send(); From b4cbe0609a39a7ec0b275bb3e79aeb708d8a974e Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 7 Mar 2013 22:26:13 +0100 Subject: [PATCH 08/14] Add missing exports so that wmts-from-capabilities example works. --- src/ol/coordinate.exports | 5 ++++- src/ol/extent.exports | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ol/coordinate.exports b/src/ol/coordinate.exports index 1dec787cd7..c538ed312c 100644 --- a/src/ol/coordinate.exports +++ b/src/ol/coordinate.exports @@ -1,2 +1,5 @@ @exportSymbol ol.Coordinate -@exportProperty ol.Coordinate.toStringHDMS +@exportSymbol ol.Coordinate.createStringXY +@exportSymbol ol.Coordinate.toStringHDMS +@exportSymbol ol.Coordinate.toStringXY +@exportSymbol ol.Coordinate.fromProjectedArray diff --git a/src/ol/extent.exports b/src/ol/extent.exports index 838f8dd55d..9ba8337eaa 100644 --- a/src/ol/extent.exports +++ b/src/ol/extent.exports @@ -1,4 +1,5 @@ @exportSymbol ol.Extent +@exportProperty ol.Extent.prototype.getCenter @exportProperty ol.Extent.prototype.getHeight @exportProperty ol.Extent.prototype.getWidth @exportProperty ol.Extent.prototype.containsCoordinate From c67e67ee12ab8689894220ce556ad6a454e74545 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 11 Mar 2013 11:29:40 +0100 Subject: [PATCH 09/14] Single tileUrlFunction in createFromTileUrlFunctions In that case, simply return the single tileUrlFunction. --- src/ol/source/wmtssource.js | 2 -- src/ol/tileurlfunction.js | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js index 2f14199557..7cca31fd66 100644 --- a/src/ol/source/wmtssource.js +++ b/src/ol/source/wmtssource.js @@ -113,8 +113,6 @@ ol.source.WMTS = function(wmtsOptions) { }; } - // TODO: update createFromTileUrlFunctions so that if - // tileUrlFunctions.length == 1, it returns the only tileUrlFunction var tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( goog.array.map(urls, function(url) { if (goog.isDef(kvpParams)) { diff --git a/src/ol/tileurlfunction.js b/src/ol/tileurlfunction.js index 3c270b80c6..209febe19c 100644 --- a/src/ol/tileurlfunction.js +++ b/src/ol/tileurlfunction.js @@ -60,6 +60,9 @@ ol.TileUrlFunction.createFromTemplates = function(templates) { * @return {ol.TileUrlFunctionType} Tile URL function. */ ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) { + if (tileUrlFunctions.length === 1) { + return tileUrlFunctions[0]; + } return function(tileCoord, tileGrid, projection) { if (goog.isNull(tileCoord)) { return undefined; From 6f83e503325a891ea8ac2c0a2379a5e761024d9f Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 11 Mar 2013 11:48:06 +0100 Subject: [PATCH 10/14] Load EPSG:21781 definition from cdnjs. --- examples/wmts-from-capabilities.html | 1 + examples/wmts-from-capabilities.js | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/wmts-from-capabilities.html b/examples/wmts-from-capabilities.html index 5a7844a548..5d090fff56 100644 --- a/examples/wmts-from-capabilities.html +++ b/examples/wmts-from-capabilities.html @@ -47,6 +47,7 @@ + diff --git a/examples/wmts-from-capabilities.js b/examples/wmts-from-capabilities.js index 766e64e015..0e7abe78da 100644 --- a/examples/wmts-from-capabilities.js +++ b/examples/wmts-from-capabilities.js @@ -12,10 +12,6 @@ goog.require('ol.source.SingleImageWMS'); goog.require('ol.source.WMTS'); -Proj4js['defs']['EPSG:21781'] = - '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 ' + - '+k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' + - '+towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs'; var projection = ol.projection.configureProj4jsProjection({ code: 'EPSG:21781', extent: new ol.Extent(485869.5728, 76443.1884, 837076.5648, 299941.7864) From 9e370bf6afe8571caa9a8882405afd7056725e89 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 11 Mar 2013 12:42:14 +0100 Subject: [PATCH 11/14] Implement ol.source.WMTS.optionsFromCapabilities and remove related ol.source.WMTS.createFromCapabilities function. --- examples/wmts-from-capabilities.js | 6 ++- src/ol/source/wmtssource.exports | 2 +- src/ol/source/wmtssource.js | 60 ++++++------------------------ 3 files changed, 17 insertions(+), 51 deletions(-) diff --git a/examples/wmts-from-capabilities.js b/examples/wmts-from-capabilities.js index 0e7abe78da..7a7c362bd0 100644 --- a/examples/wmts-from-capabilities.js +++ b/examples/wmts-from-capabilities.js @@ -30,11 +30,13 @@ xhr.open('GET', 'http://wmts.geo.admin.ch/1.0.0/WMTSCapabilities.xml', true); xhr.onload = function() { if (xhr.status == 200) { capabilities = parser.read(xhr.responseXML); + var wmtsOptions = ol.source.WMTS.optionsFromCapabilities( + capabilities, 'ch.swisstopo.pixelkarte-farbe'); + wmtsOptions.crossOrigin = null; map = new ol.Map({ layers: [ new ol.layer.TileLayer({ - source: ol.source.WMTS.createFromCapabilities( - capabilities, 'ch.swisstopo.pixelkarte-farbe', null) + source: new ol.source.WMTS(wmtsOptions) }), new ol.layer.ImageLayer({ source: new ol.source.SingleImageWMS({ diff --git a/src/ol/source/wmtssource.exports b/src/ol/source/wmtssource.exports index be270d4103..ef840a8124 100644 --- a/src/ol/source/wmtssource.exports +++ b/src/ol/source/wmtssource.exports @@ -1,2 +1,2 @@ @exportClass ol.source.WMTS ol.source.WMTSOptions -@exportSymbol ol.source.WMTS.createFromCapabilities +@exportSymbol ol.source.WMTS.optionsFromCapabilities diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js index 7cca31fd66..cd5b1b8a85 100644 --- a/src/ol/source/wmtssource.js +++ b/src/ol/source/wmtssource.js @@ -168,45 +168,26 @@ goog.inherits(ol.source.WMTS, ol.source.ImageTileSource); /** * @param {Object} wmtsCap An object representing the capabilities document. - * @param {string} layer The layer identifier that we want the grid for. - * @param {string|null=} opt_crossOrigin Optional crossOrigin value. - * @param {string=} opt_matrixSet Optional tileMatrixSet name. If not provided, - * it defaults to the first matrixSet found. - * @param {ol.source.WMTSRequestEncoding=} opt_requestEncoding Optional - * requestEncoding. If not provided, it defaults to the first value found. - * @param {string=} opt_format Optional format name. If not provided, it - * defaults to the first format found. - * @param {string=} opt_style Optional style name. If not provided, it defaults - * to the first style found. - * @param {Object=} opt_dimensions Optional object for setting dimensions - * values. - * @param {ol.Extent=} opt_extent Optional extent. - * @return {ol.source.WMTS} TileGrid instance. + * @param {string} layer The layer identifier. + * @return {ol.source.WMTSOptions} WMTS source options object. */ -ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, - opt_crossOrigin, opt_matrixSet, opt_requestEncoding, opt_format, - opt_style, opt_dimensions, opt_extent) { +ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, layer) { // TODO: add support for TileMatrixLimits var layers = wmtsCap['contents']['layers']; - var matrixSet = opt_matrixSet; var l = goog.array.find(layers, function(elt, index, array) { return elt['identifier'] == layer; }); goog.asserts.assert(!goog.isNull(l)); - - var format = goog.isDef(opt_format) ? - opt_format : /** @type {string} */ (l['formats'][0]); + goog.asserts.assert(l['tileMatrixSetLinks'].length > 0); + var matrixSet = /** @type {string} */ + (l['tileMatrixSetLinks'][0]['tileMatrixSet']); + var format = /** @type {string} */ (l['formats'][0]); var idx = goog.array.findIndex(l['styles'], function(elt, index, array) { - if (goog.isDef(opt_style)) { - return elt['identifier'] == opt_style; - } else { - return elt['isDefault']; - } + return elt['isDefault']; }); if (idx < 0) { - goog.asserts.assert(!goog.isDef(opt_style)); // opt_style was not correct idx = 0; } var style = /** @type {string} */ (l['styles'][idx]['identifier']); @@ -214,11 +195,7 @@ ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, var dimensions = {}; goog.array.forEach(l['dimensions'], function(elt, index, array) { var key = elt['identifier']; - // With the special value 'default', the server should automatically - // select the default value for this dimension. - var value = (goog.isDef(opt_dimensions) && - opt_dimensions.hasOwnProperty(key)) ? - opt_dimensions[key] : elt['default']; + var value = elt['default']; if (goog.isDef(value)) { goog.asserts.assert(goog.array.indexOf(elt['values'], value) >= 0); } else { @@ -228,16 +205,6 @@ ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, dimensions[key] = value; }); - if (goog.isDef(matrixSet)) { - goog.asserts.assert(0 < goog.array.findIndex( - l['tileMatrixSetLinks'], function(elt, index, arr) { - return elt['tileMatrixSet'] == matrixSet; - })); - } else { - goog.asserts.assert(l['tileMatrixSetLinks'].length > 0); - matrixSet = /** @type {string} */ - (l['tileMatrixSetLinks'][0]['tileMatrixSet']); - } var matrixSets = wmtsCap['contents']['tileMatrixSets']; goog.asserts.assert(matrixSet in matrixSets); var matrixSetObj = matrixSets[matrixSet]; @@ -251,8 +218,7 @@ ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, var encodings = goog.object.getKeys( gets[0]['constraints']['GetEncoding']['allowedValues']); goog.asserts.assert(encodings.length > 0); - var requestEncoding = goog.isDef(opt_requestEncoding) ? - opt_requestEncoding : /** @type {ol.source.WMTSRequestEncoding} */ + var requestEncoding = /** @type {ol.source.WMTSRequestEncoding} */ (encodings[0]); // TODO: arcgis support, quote from ol2: // The OGC documentation is not clear if we should use REST or RESTful, @@ -280,7 +246,7 @@ ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, goog.asserts.assert(false); } - return new ol.source.WMTS({ + return { urls: urls, layer: layer, matrixSet: matrixSet, @@ -289,8 +255,6 @@ ol.source.WMTS.createFromCapabilities = function(wmtsCap, layer, requestEncoding: requestEncoding, tileGrid: tileGrid, style: style, - crossOrigin: opt_crossOrigin, - extent: opt_extent, dimensions: dimensions - }); + }; }; From 8638f6d502fa7503c73cf28ad57dda7bbb0575ec Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 11 Mar 2013 15:05:53 +0100 Subject: [PATCH 12/14] s/meters_per_unit/metersPerUnit/ --- src/ol/tilegrid/wmtstilegrid.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ol/tilegrid/wmtstilegrid.js b/src/ol/tilegrid/wmtstilegrid.js index d7a3f36131..b939795662 100644 --- a/src/ol/tilegrid/wmtstilegrid.js +++ b/src/ol/tilegrid/wmtstilegrid.js @@ -66,11 +66,11 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = var origins = []; var tileSizes = []; var projection = ol.projection.get(matrixSet['supportedCRS']); - var meters_per_unit = projection.getMetersPerUnit(); + var metersPerUnit = projection.getMetersPerUnit(); goog.array.forEach(matrixSet['matrixIds'], function(elt, index, array) { matrixIds.push(elt['identifier']); origins.push(elt['topLeftCorner']); - resolutions.push(elt['scaleDenominator'] * 0.28E-3 / meters_per_unit); + resolutions.push(elt['scaleDenominator'] * 0.28E-3 / metersPerUnit); tileSizes.push(new ol.Size(elt['tileWidth'], elt['tileHeight'])); }); From d14b1c57a9bf44ba190eead9c3eed1f64a55bc0d Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 11 Mar 2013 15:15:53 +0100 Subject: [PATCH 13/14] Remove ImageLayer from wmts-from-capabilities example --- examples/wmts-from-capabilities.js | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/examples/wmts-from-capabilities.js b/examples/wmts-from-capabilities.js index 7a7c362bd0..42d7a7c77d 100644 --- a/examples/wmts-from-capabilities.js +++ b/examples/wmts-from-capabilities.js @@ -1,25 +1,21 @@ -goog.require('ol.Attribution'); goog.require('ol.Coordinate'); goog.require('ol.Extent'); goog.require('ol.Map'); goog.require('ol.RendererHint'); goog.require('ol.View2D'); -goog.require('ol.layer.ImageLayer'); goog.require('ol.layer.TileLayer'); goog.require('ol.parser.ogc.WMTSCapabilities'); goog.require('ol.projection'); -goog.require('ol.source.SingleImageWMS'); goog.require('ol.source.WMTS'); +var map, capabilities; +var parser = new ol.parser.ogc.WMTSCapabilities(); var projection = ol.projection.configureProj4jsProjection({ code: 'EPSG:21781', extent: new ol.Extent(485869.5728, 76443.1884, 837076.5648, 299941.7864) }); -var map, capabilities; -var parser = new ol.parser.ogc.WMTSCapabilities(); - var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://wmts.geo.admin.ch/1.0.0/WMTSCapabilities.xml', true); @@ -37,18 +33,6 @@ xhr.onload = function() { layers: [ new ol.layer.TileLayer({ source: new ol.source.WMTS(wmtsOptions) - }), - new ol.layer.ImageLayer({ - source: new ol.source.SingleImageWMS({ - url: 'http://wms.geo.admin.ch/', - attributions: [new ol.Attribution( - '© ' + - 'National parks / geo.admin.ch')], - params: { - 'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung' - } - }) }) ], renderer: ol.RendererHint.CANVAS, From 61603dacce3246588a3bb3266dec84605d9738bb Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 11 Mar 2013 15:47:42 +0100 Subject: [PATCH 14/14] WMTS from swisstopo now supports CORS headers --- examples/wmts-from-capabilities.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/wmts-from-capabilities.js b/examples/wmts-from-capabilities.js index 42d7a7c77d..9858e676e5 100644 --- a/examples/wmts-from-capabilities.js +++ b/examples/wmts-from-capabilities.js @@ -1,7 +1,7 @@ goog.require('ol.Coordinate'); goog.require('ol.Extent'); goog.require('ol.Map'); -goog.require('ol.RendererHint'); +goog.require('ol.RendererHints'); goog.require('ol.View2D'); goog.require('ol.layer.TileLayer'); goog.require('ol.parser.ogc.WMTSCapabilities'); @@ -28,14 +28,13 @@ xhr.onload = function() { capabilities = parser.read(xhr.responseXML); var wmtsOptions = ol.source.WMTS.optionsFromCapabilities( capabilities, 'ch.swisstopo.pixelkarte-farbe'); - wmtsOptions.crossOrigin = null; map = new ol.Map({ layers: [ new ol.layer.TileLayer({ source: new ol.source.WMTS(wmtsOptions) }) ], - renderer: ol.RendererHint.CANVAS, + renderers: ol.RendererHints.createFromQueryData(), target: 'map', view: new ol.View2D({ center: projection.getExtent().getCenter(),