ThinkGeo.com    |     Documentation    |     Premium Support

Strange behavior when downloading WMS layer

Hi,

I’m trying to download a image from a custom map server which returns me a PNG of administrative borders. I made a class derived from GoogleMapsOverlay where i simply set the url to be used. The problem is that the returned image is “shifted”.

In instance, when I check an adress with a browser I get a correct image (see todo.png). However when I use the exact same url with my class I get a strange result  (see done.png). It seems that my final result is shifted to the right.



Any idea why?



Here is the code below is this can help.


namespace ImageGeneration.Business
{
    using System.IO;
    using System.Net;
    using ThinkGeo.MapSuite.Core;
    using ThinkGeo.MapSuite.WpfDesktopEdition;
    using System.Globalization;
    using System.Text;
    using ImageGeneration.Properties;
 
    public class AdminUnitOverlay : GoogleMapsOverlay
    {
        public AdminUnitOverlay(double? opacity, string layerName, RectangleShape rec, double width, double height)
        {
            Opacity = opacity;
            LayerName = layerName;
            TileType = TileType.SingleTile;
            Url = GetImgUri(Settings.Default.DatastoreUrl, rec, width, height);
            this.SendingWebRequest += CustomGoogleMapsOverlay_SendingWebRequest;
            this.SentWebRequest += CustomGoogleMapsOverlay_SentWebRequest;
        }
 
        public double? Opacity { getprivate set; }
 
        public string LayerName { getprivate set; }
 
        public string Url { getprivate set; }
 
        void CustomGoogleMapsOverlay_SentWebRequest(object sender, SentWebRequestEventArgs e)
        {
            //App.Calls++;
            //File.AppendAllText(@“c:\calls.txt”,“Calls: “+App.Calls.ToString()+”\r\n”);
        }
 
        void CustomGoogleMapsOverlay_SendingWebRequest(object sender, SendingWebRequestEventArgs e)
        {
            e.WebRequest = WebRequest.Create(Url);
        }
 
        private string GetImgUri(string serverUrl, RectangleShape tileExtent, double tileWidth, double tileHeight)
        {
            var uriBuilder = new StringBuilder();
 
            uriBuilder.Append(
                string.Format(
                    “{0}?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&EXCEPTIONS=application/vnd.ogc.se_inimage&SRS={1}&FORMAT={2}&BBOX={3},{4},{5},{6}&WIDTH={7}&HEIGHT={8}”,
                    serverUrl,
                    “EPSG:900913”,
                    “png32”,
                    tileExtent.LowerLeftPoint.X.ToString(CultureInfo.InvariantCulture),
                    tileExtent.LowerLeftPoint.Y.ToString(CultureInfo.InvariantCulture),
                    tileExtent.UpperRightPoint.X.ToString(CultureInfo.InvariantCulture),
                    tileExtent.UpperRightPoint.Y.ToString(CultureInfo.InvariantCulture),
                    tileWidth,
                    tileHeight));
 
            uriBuilder.Append(string.Concat("&layers=", LayerName));
 
            return uriBuilder.ToString();
        }
    }
}




A bit more code



Generation of the map





 
// Initializing map
mc = new MapCreator();
mc.map.Overlays.Clear();
mc.map.Width = mapInfo.MapImageWidth;
mc.map.Height = mapInfo.MapImageHeight;
mc.map.MapUnit = GeographyUnit.Meter;
 
RectangleShape bbox = BaseShapeFactory.ProjectGeometry(
    BaseShape.CreateShapeFromWellKnownData(mapInfo.BboxWkt),
    Proj4Projection.GetEpsgParametersString(4326),
    Proj4Projection.GetGoogleMapParametersString()).GetBoundingBox();
 
mc.viewBoxContainer.Measure(new System.Windows.Size(mc.map.Width, mc.map.Height));
mc.viewBoxContainer.Arrange(new Rect(0, 0, mc.map.Width, mc.map.Height));
mc.viewBoxContainer.UpdateLayout();
 
// Positionning map
mc.map.CurrentExtent = bbox;
 
var adminOverlay = new AdminUnitOverlay(layer.Opacity, ReportConst.Default_AdminUnitLayer, bbox, mc.map.Width, mc.map.Height);
adminOverlay.DrawnTile += adminOverlay_DrawnTile;
mc.map.Overlays.Add(adminOverlay);
 




Event handler




private void adminOverlay_DrawnTile(object sender, DrawnTileTileOverlayEventArgs e)
{
    try
    {
        var overlay = (AdminUnitOverlay)sender;
 
        var img = (Bitmap)(e.GeoCanvas.NativeImage as Bitmap).Clone();
        if (img != null)
        {
            mc.map.OverlaysImages.Add((Bitmap)img.Clone(), overlay.Opacity);
            img.Dispose();
        }
    }
    catch
    {
        System.Diagnostics.Debugger.Break();
    }
}


Hi Clem,


Thanks for paying attention to Map Suite products and
detailed information about your question. Please check my answers as following:


1.  Seems like the attached images (todo.png and “done.png”)
are missed, here thinkgeo.com/forums/MapSuite/tabid/143/aft/7657/Default.aspx is a guide on how to attach the image in the thread, please
check it out.
2.  The GoogleMapsOverlay in WpfEdition is based on
the GoogleMapsLayer in MapSuiteCore.dll, and do some optimization, I think it’s
better that make AdminUnitOverlay inherited from WmsOverlay, and then Override
the method “Collection<Uri> GetRequestUrisCore(RectangleShape
requestExtent)”, please remember the Url is the root path instead of the concrete
tile path. In other words, in the attached code, please don’t call “GetImgUri”
method in the constructor of “AdminUnitOverlay”.


Please take a try and any questions please let me know.


 


Thanks,


Johnny 


 



Here is the screenshots



Image we should game:





Image downloaded with my current implementation:



Hi Chem,



I think I might have some insights on this issue as I encountered some similar issues of tiles shifts on GoogleMapsOverlay. But unfortunately, as for this GoogleMapsOveraly issue, we are still working on it and needs some days to fix it.

The above is just my guess, and I think it should be worth to try the WmsOverlay as Johnny suggested or define a custom layer to inherit from GoogleMapsLayer and then add the custom Layer into a LayerOverlay. Besides, I will follow your codes to build a sample to recreate your issue and I will let you know if any updates.



Thanks,

Troy

Hi,

so I’ve tried to simply change the inherited class from GoogleMapsOverlay to WmsOverlay and the Url call. This gives me this:




namespace ImageGeneration.Business
{
    using System.IO;
    using System.Net;
    using ThinkGeo.MapSuite.Core;
    using ThinkGeo.MapSuite.WpfDesktopEdition;
    using System.Globalization;
    using System.Text;
    using ImageGeneration.Properties;
 
    /// <summary>
    /// The custom google maps overlay.
    /// </summary>
    public class AdminUnitOverlay : WmsOverlay
    {
        private RectangleShape _bbox;
        private double _width;
        private double _height;
         
        // public CustomWpfMap Map { get; private set; }
        /// <summary>
        /// Gets the opacity.
        /// </summary>
        public double? Opacity { getprivate set; }
 
        public string LayerName { getprivate set; }
 
        public string Url { getprivate set; }
 
        /// <summary>
        /// Initializes a new instance of the <see cref=“CustomGoogleMapsOverlay”/> class.
        /// </summary>
        /// <param name=“opacity”>
        /// The opacity.
        /// </param>
        public AdminUnitOverlay(double? opacity, string layerName, RectangleShape rec, double width, double height)
        {
            _bbox = rec;
            _width = width;
            _height = height;
 
            Opacity = opacity;
 
            LayerName = layerName;
            //Parameters.Add(“srs”, “EPSG:900913”);
            //Parameters.Add(“format”, “png32”);
            TileType = TileType.SingleTile;
 
 
            this.SendingWebRequest += AdminUnitOverlay_SendingWebRequest;
            this.SentWebRequest += AdminUnitOverlay_SentWebRequest;
        }
 
        void AdminUnitOverlay_SentWebRequest(object sender, SentWebRequestEventArgs e)
        {
            //App.Calls++;
            //File.AppendAllText(@“c:\calls.txt”,“Calls: “+App.Calls.ToString()+”\r\n”);
        }
 
        void AdminUnitOverlay_SendingWebRequest(object sender, SendingWebRequestEventArgs e)
        {
            Url = GetImgUri(Settings.Default.DatastoreUrl, _bbox, _width, _height);
            e.WebRequest = WebRequest.Create(Url);
        }
 
        private string GetImgUri(string serverUrl, RectangleShape tileExtent, double tileWidth, double tileHeight)
        {
            var uriBuilder = new StringBuilder();
 
            uriBuilder.Append(
                string.Format(
                    “{0}?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&EXCEPTIONS=application/vnd.ogc.se_inimage&SRS={1}&FORMAT={2}&BBOX={3},{4},{5},{6}&WIDTH={7}&HEIGHT={8}”,
                    serverUrl,
                    “EPSG:900913”,
                    “png32”,
                    tileExtent.LowerLeftPoint.X.ToString(CultureInfo.InvariantCulture),
                    tileExtent.LowerLeftPoint.Y.ToString(CultureInfo.InvariantCulture),
                    tileExtent.UpperRightPoint.X.ToString(CultureInfo.InvariantCulture),
                    tileExtent.UpperRightPoint.Y.ToString(CultureInfo.InvariantCulture),
                    tileWidth,
                    tileHeight));
 
            uriBuilder.Append(string.Concat("&layers=", LayerName));
 
 
            return uriBuilder.ToString();
        }
    }
}

When I refresh the map to download the data I get the following exception:



Type:

System.ArgumentOutOfRangeException



Message:

Index was out of range. Must be non-negative and less than the size of the collection.

Parameter name: index



Stack:

   at System.ThrowHelper.ThrowArgumentOutOfRangeException()

   at System.Collections.Generic.List`1.get_Item(Int32 index)

   at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WmsOverlay.DrawTileCore(Tile tile, RectangleShape targetExtent)

   at ThinkGeo.MapSuite.WpfDesktopEdition.TileOverlay.DrawTile(Tile tile, RectangleShape targetExtent)

   at ThinkGeo.MapSuite.WpfDesktopEdition.TileOverlay.kBQ=(RectangleShape kRQ=)

   at ThinkGeo.MapSuite.WpfDesktopEdition.TileOverlay.DrawCore(RectangleShape targetExtent, OverlayRefreshType overlayRefreshType)

   at ThinkGeo.MapSuite.WpfDesktopEdition.Overlay.Draw(RectangleShape targetExtent, OverlayRefreshType refreshType)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.jxU=(Overlay khU=, RectangleShape kxU=, OverlayRefreshType lBU=)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.hxU=(IEnumerable`1 jBU=, RectangleShape jRU=, OverlayRefreshType jhU=)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.hxU=(RectangleShape iBU=, OverlayRefreshType iRU=)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.DrawCore(RectangleShape targetExtent, OverlayRefreshType overlayRefreshType)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.Draw(RectangleShape targetExtent, OverlayRefreshType refreshType)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.dxU=(RectangleShape eBU=)

   at ThinkGeo.MapSuite.WpfDesktopEdition.WpfMap.Refresh()

Hi Clem, 
  
 I think that “GetRequestUrisCore” is overridden is necessary. Being the request uris are got in this method as following demo: 
  
 
        protected override Collection<Uri> GetRequestUrisCore(RectangleShape requestExtent)
        {
            Collection<Uri> serverUris = new Collection<Uri>();

            //ToDo: analysis the request uris with your uri roles

            return serverUris;
        }

 
 
  
 Thanks, 
  
 Don

It’s now correctly working :) 
 Thanks a lot!

Hi Clem, 
  
 I am glad to hear that works for you. 
  
 Regards, 
  
 Don