Map with several layers

Topics: General
Nov 17, 2011 at 9:37 AM

Hi,

I wondered if the  MapControl can manage several layers data. I need to display several WMS layers and be able to show or hide as needed.

From what I saw, MapControl has only 1 MapProvider property, and it is not a collection ... So, is it possible ?

Coordinator
Nov 17, 2011 at 9:43 AM

create custom provider with different layers and switch between them

Nov 18, 2011 at 1:35 PM

Ok, I tryed to create a provider witch expose a Layers property. 

Layers is a collection of layers and each layer give the url of wms data.

I have overrided the GetTileImage method of my Provider to do the merge of layers into one image. The merge work fine, but I have problem with refresh and cache...

 

Tyles should be refresh each time layers visibility changed, even if the map is not pan or zoom...

Can you tell me how I can do that ?

Below, the code of my provider for those interested.

    public class WMSLayer
    {

        #region Properties

        public string Url { get; set; }

        public string Token { get; set; }

        public bool IsVisible { get; set; }

        #endregion
    }


    public class WMSProvider : GMapProvider
    {
        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        public WMSProvider()
        {
            Layers = new ObservableCollection<WMSLayer>();
        }

        #endregion

        #region Properties

        public ObservableCollection<WMSLayer> Layers { get; set; }

        #endregion

        #region GMapProvider Members

        readonly Guid id = Guid.NewGuid();
        public override Guid Id
        {
            get
            {
                return id;
            }
        }

        readonly string name = "WMS Provider";
        public override string Name
        {
            get
            {
                return name;
            }
        }

        GMapProvider[] overlays;
        public override GMapProvider[] Overlays
        {
            get
            {
                if (overlays == null)
                {
                    overlays = new GMapProvider[] { this };
                }
                return overlays;
            }
        }

        public override PureProjection Projection
        {
            get
            {
                return MercatorProjection.Instance;
            }
        }
        
        public override PureImage GetTileImage(GPoint pos, int zoom)
        {
            PureImage result = null;

            foreach (WMSLayer layer in Layers)
            {
                if (layer.IsVisible)
                {
                    string url = MakeTileImageUrl(pos, zoom, layer);
                    PureImage layerImage = null;

                    try
                    {
                        layerImage = GetTileImageUsingHttp(url);
                    }
                    catch (Exception)
                    {
                        // Todo catch timeout error
                    }

                    if (layerImage is WindowsPresentationImage)
                    {
                        if (result == null)
                        {
                            result = layerImage;
                        }
                        else
                        {
                            // Merge layerImage with previous
                            MemoryStream res = result.Data;
                            Image img = Image.FromStream(result.Data);

                            using (Graphics grfx = Graphics.FromImage(img))
                            {
                                grfx.DrawImage(Image.FromStream(layerImage.Data), 0, 0, img.Width, img.Height);
                            }

                            MemoryStream ms = new MemoryStream();
                            img.Save(ms, ImageFormat.Png);
                            ms.Position = 0;
                            result.Data = ms;
                        }
                    }
                }
            }

            return result;
        }
        

        #endregion

        #region WMS provider core
        
        string MakeTileImageUrl(GPoint pos, int zoom, WMSLayer layer)
        {
            string result = "";

            if (layer != null)
            {
                var px1 = Projection.FromTileXYToPixel(pos);
                var px2 = px1;

                px1.Offset(0, Projection.TileSize.Height);
                PointLatLng p1 = Projection.FromPixelToLatLng(px1, zoom);

                px2.Offset(Projection.TileSize.Width, 0);
                PointLatLng p2 = Projection.FromPixelToLatLng(px2, zoom);

                result = string.Format(CultureInfo.InvariantCulture, layer.Url + UrlEndFormat, layer.Token, p1.Lng, p1.Lat, p2.Lng, p2.Lat, Projection.TileSize.Width, Projection.TileSize.Height);
            }

            return result;
        }
        
        static readonly string UrlEndFormat = "?LAYERS={0}&TRANSPARENT=true&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&bbox={1},{2},{3},{4}&width={5}&height={6}&srs=EPSG:4326&format=image/png";
 
        #endregion

    }

Coordinator
Nov 18, 2011 at 1:42 PM

..thats not i meaned, and Guid.NewGuid(); will simply trash the local cache.

You need to make different providers for different layer configurations, all the merging will be done automatically

Nov 18, 2011 at 1:52 PM

I'm not sure I understand.

Let's say I have three layers: A, B and C
you tell me to make as many provider that there are possible combinations between these different layers :
ProviderA (that display only the layer A), ProviderB, ProviderC, ProviderAB, ProviderBC, ProviderAC, ProviderABC?

And next to set the Provider property of the MapControl with the good provider according to the visibility state of my layers ?

Coordinator
Nov 18, 2011 at 2:23 PM

yes

Jun 10, 2015 at 12:40 PM
Hi,

I have the same question. Is it possible to have an WMS Provider with different Layers?

Regards