How to get bounds of a google static map?

user1514958 picture user1514958 · Sep 20, 2012 · Viewed 15.9k times · Source

How to get bounds in degrees of google static map which has been returned, for example, for following request

http://maps.googleapis.com/maps/api/staticmap?center=0.0,0.0&zoom=10&size=640x640&sensor=false

As I know, full Earth map is 256x256 image. This means that n vertical pixels contain x degrees, but n horizontal pixels contain 2x degrees. Right?

As google says center defines the center of the map, equidistant from all edges of the map. As I understood equidistant in pixels (or in degrees?). And each succeeding zoom level doubles the precision in both horizontal and vertical dimensions. So, I can find delta value of Longitude of map for each zoom value as:

dLongitude = (HorizontalMapSizeInPixels / 256 ) * ( 360 / pow(2, zoom) );

Same calculations for Latitude:

dLatitude = (VerticalMapSizeInPixels / 256 ) * ( 180 / pow(2, zoom) );

VerticalMapSizeInPixels and HorizontalMapSizeInPixels are parameters of map size in URL.

It's good to calculate delta value of Longitude, but for Latitude it is wrong. I cannot find delta value of Latitude, there is some delta error.

Answer

Marcelo picture Marcelo · Sep 20, 2012

As I know, full Earth map is 256x256 image.

Yes.

This means that n vertical pixels contain x degrees, but n horizontal pixels contain 2x degrees. Right?

No. One pixel will represent varying amounts of latitude depending on the latitude. One pixel at the Equator represents less latitude than one pixel near the poles.

The corners of the map will depend on center, zoom level and map size, and you'd need to use the Mercator projection to calculate them. If you don't want to load the full API, here's a MercatorProjection object:

var MERCATOR_RANGE = 256;

function bound(value, opt_min, opt_max) {
  if (opt_min != null) value = Math.max(value, opt_min);
  if (opt_max != null) value = Math.min(value, opt_max);
  return value;
}

function degreesToRadians(deg) {
  return deg * (Math.PI / 180);
}

function radiansToDegrees(rad) {
  return rad / (Math.PI / 180);
}

function MercatorProjection() {
  this.pixelOrigin_ = new google.maps.Point( MERCATOR_RANGE / 2, MERCATOR_RANGE / 2);
  this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
  this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
};

MercatorProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {
  var me = this;

  var point = opt_point || new google.maps.Point(0, 0);

  var origin = me.pixelOrigin_;
  point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
  // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
  // 89.189.  This is about a third of a tile past the edge of the world tile.
  var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999, 0.9999);
  point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -me.pixelsPerLonRadian_;
  return point;
};

MercatorProjection.prototype.fromPointToLatLng = function(point) {
  var me = this;

  var origin = me.pixelOrigin_;
  var lng = (point.x - origin.x) / me.pixelsPerLonDegree_;
  var latRadians = (point.y - origin.y) / -me.pixelsPerLonRadian_;
  var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
  return new google.maps.LatLng(lat, lng);
};

//pixelCoordinate = worldCoordinate * Math.pow(2,zoomLevel)

You can save that to a separate file, for example "MercatorProjection.js", and then include it in your application.

<script src="MercatorProjection.js"></script>

With the above file loaded, the following function calculates the SW and NE corners of a map of a given size and at a given zoom.

function getCorners(center,zoom,mapWidth,mapHeight){
    var scale = Math.pow(2,zoom);
    var centerPx = proj.fromLatLngToPoint(center);
    var SWPoint = {x: (centerPx.x -(mapWidth/2)/ scale) , y: (centerPx.y + (mapHeight/2)/ scale)};
    var SWLatLon = proj.fromPointToLatLng(SWPoint);
    alert('SW: ' + SWLatLon);
    var NEPoint = {x: (centerPx.x +(mapWidth/2)/ scale) , y: (centerPx.y - (mapHeight/2)/ scale)};
    var NELatLon = proj.fromPointToLatLng(NEPoint);
    alert(' NE: '+ NELatLon);
}

and you'd call it like this:

var proj = new MercatorProjection();
var G = google.maps;
var centerPoint = new G.LatLng(49.141404, -121.960988);
var zoom = 10;
getCorners(centerPoint,zoom,640,640);