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

GoogleMapsNet - GoogleMaps Control for .NET

By , 21 Sep 2012
 

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
Member
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.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionEnhanced Featurememberhgbecker7 Feb '13 - 22:20 
Hello darkoman,
Great work, well done!
 
I like to use your .net control for an aviation application. Therefore routes on roads are not interesting but routes between to markers (direkt airline) are.
Can you please give me the information how to draw a line on the map between to given coordinates or markers. Thank you.
 
Best Regards Guenter.
AnswerRe: Enhanced Featurememberdarkoman8 Feb '13 - 11:00 
Hello,
 
thanks for the comments.
Here is the simple way of how to draw whatever you want on the Google map using GoogleMapsNet .NET control:
 
- override the Paint event for the GoogleMapsNet control in your project
- call the base class implementation for the Paint event first
- perform your custom drawing inside your overridden Paint event
 
To draw the line between any two (or more) given coordinates, please see the implementation of the GoogleMapsRoute class that is the part of the GoogleMaps namespace, and specially its member function called DrawRoute(). Another method that you will need to find the correct X and Y coordinates from the original Latitude and Longitude pair is the method called LatLongToPixel(), the static member function of the GoogleMapsNet control.
 
Hope I could help you !!!
 
Best regards,
Darkoman
"Avaritia est radix omnium malorum..."

GeneralRe: Enhanced Featurememberhgbecker11 Feb '13 - 7:45 
Hello darkoman,
 
thank you for your assisstance by answering my question about drawing a plyline from Start to destination.
I tried it, but I'm to stupid Confused | :confused: . Maybe the reason is that I'm a visual basic.net programmer.
Could you please give me a code snipped, or an enhance version of your test projekct? If it is in C# I'll use a converter to VB.
 
Thank you very much.
Best regards Guenter. Laugh | :laugh: Laugh | :laugh:
QuestionI have a bug while i move the mouse move on the mapmemberNimrodMazalTov16 Dec '12 - 20:02 
the bug is in the foreach in UpdateMap .
how can i fixs it.
GeneralMy vote of 5memberOshtri Deka15 Nov '12 - 23:08 
'nuff said.
QuestionVote 5 For You & BookmarkedmemberGun Gun Febrianza13 Oct '12 - 15:25 
this information is interested for me,
 
thank for sharing Smile | :)
Indonesian IT Intelijensi
Freedom of Revealing And Sharing Knowledge.
 
www.indonesiaitintelijensi.com

GeneralMy vote of 5memberGun Gun Febrianza13 Oct '12 - 15:24 
wow nice Release sob ! Smile | :) Vote 5 For You..
GeneralMy vote of 5memberraju melveetilpurayil11 Oct '12 - 6:00 
written well.
GeneralGreat Work.. Appreciate it..memberPasan Indeewara10 Oct '12 - 19:04 
Good stuff mate..!Cool | :cool:
GeneralMy vote of 5memberDrABELL6 Oct '12 - 17:12 
Great article, excellent solution! 5*
GeneralGreat WorkmemberSachinDakle4 Oct '12 - 20:17 
This is great work I Like this Thank you Smile | :) keep it up Thumbs Up | :thumbsup:
Sachin Dakle

Director

Unicon Computer Technology

Ph:- +91-8390777577

QuestionGMap.NETmemberradioman.lt4 Oct '12 - 9:37 
to be precise it actually caches tiles, both in the memory and the disk ;}
p.s. nice to see you're experimenting with maps Thumbs Up | :thumbsup:
d{^__^}b - it's time to fly

GeneralMy vote of 5memberamish kumar3 Oct '12 - 0:10 
Amazing Smile | :)
QuestionLicensingmemberRyanEK2 Oct '12 - 15:59 
This is great work. Just be mindful that using such a control would need to adhere to the Terms of Service outlined by Google in Section 7.1c[^].
 
Google has allowed the API to be accessible by a desktop application but it has to be free and publicly accessible ie. has a website where you can download the application at no charge.
GeneralMy vote of 5memberScruffyDuck2 Oct '12 - 0:49 
Excellent I can see several uses for this!
QuestionGreat!! [modified]memberTed Goulden25 Sep '12 - 0:22 
Not sure what I will use it for, but it looks great. Never would have occurred to me to take on such an ambitious project. Congratulations.
 
Edit: would have been nice to have a minimize capability. It takes up all my screen and when I want to switch to another program, I have to close the program.

modified 25 Sep '12 - 6:30.

AnswerRe: Great!!memberdarkoman25 Sep '12 - 0:52 
Hello,
 
this is just the demo program, showing the features of the control.
You can embed it in any form you can customize the way you prefer.
Thank You.
 

Best regards,
Darkoman
"Avaritia est radix omnium malorum..."

QuestionNot bad, but...memberMember 362963524 Sep '12 - 21:00 
Good article, but are you sure you are not violating Google Maps license?
Have you tested what happens if you access the satellite images in that way?
 
Some times ago I made exactly the same thing in C++. When you play for a while with satellite images, Google puts you in a black list and prevents your IP to download data from their servers for a day.
 
I don't know if its the same nowadays.
 
Anyway, good job!
GeneralMy vote of 5membertaha bahrami24 Sep '12 - 20:19 
very good and useful!
QuestionQuestionmemberErnst Sauer24 Sep '12 - 8:39 
I click the button "Go to location" and nothing happens :(
AnswerRe: Questionmemberdarkoman24 Sep '12 - 9:23 
Hello,
 
you should enter some keyword to search in the "Address:" textbox and click "Find..." button. After that, the datagridview control will be populated with some found locations by GoogleMaps service. Then you can click on "Go to location" button, and it will work.
 

Best regards,
Darkoman
"Avaritia est radix omnium malorum..."

GeneralRe: QuestionmemberErnst Sauer24 Sep '12 - 9:53 
Hello darkoman,
 
hm, I did this without success.
I type Munich (looking for the Oktoberfest Wink | ;) or London, then I can see the location in the GridBox.
I click "Go to Location" and I can see the new Longitude and Latitude,
but that's all, I can't see a map.
 
Tanks
Ernst
GeneralRe: QuestionmemberDogan Erdogant24 Sep '12 - 20:36 
same as me...
Dogan Erdogant

GeneralRe: Questionmemberdarkoman24 Sep '12 - 21:12 
Hello,
 
I have repeated your procedure and the map is shown correctly.
I am not sure what can be the problem at your place currently.
 

Best regards,
Darkoman
"Avaritia est radix omnium malorum..."

GeneralRe: QuestionmemberTed Goulden25 Sep '12 - 0:27 
I followed the instructions and was able to find my city and home.
1. Enter the city name plus province / state and country. Click on the "Find" button and the co-ordinates will appear in the grid.
2. Click on the "Go To Location" button.
3. Adjust the Zoom level.

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 21 Sep 2012
Article Copyright 2012 by darkoman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid