Best practices for using dynamic display


Summary
This topic shows the best practices when using dynamic display in the ArcGIS framework. It introduces current usages and requirements, demonstrates several different approaches to the dynamic display of information in a geographic information system (GIS), and uses several references available in the ArcObjects software development kit (SDK).


Using the dynamic display to enable the dynamic map

Enable the dynamic map using the IDynamicMap interface that is implemented by the Map class. Use IDynamicMap to enable or disable the dynamic map (the dynamic display). See the following illustration:
 
See the following code example for enabling the dynamic map:
[C#]
//Cast the dynamic map from the focus map.
IDynamicMap dynamicMap = m_hookHelper.FocusMap as IDynamicMap;
//Switch into dynamic mode.
if (!dynamicMap.DynamicMapEnabled)
    dynamicMap.DynamicMapEnabled = true;
[VB.NET]
' Cast the dynamic map from the focus map.
Dim dynamicMap As IDynamicMap = CType(m_hookHelper.FocusMap, IDynamicMap)
' Switch into dynamic mode.
If (Not dynamicMap.DynamicMapEnabled) Then
    dynamicMap.DynamicMapEnabled = True
End If
When enabled, the dynamic display is creating an OpenGL rendering context to draw the basic map layers and on top of the base layers, draws the dynamic layers. When the dynamic map is enabled, this is considered as being in dynamic drawing mode.

Drawing in dynamic mode

The following are the two methods to draw in dynamic mode:

Drawing options

The following are the two options for drawing:
  • Using dynamic display application programming interface (API)
  • Direct OpenGL API
By default, OpenGL textures are enabled. It is required to disable the OpenGL 2D texture flag when drawing OpenGL primitives.

Drawing marker symbols using the dynamic display API

The following code example shows how to draw a marker symbol using the dynamic display API:
[C#]
//Set the marker symbol.
m_dynamicSymbolProps.set_DynamicGlyph(esriDynamicSymbolType.esriDSymbolMarker,
    m_markerGlyphs[2]);

//Draw a marker symbol.
DynamicDisplay.DrawMarker(m_point);
[VB.NET]
'Set the marker symbol.
m_dynamicSymbolProps.DynamicGlyph(esriDynamicSymbolType.esriDSymbolMarker) = m_markerGlyphs(2)

'Draw a marker symbol.
DynamicDisplay.DrawMarker(m_point)
In the following code example, drawing is done using a compound marker symbol using the dynamic display API:
[C#]
//Draw the item as a compound marker. This means that you do not have to draw the items and its
//accompanying labels separately, thus allowing you to write less code and better set
//the marker symbol.
m_dynamicSymbolProps.set_DynamicGlyph(esriDynamicSymbolType.esriDSymbolMarker,
    m_markerGlyphs[2]);

//Drawing a compound marker symbol using six strings.
m_dynamicCompoundMarker.DrawCompoundMarker6(m_point, "TOP", "BOTTOM", "Item " +
    Convert.ToString(r[0]), heading.ToString("###.##"), m_point.X.ToString(
    "###.#####"), m_point.Y.ToString("###.#####"));
[VB.NET]
'Draw the item as a compound marker. This means that you do not have to draw the items and its
'accompanying labels separately, thus allowing you to write less code and better set
'the marker symbol.
m_dynamicSymbolProps.DynamicGlyph(esriDynamicSymbolType.esriDSymbolMarker) = m_markerGlyphs(2)

'Drawing a compound marker symbol using six strings.
m_dynamicCompoundMarker.DrawCompoundMarker6
(m_point,
"TOP",
"BOTTOM",
"Item " & Convert.ToString(r(0)),
heading.ToString("###.##"),
m_point.X.ToString("###.#####"), m_point.Y.ToString("###.#####"))

Direct OpenGL API

If using the direct OpenGL API, the coordinate system's origin is the center of the window while the width and height are identical to the device frame dimensions. See the following code example:
 
[C#]
GL.glDisable(GL.GL_TEXTURE_2D);
GL.glPushMatrix();
GL.glLoadIdentity();

// Draw a simple point.
GL.glBegin(GL.GL_POINTS);
GL.glColor3f(1.0f, 1.0f, 0.0f); //Yellow
GL.glVertex2f((float)x, (float)y);
GL.glEnd();

GL.glPopMatrix();
GL.glEnable(GL.GL_TEXTURE_2D);
[VB.NET]
GL.glDisable(GL.GL_TEXTURE_2D)
GL.glPushMatrix()
GL.glLoadIdentity()

' Draw a simple point.
GL.glBegin(GL.GL_POINTS)
GL.glColor3f(1.0F, 1.0F, 0.0F)
GL.glVertex2f(CType(x, Single), CType(y, Single))
GL.glEnd()

GL.glPopMatrix()
GL.glEnable(GL.GL_TEXTURE_2D)
See How to draw a bitmap element using OpenGL for more information on drawing direct OpenGL using textured geometries.

Dynamic layers

A dynamic layer is a custom layer. To implement a custom layer, you need to, at a minimum, implement the ILayer interface. Implementing the ILayer interface enables the layer to be added to the map and the table of contents. To implement a dynamic layer, the custom layer needs to implement IDyamicLayer. The custom dynamic layer needs to implement the methods in the following table:
 
Method
DrawDynamicLayer
Draws the layer to the specified display for the given draw phase.
Read/write property
Indicates if the dynamic layer has changed since last drawn for the specified draw phase.
Read-only property
Recompile Rate is the interval in milliseconds by which the dynamic layer draw method will be called, with the compiled draw phase.
 
The dynamic display is an active display, which means it has a fixed drawing cycle. During every drawing cycle, the dynamic display checks each dynamic layer's dirty property. If at least one of the dynamic layers is dirty, the dynamic display redraws all dynamic layers.

Drawing a dynamic layer

A dynamic layer has the following two primary draw phases:
  • Immediate—Does not store draw commands. The draw commands of the immediate draw phase are immediately drawn.
  • Compiled—Stores draw commands in a list. Dynamic display uses this list to draw the commands. The list is recreated when the dirty flag has been set.
When redrawing the display, the dynamic display iterates through the dynamic layers and does the following for each:
  • Checks if recompile is needed by checking the DynamicLayerDirty with the immediate phase. If any dynamic layer has set the dirty flag for the immediate phase, all dynamic layers DrawDynamicLayer method will be called with the immediate draw phase.
  • Draws the immediate phase and calls the DrawDynamicLayer method with the immediate phase.
  • Checks if recompile is needed by checking the DynamicLayerDirty (with the compiled phase) and the DynamicRecompileRate property.
  • If needed, recompiles the dynamic layer by calling the DrawDynamicLayer method with the compiled phase.
  • Draws the compiled phase by drawing the display list.
The following code example shows how to draw a dynamic layer in immediate mode:
 
[C#]
/// <summary>
/// The dynamic layer draw method.
/// </summary>
/// <param name="DynamicDrawPhase">The current draw phase of the dynamic drawing.</param>
/// <param name="Display">The ActiveView's display.</param>
/// <param name="DynamicDisplay">The ActiveView's dynamic display.</param>
public void DrawDynamicLayer(ESRI.ArcGIS.Display.esriDynamicDrawPhase
    DynamicDrawPhase, ESRI.ArcGIS.Display.IDisplay Display,
    ESRI.ArcGIS.Display.IDynamicDisplay DynamicDisplay)
{
    //Make sure the current draw phase is immediate. In this example, there is no use of the
    //compiled draw phase. Use the esriDDPCompiled draw phase to draw semi-static items (items
    //whose update rate is lower than the display update rate).
    if (esriDynamicDrawPhase.esriDDPImmediate != DynamicDrawPhase)
        return ;

    //Actual drawing to take place here.          

    //Set the dirty flag to true to let the dynamic display that the layer needs to be redrawn.
    base.m_bIsImmediateDirty = true;
}
[VB.NET]
''' <summary>
''' The dynamic layer draw method.
''' </summary>
''' <param name="DynamicDrawPhase">The current draw phase of the dynamic drawing.</param>
''' <param name="Display">The ActiveView's display.</param>
''' <param name="DynamicDisplay">The ActiveView's dynamic display.</param>
Public Overrides Sub DrawDynamicLayer(ByVal DynamicDrawPhase As ESRI.ArcGIS.Display.esriDynamicDrawPhase, ByVal Display As ESRI.ArcGIS.Display.IDisplay, ByVal DynamicDisplay As ESRI.ArcGIS.Display.IDynamicDisplay)

'Make sure the current draw phase is immediate. In this example, there is no use of the
'compiled draw phase. Use the esriDDPCompiled draw phase in to draw semi-static items (items
'whose update rate is lower than the display update rate).
If esriDynamicDrawPhase.esriDDPImmediate <> DynamicDrawPhase Then
    Return
End If

'Actual drawing to take place here.

'Set the dirty flag to true to let the dynamic display that the layer needs to be redrawn.
m_bIsImmediateDirty = True
End Sub
A layer recompiles (in compiled phase) when any refresh events or when the following conditions are met:
  • DynamicLayerDirty property is set to true
  • DynamicRecompileRate time from the previous recompile time has elapsed
 
The layer's DrawDynamicLayer method is called with the following:
  • Compiled phase—When the layer needs to be recompiled
  • Immediate phase—When the layer needs to be redrawn
When redrawing the compiled phase of a dynamic layer, it is not necessary to call its DrawDynamicLayer method but only redraw the already compiled list. The DrawDynamicLayer method (of the compiled phase) is only called when needed to recompile; however, when redrawing the immediate phase of a layer, the DrawDynamicLayer method (of the immediate phase) is being called.

Draw cycle sequence (including DynamicMapEvents)

There are two DynamicMapEvents methods that can be used to draw objects. The two draw phases are esriDMDPLayers and esriDMDPDynamicLayers. During every draw cycle, the layers are drawn and the dynamic map events are fired in the following sequence:
  1. BeforeDynamicDraw(esriDMDPLayers) event is being fired
  2. Layers are drawn; these are the layers that do not support IDynamicLayers (static layers)
  3. AfterDynamicDraw(esriDMDPLayers) event is fired
  4. BeforeDynamicDraw(esriDMDPDynamicLayers) event is fired
  5. Dynamic layers are drawn
  6. Immediate phase (esriDDPImmediate)
  7. Compiled phase (esriDDPCompiled)
  8. AfterDynamicDraw(esriDMDPDynamicLayers) event is fired
See the following illustration:
The following code example shows how to draw in the AfterDynamicDraw on top of the dynamic layers:
[C#]
//Wire the DynamicMap after draw events.
((IDynamicMapEvents_Event)m_dynamicMap).AfterDynamicDraw += new
    IDynamicMapEvents_AfterDynamicDrawEventHandler(OnAfterDynamicDraw);

/// <summary>
/// DynamicMap AfterDynamicDraw event handler method.
/// </summary>
/// <param name="DynamicMapDrawPhase"></param>
/// <param name="Display"></param>
/// <param name="dynamicDisplay"></param>
void OnAfterDynamicDraw(esriDynamicMapDrawPhase DynamicMapDrawPhase, IDisplay
    Display, IDynamicDisplay dynamicDisplay)
{
    if (esriDynamicMapDrawPhase.esriDMDPDynamicLayers != DynamicMapDrawPhase)
        return ;

    //Do the drawings in here.
}
[VB.NET]
'Wire the DynamicMap after draw events.
AddHandler (CType(m_dynamicMap, IDynamicMapEvents_Event)).AfterDynamicDraw, AddressOf OnAfterDynamicDraw

''' <summary>
''' DynamicMap AfterDynamicDraw event handler method.
''' </summary>
''' <param name="DynamicMapDrawPhase"></param>
''' <param name="Display"></param>
''' <param name="dynamicDisplay"></param>

Private Sub OnAfterDynamicDraw(ByVal DynamicMapDrawPhase As esriDynamicMapDrawPhase, ByVal Display As IDisplay, ByVal dynamicDisplay As IDynamicDisplay)
    
    'Make sure the display is valid and that the layer is visible.
    If Nothing Is dynamicDisplay OrElse Nothing Is Display Then
        Return
    End If
    
    'Do the drawings in here.
    
End Sub

Drawing objects API

The dynamic display has the following methods for drawing into the OpenGL rendering context:
  • IDynamicLayer.DrawDynamicLayer
  • IDynamicMapEvents.BeforeDynamicDraw
  • IDynamicMapEvents.AfterDynamicDraw
In these methods, you can draw using the OpenGL API or the dynamic display draw methods:  
  • Use the IDynamicDisplay interface to draw objects in map coordinates. Use the IDynamicCompoundMarkerSymbol interface as an additional option for drawing character marker symbols with surrounding attribute text.
  • Use the IDynamicScreenDisplay interface to draw objects in screen coordinates. This origin uses the DisplayTransformation.DeviceFrame. In this case, it uses the upper left of the screen.
  • Use the IDynamicGlyphFactory interface to create and delete dynamic glyphs. To get the interface to IDynamicGlyphFactory, use IDynamicDisplay. 
  • Use the IDynamicSymbolProperties interface to control the dynamic symbols properties (dynamic marker, line, text, and fill). 
  • Use the IDynamicGlyph interface to access properties of dynamic glyphs. A dynamic glyph is a handle to a resource. 
  • Use the IDynamicMap interface to set the IDynamicMap.UseSubPixelRendering property. 

Working with dynamic symbols

Dynamic symbols are used to draw objects that update dynamically. Dynamic symbols consist of marker, line, text, and fill properties that can be managed using the IDynamicSymbolProperties interface. The following table indicates the properties of each symbol component:
 
 
Marker
Line
Text
Fill
DynamicGlyph
v
v
v
 
Color
v
v
v
v
Heading
v
 
v
 
Smooth
v
v
v
 
Scale
v
v
v
 
Rotational alignment
v
 
v
 
Vertical alignment
 
 
v
 
Horizontal alignment
 
 
v
 
 
  • Symbol is a state of drawing:
    • Controls the symbol through IDynamicSymbolProperties
  • Needs to be synthesized through DynamicGlyph:
    • DynamicGlyph provides resource for symbol
  • DynamicSymbol types:
    • esriDSymbolMarker
    • esriDSymbolLine
    • esriDSymbolText
    • esriDSymbolFill
  • DynamicGlyph types:
    • esriDGlyphMarker
    • esriDGlyphLine
    • esriDGlyphText
 
Before drawing a symbol, set the DynamicSymbolProperties by doing the following :
  • Get IDynamicGlyphFactory from the DynamicDisplay
  • Create marker
  • Load from bitmap (BMP)
  • PictureMarker.CreateFromFile
  • Create line
  • Create text
See the following table:
 
Read/write property
Indicates the dynamic glyph for the specified dynamic symbol.
Method
Indicates the color for the specified dynamic symbol.
Method
Scales the dynamic symbol.
Read/write property
Indicates the heading for the specified dynamic symbol. Only valid if dynamic symbol rotation alignment is a heading and for text and marker.
Read/write property
Indicates the rotation alignment for the specified dynamic symbol. Only valid for text and marker.
Method
Indicates the color for the specified dynamic symbol.
Method
Scales the dynamic symbol.
Read/write property
Indicates whether the specified dynamic symbol will be smooth. Only valid for text, line, and marker.
Read/write property
Indicates the horizontal alignment for the text dynamic symbol.
Read/write property
Indicates the vertical alignment for the text dynamic symbol.

Dynamic glyph factory

The DynamicGlyphFactory is the engine used to create and delete glyphs used by the DynamicDisplaySymbol. The following are the definitions of a glyph:
  • Image of a typographical sign
  • Image used in the visual representation of characters; how a character looks. A font is a set of glyphs
  • A single unit of display in a font (Microsoft). It can be defined by the following:
    • Outline (in OpenType)
    • Bitmap
    • Set of graphic commands
  • DynamicGlyph:
    • Glyph used in the dynamic display environment
  • Handle of the resource for rendering dynamic symbols
See the following table:
 
Method
Creates a dynamic glyph from a symbol.
Method 
Creates a dynamic glyph from a file.
Method 
Deletes a dynamic glyph from a symbol.
Read-only property 
Retrieves a dynamic glyph from a glyph group.
Method 
Initializes the dynamic glyph factory.
Method 
Loads an external dynamic glyph group from
a file.
Method 
Unloads an external dynamic glyph group from
a file.

General guidelines for drawing dynamic layers

Use the compiled phase for drawing most layers. In the compiled phase, do not create dynamic glyphs or textures. Use the immediate phase to create dynamic glyphs and textures, for example, if you have one layer with many features that update every 20 seconds. In this case, redraw this in the compiled phase. If you have a layer you need to update at subsecond rates, draw it in the immediate phase.
When creating a dynamic glyph from text or a dynamic marker, remember that when dynamic display is enabled, what was once white becomes the color you choose. If created with a color, that color becomes darker when enabled; however, black remains black.
When drawing the dynamic layer using the DrawDynamicLayer method or when listening to DynamicMapEvents, initially cache (keep it as a class member) the DynamicGlyphFactory, the DynamicSymbolProperties, and the DynamicCompoundMarker. This is an efficient method considering the repetition of draw cycle sequences.
 
See the following code example:
 
[C#]
public override void DrawDynamicLayer(ESRI.ArcGIS.Display.esriDynamicDrawPhase
    DynamicDrawPhase, ESRI.ArcGIS.Display.IDisplay Display,
    ESRI.ArcGIS.Display.IDynamicDisplay DynamicDisplay)
{
    ... if (m_bOnce)
    {
        //Cast the dynamic display into dynamic glyph factory.
        m_dynamicGlyphFactory = DynamicDisplay.DynamicGlyphFactory;
        //Cast the dynamic display into dynamic symbol properties.
        m_dynamicSymbolProps = DynamicDisplay as IDynamicSymbolProperties;
        //Cast the compound marker symbol.
        m_dynamicCompoundMarker = DynamicDisplay as IDynamicCompoundMarker;

        //Do other initializations in here.

        m_bOnce = false;
    }
    ...
}
[VB.NET]
Public Overrides Sub DrawDynamicLayer(ByVal DynamicDrawPhase As ESRI.ArcGIS.Display.esriDynamicDrawPhase, ByVal Display As ESRI.ArcGIS.Display.IDisplay, ByVal DynamicDisplay As ESRI.ArcGIS.Display.IDynamicDisplay)
...
If m_bOnce Then
    'Cast the dynamic display into dynamic glyph factory.
    m_dynamicGlyphFactory = DynamicDisplay.DynamicGlyphFactory
    'Cast the dynamic display into dynamic symbol properties.
    m_dynamicSymbolProps = TryCast(DynamicDisplay, IDynamicSymbolProperties)
    'Cast the compound marker symbol.
    m_dynamicCompoundMarker = TryCast(DynamicDisplay, IDynamicCompoundMarker)
    
    'Do other initializations in here.
    
    m_bOnce = False
End If

...

End Sub

Draw rates

The default draw cycle is the actual draw time plus the draw rate, which means that the draw rate is the lag time between each two cycles. In this mode, you can consider the draw rate as sleep time between two draw cycles.
The following are the two types of  DynamicMap events:
  • DynamicMapStarted and DynamicMapFinished—Fired on start and end of each dynamic map heart beat
  • BeforeDynamicDraw and AfterDynamicDraw—Fired on before and after the dynamic display drawing
The draw rate (actual cycle time) is between every two DynamicMapStarted events. The actual draw time is between every DynamicMapStarted and DynamicMapFinished events.

In conclusion

Dynamic display has been an integral part of the map display pipeline since ArcGIS 9.2. It provides an ArcObjects API for developers to leverage accelerated graphics technology when required. The dynamic display operates as another display mode, which means most other standard ArcGIS tools continue to work. Developers can define dynamic symbols that can be moved, oriented, scaled, or even animated in real time.


See Also:

Dynamic display
Sample: Dynamic display compass
Sample: Dynamic display—tracking dynamic object
How to create a dynamic glyph from a marker symbol
Rendering dynamic map content
Maximizing performance in dynamic display




Development licensing Deployment licensing
Engine Developer Kit Engine
ArcGIS for Desktop Basic
ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced