Tuesday, November 30, 2010

DotNetFish Part 1 - Using Gmap.net to create the map image.

Now its time to get down to business and do some actual work. Below is the technology stack I am planning to use for this project.

I have decided to use Gmap.Net to help me build the map. If you havent heard of this great project, you should go check them out. GMap.Net This project makes it very easy to display a map from google, or any number of mapping servers. Getting setup was dead easy. For this tool, I just went with a standard Winform project, This will only be used internally, and no reason to spend time learning WPF right now when I don't need it.

Now then, lets look at what is needed to get Gmap.net Running

  1. Grab the source code of the latest stable branch from the Gmap.Net repository.
  2. Load the source code into visual studio and build the project
  3. You can skip the first two steps, and just grab the binaries, but those don't come with examples, which you'll probably want.
  4. Add the Gmap.Net.Core.Dll and the Gmap.Net.WindowsForms.dll to your references. (Make sure that if you copy the refrences to your project directory, that the System.Data.Sqlite.dll is in the same directory as the two Gmap Dll's
  5. Add the Gmap.WindowsForms.dll to your toolbox, so you can have access to the Gmap map control
Once you have done all of this, you should be able to add a Map control to your form. In the Constructor for your form, you will want to add this code.


// config map 
MainMap.Position = new PointLatLng(35.2276723549358, -97.22351074);
MainMap.MapType = MapType.GoogleMap;
MainMap.MinZoom = 1;
MainMap.MaxZoom = 17;
MainMap.Zoom = 10; 

That should get a basic map up and running on your form. Now for my application I need to do the following

  1. Allow the user to select a lake with a selection tool
  2. After the user has selected a lake, build an image from the tileset.
  3. Do some processing of the image. (Turn the image black and White)
We really don't need to know how the map stuff works, except that the map is divided up into tiles. The way the app will work, is when the user selects a lake, the start and end points longitude and latitude is saved. Gmap already provides a nice selection tool by holding the shift key. This allows us to zoom in on the map using shift. I don't need the zoom ability, but the selection box is perfect. So I modified the Gmap code to not zoom in when using the selection tool. Easy as pie.


Here is the code I am using to get the Tile Coordinates

PureProjection prj = null;
int maxZoom;
int zoom = 15;
GMaps.Instance.AdjustProjection(type, ref prj, out maxZoom);
GMaps.Instance.Mode = AccessMode.ServerOnly;
GMaps.Instance.ImageProxy = new WindowsFormsImageProxy();
//This line converts the LatLng to the Proper TileXY given the level of zoom.
//Remember that each level of zoom has a different TileXY coordinate for a given Lat and Lng
prj.FromPixelToTileXY(prj.FromLatLngToPixel(p.Lat, p.Lng, zoom))


Once we know which tiles we need, it will be very simple to get those tiles and stitch them together into the image.

Here is the code that does the stitching.
using (Bitmap bmp = new Bitmap(tilesWide * 256, tilesHigh * 256))
            {
                for (int x = 0; x < tilesWide; x++)
                {
                    for (int y = 0; y < tilesHigh; y++)
                    {
                        using (Graphics gfx = Graphics.FromImage(bmp))
                        {
                            Exception ex;
                            WindowsFormsImage tile = GMaps.Instance.GetImageFrom(type, new GPoint(startTile.X + x, startTile.Y - y), zoom, out ex) as WindowsFormsImage;

                            if (ex != null)
                            {
                                e.Cancel = true;
                                return;
                            }
                            else if (tile != null)
                            {
                                using (tile)
                                {
                                    gfx.DrawImage(tile.Img, x * 256, (tilesHigh - y - 1) * 256);
                                   
                                }
                            }
                        }
                    }
                }

No comments:

Post a Comment