Google
 

Sunday, September 11, 2011

Reprojection to EPSG:900913 using MapServer

If you are embedding a map on some web page (read: OpenLayers) and need to add layers from some third party GIS server, you're most likely to come across the word "Mercator" and its myriads of standards. Web based mapping services use Spherical Mercator, however commercial GIS services (like, Esri) might use some other standards like EPSG:4326. This incompatibility leads to a lot of trouble as OpenLayers only accepts Spherical Mercator.

From OpenLayers Docs:
Spherical Mercator is a de facto term used inside the OpenLayers community – and also the other existing Open Source GIS community – to describe the projection used by Google Maps, Microsoft Virtual Earth, Yahoo Maps, and other commercial API providers.

This term is used to refer to the fact that these providers use a Mercator projection which treats the earth as a sphere, rather than a projection which treats the earth as an ellipsoid. This affects calculations done based on treating the map as a flat plane, and is therefore important to be aware of when working with these map providers.

In order to properly overlay data on top of the maps provided by the commerical API providers, it is neccesary to use this projection. This applies primarily to displaying raster tiles over the commercial API layers – such as TMS, WMS, or other similar tiles.

In order to work well with the existing commercial APIs, many users who create data designed for use within Google Maps will also use this projection. One prime example is OpenStreetMap, whose raster map tiles are all projected into the ‘spherical mercator’ projection.

Projections in GIS are commonly referred to by their “EPSG” codes, identifiers managed by the European Petroleum Survey Group. One common identifier is “EPSG:4326”, which describes maps where latitude and longitude are treated as X/Y values. Spherical Mercator has an official designation of EPSG:3857. However, before this was established, a large amount of software used the identifier EPSG:900913. This is an unofficial code, but is still the commonly used code in OpenLayers. Any time you see the string “EPSG:4326”, you can assume it describes latitude/longitude coordinates. Any time you see the string “EPSG:900913”, it will be describing coordinates in meters in x/y.

If you are to overlay third party GIS layer, which is not in spherical mercator, you'll have to reproject the layer.
One of the reasons that the Spherical Mercator projection is so important is that it is the only projection which will allow for overlaying image data on top of commercial layers like Google Maps correctly. When using raster images, in the browser, it is not possible to reproject the images in the same way it might be in a ‘thick’ GIS client. Instead, all images must be in the same projection.

There are several tools for reprojection, but the popular (and free) one is MapServer. The process is explained here. The process works like this:

However this doesn't work. It turned out, MapServer doesn't reproject to 900913 properly (even after adding the 900913 reprojection line to /usr/share/proj/epsg). Maybe a bug.

So here's the hack: MapServer does reproject to EPSG:3857. But EPSG:3857 and EPSG:900913 are same thing. So we need to write an intermediate proxy which takes WMS request for 900913, replaces the 900913 to 3857 in the WMS request URL and redirects the request to MapServer.

Here's the PHP script (reproject.php) to act as proxy:

<?php
header("Location: http://{mapserver_address}/cgi-bin/mapserv?" . str_ireplace("epsg%3A900913","epsg%3A3857",$_SERVER['QUERY_STRING']));


1. Install MapServer. In Ubuntu,

sudo apt-get install apache2 php5 cgi-mapserver mapserver-bin


for verification, check http://localhost/cgi-bin/mapserv

2. Put the reproject.php file to web root (/var/www)

3. Write a configuration file (say, wms.map) and place it in the same folder as mapserv (usually at /usr/lib/cgi-bin/)

MAP

NAME "reprojected_wms"
PROJECTION
"init=epsg:3857"
END

WEB
IMAGEPATH "/var/www/docs_maps/"
IMAGEURL "http://{mapserver_address}/docs_maps/"

METADATA
"wms_title" "Reprojected WMS
"wms_onlineresource" "http://{mapserver_address}/reproject.php?map=wms.map&"
"wms_srs" "EPSG:3857"
"wms_server_version" "1.1.1"
END
END

EXTENT 8865484.246776307 3016430.900654626 9864020.0791919 3587377.91450212

LAYER
NAME "My Layer
TYPE RASTER
STATUS OFF
CONNECTION "http://{GIS_Server}/WMSServer?"
CONNECTIONTYPE WMS
PROJECTION
"init=epsg:3857"
END
METADATA
"wms_title" "GIS Layer"
"wms_srs" "EPSG:3857"
"wms_name" "1"
"wms_server_version" "1.1.1"
"wms_format" "image/png"
"wms_cache_to_disk" "1"
END

END
CONFIG "PROJ_LIB" "/usr/share/proj"

END


Now use the WMS URL http://{mapserver_address}/reproject.php?map=wms.map& wherever needed.

Many thanks to Prabhas for devising the steps and helping me with this blog.

Saturday, September 10, 2011

File upload over web is broken!

XKCD had a nice comic on 'File Transfer' yesterday.


The comic neatly illustrates the woes of transferring files. However this makes one realize another side of the story:

File upload over web is broken!

Have you realized that every browser now has more-or-less functional download manager and features like pause/resume. Even almost all web servers support partial file download, and the feature is exploited by myriads of download accelerators out there.

But how about file uploads? You choose the file, hit the Upload button, and wait! No such thing as progress bars, upload pause/resume and, obviously, upload-accelerators are out of question.

This was okay some years back, when the web was mostly one way business. Not anymore! Nowadays we upload videos, photos and a lot of other large sized files. And how the browsers support the process?




And that's it! Some versions back, there wasn't any such indicator available altogether.

There are workarounds though, like using Flash or Java. Or even better using HTML5. But the whole upload process needs some serious overhauling.

Saturday, September 03, 2011

Weird behaviour while rotating image in C#

I was working on an image processing code in C#. Had to rotate an image by few degrees around a specified point. This can be done either by transformation or matrix method.

private Bitmap rotateImage(Bitmap b, int x, int y, float angle)
{
//create a new empty bitmap to hold rotated image
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);

//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(returnBitmap);

Matrix m = new Matrix();
m.RotateAt((float)angle, new PointF(x,y));

g.Transform = m;
g.DrawImage(b, 0, 0);

return returnBitmap;
}

However this wont work properly. It rotates the image, but strangely enough at the same time scales it down too (on larger images).

After some digging into MSDN, found this page, http://msdn.microsoft.com/en-us/library/1bttkazd.aspx, which says:

GDI+ may automatically scale an image as you draw it, which would decrease performance. Alternatively, you can control the scaling of the image by passing the dimensions of the destination rectangle to the DrawImage method.
So to avoid scaling, the above DrawImage line should be changed to

g.DrawImage(b, 0, 0, b.Width, b.Height);

I have no idea why any function would have "automatic" behaviour. But this is how it works. Weird.