ThinkGeo.com    |     Documentation    |     Premium Support

Server side cache

Hello ThinkGeo-Team,


to improve the performance of our GIS application we want to shift most of the drawing logic from client to our application server. Communication between client and server is done via webservices. We want to draw layers that are used as background only on the first request and then cache the drawn picture with FileBitmapCache - the next request gets the data from the cache.


After searching in the forum we found some code that is very similar to what we need.


gis.thinkgeo.com/Support/Dis...fault.aspx


I made a small sample application but it did not work correct. The tiles from cache are not correct. Some are black. The background is black too.


In the post above there was a similar problem but I do not understand how to solve it. Please can you check the sample code and put me in the right way.


Thanks


Thomas



GISCaching.zip (311 KB)

Thomas,


Thanks for your post and code which make me understand the problem more quickly. Following places need to be updated to correct this issue, in each place need to be updated; I comment the original code out to mark it clearer.
 

Imports ThinkGeo.MapSuite.Core
 
Public Class cdNettroFeatureLayer
    Public Function getMapImage(ByVal minX As Double, ByVal maxY As Double, ByVal maxX As Double, ByVal minY As Double, ByVal Width As Single, ByVal Height As Single) As Byte()
 
        Const CACHE_ID As String = "1234567890"
 
        Dim BoundingBox As ThinkGeo.MapSuite.Core.RectangleShape
        Dim bitmapCache As ThinkGeo.MapSuite.Core.FileBitmapTileCache
        Dim Scale As Double
        Dim ms As System.IO.MemoryStream
        Dim matrix As ThinkGeo.MapSuite.Core.MapSuiteTileMatrix
        Dim tiles As System.Collections.ObjectModel.Collection(Of ThinkGeo.MapSuite.Core.BitmapTile)
        Dim bmp As System.Drawing.Bitmap
        Dim graphics As System.Drawing.Graphics
        Dim alreadyLoaded As Boolean = False
 
        Dim oCanvas As ThinkGeo.MapSuite.Core.GdiPlusGeoCanvas
        Dim oImage As ThinkGeo.MapSuite.Core.GeoImage
        Dim oLabelsInAllLayers As System.Collections.ObjectModel.Collection(Of ThinkGeo.MapSuite.Core.SimpleCandidate)
        Dim oShapeFileFeatureLayer As ThinkGeo.MapSuite.Core.ShapeFileFeatureLayer
        Dim strShapeFile As String
 
        BoundingBox = ThinkGeo.MapSuite.Core.ExtentHelper.SnapToZoomLevel(New ThinkGeo.MapSuite.Core.RectangleShape(minX, maxY, maxX, minY), ThinkGeo.MapSuite.Core.GeographyUnit.Meter, _
                                                                          Width, Height, New ThinkGeo.MapSuite.Core.ZoomLevelSet())
 
        Scale = ThinkGeo.MapSuite.Core.ExtentHelper.GetScale(BoundingBox, Width, ThinkGeo.MapSuite.Core.GeographyUnit.Meter)
 
        ms = New System.IO.MemoryStream
        matrix = New ThinkGeo.MapSuite.Core.MapSuiteTileMatrix(Scale, 256, 256, ThinkGeo.MapSuite.Core.GeographyUnit.Meter)
 
        bitmapCache = New ThinkGeo.MapSuite.Core.FileBitmapTileCache(System.IO.Path.Combine(System.Environment.CurrentDirectory, "ServerCache"), _
                                                                    CACHE_ID, ThinkGeo.MapSuite.Core.TileImageFormat.Png, matrix)
 
        tiles = bitmapCache.GetTiles(BoundingBox)
 
        If (tiles.Count > 0) Then
            alreadyLoaded = True
            For Each tile As ThinkGeo.MapSuite.Core.BitmapTile In tiles
                If tile.Bitmap Is Nothing Then
                    alreadyLoaded = False
                    Exit For
                End If
            Next
        End If
 
 
        'bmp = New System.Drawing.Bitmap(CInt(Width), CInt(Height))
        Dim cells As System.Collections.ObjectModel.Collection(Of TileMatrixCell) = bitmapCache.TileMatrix.GetIntersectingCells(BoundingBox)
        Dim drawingExtent As RectangleShape = GetExpandToIncludeExtent(cells)
 
        Dim drawingBitmapWidth As Integer = bitmapCache.TileMatrix.TileWidth * CInt(Math.Round(drawingExtent.Width / cells(0).BoundingBox.Width))
        Dim drawingBitmapHeight As Integer = bitmapCache.TileMatrix.TileHeight * CInt(Math.Round(drawingExtent.Height / cells(0).BoundingBox.Height))
        bmp = New Bitmap(drawingBitmapWidth, drawingBitmapHeight)
 
 
        If (alreadyLoaded) Then
 
            ' All tiles already exist in cache 
            graphics = System.Drawing.Graphics.FromImage(bmp)
 
            For Each tile As ThinkGeo.MapSuite.Core.BitmapTile In tiles
 
                If (Not tile.Bitmap Is Nothing) Then
 
                    Dim upperLeftPoint = ThinkGeo.MapSuite.Core.ExtentHelper.ToScreenCoordinate(BoundingBox, tile.BoundingBox.UpperLeftPoint, Convert.ToSingle(Width), Convert.ToSingle(Height))
                    Dim screenUpperLeftPointX = Convert.ToInt32(Math.Round(upperLeftPoint.X))
                    Dim screenUpperLeftPointY = Convert.ToInt32(Math.Round(upperLeftPoint.Y))
 
                    graphics.DrawImageUnscaled(tile.Bitmap, screenUpperLeftPointX, screenUpperLeftPointY)
 
                Else
 
                    ' haven't gotten the bitmap, we should find out why this happens. 
                    Throw New Exception("Problem while retriving Server Tile Cache !")
 
                End If
 
            Next
 
            graphics.Dispose()
            graphics = Nothing
 
        Else
 
            oCanvas = New ThinkGeo.MapSuite.Core.GdiPlusGeoCanvas
            oLabelsInAllLayers = New System.Collections.ObjectModel.Collection(Of ThinkGeo.MapSuite.Core.SimpleCandidate)
            'oImage = New ThinkGeo.MapSuite.Core.GeoImage(CInt(Width), CInt(Height))
            oImage = New ThinkGeo.MapSuite.Core.GeoImage(drawingBitmapWidth, drawingBitmapHeight)
 
            strShapeFile = System.IO.Path.Combine(System.Environment.CurrentDirectory, "alk-flurstueck-objekt.shp")
 
            oShapeFileFeatureLayer = New ThinkGeo.MapSuite.Core.ShapeFileFeatureLayer(strShapeFile)
            oShapeFileFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = ThinkGeo.MapSuite.Core.AreaStyles.Country1
            oShapeFileFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ThinkGeo.MapSuite.Core.ApplyUntilZoomLevel.Level20
 
            oCanvas.BeginDrawing(oImage, BoundingBox, ThinkGeo.MapSuite.Core.GeographyUnit.Meter)
 
            Try
                oShapeFileFeatureLayer.Open()
                oShapeFileFeatureLayer.Draw(oCanvas, oLabelsInAllLayers)
            Finally
                If oShapeFileFeatureLayer.IsOpen Then
                    oShapeFileFeatureLayer.Close()
                End If
            End Try
 
            If oCanvas.IsDrawing Then
                oCanvas.Flush()
                oCanvas.EndDrawing()
            End If
 
            ms = ThinkGeo.MapSuite.Core.GdiPlusGeoCanvas.ConvertGeoImageToMemoryStream(oImage, System.Drawing.Imaging.ImageFormat.Bmp)
            bmp = New System.Drawing.Bitmap(ms)
 
            'bitmapCache.SaveTiles(CType(bmp.Clone(), System.Drawing.Bitmap), BoundingBox)
            bitmapCache.SaveTiles(CType(bmp.Clone(), System.Drawing.Bitmap), drawingExtent)
 
        End If
 
        'Write in the memorystream 
        bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp)
        bmp.Dispose()
        bmp = Nothing
        Return ms.ToArray
 
    End Function
 
    Private Function GetExpandToIncludeExtent(ByVal cells As System.Collections.Generic.IEnumerable(Of ThinkGeo.MapSuite.Core.TileMatrixCell)) As ThinkGeo.MapSuite.Core.RectangleShape
 
        Dim totalExtent As ThinkGeo.MapSuite.Core.RectangleShape = Nothing
 
        For Each cell As ThinkGeo.MapSuite.Core.TileMatrixCell In cells
            If totalExtent Is Nothing Then
                totalExtent = DirectCast(cell.BoundingBox.CloneDeep, ThinkGeo.MapSuite.Core.RectangleShape)
            Else
                totalExtent.ExpandToInclude(cell.BoundingBox)
            End If
 
        Next
 
        Return totalExtent
 
    End Function
End Class


 
 
Any more questions just feel free to let me know.
 
Thanks.
 
Yale

Hello Yale


thanks for response.


I updated my sample with your code but now there is another problem. As you can see on the screenshot the drawing positions of cached and uncached layers did not match.


 


But maybe we can ignore this problem because I have another idea where I use Overlay-Class on server side. In my sample application you can see this code in cNettroFeatureLayer2-Class. Also I have changed the image format from .bmp to .png to get an transparent background.


What  do you think on my code in cNettroFeatureLayer2 class. Any improvements?


Thanks Thomas



GISCaching2.zip (312 KB)

Thomas, 
 Thanks for your sharing and feedback. 
  
 It is amazing that the new way with cdNettrolFeatureLayer2 used is much easier to read and maintain, as well as working better than the first way, which is trying to use the Core to build up Grid or Matrix system to build up the tiles itself. 
  
 As far as I can see, the cdNettrolFeatureLayer2 works fine, and the code is clean. The only thing can think about is can we try to remove some local variables or to keep it in class module to avoid them to be recreated times and times again, such as bitmapCache? 
  
 Any more questions just feel free to let me know. 
  
 Thanks. 
  
 Yale