ThinkGeo.com    |     Documentation    |     Premium Support

Updating a subset of features, need help

Based on a suggestion here, I've implemented a custom InMemoryFeatureSource which overrides GetFeaturesForDrawingCore to return a collection of just the features I've changed. Unfortunately, the application then only updates the first N features in the entire collection, not the subset I've changed. I.e. if I have 800 features and have randomly updated 100 of them, only the first 100 in the collection are getting re-drawn. Have I misunderstood how GetFeaturesForDrawingCore is supposed to work? I will have thousands of features and want all of the un-changed features to stay just as they were. Is there a fleshed-out sample that I could use for this?


Janene



    public class HighSpeedInMemoryFeatureSource : ThinkGeo.MapSuite.Core.InMemoryFeatureSource
    {
        private Collection<Feature> dirtyFeatures = null;

        public HighSpeedInMemoryFeatureSource(IEnumerable<FeatureSourceColumn> featureSourceColumns)
            : base(featureSourceColumns)
        {
            this.dirtyFeatures = new Collection<Feature>();
        }

        public HighSpeedInMemoryFeatureSource(IEnumerable<FeatureSourceColumn> featureSourceColumns, IEnumerable<Feature> features)
            : base(featureSourceColumns, features)
        {
            this.dirtyFeatures = new Collection<Feature>();
        }

        public HighSpeedInMemoryFeatureSource(IEnumerable<FeatureSourceColumn> featureSourceColumns, IEnumerable<BaseShape> shapes)
            : base(featureSourceColumns, shapes)
        {
            this.dirtyFeatures = new Collection<Feature>();
        }

        protected override Collection<Feature> GetFeaturesForDrawingCore(RectangleShape boundingBox,
            double screenWidth, double screenHeight, IEnumerable<string> returningColumnNames1)
        {
            if (dirtyFeatures.Count != 0) {
                // Just return all the dirty features. 
                return dirtyFeatures;
            } 
            Collection<Feature> drawingFeatures = new Collection<Feature>();
            foreach (Feature feature in InternalFeatures) {
                drawingFeatures.Add(feature);
            } return drawingFeatures;
        }
        public void addDirtyFeature(Feature dirtyF)
        {
            this.dirtyFeatures.Add(dirtyF);
        }
        public void ClearDirtyFeatures()
        {
            this.dirtyFeatures.Clear();
        }
    }

    public class HighSpeedInMemoryFeatureLayer : InMemoryFeatureLayer
    {
        public HighSpeedInMemoryFeatureLayer()
            : this(new Collection<FeatureSourceColumn>())
        {
        }

        public HighSpeedInMemoryFeatureLayer(IEnumerable<FeatureSourceColumn> featureSourceColumns)
        {
            // Create our new improved feature source and set it.
            this.FeatureSource = new HighSpeedInMemoryFeatureSource(featureSourceColumns);
        }
        public HighSpeedInMemoryFeatureLayer(HighSpeedInMemoryFeatureSource source)
        {
            // Create our new improved feature source and set it.
            this.FeatureSource = source;
        }
    }




Janene,


Thanks for your code. I think you are basically right for your purpose while it is really hard to make it work somehow in this way.
 
I have discussed with Sun who worked on the following post:
gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/21/aft/6047/afv/topic/afpgj/1/Default.aspx#10032
 
Here I just want to make sure your requirements with my opinions.
 
The target changed features are fixed or random? In your description, it seems random.
For example, we have 10 thousands of features and only 3 of them (feature 1st, feature 3rd, and feature 1001st) need to be updated for its changes, next time , another 3 features need to be changed , it is still the 3 features(feature 1st, feature 3rd, and feature 1001st) or not?
 
If it is changeable, can you explain the logic for this? If it is really randomly, it is really hard only redraw those 3 features, because the other 9997 features also need to be drawn.
 
I know that if it is fixed, somehow it is easy because we just need to redraw the 3 features as a new bitmap on top of a base map which is composed of the other 9997 features.
 
If I am not clear enough please feel free to let me know.
 
Thanks.
 
Yale

Hi Yale, thanks for your reply. 
  
 The features to be updated will move throughout all of the feature set. Each feature will eventually be updated over the course of 250 msecs. Basically, I’ll have several thousand features with updates coming in groups for subsets every 250 msec. As the updates come in, I want to redraw the features that have changed. They will be geographically close so I could do updates for features within a bounding box if that’s faster. 
  
 I’m trying to keep up with the incoming data updates for many thousands of points and re-drawing the entire feature set every 250 msec is not keeping up, hence trying subsets.  
  
 If this isn’t clear enough, please let me know. Thanks! 
  
 Janene

Janene,


Attachment contains a demo shows my idea for your requirement.
 
Basically, my idea is cached the original bitmap as base bitmap, then only draw those dirty features on top of it.
 
If those dirty features longitude & latitude was update very large, for example, it was moved from upper left corner of MapControl to lower right Conner, then it was not suitable.
 
Any more questions feel free to let me know.
 
Thanks.
 
Yale
 

1114-Post_Demo.zip (12.3 KB)

Hi Yale,


I can't run your attached project as the version of the DesktopEdition you reference has a "MapFocusMode" that my eval version does not have. If there is an updated release I can get, that would be great.


Janene



I tried copying the new layer and source classes into my project and the program throws an except when creating the new Bitmap (line 64, according to my editor). The bitmap is huge: 65645 x 17452. The canvas is 1500x931 and I've set the layers to be drawing quality of highSpeed, not highQuality. 


I'm beginning to think the map is simply not going to work for my application. If you have another idea, please let me know. 


Thanks.


Janene McCrillis


Wireless Seismic


 



Posted By Janene on 08-28-2009 09:58 AM 

Hi Yale,


I can’t run your attached project as the version of the DesktopEdition you reference has a “MapFocusMode” that my eval version does not have. If there is an updated release I can get, that would be great.


Janene



Janene,
 
Sorry for the misunderstanding up to now. In version 3.0.362, you just copy the line of Setting MapFocusMode in InitializeComponent and it should work.
 
The update version just fixed some minor mistakes, and we are now on the way of next public release.
 
Any more questions please feel free to let me know.
 
Thanks.
 
Yale





 



Posted By Janene on 08-28-2009 01:32 PM 

I tried copying the new layer and source classes into my project and the program throws an except when creating the new Bitmap (line 64, according to my editor). The bitmap is huge: 65645 x 17452. The canvas is 1500x931 and I’ve set the layers to be drawing quality of highSpeed, not highQuality.


I’m beginning to think the map is simply not going to work for my application. If you have another idea, please let me know.


Thanks.


Janene McCrillis


Wireless Seismic


 



Janene,
 
May I know why your cached bitmap for the screen is so huge? What is the width and height for your MapControl? Are you using the screen monitor with default resolution?
 
Any more information would be appreciated.
 
Thanks.
 
Yale
 





 



Hi Yale, 
  
 My screen resolution is 1680x1050, 32-bit color. It’s a wide-screen monitor, which is what our users will be utilizing. I put the map size in my message before, 1500x931.  
  
 Let me know if you have further questions or suggestions. Thanks. 
  
 Janene

Janene, 
  
 There must be something wrong; the bitmap size should be exactly same with your map control (1680 * 1050 if docked). 
  
 Could you describe the main difference between your applications with the demo posted above? 
  
 In the sample, I have 400 points, then I only want to update the middle 4 points of them, I think it should be very similar with your description. 
  
 Any more questions please feel free to let me know. 
  
 Thanks. 
  
 Yale 


Hi Yale,



I debugged the issue and it was a problem with the function calculating the extent of the changed features returning a rectangle far too large. I've changed it to the following:




        public RectangleShape GetDirtyFeaturesExtent()
        {
            RectangleShape rectangleShape = new RectangleShape();
            if (dirtyFeatures.Count != 0)
                rectangleShape = ExtentHelper.GetBoundingBoxOfItems(dirtyFeatures);
            return rectangleShape;
        }
 

I have this running now. As it continues to update the points and each of the features eventually gets an update,the display slows down, probably because the list of dirty points becomes the entire set of 1600. I've tried clearing out the dirtyFeatures collection after each re-draw, but the DrawCore method then misses the updates and nothing is drawn. 



Another issue I saw with this is that, if the new shape doesn't completely cover the old one, then both shapes are on the display, the new one hiding only some of the original.



Janene

 



Janene, 
  
 I think now we are on the same pace.  
  
 Yes, I agree that this algorithm should only be very efficient if only a small portion of data among a huge data need to be updated. 
  
 For example, I have 10,000 records, while I need to update 10 of them. 
  
 Besides, as you said, this tricky way can only be suitable that the area of target updated data (old & new) only takes up a small portion of whole data. 
  
 Any more questions please feel free to let me know. 
 Thanks. 
  
 Yale