ThinkGeo.com    |     Documentation    |     Premium Support

InMemoryFeatureLayer and animated points

I’ve got a collection of InMemoryFeatureLayers representing a moderately large number of points, perhaps ranging from a low of 500 up to 5000.  These are base layers that are basically static and always populated the same from beginning to end of a user session.



Based on various state changes, I need to draw subsets of these points in different ways.  And certain states take precedence over other states.  So assuming a numeric ranking from 1-10 where 10 is the most important, a point that is simultaneously in state 3 and 7 will have state 3 drawn first, with state 7 perhaps obscuring some or all of the representation of state 3.



My first thought was separate layers for each state.  When state changes occur, just add the point feature to the appropriate layer, and let it draw using the normal features of zoomlevels and styles.  This works as far as that goes, but it falls short of the end goals, particularly with animation.  Or would it be better to use the extra overlay layers and add non-point shapes to them as required to represent states, thought that hardly seems any better/easier?  



The main problem thus far is that some of the states must be animated.  

1) One state would be drawn like a simplified sonar depiction with radiating circles like dropping a pebble in a pond.

2) One state would be drawn like a warning beacon in a lighthouse.  Basically a narrow pie wedge that rotates about the center point.

3) Another state represents the current selected (clicked by user) point, most likely by surrounding the point with a simple ring that pulses on and off.



Another important consideration is that some of the point “states” are VERY important and must always be visible.  To reduce the “noise” of closely crowded points, the individual points are not visible when zoomed out.  But important states will be visible even when the point is NOT visible due to zoom level.



Most of your samples are based around city maps, so you could perhaps think of this as if it were an Alarm monitoring company.  Each point representing a customer’s address on a city map (Austin perhaps?).  Nothing fancy, just a smallish colored point shape at each customers location.  If the alarm is on/active, it animates like a short lighthouse beam.  If it the alarm is signaling an emergency, it has the sonar rings.  And, since an alarm signaling an emergency is quite important regardless of zoom level, and unlikely to be so frequent as to be over crowded, it should show up at ALL zoom levels.  



This seems to require override of DrawCore, so now I’m wondering if the best route is to just forget the state layers, and do the drawing in the layers that own the base/static points.  Just custom draw the points.  But that leaves me implementing everything including zoom level handling.  It seems there should be an easier way.  Perhaps deriving a class from PointStyle that is used for each of the “state” layers?  



Does there exist, or can you provide a sample (or post) that will help me sort out the best way to handle this requirement.  The only real custom drawing sample I could find is the DraggedPointStyle that utilizes the EditInteractiveOverlay, something VERY different than what I am trying to accomplish.


Never mind on this, it is simple as I thought it should be.   
  
 The key was overriding DrawCore on a class derived from PointStyle.  I then create a layer in the appropriate order for each state based on it’s importance (so more important draws after/over less important), and use my custom point styles along with an animation timer.  The state layers go in their own overlay so that refresh is not expensive. 
  
 This makes the drawing trivial, and I can still utilize all the zoomlevels and other features.

Hi Russ, 
  
 That’s great you figured it out! Overriding DrawCore method in map suite Layers and Styles is a very common and flexible way to implement some special cases. If you have any questions on accomplishing your case, don’t hesitate to let us know. 
  
 Thanks, 
 Troy

I was able to get this working for the radiating and pulsing circles.  In my custom style DrawCore override, I simply have code like the following. 

  


canvas.DrawEllipse( pointShape, curSize, curSize, pen, brush, DrawingLevel.LabelLevel );

  

This works perfectly.  These are used as status/alert/warning/attention feedback indicators, and one requirement is that these are always the same size regardless of zoom.  So if you are zoomed way out to see everything, and you see a pulsing red dot, you can zoom in closer to see specifics. 



Then I got a new requirement.  For better differentiation, some of these attention symbols should be triangles, stars, etc.  I thought, “no problem”.  But such was not the case… 



For my first attempt I just added the following to the new style. 

 

float offset = curSize / 2;
PointShape center = (PointShape)feature.GetShape( );
PointShape upperLeft = new PointShape( center.X - offset, center.Y + offset );
PointShape lowerRight = new PointShape( center.X + offset, center.Y - offset );
RectangleShape rectangleShape = new RectangleShape( upperLeft, lowerRight );
canvas.DrawArea( rectangleShape, pen, brush, DrawingLevel.LabelLevel );

 

It is also supposed to “pulse”, so “curSize” follows the same logic and values that work for DrawEllipse.  But this code scales with the map scale, and is not acceptable.  How do I get the ability to make this square act the same (same scale independence) as the circle? 



Also, since your code is obfuscated, I can’t see how your code manages PointSymbolType.Square, which works as I desire, otherwise I could find my own answer.  I also can’t seem to find any samples on this (but will look again).  I also need to find information on doing the same scale independent drawing for stars and other shapes for other such custom automated state styles.  Basically, I need the same capability you use for your PointSymbolType rendering, but be able to do it with animate sizes, and (at times) with transparent fill. 


Ok, looks like the answer can be found in your DoughnutPointStyle sample.



So, with a few modifications, the non-scaling drawing code adapts to something like this.


ScreenPointF screenPointF = ExtentHelper.ToScreenCoordinate( canvas.CurrentWorldExtent, feature, canvas.Width, canvas.Height );
 
IEnumerable<ScreenPointF[]> screenPointFs = GetVerticesForASquare(screenPointF, curSize );
 
canvas.DrawArea(screenPointFs, pen, brush, DrawingLevel.LevelFour, this.XOffsetInPixel, this.YOffsetInPixel, PenBrushDrawingOrder.BrushFirst);

GetVerticesForASquare is a bit messy, particularly in the original sample (and any non-trivial implementation), but basically something like a the old "turtle graphics" approach.



Is there a better solution, or am I on the right path?

Hi Russ, 
  
 You way is correct.  
  
 If you want to make points looks different, you should want to override PointStyle, calculate vertexes for target shape then draw them. 
  
 What you need to do is modify the algorithm for calculate target shape so that it works better in your scenario. 
  
 Regards, 
  
 Don 


Yes, that is in my custom style subclassing PointStyle.  It’s working correctly for now, and it’s relatively easy to create other styles as needed.  I was just hoping there was some way to leverage the styles that already exist (star, cross, etc).  The shapes you provide cover everything I need, I just need to animate them to make the pulse/flash/radiate.

Hi Russ, 
  
 I know what you need here, but I am afraid we cannot directly use the render for star/cross etc. 
  
 But you should want to know how we render that, we call canvas.DrawText to draw the special shape, so it in fact is a special character. 
  
 You want to let it pluse/flash/radiate, you can try to draw differernt font size but I think write code to calculate shape should looks better. 
  
 Regards, 
  
 Don

Thank you.  And you are right, I’ll just work out the vertices for whatever we decide to provide.

Hi Russ, 
  
 Thanks for reply, any question please let us know. 
  
 Regards, 
  
 Don