ThinkGeo.com    |     Documentation    |     Premium Support

FileBitmapTileCache caching or using bad tiles

Couple of questions, which I need answers as soon as possible, please.


1. What happens if TileOverlay is unable to write to its cache.  Does it run into a problem rendering rest of the layer?  In other words, what will prevent DrawCore of a layer from being called?


2. Is it possible to prevent FileBitmapTileCache from caching bad tiles i.e tiles with a size less than a certain threshold, say 2K, and for LayerOverlay not to use such bad tiles?


 TIA.



Hi Klaus,


 


1. When FileBitmapTileCache is unable to save image files (like when its CacheDirectory


is set to an unauthorized folder), the following drawing procedure will fail too.


This is because when we are using caches in a TileOverlay, the TileOverlay saves the drawing result to image files, then it loads the image files. So if the file saving fails, then the upcoming drawing will fail too.


 


2. Currently we don’t have an existing solution for this, but we can accomplish this by inheriting FileBitmapTileCache and overriding the SaveTileCore method. Here is a sample that may be usable:


 public class MyFileCache : FileBitmapTileCache
{
    public MyFileCache(string folder)
        : base(folder)
    { }

    protected override void SaveTileCore(ThinkGeo.MapSuite.Core.Tile tile)
    {
        BitmapTile bitmapTile = tile as BitmapTile;
        if (bitmapTile != null)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmapTile.Bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
                long sizeInKB = stream.Length / 1024;
                if (sizeInKB > 2)
                {
                    base.SaveTileCore(tile);
                }
            }
        }
    }
}


Hope this can be of help.


 


Regards,


Tsui



Tsui,  



On 2, will try proposed solution, thanks. 



On 1, you guys should look into the draw sequence after creating the tile bitmap.  Why not use created bitmap to render to screen then save to disk after.  Sounds like drawing first, then saving later will improve perceived performance a bit as IO access has some small cost.


Also, on a related note,  TileOverlay perceived performance can be further improved by creating and loading tiles that are within visible extent before creating and loading tiles for buffer zone. 


Thanks again.



Hi Klaus, 
  
 We made a little change in the Tile class, now it draws itself even if the TileCache fails to save images. 
 Now, if the TileCache property of a TileOverlay is set to an unauthorized path, the behavior of a tile will be like this: 
 It tries to use the TileCache to get saved image file, this fails. 
 Then it draws itself and tries to save the drawing result to disk, the saving part fails, but we handled the exception here. 
 Please download the next package (any version after 4.5.29.0) from help desk and try again. 
  
 Regards, 
 Tsui

Good stuff Tsui, thanks but I am not observing expected behavior.  I tried setting cache directory to one that has no read/write permissions and I do not see tiles.  If I do not turn on cache, tiles are drawn.


DLL versions I am using is 4.5.30.0 downloaded today.



One more request on this subject of tile creation and caching:  would it be relatively easy to first create tiles within the visible extent of the map before those in the buffer zone?   This should also improve on perceived performance especially if the TileBuffer property is set to a value greater than 0.   



My status bar tracks tile drawing progress and what I am noticing is that there is progress, probably from the buffer tiles being created, even though I do not see new tiles coming in on the screen.   



Hi Klaus, 
  
 Were you using single tile mode when you observed the unexpected behavior? If that is the case, then it’s our fault. We missed the code that saves cache in single tile mode. Please try the next package and try again. 
  
 We’ll get back to you later on the buffer zone issue. 
  
 Regards, 
 Tsui

 Hi Klaus,


 


About the buffer:


What you described is just what we are doing. When the TileBuffer is greater than 0, we do draw the visible tiles first and draw the buffer zone later.


 


About the drawing progress:


The tiles in buffer zone are counted when we calculate the percentage. If you don’t want the buffer tiles to affect the percentage, there is a little work-around that may help:


 int previousPercentage = 0;

private void tileOverlay_DrawTilesProgressChanged(object sender, DrawTilesProgressChangedTileOverlayEventArgs e)
{
    if (Math.Abs(e.ProgressPercentage - previousPercentage) >= 5 || e.ProgressPercentage == 100 && previousPercentage != 100)
    {
        previousPercentage = e.ProgressPercentage;

        TileOverlay tileOverlay = (TileOverlay)sender;
        Canvas drawingCanvas = (Canvas)tileOverlay.OverlayCanvas.Children[0];

        var tilesInVisibleExtent = drawingCanvas.Children
                                                .OfType<ThinkGeo.MapSuite.WpfDesktopEdition.Tile>()
                                                .Where(tile => tileOverlay.MapArguments.CurrentExtent.Contains(tile.TargetExtent));

        var tilesLoaded = tilesInVisibleExtent.Where(tile => tile.IsOpened);

        double percentage = tilesLoaded.Count() * 100 / tilesInVisibleExtent.Count();
        //update the progress bar
    }
}


Just hook the code above to the DrawTilesProgressChanged event. The conditional check at the beginning is added because sometimes this event happens too frequently that the UI thread may get blocked.


 


Regards,


Tsui




 Tsui,


Suggested solution for draw draw progress works great, thank you.   As for buffer zone, it this is what you guys are currently doing, that is fine. I have a related question based on a quick test I performed with TileBuffer set to 0 and TileType set to Multiple.  This test is captured in attached sample:


If TileBuffer on LayerOverlay is set to 0 there is usually many more tiles that what is required for visible extent regardless of TransitionEffect setting?   For example, at zoom level 0, we require 6 tiles for visible extent but total number of tiles in overlay is 8.  At zoom level 1, we require 6 tiles for display but total number is 20, etc.  This does not seem to affect progress percentage based on logic your proposed but just out of curiosity what these additional tiles for?  


Back to original problem:   This is still an issue.  Maybe it is specific to the WorldMapKitRenderLayer.  Run attached sample with your windows user denied read or write permission to cache directory and you will see that layer does not draw.


Please let me know, thanks.


K




Tsui, I cannot upload zipped sample which is 31Kb in size!

 Hi Klaus,


 


Please refer the attachment instruction 


(gis.thinkgeo.com/Support/Dis...fault.aspx) and try again.


If it still won’t work, please send the sample to forumsupport@thinkgeo.com


 


Looking forward to your sample.


 


Regards,


Tsui



Oops, my mistake.  I was uploading wrong zip file.    Run sample with security permissions on your cache directory set to deny all and layer will not draw.




 Hi Klaus,


 
I Copied all the world map kit data to my local machine, then modified the CreateWMKOverlayFromLocal method in the sample a little bit like this:
 
LayerOverlay CreateWMKOverlayFromLocal()
{
    var worldMapKitRenderLayer = new WorldMapKitRenderLayer(@"C:\WorldMapKitData");
    var layers = GetBaseMapSymbolLayers();
    worldMapKitRenderLayer.LoadLayers(layers);

    var overlay = new LayerOverlay();
    overlay.Name = "WMK";
    overlay.RenderMode = RenderMode.GdiPlus;
    overlay.TileType = TileType.MultipleTile;
    overlay.TileBuffer = 0;
    overlay.TransitionEffect = TransitionEffect.Stretch;

    // Set security permissions to your cache directory to deny everything and layer will not draw
    overlay.TileCache = new FileBitmapTileCache(@"Z:\GIS\caches", "WMK") { TileAccessMode = TileAccessMode.ReadAdd };
    overlay.Layers.Add(worldMapKitRenderLayer);
    return overlay;
}

 
The path “Z:\GIS\caches” doesn’t exist on my local machine.
The sample worked. Even though no cache image files are saved, but the tiles are drawn.
Please download the latest package and try again and please make sure the version is 4.5.32.0 or higher.
 
Regards,
Tsui

Tsui, to duplicate, try this:


1. Set cached directory to say c:\gis\caches and make sure this folder and subfolder "wmk" exists.


2. From Windows Explorer, right click on c:\gis\caches\wmk folder , select Properties | Security, then set option for Deny on Full control for your windows userid.    In other words, remove any read/write permission on this folder for your userid.


3. Run sample again and observe that layer does not draw.  I am running v 4.5.32.0.



Hi Klaus, 
  
 Thanks for your information, we found the bug. 
 We only dealt with conditions that a path doesn’t exist, but did not deal with conditions that a path is not allowed to access. We fixed this issue. 
 We are correcting this error we made; we’ll let you when it’s taken care of. 
 Sorry for all the inconvenience. 
  
 And about the earlier question, you mentioned that there are 20 tiles when only 6 tiles are required. Would you please let us know how you got this observation, so we can reproduce it? 
  
 Regards, 
 Tsui

Glad to know you found bug.  We ran into this issue by accident.


In regards to second issue when tile count is greater than expected, please run modified sample and look at your Visual Studio's output window.   At zoom level 4, for example, we have 6 tiles visible and 20 tiles in total.  This is with Overlay.Transition effect set to None and Overlay.TileBuffer set to 0.


Thanks again.



001_WmkRenderLayer.zip (32.1 KB)

 Hi Klaus,


 


The drawn percentage method we suggested in another post is a little misleading, we are sorry about that.




                                                  


In that method, only the tiles marked as “In Extent” in the screen shot above are counted as visible tiles, because we used the Contains method to filter tiles.


But actually all the tiles shown in the screen shot above should be counted as visible, even though some of them are only partially visible.


To correct this error, replace the Contains method with Intersects method.


 


Sorry for the confusion and hope this will be of help.


 


Regards,


Tsui



.....pictures do speak a thousand words indeed.  It is very comforting to be able to explain what one is observing.     



Also, I just confirmed that tiles are now being drawn regardless of security permissions of cache directory.   



Great stuff and thanks again Tsui.









Hi Klaus, 
  
 Glad to be of help. And thanks for reporting these valuable information which helped us to fix the bug. 
 Please let us know if you have any other questions. 
  
 Regards, 
 Tsui