ArcObjects Library Reference  

Display Library Overview


Supported with: ArcGIS Engine, ArcGIS Desktop, ArcGIS Server

Library dependencies: System, SystemUI Geometry

Additional library contents: Contents, Object Model Diagram

 

This content is also available in versions that specifically target .NET and Java developers. Click on the appropriate link to view either version.
        .NET overview of the Display assembly
        Java overview of the Display package


The Display library contains objects used for the display GIS data. In addition to the main display objects that are responsible for the actual output of the image, the library contains objects that represent symbols and colors, controlling the properties of entities drawn on the display. The library also contains objects that provide the user with visual feedback when interacting with the display.  


The objects that implement this functionality are grouped into a number of library subsystems. These library subsystems are:


Display

The Display object abstracts a drawing surface. A drawing surface is any hardware device, export file, or memory stream that can be represented by a Windows Device Context. Each display manages its own Transform object which handles the conversion of coordinates from real-world space to device space and back. The following standard displays are provided: ScreenDisplay abstracts a normal application window. It implements scrolling and backing store (multiple backing layers are possible). SimpleDisplay abstracts all other devices that can be rendered to using a Windows Device Context, such as printers, metafiles, bitmaps, and secondary windows.

The display objects allow application developers to easily draw graphics on a variety of output devices. These objects allow you to render shapes stored in real-world coordinates to the screen, the printer, and export files. Application features such as scrolling, backing store, print "tiling", and printing to a frame can be easily implemented. If some desired behavior is not supported by the standard objects, custom objects can be created by implementing one or more of the standard display interfaces.

In general, you must have a device context to do any drawing in windows. The HDC (handle to a device context) defines the device that you are drawing on. Some example devices are windows, printers, bitmaps, and metafiles. In ArcObjects, a display is simply a wrapper for a windows device context.

Use a SimpleDisplay coclass when you want to draw on a printer, export file, or simple preview window. Specify the HDC that you want to use to StartDrawing. This tells the display which window, printer, bitmap, or metafile to draw on. The HDC is created outside of ArcObjects using a Windows GDI function call.

Use a ScreenDisplay coclass when you want to draw maps to the main window of your application. This coclass handles advanced application features such as display caching and scroll bars. Specify the HDC for the associated window to StartDrawing. Normally, this is the HDC returned when you call the Windows GDI BeginPaint function in your application's WM_PAINT handler. Alternatively, you may specify 0 as the HDC parameter for StartDrawing, and an HDC for the associated window is automatically created. Normally, a ScreenDisplay uses internal display caches to boost drawing performance. During a drawing sequence, output is directed to the active cache and once per second, the window (i.e., the HDC specified to StartDrawing) is progressively updated from the active cache. If you want to prevent progressive updates (i.e., if you would rather update the window once when drawing has completed), specify the recording cache HDC (IScreenDisplay::CacheMemDC(esriScreenRecording)) to StartDrawing.

Use the IDisplay interface to draw points, lines, polygons, rectangles, and text on a device. Access to the display object's DisplayTransformation object is provided by this interface.

DisplayTransformation – This object defines how real-world coordinates are mapped to a output device. Three rectangles define the transformation. The Bounds specifies the full extent in real-world coordinates. The VisibleBounds specifies what extent is currently visible. And the DeviceFrame specifies where the VisibleBounds appears on the output device. Since the aspect ratio of the DeviceFrame may not always match the aspect ratio of the specified VisibleBounds, the transformation calculates the actual visible bounds that fits the DeviceFrame. This is called the FittedBounds and is in real-world coordinates. All coordinates can be rotated about the center of the visible bounds by simply setting the transformation’s Rotation property.

Display Caching

Here's the basic idea behind display caching. The main application window is controlled by a view (IActiveView). There are currently two view coclasses implemented: Map (data view) and PageLayout (layout view). ScreenDisplay makes it possible for clients to create any number of caches (a cache is just a device dependent bitmap). When a cache is created, the client gets a cacheID. The id is used to specify the active cache (last argument of StartDrawing, i.e., where output is directed), invalidate the cache, or draw the cache to a destination HDC. In addition to dynamic caches, the ScreenDisplay also provides a recording cache that accumulates all drawing that happens on the display. Clients manage recording using the StartRecording and FinishRecording methods.

To see how caches are implemented within ArcObjects the Map coclass will be examined. In the simplest case, Map creates one cache for all the layers, another cache if there are annotation or graphics, and a third cache if there's a feature selection. It also records all output. (In addition to these caches, it's also possible for individual layers to request a private cache by returning true for their Cached property. If a layer requests a cache, the Map creates a separate cache for the layer and groups the layers above and below it into different caches.) The IActiveView::PartialRefresh method uses it's knowledge of the cache layout to invalidate as little as possible so that we can draw as much as possible from cache. Given these caches, all of the following scenarios are possible:

Recording Cache

The ScreenDisplay can record what gets drawn. Use StartRecording() and StopRecording() to let the display know what exactly should be recorded. Use DrawCache(esriScreenRecording) to display what was recorded. Use get_CacheMemDC(esriScreenRecording) to get a handle to the memory device context for the recording bitmap. This functionality has several important uses.

  1. First, a single bitmap backing store is simple to implement, just use a drawing sequence like the following:

  2. [Visual Basic 6.0]
    If (m_pScreenDisplay.IsCacheDirty(esriScreenRecording)) Then
      m_pScreenDisplay.StartRecording
      m_pDraw.StartDrawing hDC, esriNoScreenCache
    
      Call DrawContents
    
      m_pDraw.FinishDrawing
      m_pScreenDisplay.StopRecording
    Else
      m_pScreenDisplay.DrawCache Picture1.hDC, esriScreenRecording, 0, 0
    End If
       
  3. Second, clients can use allocated display caches (created with IScreenDisplay::AddCache) to cache different phases of their view drawing while still having a single bitmap (the recording) to use for quick refreshes. Finally, you can access the recording bitmap while drawing to implement interesting advanced rendering techniques such as translucency.

Caveats

If any part of your map contains transparency it will affect how things get refreshed. When a transparent layer draws, everything below it, becomes part of the layer's rendering. As a result, the transparent layer must redraw from scratch every time that something below it changes.

Text also has transparency if the anti-aliasing setting is turned on in Microsoft Windows. This means that the text uses the layers that draw below it to carry out the anti-aliasing (the edges of the text are blended into the background). As a result, the annotation or auto-labels must draw whenever a layer changes.

How to cache layers

Set the cached flag on the layers you want to have their own display cache. Then reactivate the view.


[Visual Basic 6.0]
Private Sub EnableLayerCaches()
  Dim i As Integer
  For i = 0 To m_pMap.LayerCount - 1
    m_pMap.Layer(i).Cached = IIf(chkCustomCaches.Value = 1, True, False)
  Next i

  ' Reactivate
  Dim pMxDoc As IMxDocument
  Set pMxDoc = m_pApp.Document

  pActiveView.Deactivate
  pActiveView.Activate pActiveView.ScreenDisplay.hWnd
  pActiveView.Refresh
End Sub

Rotation

Understanding how rotatation is implemented within the display objects is important since it affects all entities that are displayed. Rotation happens below the transformation level so clients of DisplayTransformation always deal with unrotated shapes. For example, when you get a shape back from one of the transform routines, it's in unrotated space. Also, when you specify an extent to the transform, the extent is also in unrotated space. When working with polygons everything just works. When working with envelopes, things are more complicated because rotated rectangles cannont be represented. This is best illustrated with 2 examples:

Getting a rectangle from the transform. For example, let's say you want a rectangle representing the client area of the window. Since the user is seeing rotated space on the display, it's not possible to represent the requested area as an Envelope. The four corners of the rectangle have unique x and y values in map space. The internal representation of the Envelope coclass assumes shared x and y values for the sides. As a result the envelope returned by DisplayTransformation.FittedBounds isn't really what you want because a rectangular polygon is needed to accurately represent the client area in unrotated map space. Currently there's a bug that causes FittedBounds to return the same envelope that is returned when there is no rotation. When this is fixed, it should return a slightly expanded envelope as you expected. Most clients avoid using an envelope when there is rotation and implement code like the following to find the rectangular polygon that matches some rectangle on the user's display:


[C++]
inline void ToUnrotatedMap(const RECT& r, IGeometry* pBounds, IDisplayTransformation* pTransform)
{
  WKSPoint mapPoints[5];
  POINT rectCorners[4] = {{r.left, r.bottom}, {r.left, r.top}, {r.right, r.top}, {r.right, r.bottom}};
  pTransform->TransformCoords(mapPoints, rectCorners, 4, esriTransformToMap | esriTransformPosition);

  // build polygon from mapPoints
  mapPoints[4] = mapPoints[0];
  IPointCollectionPtr(pBounds)->SetWKSPoints(5, mapPoints);
  ITopologicalOperator2Ptr(pBounds)->put_IsKnownSimple(VARIANT_TRUE);
} 

Specifying a rectangle to the transform. Remember that the client needs to work in unrotated space and let the transform handle the rotation just before displaying. What does this mean in the simple case of dragging a zoom rectangle. First, the user sees rotation space. The rectangle they drag is in rotation space. (Note: the tool uses code like above to create a rectangular polygon representing the area selected by the user.) The tool needs to convert the rectangle to unrotated space before specifying it to the transform. The following code shows how to do this (pRotatedExtent is a rectangular polygon that exactly matches the rectangle dragged by the user):


[Visual Basic 6.0]
Dim pAreas As IArea
Set pArea = pRotatedExtent

Dim pCenter As IPoint
set pCenter = pArea.Centroid

Dim pTrans As ITransform2D
Set pTrans = pRotatedExtent

pTrans.Rotate pCenter, (90 * (3.1416 / 180))

Dim pNewExtent As IEnvelope
Set pNewExtent = pRotatedExtent.Envelope

Refreshing versus Invalidation

In order to cause a display to redraw, the Invalidate routine must be called. Most clients never use IScreenDisplay::Invalidate however. The reason is that if there is a view being used in your application, i.e., the Map or PageLayout coclass, the view should be used for refreshing the screen, i.e., Refresh, PartialRefresh. The view manages the display's caches and knows the best way to carry out invalidation. Just make sure PartialRefresh is called using the most specific arguments possible. Also, only call Refresh when absolutely necessary since this is usually a very time consuming operation.

One Stop Invalidation - In order to allow views (Map and PageLayout) to completely manage display caching, all invalidation must go through the view. Calling IActiveView::Refresh always draws everything. This is very inefficient. The method called PartialRefresh should be used whenever possible. It lets you specify what part of the view to redraw and allows the view to work with display caches in a way the allows drawing to be quick and efficient.

 

Draw Phase Map PageLayout
esriViewBackground unused page/snap grid
esriViewGeography layers unused
esriViewGeoSelection feature selection unused
esriViewGraphics labels/graphics graphics
esriViewGraphicSelection graphic selection element selection
esriViewForeground unused snap guides

Arguments for PartialRefresh

The table below shows some example calls to the partial refresh method; note the use of optional arguments:

Action Method Call
Refresh Layer

[Visual Basic 6.0]
pMap.PartialRefresh(esriViewGeography, pLayer, 0) 
Refresh All Layers

[Visual Basic 6.0]
pMap.PartialRefresh(esriViewGeography, 0, 0) 
Refresh Selection

[Visual Basic 6.0]
pMap.PartialRefresh(esriViewGeoSelection, 0, 0) 
Refresh Labels

[Visual Basic 6.0]
pMap.PartialRefresh(esriViewGraphics, 0, 0) 
Refresh Element

[Visual Basic 6.0]
pLayout.PartialRefresh(esriViewGraphics, pElement, 0) 
Refresh All Elements

[Visual Basic 6.0]
pLayout.PartialRefresh(esriViewGraphics, 0, 0) 
Refresh Selection

[Visual Basic 6.0]
pLayout.PartialRefresh(esriViewGraphicSelection, 0, 0) 

Example uses of PartialRefresh

Note: invalidating any phase will cause the recording cache to be invalidated. To force a redraw from the recording cache, use the following call


[Visual Basic 6.0]
 pScreenDisplay.Invalidate(0, VARIANT_FALSE, esriNoScreenCache).

Display Events

This section describes the events that are fired when a map draws. To provide better insight into drawing events, drawing order and display caching are discussed as well.

Drawing Order

To better understand the events that are fired when a map draws, the following section describes the order that objects are drawn for each kind of view.

Map (data view) – The following shows top to bottom order, i.e., each item is drawn above the items below it:

Object Phase Cache
Graphic Selection esriViewForeground none
Clip Border esriViewForeground none
Feature Selection esriViewGeoSelection selection
Auto Labels esriViewGraphics annotation
Graphics esriViewGraphics annotation
Layer Annotation esriViewGraphics annotation
Layers esriViewGeography layer(s)
Background esriViewBackground bottom layer

Map Class Drawing Order

PageLayout – The following shows top to bottom order, i.e., each item is drawn above the items below it:

Object Phase Cache
Snap Guides esriViewForeground none
Selection esriViewGraphicSelection selection
Elements esriViewGraphics element
Snap Grid esriViewBackground element
Print Margins esriViewBackground element
Paper esriViewBackground element

PageLayout class drawing order

Drawing Events

The following IActiveViewEvents events can be used to add custom drawing to your application:

The AfterDraw event is fired after every phase of drawing. To draw a graphic into a cache, use the following design:

  1. Create an object that connects to the active view (map). For example “Events”.
  2. Pick the draw phase that you want to draw after. The phase you pick determines what gets drawn above and below you.
  3. Draw in response to IActiveViewEvents::AfterDraw

Not all of the views fire all of the events. Additionally, if a view is partially refreshed, the phases that draw from cache do not fire their AfterDraw event. For example, if the selection is refreshed, all of the layers draw from cache. As a result, the AfterDraw(esriViewGeography) event does not fire. However, there is an exception, in the case of esriViewForeground, the event is fired everytime the view draws. Even if everything in the map draws from the recording cache, the foreground event still fires.

How to Enable item events with VerboseEvents

The AfterItemDraw is fired after each feature or graphic is displayed and can seriously impact drawing performance if a connected handler is not efficient. Normally clients connect to the AfterDraw event. Note that it's important to check the second argument and respond to the appropriate phase of drawing since the AfterDraw routine will be called several times when the map is drawn.

For efficiency, IActiveView has a property called VerboseEvents. It can be used to limit the number of events that are fired. If VerboseEvents=false, AfterItemDraw is not fired. This is the default setting.

Events and Display Caching

The following tables shows the device context that is active when each of the AfterDraw events is fired:

Event Active HDC
esriViewForeground window
esriViewGraphics annotation cache
esriViewGeoSelection selection cache
esriViewGeography top layer cache
esriViewBackground bottom layer cache

Map class AfterDraw Device Contexts

 

Event Active HDC
esriViewForeground window
esriViewGraphicSelection selection cache
esriViewGraphics element cache
esriViewBackground element cache

PageLayout class AfterDraw Device Contexts

Create a private cache

For drawing graphics (events), you probably want to use esriViewGraphics. AfterDraw has two arguments, pDisplay and drawPhase. It gets called for each of the phases so make sure you only draw when your phase is specified. Draw directly to the display and don't worry about caches. The StartDrawing and FinishDrawing methods are called by Map. If the phase you are drawing after is cached, your drawing will automatically be cached.

  1. Create the cache in response to IDocumentEvents::ActiveViewChanged. Map creates it's caches in response to Activate and throws away all caches in response to Deactivate. The ActiveViewChanged event is fired after Map creates its caches so if there's not enough memory, the map will get its caches but the private cache will not.

    [Visual Basic 6.0]
    Dim pActiveView As IActiveView
    Set pActiveView = pMap
    
    Dim pScreen As IScreenDisplay
    Set pScreen = pActiveView.ScreenDisplay
    
    pScreen.AddCache(m_myCacheID)
    
    
  2. AfterDraw should look something like this:

  3. [Visual Basic 6.0]
    if (phase != esriViewXXX) Then Exit Sub
    
    
    Dim pScreen As IScreenDisplay
    Set pScreen = pDisplay
    
    if (Not pScreen Is Nothing) Then
      ' Draw directly to output device
      DrawMyStuff(pDisplay)
      Exit Sub
    End If
    
    ' Draw to screen using cache if possible
    Dim hWindowDC As Long;
    WindowDC = pScreen.WindowDC
    
    Dim bDirty As Boolean
    pScreen.IsCacheDirty(m_myCacheID, bDirty);
    If (bDirty)
      ' draw from scratch
      pScreen.FinishDrawing
      pScreen.StartDrawing hWindowDC, m_myCacheID
      DrawMyStuff(pDisplay) // Map::CachedDraw handles FinishDrawing
    Else
      ' draw from cache
      pScreen.DrawCache(hWindowDC, m_myCacheID, 0, 0)
    End If
    
    

Transparency

Both symbols and images can make use of transparent colors. The transparency (alpha blend) algorithm is raster based. Vector drawing must first be converted to raster in order to support it. Transparent objects are drawn to a source bitmap. The background that the objects are drawn on must be stored in a background bitmap. Transparency is accomplished by blending the source bitmap into the background bitmap using either a single transparency value for all the bits or a mask bitmap containing transparency values for each individual pixel. To support transparency, IDisplay provides the BackgroundDC attribute that can be used to get a bitmap containing all of the drawing that has happened in the current drawing sequence.

Display Transparency

The transparency algorithm is encapsulated into the display filter object: TransparencyDisplayFilter. The same filter coclass can be used by feature layers, raster layers, elements, third parties, etc.

To draw with transparency, do the following:


[Visual Basic 6.0]
Dim pFilter As ITransparencyDisplayFilter
Set pFilter = New TransparencyDisplayFilter

pFilter.Transparency = 100
pDisplay.StartDrawing(hdc, cacheID)
pDisplay.Filter = pFilter

DrawToDisplay()

pDisplay.Filter = 0
pDisplay.FinishDrawing 

 

For raster layers, DrawToDisplay() means get the destination DC from the display and BitBlt the raster image to it.

When the filter is specified, the display creates an internal filter cache that is used along with the recording cache to provide the necessary raster info to the filter. Output is routed to the filter cache so that when the raster layer asks for the destination DC, it gets the filter cache DC. The display applies the filter when pDisplay.Filter is set to 0. Apply receives the current background bitmap (recording cache), the opaque raster layer image (filter cache), and the destination (window). The filter knows the transparency value is 100 so it does the blending and sends the results to the window.

Symbol Transparency

How do we technically make symbols and images support transparency. The view objects (Data and Layout) handle drawing maps both to output devices (windows and printers) and export files (bitmap and metafiles). All graphic elements and layers need to report whether or not they are using transparent colors. So that when the view starts to generate output, it can check if there are any transparent colors. If there are, it uses the following algorithm to produce output:

  1. Divide the display surface up into bands so that the in-memory bitmaps required to create transparent colors do not consume too much memory.
  2. Create a BackingDisplay the size of one band. A BackingDisplay has an internal device independent bitmap that has the same color depth and resolution as the output device. Drawing is directed to the bitmap then when drawing is finished, the bitmap is copied to the actual output device (or file). The layers and symbols treat this BackingDisplay just like any other display so no special coding is required for them.
  3. For each band: adjust the display's transform to reference the current band and draw the view. The renderers will automatically clip to the band since the transform's visible bounds equals the band rectangle.

This will result in a series of bitmaps (the bands) being copied to the output device or export file. If there are no transparent colors in the map, the metafile will be generated normally, i.e., it will contain series of vector graphics.

Rapid Display

Often times it is necessary to quickly update the display to show movement of live objects. For example, movements of commercial assets tracked by GPS. There are two aspects to the problem:

  1. How to store the live data
  2. How to rapidly draw it to the display.

Design Patterns

There are many ways to store and draw event data in your application. The most common methods are as follows:

Note the three common ways to store custom data:

  1. Features in a GeoDatabase
  2. Elements in a graphics layer
  3. Proprietary data structure.

The best choice depends on where in the drawing order your events need to draw, whether you want to use standard rendering objects, and whether or not you need to support a proprietary data format.

In all cases, the standard Invalidation model of drawing should be used. That is, create an object that draws (i.e., layer, graphic element, or event handler), plug it into your map, and call IActiveView::PartialRefresh when you want it to draw.

Animation Support

At version 9 of ArcObjects, a new interface, IViewRefresh makes it simpler to quickly refresh the display to show live objects. Clients should use the AnimationRefresh routine in place of PartialRefresh to invalidate their custom drawing object. For example, you may store “live” features using a layer with its own display cache. Animation is accomplished by moving features, invalidating the layer (with AnimationRefresh), and letting redraw happen naturally. When AnimationRefresh is used instead of PartialRefresh, the following optimizations / tradeoffs are enabled:

Text Anti-aliasing is temporarily disabled. This prevents labels from having to be redrawn every time the animation layer is invalidated. Remember that anti-aliased text uses the background as part of its rendering so normally when anything below it changes, the text also needs to draw from scratch.

Transparent layers above the animation layer are not automatically invalidated along with the animation layer. This speeds up the redraw with the following limitation: Features in the animation layer will no longer show through the transparent layer above it.

All drawing is directed to the recording cache HDC rather than the window. This causes all drawing to happen behind the scenes. When drawing is complete, the window is updated once from the completed recording cache. The result is less flashing.

To avoid excessive CPU consumption during rapid drawing you can make a call to UpdateWindow between invalidating old location and invalidating new location.

Display Design Patterns

To help you understand how the various display objects work together to solve common development requirements, several application scenarios are given along with details on their implementation. Use these patterns as a starting point for working with the display objects.

The application window

One of the most common tasks is to draw maps in the client area of an application window with support for scrolling and backing store. The display objects are used as follows to make this possible.

Initialization

Start by creating a ScreenDisplay when the window is created. You'll also need to create one or more symbols to use for drawing shapes. Forward the application's hWnd to pScreenDisplay.hWnd. Obtain from the ScreenDisplay its IDisplayTransformation interface and set the full and visible map extents using pTransformation.Bounds and pDisplayTransform.VisibleBounds. The visible bounds determines the current zoom level. ScreenDisplay takes care of updating the display transformation's DeviceFrame. The ScreenDisplay monitors the window's messages and automatically handles common events such as window resizing or scrolling.

[Visual Basic 6.0]
Private m_pScreenDisplay As IScreenDisplay
Private m_pFillSymbol As ISimpleFillSymbol

Private Sub Form_Load()
  Set m_pScreenDisplay = New ScreenDisplay
  m_pScreenDisplay.hWnd = Picture1.hWnd

  Set m_pFillSymbol = New SimpleFillSymbol

  Dim pEnv As IEnvelope
  Set pEnv = New Envelope

  pEnv.PutCoords 0, 0, 50, 50

  m_pScreenDisplay.DisplayTransformation.bounds = pEnv
  m_pScreenDisplay.DisplayTransformation.VisibleBounds = pEnv
End Sub

Drawing

The display objects define a generic IDraw interface, which makes it easy to draw to any display. As long as you use IDraw or IDisplay to implement your drawing code, you don't have to worry about what kind of device you're drawing to. A drawing sequence starts with StartDrawing and ends with FinishDrawing. For example, create a routine that builds one polygon in the center of the screen and draws it. The shape is drawn using the default symbol. Here are the sample routines:

[Visual Basic 6.0]
Private Function GetPolygon() As IPolygon
  Set GetPolygon = New Polygon

  Dim pPointCollection As IPointCollection
  Set pPointCollection = GetPolygon

  Dim pPoint As IPoint
  Set pPoint = New Point

  pPoint.PutCoords 20, 20
  pPointCollection.AddPoint pPoint

  pPoint.PutCoords 30, 20
  pPointCollection.AddPoint pPoint

  pPoint.PutCoords 30, 30
  pPointCollection.AddPoint pPoint

  pPoint.PutCoords 20, 30
  pPointCollection.AddPoint pPoint

  GetPolygon.Close
End Function


Private Sub MyDraw(pDisplay As IDisplay, hDC As esriSystem.OLE_HANDLE)
  ' Draw from Scratch
  Dim pDraw As IDraw
  Set pDraw = pDisplay

  pDraw.StartDrawing hDC, esriNoScreenCache

  Dim pPoly As IPolygon
  Set pPoly = GetPolygon()

  pDraw.SetSymbol m_pFillSymbol
  pDraw.Draw pPoly

  pDraw.FinishDrawing
End Sub
This routine can be used to draw polygons to any device context. The first place we need to draw, however, is to a window. To handle this, write some code in the Paint method of the Picture Box that passes the application's ScreenDisplay pointer and Picture Box HDC to the MyDraw routine. Notice that the routine takes both a display pointer and a Windows device context.

[Visual Basic 6.0]
Private Sub Picture1_Paint()
  MyDraw m_pScreenDisplay, Picture1.hDC
End Sub
Forwarding the DC allows the display to honor the clipping regions that Windows sets into the paint HDC.

Adding Display Caching

Some drawing sequences can take a while to complete. A simple way to optimize your application is to enable display caching. This refers to ScreenDisplay's ability to record your drawing sequence into a bitmap and then use the bitmap to refresh the picture box's window whenever Paint method is called. The cache is used until your data changes and you call IScreenDisplay::Invalidate to indicate that the cache is invalid. There are two kinds of caches: recording caches and user-allocated caches. Use recording to implement a display cache in the sample application's Paint method.

[Visual Basic 6.0]
Private Sub Picture1_Paint()
  If (m_pScreenDisplay.IsCacheDirty(esriScreenRecording)) Then
    m_pScreenDisplay.StartRecording

    MyDraw m_pScreenDisplay, Picture1.hDC

    m_pScreenDisplay.StopRecording
  Else
    Dim rect As tagRECT
    m_pScreenDisplay.DrawCache Picture1.hDC, esriScreenRecording, rect, rect
  End If
End Sub
When you execute this code, you will see that nothing is drawn on the screen. This is due to the ScreenRecording cache not having its dirty flag set. To ensure that the MyDraw function is called when the first paint message is received, you must invalidate the cache. Add the following line at the end of the Form_Load method.

[Visual Basic 6.0]
m_pScreenDisplay.Invalidate Nothing, True, esriScreenRecording
Some applications, ArcMap for example, may require multiple display caches. To utilize multiple caches, follow these steps:
  1. Add a new cache using IScreenDisplay::AddCache. Save the cache ID that is returned.
  2. To draw to your cache, specify the cache ID to StartDrawing.
  3. To invalidate your cache, specify the cache ID to Invalidate.
  4. To draw from your cache, specify the cache ID to DrawCache.
To change the sample application to support its own cache, make the following changes:

[Visual Basic 6.0]
      Private m_lCacheID As Long

[Visual Basic 6.0]
      m_lCacheID = m_pScreenDisplay.AddCache

Pan, zoom, and rotate

A powerful feature of the display objects is the ability to zoom in and out on your drawing. It's easy to implement tools that let users zoom in and out or pan. Scrolling is handled automatically. To zoom in and out on your drawing, simply set your display's visible extent. For example, add a command button to the form and place the following code, which zooms the screen by a fixed amount, in the Click event of the button.

[Visual Basic 6.0]
Private Sub Command1_Click()
  Dim pEnv As IEnvelope

  Set pEnv = m_pScreenDisplay.DisplayTransformation.VisibleBounds
  pEnv.Expand 0.75, 0.75, True
  m_pScreenDisplay.DisplayTransformation.VisibleBounds = pEnv

  m_pScreenDisplay.Invalidate Nothing, True, esriAllScreenCaches
End Sub
ScreenDisplay implements TrackPan, which can be called in response to a mouse down event to let users pan the display. You can also rotate the entire drawing about the center of the screen by setting the DisplayTransformation's Rotation property to a nonzero value. Rotation is specified in degrees. ScreenDisplay implements TrackRotate, which can be called in response to a mouse down event to let users interactively rotate the display.

Printing

Printing is very similar to drawing to the screen. Since you don't have to worry about caching or scrolling when drawing to the printer, a SimpleDisplay can be used. Create a SimpleDisplay object and initialize its transform by copying the ScreenDisplay's transform. Set the printer transformation's DeviceFrame to the pixel bounds of the printer page. Finally, draw from scratch using the SimpleDisplay and the printer's HDC.

Output to a metafile

The GDIDisplay object can be used to represent a metafile. There's little difference between creating a metafile and printing. If you specify 0 as the lpBounds parameter to CreateEnhMetaFile, the MyDraw routine can be used. Just substitute hMetafileDC for hPrinterDC. If you want to specify a bounds to CreateEnhMetafFile (in HIMETRIC units), set the DisplayTransformation's DeviceFrame to the pixel version of the same rectangle.

Print to a frame

Some projects may require output to be directed to some subrectangle of the output device. It's easy to handle this by setting the DisplayTransformation's device frame to a pixel bounds that is less than the full device extent.

Filters

Very advanced drawing effects, such as color transparency, can be accomplished using display filters. Filters work along with a display cache to allow a rasterized version of your drawing to be manipulated. When a filter is specified to the display (using IDisplay::putref_DisplayFilter), the display creates an internal filter cache that is used along with the recording cache to provide raster info to the filter. Output is routed to the filter cache until the filter is cleared (that is, putref_DisplayFilter(0)). At that point, the display calls IDisplayFilter::Apply. Apply receives the current background bitmap (recording cache), the drawing cache (containing all of the drawing that happened since the filter was specified), and the destination HDC. The transparency filter performs alpha blending on these bitmaps and draws them to the destination HDC to achieve color transparency. New filters can be created to realize other effects.

Colors

Color is used in many places in ArcGIS applications—in feature and graphics symbols, as properties set in renderers, as the background for ArcMap or ArcCatalog windows, and as properties of a raster image. The type of color model used in each of these circumstances will vary. For example, a window background would be defined in terms of an RGB color because display monitors are based on the RGB model. A map made ready for offset-press publication could have CMYK colors to match printer's inks.

Color can be represented using a number of different models, which often reflect the ways in which colors can be created in the real world.You may be familiar with the RGB color model, which is based on the primary colors of light—red, green, and blue. When red, green, and blue rays of light coincide, white light is created. The RGB color model is therefore termed additive, as adding the components together creates light. By displaying pixels of red, green, and blue light, your computer monitor is able to portray hundreds, thousands, and even millions of different colors. To define a color as an RGB value, you give a separate value to the red, green, and blue components of the light. A value of 0 indicates no light, and 255 indicates the maximum light intensity.

Red, green, blue (RGB) color model

 

Here are a few rules for RGB values:

Another common way to represent color, the CMYK model, is modeled on the creation of colors by spot printing. Cyan, magenta, yellow, and black inks are mingled on paper to create new colors. The CMYK model, unlike RGB, is termed subtractive, as adding all the components together creates an absence of light (black).

Cyan, magenta, yellow (CMY) color model


Cyan, magenta, and yellow are the primary colors of pigments—in theory you can create any color by mixing different amounts of cyan, magenta, and yellow. In practice, you also need black, which adds definition to darker colors and is better for creating precise black lines. HSV, or the hue, saturation, and value color model, describes colors based around a color wheel that arranges colors in a spectrum. The hue value indicates where the color lies on this color wheel and is given in degrees. For example, a color with a hue of 0 will be a shade of red, whereas a hue of 180 will indicate a shade of cyan.

Color wheel for hue, saturation, and value (HSV) color model


Saturation describes the purity of a color. Saturation ranges from 0 to 100; therefore, a saturation of 20 would indicate a neutral shade, whereas a saturation of 100 would indicate the strongest, brightest color possible. The value of a color determines its brightness, with a range of 0 to 100. A value of 0 always indicates black; however, a value of 100 does not indicate white, it just indicates the brightest color possible. Hue is simple to understand, but saturation and value can be confusing. It may help to remember these rules:

The HLS, or hue, lightness, and saturation model, has similarities with the HSV model. Hue again is based on the spectrum color wheel, with a value of 0 to 360. Saturation again indicates the purity of a color, from 0 to 100. However, instead of value, a lightness indicator is used, again with a range of 0 to 100. If lightness is 100, white is produced, and if lightness is 0, black is produced. The last color model is grayscale. 256 shades of pure gray are indicated by a single value. A grayscale value of 0 indicates black, and a value of 255 indicates white.

Grayscale color model


The CIELAB color model is used internally by ArcObjects, as it is device independent. The model, based on a theory known as opponent process theory, describes color in terms of three “opponent channels”. The first channel, known as the 1 channel, traverses from black to white. The second, or 2 channel, traverses red to green hues. The last channel, or 3 channel, traverses hues from blue to yellow.

Sample Color Values


Objects that support the IColor interface allow precise control over any color used within the ArcObjects model. You can get and set colors using a variety of standard color models—RGB, CMYK, HSV, HLS, and Grayscale.

The properties available on the IColor interface define the common functionality of all color objects. Representations of colors are held internally as CIELAB colors, described in the color theory topic. The CIELAB color model is device independent, providing a frame of reference to allow faithful translation of colors between one color model and another. You can use the GetCIELAB and SetCIELAB methods of the IColor interface to interact directly with a color object using the CIELAB model.Although colors are held internally as CIELAB colors, you don't need to deal directly with the CIELAB color model—you can use the IColor interface to simply read and define colors. For example, the RGB property can be used to read or write a Long integer representing the red, green, and blue values for any color object. You can use the Visual Basic RGB function to set the RGB property of a color object as follows.

[Visual Basic 6.0]
colMyColor.RGB = RGB(intMyRedValue, intMyGreenValue, intMyBlueValue)
Or, you could use the following function, which essentially performs the same action but lets you see how the conversion is performed.

[Visual Basic 6.0]
Public Function RGBToLong(lngRed As Long, lngGreen As Long, _
  lngBlue As Long) As Long
  RGBToLong = lngRed + (&H100 * lngGreen) + (&H10000 * lngBlue)
End Function
If you are reading the RGB property, you can break down the RGB value into its component red, green, and blue values with an inverse function of the previously defined RGBToLong function, as follows:

[Visual Basic 6.0]
Public Function ReturnRGBBytes(ByVal lngRGB As Long) As Byte()
  Dim bytArray(2) As Byte
  bytArray(0) = lngRGB Mod &H100
  bytArray(1) = (lngRGB \ &H100) Mod &H100
  bytArray(2) = (lngRGB \ &H10000) Mod &H100
  ReturnRGBBytes = bytArray
End Function
One important point to note when reading the RGB property: the UseWindowsDithering property should generally be set to True. If UseWindowsDithering is False, the RGB property returns a number with a high byte of 2, indicating the use of a system color, and the RGB property will return a value outside of the range you would expect. If you write to the RGB property, the UseWindowsDithering property will be set to True for you. For more information on converting individual byte values to long integer representation, look for topics on color models and hexadecimal numbering in your development environment's online Help system. The IColor interface also provides access to colors through another color model—CMYK. The CMYK property can be used in a similar way as RGB to read or write a Long integer representing the cyan, magenta, yellow, and black components of a particular color—the difference being that the CMYK color model requires four values to define a color. Visual Basic does not have a function for creating a CMYK Long integer value, but the RGBToLong function can be adapted as shown.

[Visual Basic 6.0]
Public Function CMYKToLong(lngBlack As Long, lngYellow As Long, lngMagenta As Long, lngCyan As Long) As Long
  CMYKToLong = lngBlack + (&H100 * lngYellow) + (&H10000 * lngMagenta) + (&H1000000 * lngCyan)
End Function
Setting the NullColor property to True will result in the set color being nullified. All items with color set to Null will not appear on the display. This only applies to the specific color objects—not all items with the same apparent color; therefore, you can have different null colors in one Map or PageLayout.IColor also has two methods to convert colors to and from specific CIELAB colors, using the parameters of the CIELAB color model. You can set a color object to a specific CIELAB color by using SetCIELab, or read CIELAB parameters from an existing color by using GetCIELab. See also the CieLabConversion coclass. Color transparency does not get used by the feature renderers; instead, a display filter is used. Setting the transparency on a color has no effect, unless the objects using the color honor this setting. The Color class is only an abstract class—when dealing with a color object, you always interact with one of the color coclasses, which are described below. RGBColor, CMYKColor, GrayColor coclass, HSVColor, and HLSColor are all creatable classes, allowing new colors to be created programmatically according to the most appropriate color model.

Color Ramps

The objects supporting the IColorRamp interface offer a simple way to define a series of colors for use elsewhere in ArcObjects. For example, you can set a color ramp directly onto the ColorRamp property of the IGradientFillSymbol interface of a FillSymbol, or you might wish to create a color ramp to define the colors used in a ClassBreaksRenderer. The individual ColorRamp objects offer different ways of defining the criteria that determine which colors will comprise the ColorRamp. Random colors can be created using the RandomColorRamp, and sequential colors can be created using the AlgorithmicColorRamp. The PresetColorRamp coclass contains 13 colors, allowing the creation of ramps mimicking ArcView GIS 3.x color ramps. In addition, the MultiPartColorRamp allows you to create a single color ramp that concatenates other color ramps, providing unlimited color ramp capabilities.

ColorRamps are used in two different ways in ArcObjects: by accessing the individual colors in a ramp or by using the ramp object directly as a property or, in a method, of another object. First, a color ramp can be set up and its individual colors accessed. For example, when a UniqueValueRenderer is created, each symbol in its symbol array should be set individually, perhaps using colors from a color ramp. To retrieve individual colors from a color ramp, first set the Size property according to the number of Color objects you wish to retrieve from the ramp. The CreateRamp method should then be called, which populates both the Color and the Colors properties. The Color property holds a read-only, zero-based array of Color objects, returned by index. The code fragment below shows the creation of a RandomColorRamp and the generation of 10 color objects from that ramp. Note that the Boolean parameter used in the CreateRamp method is checked after the method is called to ensure the colors were generated correctly.

[Visual Basic 6.0]
Dim pColorRamp As esriDisplay.IRandomColorRamp
Set pColorRamp = New esriDisplay.RandomColorRamp

pColorRamp.Size = 10

Dim bOK As Boolean
pColorRamp.CreateRamp bOK
If (bOK) Then
  Dim i As Integer
  For i = 0 To pColorRamp.Size - 1
    ' Access the Color array here, for example, set the colors
    ' for an array of symbols, or map layers etc...
  Next i
End If
The Colors property returns an enumeration of colors and is useful as a lightweight object to pass around between procedures.Second, a color ramp object may be used directly—for example, the ColorRamp property of the IGradientFillSymbol can be set to a specific color ramp object. The MultiPartColorRamp also uses color ramp objects directly by passing the object as a parameter in the AddRamp method. Below you can see a GradientFillSymbol object being created with an AlgorithmicColorRamp as its fill. The IntervalCount is set, which decides the amount of colors in the gradient fill.

[Visual Basic 6.0]
Dim pAlgoRamp As IAlgorithmicColorRamp
Set pAlgoRamp = New AlgorithmicColorRamp

pAlgoRamp.FromColor = myFromColorObject
pAlgoRamp.ToColor = myToColorObject

Dim pGFill As esriDisplay.IGradientFillSymbol
Set pGFill = New esriDisplay.GradientFillSymbol

pGFill.ColorRamp = pAlgoRamp
pGFill.IntervalCount = 5
If the ramp will be used directly, as above, it is not necessary to set the Size property or to call the CreateRamp method yourself. In these cases, the parent object uses the information contained in the color ramp object to generate the number of colors it requires. The Size property will be ignored.The name property simply stores a string, which you may want to use to keep track of your color ramps—it is not used internally by ArcObjects.

Symbols

ArcObjects uses three categories of symbols to draw geographic features: marker symbols, line symbols, and fill symbols. These same basic symbols are also used to draw graphic elements, such as neatlines and North arrows, on a Map or PageLayout. A fourth symbol, the TextSymbol, is used to draw labels and other textual items. A fifth symbol, the 3DChartSymbol, is used for drawing charts. In the case of a graphic element, a symbol is set as a property of each element. Layers, however, are drawn with a renderer, which has one or more symbols associated with it. The size of a symbol is always specified in points (such as the width of a line), but the size of their geometry (such as the path of a line) is determined by the item they are used to draw. Most items, when created, have a default symbol, so instead of creating a new symbol for every item, you can modify the existing one. Another way to get a symbol is to use a style file. ArcObjects uses style files, which are distributable databases, to store and access symbols and colors. Many standard styles, offering thousands of predefined symbols, are available during the installation process. Using the StyleGallery and StyleGalleryItem classes, you can retrieve and edit existing symbols, which may be more efficient than creating symbols from scratch. You might also wish to use the standard symbol editors found in ArcMap, which can be opened programmatically using the SymbolEditor coclass. The following pages describe how to create all the different symbols from first principles. The ISymbol interface provides high-level functionality for all symbols. It allows you to draw any symbol directly to a device context (DC). A device context is an internal Windows structure—each window has a device context handle, or hDC.

The SetupDC, Draw, and ResetDC methods can be used in conjunction with the ROP2 property to draw a symbol to a device context, providing a familiar procedure for those who have worked with device context drawing before. Calling the SetupDC method selects the Symbol into the specified DC, and setting the ROP2 property to one of the esriRaster-OpCodes specifies how the Symbol is drawn (see below). Subsequently calling the Draw method will draw the Symbol, using the Geometry parameter from the Draw method, to the DC. The following code demonstrates drawing to a device context, where pDisplay is a valid Display object, pPoint is a valid Point in display coordinates, and pSymbol is any valid Symbol. There are two important points to note:

[Visual Basic 6.0]
Sub DrawSymbol
  pDisplay.StartDrawing pDisplay.hDC, esriNoScreenCache
  pSymbol.SetupDC pDisplay.hDC, pDisplay.DisplayTransformation
  pSymbol.Draw pPoint
  pSymbol.ResetDC
  pDisplay.FinishDrawing
End Sub
Symbol Level Drawing

You can use symbol level drawing to alter the draw order of features within feature layers. By using symbol level drawing you can control the draw order of features on a symbol by symbol basis. This means that features do not necessarily need to be drawn in the same order that feature layers appear in the ArcMap table of contents. With symbol level drawing you can control when a feature draws by controlling when the feature's symbol draws. Furthermore, when multi layer symbols are used, you can control the drawing order of individual symbol layers.

Using symbol level drawing is most useful for maps with cased lines because it can be used to create overpass and underpass effects where the line features cross, which is a good way to show connectivity. Symbol level drawing can be used to achieve other advanced effects as well.

IMapLevel is the interface that you use to assign a map level (or levels if the symbol is multi layer) to a symbol, thus preparing it to be used with symbol level drawing. Not all symbols support this interface. Note that if you assign a symbol with map levels to a graphic element, then the levels will be ignored. Also, ISymbol::Draw ignores levels as well.

To use symbol level drawing:

(1) Turn on symbol level drawing, either for a layer using ISymbolLevels::UseSymbolLevels, or for your entire map using IMap::UseSymbolLevels. Prior to ArcGIS 9.0 symbol levels were referred to in the ArcMap GUI as 'Advanced Drawing Options' and they were only available at the map level. In ArcGIS 9.0 and later versions, symbol level support was added for individual FeatureLayers and GroupLayers. In the GUI this is called 'Symbol Level Drawing'. The preferred use of symbol levels is at the layer level since in ArcGIS 9.0 and later there is no GUI for map-based symbol level drawing and layer-based symbol level drawing is more efficient.

(2) For each layer in your map that you want to use symbol levels for, access the layer's renderer using IGeoFeatureLayer::Renderer.

(3) Access your layer's symbols through the renderer.

(4) Using IMapLevel, set symbol levels on your layer's symbols. Symbols with MapLevel = 0 draw first, then symbols with MapLevel = 1, continuing until the highest MapLevel is reached. If two symbols have the same MapLevel, then the features drawn with these symbols are drawn in the normal layer order. A MapLevel of -1 for a multilayer symbol (MultiLayerMarkerSymbol, MultiLayerLineSymbol, MultiLayerFillSymbol) indicates that each of the symbol's individual layers are drawn with their individual MapLevel .

Symbol Levels dialogs

The Advanced Drawing Options dialog is used to set up map-based symbol level drawing. This dialog is only supported for new symbology in ArcGIS 8.3 and earlier versions. You can see this dialog in ArcGIS 9.0 if you open an .mxd created in ArcGIS 8.3 that has symbol levels.

Advanced Drawing Options dialog


The Symbol Level Drawing dialog is used to set up layer-based symbol level drawing. This dialog opens from either the feature layer properties dialog or the group layer properties dialog in ArcMap.

Symbol Level Drawing dialog


Join and Merge

In both of the dialogs above, Join and Merge are GUI terms used to help users set up symbol levels. See the ArcGIS Desktop Help for more information. The graphics below show the effect of joining a symbol, which makes features with the same symbol appear to 'connect' to each other. Merge makes features with different symbols appear to 'connect'. Both of these effects are implemented behind the scenes using the symbol level objects and interfaces. You can toggle symbol level drawing on or off, either using ISymbolLevels::UseSymbolLevels for a layer, or for an .mxd built in ArcGIS 8.3 or earlier, for your entire map using IMap::UseSymbolLevels.

Symbols drawing using Map Levels


[Visual Basic 6.0]

The following VB code turns on symbol level drawing for the layer in the map and sets up the multi-layer symbol assigned to this layer to be joined.

' ...

If (TypeOf pMap.Layer(0) Is IGeoFeatureLayer) Then
  Dim pFeatLyr As IGeoFeatureLayer
  Set pFeatLyr = pMap.Layer(0)
  Dim pSymbolLevels As ISymbolLevels
  Set pSymbolLevels = pFeatLyr
  pSymbolLevels.UseSymbolLevels = True

  If (TypeOf pFeatLyr.Renderer Is ISimpleRenderer) Then
    Dim pSimpleRend As ISimpleRenderer
    Set pSimpleRend = pFeatLyr.Renderer

    If (TypeOf pSimpleRend.Symbol Is IMultiLayerLineSymbol) Then
      Dim pMulti As IMultiLayerLineSymbol
      Set pMulti = pSimpleRend.Symbol
      SetMapLevel pMulti, -1

      Dim i As Long

      For i = 0 To pMulti.LayerCount - 1
        SetMapLevel pMulti.Layer(i), pMulti.LayerCount - (i + 1)
      Next i
    End If
  End If
End If

' ...

Sub SetMapLevel(pMapLevel As IMapLevel, lngLevel As Long)
  If Not pMapLevel Is Nothing Then
    pMapLevel.MapLevel = lngLevel
  End If
End Sub

Marker Symbols

The IMarkerSymbol interface represents the properties all types of MarkerSymbol have in common. These are Angle, Color, Size XOffset, and YOffset.

IMarkerSymbol is the primary interface for all marker symbols. All other marker symbol interfaces inherit the properties and methods of IMarkerSymbol. The interface has five read_write properties that allow you to get and set the basic properties of any MarkerSymbol. The Color property can be set to any IColor object, and its effects will be dependent on the type of coclass you are using.

Marker Symbol Color Properties


The Size property sets the overall height of the symbol if the symbol is a SimpleMarkerSymbol, CharacterMarkerSymbol, PictureMarkerSymbol, or MultiLayerMarkerSymbol. For an ArrowMarkerSymbol, Size sets the length. The units are points. The default size is eight for all marker symbols except the PictureMarkerSymbol—its default size is 12. The Angle property sets the angle in degrees to which the symbol is rotated counterclockwise from the horizontal axis; and its default is 0. The XOffset and YOffset properties determine the distance to which the symbol is drawn offset from the actual location of the feature. The properties are both in printer's points, both have a default of zero, and both can be negative or positive; positive numbers indicate an offset above and to the right of the feature, and negative numbers indicate an offset below and to the left. Below, you create an ArrowMarkerSymbol and set only the properties inherited from IMarkerSymbol.


[Visual Basic 6.0]
Dim pArrow As IMarkerSymbol
Set pArrow = New ArrowMarkerSymbol

With pArrow
  .Angle = 60
  .Size = 50
  .XOffset = 20
  .YOffset = 30
  .Color = pColor
End With

The Size, XOffset, and YOffset of a marker symbol is in printer's points—1/72 of an inch.

The types of marker symbols


The rotation of a marker symbol is specified in mathematical notation.

Marker Symbol Rotation


Below are some examples of each of the marker symbol types.

Simple marker symbols


Arrow marker symbols


Character marker symbols


Picture marker symbols


Multilayer marker symbols


Line Symbols

The ILineSymbol interface represents the two properties—Color and Width—all types of line symbols have in common.

ILineSymbol is the primary interface for all line symbols, which all inherit the properties and methods of ILineSymbol. The interface has two read_write properties that allow you to get and set the basic properties of any line symbol. The Color property controls the color of the basic line (it does not affect any line decoration that may be present—see the ILineProperties interface) and can be set to any IColor object. The Color property is set to black by default except for the SimpleLineSymbol, which has a default of mid-gray. The Width property sets the overall width of a line, and its units are points. Note that for a HashLineSymbol, the Width property sets the length of each hash—see HashLineSymbol for more information. The default width is 1 for all line symbols except MarkerLineSymbol, which has a default width of 8.

Types of Line Symbol

A line symbol represents how a one-dimensional feature or graphic is drawn. Straight lines, polylines, curves, and outlines can all be drawn with a line symbol. There are five different types of line symbols you can use.

Line Symbol Width


The width of a line symbol is in printer's points—about 1/72 of an inch.

Fill Symbol

The IFillSymbol interface represents the two properties—Color and Outline—all types of fill symbols have in common.

The IFillSymbol interface, inherited by all the specialist fill symbols in ArcObjects, has two read_write properties. The Color property controls the color of the basic fill as described below and can be set to any IColor object.

Fill Symbol Default Colors


The Outline property sets an ILineSymbol object, which is drawn as the outline of the fill symbol. By default, the outline is a solid SimpleLineSymbol, but you can use any type of line symbol as your outline. Note that the outline is centered on the boundary of the feature; therefore, an outline with a width of 5 will overlap the fill symbol by a visible amount.


Types Of Fill Symbols


A fill symbol specifies how the area and outline of any polygon is to be drawn.

 

Text Symbol

The TextSymbol coclass provides the object that is used to symbolize text in graphic elements, annotation, labels, and other places. A TextSymbol defines much more than just a font. Its three main interfaces, ITextSymbol, ISimpleTextSymbol, and IFormattedTextSymbol, control exactly how the text appears and how the individual characters are displayed. Extended ASCII characters are supported by the TextSymbol.

The ITextSymbol interface is the primary interface for defining the characteristics of a text and is inherited by the ISimpleTextSymbol and IFormattedTextSymbol interfaces and therefore may not need to be declared specifically. It contains the Font property, which is the first logical step to defining a new TextSymbol. To set a Font, you should first create a COM font object. Using the IFontDisp interface of your font, you should set the Name of the font. You should also set whether or not your IFontDisp is italic, bold, strike-through, or underlined and set its CharacterSet and weight. In Visual Basic, you can use the StdFont object, which provides VB's standard implementation of the COM font object.

[Visual Basic 6.0]
Dim pFnt As stdole.IFontDisp
Set pFnt = New stdole.StdFont
pFnt.Name = "ESRI Cartography"
pFnt.Bold = True
Now you can set the Font and also set the Color (as any coclass supporting IColor) and a Size (in points). The Text property is used for a standalone TextSymbol object only (such as a TextSymbol in a style file); a TextElement will draw text according to the Text property of the TextElement coclass. Set the HorizontalAlignment and VerticalAlignment relative to the text anchor as shown below.

Each font may include different character sets to allow for different alphabets and symbology. For most applications, you won't need to swap character sets from the default. The StdFont object is defined in the stdole2.tlb type library, a reference to which is included, by default, in all standard VB projects. Other development environments provide a similar implementation. If no generic Font class is available the esriSystemUI.SystemFont class can be used - it provides similar functionality to tht of the stdole2.Font class. If the TextSymbol is used to draw text to a point, not along a line (see TextPath), you can use the Angle property to rotate the text string. The Angle property specifies the angle of the text baseline, in degrees from the horizontal, and defaults to zero. For Hebrew and Arabic fonts, set the RightToLeft property to True to lay the text string out in a right-to-left reading order. For any existing TextSymbol, the actual size in x and y directions can be calculated using the GetTextSize method. Having set a Size that defines the font height, the GetTextSize method will calculate the actual height and length of the symbol in points. Note that the GetTextSize method ignores the TextPath property if it is set through the ISimpleTextSymbol interface. GetTextSize is useful for calculating text placements on a PageLayout or whether a text string should be truncated to fit within a certain space. The use of this method is shown below, where pDisplay is the IDisplay of the PageLayout or Map that the TextSymbol belongs to, and pTextSymbol is a valid TextSymbol. Note that the StartDrawing and FinishDrawing calls are necessary to make sure the hDC of the display is valid. The dblX and dblY variables are populated respectively with the height and length of the text parameter when drawn with the pTextSymbol symbol.

[Visual Basic 6.0]
Dim dblX As Double, dblY As Double
pDisplay.StartDrawing 0, esriNoScreenCache
pTextSymbol.GetTextSize pDisplay.hDC, pDisplay.DisplayTransformation, "My Text", dblX, dblY
pDisplay.FinishDrawing

Chart Symbol

 

A 3DChartSymbol is an abstraction of the three types of chart symbol. It represents a marker symbol, which can be used by a ChartRenderer to symbolize geographical data by multiple attributes. Although they are generally used by a ChartRenderer, if all the properties are set appropriately you can also use the symbol as a MarkerSymbol to symbolize an individual Feature or Element. The following sections describe how to set up the different coclasses that implement I3DChartSymbol. For more information on using these coclasses as part of a ChartRenderer, see the sections on feature renderers in this chapter.

IChartSymbol is used to calculate the size of bars or pie slices in a chart symbol. The maximum attribute value that can be represented on the chart is used to scale the other attribute values in a chart. You should always set this property when creating a 3DChartSymbol. When creating a ChartRenderer, you should have access to the statistics of your FeatureClass—you can use these statistics to set the MaxValue property to the maximum value of the attribute or attributes being rendered. For example, if there are two fields rendered with a chart symbol, one containing attribute values from 0 to 5 and one containing attribute values from 0 to 10, set MaxValue to 10.

[Visual Basic 6.0]
Dim pChartSymbol as IShartSymbol
Set pChartSymbol = New BarChartSymbol
pChartSymbol.MaxValue = 10
The Value property contains an array of values indicating the relative height of each bar or width of each pie slice. If using the ChartSymbol in a ChartRenderer, you do not need to set this property. The Value array is populated repeatedly during the draw process by the ChartRenderer, using attribute values from the specified attribute Fields from the FeatureClass coclass to create a slightly different symbol for each Feature. All Values are set back to 0 after the draw has completed. If you wish to use the symbol independently of a ChartRenderer, you should set the Value array with the values you wish to use in the bar or pie chart.

Display Feedbacks

The set of objects that implement the IDisplayFeedback interface gives you fine-grained control over customizing the visual feedback when using the mouse to form shapes on the screen display. You can direct the precise visual feedback for tasks, such as adding, moving, or reshaping features or graphic elements. The objects can also be used without creating any features or elements for a task, such as measuring the distance between two points. Typically, you would use the display feedback objects within code that handles the mouse events of a tool based on the ITool or IUIToolControl interfaces, such as Mouse_Down and Mouse_Move. Which mouse events to program depends on the task at hand. For example, when adding a new envelope, you would program the display feedback objects in the Mouse_Down, Mouse_Move, and Mouse_Up events. Or, when digitizing a new polygon, you would program the Mouse_Down, Mouse_Move, and Mouse_DblClick events. When you are collecting points with the mouse to pass to the display feedbacks, you can use the ToMapPoint method on IDisplayTransformation to convert the current mouse location from device coordinates to map coordinates. Although the feedback objects (excluding the GroupFeedback object) all have common functionality, their behavior does vary. These variations can be divided as follows:
  1. Feedbacks that return a new geometry. The interfaces for these objects have a Stop method that returns the new geometry. These objects are NewEnvelopeFeedback, NewBezierCurveFeedback, NewDimensionFeedback, NewLineFeedback, NewPolygonFeedback, MoveEnvelopeFeedback, MoveLineFeedback, MovePointFeedback, MovePolygonFeedback, BezierMovePointFeedback, LineMovePointFeedback, PolygonMovePointFeedback, ReshapeFeedback, ResizeEnvelopeFeedback, and StretchLineFeedback.
  2. Feedbacks that are for display purposes only. The developer is required to calculate the new geometry. For example, you can use the start and end mouse locations and calculate the delta x and delta y shifts, and then you can update or create the geometry from this. These feedback objects are MoveGeometryFeedback, MoveImageFeedback, NewMultiPointFeedback, and VertexFeedback.
The objects are used within applications to allow graphic elements to be digitized and modified within the map (data view) and layout (layout view) and are also used by the ArcMap feature editing tools. Some of the feedback objects have a Constraint property that determines how the feedback behaves. These constraints can specify, for example, that a ResizeEnvelopeFeedback maintains the aspect ratio of the input Envelope. The details of these constraints are given with the individual feedbacks. The display feedback objects also provide some of the base functionality for the rubberband objects described earlier. You should use the rubberband objects first if they suit your requirements; select the display feedback objects if you want greater control over the user interface when modifying graphics or features. This greater control comes at the cost of more code.

The IDisplayFeedback interface is used to define the common operations on all of the display feedback operations. These include moving, symbolizing, and refreshing the display feedbacks as well as setting a display feedback object's Display property (for example, setting it to IActiveView::ScreenDisplay). The IDisplayFeedback interface is useful only in combination with one of the display feedback objects and its derived interfaces, for example, the NewPolygonFeedback object and its INewPolygonFeedback interface. Nearly all of the display feedback interfaces employ interface inheritance from IDisplayFeedback; hence, there is no need to use QueryInterface to access its methods and properties. Typically, the Display and Symbol properties would be set when a display feedback object is initialized, while the MoveTo method would be called in a mouse move event. Setting the Symbol property is optional. If not set, a default symbol is used. The Refresh method is used to redraw the feedback after the window has been refreshed (for example, when it is activated again), and it should be called in response to the Tool's Refresh event. This would be UIToolControl_Refresh for UIToolControl in VBA, or ITool_Refresh if you are implementing ITool in VB or VC++. The hDC parameter, which is required by the Refresh method, is actually passed into the subroutine for you. In the following example, a check is first made to see if m_pNewPolyFeedback, which is a member variable NewPolygonFeedback object, has been instantiated yet, that is, if the user is currently using the feedback. If it has been instantiated, then the Refresh method is called.

[Visual Basic 6.0]
Private Sub UIToolControl1_Refresh(byVal hDC As Long)
  If Not m_pNewPolyFeedback Is Nothing Then
    m_pNewPolyFeedback.Refresh hDC
  End If
End Sub

 

The following code example shows how to use the IDisplayFeedback interface with the INewEnvelopeFeedback interface to create a display feedback that will allow the user to add a new polygon. Note that this code simply demonstrates the visual feedback; further code is required if you wish to add that drawn shape as a map element or feature. The new envelope feedback object is declared as a member variable as follows:

[Visual Basic 6.0]
Private pNewEnvFeed As INewEnvelopeFeedback

 

Other objects are locally declared—pEnv as IEnvelope, pScreenDisp as IScreenDisplay, pLineSym as ISimpleLineSymbol, and pStartPoint and pMovePoint as IPoint. The following code would be placed in the Mouse_Down event to set up the Display and Symbol properties and to call INewEnvelopeFeedback::Start with the current mouse location in map units.


[Visual Basic 6.0]
Set pNewEnvFeed = new NewEnvelopeFeedback
Set pNewEnvFeed.Display = pScreenDisp
Set pNewEnvFeed.Symbol = pLineSym
pNewEnvFeed.Start pStartPoint
The following line of code would be placed in the Mouse_Move event to move the display feedback to the current mouse location in map units, using the MoveTo method from IDisplayFeedback.

[Visual Basic 6.0]
pNewEnvFeed.MoveTo pMovePoint
The following line of code would be placed in the Mouse_Up event to return the result using the Stop method from INewEnvelopeFeedback.

[Visual Basic 6.0]
Set pEnv = pNewEnvFeed.Stop

Rubber Bands

The RubberPoint, RubberEnvelope, RubberLine, RubberPolygon, RubberRectangularPolygon, and RubberCircle coclasses, all implementing the IRubberBand interface, allow the user to digitize geometries on the display using the mouse—either to create whole new geometry objects or to update existing ones. As such, they can be viewed as simple versions of the feedback objects that are covered later in this chapter. Some examples of uses for these rubberbanding objects include dragging an envelope, forming a new polyline, or moving a point. Each of the above classes supports the IRubberBand interface, but the behavior depends on the class used.

The IRubberband interface has two methods, TrackExisting and TrackNew, which are used to move existing geometries and create new geometries, respectively. These methods would normally be called from within the code for a tool's Mouse_Down event, and they would then handle all subsequent mouse events themselves. They would capture subsequent mouse and keyboard events, such as Mouse_Move, Mouse_Up, and Key_Down events, and would complete when they received a Mouse_Up event or abort if the Esc key was pressed. Because the events are being trapped by the rubberband objects, no events will be raised in VBA. This means that very little code is required to use them, although this comes at the expense of flexibility. Typically, these objects would be used for simple tasks such as dragging a rectangle or creating a new line. Operations that involve moving the vertices of existing geometries would require the feedback objects to be used instead. The TrackNew method takes two parameters: an IScreenDisplay object representing the ScreenDisplay to draw the Rubberband and an ISymbol object to use for drawing the rubberband. If no symbol is given, then the default symbol is used. The method returns a new geometry object—the type of geometry returned depends on which class was used. RubberPolygon class returns a Polygon object. If the method fails to complete (that is, if the user presses the Esc key), then Nothing is returned. The types of geometry that are returned for TrackNew by each of the rubber objects are as follows: The following code shows how to use the TrackNew method of IRubberBand with a RubberLine object.

[Visual Basic 6.0]
Private Sub UIToolControl1_MouseDown(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)
  Dim pRubberLine As IRubberBand
  Dim pGeom As IGeometry
  Dim pMXDoc As IMxDocument

  ' QI for the MXDocument interface
  Set pMXDoc = ThisDocument

  ' Create a new Rubber Line object
  Set pRubberLine = New RubberLine

' Track new polyline on current document's display using default symbol
  Set pGeom = pRubberLine.TrackNew(pMXDoc.ActiveView.ScreenDisplay, Nothing)
End Sub

 

The TrackExisting method also takes ScreenDisplay and Symbol parameters as well as an IGeometry representing the input Geometry. This last parameter represents the geometry to move on the screen and is passed by reference so that it may be altered by the rubberband operation. The method returns a Boolean, which will be True unless the operation was interrupted by the user pressing the Esc key. The method will do nothing if the Geometry that is passed in does not intersect the current mouse location. The types of geometry that are expected by TrackExisting for each of the rubber objects are as follows:

The following code illustrates how to move an existing polygon using the TrackExisting method of IRubberBand with a RubberPolygon object. pGeomPoly is declared as an IPolygon and is used to represent the Polygon to be moved.

[Visual Basic 6.0]
Private Sub UIToolControl1_MouseDown(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)
  Dim pRubberPoly As IRubberBand
  Dim pMXDoc As IMxDocument
  Dim Success As Boolean

  ' QI for the MXDocument interface
  Set pMXDoc = ThisDocument

  ' Create a new Rubber Polygon object
  Set pRubberPoly = New RubberPolygon

  ' Move an existing Polygon on current doc's display using default symbol
  Success = pRubberPoly.TrackExisting(pMXDoc.ActiveView.ScreenDisplay, Nothing, pGeomPoly)
End Sub

Trackers

There are three kinds of selection trackers:

The PointTracker object is not currently useful. Moving and resizing of point elements is handled by envelope trackers, the size of the envelope corresponding to the symbolized point. Although the selection trackers are coclasses, you would only cocreate one if you were building your own custom element when implementing IElement::SelectionTracker

.
The envelope tracker operates on all element type


The line tracker and polygon tracker lets the user manipulate the vertices of polylines and polygons.


The callout tracker lets the user manipulate text callouts.

The ISelectionTracker interface controls the selection handle user interface. You might use ISelectionTracker in order to provide different behavior than that of the standard ArcMap interface, for example, the Element Movement tool that snaps elements to a grid. However, it is more likely that you will use this interface when building a custom object such as an element. You can gain access to selection trackers with IElement::SelectionTracker, IElementEditVertices::GetMoveVerticesSelectionTracker, or IGraphicsContainerSelect::SelectionTracker. When using IElement, you will get either an envelope tracker or edit vertices tracker, depending on the state of the element. This code example ensures that an envelope tracker is returned—if the element has a vertex edit tracker, it is changed to a envelope tracker and the document is refreshed.

[Visual Basic 6.0]
Public Sub EnsureEnvelopeTracker(pActiveView As IActiveView, pElement As IElement)
  Dim pScreenDisplay As IScreenDisplay
  Set pScreenDisplay = pActiveView.ScreenDisplay

  If (TypeOf pElement Is IElementEditVertices) Then
    Dim pElemVert As IElementEditVertices
    Set pElemVert = pElement

    If (pElemVert.MovingVertices) Then
      pElemVert.MovingVertices = False
      pActiveView.PartialRefresh esriViewGraphicSelection, Nothing, pElement.SelectionTracker.Bounds(pScreenDisplay)
    End If
  End If
End Sub

 

After obtaining a reference to a selection tracker, always set the Display property before using it. The Geometry property of a selection tracker applies to the tracker, not the element: for envelope trackers, the geometry is a polygon created from the envelope shape; for vertex edit trackers, the geometry is a polygon or polyline as appropriate. The Geometry property is updated when the user finishes reshaping the element with the selection tracker. The HitTest method provides information about the position of the mouse. The returned values are defined by esriTrackerLocation: The enumeration names are most relevant to envelope trackers, but HitTest can also be used with vertex edit trackers and callout trackers. In these cases, the returned values are LocationNone, LocationInterior, and LocationTopLeft. Many of the ISelectionTracker methods—for example, OnMouseDown—correspond to user interface events. When controlling a selection tracker with a user interface tool, pass on the tool events to the selection tracker, for example:


[Visual Basic 6.0]
Private Sub OnMouseMove(ByVal button As Long, ByVal shift As Long, ByVal x As Long, ByVal y As Long)
  If Not m_pSelTracker Is Nothing Then
    ' Pass on the mouse move event to selection tracker
    m_pSelTracker.OnMouseMove button, shift, x, y
  End If
End Sub

 

QueryMoveFeedback and QueryResizeFeedback return the feedback objects that the selection tracker is using. Draw is called by ArcMap if the element is selected, so normally you do not need to use this method (though it is important if you implement your own custom selection tracker).

The CancelTracker object is the favorite class of many users, though most probably don't realize it. Have you ever started a process and realized as soon as you did that it wasn't what you wanted? If the process employed the CancelTracker object, then you would be able to hit the escape key and halt the process before it had completed. The CancelTracker object is the object used by ArcObjects to monitor the Esc key (optionally, the space bar and mouse clicks as well) and terminate processes at the request of the user. A CancelTracker is typically handed into or created just prior to functions that execute a lengthy operation. Just before such operations begin, ITrackCancel::Reset must be called; Reset sets the state of the CancelTracker to uncancelled and returns the internal counter, which is used to update progression to zero. Within the innermost loop of the operation, ITrackCancel::Continue should be called to check whether the user has canceled the operation. By default, a cancellation occurs under the following circumstances:

If any of these actions occurs, the ITrackCancel::Continue method will return false and the operation's logic should then use this indicator to exit the loop. Any object that exposes IProgressor or IStepProgressor, such as the ProgressDialog object, can be bound to the CancelTracker so that it will be updated correctly and efficiently and with no additional code within the operation itself. Once the progressor is connected to the CancelTracker via the Progressor property, it will be updated automatically as the operation is executed. If the progressor is a step progressor, the MaxRange should be set to equal the number of iterations that the operation will progress through; this number should also match the number of times Continue will be called in the operation's innermost loop. In order for COM and various other parts of Windows to work correctly and responsively, Windows messages must be processed at regular intervals. For this reason, the CancelTracker's implementation will process noninput (mouse, keyboard)-related messages every second during the operation if any such messages are pending. This default frequency may be changed utilizing the ITrackCancel::CheckTime property. As a developer, you may use the CancelTracker several ways. Some ArcObjects commands (such as IActiveView::Output) take a CancelTracker object as an input parameter as the following code snippet demonstrates:

[Visual Basic 6.0]
Dim pCancel as ITrackCancel
Set pCancel = New CancelTracker
PaCTIVEvIEW.Output <OLE_handle>, <screen resolution>, <pixel bounds>, <visible bounds>, pCancel

 

In this case, you can provide cancel capabilities by simply creating a CancelTracker object and passing it in to the Output method. The Output method will then take care of monitoring the Esc button and canceling the process if the user chooses to. Another way to use a CancelTracker object is similar to the process above, but you as the developer are responsible for monitoring the object. An approach of this type would be used when the execution of your code could take a considerable amount of time and you want to give the user the option of canceling out of the process. The following VBA code demonstrates this process. The code is designed to loop through a set of selected network features and run the Connect method on them to ensure they are connected to the network. The CancelTracker object is included for aborting the process if the user accidentally selects too many features or just wants the process to stop.


[Visual Basic 6.0]
Dim m_pTrackCancel As ITrackCancel


Sub testCancel()
  Dim pEd As IEditor, pEnumSel As IEnumFeature, pFeat As IFeature
  Dim pNetFeat As INetworkFeature, pUID As New UID

  pUID = "esriEditor.Editor"
  Set pEd = Application.FindExtensionByCLSID(pUID)

	Set pEnumSel = pEd.EditSelection
  Set pFeat = pEnumSel.Next

  Set m_pTrackCancel = New CancelTracker
  pEd.StartOperation
  Do While Not pFeat Is Nothing
    If (TypeOf pFeat Is INetworkFeature) Then
      Set pNetFeat = pFeat
      pNetFeat.Connect
    End If

    `Check for a cancel
    If (Not m_pTrackCancel.Continue) Then
      MsgBox "Canceled!"
      pEd.StopOperation "Connect network features."
      Exit Sub
    End If

    Set pFeat = pEnumSel.Next
  Loop

  pEd.StopOperation "Connect network features."
End Sub
This code could also be used in conjunction with a ProgressDialog object to provide a dialog box with a Cancel button to the user. For an example of how to use a ProgressDialog object with a CancelTracker object, see the Developer Sample `Convert AV3 to AV8 Attribute Indexes'.

 

Representations

 

A RepresentationClass is also called a feature class representation. It is associated with a collection of RepresentationRules to symbolize features and store that information in the geodatabase. It allows the geometry and properties of features to be altered from the rule without disrupting the associated spatial data. Representations (also called as feature representations) are representations of individual features participating in a RepresentationClass. RepresentationClass, RepresentationRules and Representation classes are objects in esriGeodatabase library.

RepresentationRules is a collection of one or more individual RepresentationRule objects which are used to categorize features in a geodatabase into groups. A regular representation rule consists of multiple layers of basic symbols which are BasicMarkerSymbol, BasicLineSymbol or BasicFillSymbol for drawing markers, LineStrokes and Fill Patterns. More complex symbology can be achieved by including one or more GeometricEffects in a representation rule. A GeometricEffect is a dynamic process that alters geometry at draw time. It can even change geometry type. For example, point, line or polygon geometries can be processed through a GeometricEffectBuffer to produce buffer polygons around them.

All representation rule objects support IRepresentationRule interface. Use LayerCount and Layer properties to get the total number of symbol layers and to retreive individual symbol layers at a given index. InsertLayer method can be used to insert new symbol layer to a representation rule. You can specify the index and basic symbol as input values. Use RemoveLayer method to remove a specific symbol layer present in the representation rule given its index.

RepresentationRule class also implements IRepresentationRuleInit interface which is useful for transforming a regular ArcGIS symbol to a BasicSymbol. Note that since only BasicSymbols are used to construct a RepresentationRule, it is important to transform a regular Symbol to a BasicSymbol in order to use with representations.

There are three different types of basic symbols: BasicMarkerSymbol for markers, BasicLineSymbol for line strokes and BasicFillSymbol for fill patterns. All Basic symbol classes implement IBasicSymbol interface.

BasicMarkerSymbol

Basic Marker Symbols

 

A BasicMarkerSymbol is used to draw marker symbols and has Marker, Size and Angle as its graphic attributes. These properties can be managed using the IGraphicAttributes interface. The attributes are listed in the esriGraphicAttribute enumeration and are prefixed with esriGAMarker such as esriGAMarkerSize etc. All BasicMarkerSymbol classes implement IBasicMarkerSymbol interface which has a single property MarkerPlacement on it. A MarkerPlacement class is a marker placement style for placing markers. You can place either single or multiple number of markers depending on what MarkerPlacement you choose. For example, OnPoint places a single marker over a point, while AlongLine places multiple markers along a line. The default marker placement for any basic marker symbol is OnPoint. Use IMarkerPlacement interface to create and manipulate the properties of placement styles. esriMarkerPlacementAttributes enumeration lists graphic attributes for all marker placements where each attribute is prefixed with esriGA(name)(attribute) such as esriGAInsidePolygonGridAngle where InsidePolgon is marker placement style and GridAngle is its graphic attribute.

You must implement IMarkerPlacement, IGraphicAttributes and IPersistVariant interfaces in order to create custom MarkerPlacements using Visual Basic 6.0. IMarkerPlacement interface has AcceptGeometryType property which determines acceptable input geometry types (AcceptGeometryType property returns true), Reset method useful to set the placement style with an acceptable input geometry, and Next method to retrieve the set of output affine transformations that result due to processing of input geometry by the placement style. IGraphicAttributes interface contains the list of graphic attributes a marker placement will contain and IPersistVariant interface is useful for persisting the custom MarkerPlacement.

The following table lists the different types of marker placement styles available along with their valid input geometry types and list of graphic attributes:

Marker Placement Valid Input Geometry Graphic Attributes
AlongLine Line, Polygon Step, Endings, Control Points, Angle to Line
AtExtremities Line Type, Offset, Angle to Line
Decoration Line, Polygon Number of Positions, Begin Gap, End Gap, Flip All, Flip First, Angle to Line
InsidePolygon Polygon X - Step, Y - Step, Grid Angle, Shift Odd Rows, X-Offset, Y-Offset, Clipping
OnLine Line, Polygon Position, Relative To, Angle to Line
OnPoint Point X-Offset, Y-Offset
PolygonCenter Polygon X-Offset, Y-Offset, Center Method, Center Clipping
RandomAlongLine Line, Polygon Step, Endings, Control Points, Random, Skew Effect
RandomInPolygon Polygon X-Offset, Y-Offset, Clipping
VariableAlongLine Line, Polygon Step, Endings, Control Points, Min Zoom, Max Zoom, Method, Line

 

For an example of how to write a custom MarkerPlacement object, see the Developer Samples `Marker Placement Around Point' and 'Marker Placement On Control Points'.

The following function shows the usage of IMarker and IGraphics interfaces to create new markers. A new geometry and representation rule are created for this purpose. The markers created can then be used to draw BasicMarkerSymbols.


[Visual Basic 6.0]
Public Function CreateMarker() As IRepresentationMarker
    Dim pMarker As IRepresentationMarker
    Dim pGeom As IGeometry
    Dim pSegCol As ISegmentCollection
    Dim pEnvelope As IEnvelope
    Dim pFillPattern As IFillPattern
    Dim pColor As IRgbColor
    Dim pGA As IGraphicAttributes
    Dim pRR As IRepresentationRule
    Dim pBasicFill As IBasicFillSymbol
    Dim pGraphics As IRepresentationGraphics

    Set pMarker = New RepresentationMarker
    Set pGraphics = pMarker

    Set pGeom = New Polygon
    Set pSegCol = pGeom
    Set pEnvelope = New Envelope
    pEnvelope.PutCoords -0.5, -0.5, 0.5, 0.5
    pSegCol.SetRectangle pEnvelope

    Set pFillPattern = New SolidColorPattern
    Set pColor = New RgbColor
    pColor.Red = 0
    pColor.Green = 0
    pColor.Blue = 250
    Set pGA = pFillPattern
    pGA.Value(0) = pColor   'color
    Set pBasicFill = New BasicFillSymbol
    Set pBasicFill.FillPattern = pFillPattern
    Set pRR = New RepresentationRule
	pRR.InsertLayer 0, pBasicFill
    pGraphics.Add pGeom, pRR    'Add graphics to marker

    Set CreateMarker = pMarker

End Function

The following code shows how to assign a BasicMarkerSymbol with the marker created using CreateMarker function:


[Visual Basic 6.0]
    'Create new Basic Marker Symbol
    Dim pBasMarker As IBasicMarkerSymbol
    Dim pGraphicAttributes As IGraphicAttributes
    Set pBasMarker = New BasicMarkerSymbol
    Set pGraphicAttributes = pBasMarker
    'Assign attributes
    pGraphicAttributes.Value(1) = CreateMarker()        'Marker symbol
    pGraphicAttributes.Value(2) = 5                     'Size of marker
    pGraphicAttributes.Value(3) = 30                    'Angle of marker

Note: Unlike all other graphic attributes, the graphic attribute index for a BasicMarkerSymbol starts with 1 and not 0.

 

BasicLineSymbol

A BasicLineSymbol is used to draw stroke symbols. All BasicLineSymbol classes implement IBasicLineSymbol interface which has a single property LineStroke on it. A LineStroke has Width, Caps, Joins and Color for its graphic attributes. These properties can be manipulated using the IGraphicAttributes interface. The attributes are listed in the esriGraphicAttribute enumeration and are prefixed with esriGAStroke such as esriGAStrokeWidth etc. Use ILineStroke interface to create and manipulate the properties of a new stroke symbol.

 

BasicFillSymbol

BasicFillSymbol Fill Patterns: Solid, Hatch and Gradient

A BasicFillSymbol is used to draw Fill symbols. All BasicFillSymbol classes implement IBasicFillSymbol interface which has a single property FillPattern on it. There are three different types of fill patterns: SolidColorPattern has Color, GradientPattern has Color1, Color2, pattern Style, Interval, Percent, Algorithm, Angle and LinePattern has Color, Width, Angle, Step, Offset as graphic attributes. These properties can be manipulated using the IGraphicAttributes interface. The attributes are listed in the esriGraphicAttribute enumeration and are prefixed with esriGA(fill pattern type) such as esriGASolidColorPatternColor etc. Use IFillPattern interface to create and manipulate the properties of a new Fill Pattern symbol.

 

GeometricEffect and GeometricEffects

GeometricEffects are dynamic processes that alter the geometry of features. A single representation rule can contain multiple geometric effects, functioning in sequence to create complex symbols. When a single RepresentationRule object is applied with a chain of geometric effects, the end result of applying the chain of effects can be considered and managed as a single Geometric Effect. For this reason, RepresentationRule class inherits both IGeometricEffect and IGeometricEffects interfaces. The result of geometric effects applied on a rule are directly passed onto all basic symbol layers present within the rule for drawing features. While IGeometricEffects interface is useful to browse through individual geometric effects participating in the rule, IGeometricEffect interface is useful to manage the chain of multiple geometric effects as a single geometric effect.

For example, if there are two geometric effects GeometricEffectDash and GeometricEffectOffset applied on linestrokes in sequential order, then you can use IGeometricEffects interface to get the results for individual Dash or Offset effects but not both. However, you can use IGeometricEffect interface to get the result of applying a combination of Dash and Offset effects as a single effect.

Chain of Effects: GeometricEffectDash and GeometricEffectOffset (Original line represented with solid color)

For an example of how to write a custom GeometricEffect object, see the Developer Sample `Geometric Effect Sine Wave'.

Important Note: RepresentationRule CoClass does not implement IGraphicAttributes. Thus, when IGeometricEffect is used to reference a RepresentationRule in order to retrieve the chain of effects on this rule as a single effect, IGraphicAttributes interface must not be used to get back the graphic attributes present for these effects.

The following code shows the usage of IGeometricEffects and IGeometricEffect interfaces on a Representation Rule and can be applied to BasicSymbols as well.


[Visual Basic 6.0]
    Dim pRepRules As IRepresentationRules
    Dim pRule As IRepresentationRule
    Dim pRuleGeometricEffect As IGeometricEffect
    Dim pRuleGeometricEffects As IGeometricEffects
    Dim pGE As IGeometricEffect
    Dim i As Integer, sClassName As String

    Set pRepRules = pRepClass.RepresentationRules
    Set pRule = pRepRules.Rule(3) 'Representation Rule with Index value = 3
    Set pRuleGeometricEffect = pRule   'Get multiple geometric effects applied to this rule as a single effect
    Set pRuleGeometricEffects = pRule  'Get multiple geometric effects applied to this rule as a collection of individual effects
    'Using pRuleGeometricEffects get each effect separately
    For i = 0 To pRuleGeometricEffects.Count - 1
       Set pGE = pRuleGeometricEffects.Element(i)
       Dim pGA As IGraphicAttributes
       Set pGA = pGE
       sClassName = pGA.ClassName
       Debug.Print "Type of GeometricEffect at index = " & i + 1 & " : " & sClassName
    Next i

The following table lists the different types of geometric effects available along with their valid input and output geometry types and graphic attributes:

Geometric Effect Input Geometry : Output Geometry Graphic Attributes
Radial Point : Line Angle, Length
Buffer Point : Polygon, Line : Polygon, Polygon : Polygon Size
Reverse Line : Line Reverse
Simplify Line : Line, Polygon : Polygon Tolerance
Dashes Line : Line, Polygon : Line Pattern , Endings
OffsetCurve Line : Line, Polygon : Polygon Offset, Method, Simple
Cut Line : Line, Polygon : Line Begin , End
SmoothCurve Line : Line, Polygon : Polygon Flat , Tolerance
AddControlPoints Line : Line, Polygon : Polygon Tolerance
EnclosingPolygon Line : Polygon, Polygon : Polygon Method
Donut Polygon : Polygon Width

 

Graphic Attributes and Graphic Attribute Types

GraphicAttributes are attributes used to define graphical properties for all MarkerPlacements and GeometricEffects, BasicMarkerSymbol, LineStroke, GradientPattern, LinePattern and SolidColorPattern objects. A RepresentationClass also has a single graphic attribute for controlling its visibility property. All graphic attributes are enumerated into esriGraphicAttribute, esriGeometricEffectAttributes and esriMarkerPlacementAttributes enumerations.

IGraphicAttributes interface is the basic interface that any class will have to implement in order to have a list of its own graphic attributes. Use ClassName property on this interface in conjunction with either IGeometricEffect or IMarkerPlacement interfaces to determine which Geometric Effect or Marker Placement object is being used currently. esriGraphicAttributeType enumeration has a list of all available attribute types which are boolean, color, double, integer, marker, text, dash, enum and size.

Basic Marker Symbols, Modifying Graphic Attributes: Color, Angle, Size, and Transparency

 

The following subroutine shows how to derive the list of graphic attributes for all symbol layers present in a representation rule. A reference to a RepresentationClass is passed as input parameter. The first representation rule present in the collection of represenation rules object is used here.


[Visual Basic 6.0]
Public Sub IRepresentationRule_Layer(pRepClass As IRepresentationClass)
    Dim pRepRule As IRepresentationRule
    Dim pRepRules As IRepresentationRules
    Dim lID As Long
    Dim pBasicSymbol As IBasicSymbol
    Dim i As Integer
    Dim pGA As IGraphicAttributes
    Dim pBasMarkerSymbol As IBasicMarkerSymbol
    Dim pBasLineSymbol As IBasicLineSymbol
    Dim pBasFillSymbol As IBasicFillSymbol

    Set pRepRules = pRepClass.RepresentationRules
    pRepRules.Reset
    pRepRules.Next lID, pRepRule    'Set pRepRule with very first rule
    For i = 0 To pRepRule.LayerCount - 1
        Set pBasicSymbol = pRepRule.Layer(i)
        'Determine if this symbol is of type marker, line or fill symbol
        If TypeOf pBasicSymbol Is IBasicMarkerSymbol Then
            Set pBasMarkerSymbol = pBasicSymbol
            Set pGA = pBasMarkerSymbol
        ElseIf TypeOf pBasicSymbol Is IBasicLineSymbol Then
            Set pBasLineSymbol = pBasicSymbol
            Set pGA = pBasLineSymbol
        ElseIf TypeOf pBasicSymbol Is IBasicFillSymbol Then
            Set pBasFillSymbol = pBasicSymbol
            Set pGA = pBasFillSymbol
        End If
    Next i
End Sub

Map Context and Output Context

There are three reference frames which are used for data translation between geographic, map and output display context. These frames are:

  1. Geographic Reference Frame: A feature layer represents geographic data and may be re-projected prior to drawing the features onto a map.
  2. Map Reference Frame: This is an intermediate frame introduced to define a clear context in which geometric effects and all on-the-fly processing works. This frame is similar to the map sheet frame which is used with a 72 dpi graphic resolution centered at the center of the geographic spatial reference. The advantage of having the map reference frame is to provide a stable context for geometric effects and marker placement properties as this is in a graphic frame but independent of zoom levels and pan positions. All linear attributes (distance/length) are relative to this frame. For example, a 12 point offset is a 12 unit displacement in MRF. Effects will store these attributes in MRF units and use them without any transformation.
  3. Output Reference Frame: This consists of an output device, that displays the map with a zoom level which is not equal to the reference scale and a changed center position.

Reference Frames used by Representations

 

Use IMapContext and IOutputContext interfaces to get references to a MapContext and OutputContext objects.