ThinkGeo.com    |     Documentation    |     Premium Support

Refreshing layer to hide one feature takes a long time

Hello, I am trying to hide/show a single feature on a large layer but the refresh of the entire layer takes way too long. It takes up to 30 seconds to refresh the layer after turning off one single point… How can I speed this up?




public void HideFeatureOnLayer(string featureLayersGroupName, string featureLayerName,
                               ObservableCollection<mapfeature> features, bool doRefresh)
{
    Validate.NotNullOrEmpty("featureLayersGroupName", featureLayersGroupName);
    Validate.NotNullOrEmpty("featureLayerName", featureLayerName);
 
    FeatureLayer featureLayer = GetFeatureLayerByName(featureLayerName);
 
    if (featureLayer != null && featureLayer.FeatureSource != null)
    {
        featureLayer.FeatureSource.FeatureIdsToExclude.Clear();
 
        foreach (MapFeature feature in features)
        {
            featureLayer.FeatureSource.FeatureIdsToExclude.Add(feature.FeatureId);
        }
        featureLayer.FeatureSource.Open();
        if (doRefresh)
        {
            RefreshFeatureLayersGroup(featureLayersGroupName);
        }
    }            
}
 
public void RefreshFeatureLayersGroup(string featureLayersGroupName)
{
    Validate.NotNullOrEmpty("featureLayersGroupName", featureLayersGroupName);
 
    if (_mapControl.Overlays.Contains(featureLayersGroupName) && !IsRefreshSuppressed)
    {
       _mapControl.Overlays[featureLayersGroupName].Refresh();
    }
}



Some more information:

The large layer is a shape file layer of wells. The layer can be only a few hundred or up to a few hundred thousand points. The layer that currently taking 30 seconds only has a 14000 points.



I have started to come up with a solution as we are very short on time. I was thinking I could break up the total number of points into groups of 500 or 1000 and create a different shape file for each group. Then I would build a manager that would know what layer a point belongs to so the refresh would only be 1 of the layers and not all of them when turning on or off a single feature. This could work for controlling the visibility of a single feature but it would not work for controlling the visibility of the entire group of points. 



The number of points in a shape file could get up to 100,000 so we could have 100 shape file layers for these points. Would loading this many layers into the map be any slower then loading the one shape file with 100,000 points?



I have the same issue in that it can take 10 seconds or more to simply make one layer visible or invisible.  I set the IsVisible property on the Feature Layer to either True or False.



My application has 65 layers, but even if I InVisible most of them or if most are not in the current extent it still takes 10 or so seconds to Visible/InVisible the layer.



One thing to keep in mind is display device size and resolution.  My application is used on 22" and 24" monitors at a high resolution.  The larger the area that the map consumes also determines responsiveness.



So I’m also interested in what can be done to make this faster as my users have brought this to my attention and would like to see the time improved.



Regards,

Dennis



Posted By Scott on 06-19-2015 03:45 PM


Hello, I am trying to hide/show a single feature on a large layer but the refresh of the entire layer takes way too long. It takes up to 30 seconds to refresh the layer after turning off one single point… How can I speed this up?




public void HideFeatureOnLayer(string featureLayersGroupName, string featureLayerName,
                               ObservableCollection<mapfeature> features, bool doRefresh)
{
    Validate.NotNullOrEmpty(“featureLayersGroupName”, featureLayersGroupName);
    Validate.NotNullOrEmpty(“featureLayerName”, featureLayerName);
 
    FeatureLayer featureLayer = GetFeatureLayerByName(featureLayerName);
 
    if (featureLayer != null && featureLayer.FeatureSource != null)
    {
        featureLayer.FeatureSource.FeatureIdsToExclude.Clear();
 
        foreach (MapFeature feature in features)
        {
            featureLayer.FeatureSource.FeatureIdsToExclude.Add(feature.FeatureId);
        }
        featureLayer.FeatureSource.Open();
        if (doRefresh)
        {
            RefreshFeatureLayersGroup(featureLayersGroupName);
        }
    }            
}
 
public void RefreshFeatureLayersGroup(string featureLayersGroupName)
{
    Validate.NotNullOrEmpty(“featureLayersGroupName”, featureLayersGroupName);
 
    if (_mapControl.Overlays.Contains(featureLayersGroupName) && !IsRefreshSuppressed)
    {
       _mapControl.Overlays[featureLayersGroupName].Refresh();
    }
}



Some more information:

The large layer is a shape file layer of wells. The layer can be only a few hundred or up to a few hundred thousand points. The layer that currently taking 30 seconds only has a 14000 points.



I have started to come up with a solution as we are very short on time. I was thinking I could break up the total number of points into groups of 500 or 1000 and create a different shape file for each group. Then I would build a manager that would know what layer a point belongs to so the refresh would only be 1 of the layers and not all of them when turning on or off a single feature. This could work for controlling the visibility of a single feature but it would not work for controlling the visibility of the entire group of points. 



The number of points in a shape file could get up to 100,000 so we could have 100 shape file layers for these points. Would loading this many layers into the map be any slower then loading the one shape file with 100,000 points?


Hi Scott,



Would you let us know how you define the single point shape file layer, which includes 100,000 points? It’s better you can attach more snippets codes here.  As I know if you are using an image point style will more slower than using point Symbol type.



Besides, if the style is not the crime of the performance issue, then would you let us know more about your scenario like how many layerovelayers, any other raster layers etc…?



Thanks



Troy



Posted By Dennis on 06-22-2015 03:49 PM


I have the same issue in that it can take 10 seconds or more to simply make one layer visible or invisible.  I set the IsVisible property on the Feature Layer to either True or False.



My application has 65 layers, but even if I InVisible most of them or if most are not in the current extent it still takes 10 or so seconds to Visible/InVisible the layer.



One thing to keep in mind is display device size and resolution.  My application is used on 22" and 24" monitors at a high resolution.  The larger the area that the map consumes also determines responsiveness.



So I’m also interested in what can be done to make this faster as my users have brought this to my attention and would like to see the time improved.



Regards,

Dennis



Hi Dennis,



Grouping the layers into several LayerOverlay might be one of the options and then only redraw the modified LayerOverlay. Also, we can try to set the DrawingQuality as HighSpeed to see if any helps. Or Try to set the GCCollectionMode as Optimized



As we don’t know more details about your 65 layers, I would suggest we can comment out some of them to make sure if this is because some complex layers take more time to draw, then we can focus on those layers. That would be helpful if you can let us know what are the layers and the layeroverlays.



Thanks,



Troy

Hi Troy, it is a single point on a large shape file. The shape file has 100,000 points and I want to turn the visibility off on one of them. Looking at my code sample I am using the method FeatureIdsToExclude().  
  


Hi Scott, 
  
 I am trying to build a sample to simulate your case, before it is done, would you let me know how you define the point layer style, using point Symbol type or an image? As I know using symbol type, then the performance would be much better. 
  
 Also, can we try to set the DrawingQuality as HighSpeed to see if any helps. Or Try to set the GCCollectionMode as Optimized. 
  
 Besides, based on your scenario, I am guessing if the DrawingFeatures event will help you to improve it? The DrawingFeatures event will be triggered before drawing and in this event, you can except the usefulness features in it.  
  
 Thanks, 
  
 Troy

Hi Troy,thank you for your reply. Yesterday I forgot to include the code for the draw core override on point style. As  you can see below, the point is a character.




public class CustomWellSymbolStyle : PointStyle
{
 
    protected override void DrawCore(IEnumerable<feature> features, GeoCanvas canvas, System.Collections.ObjectModel.Collection<simplecandidate> labelsInThisLayer, System.Collections.ObjectModel.Collection<simplecandidate> labelsInAllLayers)
    {
        GeoFont font = new GeoFont(_fontName, _textTextSize);
        GeoSolidBrush brush = new GeoSolidBrush(_textColor);
        GeoPen geoPen = new GeoPen(_textColor);
 
        List<screenpointf> allScreenPoints = new List<screenpointf>();
 
        foreach (Feature feature in features)
        {
            RectangleShape worldExtent = canvas.CurrentWorldExtent;
            ScreenPointF screenPoint = ExtentHelper.ToScreenCoordinate(worldExtent, feature, canvas.Width,
                                                              canvas.Height);
 
            bool uniquePoint = !allScreenPoints.Contains(screenPoint);
 
            if (uniquePoint)
            {
                allScreenPoints.Add(screenPoint);
                ScreenPointF[] screenPoints = new[] { new ScreenPointF(screenPoint.X, screenPoint.Y) };
                int glyphIndex = ParseGlyphIndex(feature);
 
                canvas.DrawText(string.Format("{0}", (char)glyphIndex), font, brush, geoPen, screenPoints,
                                DrawingLevel.LabelLevel, 0, 0, 0);
            }
        }
    }
}

I am not familiar with the DrawingQuallity or GCCCollection stuff so I will have to look into it. Could you point me to some of your examples implementing these?


Hi Scott,



Thanks for the codes, it gives me more insights. The customWellStyle actually is a text style which is much more slow than a symbol style, this is because in the end, we are using the GdiPlusCanvas to render, and drawText would need more resources than drawline etc…So, the below style will bring a big difference:



            //pointsLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City1;
            pointsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(new CustomWellSymbolStyle());


I created a test sample with your codes and here are my suggestions:


        
  • Comment out the comparison code will speed up 50% with 100,000 points, in my test, with the code, the time is about 46s, without it will take 23s.

  •     

  •     



//bool uniquePoint = !allScreenPoints.Contains(screenPoint);
//if (uniquePoint)
                {
                    allScreenPoints.Add(screenPoint);
                    ScreenPointF[] screenPoints = new[] { new ScreenPointF(screenPoint.X, screenPoint.Y) };
                    canvas.DrawText(string.Format("{0}", (char)index), characterFont, geoBrush, geoPen, screenPoints,
                                    DrawingLevel.LabelLevel, 0, 0, 0);
                }


        
  • I don’t know your case detail, but drawing 100,000 points/labels in one view may be difficult to read and make the map busy. So, I think a good solution is if we can use Cluster point style, with this style, in the high zoom level, a few points will be drawn with a point count label to show how many point is hidden. ZoomIn the map will make the hidden points shown. More detail, please refer to our ClusterPointStyle sample. wiki.thinkgeo.com/wiki/Map_S…PointStyle


Please let us know if any questions.



Thanks,



Troy

sampleTest.zip (8.6 KB)

Thanks Troy, using a point instead of text made a big difference. We ended up using the zoom levels so when we are zoomed in enough we can then display the text with out any unmanageable performance hits. This solves our problem  
  
 Thanks.

Hi Scott,



Sounds great. If any other questions, don’t hesitate to let us know.



Thanks,



Troy