ThinkGeo.com    |     Documentation    |     Premium Support

Web Mercator and Bing/Google Map Tile creation

I’m trying to create tiles for small areas (1000x1000 meters or so) to display on mobile platforms built in map controls (UWP, iOS and Android using Xamarin Forms). I was following the example of the Tile Generator to draw the layer to a canvas and then break up the bitmap into the 256x256 tiles. But something doesn’t seem right, I think it’s maybe projection or something. I’ve tried the WebMercator, Bing and Google proj4, the scale is just a little off when I actually load it on the platform’s map control (using UWP for testing).

I’m mainly wondering if I’m doing the drawing correctly. I’ll post the code next.

indent preformatted text by 4 spaces

var canvas = new GdiPlusGeoCanvas();
canvas.BeginDrawing(masterImage, drawRect, GeographyUnit.DecimalDegree);
tgLayer.AddStyleToLayer(YieldThinkGeoStyles.CreateDryYieldStyle(layer));
tgLayer.Draw(canvas, new Collection());
//overlay.Draw(canvas);
canvas.EndDrawing();

        var dirInfo = new DirectoryInfo(@"c:\temp\tiletest");
        if( dirInfo.Exists ) dirInfo.Delete(true);
        dirInfo.Create();

        for( int x = 0; x < tileRange.TileWidth; x++ )
        {
            for( int y = 0; y < tileRange.TileHeight; y++ )
            {
                var tileRect = new Rectangle(x * 256, y * 256, 256, 256);
                using( var tileBitmap = new Bitmap(256, 256) )
                using( var gfx = Graphics.FromImage(tileBitmap) )
                {
                    gfx.FillRectangle(new SolidBrush(Color.White), 0, 0, 256, 256);
                    gfx.DrawImage(
                        masterImage,
                        new Rectangle(0, 0, 256, 256),
                        tileRect,
                        GraphicsUnit.Pixel);

                    gfx.DrawRectangle(new Pen(Color.Red, 2), 0, 0, 256, 256);
                    tileBitmap.Save($@"c:\temp\tiletest\{tileRange.StartX + x}_{tileRange.StartY + y}_{levelOfDetail}.png", ImageFormat.Png);

                }
            }
        }
        masterImage.Dispose();
        ShellHelper.ShellExecute(@"c:\temp\tiletest");

Hi Brain,

It looks you put the problem under incorrect sub forum.

And I am not very clear about “the scale is just a little off”, does the tiles cannot be combine to a map or it have some offset?

I think for your requirement, you should want to user our cache system, and you can try to build the tiles by our CacheGenerator.
http://wiki.thinkgeo.com/wiki/map_suite_wpf_desktop_edition_all_samples#tile_cache_generator

Regards,

Don

Hi Don,

Sorry, I wasn’t very descriptive. Here is a screenshot of the issue. It was taken from a UWP application using the UWP Map Control. The aerial image is from bing and the red field boundary is from a polygon drawn on the bing map and it’s correct. The Tile outlines you see are what I exported using the code above and the multi colored should match the red field boundary on the bing map.

It’s possible I’m calculating the tile bounds incorrectly, but I would then expect the polygon layer (the one multi colored) to not be fully drawn and would still line up with the field boundary. This makes me think I’m either using the wrong projection or I’m not drawing the layer on the canvas correctly.

So here is my process, maybe you can spot something wrong in it. I’m also open adapting the tile cache example, but I haven’t figured out how exactly to make sure it’s creating the correct tiles with web Mercator projection

  1. Calculate the xyz tiles needed to cover the layer I’m tiling using a c# port of this code
    http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/

  2. Calculate the bounding box of those tiles in web Mercator

  3. Create a RectangleShape using that bounding box

  4. Create a bitmap the correct size for the xyz tiles

  5. create a GdiPlusGeoCanvas using that bitmap and set it’s world extent to the Rectangle Shape

  6. Project the layer to be drawn on the canvas using web Mercator

  7. Draw that layer onto the canvas

  8. Split the bitmap into the 256x256 tiles and save with the x_y_z coordinates.

For now I’m then just loading them into the UWP mapcontrol from the file system as a test, later I’ll serve them from a web service.

I only using MapSuite to create the tile images, I can’t use it on t he clients because I’m making a Xamarin Forms apps that must support UWP which you don’t have a MapSuite version for. So I’m trying to pre-render the more complicated layers as tile images I can then overlay on the native UWP, iOS and Android map controls.

Hope this helps explain things better, let me know if you have any more thoughts or want to see any of the code doing any of those steps. I feel like I’m just missing something.

Thanks!

Hi Don,

I think I solved my issue. I was doing everything correctly except calculating the size of the bitmap. I was getting the Tile X,Y,Z bounds and for example was subtracting the left tile x from the right tile x to get the bitmap with.

So left tile is 10, right is 8…10 - 8 = 2. To get the bitmap width is x 256, so 2 x 256 = 512. But I really needed Tiles 8, 9, 10…so the tile width was 3 not 2. So I was drawing the correct bounding box, but my bitmap was 1/3 to small.

Now that I’m correctly calculating the bitmap size all works perfect!

Hi Brian,

Very glad to hear it works for you.

Any questions please free to let us know.

Thanks,
Peter