Some of these maps are available via Web Map Service WMS interfaces as specified by the OGC. WMS is essentially a standardised interface to maps on the Web that allows a client to specify the format (e.g. PNG), the size (e.g. 320x460) and the exact geographical coordinates: and what the user gets in return in an image.
That makes it very easy to overlay Google Maps with all sorts of imagery, particularly satellite imagery.
For this we start out defining a new Overlay class, WMSClient:
private class WMSOverlay extends Overlay {
@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
super.draw(canvas, mapView, shadow);
WMSLoader wmsclient = new WMSLoader();
GeoPoint[] cornerCoords = MapUtils.getCornerCoordinates(mapView.getProjection(), canvas);
Bitmap image = wmsclient.loadMap(canvas.getWidth(), canvas.getHeight(), cornerCoords[0], cornerCoords[1]);
Paint semitransparent = new Paint();
semitransparent.setAlpha(0x888);
canvas.drawBitmap(image, 0, 0, semitransparent);
}
}
It is very simple: it somehow gets a Bitmap image from a class WMSLoader, to which I come in a second. Then it simply draws that image on the canvas, making it here semitransparent, so we see the underlying Google image.
To get the WMS image we first need to get the corner coordinates of the screen, which is not very difficult as the projection object has a translation function for this (0,0) is the left top corner, and the right bottom is (width(), height()).
Now to our WMSLoader:
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.google.android.maps.GeoPoint;
public class WMSLoader {
public static String TAG = "WMSLoader";
public Bitmap loadMap(int width, int height, GeoPoint ul, GeoPoint lr) {
URL url = null;
try {
url = new URL(String.format("http://iceds.ge.ucl.ac.uk/cgi-bin/icedswms?" +
"LAYERS=lights&TRANSPARENT=true&FORMAT=image/png&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application/vnd.ogc.se_inimage&SRS=EPSG:4326" + "" +
"&BBOX=%f,%f,%f,%f&WIDTH=%d&HEIGHT=%d",
MapUtils.longitude(ul), MapUtils.latitude(lr),
MapUtils.longitude(lr), MapUtils.latitude(ul), width, height));
} catch (MalformedURLException e) {
Log.e(TAG, e.getMessage());
}
InputStream input = null;
try {
input = url.openStream();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
return BitmapFactory.decodeStream(input);
}
This class here has most of the URL hard-coded for proof of concept. Here we get an image from the ICEDS server, an academic WMS Server at University College London. In this case the 'lights' layer, which shows night-time light pollution - an indication of populatio density (or industrial activity). We just compose the complete URL, then open the input stream, where we get the image and pass it back to our Overlay. Bingo.
(There is a thing about projections: Google Maps uses a form of Mercator, the one supported by the ICEDS server is WGS84. That means pixels will not lie exactly on top of each other, but it matters most when the image is zoomed out. We would need a server supporting the Google Maps projection to be exact....)
Anyway, this is how it looks on the screen:
