ThinkGeo.com    |     Documentation    |     Premium Support

InMemoryFeatureLayer - LayerOverlay Refresh Issue

I am using an InMemoryFeatureLayer to dynamically display features based on Lat/Long position.


For the sake of CPU efficiency a Refresh of the associated LayerOverlay is only invoked if the currently visible Map Extent is affected.  In other words, if the update occurs out-of-view a Refresh is not done.


Because a Refresh is not performed on each Feature Update the Features are not displayed properly when the map is panned.


If the feature is within the current extent and then its Latitude is reduced outside the current extent then the feature no longer appears on the map, which is correct.  As the Latitude of this feature continues to decrease it stays out-of-view, which is still correct.  At this point if the map is panned the feature comes into view not once, but rather twice.  The icons representing the feature correspond to the very first position where the feature went out-of-view and the last position of the feature before panning.  (The first time a feature goes out-of-view a LayerOverlay Refresh is invoked since the icon should no longer appear in the current extent.)


One solution is to always Refresh the LayerOverlay, but with large numbers of dynamic features this will run the CPU at unacceptably high levels.


It seems that sometimes when the Latitude increases causing the feature to move out-of-view, followed by several move Latitude increases, followed by panning only one icon is present and it is in the proper position.  But not always.  Sometimes it exhibits the same symptoms as when the latitude of the feature decreases.


If a zoom-out is performed the feature is properly positioned and represented due to the fact that zoom by itself causes a LayerOverlay Refresh.


Since the out-of-view icons are positioned at the first out-of-view position and the last out-of-view position (but not inbetween first and last) that some background task of MapSuite is not doing a repaint upon start of panning.  It is painting the icon at the last out-of-view position, but not the one at the first out-of-view position.


What can be done to ensure that the icons representing features are displayed and positioned correctly upon panning into view?


Any suggestions and/or assistance is appreciated.


Regards,


Dennis


 


 



Dennis,  this is an interesting question which contains a lot of info.  To help you further with this, break it down into smaller steps which can be reproduced. 



So far, what I have gathered is the following: 



1. You have an InMemoryFeatureLayer added to the LayerOverlay. 

2. You add Features to the InternalFeatures collection of the feature layer. 

3. Somehow, the positions of these features within the collection change.   

Now, what is not clear here is how you do this given that features are immutable?   Is this where the problem lies? 

4. You refresh map but conditionally render features based on the map's current extent?   Are you using a custom style for this or are you hooking up to the DrawingFeatures event of the layer?  Could the problem lie here? 



I am suspecting that when the latitude of your feature changes, the previous version of this feature is not removed from the feature collection.   You could also use a very small number of points to proof concept, as it will also be easy to reproduce if there is indeed a problem.



Dennis, 
  
 In addition to the suggestions Klaus has made can I ask how many points are you dealing with? 
  
 Have you looked at the "Refresh Points Randomly" sample application under the "Dynamic Shapes" section of the How Do I Samples?  The reason I ask is this sample refreshes 2000 points on the map very quickly with very low CPU usage.  Can you take a look at that sample and see if it is doing something different than your code and let us know if this performance is acceptable for your requirements? 
  
 Thanks! 
  


Klaus & Clint,


Thank you both for responding.  Let me see if I can provide answers for both of you and a further explanation of my concerns.


The InMemoryFeatureLayer is used to track vehicle movement in real-time based on Lat/Long.  I used the MovingVehiceWithChangingLabel and DetectGPSDesktop as examples.  I used RefreshPointsRandomly as a further reference.


Here are answers to Klaus's questions:


1. You have an InMemoryFeatureLayer added to the LayerOverlay.  Yes.

2. You add Features to the InternalFeatures collection of the feature layer. Yes.

3. Somehow, the positions of these features within the collection change. The position within the collection does not change, except when a feature is added or removed.

Now, what is not clear here is how you do this given that features are immutable? Is this where the problem lies? I don't believe so.  It is not the feature itself per se that changes, but rather its x/y position on the map.

4. You refresh map but conditionally render features based on the map's current extent?  If the new position(x/y) of the feature, or the current position(x/y) of the feature, is within the CurrentExtent then a LayerOverlay Refresh is invoked.


Are you using a custom style for this or are you hooking up to the DrawingFeatures event of the layer? I use a CustomStyle that is a collection of ValueStyle's.  Could the problem lie here?  I don't believe so.





I am suspecting that when the latitude of your feature changes, the previous version of this feature is not removed from the feature collection.  The feature is not removed when the position, X/Y, changes. But rather the PointShape of the Feature is updated to reflect the new X/Y by using the Update Method of EditTools.


My concern at this point is not so much CPU, but rather that when the map is panned and the feature comes into view there are two representations on the map of that one feature.  The two representations of the feature that appear correspond to the first out-of-view(extent) and the last out-of-view(extent) positions.  There can be many position changes that occur out-of-view and still the only ones that appear upon panning are the very first and very last.


 


Let me give you my work-around solution and that might make it clearer as to what I am attempting to explain: Right now the LayerOverlay is Refreshed if either the new position of the feature or the current position of the feature is within the CurrentExtent.  The solution is to actually do a Refresh not just the first time that a feature goes out-of-view, but a second time that the feature is out-of-view. This actually solves the problem so that when the map is panned only one representation, and indeed at the correct X/Y, is shown on the map.


 


If possible I would like to do away with the second out-of-view refresh.  Do you feel in any way that this might be an issue with the internals of MapSuite?


 


Regards,


Dennis


 


 


 


 



Hi Dennis, 
  
  Could you try to remove the Feature from the collection and add a new one with the latest lat/long instead of update it with EditTools as proposed by Klaus? I’m guessing it will solve your problem without need of second Refresh. In addition it turns out that this method is faster than updating the Feature position. 
  
 Carlos.

Dennis, 
  
 If the idea of Carlos and Klaus to delete and re add the feature doesn’t work for you, can you provide a small sample to show what you are seeing?  I’m sure we could get to the bottom of it once we had some code to look at. 
  
 Thanks! 


Thank you all again for your help.


I've done some experimenting as suggested.


I changed the code to delete/add the feature instead of update the position of the feature.  I found that delete/add actually takes more CPU than an update.  The delete/add method took a consistent 5% of the CPU, which includes a Refresh.  The update method took anywhere from 3% to 5% of the CPU, which includes a Refresh.


The delete/add method also did not alleviate my original problem.  I still end up with two representations of the feature on the map after a pan.


Attached is a file with code that shows how the InMemoryFeatureLayer is instantiated, how a new feature is added, and how an existing feature has its position updated.


I also have a Word document which has some screen captures that show the sequence of events that end up with two representations of the feature on the map.  That file is too large to upload.  If you have a email address I will send it to you that way.


Regards,


Dennis


 



Dennis, 
  
 You can either zip up the word document and attach it to the forums or send it via email to forumsupport@thinkgeo.com
  
 Thanks!

Dennis, 
  
 Also what % of the CPU are you expecting this operation to take?

Dennis, 
  
 Thanks for the code and the word document.  After reviewing everything I have a couple things you can try out. 
  
 1.  I see when you initially add the feature you are using the InternalFeatures collection, while this is ok I would recommend you use the EditTools instead to be consistent when we do the updating later on.  I have seen some weird behavior when features are added outside of the EditTools and then you use the Edit Tools to update them. 
  
 So what I would recommend is changing this line of code from: 
  
 this.TrackingLayer.InternalFeatures.Add(oTracking.sKey, myFeature); 
  
 to  
  
                 this.TrackingLayer.EditTools.BeginTransaction(); 
                 myFeature.ID = oTracking.sKey; 
                 this.TrackingLayer.EditTools.Add(myFeature); 
                  
                 //You can then check the Result of the Commit to make sure everything suceeded if you want too. 
                 myTranResult = this.TrackingLayer.EditTools.CommitTransaction(); 
  
 2).  On your code where you update the location can you use the following code: 
  
           this.TrackingLayer.EditTools.BeginTransaction(); 
           this.TrackingLayer.EditTools.Update(oTracking.ItemPoint); 
         //You can then check the Result of the Commit to make sure everything suceeded if you want too. 
            myTranResult = this.TrackingLayer.EditTools.CommitTransaction(); 
  
  
 Hope this helps. 
  
 Thanks! 


Dennis, 
  
   One thing to consider as well is the index to the InMemoryFeatureaLayer.  After you initially add the features to the internal feature collection do you call InMemoryFeatureLayer.BuildIndex?  This will build a spatial index in memeory and make things much more efficient.  Next we need to consider when you modify the layer as that will affect the index.  If you modify the items through the .InternalFeatures collection then you need to call the BuildIndex again.  The building of the index can take some time and there is a better way.  As Clint discussed above if, after you use the BuildIndex the first time, use the EditTools and transactions they will update the index in a much more efficient way.  In this way you would not then ever need to touch the InternalFeatures collection. 
  
 David

Clint,


I'd like to see an average of 3-5% CPU and peeks of 10-15% in production.


Thanks for your suggestions on the code changes.  Unfortunately they did not work.  Specifically, changing the Add of a feature using EditTools instead of InternalFeatures always results in two representations of the feature on the map after panning the features back into view as I have previously described.


Dennis


 


 



Dennis, 



Thanks for the reply.   



It seems strange that there are two representation on the map, can you verify that the ID's are the same when you are doing the update.  Also what does the transaction result say after the commit?  Does it show that it successfully updated the feature?   



One last question, what is the CPU usage you are currently seeing in your application? 



Thanks! 



Clint,

I have verified that the layer has only one feature, but there are two representations on the map. This indicates to me some type of redraw issue.

The CPU is at 5% to refresh on feature, whether that feature is in the CurrentExtent or not.

Dennis

Thanks Dennis, is there anyway you can zip up a small sell contained sample project that will run and show the issue?  We can’t seem to recreate the same behavior here and your code looks fine.  If we have a sample app where we can recreate it, we will be able to get to the bottom of it very quickly. 
  
 If you want you can email the sample to forumsupport@thinkgeo.com
  
 Thanks!