MapSuite Team,
I’ve discovered that the drawing times on InMemoryFeatureLayer seem excessive.
Attached are two files. One shows the drawing times and one contains the Drawing/Drawn events code.
Some of the InMemoryFeatureLayer’s would have none to very few features so I am surprised that those times appear excessive.
I would think that 12-13 seconds is excessive to draw. What are you thoughts?
Thanks,
Dennis
DrawingAndDrawnEventsMethods.txt (4.15 KB)
DrawingTimesInMemoryFeatureLayer.txt (825 Bytes)
Drawing Times
Hi Dennis,
I did some test and it looks we hadn’t found the inmemoryFeatureLayer can render so long time, I read your code for DrawingAndDrawnEvent, and I think use StopWatch is more simple for it.
Please see the test code as below, you can directly put it into our DisplayASimpleMap sample in HowDoISamples project and here list the test result:
Draw Time0.0331014seconds
Draw Time0.0277741seconds
Draw Time0.04039seconds
Draw Time0.0313161seconds
Draw Time0.0405391seconds
Draw Time0.0313413seconds
Draw Time0.0339042seconds
Draw Time0.0345923seconds
Draw Time0.023835seconds
Draw Time0.0339116seconds
Draw Time0.0190954seconds
Draw Time0.032011seconds
Draw Time0.0474717seconds
Draw Time0.0171855seconds
Draw Time0.0165624seconds
Draw Time0.0172569seconds
Draw Time0.027217seconds
Draw Time0.0758071seconds
using System.Windows;
using System.Windows.Controls;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.WpfDesktopEdition;
namespace CSHowDoISamples
{
public partial class DisplayASimpleMap : UserControl
{
public DisplayASimpleMap()
{
InitializeComponent();
}
private void WpfMap_Loaded(object sender, RoutedEventArgs e)
{
Map1.MapUnit = GeographyUnit.DecimalDegree;
LayerOverlay testOverlay = new LayerOverlay() { TileType = TileType.SingleTile };
testOverlay.Layers.Add(new BackgroundLayer(new GeoSolidBrush(GeoColor.FromArgb(255, 233, 232, 214))));
ShapeFileFeatureLayer utahWaterShapeLayer = new ShapeFileFeatureLayer(@"…\SampleData\Data\UtahWater.shp");
InMemoryFeatureLayer testLayer = new InMemoryFeatureLayer();
testLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Water1;
testLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
utahWaterShapeLayer.Open();
foreach (Feature feature in utahWaterShapeLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.AllColumns))
{
testLayer.InternalFeatures.Add(feature);
}
testOverlay.Layers.Add(“UtahWaterShapes”, testLayer);
testOverlay.Drawing += testOverlay_Drawing;
testOverlay.Drawn += testOverlay_Drawn;
Map1.Overlays.Add(“UtahWaterOverlay”, testOverlay);
Map1.CurrentExtent = new RectangleShape(-113.11473388671875, 41.949816894531253, -111.08226318359375, 40.499621582031253);
Map1.Refresh();
}
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
void testOverlay_Drawn(object sender, DrawnOverlayEventArgs e)
{
stopwatch.Stop();
System.Diagnostics.Debug.WriteLine(“Draw Time” + stopwatch.Elapsed.TotalSeconds + “seconds”);
}
void testOverlay_Drawing(object sender, DrawingOverlayEventArgs e)
{
stopwatch.Restart();
}
}
}
I think that maybe related with what you put into your InmemoryFeatureLayer, if possible please let me know more detail.
Regards,
Don
Don,
Apologies for taking so long to reply as I’ve been consumed with other issues.
I’m not surprised at the drawing times in your sample as it is really a simple static InMemoryFeatureLayer.
My application supports multiple InMemoryFeatureLayer each with their own LayerOverlay. Two of the InMemoryFeatureLayer transact 1-2M updates per 24hours so they are quite active. One of these is used for vehicle tracking so the X/Y of the features are also constantly changing.
One unusual thing I’ve noticed is that the draw-time continues to increase over time. It might start out at 2000ms, but over time can grow to 20000ms.
With so many updates coming in I’ve had to take extra care in invoking LayerOverlay.Refresh(). For example, I only invoke a Refresh if the feature that is being added/updated/deleted is within the current extent. I also only Refresh a half second after an add/update/delete so that multiple Refreshes can be consolidated into one Refresh.
One other issue with this I’ve noticed is that even though any given InMemoryFeatureLayer may have zero features I’m still reporting these long draw times. If there are no or minimal features why would it take so long to draw?
Might there be an issue if a Refresh is invoked and before that Refresh is complete another Refresh is invoked? I’m thinking that maybe I need to synchronize the invocation of Refresh with the LayerOverlay Drawing & Drawn Events.
I’m attempting to find the cause of an “Object Reference Not Set to an Instance of an Object” Exception that is being encountered within WpfDesktopEdition and thinking it is possible that this odd behavior is causing this exception.
A change I made recently based on your suggestion was to invoke only one Open() on an InMemoryFeatureLayer when the application starts and then leave it open for the duration. This has solved the Drawing/Drawn Exceptions that I was getting. Given that there is now only one Open() is there any type of ‘clean-up’ work that has to be done after an add/update/delete of a feature?
Attached are the property settings for the LayerOverlay. Also attached is a code snippet that shows an add.
Your thoughts?
Thanks,
Dennis
TrackingOverlayEntries.txt (1.42 KB)
InMemoryFeatureLayerEditToolsAddSnippet.txt (1.14 KB)
Hi Dennis,
Thanks for your detail description.
In fact the InMemoryFeatureLayer is not a complex layer, its feature source only contains two collections: internalFeatures and columns.
If you want to add/delete/modify features, you only need to handle internalFeatures, but you can also check the columns size to make sure it won’t be added too many items. And please call TrackShapeLayer.BuildIndex to rebuild index once in a while.
If you guess your layer refresh so long time is because when it run long time, some collection is too big, you can try to serialization the empty layer which need refresh 20 seconds to make sure it don’t contains any redundancy data.
BTW, I read the code related BeginTransaction and CommitTransaction, it looks it only handle the feature and rebuild the index. I hadn’t found anywhere it will include bigger size after run long time. Does your code release the TransactionResult after Add/Delete/Edit?
Regards,
Don
Don,
A number of questions/responses for you…
To be more efficient I wanted to change from using EditTools to directly add/delete/update the InternalFeatures. I am successful in using TrackingLayer.InternalFeatures.Add(TheKey, TheFeature) to add a new feature and TrackingLayer.InternalFeatures.Remove(TheKey). However, I cannot find an InternalFeatures Update Method. I am successful at using TrackingLayer.FeatureSource.UpdateFeature(TheBaseShape). Is there a method to update using InternalFeatures?
The InternalFeatures Collection does not continuously grow. Features are added as needed and then are deleted when no longer used. So any one InternalFeatures Collection will typically have less than 1000 Features.
Not all InMemoryFeatureLayer/LayerOverlays have features. Some of them never have any features based on what any given user is currently responsible for. What is odd is that these layers also have draw times, which makes no sense since they have no features. I would think the draw time would always be zero.
I will be adding some logic to periodically invoke BuildIndex. The plan was to invoke BuildIndex at a timed interval after a feature has been either added or deleted. Should a BuildIndex also be run if the position of a feature changes? Since this is building a spatial index I would think so. Since the application receives 2.5 million Tracking Messages per 24 hour period this will be an awful lot of BuildIndex invocations since 70% of those 2.5 million messages are location changed messages. I may not be able to afford all that processing unless maybe do a BuildIndex once every 15-30 minutes, but not sure what that will buy since there are so many position changes. Any thoughts/recommendations on this?
I am not doing anything specifically to release the TransactionResult after its use. It is a local property in a local method. How would you recommend it be released?
Thanks,
Dennis
Hi Dennis,
The following is the responses for you.
#1 How to update the feature in InternalFeatures?
Please try the following to update the feature for InMemoryFeatureLayer:
TrackingLayer.InternalFeatures[index] = newFeature;
#2 Should a BuildIndex also be run if the position of a feature changes?
It’s necessary to rebuild the index when the position of a feature changes or it’ll get the wrong result when it queries the features by using the spatial index.
#3 Build index at a timed interval for InMemoryFeatureLayer
It will rebuild index automatically when call the “CommitTransaction” method, but please try the following steps to work it around.
1. Add a new feature by using InMemoryFeatureLayer.InternalFeatures.Add(key, feature).
2. Delete a feature by using InMemoryFeatureLayer.InternalFeatures.Remove(key).
3. Update feature like the #1.
4. Rebuild index at a timed interval by using CreateIndex();
Hope it’s helped.
Thanks,
Peter
MapSuite Team,
I continue to experience increasing draw times the long the map runs and is used.
In one of your previous responses you asked if I released the TransactionResult after Add/Delete/Edit. I do not release this as did not realize it had to be released. What is the code to release it as I don’t see any methods on the object to do a release?
Does the InternalFeatures collection need to be ‘cleaned up’ in any way every so often.
I now invoke a BuildIndex when the InMemoryFeatureLayer is created. That is the first and only time the BuildIndex is invoked. I want to verify that when a feature changes is X/Y the index will be automatically updated behind the scenes when using EditTools?
Is the index also update behind the scenes when using InternalFeatures?
Thanks,
Dennis
Hi Dennis,
About TransactionResult, I means whether your custom code hold them so they hadn’t been release automatic. You don’t need to manual release them, that’s just my guess, if your code hadn’t hold them please just ignore that.
BuildIndex for InMemoryFeatureLayer is for make it works well, for now, we only call that when we call “clear” or “CommitTransaction”. I think you should want to manual call that each time you modify the data in InMemoryFeatureLayer.
Regards,
Don