ThinkGeo.com    |     Documentation    |     Premium Support

Refreshing map

I have a real time (ship tracking) application that can track a few hundred ships at once, so performance is all important - I want the users to be able to pan and zoom smoothly while the screen is continually being updated by data being placed into a SQL Server database which MapSuite Desktop Edition reads and puts on the maps.


Previously I was performing the following command:


WinformsMap1.Refresh()


every second (triggered by a timer) but the performance was not good - too much refreshing.

I found that I didn't actually need to do a full refresh but could just do this command:


WinformsMap1.Refresh(DynamicLayerOverlay)


where DynamicLayerOverlay consists of 3 layers:


        DynamicLayerOverlay.Layers.Add("ShipLayer", ShipLayer)

        DynamicLayerOverlay.Layers.Add("TrailLayer", TrailLayer)

        DynamicLayerOverlay.Layers.Add("TrailLayer2", TrailLayer2)


as shown in the screen dump below - ShipLayer is the green ship (actually a helicopter making a delivery to a moving ship in this case!) while TraiLayer is the trail "dots" and TrailLayer2 is the trail "lines"



So, every 1 cycle the WinformsMap1.Refresh(DynamicLayerOverlay) is definitely being called. However, as can be seen in the above screen dump, sometimes the vessel draws as a new shape in the new location but doesn't clear the old vessel. The helicopter landed up in the north west corner of the map but then took off again as can be seen by the trail and the correct location is the one in the south east corner of the map.


Any idea why the refresh isn't working properly? If I just pan the map even a couple of milimetres manually the old, incorrect vessel disappears and the map is as it should be.


I am using MapSuiteCore:5.5.0.91, DesktopEdition:5.5.0.91. I haven't started with V6 yet but haven't seen any indication that this part of the code has been worked on...



Hi David,


I wrote a sample that may be the similar scenario to yours and it works properly,



InMemoryFeatureLayer inm = new InMemoryFeatureLayer();
        LayerOverlay overlay = new LayerOverlay();
        Random ram = new Random();

        public DisplayShapeMap()
        {
            InitializeComponent();
        }

        private void DisplayMap_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
            winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);
            inm.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.CreateSimpleLineStyle(GeoColor.SimpleColors.Blue, 2, false);
            inm.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            overlay.Layers.Add(inm);

            winformsMap1.Overlays.Add(overlay);
            winformsMap1.CurrentExtent = new RectangleShape(-139.2, 92.4, 120.9, -93.2);
            winformsMap1.Refresh();

            Timer timer = new Timer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = 1000;
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            LineShape line = new LineShape(new Vertex[] { new Vertex(ram.Next(-180, 180), ram.Next(-90, 90)), new Vertex(ram.Next(-180, 180), ram.Next(-90, 90)) });
            inm.InternalFeatures.Clear();
            inm.InternalFeatures.Add(new Feature(line));
            winformsMap1.Refresh(overlay);
        }

If my code is different from yours, could you please tell me how you update the layer and refresh the overlay?


Thanks,


Edgar


 



Sorry to be revisiting this problem after so long - been doing other things for the past year but the problem still exists. 
  
 You are using an InMemoryFeatureLayer. 
  
 I am using the following 3 layers in my DynamicOverlay: 
     Dim ShipLayer As MsSql2008FeatureLayer 
     Dim TrailLayer As MsSql2008FeatureLayer 
     Dim TrailLayer2 As MsSql2008FeatureLayer 
 I need to use MsSql2008FeatureLayers as I am getting my data directly from a MSSQL 2008 database. 
  
 The only real difference I can see is that you have this line: 
  
 inm.InternalFeatures.Clear(); 
  
 but it appears that the MsSql2008FeatureLayer doesn’t have the InternalFeatures property to clear…any ideas?  
 Or maybe your test scenario is working ok because it is using a different kind of layer? 
  
  
  
  
  
  


Hi Dave, 



Thanks for your further information, the reason for the old vessel existing on the map is that when you use WinformsMap1.Refresh(DynamicLayerOverlay) all the features in ShipLayer will be drawn. So if there are two records in shipLayer’s corresponding DataTable, and one record is for the old vessel location, another one is for the new vessel location, then both records will be drawn. 



To solve this problem following code should be able to provide a basic idea: 



private void Form_Loaded(object sender, RoutedEventArgs e) 



… 

inm.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = yourShipStyle; 

inm.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; 

DynamicLayerOverlay.Layers.Add(inm); 

 DynamicLayerOverlay.Layers.Add(“TrailLayer”, TrailLayer)

DynamicLayerOverlay.Layers.Add(“TrailLayer2”, TrailLayer2)

// please don’t use DynamicLayerOverlay.Layers.Add(“ShipLayer”, ShipLayer) 

… 





InMemoryFeatureLayer inm = new InMemoryFeatureLayer(); 



void timer_Tick(object sender, EventArgs e) 



Feature VesselLatestLocation = ShipLayer.FeatureSource.GetFeatureById(ShipLayer.FeatureSource.GetCount().ToString(), ReturningColumnsType.NoColumns); 

inm.InternalFeatures.Clear(); 

inm.InternalFeatures.Add(VesselLatestLocation); 

wpfMap1.Refresh(overlay); 





if you have any more question , please feel free to let us know. 



Best Regards 



Summer

I will take a look at the code this evening or tomorrow, but to clarify - there is never more than 1 record per vessel in the SQL Server database - so how would there get to be more than 1 record per vessel in the shipLayer datatable?

Ok, thanks very much - I found that it does appear to solve the problem - there are no more duplicates (but it seems slower to run than before - my cycle time has changed from 0.5 seconds to 0.9 seconds). But it now raises 2 questions: 
  
 1) (already asked above yesterday) If the SQL Server table NEVER has more than 1 record per ship, how does the shipLayer datatable get more than 1 record per ship? 
  
 2) When I clicked on a ship icon (from my MsSql2008FeatureLayer), I had code: 
 Dim selectedFeatures As Collection(Of Feature) = shipLayer.QueryTools.GetFeaturesNearestTo(e.WorldLocation, GeographyUnit.DecimalDegree, 1, ReturningColumnsType.AllColumns) 
 which would select the nearest ship. Now I am using an InMemoryFeatureLayer instead, it appears that GetFeaturesNearestTo isn’t available for this kind of layer? Is there an equivalent?

Hi David, 
  
 From the description I thought your scenario should contains many endpoints, and they will connect to remote SQL server and query frequently. So I think the slow should caused by communication between endpoint and SQL server. 
  
 I have a suggestion about your scenario, you can try to create a windows service and a web service. The windows service read related information from SQL server and save them in server. Endpoint read the latest information via web service and render them in an InMemoryFeatureLayer. 
  
 I think this solution should be helpful for improve performance if your bottleneck is the time connect and query to SQL server. 
  
 Regards, 
  
 Don

The SQL Server is on the same machine as the Desktop Edition of Map Suite - so there is no remote querying done. This slowdown from 0.5 seconds to 0.9 seconds per cycle is just from putting the data into an InMemoryFeatureLayer instead of the MsSql2008FeatureLayer - nothing else was changed. And I haven’t tested it thoroughly by switching between the 2 or turning off all other applications which might affect it - this was just a quick observation as I have a display of Overlay.DrawingTime in my application. 
  
 Definitely I don’t want to modify the whole application which is very large at this late stage to fix a problem which shouldn’t exist - there is only 1 record for each vessel in the SQL Server table.

Hi David, 
  
 Sorry when I reply your post, I haven’t refresh this topic so ignore your reply at 08-28-2013 07:36 PM. 
  
 1. You mention: "If the SQL Server table NEVER has more than 1 record per ship, how does the shipLayer datatable get more than 1 record per ship? " Does this still happen when you test the code provided by Summer? The shipLayer will only contains one record if SQL server table contains 1 record. So please check whether the SQL server only return one point first before you pass the data to InmemoryFeatureLayer. Does the ShipLayer.FeatureSource.GetFeatureById return multiply points when you test, if you are not use it, please tell me how you get the VesselLatestLocation for now. 
  
 2. The InmemoryFeatureLayer also support this function: shipLayer.QueryTools.GetFeaturesNearestTo. 
  
 Regards, 
  
 Don


> 2. The InmemoryFeatureLayer also support this function: shipLayer.QueryTools.GetFeaturesNearestTo.

Hi Don,



Is this something new to V7?



I tried:

Debug.Print(ShipLayer.QueryTools.CanExecuteSqlQuery)

True

Debug.Print(inm.QueryTools.CanExecuteSqlQuery)

False



I haven’t updated to V7 yet - am using MapSuiteCore:6.0.0.135



(I am still trying to figure out how to see if the ShipLayer.FeatureSource.GetFeatureById returns multiple points)

Hi David, 
  
 I tested in 6.0.0.135, this function wasn’t supportted in that version. You can try to update your version for get this feature. 
  
 About the 2nd question, that’s correct, because only ShapeFileFeatureLayer and MsSql2008FeatureLayer return true for CanExecuteSqlQuery property. 
  
 For make sure whether GetFeatureById return multiple points, you can set breakpoint in that line, and see how many points return. 
  
 Regards, 
  
 Don