Abstract
MapTilesBuilder is the simple Java console application to create a set of map tiles for Google Maps API based web maps.
MapTilesBuilder has been originally built by ITRoadLabs project, so you can find some information (in Russian) on the project site http://itroadlabs.appspot.com
The Key Idea
If you want to build simple Google Maps web application you will need to create custom tiles based on your own geospatial dataset. The common practice is to use web maps servers: MapServer, GeoServer, and Oracle MapViewer.
But sometimes you have hosting restrictions which prevents you from installing web maps server on your hosting. Or you are limited in resources on your server (memory, CPU).
There is the way to create web maps application without maps servers - just to generate map tiles somewhere outside of your server and deploy those tiles (pictures) on the server as a static content.
How to create map tiles set? MapTilesBuilder will do it for you...
How does it work?
MapTilesBuilder interacts with WMS server (MapServer, GeoServer, Oracle MapViewer), and WMS server provides tile images.
MapTillesBuilder requests WMS server (via HTTP) to render a tile (picture) with specified bounds, and WMS server responses with rendered tile image. You just need to provide tiles pane bounds (map window) - latitudes/longitudes, and zooms range (Google Maps zooms).
Thereby MapTilesBuilder:
- Calculates tile position (x,y) in the Google Maps tiles matrix; for specified zoom,
- Calculates tile bounds (latitude/longitude) by tile position (x,y) and specified zoom,
- Creates WMS HTTP request to WMS server.
After response with tile image received, the tile image will be saved on the disk with appropriate file name. For an example "2342_3433_17.png" - where 2342 and 3433 are tile position (x,y), and 17 is the zoom number.
Also MapTilesBuilder has additional and very important feature - indexing. Look at the picture below:
This example illustrates one important thing - there may be a lot of "empty" tiles, i.e. tiles with no map objects. You can ignore this, but this means you will have overhead at tiles disk storage size and overhead at WMS server load (it is not necessary to render "empty" tiles). As a result tiles will be rendered longer.
How to avoid it? To avoid it we can use indexes. For an example, following SQL shows how many map objects are there in the tile bounds (PostgesSQL/PostGIS syntax):
SELECT COUNT(*) FROM streets_geom
WHERE Intersects(GeomFromText('POLYGON((:minX, :maxY, :maxX, :maxY,
:maxX, :minY, :minX, :minY, :minX, :maxY'))), the_geom) = TRUE
Where parameters minX, minY, maxX, maxY - tile bounds (latitude/longitude).
So, if you are executing the query above for each tile in the map tiles pane, then you have some kind of index - just the matrix "m"; when m[x,y] = 0 - there are no map objects in the tile position (x,y), m[x,y] > 0 - the opposite.
Next - you only request WMS server for tiles with m[x,y] > 0. That way we have a very good performance effect.
Afterward we have a tiles set and indexes. How to use it? Look at the example below (Java Servlet):
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int x = Integer.parseInt(request.getParameter("x"));
int y = Integer.parseInt(request.getParameter("y"));
int zoom = Integer.parseInt(request.getParameter("zoom"));
if (tilesIndex.forZoom(zoom).isEmpty(x,y)) {
forward("/map-tiles/transparent-stub.png", request, response);
} else {
forward("/map-tiles/" + zoom + "/" + x + "_" + y + ".png", request, response);
}
}
And on the page, there is JavaScript code to work with tiles servlet (Google Maps API):
tileLayer.getTileUrl = function(tile, zoom) {
return '/tiles-servlet?z=' + zoom + '&x=' + tile.x + '&y=' + tile.y;
};
Yes, this technique has disadvantages. For example, you are unable to create "real-time" updated maps. Yes, sure... But two questions:
- Is it always required??
- Do you really need it??
Anyway, it is possible to have special automatic tool to track map changes and redeploy rendered tiles (redeploy only changed tiles).