Tiling in Winform

Topics: SharpMap Project, SharpMap v0.9 / v1.x, SharpMap v2.0, WinForms Controls
Mar 16, 2009 at 1:31 AM
Hi ,

Problem.
We had performance and usability issues with some of the layers which are feature intensive.

We tried
Then we heard about this tiling thing  and openlayers and gave it a try.  The performance and usability improved many times indeed as openlayers splits up the mapimage area into several bounding boxes and splits the requests into several requests  just for the areas that require the map to be redrawn. (basically what every one refers to as Tiling). 

However
We are developing the solution in winforms and openlayers is all javascript. Just wondering whether there its possible to implement tiling in the Winforms version of sharpmap.  To me it doesnt look like its a part of v.9 release . Is this planned /exists in the v 2.0 trunk ??

Or are there sharp map extensions which can achieve this ??

Regards

Bijoy

 


Coordinator
Mar 16, 2009 at 11:32 AM
Hi Bijoy, it doesn't exist in either version. It could be done, but I am not sure if the benefit would be worth it especially for 0.9..
For the web, the webserver is inherently multithreaded, so many instances of the sharpmap engine can be handling many requests, with the desktop you are basically on one thread so the tiles would be rendered sequentially (v2 is multithreaded).  
hth jd
Developer
Mar 16, 2009 at 11:53 AM
Edited Mar 16, 2009 at 11:55 AM
Hi Bijoy,

Yes, there is some support for tiling in WinForms in SharpMap v.9. You can use the TiledWmsLayer which uses the WMS-C protocol. See:

The WMS-C protocol is basically the WMS protocol but restricted to specific tile bboxes. The advantage is that it can also call a WMS and cache the tiles locally. 

I have rewritten and improved the tiling part and added the TMS and Virtual Earth protocol in a separate library, which I should integrate with SharpMap soon: http://brutile.codeplex.com/

If you create a tilecache using tilecache.py (a tool developed by the OpenLayers people) you can use both TMS and WMS-C to access those tiles. TMS is less error prone though because it does not have to deal with rounding errors of bboxes.

A general issue with tiling is that you only really benefit from it if you request the tiles asynchronously. The current WMS-C implementation in SharpMap requests all tiles sequentially before it renders them. This is not what you want. You only benefit from it if you use a local tilecache. The brutile project contains a WPF demo which shows how it works with asynchronous requests. This has a very different architecture from SharpMap v0.9 and it is not easy to change that. There are some options to improve it thougt.

Maybe you could start by just using TiledWmsLayer to access a cache generated with tilecache.py and then think about ways to improve from there.

Paul
Coordinator
Mar 16, 2009 at 12:13 PM
Good catch Paul :) ..
Developer
Mar 16, 2009 at 3:35 PM
@john

I would be great if we could have async tile requests with notifications of the renderer if the tiles come in. 

Paul
Mar 18, 2009 at 5:04 AM

thanks paul.

Glad that you have implemented this. i have been experimenting since yesterday with TiledWmsLayer after reading.

Have got to a stage where the TiledWmsLayer splits up the layer into multiple bounding boxes and sents request to the server.

A couple of issues I have come across which prevent local/server caching of the tiles.

1. In the Render Method of TiledWmsLayer TileCache of the tileSet all seems to be null and hence the request is always sent to the server.  How do we set the TileCache for a given Tile Set

if ((tileSet.TileCache != null) && (tileSet.TileCache.ContainsTile(tileExtent)))

I think the TileSet object is created in the function ParseTileSetNode however it doesnt seem to be  doing anything to the TileCache Object.

 

 


Second Problem - again to do with caching.
string
wmsUrl = "http://localhost:8080/geoserver/gwc/service/wms?SERVICE=wms&REQUEST=GetCapabilities&FORMAT=image/png&";

 

 

TiledWmsLayer layer = new TiledWmsLayer("Roads", wmsUrl,"EPSG:4326","image/png");

 

The initial request above to get the capability document is sent to GeoWebCache (Tileserver for Geoserver). No problem there.

But subsequent request are sent to below .It appears to strip out the bits in the URL that link to the GeoWebCache Tile server. 

http://localhost:8080/geoserver/wms?SERVICE=WMS&&REQUEST=GetMap&BBOX=138.603911617188,-34.9134252421875,138.60940478125,-34.907932078125&WIDTH=256&Height=256&LAYERS=topp:roads&FORMAT=image/png&SRS=EPSG:4326&VERSION=1.1.1&STYLES=googleroads

I understand that this could be because the capabilities document would have have described the base url like the below one.  Any work arounds here ???






 

 

Developer
Mar 18, 2009 at 8:46 AM
Edited Mar 18, 2009 at 8:48 AM
Hi Bijoy,

You have to assign the TileCache with a TileCacheFileStorage yourself when you create the layer.

Is it your own GeoWebCache server? The url is retrieved from the capabilities, so it should not have 'localhost' in the capabilties. Maybe it is possible to configure this in GeoWebCache. A  workaround I have used is to save a version of the capabilties to local file, change the url in there and read the capabilities from file. I wrote a version that detects if it is a file or web url but I am not sure if that version is in the trunk now. Will look at it later.

Paul
Mar 19, 2009 at 2:13 AM
Works like a charm paul. Thanks. Should be useful if you include that in the comments section to initialiase the TileCacheFileStorage so that others may be able to easily find it.

Otherwise a small but annoying problem exists still though , I find some spaces in between some of the tiles which are noticeable neverthless.  Has this been fixed in any of the later changesets/

I tested the same piece of map using openlayers and its ok there ,

noticed someones made a comment  related to the borderbug  in the render method of tiledwmslayer

              #region Comment on BorderBug correction
              // Even when tiles border to one another without any space between them there are
              // seams visible between the tiles in the map image.
              // This problem could be resolved with the solution suggested here:
              // http://www.codeproject.com/csharp/BorderBug.asp
              // The suggested correction value of 0.5f still results in seams in some cases, not so with 0.4999f.
              // Also it was necessary to apply Math.Round and Math.Ceiling on the destination rectangle.
              // PDD.
              #endregion


Developer
Mar 25, 2009 at 6:01 PM
Yes, I now use as ImageAtributes with:
attributes.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY);

and in my drawing method i just use Math.Round:

    private void DrawImage(Graphics graphics, Bitmap bitmap, RectangleF destF, Tiling.TileInfo tile)
    {
      Rectangle dest = RoundRectangle(destF);
      graphics.DrawImage(bitmap, dest, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, attributes);
    }

    private static Rectangle RoundRectangle(RectangleF dest)
    {
      double minX = Math.Round(dest.X);
      double minY = Math.Round(dest.Y);
      double maxX = Math.Round(dest.Right);
      double maxY = Math.Round(dest.Bottom);
      return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
    }
Mar 26, 2009 at 12:42 AM
Hi Paul ,

 I tried adding this , but the problem remains. Any chance you can help me with the changeset that contains these changes that you mention above.
Developer
Mar 31, 2009 at 8:53 PM
I fixed it in the trunk and added a sample: http://sharpmap.codeplex.com/SourceControl/changeset/view/48802#739068

Paul
Apr 1, 2009 at 1:55 AM

great paul .  That appears to have fixed it

Just a small issue I have found in Tileset class  GetCapabilities request to Geoserver returns mulitplie tilesets rows for a given tileset and they vary by srs and format.

I have hardcoded in my version like below otherwise it throws an exception.

public static SortedList<string, TileSet> ParseVendorSpecificCapabilitiesNode(XmlNode xnlVendorSpecificCapabilities)

 

 

tileSet.format.ToLower() == "image/png" && tileSet.Srs=="EPSG:4326")

 

tileSets.Add(tileSet.Name, tileSet);

 

}

 

return tileSets;

 

}

Also could you pls add sample code in Winform Samples to initialise the cache .  I had found out this only by asking your earlier and hopefully should help others.

layer.TileSets[

"basic"].TileCache = new SharpMap.Web.Wms.Tiling.TileCacheFileStorage(@"c:\temp\geocache");