From e9d84017867d3016425291cad0fbe49022f9c4b3 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 8 Jan 2014 21:19:52 +0100 Subject: [PATCH] Refactor ol.source.ImageWMS URL logic * Always request images of integer WIDTH and HEIGHT * Match BBOX to requested size * Handle integer-only DPIs in GeoServer --- src/ol/source/imagewmssource.js | 130 +++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 27 deletions(-) diff --git a/src/ol/source/imagewmssource.js b/src/ol/source/imagewmssource.js index 89b228408c..72b591e09a 100644 --- a/src/ol/source/imagewmssource.js +++ b/src/ol/source/imagewmssource.js @@ -1,43 +1,48 @@ +// FIXME factor out v13 calculation + goog.provide('ol.source.ImageWMS'); goog.require('goog.asserts'); goog.require('goog.object'); +goog.require('goog.string'); +goog.require('goog.uri.utils'); goog.require('ol.Image'); -goog.require('ol.ImageUrlFunction'); goog.require('ol.extent'); goog.require('ol.source.Image'); -goog.require('ol.source.wms'); +goog.require('ol.source.wms.ServerType'); /** * @constructor * @extends {ol.source.Image} - * @param {olx.source.ImageWMSOptions} options Options. + * @param {olx.source.ImageWMSOptions=} opt_options Options. * @todo stability experimental */ -ol.source.ImageWMS = function(options) { +ol.source.ImageWMS = function(opt_options) { - /** - * @private - * @type {Object} - */ - this.params_ = options.params; - - var imageUrlFunction = goog.isDef(options.url) ? - ol.ImageUrlFunction.createFromParamsFunction( - options.url, this.params_, ol.source.wms.getUrl) : - ol.ImageUrlFunction.nullImageUrlFunction; + var options = goog.isDef(opt_options) ? opt_options : {}; goog.base(this, { attributions: options.attributions, crossOrigin: options.crossOrigin, extent: options.extent, projection: options.projection, - resolutions: options.resolutions, - imageUrlFunction: imageUrlFunction + resolutions: options.resolutions }); + /** + * @private + * @type {string|undefined} + */ + this.url_ = options.url; + + /** + * @private + * @type {Object} + */ + this.params_ = options.params; + /** * @private * @type {ol.source.wms.ServerType|undefined} @@ -81,8 +86,16 @@ ol.source.ImageWMS.prototype.getParams = function() { */ ol.source.ImageWMS.prototype.getImage = function(extent, resolution, pixelRatio, projection) { + + if (!goog.isDef(this.url_)) { + return null; + } + resolution = this.findNearestResolution(resolution); - pixelRatio = this.hidpi_ ? pixelRatio : 1; + + if (pixelRatio != 1 && (!this.hidpi_ || !goog.isDef(this.serverType_))) { + pixelRatio = 1; + } var image = this.image_; if (!goog.isNull(image) && @@ -92,20 +105,83 @@ ol.source.ImageWMS.prototype.getImage = return image; } - extent = extent.slice(); - ol.extent.scaleFromCenter(extent, this.ratio_); - var width = (extent[2] - extent[0]) / resolution; - var height = (extent[3] - extent[1]) / resolution; - var size = [width * pixelRatio, height * pixelRatio]; + var params = { + 'SERVICE': 'WMS', + 'VERSION': '1.3.0', + 'REQUEST': 'GetMap', + 'FORMAT': 'image/png', + 'TRANSPARENT': true + }; + goog.object.extend(params, this.params_); - if (goog.isDef(this.serverType_) && pixelRatio > 1) { - var param = ol.source.wms.getDpiParam(this.serverType_, pixelRatio); - goog.object.extend(this.params_, param); + var v13 = goog.string.compareVersions( + goog.object.get(params, 'VERSION'), '1.3') >= 0; + + params[v13 ? 'CRS' : 'SRS'] = projection.getCode(); + + if (!('STYLES' in this.params_)) { + goog.object.set(params, 'STYLES', new String('')); } - this.image_ = this.createImage( - extent, resolution, pixelRatio, size, projection); + if (pixelRatio != 1) { + switch (this.serverType_) { + case ol.source.wms.ServerType.GEOSERVER: + var dpi = (90 * pixelRatio + 0.5) | 0; + goog.object.set(params, 'FORMAT_OPTIONS', 'dpi:' + dpi); + break; + case ol.source.wms.ServerType.MAPSERVER: + goog.object.set(params, 'MAP_RESOLUTION', 90 * pixelRatio); + break; + case ol.source.wms.ServerType.QGIS: + goog.object.set(params, 'DPI', 90 * pixelRatio); + break; + default: + goog.asserts.fail(); + break; + } + } + + extent = extent.slice(); + var centerX = (extent[0] + extent[2]) / 2; + var centerY = (extent[1] + extent[3]) / 2; + if (this.ratio_ != 1) { + var halfWidth = this.ratio_ * (extent[2] - extent[0]) / 2; + var halfHeight = this.ratio_ * (extent[3] - extent[1]) / 2; + extent[0] = centerX - halfWidth; + extent[1] = centerY - halfHeight; + extent[2] = centerX + halfWidth; + extent[3] = centerY + halfHeight; + } + + var imageResolution = resolution / pixelRatio; + + // Compute an integer width and height. + var width = Math.ceil((extent[2] - extent[0]) / imageResolution); + goog.object.set(params, 'WIDTH', width); + var height = Math.ceil((extent[3] - extent[1]) / imageResolution); + goog.object.set(params, 'HEIGHT', height); + + // Modify the extent to match the integer width and height. + extent[0] = centerX - imageResolution * width / 2; + extent[2] = centerX + imageResolution * width / 2; + extent[1] = centerY - imageResolution * height / 2; + extent[3] = centerY + imageResolution * height / 2; + + var axisOrientation = projection.getAxisOrientation(); + var bbox; + if (v13 && axisOrientation.substr(0, 2) == 'ne') { + bbox = [extent[1], extent[0], extent[3], extent[2]]; + } else { + bbox = extent; + } + goog.object.set(params, 'BBOX', bbox.join(',')); + + var url = goog.uri.utils.appendParamsFromMap(this.url_, params); + + this.image_ = new ol.Image(extent, resolution, pixelRatio, url, + this.crossOrigin, this.getAttributions()); return this.image_; + };