Friday, October 18, 2013





How to Leverage Microsoft XNA for the development of GIS (Geographical Information System)


Introduction


In this article, I will discuss a problem about how we can calculate the latitude and longitude information for a particular location, without using any online service such as Microsoft, or Google map service. Although I have taken the image data from Google, all the background processing for calculating the latitude and longitude is done by me using Mercator projection method. I have included the code files to demonstrate how you can convert the mouse position on the map to real world latitude and longitude values, which is demonstrated in the figure below:



In the upper left corner of the window above X, Y show the screen co-coordinates for the Yellow pointer and latitude and longitude show the real world latitude and longitude of the Yellow pointer on to the screen. If you run the application file included with this article, you will see that mouse co-ordinates (X,Y) will be shown on the screen and their real world latitude and longitude values as soon as you move the mouse in the application window.

What is the Problem?

The things such as XNA framework, Mercator projection formulas are easily available. The main problem is to convert Latitude and longitude values to screen co-ordinates. It was the requirement in one of my projects.
You can easily understand the Mercator projection, but to apply that to Google images and to program that in the computer is a slightly difficult problem. In order to apply Mercator projection, you need to calculate different parameters such as radius, circumference and others. I have addressed all these difficulties and implemented the Mercator projection using C#.NET. Similar to Mercator projection, there are more advanced projections available which are more accurate, but for the sake of simplicity, I chose the Mercator projection. You can utilize the information present in this article to apply to different projections methodologies.

What is Mercator Projection?

To define it simply, a projection in the field of cartography is a field in which you draw the map of the whole world which is 3D onto a 2 dimensional surface. Mercator projection is a kind of projection. In Mercator projection, each and every individual point on the earth is first projected to inside surface of a cylinder and then that cylinder expanded to view the whole globe. Mercator projection model can be found on the internet easily and there is a good description of Mercator projection on Wikipedia.
There are some limitations to Mercator projection. One is that the formula is not defined for 90 degree values, another is values obtain from these formulas contain some error which is very tiny.

How Google People Arrange their Map?

Google people also use the Mercator projection. They organize images at different zoom levels. Zoom level ranges from 1 to 19. At each zoom level, they have divided the map into tiles. Each tile consists of 256*256 pixels. There are different number of tiles for each zoom level. Number of tiles per zoom level is given by:
Total number of tiles = 2 ^ (2*zoom Level)
Hence it shows that more zoom level means more number of tiles and more information and detail is present. Since Google has arranged their maps in tiles, it is easier to work with them because the smallest unit of the map is not meter or centimeter but it is a pixel which is easier to work when working with graphics and computer programming.

Steps to Translate from Latitude and Longitude to 2 Dimensional Co-ordinates(x, y)

Step 1

The very first step is to define zoom level.
this.zoomLevel = zoomLevel; // ranges from 1 to 19

Step 2

In this, we have to calculate the circumference, radius and Centre of the projected map. First, we calculate the circumference. In order to calculate, we should know the zoom level and then we calculate the number of horizontal tiles of the projection.
Math.Pow(2, zoomLevel); // this statement gives us the number of tiles 
After that we multiply it by 256, which is the horizontal length of the projection, therefore:
this.circumference = 256 * Math.Pow(2, zoomLevel);
Once we know the circumference, it is easier to find the radius and centre of the projection.
Circumference = 2 * Pi * radius
Therefore:
this.radius = (this.circumference) / (2 * Math.PI); 
Similarly for calculating the centre:
this.centre = new RTPoint(this.circumference / 2, this.circumference / 2);
Where RTPoint is a class used to define any 2 dimensional point in x, y plane.

Step 3

In step 3, we will calculate the x from Longitude and y from latitude.
Calculating the x from longitude is much easier. You simply have to multiply the longitude value with the radius.
public double getXFromLongitude(double longInDegrees)
{ 
double x = 0;
double longInRadians = longInDegrees * Math.PI / 180;
x = this.radius *
longInRadians; 
After this, you will have to calculate the false easting. False easting is calculated for X, since it is the horizontal shift of the origin. For calculating false easting sometime you have to add with x component of the centre and sometime you have to subtract from the component. This will depend upon the part of the image you are considering or depend up the values of x. For example, if you are taking the image in India or Pakistan you will have to add with the centre, if you are considering the image of U.S you will have to subtract from the centre.
x = this.centre.getPointX()+ x; // adding the x to centre’s x 
return x; 
Now, for calculating y from latitude, you will have to apply the formula for Mercator projection whose implementation in programming language is as follows:
public double getYFromLatitude(double latInDegrees) 
double y;
double latInRadians = latInDegrees * Math.PI / 180;
// Log for the base of E i.enatural logarthim..
double logVal = Math.Log(((1 + Math.Sin(latInRadians)) / (1 - Math.Sin(latInRadians))),
 Math.E);
y = this.radius * 0.5 * logVal;
One thing to note in the above statement is that the base for the logarithm used is natural base (E).
Similarly in calculating the y from latitude, we have to calculate the false northing. Again for false northing is specific to image area or y values.
// False Northing....
y = this.centre.getPointY() - y;
return y;  
Up to this step, we now have the x and y values, but this x, y values are for the complete Mercator projection. These values are projection x, y values. For converting them to our specific map on screen, we have to perform some translations which are described in the next step.

Step 4

In this step, we have to convert the above calculated x, y values to screen co-ordinates. At higher zoom level, we can only display the map for a particular area. The limits of the size of map are bounded by the screen resolution. Therefore, in order to work with a portion of image first we must know the centre of that portion of image. While taking images from Google map service, you can specify the centre of the map and resolution of the map, hence this centre is the centre of that particular portion of map. In the above figure, the map is centre at latitude = 24.846605 and longitude = 67.028379, and the resolution for the image is 800 by 800 pixels.
Hence we find the x, y values at this centre.
double x = projection.getXFromLongitude(67.028379);
double y = projection.getYFromLatitude(24.846605);
screenMapCentre = new RTPoint (x, y);
After that, I will shift the centre to upper left corner of the screen, since in computer screen the x, y is set to (0,0) in the upper left corner. And the value of x increases if you move to right and value of y increases if you move downward. Therefore we have to shift the centre to upper left corner. Note that this shift is different from the shift that we have done while false easting and false northing, this shift is just for working with computer screen. Because the resolution of the complete map image is 800 by 800 therefore for shifting the centre you have to subtract 400 from both x, y.
x = x - 400; 
y = y - 400;
shiftedCentre = new RTPoint(x, y); 
Hence for getting screen coordinates, you will have to subtract the projection coordinates values from the shifted centre.
aDot.X = (float)(projection.getXFromLongitude(longitudeInRadian)
 - shiftedCentre.getPointX());
aDot.Y = (float)(projection.getYFromLatitude(latitudeInRadian)
- shiftedCentre.getPointY()); 
In this way, you can obtain the value of any position in latitude and longitude to in x, y format, and you can show a marker, dot, arrow or anything on that x, y value of computer screen. Note that the all these screen values are particular to your application only, not to the complete screen.

Steps to Translate from 2 Dimensional Co-ordinates to Latitude and Longitude

In this article, the code example which I provided contains the working functionality for converting mouse position to latitude and longitude. In my application, when pointing any location on the map it will display the latitude and longitude on the screen. For testing, you can put this latitude and longitude in Google earth and it will show the same position as shown by my application.
The method for converting 2D co-ordinate to latitude and longitude is simply the reverse procedure of the above method. Step 1 and Step 2 are similar since they are initialization steps.

Step 3

First we have to convert from screen x, y coordinate to Mercator projection x, y values and it is the reverse procedure for the step-5 above.
X = xMousePos +
shiftedCentre.getPointX()
Y = yMousePos + shiftedCentre.getPointY() 

Step 4

In this step, I will convert X to longitude and Y to latitude. For converting X to longitude, we will execute the following lines of code:
double longitude = 0; 
 // False Easting          
            xValue = xValue - this.centre.getPointX(); 
            longitude = xValue / this.radius; 
      longitude = longitude * 180 / Math.PI; 
Note that this time for we also perform the False easting exactly opposite as we were doing when converting from longitude to X.
Than we convert the Y value to latitude with the following code:
double latitude =0;
// opposite of false northing.
yValue =  this.centre.getPointY()- yValue; 
double InvLog = yValue / (this.radius * 0.5);
InvLog = Math.Pow(Math.E, InvLog);
latitude =  Math.Asin(  (InvLog - 1) / (InvLog + 1) );
latitude = latitude * 180 / Math.PI;
return latitude;  
The whole method is just the reverse of the above work which we have already done.
Hence in this way, we have converted the X, Y values to longitude and latitude values.

How Microsoft XNA Framework Helped Me?

Microsoft XNA is a fantastic framework for creating games for hobbyists and for non professional game developers. It is easier as compared to DirectX API. I use it because it is simple and easy to implement and one of my requirements was to display the values in real-time as soon as the user moved the cursor on the screen. Since games are built on such a model that when parameters of any texture or objects are changed, they are immediately reflected in the model. So I picked up an easier gaming API and show the values of latitude, longitude, X and Y values as soon as the user moves the mouse cursor on the computer screen.
You can use XNA framework with C# and .NET and you can utilize all the power given by the .NET Framework. You can also obtain values from other sources such as serial or USB port and can process and display those values onto the screen quite easily. Another feature of XNA is that it supports 3D graphics too.
You can easily download Microsoft XNA framework from Microsoft’s web site.

How do I Take Images from Google Map Service?

You can obtain register with Google maps API service and can work with them utilizing the key provided by Google, but I use the Google code playground tool. Code playground is a tool provided from Google maps API website, where you can run, test and debug your code. There is a very good documentation for Google maps API on that website from where you can read about the different service methods. For taking images, I utilize the service method as follows:
     var map;
        functioninitialize() {
      if(GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("map_canvas"));
      map.setMapType(G_SATELLITE_MAP); 
         map.setCenter(new GLatLng(24.846605, 67.028379),17); // defining the centre on 
     // the screen and zooming level.  
The above JavaScript code utilizes the Google map service class GMAP2 for creating a map and then calling the relevant methods.
The complete map will be displayed in the div area of an HTML page. On the HTML page, you can define the number of pixels for the map by defining the width and height of the div element as shown in the following code:
  <body onload="initialize()" onunload="GUnload()"> 
    <div id="map_canvas" style="width: 800px; height: 800px"></div>  
After the image is loaded, you can print screen and then with the help of any image editor such as Microsoft paint, paint.net or Photoshop you can extract the image and then you can use that image in your application.

What Interesting Things Others Can Do?

Well there are a lot of things which you can play around with such as accessing the GPS coordinate from GPS card or any other GPS device and show it on the GOOGLE map. You can also work with the features of XNA framework, I developed it in 2D, but you can also convert it into 3D. Other people can also calculate a proper method for calculating the false easting and false northing. One method is that they can define either to add or subtract depending upon the x, y values.
With the help of this simple programming model, you can develop the real-time GPS system, which displays the position of a particular object onto the Google Map. You can also use this programming model with the accelerometers to show the real-time positions with little error, because commercial GPSs are slow and do not provide much accuracy when placed on a fast moving vehicle hence you can build your own using 3 axis accelerometers.

Conclusion

One question asked by many colleagues is why I have not used Google maps API. First of all, Google maps API is online and cannot be accessed offline. In my application, I have completely implemented the Mercator projection hence you can modify and customize it for any application especially where very fast response is required. You can implement it to any application from mobiles, GPS navigation and inertial navigation system for real-time position display. Well there are a lot of things which you can play around such as accessing the GPS coordinate from GPS card or any other GPS device and show it on the Google map.