Issues were found with Leaflet when trying to use WMS and ESRI services with polar stereographic projections (in particular was using EPSG:3031 but issues would apply to may other projections. We found working solutions (see below) but at the core, there are issues with Leaflet core objects and we are not keen on doing what feels like open-heart surgery on unfamiliar code.
There are two main issues.
Firstly, the lat/long coordinates for a tile or map are calculated and then stored in a bounds object that is unsafe. Only two corners are used to define the lat/long bounds which has the implicit assumption that say latitude of southwest corner is the same as the latitude of the southeast corner. Many projections other than polar stereographic invalidate that assumption. Our fix avoided the bounds object but we suspect that other parts of leaflet will not be functioning accurately because of the way the bounds object is used. Bounds should be modified so 4 corner point can be used to define it; midpoint takes account of dateline; explicit calculation of corners.
Secondly, Leaflet assumes that an increasing y axis => increasing latitude. Consider a polar map with pole at the center. (any polar projection). For the whole of the map, projected y coordinates increase from the bottom of the map to the top of the map. However starting from bottom, abs(latitude) increases till the pole is reached and then decreases as move top of the map.
This fiddle demonstrates the problem. https://jsfiddle.net/dandooley/qj8q834w/
The AGS layer (the graticle) is not on pole, and if you zoom out, it moves in ever worse position.
The WMS layer (a geology map) is smeared into a vertical bar, right of center.
Without modifying leaflet L.Bounds class, we have fixed the WMS code with this version of getTileUrl
getTileUrl: function (coords) {
var tileBounds = this._tileCoordsToNwSe(coords),
nw = this._crs.project(tileBounds[0]),
se = this._crs.project(tileBounds[1]);
if (se.y > nw.y){
var temp = nw;
nw = se;
se = temp;
console.log("Switch Y");
}
var bbox = (this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
[se.y, nw.x, nw.y, se.x] :
[nw.x, se.y, se.x, nw.y]).join(','),
url = L.TileLayer.prototype.getTileUrl.call(this, coords);
return url +
L.Util.getParamString(this.wmsParams, url, this.options.uppercase) +
(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
}
and this alteration to L.GridLayer
and this within L.GridLayer:
_tileCoordsToNwSe: function (coords){
var map = this._map,
tileSize = this.getTileSize(),
nwPoint = coords.scaleBy(tileSize),
sePoint = nwPoint.add(tileSize),
nw = map.unproject(nwPoint, coords.z),
se = map.unproject(sePoint, coords.z);
return [nw,se];
},
// converts tile coordinates to its geographical bounds
_tileCoordsToBounds: function (coords) {
var bp = _tileCoordsToNwSe(coords),
bounds = new L.LatLngBounds(bp[0], bp[1]);
if (!this.options.noWrap) {
map.wrapLatLngBounds(bounds);
}
return bounds;
}
DynamicMapLayer in AGS can fixed with this:
Then the AGS Fix within DynamicMapLayer:
_buildExportParams: function () {
// var bounds = this._map.getBounds();
// var size = this._map.getSize();
// var ne = this._map.options.crs.project(bounds.getNorthEast());
// var sw = this._map.options.crs.project(bounds.getSouthWest());
// var sr = parseInt(this._map.options.crs.code.split(':')[1], 10);
//
// // ensure that we don't ask ArcGIS Server for a taller image than we have actual map displaying
// var top = this._map.latLngToLayerPoint(bounds._northEast);
// var bottom = this._map.latLngToLayerPoint(bounds._southWest);
//
// if (top.y > 0 || bottom.y < size.y) {
// size.y = bottom.y - top.y;
// }
var bounds = this._map.getPixelBounds();
var sw = this._map.unproject(bounds.getBottomLeft());
var ne = this._map.unproject(bounds.getTopRight());
var size = this._map.getSize();
var ne_p = this._map.options.crs.project(ne);
var sw_p = this._map.options.crs.project(sw);
// ensure that we don't ask ArcGIS Server for a taller image than we have actual map displaying
var top = this._map.latLngToLayerPoint(ne);
var bottom = this._map.latLngToLayerPoint(sw);
if (top.y > 0 || bottom.y < size.y) {
size.y = bottom.y - top.y;
}
var sr = parseInt(this._map.options.crs.code.split(':')[1], 10);
if (sw_p.y > ne_p.y){
var temp = ne_p;
ne_p = se_p;
se_p = temp;
console.log("Switch Y");
}
var params = {
bbox: [sw_p.x, sw_p.y, ne_p.x, ne_p.y].join(','),
size: size.x + ',' + size.y,
dpi: 96,
format: this.options.format,
transparent: this.options.transparent,
bboxSR: sr,
imageSR: sr
};
Phil Scadden & Dan Dooley
thanks for the thorough writeup @scaddenp.
it _looks like_ you've identified an appropriate and self-contained improvement for Leaflet's support for WMS layers in polar projections. are you game for submitting the changes as a pull request (without the console.log() statement)? this would help us see whether any unit tests are affected and make it more convenient for others to pull your work down.
it'd also be helpful if you could provide a link to a public WMS service that supports wkid:3031 exports if you have one handy.
as for the esri-leaflet suggestions, we can continue that discussion in https://github.com/Esri/esri-leaflet/issues/970.
I have never actually used Git so submitting a "pull request" sounds a little scary to me. While the patch is self-contained, it also feels somewhat like a hack and note that it also affects L.GridLayer (though it could be made more self-contained). The jsfiddle link in the original issue points to a public WMS layer on our server maps.gns.cri.nz/geology/web server which does support 3031. It is part of our contribution to the OneGeology project so should be around for a while.
If there is a comprehensive test suite, I would rather tempted to attempt an additive modification of L.Bounds. Add a constructor to use 4 corners, add _se,_sw,_nw,_ne vars, Modify existing methods to use them.
Looked of github docs. I will attempted to create a branch, and make a pull request for just the WMS/GridLayer stuff.
Just curious but is it possible to do a backport with github? We really need this in 1.0.3 as 1.1 breaks plugins. Can do it manually (doing at moment) but curious.
@scaddenp sorry to hear that! Any particular plugins you rely on that break? While we can't fix all plugins, it is _probably_ pretty straight forward to fix most, and we might be able to give some help on how to do that.
While it would be theoretically possible to do a 1.0.4 release with these changes, it's not likely this is something we will do, given there's a fair amount of work involved in a release, and we're pretty limited on resources (time) for maintenance.
If you really need this in 1.0.3, I think you're probably better off handling that yourself at this point.
Leaflet. Draw. Seems bogged down. I made own backport for moment
On 12/07/2017 22:03, Per Liedman notifications@github.com wrote:
@scaddenphttps://github.com/scaddenp sorry to hear that! Any particular plugins you rely on that break? While we can't fix all plugins, it is probably pretty straight forward to fix most, and we might be able to give some help on how to do that.
While it would be theoretically possible to do a 1.0.4 release with these changes, it's not likely this is something we will do, given there's a fair amount of work involved in a release, and we're pretty limited on resources (time) for maintenance.
If you really need this in 1.0.3, I think you're probably better off handling that yourself at this point.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/Leaflet/Leaflet/issues/5617#issuecomment-314715945, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AANvEdV-3-b-b4xWXzbW1yd8juo671PZks5sNJnUgaJpZM4OSQfb.
Notice: This email and any attachments are confidential and may not be used, published or redistributed without the prior written consent of the Institute of Geological and Nuclear Sciences Limited (GNS Science). If received in error please destroy and immediately notify GNS Science. Do not copy or disclose the contents.
It looks like this can be closed since #5618 has been merged. There might still be some outstanding issues with using polar projections effectively in Leaflet, but I think we should have separate issues for those.