OpenLayers – Fixing Image Layers Misplacement on Google Maps V3 and OSM

coordinate systemopenlayers-2

Summary:

I have 2 different image layers that looked fine with my old mapstraction/google maps based system. Using the same coordinates as bounds in openlayers results in a shift to the north by like 100 miles.

  • potentially most important is that this seems to be limited to the image layers only. For all of the vector-based layers I've looked at (vector based markers and vector based polylines), they all seem to be in the right spot when compared to the old system.
  • one image layer is an image of text where the original coordinates were chosen somewhat arbitrarily so the fact that it's shifted north is not a big deal (screenshot example: https://img.skitch.com/20110427-jj62ac75y8eihms3gxxfr15371.jpg)
  • the other image layer is weather radar and it's absolutely essential that the image overlay be in the correct place (screenshot example: http://img.skitch.com/20110426-dxwtj44q4g9su5e58p9gc85x2s.jpg)
  • this happens with Google Maps v3 base layers and OpenStreetMap base layers. I have not tested other base layers
  • the original question below was centered around the weather radar problem because that's where I originally noticed the image overlay problem, but it would appear that whatever I'm doing wrong for the weather radar image layer is also being done wrong for the text/image overlay.

I'm new to OpenLayers, so I'm hoping I'm missing something obvious.

I'm trying to transition my maps to OpenLayers from Mapstraction (and before that it was just the plain Google Maps v3 API). I'm having issues with one of the images not aligning properly (though all other types of layers seem to work just fine).

Specifically, I'm trying to overlay a weather radar image (http://radar.weather.gov/ridge/Conus/RadarImg/latest_radaronly.gif) but it's not putting it in the correct place. I've tried using both OSM and Google Maps v3 base layers, and it always appears to be too far north.

Screenshot explanation: img.skitch.com/20110426-dxwtj44q4g9su5e58p9gc85x2s.jpg

I originally got the coordinates through the KMZ file that you can download here: www.srh.noaa.gov/ridge/kmzgenerator.php. Click on "Lower 48 States" under the "National & regional mosaics" section to get the KMZ file. Alternatively, the KML contents are viewable here: gist.github.com/942730

I'm assuming I'm not specifying the bounds for the image layer properly:

# full code in the example links below this

proj4326 = new OpenLayers.Projection("EPSG:4326");

bounds = new OpenLayers.Bounds();
bounds.extend(new OpenLayers.LonLat(-127.620375523875420, 21.652538062803));
bounds.extend(new OpenLayers.LonLat(-66.517937876818, 50.406626367301044));
bounds.transform(proj4326, mapObject.getProjectionObject());
radar_overlay = new OpenLayers.Layer.Image('radar', 'http://radar.weather.gov/ridge/Conus/RadarImg/latest_radaronly.gif', bounds, new OpenLayers.Size(3400, 1600), {
  'isBaseLayer': false,
  'alwaysInRange': true
});

Full Examples:

http://jsfiddle.net/hayley/C4rue/ – (out of place) – simplified example with OL and google maps v3

beta.wickedwx.com/ – (out of place) more complete example – on this map, there's also an orange dot for the radar location at Wichita, Kansas where there's usually a blue blob (ground clutter on the radar), but the blue blob ends up being placed near Salina, Kansas (screenshot example: img.skitch.com/20110426-dxwtj44q4g9su5e58p9gc85x2s.jpg)

http://wickedwx.com/ – working example that uses mapstraction and google maps v3

Best Answer

Hayley,

2nd UPDATE: Played around some more and got the radar overlay to work with OpenLayers. What I and a few others have referred to holds true here. The Ridge Radar gifs are really meant to go into Google Earth (though they might also play nice in Google Maps too). However, in OpenLayers, one does have to ensure that raster images are transformed to spherical mercator in order to display in Google Maps and Open Street Maps via OpenLayers. In order to do that, you have to geo-reference the raster to ESPG 4326 and then transform it to spherical mercator. Now I used GDAL to do the geo-referencing and also warping to spherical mercator. Here are the commands I used:

gdal_translate -of PNG -a_srs EPSG:4326 -a_ullr -127.62 50.41 -66.42 21.61 radar.gif radartemp1.png

gdalwarp -t_srs '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs' radartemp1.png radartemp2.png

gdal_translate -of PNG -outsize 80% 80% radartemp2.png radartemp3.png

The first line geo-references the image to EPSG 4326 and also converts to a PNG. Just used to doing that but you should be able to keep GIFs (-of GIF).

The second line converts the image to EPSG 900913 via the proj.4 commands in single quotes. I had tried using 900913 and also 3785/3857 in gdalwarp but my version of GDAL didn't like those. Found the proj.4 commands worked. Key to this was the +nadgrids=@null option. I found that in our geo-referencing things worked fine with the transformation that we were using for our initial GM prototype. However, our images were "squished" when we tried to use them for OL. Discovered after a search and also in the reference that snapwire_org indicated that this is critical to getting the grid transformed into spherical mercator.

Now I found that in order to work with EPSG 900913 in OL, I had to use meters for the projection instead of the lat lon bounds and just transform everything between the two:

Declaring the map:

map = new OpenLayers.Map("map", {

    projection: new OpenLayers.Projection("EPSG:900913"),
    units: "m",
    maxResolution: 156543.0339,
    maxExtent: new OpenLayers.Bounds(
        -20037508, -20037508, 20037508, 20037508.34),
    displayProjection: new OpenLayers.Projection("EPSG:4326"),
    controls: [
        new OpenLayers.Control.Navigation(),
        new OpenLayers.Control.KeyboardDefaults(),
        new OpenLayers.Control.PanZoomBar(),
        new OpenLayers.Control.Scale(),
        new OpenLayers.Control.Attribution()
    ]

});

Now for the image overlay:

// create spherical mercator base layers

var googleLayer = new OpenLayers.Layer.Google("Google Physical", {type: google.maps.MapTypeId.TERRAIN, visibility: true});
var gstr = new OpenLayers.Layer.Google("Google Streets", {type: google.maps.MapTypeId.ROAD, visibility: true});
var osmLayer = new OpenLayers.Layer.OSM("OpenStreetMap");

NOW I've entered the correct numbers here after the 3rd GDAL transformation step above for your use in the new OpenLayers.Bounds line below

// create overlay with first image (GMoverlay is a global);

GMoverlay= new OpenLayers.Layer.Image("Radar Overlay","radartemp3.png",
     new OpenLayers.Bounds(-14206593.415,2465071.940,-7394741.764,6517585.728),   
     new OpenLayers.Size(847,484),
     {isBaseLayer: false, opacity: 0.4,
      projection: new OpenLayers.Projection("EPSG:900913")});

//add layers to map

map.addLayers([googleLayer, gstr,osmLayer, GMoverlay]); 

Again, you can see in the Bounds, we're using meters:

new OpenLayers.Bounds(-14206593.415,2465071.940,-7394741.764,6517585.728)

You would get that info by running

gdalinfo radartemp3.png

The lower left and upper right coordinates of the transformed image are displayed in this command's output and then entered in the part above when declaring the new OL Image.

In going back and forth between meters and standard Lat/Lon, you have to use OL transforms like this one for setting the initial center:

map.setCenter(new OpenLayers.LonLat(-80, 40).transform(
        new OpenLayers.Projection("EPSG:4326"),
        map.getProjectionObject()),5);

You need to be careful here using transform on geometries as I discovered when grabbing a point on the map. This is also discussed in that link on spherical mercator and here's the relevant statement:

"Because all transforms are in place, once you have added a geometry to a layer, you should not call transform on the geometry directly: instead, you should transform a clone of the geometry:"

The referenced link that snapwire_org mentioned has a good deal of what I refer to here.

Also note that the size of the image is about a quarter the size of radartemp3.png. That's because you have to reduce the size number the farther out you zoom. So, you can't use 3700 x 1600 of the original image.

This really should be the answer you're looking for. I checked it myself in a test OL app with much of the pieces above and it projected spot on to what was being displayed at weather.gov. You still will have to do the geo-referencing and transformations. But GDAL is also open source and easy to install.

Tell you, it took a while to find that proj.4 option for our transformations. Then I pieced together several references which set up the map and image overlay in meters (including the one from snapwire_org) and then did transformations for points between 4326 and 900913. Worked like a charm then.

Good luck!