Click here to Skip to main content
Click here to Skip to main content

GoogleMapsNet - GoogleMaps Control for .NET

, 21 Sep 2012
Rate this:
Please Sign up or sign in to vote.
A simple .NET control for GoogleMaps web services.

Introduction

This article is an attempt to embed the GoogleMaps collection of web services into a simple .NET control. It should provide the developer a simple solution for accessing the most important parts of the GoogleMaps web services. It however does not cover 100% of all its features but concentrates on the general information provided by Google.

Background

I have done a lot of research in order to find a similar control on the Internet, but I have found only one complete solution, present also here on the CodeProject. Here is the link. It is called GMap.NET and supports other map service providers. The control presented in this article is a pure .NET control, written in C#, and embeds a few of the most important GoogleMaps web services.

It works asynchronously and uses threads to download data from the Internet. You can access all different map types supported by GoogleMaps: roadmap, terrain, satellite, and hybrid. The control loads parts of the world map dynamically, similar to the web browser. However, to avoid memory issues, it does not cache the results.

How is GoogleMaps organized?

It is the collection of web services. Google has also provided the JavaScript API (latest revision is 3.10) in order to use these maps on custom web-sites. Please see the following link to learn more about this API.

So, if we already have this JavaScript API, why do we need the .NET control? Well, you would have to add the WebBrowser .NET control in order to use GoogleMaps on WinForms and provide the background page with embedded JavaScript code, or build some kind of your own local service to handle the API calls.

But, can it be solved in a different manner? At this moment, and if Google does not change the URLs and specifications (algorithms) - it can.

The most tricky part of this story is the HTTP request that travels to GoogleMaps servers and back. In most cases these servers will return the images (in the specific format) and the XML (or JSON) documents. All that is needed to be done, when you finally access the servers, is to put the right images on the right place on the screen.

The Map of the World

GoogleMaps servers will deliver, upon processing the request from the client, the parts of the world map (so called tiles) at the specific zoom level. These tiles are a part of the simple coordinate system based on the latitude-longitude pair of the point on the world map, and rendered at a certain zoom level. The zoom level usually goes from 0 - a single tile representing the whole world, to 17 - the most detailed representation. The world map is divided into 2n tiles horizontally and vertically, where n represents the current zoom level. Each tile is of the size of 256x256 pixels. Depending on the type of the map, the tiles are usually PNG or JPEG images.

So, how do we access these tiles? There is a simple HTTP request that can be sent to GoogleMaps servers to obtain these tiles. First what is needed to be known is that Google has four main servers dedicated to this task. They are at this moment: mts0, mts1, mts2, and mts3. This is an example of the HTTP request sent to Google:

http://mts0.googleapis.com/vt?lyrs=m&x=48&y=96&z=8

This request addresses the mts0 server and requests the tile with coordinates (48, 96) at zoom level 8. The same result is obtained using the following:

http://mts1.googleapis.com/vt?lyrs=m&x=48&y=96&z=8
http://mts2.googleapis.com/vt?lyrs=m&x=48&y=96&z=8
http://mts3.googleapis.com/vt?lyrs=m&x=48&y=96&z=8

So, using the four servers, instead of only one, will speedup the download and will not overload the single server. What are other params of the request? The param lyrs specifies the type of map to download. Here is a list of all of them:

http://mts0.googleapis.com/vt?lyrs=m&x=48&y=96&z=8 - roadmap
http://mts0.googleapis.com/vt?lyrs=t&x=48&y=96&z=8 - terrain
http://mts0.googleapis.com/vt?lyrs=p&x=48&y=96&z=8 - terrain + labels
http://mts0.googleapis.com/vt?lyrs=s&x=48&y=96&z=8 - satellite
http://mts0.googleapis.com/vt?lyrs=y&x=48&y=96&z=8 - satellite + labels

Now, when we have tiles for the map, we need to assemble it in the right way. How do we do that?

Building the Map

The first thing that needs to be defined is the center of the map. It is the point that is going to be in the center of our screen. We pick it randomly since it can be any point on the globe. Let's center the map at the city of London (51.5081289, -0.1280050), at a zoom level of 8. How do we find the correct tiles?

We will start with the latitude-longitude pair of this location. We need to translate it into absolute screen points (x, y). Remember that at a zoom level of 8 we have 28 tiles horizontally and vertically, and that means that the size of our map is 28*256 x 28*256 pixels. It is obvious that we can not download the whole map and neither do we need to. How do we find the correct tile that holds the center of our map? We need some transformational equations to translate latitude-longitude pair into absolute screen offset. Please see the following link for a general information on this topic.

The GoogleMapsNet control described in this article uses the following method:

public static Point LatLongToPixel(double latitude, double longitude, double zoom)
{
    Point point = new Point();

    double centerPoint = Math.Pow(2, zoom + 7);
    double totalPixels = 2 * centerPoint;
    double pixelsPerLngDegree = totalPixels / 360;
    double pixelsPerLngRadian = totalPixels / (2 * Math.PI);
    double siny = Math.Min(Math.Max(Math.Sin(latitude * (Math.PI / 180)), -0.9999), 0.9999);
    point = new Point((int)Math.Round(centerPoint + longitude * pixelsPerLngDegree), 
            (int)Math.Round(centerPoint - 0.5 * Math.Log((1 + siny) / (1 - siny)) * pixelsPerLngRadian));

    return point;
}

After calling this method we get the (x, y) pair of values (32745, 21792). This is the absolute world position of the map center. Next we will calculate the viewport bounds, that is the part of the world map that is visible from our screen. It is quite simple. The center of the viewport is our center point. We form the viewport rectangle by calculating offset to the left side by subtracting the half-width of our screen, and the offset to the top side by subtracting the half-height of our screen. The width and height of our viewport are set to the width and height of our screen. See below:

m_rcViewport = new Rectangle(m_ptMapCenter.X - this.ClientRectangle.Width / 2, 
  m_ptMapCenter.Y - this.ClientRectangle.Height / 2, 
  this.ClientRectangle.Width, this.ClientRectangle.Height);

The last thing that needs to be done is to calculate the left, top, right, and bottom tiles that need to be downloaded. Here is the code:

int startx = m_rcViewport.Left / 256;
int endx = m_rcViewport.Right / 256;
int starty = m_rcViewport.Top / 256;
int endy = m_rcViewport.Bottom / 256;

That's all. After this all we need to do is run the loop and get those tiles, like below:

for (int y = starty; y <= endy; y++)
{
    for (int x = startx; x <= endx; x++)
    {
        // Download tile with coordinates (x, y)
    }
}

Finally, our screen looks like the following one:

Adding the Markers

The markers on GoogleMaps are useful since they can keep additional information about places on the map. You can put the marker anywhere on the map. The marker is defined by its (latitude, longitude) pair of coordinates. The GoogleMapsNet control allows you to add markers anywhere. The links to the original GooogleMaps images are shown below:

http://www.google.com/mapfiles/marker.png - default marker
http://www.google.com/mapfiles/shadow50.png - marker shadow

marker marker shadow

GoogleMaps Web Service - Goecoding and Reverse Geocoding

The geocoding web service allows you to find locations defined by the (latitude, longitude) pair using the address search criteria. It is accessible through the following HTTP request:

http://maps.googleapis.com/maps/api/geocode/xml?address=london&sensor=false

Here we specify the XML output format, put the keyword in the address param, and set the sensor param to true or false. You will receive the XML document from the GoogleMaps servers with the structure described in this link.

Similarly, Google provides the reverse feature to find the addresses based on the (latitude, longitude) pair search. See below:

http://maps.googleapis.com/maps/api/geocode/xml?latlng=51.5081289,-0.1280050&sensor=false

The Geocoding and Reverse Geocoding features are supported in the GoogleMapsNet control.

GoogleMaps Web Service - Directions

The Directions web service will provide you a route between the two points on the map. You access it like this:

http://maps.googleapis.com/maps/api/directions/xml?origin=London&destination=Glasgow&sensor=false

Again, you will receive the XML document with the structure described in this link. The route is a collection of locations, but returned as an encoded string. The encoding algorithm is described here.

The Directions feature is supported in the GoogleMapsNet control.

GoogleMaps Web Service - Distance Matrix

The Distance Matrix web service will provide you information about the distance between two points on the map. You access it like this:

http://maps.googleapis.com/maps/api/distancematrix/xml?origins=London&destinations=Glasgow&mode=driving&sensor=false

The XML document structure is described in this link.

The Distance Matrix feature is supported in the GoogleMapsNet control.

GoogleMaps Web Service - Elevation

The Elevation web service will provide you information about the elevation (height) of the point on the map. You access it like this:

http://maps.googleapis.com/maps/api/elevation/xml?locations=51.5081289,-0.1280050&sensor=false

The XML document structure is described in this link.

The Elevation feature is supported in the GoogleMapsNet control.

Demo Application

The Windows Forms demo application, written in C#, and using the GoogleMapsNet control is shown on the screenshot below:

Demo application

All described features are accessible through the control panel on the right side of the main application window. But, let's now see how to use it from C#.

Using the Code

First, you should add a reference to the GoogleMapsNet control to your project, like on the image below:

Next, you add it on the form, or use the creation code, similar to the below one:

googleMapsNet1 = new GoogleMapsNet();
googleMapsNet1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
googleMapsNet1.Latitude = 0;
googleMapsNet1.Location = new System.Drawing.Point(12, 12);
googleMapsNet1.Longitude = 0;
googleMapsNet1.Name = "googleMapsNet1";
googleMapsNet1.ShowGrid = false;
googleMapsNet1.Size = new System.Drawing.Size(1024, 768);
googleMapsNet1.TabIndex = 1;
googleMapsNet1.LongitudeChanged += new System.EventHandler(this.googleMapsNet1_LongitudeChanged);
googleMapsNet1.LatitudeChanged += new System.EventHandler(this.googleMapsNet1_LatitudeChanged);
googleMapsNet1.ZoomChanged += new System.EventHandler(this.googleMapsNet1_ZoomChanged);
googleMapsNet1.Dock = DockStyle.Left;
this.Controls.Add(googleMapsNet1);

The GoogleMapsNet control exposes three main events: LatitudeChanged, LongitudeChanged, and ZoomChanged. Add custom handlers for them to track the map params being changed.

To show the map, do the following:

// Show map
googleMapsNet1.ShowMap(mapType, longitude, latitude, zoom);

To add the marker on the map, do the following:

// Add marker
googleMapsNet1.AddMarker(longitude, latitude, zoom);

To remove all markers on the map, do the following:

// Clear markers
googleMapsNet1.ClearMarkers();

To get the Geocoding results, do the following:

// Show locations based on address search
DataTable table = googleMapsNet1.AddressToLongitudeLatitude(address);

To get the Reverse Geocoding results, do the following:

// Show addresses based on location
DataTable table = googleMapsNet1.LongitudeLatitudeToAddress(longitude, latitude);

To add the route to the map, do the following:

// Add route
DataTable table = googleMapsNet1.AddRoute(origin, destination);

To remove all routes on the map, do the following:

// Clear routes
googleMapsNet1.ClearRoutes();

To get the Distance Matrix results, do the following:

// Calculate distance
DataTable table = googleMapsNet1.CalculateDistance(origin, destination);

To get the Elevation results, do the following:

// Calculate elevation
DataTable table = googleMapsNet1.CalculateElevation(origin, destination);

Points of Interest

This was one of the most interesting projects I have been working on recently. I had a very good time working on this and I hope developers will find a good use for this control.

History

  • September, 2012 - GoogleMapsNet control, version 1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

darkoman
Software Developer (Senior) Elektromehanika d.o.o. Nis
Serbia Serbia
He has a master degree in Computer Science at Faculty of Electronics in Nis (Serbia), and works as a C++/C# application developer for Windows platforms since 2001. He likes traveling, reading and meeting new people and cultures.

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberamish kumar3-Oct-12 0:10 
QuestionLicensing PinmemberRyanEK2-Oct-12 15:59 
GeneralMy vote of 5 PinmemberScruffyDuck2-Oct-12 0:49 
QuestionGreat!! [modified] PinmemberTed Goulden25-Sep-12 0:22 
AnswerRe: Great!! Pinmemberdarkoman25-Sep-12 0:52 
QuestionNot bad, but... PinmemberMember 362963524-Sep-12 21:00 
GeneralMy vote of 5 Pinmembertaha bahrami24-Sep-12 20:19 
QuestionQuestion PinmemberErnst Sauer24-Sep-12 8:39 
I click the button "Go to location" and nothing happens :(
AnswerRe: Question Pinmemberdarkoman24-Sep-12 9:23 
GeneralRe: Question PinmemberErnst Sauer24-Sep-12 9:53 
GeneralRe: Question PinmemberDogan Erdogant24-Sep-12 20:36 
GeneralRe: Question Pinmemberdarkoman24-Sep-12 21:12 
GeneralRe: Question PinmemberTed Goulden25-Sep-12 0:27 
GeneralRe: Question PinmemberErnst Sauer25-Sep-12 1:01 
AnswerRe: Question Pinprofessionalhgbecker8-Aug-13 4:34 
GeneralMy vote of 5 PinmemberScruffyDuck22-Sep-12 1:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 21 Sep 2012
Article Copyright 2012 by darkoman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid