[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