ThinkGeo.com    |     Documentation    |     Premium Support

Non smooth panning

Hi,


My map data is located in a centralized web service server and it returns my desktop app images in bytes.  The panning seems not smooth enough after I added more layers. 


The following is how I add my layers.  It's built from the C# web service sample code with spatial index for each shape file.


 



if (Application["usaLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\USStates.shp"), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.State1;

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

layer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.City1("STATE_NAME");

layer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.BestPlacement = true;

Application["usaLayer"] = layer;

}

if (Application["worldLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\Countries02.shp"), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Application["worldLayer"] = layer;

}

if (Application["canadaLayer4"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.CANADALAYER4), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.State1;

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["canadaLayer4"] = layer;

}

if (Application["oceanLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.OCEANLAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = waterStyle; // AreaStyles.Water1;

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["oceanLayer"] = layer;

}

if (Application["islandLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.ISLANDLAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add( AreaStyles.Country1 );

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["islandLayer"] = layer;

}

if (Application["landuseALayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.LANDUSEALAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(AreaStyles.Park1);

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["landuseALayer"] = layer;

}

if (Application["landuseBLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.LANDUSEBLAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(AreaStyles.Grass1);

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["landuseBLayer"] = layer;

}

if (Application["landcustLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.LANDCUSTLAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(AreaStyles.Urban1);

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["landcustLayer"] = layer;

}

if (Application["water1Layer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.WATERWAY1LAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(waterStyle);//AreaStyles.Water1);

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["water1Layer"] = layer;

}

if (Application["water2Layer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.WATERWAY2LAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(waterStyle);//AreaStyles.Water1);

layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

Application["water2Layer"] = layer;

}

if (Application["sm_street1Layer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.STREETLAYER1), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel14.DefaultLineStyle.OuterPen = new GeoPen(GeoColor.FromArgb(200, GeoColor.StandardColors.WhiteSmoke), 5);

layer.ZoomLevelSet.ZoomLevel14.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level15;

Application["sm_street1Layer"] = layer;

}

if (Application["sm_street1labelLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.STREETLAYER1), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel14.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level15;

layer.ZoomLevelSet.ZoomLevel14.CustomStyles.Add(TextStyles.LocalRoad1("NAME"));

Application["sm_street1labelLayer"] = layer;

}

if (Application["street1Layer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.STREETLAYER1), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel16.CustomStyles.Add(LineStyles.LocalRoad1);

layer.ZoomLevelSet.ZoomLevel16.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Application["street1Layer"] = layer;

}

if (Application["street1labelLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.STREETLAYER1), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel16.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

TextStyle textStyle = TextStyles.LocalRoad1("NAME");

textStyle.TextLineSegmentRatio = double.MaxValue;

textStyle.SplineType = SplineType.StandardSplining;

layer.ZoomLevelSet.ZoomLevel16.CustomStyles.Add(textStyle);

Application["street1labelLayer"] = layer;

}

 

if (Application["hwyLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.HWYLAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel13.CustomStyles.Add(LineStyles.Highway1);

layer.ZoomLevelSet.ZoomLevel13.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

Application["hwyLayer"] = layer;

}

 

if (Application["hwylabelLayer"] == null)

{

layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @CommonTypes.HWYLAYER), ShapeFileReadWriteMode.ReadOnly);

layer.ZoomLevelSet.ZoomLevel13.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

TextStyle textStyle = TextStyles.LocalRoad1("NAME");

textStyle.TextLineSegmentRatio = double.MaxValue;

textStyle.SplineType = SplineType.StandardSplining;

layer.ZoomLevelSet.ZoomLevel13.CustomStyles.Add(textStyle);

Application["hwylabelLayer"] = layer;

}

mapEngine.StaticLayers.Add("usaLayer", (ShapeFileFeatureLayer)Application["usaLayer"]);

mapEngine.StaticLayers.Add("worldLayer", (ShapeFileFeatureLayer)Application["worldLayer"]);

mapEngine.StaticLayers.Add("canadaLayer4", (ShapeFileFeatureLayer)Application["canadaLayer4"]);

mapEngine.StaticLayers.Add("oceanLayer", (ShapeFileFeatureLayer)Application["oceanLayer"]);

mapEngine.StaticLayers.Add("islandLayer", (ShapeFileFeatureLayer)Application["islandLayer"]);

mapEngine.StaticLayers.Add("landuseALayer", (ShapeFileFeatureLayer)Application["landuseALayer"]);

mapEngine.StaticLayers.Add("landuseBLayer", (ShapeFileFeatureLayer)Application["landuseBLayer"]);

mapEngine.StaticLayers.Add("landcustLayer", (ShapeFileFeatureLayer)Application["landcustLayer"]);

mapEngine.StaticLayers.Add("water1Layer", (ShapeFileFeatureLayer)Application["water1Layer"]);

mapEngine.StaticLayers.Add("water2Layer", (ShapeFileFeatureLayer)Application["water2Layer"]);

mapEngine.StaticLayers.Add("sm_street1Layer", (ShapeFileFeatureLayer)Application["sm_street1Layer"]);

mapEngine.StaticLayers.Add("sm_street1labelLayer", (ShapeFileFeatureLayer)Application["sm_street1labelLayer"]);

mapEngine.StaticLayers.Add("street1Layer", (ShapeFileFeatureLayer)Application["street1Layer"]);

mapEngine.StaticLayers.Add("street1labelLayer", (ShapeFileFeatureLayer)Application["street1labelLayer"]);

mapEngine.StaticLayers.Add("hwyLayer", (ShapeFileFeatureLayer)Application["hwyLayer"]);

mapEngine.StaticLayers.Add("hwylabelLayer", (ShapeFileFeatureLayer)Application["hwylabelLayer"]);

mapEngine.OpenAllLayers();

mapEngine.DrawStaticLayers(bitmap, GeographyUnit.DecimalDegree);

mapEngine.CloseAllLayers();


Thanks



Hi, 
  
 I removed all the layers now except one empty overlay.  I catched the OverlayDrawn event.  I noticed that the overlay is not drawn while my mouse moves.  I’d have to stop dragging so that the blank tiles will then be filled with map images.  Anything can I do to make the overlay draws whenever it pans to empty tiles? 
  
 Thanks!

Hi, 
  
 I just came across another subject in the forum that mentioned continous panning is not available.  Thanks anyway. 
  
 I still have difficulties making my map pan smoothly though.  Now I left one ShapeFileFeatureLayer in my web service.  For my desktop, I have one LayerOverlay in which I have a custom layer (I overrided the DrawCore so that I get my map from the web service).  I catched the OverlayDrawn event and I got the following overlay drawing time. 
  
 Here are the sample times of my first 6 pannings: 
 {00:01:56.9459621} 
 {00:05:08.0002600} 
 {00:06:59.7538547} 
 {00:01:44.1791750} 
 {00:01:07.4236455} 
 {00:03:49.6532325} 
  
 Even panning only a tiny bit, the drawing time is still over 1 minute.  Please advice. 
  
 Thanks. 
  






 




Hi, Tracy, 


It is the same idea and problem with the following post?
gis.thinkgeo.com/Support/Dis...fault.aspx

I think the Desktop Edition, if you pan to empty tiles (new tiles), it will go to draw automatically.Hope my following code can give you some help.


 First is the ImageService you can created, very similar to your service Sample service code:

/// <summary>
/// Summary description for ImageService
/// </summary>
[WebService(Namespace = "tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService]
public class ImageService : System.Web.Services.WebService
{
  [WebMethod]
  public byte[] GetMapImage(double worldUpperLeftX, double worldUpperLeftY, double worldLowerRightX, double worldLowerRightY, int imageWidth, int imageHeight, string layerName)
{
    Layer layer = GetLayer(layerName);
    GeoImage geoImage = GdiPlusGeoCanvas.CreateGeoImage(imageWidth, imageHeight);
    GdiPlusGeoCanvas.FillBackground(geoImage, new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean));
    RectangleShape worldExtent = new RectangleShape(new PointShape(worldUpperLeftX, worldUpperLeftY), new PointShape(worldLowerRightX, worldLowerRightY));

    lock (layer)
    {
       GdiPlusGeoCanvas gdiPlusGeoCanvas = new GdiPlusGeoCanvas();
       try
       {
         layer.Open();
         gdiPlusGeoCanvas.BeginDrawing(geoImage, worldExtent,GeographyUnit.DecimalDegree);
         layer.Draw(gdiPlusGeoCanvas, new Collection<SimpleCandidate>());
       }
       finally
       {
          if (gdiPlusGeoCanvas.IsDrawing)
          {
             gdiPlusGeoCanvas.EndDrawing();
          }
          layer.Close();
       }
    }

    return GdiPlusGeoCanvas.ConvertGeoImageToMemoryStream(geoImage).ToArray();
}

private Layer GetLayer(string layerName)
{
   ShapeFileFeatureLayer layer = null;
   if (Application["usaLayer"] == null)
   {
      layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\USStates.shp"), ShapeFileReadWriteMode.ReadOnly);
      layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.State1;
      layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

      Application["usaLayer"] = layer;
   }

   if (Application["worldLayer"] == null)
   {
      layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\Countries02.shp"), ShapeFileReadWriteMode.ReadOnly);
      layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
      layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

      Application["worldLayer"] = layer;
   }

   switch (layerName.ToUpperInvariant())
   {
      case "USA":
         layer = (ShapeFileFeatureLayer)Application["usaLayer"];
         break;
      case "WORLD":
         layer = (ShapeFileFeatureLayer)Application["worldLayer"];
         break;
      default:
         break;
   }

   return layer;
}
}

Then you can create your own Layer to use the service like this which will be used in the Client side:



public class SimpleCustomLayer : ShapeFileFeatureLayer
{
   private CustomImageService.ImageServiceSoapClient imageServiceSoapClient = new Post5214.CustomImageService.ImageServiceSoapClient(); 
        
   protected override void OpenCore()
   {

   }

   protected override void CloseCore()
   {

   }

   protected override RectangleShape GetBoundingBoxCore()
   {

      return new RectangleShape(-143.4, 109.3, 116.7, -76.3);
   }

   protected override void DrawCore(GeoCanvas canvas, Collection<SimpleCandidate> labeledInLayers)
   {
     Bitmap customImage = GetImage(canvas.CurrentWorldExtent.UpperLeftPoint.X, canvas.CurrentWorldExtent.UpperLeftPoint.Y, canvas.CurrentWorldExtent.LowerRightPoint.X, canvas.CurrentWorldExtent.LowerRightPoint.Y, (int)canvas.Width, (int)canvas.Height);

     canvas.DrawWorldImageWithoutScaling(canvas.ToGeoImage(customImage), canvas.CurrentWorldExtent.GetCenterPoint().X, canvas.CurrentWorldExtent.GetCenterPoint().Y, DrawingLevel.LevelOne);

     customImage.Dispose();

   }

   private Bitmap GetImage(double upperLeftX, double upperLeftY, double lowerRightX, double lowerRightY, int screenWidth, int screenHeight)
   {
     byte[] byteArray = imageServiceSoapClient.GetMapImage(upperLeftX, upperLeftY, lowerRightX, lowerRightY, screenWidth, screenHeight, "WORLD");
     MemoryStream memoryStream = new MemoryStream(byteArray);

     Bitmap customImage = new Bitmap(memoryStream);
     Graphics g = Graphics.FromImage(customImage);

     g.Dispose();

     return customImage;
   }
}

At last ,you can use like this in the Client side:

winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);

SimpleCustomLayer worldLayer = new SimpleCustomLayer();

LayerOverlay staticOverlay = new LayerOverlay();
staticOverlay.Layers.Add("WorldLayer", worldLayer);
winformsMap1.Overlays.Add(staticOverlay);

winformsMap1.CurrentExtent = new RectangleShape(-143.4, 109.3, 116.7, -76.3);
winformsMap1.Refresh();



Any more questions just let me know.


Thanks.
 
Yale

Posted By Tracy on 06-22-2009 08:50 PM 

Hi, 



I just came across another subject in the forum that mentioned continous panning is not available. Thanks anyway. 



I still have difficulties making my map pan smoothly though. Now I left one ShapeFileFeatureLayer in my web service. For my desktop, I have one LayerOverlay in which I have a custom layer (I overrided the DrawCore so that I get my map from the web service). I catched the OverlayDrawn event and I got the following overlay drawing time. 



Here are the sample times of my first 6 pannings: 

{00:01:56.9459621} 

{00:05:08.0002600} 

{00:06:59.7538547} 

{00:01:44.1791750} 

{00:01:07.4236455} 

{00:03:49.6532325} 



Even panning only a tiny bit, the drawing time is still over 1 minute. Please advice. 



Thanks. 




Tracy,
Thanks for your post!
 
I am very curious why it take so long to draw the map. Did the time get from the Service side?
Can you check which layer use the most of the time and send me the data if possible, I would like have a try to see why it take so much time. If every pan, it will take so long, it of course will cause sluggish.
          
        
Any more questions just let me know.
 
Thanks.
 
Yale





 



Hi Yale,


I took your code posted above and now I just use the sample app data(single layer:  Countries02) that comes with the evaluation edition on service side for testing.I noticed that my problem is actually on the client side when an overlay is redrawn.  I catch the OverlayDrawing and OverlayDrawn events and compute the time difference myself ( I yesterday used e.Overlay.DrawingTime property but it seemed it returned me wrong durations).  When I pan my map, the time difference between overlay drawing and drawn is about 1.5 - 2 secs.  There is a delay for the map display to be complete after overlay drawn event is raised.  The delay is roughly 0.5sec on average (I believe this delay is caused by threading).  The time required for panning makes it visually non smooth.  What can I do to speed it up?


Thanks!



Here is what I now have in service



namespace MapWebService
{
    /// <summary>
    /// Summary description for Service1
    /// </summary>
    [WebService(Namespace = "tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class Service1 : System.Web.Services.WebService
    {
        [WebMethod]
        public byte[] GetMapImage(double worldUpperLeftX, double worldUpperLeftY, double worldLowerRightX, double worldLowerRightY, int imageWidth, int imageHeight, string layerName)
        {
            ShapeFileFeatureLayer layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\Countries02.shp"), ShapeFileReadWriteMode.ReadOnly);

            layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
            layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            Application["countries02"] = layer;

            GeoImage geoImage = GdiPlusGeoCanvas.CreateGeoImage(imageWidth, imageHeight);
            GdiPlusGeoCanvas.FillBackground(geoImage, new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean));
            RectangleShape worldExtent = new RectangleShape(new PointShape(worldUpperLeftX, worldUpperLeftY), new PointShape(worldLowerRightX, worldLowerRightY));

            lock (layer)
            {
                GdiPlusGeoCanvas gdiPlusGeoCanvas = new GdiPlusGeoCanvas();
                try
                {
                    layer.Open();

                    gdiPlusGeoCanvas.BeginDrawing(geoImage, worldExtent, GeographyUnit.DecimalDegree);
                    layer.Draw(gdiPlusGeoCanvas, new Collection<SimpleCandidate>());
                }
                finally
                {
                    if (gdiPlusGeoCanvas.IsDrawing)
                    {
                        gdiPlusGeoCanvas.EndDrawing();
                    }

                    layer.Close();
                }
            }

            return GdiPlusGeoCanvas.ConvertGeoImageToMemoryStream(geoImage).ToArray();
        }
    }
}

Here is my client code



    public partial class Form1 : Form
    {
        DateTime startOverlayDraw;
        private Service1SoapClient imageServiceSoapClient = new Service1SoapClient();
        public System.TimeSpan serviceDrawingTime;
        
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean);

            LayerOverlay staticOverlay = new LayerOverlay();
            
            SimpleCustomLayer customLayer = new SimpleCustomLayer();
            staticOverlay.Layers.Add("CustomLayer", customLayer);
            winformsMap1.Overlays.Add(staticOverlay);
            
            winformsMap1.CurrentExtent = new RectangleShape(-123.18935, 49.204813, -123.06730, 49.126915);
            
            winformsMap1.Refresh();
        }

        private void winformsMap1_OverlayDrawn(object sender, OverlayDrawnWinformsMapEventArgs e)
        {
            MessageBox.Show((DateTime.Now - startOverlayDraw).ToString());
            
        }

        private void winformsMap1_OverlayDrawing(object sender, OverlayDrawingWinformsMapEventArgs e)
        {
            startOverlayDraw = DateTime.Now;
        }
    }
}


Tracy,


Thanks for your post!


First, I think you’d betteruse theOverlaysDrawing and OverlaysDrawn events to test the whole speed, because OverlayDrawing and OverlayDrawn only consider ONLY one Overlay and will fire many times if many overlays exist.


 



winformsMap1.OverlaysDrawing += new EventHandler<OverlaysDrawingWinformsMapEventArgs>(winformsMap1_OverlaysDrawing);
winformsMap1.OverlaysDrawn += new EventHandler<OverlaysDrawnWinformsMapEventArgs>(winformsMap1_OverlaysDrawn);

Second, I also tested both the server side time and client side time as following way:


Clint side



void winformsMap1_OverlaysDrawn(object sender, OverlaysDrawnWinformsMapEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("WinformMaps draw time:" + (DateTime.Now - startTimeToDraw).ToString());
}

void winformsMap1_OverlaysDrawing(object sender, OverlaysDrawingWinformsMapEventArgs e)
{
   startTimeToDraw = DateTime.Now;
}

Server side:



Stopwatch watch = new Stopwatch();
watch.Start();
lock (layer)
{
   GdiPlusGeoCanvas gdiPlusGeoCanvas = new GdiPlusGeoCanvas();
   try
   {
      layer.Open();
      gdiPlusGeoCanvas.BeginDrawing(geoImage, worldExtent,GeographyUnit.DecimalDegree);
      layer.Draw(gdiPlusGeoCanvas, new Collection<SimpleCandidate>());

   }
   finally
   {
      if (gdiPlusGeoCanvas.IsDrawing)
      {
         gdiPlusGeoCanvas.EndDrawing();
      }
      layer.Close();
   }
}

watch.Stop();
System.Diagnostics.Debug.WriteLine("DrawingTime =" + watch.ElapsedMilliseconds.ToString() + "Milliseconds");

 I think the performance is acceptable; none of the operations (random double zoom in, Pan Etc) exceed 1 second. Following is my test result.


 


DrawingTime =295Milliseconds
WinformMaps draw time:00:00:00.5644485
DrawingTime =74Milliseconds
WinformMaps draw time:00:00:00.1383021
DrawingTime =231Milliseconds
WinformMaps draw time:00:00:00.5488101
DrawingTime =156Milliseconds
WinformMaps draw time:00:00:00.4144176
DrawingTime =127Milliseconds
WinformMaps draw time:00:00:00.3142341
DrawingTime =130Milliseconds
WinformMaps draw time:00:00:00.3244968
DrawingTime =171Milliseconds
WinformMaps draw time:00:00:00.4266351
DrawingTime =166Milliseconds
WinformMaps draw time:00:00:00.4237029
DrawingTime =120Milliseconds
WinformMaps draw time:00:00:00.2668302
DrawingTime =128Milliseconds
WinformMaps draw time:00:00:00.2770929
DrawingTime =115Milliseconds
WinformMaps draw time:00:00:00.2526579
DrawingTime =157Milliseconds
WinformMaps draw time:00:00:00.4237029
DrawingTime =92Milliseconds
WinformMaps draw time:00:00:00.2018331
DrawingTime =87Milliseconds
WinformMaps draw time:00:00:00.2028105
DrawingTime =123Milliseconds
WinformMaps draw time:00:00:00.3196098
 
 
Third, if you really want toincrease the performance, you can try to add cache system to the server side to avoid it to draw every time. 
 
If any more questions just let me know.
 
Thanks.

 


Yale

Hi Yale,


I now have two layers, one renders a boundary area layer and one renders street layer.  I added both layers to one overlay as following on my client side.



        private void Form1_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree; 
            
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean);
                       
            SimpleCustomLayer streetLayer = new SimpleCustomLayer();
            streetLayer.Name = "streetLayer_polyline";

            SimpleCustomLayer adminLayer = new SimpleCustomLayer();
            adminLayer.Name = "Adminbndy4_region";

            winformsMap1.StaticOverlay.Layers.Add(adminLayer);
            winformsMap1.StaticOverlay.Layers.Add(streetLayer);

            winformsMap1.CurrentExtent = new RectangleShape(-123.18935, 49.204813, -123.06730, 49.126915); 
            winformsMap1.Refresh(); 

        }

        private void winformsMap1_OverlaysDrawing(object sender, OverlaysDrawingWinformsMapEventArgs e)
        {
            startTimeToDraw = DateTime.Now;
        }

        private void winformsMap1_OverlaysDrawn(object sender, OverlaysDrawnWinformsMapEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("WinformMaps draw time:" + (DateTime.Now - startTimeToDraw).ToString()); 
        }

The following is how I render the two layers from two different shape files on service side.



        [WebMethod]
        public byte[] GetLayerImage(double worldUpperLeftX, double worldUpperLeftY, double worldLowerRightX, double worldLowerRightY, int imageWidth, int imageHeight, string layerName)
        {
            ShapeFileFeatureLayer layer = getLayer(layerName);
            
            return Draw(worldUpperLeftX, worldUpperLeftY, worldLowerRightX, worldLowerRightY, imageWidth, imageHeight, layer, layerName);
        }

        private ShapeFileFeatureLayer getLayer(string layerName)
        {
            ShapeFileFeatureLayer layer = null;

            if (Application["streetLayer_polyline"] == null)
            {
                layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\streetLayer_polyline.shp"), ShapeFileReadWriteMode.ReadOnly);

                layer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle.OuterPen = new GeoPen(GeoColor.FromArgb(200, GeoColor.StandardColors.WhiteSmoke), 5);
                layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
                Application["streetLayer_polyline"] = layer;
            }

            if (Application["Adminbndy4_region"] == null)
            {
                layer = new ShapeFileFeatureLayer(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\Adminbndy4_region.shp"), ShapeFileReadWriteMode.ReadOnly);

                layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
                layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
                Application["Adminbndy4_region"] = layer;
            }

            switch (layerName) 
            { 
                case "Adminbndy4_region": 
                    layer = (ShapeFileFeatureLayer)Application["Adminbndy4_region"]; 
                    break; 
                case "streetLayer_polyline": 
                    layer = (ShapeFileFeatureLayer)Application["streetLayer_polyline"]; 
                    break; 
                default: 
                    break;
            } 
            return layer; 
        }

        private byte[] Draw(double worldUpperLeftX, double worldUpperLeftY, double worldLowerRightX, double worldLowerRightY, int imageWidth, int imageHeight, ShapeFileFeatureLayer layer, string layerName)
        {
            GeoImage geoImage = GdiPlusGeoCanvas.CreateGeoImage(imageWidth, imageHeight);
            RectangleShape worldExtent = new RectangleShape(new PointShape(worldUpperLeftX, worldUpperLeftY), new PointShape(worldLowerRightX, worldLowerRightY));

            Stopwatch watch = new Stopwatch();
            watch.Start();

            lock (layer)
            {
                GdiPlusGeoCanvas gdiPlusGeoCanvas = new GdiPlusGeoCanvas();
                try
                {
                    layer.Open();

                    gdiPlusGeoCanvas.BeginDrawing(geoImage, worldExtent, GeographyUnit.DecimalDegree);
                    layer.Draw(gdiPlusGeoCanvas, new Collection<SimpleCandidate>());
                }
                finally
                {
                    if (gdiPlusGeoCanvas.IsDrawing)
                    {
                        gdiPlusGeoCanvas.EndDrawing();
                    }

                    layer.Close();
                }
            }

            watch.Stop();
            System.Diagnostics.Debug.WriteLine("Drawing layer ="+layerName);
            System.Diagnostics.Debug.WriteLine("DrawingTime =" + watch.ElapsedMilliseconds.ToString() + "Milliseconds");

            byte[] image = GdiPlusGeoCanvas.ConvertGeoImageToMemoryStream(geoImage).ToArray();

            return image;
        }

My client side has the following drawing times which I found very slow. 


 



WinformMaps draw time:00:00:01.5315244
WinformMaps draw time:00:00:02.1097530
WinformMaps draw time:00:00:05.9073084
WinformMaps draw time:00:00:04.8602458
WinformMaps draw time:00:00:01.2502240
WinformMaps draw time:00:00:01.9691028
WinformMaps draw time:00:00:01.5158966
WinformMaps draw time:00:00:00.9689236
WinformMaps draw time:00:00:01.0470626
WinformMaps draw time:00:00:01.0470626
WinformMaps draw time:00:00:05.4853407

My server side has the following drawing times for each layer. 



Drawing layer =Adminbndy4_region
DrawingTime =334Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =433Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =276Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =1284Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =588Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =3538Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =796Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =2361Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =427Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =305Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =534Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =392Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =450Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =136Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =342Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =92Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =312Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =349Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =220Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =669Milliseconds
Drawing layer =Adminbndy4_region
DrawingTime =566Milliseconds
Drawing layer =streetLayer_polyline
DrawingTime =3360Milliseconds

I tried to add layers in the service instead so that one image is returned to the client but it doesn't make much different. 


I'd like to give you my shp files but I can't upload them since they exceed the 250kb limit. 


Please advice. 


Thanks!



Tracy. 
  
 It seems your performance is really somehow unexpected. As I said, we will public some APIs to help build cache system in the near future, I am sure this will give you great enhancement performance. 
  
 Still, I want to try your 2 shape files data to see why it is so slow. If you want, you can contact our sales support@thinkgeo.com and send him the shapes and ask him to forward to Yale that would be great! 
  
  
 Any more questions just let me know. 
  
 Thanks. 
  
 Yale 


Hi Yale, 
  
 I have emailed support my both layers.  The boundary area layer I have sent all in a zip file.  However, the street layer is too big that I separated the shp, shx, etc into different messages.   
  
 Thanks in advance for your help! 
  
 Tracy

Tracy,


Thanks for your post and data, I have tested the data from you and got the same results as you!


I found most of the time its performance is OK, the bad performance (will take about 5 seconds) will probably happens when almost all the records in the boundary area layer expected to be shown when in a comparatively high ZoomLevel shown in ScreenShot.


At this time, almost all the time is spent on the fetching data from shp and draw them, you know in this kind of ZoomLevel and extent, about 3000~4000 Polygons should be drawn, this is relatively uncommon.


My suggestions can we control not to draw on this ZoomLevel for this data? If we really has to do that to gain better result, 2 suggestions provided.


1)      Create your own FeatureSource and FeatureData and cache the data in server side memory instead of reading it every time. I am not confident it will gain excellent improvement.


Following is some posts you can get some ideas about it


gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/12/aft/5192/afv/topic/afpgj/2/Default.aspx#6059
 
gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/21/aft/5766/afv/topic/afpgj/1/Default.aspx#8904
 
2)      Do cache system in the service side as I talked about before.
Personally this is the best way as well as most time-consuming way. In this way, we will pre-generate cached tiles for the server side layers. When the client side need request, we DONOT need to draw every time. Instead, we just need to return back the corresponding tiles. This technique applies those layers which data is rarely changed.
 
 
Any more questions just let me know.
 
Thanks.
 
Yale

Hi Yale, 
  
 There is another application I’m working on that does not use the desktop map control.  All it does is to retrieve one map image at a time from web server.  I’m wondering whether cache system in the service side will also benefit this application since this application does not use tiles. 
  
 In web server, I added about 9 layers, including the area boundary layer and the street layer I sent to you before, to mapEngine and drew one image.  The file size of my image is about 300MB.  However, leaving only the area boundary layer for the same dimensions of image gave me also roughly 300MB file size.  I’m wondering how it happens.  I originally thought that less details in the image would give me a smaller file and the drawing time would be shorter. 
  
 Thanks, 
 Tracy 
  


Tracy, 
  
 Thanks for your post! 
  
 I think if you add the cache system in the service side and pre-generate the cached images, it will absolutely enhance the performance, and this enhancement will be much more obvious in the case your data is service side is huge. 
  
 I want to clarify one thing for my better understanding; you talked about the 300MB size. I want to make sure this 300MB is the data size, not an image size which you want to transfer from service side to client side. Right? Because normally, the image transferred from service side to client side should be very small, size is 1024 * 1024 and of course it should less than 2 MB. 
  
  
 Any more questions just let me know. 
  
 Thanks. 
  
 Yale 


Hi Yale, 
  
 Sorry about the file size.  I meant 3MB.  Is my file size supposed to be much smaller when I leave one layer to draw instead of 9 layers? 
  
 Thanks, 
 Tracy

Hi Yale,


Attached two map screenshots, one from msn map and one from thinkgeo web demo. 




 


I tried with google map and yahoo map as well but it seems thinkgeo map is somewhat stretched compared to others.


Thanks,


Tracy



Tracy, 


Thanks for your post!
 
I do not think there are “somewhat stretched” compare to Google/VE/Yahoo. The only potential difference is that we use different data instead. We use the Tiger data to render our maps in maps.thinkgeo.com, while the others seems using the NavteqData.
 
 
We provide some functionality to use the Google/Yahoo/VE as background and render our own data on top of it in WebEdtion. If you are interested, just have a look at the following samples in WebEdtion to compare the drawing bitmaps.
 
HowDoISamples/Samples/ Overlays/ UseGoogleMap.aspx
HowDoISamples/Samples/ Overlays/ UseVirtualEarth.aspx
HowDoISamples/Samples/ Overlays/ UseYahooMap.aspx
 
We also provide some on-line samples for WebEditon, you can use it if you do not want to install it on your local PC.
 
websamples.thinkgeo.com/webeditionsamples/
 
Let me know if you have more problems.
 
Thanks.
 
Yale

Yale, 
  
 The difference takes place in the projection. 
  
 Usually, when data are in wgs84, tools display them using a perpendicular projection to the center of the map; where MS use a perpendicular projection to the equator; this makes every data streched in the Y axis. I feel this as a MS bug; but anyway a very easy workaround is to projette the map to either: 
 - a projection that works every where (google projection or miller projection) 
 - a local projection (I dont’ know which projection are relevant for that map. 
  
 Hope this helps. 
 Patrick.

Thanks for your sharing, Patrick! 
  
 I am not sure about this idea about the perpendicular projection up to now; I will do some investigation about it! Thanks for your answer and hints! 
  
  
 Let me know if you have more problems. 
  
 Thanks. 
  
 Yale 


Thanks for the idea, Patrick. 


I believe my data is in wgs84 since in the corresponding .prj file, I found the following:


GEOGCS["Lat Long WGS84",DATUM["D_WGS84",SPHEROID["World_Geodetic_System_of_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]


I did the following but once I added the projection, the map doesn't want to render anymore. 


 


 




private void Form1_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.Meter;
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.DeepOcean);

            LayerOverlay staticOverlay = new LayerOverlay();
            
            RectangleShape recShp = new RectangleShape(0,0,0,0);
            winformsMap1.CurrentExtent = recShp;
            

            ShapeFileFeatureLayer layer = new ShapeFileFeatureLayer(@"C:\WebServiceImageServer\NEW_CAN\Islands_region.shp", ShapeFileReadWriteMode.ReadOnly);

           
            layer.Open();
            winformsMap1.CurrentExtent.ExpandToInclude(layer.GetBoundingBox());
            layer.Close();
            
            layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            layer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(AreaStyles.Country1);
            layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

            Proj4Projection proj4 = new Proj4Projection();
            proj4.ExternalProjectionParametersString = Proj4Projection.GetGoogleMapParametersString();
            proj4.InternalProjectionParametersString = Proj4Projection.GetEpsgParametersString(4326);
            proj4.Open();
            
            layer.FeatureSource.Projection = proj4;
            winformsMap1.StaticOverlay.Layers.Add(layer);

            winformsMap1.Refresh();
}


Thanks in advance!