[OpenLayers-Users] HOWTO: Using TMS and openlayers to view a tiled
image that crosses the 180 line.
Phil Scadden
p.scadden at gns.cri.nz
Wed Jun 15 00:51:21 EDT 2011
I've battled with Openlayers code for days trying to achieve this. In
the end, I used custom options and my own code. I cant figure out how
things go wrong and this code is awfully cumbersome but it does have the
advantage of that it works. I'm putting this up in hopes it might help
other folk not waste time. I would just love to see someone competent
come along and clean this up.
Firstly, creating a TMS that crosses the 180 line:
I could not find a tool to do this. I achieved it in two steps. Split
the image on the 180 (or generate the two image sets one for each side
of the 180). I used mapTiler to create a TMS directory for each. Then in
Windows, I used explorer to copy all the upper level directories (there
will be one for each zoom), and then pasted them into the top level of
the second directory. There is usual caveat about overwriting files of
same name, but while there will be directories with same, there arent
files of same name and windows does the job nicely.
Now using it in openlayers. The immediate problem is that if you dont
specify a maxExtent for the layer, then you get pink tiles where the TMS
isnt defined. Worse still, after the first draw in Firefox, if you zoom,
pan, then instead of pink tiles you get old tiles! Despite the DOM for
the tile being correct. I point to a blank png instead. However, how do
you specify a maxExtent that crosses the 180? Worse, if you specify a
maxEntent for the layer that is different from map.maxExtent, then it
screws up the tile layout. Never figure that out, and OL just doesnt
deal with bounds where left coord is positive and right coordinate is
negative. There are ways to specify min and max zoom for a layer but boy
are they difficult to use. Instead, I added 3 parameters to the options
when creating the layer, minZoom, maxZoom and instead of maxExtent (dont
specify), I put in tileExtent which is a bounds which will have positive
left and negative right. The OL getTileURL code doesnt work (cant make
it work for ANY TMS that doesnt cover entire extent, so overwrote the
getTileURL based on the autocreated version that comes with mapTiler
(who obviously hit similar issues).
So, my layer create looks like this:
var magneticAnomaly = new OpenLayers.Layer.TMS(
"Magnetic", "data",
{serviceVersion: '', layername: "mage1",
type: 'png', wrapDateLine:true,
getURL: overlay_getTileURL,
tileExtent :mapBounds,
mapMinZoom:3, mapMaxZoom:8,
alpha: true, displayOutsideMaxExtent:true,
isBaseLayer: false
});
Note: displayOutsideMaxExtent, getURL,mapMinZoom and mapMaxZoom, and of
course getURL
mapBounds is for example;
var mapBounds = new OpenLayers.Bounds( 159.999999951,
-55.991879165, -172.0, -30.0);
mapBounds.transform(p4326, map.projection );
Now some custom functions:
I think that tile.adjustBounds method is supposed to do something
similar but I couldnt figure it out.
function adjustBounds(bounds,extent) {
if ((bounds.left - extent.left)<-1) {
bounds.left = (bounds.left - extent.left) + extent.right;
bounds.right = (bounds.right - extent.left) + extent.right;
} else if ((bounds.right - extent.right)>1) {
bounds.left = extent.left + (bounds.left - extent.right);
bounds.right = extent.left + (bounds.right - extent.right);
}
}
And here is the custom getTileURL, modified from mapTiler.
function overlay_getTileURL(bnds) {
var bounds = bnds.clone();
adjustBounds(bounds,this.maxExtent);
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.maxExtent.left)
/ (res * this.tileSize.w));
// the above it not a typo - this.tileOrigin.lon doesnt seem to work
var y = Math.round((bounds.bottom -
this.tileOrigin.lat) / (res * this.tileSize.h));
var z = this.map.getZoom();
if (this.map.baseLayer.name == 'Virtual Earth Roads' ||
this.map.baseLayer.name == 'Virtual Earth Aerial' ||
this.map.baseLayer.name == 'Virtual Earth Hybrid') {
z = z + 1;
}
if (this.tileExtent.left > this.tileExtent.right) {
var b1 = new OpenLayers.Bounds(this.tileExtent.left,
this.tileExtent.bottom,this.map.maxExtent.right,this.tileExtent.top);
var b2 = new
OpenLayers.Bounds(this.map.maxExtent.left,
this.tileExtent.bottom,this.tileExtent.right,this.tileExtent.top);
if ( (b1.intersectsBounds(bounds) ||
b2.intersectsBounds(bounds)) && z >= this.mapMinZoom && z <=
this.mapMaxZoom ) {
return this.url + this.serviceVersion + "/" +
this.layername + "/" + z + "/" + x + "/" + y + "." + this.type;
} else {
return "images/none.png";
}
}else{
if ( this.tileExtent.intersectsBounds(bounds) && z >=
this.mapMinZoom && z <= this.mapMaxZoom ) {
return this.url + this.serviceVersion + "/" +
this.layername + "/" + z + "/" + x + "/" + y + "." + this.type;
} else {
return "images/none.png";
}
}
}
The code will even work for images that dont cross the 180.
Notice: This email and any attachments are confidential. If received in error please destroy and immediately notify us. Do not copy or disclose the contents.
More information about the Users
mailing list