ThinkGeo.com    |     Documentation    |     Premium Support

Migrate to WPF Desktop edition

Hello ThinkGeo-Team,


we want to switch map control in our application from Desktop to WPFDesktop edition. At the moment we try to migrate our code to work with WPF edition.


Currently we need help on following problems:


1.)

We have a server side caching system based on following code:



Public Function GetLayerImage(ByVal dblBBULX As Double, ByVal dblBBULY As Double, _
                                        ByVal dblBBLRX As Double, ByVal dblBBLRY As Double, _
                                        ByVal lngImageWidth As Integer, ByVal lngMapUnit As ThinkGeo.MapSuite.Core.GeographyUnit, ByVal lngImageHeight As Integer) As Byte()


      Dim oBoundingBox As ThinkGeo.MapSuite.Core.RectangleShape
      Dim bytArray(-1) As Byte

      Dim oLayer As ThinkGeo.MapSuite.Core.ShapeFileFeatureLayer
      Dim oCanvas As ThinkGeo.MapSuite.Core.GeoCanvas
      Dim oGeoImage As ThinkGeo.MapSuite.Core.GeoImage = New ThinkGeo.MapSuite.Core.GeoImage(lngImageWidth, lngImageHeight)
      Dim oOverlay As ThinkGeo.MapSuite.DesktopEdition.LayerOverlay

      oBoundingBox = New ThinkGeo.MapSuite.Core.RectangleShape(New ThinkGeo.MapSuite.Core.PointShape(dblBBULX, dblBBULY), _
                                                               New ThinkGeo.MapSuite.Core.PointShape(dblBBLRX, dblBBLRY))

      oOverlay = New ThinkGeo.MapSuite.DesktopEdition.LayerOverlay()

      SyncLock oOverlay

        oLayer = New ThinkGeo.MapSuite.Core.ShapeFileFeatureLayer()
        oOverlay.Layers.Add(oLayer)
        oOverlay.TileCache = New ThinkGeo.MapSuite.Core.FileBitmapTileCache()

        oCanvas = New ThinkGeo.MapSuite.Core.GdiPlusGeoCanvas

        Try

          oCanvas.BeginDrawing(oGeoImage, oBoundingBox, lngMapUnit)
          oOverlay.Draw(oCanvas)

        Finally
          If oCanvas.IsDrawing Then
            oCanvas.Flush()
            oCanvas.EndDrawing()
          End If
        End Try

      End SyncLock

      bytArray = ThinkGeo.MapSuite.Core.GdiPlusGeoCanvas.ConvertGeoImageToMemoryStream(oGeoImage, System.Drawing.Imaging.ImageFormat.Png).ToArray

      Return bytArray

    End Function
 

As you can see we use Overlay and the associated cache to draw on canvas. With the WPF edition we can't do this because there is now draw() method with we can draw direct to the canvas. How can we implement a server cache with WPF edition?


2.)

We have to edit large shapes. In the Desktop Edition you made some enhancements to improve the performance when working with large shapes.

wiki.thinkgeo.com/wiki/File:...Vertex.jpg

 

In the WPF edition editing of those large shapes is not usable. Can we do something to improve the performance?


Thomas



 Thomas,


Thanks for your post!


For Issue #1 the structure is different in the WPF Edition as we don't accept the GeoCanvas at the Overlay level.  However you can accomplish what you want by accessing the Geocanvas on the layer within the overlay.  Below is a code snippet that shows how to do this:


 



Private Sub GetLayersImage(overlay As LayerOverlay, canvas As GdiPlusGeoCanvas)
        Dim candidates As New Collection(Of SimpleCandidate)
        For Each layer As Layer In overlay.Layers
            layer.Open()
            layer.Draw(canvas, candidates)
            layer.Close()
        Next
    End Sub

On issue #2 the code sample you referred to in the wiki should work with the WPF Edition too without any issue.  Did you get it working and it's just that the performance is to slow?


Thanks!



Clint,


Thanks for your information. But I think I have to give you some more information because my sample code is not showing the real code, its just a sample to give you an overview what we are doing.


We use overlay with activated FileBitmapCache. If a user requests an extent for the first time, overlay draws the image with the layer. On the second request overlay draws the image using the data in the tile cache whitch is much more faster.


In your sample there is no caching operation.


issue #2:


In our evaluation version of WPF-Control we use the same code as in the Dektop edition but editing is much slower. I will make some tests with the wiki sample.


Thomas



Thomas, 
  
 Thanks for your reply.   
  
 On Issue #1, is there anyway you can use our built in cache system?  It sound like it will do what you want without the complexity of having to manage it yourself, however you may have additional requirements that I’m aware of.  For a sample on how to use the built in Tile Cache system check out the How Do I sample included with the WPF Edtion, I believe it’s in the following directory;  “\HowDoISamples\CSharp Samples\Getting Started\UsingTileCache.xaml” 
  
 On Issue #2 if you are seeing slowness one thing you might try is setting the RenderMode on the EditOVerlay and TrackOverlay using the code below: 
  
 wpfMap1.EditOverlay.RenderMode = RenderMode.GdiPlus; 
 wpfMap1.TrackOverlay.RenderMode = RenderMode.GdiPlus; 
  
 WPF rendering has several ties to the rendering depending on the OS and hardware configuration, so if you set the render mode go GDI Plus it will be using the same rendering as the Desktop edition. 
  
 Thanks! 
  


Clint,


if you look on my sample code you can see that I'm using your caching system.


oOverlay.TileCache = New ThinkGeo.MapSuite.Core.FileBitmapTileCache(...Path to our cache directory)

 


Also you can see in my sample code how it works in Desktop Edition. I use overlay with activated Tile-Cache to draw on local GdiPlusGeoCanvas then convert the canvas image to byte array and deliver it to my client.


In WPF-Edition there is no Draw() method in overlay. As you mentioned I can use layer-object to draw to the canvas but then I can't use Tile-Cache because it is only on the overlay level.


Thomas



Thomas, 



Let's step back a little bit so I have a better understanding of what you are wanting to do overall and then maybe I can provide a good approach in how to do this in the WPF Edition.   



On your original post you said "We have a server side caching system based on following code".    Can you provide more information on how your server side cacheing works?  I'm assuming it will serve up a cached image that you will then want to draw on the client?  If this is the case you wouldn't you have the equivalent of one layer within your overlay making up the tile from the server side cache and could use the Layer.Draw? 



Can you also give a general overview of your application and architecture and maybe that will help me better understand the issue. 



Thanks! 



Clint, 
  
 you wrote: “I’m assuming it will serve up a cached image that you will then want to draw on the client?”. This is exactly what I want to do! 
 In our client/server application the users can create their own layers and maps. If the user created map contains many layers e.g. Shapefile-Layers with great number of shapes the drawing performance is very slow. To improve the performance the user can combine those layers how are used as static background to a static map and activate the client side caching system. This means we put them all in one overlay and activate the associated Tile-Cache. This works fine on the client. But every client (>100) has to draw the static background map until it is stored in the client cache. To avoid this we want to create a server side cache on our application server. First map request creates the image and returns it to the client besides the image is stored it in the server cache. Second map request can get the image from the server cache. 
  
 The sample code shows how we have done this in the Desktop Edition. I think in WPF-Edition we must use the TileCache-Class to get the same result but I need some sample code how to do this. 
  
 Thomas

 Hi Thomas,


 
I reviewed your scenario and found that you want to use the functionality of the Draw method to generate cache files. The WPF and Desktop Edition are designed in different structure. So the Draw with GeoCanvas parameter is moved into the Tile level so that we can have better performance with multithread.
 
We still have a chance to implement an extension for you with the Draw method you need. Please see the code below.

public static class LayerOverlayExtension
{
    public static void Draw(this LayerOverlay layerOverlay, GeoCanvas geoCanvas)
    {
        Collection<SimpleCandidate> labelCandidates = new Collection<SimpleCandidate>();
        foreach (var layer in layerOverlay.Layers)
        {
            lock (layer)
            {
                if (!layer.IsOpen) layer.Open();
                geoCanvas.Flush();
                layer.Draw(geoCanvas, labelCandidates);
            }
        }

        if (layerOverlay.TileCache != null)
        {
            layerOverlay.TileCache.TileMatrix.Scale = ExtentHelper.GetScale(geoCanvas.CurrentWorldExtent, geoCanvas.Width, geoCanvas.MapUnit);
            var tiles = layerOverlay.TileCache.GetTiles(geoCanvas.CurrentWorldExtent);
            foreach (var tile in tiles)
            {
                if (tile.Bitmap == null)
                {
                    GdiPlusGeoCanvas tempGeoCanvas = new GdiPlusGeoCanvas();
                    Bitmap nativeImage = new Bitmap(layerOverlay.TileWidth, layerOverlay.TileHeight);
                    try
                    {
                        tempGeoCanvas.BeginDrawing(nativeImage, tile.BoundingBox, geoCanvas.MapUnit);
                        Collection<SimpleCandidate> tempLabelCandidates = new Collection<SimpleCandidate>();
                        foreach (var layer in layerOverlay.Layers)
                        {
                            lock (layer)
                            {
                                if (!layer.IsOpen) layer.Open();
                                geoCanvas.Flush();
                                layer.Draw(tempGeoCanvas, tempLabelCandidates);
                            }
                        }
                        tempGeoCanvas.EndDrawing();
                        tile.Bitmap = nativeImage;
                        layerOverlay.TileCache.SaveTile(tile);
                    }
                    finally
                    {
                        nativeImage.Dispose();
                    }
                }
            }
        }
    }
}

 

Here is also a sample for you to use this extension. Please make sure putting the our dlls into the dependencies folder and put country02.shp into the app_data folder to run this app.
 
Please let me know if you have any question.
 
Thanks,
Howard

Post9837_WPFOverlayDrawWithGeoCanvasParameter.zip (11.2 KB)

Hello Howard,


thanks for your sample. I made some test with your sample and it is almost close to what we want to do. When looking on your sample code I recognized that we can build our server cache simply by using the TileCache class. I think this is a better way than our current implementation with the desktop edition because we access the caching system in a multithreaded way and I think overlay class is designed to work in the UI thread.


I have modified your sample (see attachement) even we want to use it in our application. But there is a bug in my caching system. The cached image is not drawn as expected.


Sorry for the unprofessional source code but I normaly use vb.


Thomas



Hi Thomas, 
  
 I see, the attached file cannot be downloaded, please re-upload the sample so that I can check the cache image issue. 
  
 Thanks, 
 Chen

Hi Thomas, 

  

The attached file cannot be downloaded, please re-upload the sample so that I can check the cache image issue. I didn't aware that you are using VB; sorry for that; just let me know if you need the VB version :)

  

Thanks, 

Chen



here again....



Post9837_WPFOverlayDrawGeoCanvasParam_V2.zip (23.5 KB)

Hi Thomas,


I checked your code and found there is an issue for the mechanism to merge tile images to a whole image. I have corrected it and please feel free to see how it works.


Another tips is that, only if the TileCache object is set on the LayerOverlay, we will load the cache automatically, so we need create a new FileBitmapTileCache with the same cache id and cache directory. If the TileCache property is not set, we need write our own logic to read cache and combine them.


Now this sample works fine now, please feel free to see if you have more queries.


Thanks,

Howard



Post9837_V2.zip (13.6 KB)

Hi, 
  
 can’t download the sample. Please rename your attached filename to a shorter one. Looks like the file extension is not valid because it is cut if the filename is to long. 
  
 Thomas

Hi Thomas, 
  
 I have updated the attached file in the previous reply. Please download that again and feel free to let us know if you have more queries. Sorry for the inconvenience. 
  
 Thanks, 
 Howard

Hi Howard, 
  
 it works. 
  
 Thanks for help, 
 Thomas

Hello Thomas, 
  
 You are welcome, please feel free to let us know your problems. 
  
 Regards, 
  
 Gary