ThinkGeo.com    |     Documentation    |     Premium Support

MiniMapAdornmentLayer Performance Help

Hi,


I've added the MiniMapAdornmentLayout example to my application, and I noticed a significant performance degradation when zooming and panning.  This is most likely due to the fact that my layer has 18,000 features to render, and now those points are being rendered twice (once in the map's main layer, and again for the mini map)!  I was thinking that to improve performance, perhaps I could render a cached image of my feature layer into the mini map adornment.  


I've attempted to do this, with the code below, but am failing to see my image in the mini map.


Are there any examples for how to render a layer to an image, and then the image back to a canvas?  Or perhaps someone has some other ideas around this.  Also, How do I make my code look like code in this editor?


My code is below, and like I said is based on the MiniMapAdornmentLayout example.


Thanks,


Greg


 


  private GeoImage miniImage;



        private GeoImage GetPointsImage(Layer layer, GeographyUnit mapUnit, RectangleShape scaledWorldExtent, Collection<SimpleCandidate> labelsInAllLayers)

        {

            if (miniImage == null) {

                miniImage = new GeoImage(width, height);

                GdiPlusGeoCanvas miniCanvas = new GdiPlusGeoCanvas();

                miniCanvas.BeginDrawing(miniImage, scaledWorldExtent, mapUnit);

                layer.Draw(miniCanvas, labelsInAllLayers);

                miniCanvas.EndDrawing();

            }

            return miniImage;

        }



        protected override void DrawCore(GeoCanvas canvas, Collection<SimpleCandidate> labelsInAllLayers)

        {

            GeoImage miniImage = new GeoImage(width, height);

            RectangleShape scaledWorldExtent = MapEngine.GetDrawingExtent(canvas.CurrentWorldExtent, width, height);

            scaledWorldExtent.ScaleUp(300);

            GdiPlusGeoCanvas minCanvas = new GdiPlusGeoCanvas();



            minCanvas.BeginDrawing(miniImage, scaledWorldExtent, canvas.MapUnit);

            ScreenPointF drawingLocation = GetDrawingLocation(canvas, width, height);



            foreach (Layer layer in layers) {

                GeoImage pointImage = GetPointsImage(layer, canvas.MapUnit, scaledWorldExtent, labelsInAllLayers);

                if (pointImage != null) {

                    minCanvas.DrawScreenImageWithoutScaling(

                        pointImage,

                        (width / 2),

                        (height / 2),

                        DrawingLevel.LevelOne,

                        0,

                        0,

                        0);

                }

            }



           



            minCanvas.DrawArea(RectangleShape.ScaleDown(minCanvas.CurrentWorldExtent, 1), new GeoPen(GeoColor.StandardColors.Gray, 2), DrawingLevel.LevelOne);

            minCanvas.DrawArea(canvas.CurrentWorldExtent, new GeoPen(GeoColor.StandardColors.Gray, 2), DrawingLevel.LevelOne);

            minCanvas.EndDrawing();



            canvas.DrawScreenImageWithoutScaling(miniImage, (drawingLocation.X + width / 2) + 10, (drawingLocation.Y + height / 2) - 10, DrawingLevel.LevelOne, 0, 0, 0);

}





Greg,


Following guide shows you how to paste your code like a editor.
gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/21/aft/4941/afv/topic/Default.aspx
 
The problem in your code is that the following code really drawn to get the image is never excuted:

private GeoImage GetPointsImage(Layer layer, GeographyUnit mapUnit, RectangleShape scaledWorldExtent, Collection labelsInAllLayers)
{
    if (miniImage == null) 
    {
        miniImage = new GeoImage(width, height);
        GdiPlusGeoCanvas miniCanvas = new GdiPlusGeoCanvas();
        miniCanvas.BeginDrawing(miniImage, scaledWorldExtent, mapUnit);
        layer.Draw(miniCanvas, labelsInAllLayers);
        miniCanvas.EndDrawing();
    }
    return miniImage;
}

 
Following is my solution, hope it can helps somehow:
First change a bit in the MiniMapAdormentLayer as following:

    public class MiniMapAdornmentLayer : AdornmentLayer
    {
        private Collection<Layer> layers;
        private int width;
        private int height;

        public MiniMapAdornmentLayer()
            : this(new Layer[] { }, 100, 100)
        { } 

        public MiniMapAdornmentLayer(int width, int height)
            : this(new Layer[] { }, width, height)
        { }

        public MiniMapAdornmentLayer(IEnumerable<Layer> layers, int width, int height)
        {
            this.layers = new Collection<Layer>();
            foreach (Layer layer in layers)
            {
                this.layers.Add(layer);
            }

            this.width = width;
            this.height = height;
        }

        public Collection<Layer> Layers
        {
            get { return layers; }
        }

        public int Width
        {
            get { return width; }
            set { width = value; }
        }

        public int Height
        {
            get { return height; }
            set { height = value; }
        }

        private Bitmap miniCachedImage;

        public Bitmap MiniCachedImage
        {
            get { return miniCachedImage; }
            set { miniCachedImage = value; }
        }

        protected override void DrawCore(GeoCanvas canvas, Collection<SimpleCandidate> labelsInAllLayers)
        {
            GeoImage miniImage = new GeoImage(width, height);
            RectangleShape scaledWorldExtent = MapEngine.GetDrawingExtent(canvas.CurrentWorldExtent, width, height);
            scaledWorldExtent.ScaleUp(300);
            GdiPlusGeoCanvas minCanvas = new GdiPlusGeoCanvas();

            minCanvas.BeginDrawing(miniImage, scaledWorldExtent, canvas.MapUnit);
            if (MiniCachedImage == null)
            {
                foreach (Layer layer in layers)
                {
                    layer.Draw(minCanvas, labelsInAllLayers);
                }
            }
            else
            {
                MemoryStream memoryStream = new MemoryStream();
                MiniCachedImage.Save(memoryStream,System.Drawing.Imaging.ImageFormat.Png);
                GeoImage tempImage = new GeoImage(memoryStream);
                minCanvas.DrawScreenImage(tempImage, width / 2, height / 2, width, height, DrawingLevel.LevelOne, 0, 0, 0);
            }

            minCanvas.DrawArea(RectangleShape.ScaleDown(minCanvas.CurrentWorldExtent, 1), new GeoPen(GeoColor.StandardColors.Gray, 2), DrawingLevel.LevelOne);
            minCanvas.DrawArea(canvas.CurrentWorldExtent, new GeoPen(GeoColor.StandardColors.Black, 2), DrawingLevel.LevelOne);

            minCanvas.EndDrawing();

            ScreenPointF drawingLocation = GetDrawingLocation(canvas, width, height);

            canvas.DrawScreenImageWithoutScaling(miniImage, (drawingLocation.X + width / 2) + 10, (drawingLocation.Y + height / 2) - 10, DrawingLevel.LevelOne, 0, 0, 0);
        }
    }

 
Second, when you use it , cached the images after the regurlar layers drawn:

        private void TestForm_Load(object sender, EventArgs e)
        {
            // Set the full extent and the background color
            mapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(new RectangleShape(-180.0, 83.0, 180.0, -90.0), Map.Width, Map.Height);
            mapEngine.BackgroundFillBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);

            // Add the static layers to the MapEngine
            worldLayer = new ShapeFileFeatureLayer(@"..\..\Data\Countries02.shp", ShapeFileReadWriteMode.ReadOnly);
            worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.County1;
            worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            mapEngine.StaticLayers.Add("WorldLayer", worldLayer);

            // Add MiniMapAdornmentLayer to the MapEngine
            MiniMapAdornmentLayer miniMapLayer = new MiniMapAdornmentLayer();
            miniMapLayer.Location = AdornmentLocation.LowerLeft;

            miniMapLayer.Layers.Add(new BackgroundLayer(mapEngine.BackgroundFillBrush));
            for (int i = 0; i < mapEngine.StaticLayers.Count; i++)
            {
                miniMapLayer.Layers.Add(mapEngine.StaticLayers<i>);
            }

            mapEngine.DynamicLayers.Add("MiniMapLayer",miniMapLayer);

            DrawImage();
        }

      
        private void DrawImage()
        {
            if (bitmap != null) { bitmap.Dispose(); }
            bitmap = new Bitmap(Map.Width, Map.Height);
            mapEngine.OpenAllLayers();
            mapEngine.DrawStaticLayers(bitmap, GeographyUnit.DecimalDegree);

            ((MiniMapAdornmentLayer)(mapEngine.DynamicLayers["MiniMapLayer"])).MiniCachedImage = bitmap;

            mapEngine.DrawDynamicLayers(bitmap, GeographyUnit.DecimalDegree);
            mapEngine.CloseAllLayers();

            Map.Image = bitmap;
        }

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