Arranging MOLE graphics using manual decluttering
MainForm.vb
' Copyright 2010 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions.
' 

Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data
Imports System.IO
Imports System.Runtime.InteropServices

Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Controls
Imports ESRI.ArcGIS.ADF
Imports ESRI.ArcGIS.SystemUI
Imports ESRI.ArcGIS

Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.DefenseSolutions

Namespace ManualGroupDraw
  Public NotInheritable Partial Class MainForm
    Inherits Form
    #Region "class private members"

    Private m_mapControl As IMapControl3 = Nothing
        Private m_Random As New Random()
    Private m_MoleGroup As IMoleGroupElement = New MoleGroupElementClass()

    #End Region

    #Region "Constructor"

    Public Sub New()
            InitializeComponent()
    End Sub

    #End Region

    #Region "Form Event Handlers"

        Private Sub MainForm_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            ' get the MapControl
            m_mapControl = DirectCast(axMapControl1.Object, IMapControl3)

            ' get a map from the SDK sample data
            Dim dataPath As String = GetSdkDataPath() + "MilitaryOverlayEditor\"
            Dim defaultMxDoc As String = dataPath & "molebasemap.mxd"

            ' load the map into the map control
            If Me.m_mapControl.CheckMxFile(defaultMxDoc) Then
                Dim missing As Object = System.Reflection.Missing.Value
                Me.m_mapControl.LoadMxFile(defaultMxDoc, missing, missing)
            Else
                Dim errorMsg As String = "Could not load default map document - Application may not work!"
                errorMsg &= Environment.NewLine & defaultMxDoc
                System.Diagnostics.Trace.WriteLine(errorMsg)
                MessageBox.Show(errorMsg)
            End If
            ' begin with no decluttering
            cbDeclutter.SelectedIndex = 0
        End Sub

        Private Function GetSdkDataPath() As String
            'get the ArcGIS path from the registry
            Dim key As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\ESRI\ArcGIS_SXS_SDK")
            Dim path As String = Convert.ToString(key.GetValue("InstallDir"))

            'set the of the logo
            Dim str As String = System.IO.Path.Combine(path, "Samples\data\")
            If (Not System.IO.Directory.Exists(str)) Then
                MessageBox.Show("Path :" & str & " does not exist!")
                Return String.Empty
            End If

            Return str
        End Function

        Private Sub cbDeclutter_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles cbDeclutter.SelectedIndexChanged
            ' get the selected option from the combo box
            Dim declutterOptions As moleDeclutterOptionEnum() = {moleDeclutterOptionEnum.moleDeclutterNone, moleDeclutterOptionEnum.moleDeclutterLeader, moleDeclutterOptionEnum.moleDeclutterManual, moleDeclutterOptionEnum.moleDeclutterStack}
            Dim declutterOption As moleDeclutterOptionEnum = declutterOptions(cbDeclutter.SelectedIndex)
            If m_MoleGroup.DeclutterOption <> declutterOption Then
                ' the option has changed - set the new option and recalculate if necessary
                m_MoleGroup.DeclutterOption = declutterOption
                m_MoleGroup.EnableDeclutter = (declutterOption <> moleDeclutterOptionEnum.moleDeclutterNone)
                Dim groupElement As IGroupElement = TryCast(m_MoleGroup, IGroupElement)
                If declutterOption = moleDeclutterOptionEnum.moleDeclutterManual AndAlso groupElement.ElementCount > 0 Then
                    ' calculate the decluttered positions manually - in decimal degrees
                    Dim xStep As Double = 25
                    Dim xDeclutter As Double = -0.5 * groupElement.ElementCount * xStep
                    If xDeclutter < -180 Then
                        ' don't fall off the end of the world
                        xStep = 360 / groupElement.ElementCount
                        xDeclutter = -180 - 0.5 * xStep
                    Else
                        xDeclutter -= 0.5 * xStep
                    End If
                    Dim point As IPoint = New PointClass()
                    Dim moleDeclutterElement As IMoleDeclutterElement = TryCast(m_MoleGroup, IMoleDeclutterElement)
                    For i As Integer = 0 To groupElement.ElementCount - 1
                        ' set a declutter point for each element
                        ' these lines of code have no effect in stack or leader mode
                        Dim element As IElement = TryCast(groupElement.Element(i), IElement)
                        xDeclutter += xStep
                        point.PutCoords(xDeclutter, 45)
                        moleDeclutterElement.DeclutterElement(element, TryCast(point, IGeometry))
                    Next
                End If
                ' update the display
                m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
            End If
        End Sub

        Private Sub btnAddGroup_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnAddGroup.Click
            ' tell the user that we are busy for a few seconds, and don't let them press the button again
            Cursor = Cursors.WaitCursor
            btnAddGroup.Enabled = False
            cbDeclutter.Enabled = True

            ' tell MOLE to leave it cluttered, for now
            m_MoleGroup.DeclutterOption = moleDeclutterOptionEnum.moleDeclutterNone
            m_MoleGroup.EnableDeclutter = False

            ' generate some elements (vary the number of elements as much as desired)
            Dim point As IPoint = New PointClass()
            Dim groupElement As IGroupElement = TryCast(m_MoleGroup, IGroupElement)
            Dim symIDs As New DemoSymbolIDs()
            For i As Integer = 0 To 9
                ' create a MarkerElement with a MOLE symbol
                Dim moleSymbol As IMoleSymbol = New MoleMarkerSymbolClass()
                moleSymbol.SymbolID = symIDs(i)
                Dim markerElement As IMarkerElement = New MarkerElementClass()
                markerElement.Symbol = TryCast(moleSymbol, IMarkerSymbol)
                Dim element As IElement = TryCast(markerElement, IElement)

                ' add the element to the group at a random clustered location
                point.PutCoords(m_Random.Next(-15, 15), m_Random.Next(-15, 15))
                element.Geometry = TryCast(point, IGeometry)
                groupElement.AddElement(element)
            Next
            ' add the group to the map and update the view
            m_mapControl.ActiveView.GraphicsContainer.AddElement(TryCast(m_MoleGroup, IElement), 0)
            m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)

            ' tell the user that we are no longer busy
            Cursor = Cursors.Default
        End Sub

    #End Region

    #Region "Map Control Event Handlers"

        Private Sub axMapControl1_OnMapReplaced(ByVal sender As Object, ByVal e As IMapControlEvents2_OnMapReplacedEvent) Handles axMapControl1.OnMapReplaced
            'put the current document name in the status bar
            If m_mapControl.DocumentFilename IsNot Nothing Then
                statusBarXY.Text = System.IO.Path.GetFileName(m_mapControl.DocumentFilename)
            End If
        End Sub

        Private Sub axMapControl1_OnMouseMove(ByVal sender As Object, ByVal e As IMapControlEvents2_OnMouseMoveEvent) Handles axMapControl1.OnMouseMove
            statusBarXY.Text = String.Format("{0}, {1}  {2}", e.mapX.ToString("#######.##"), e.mapY.ToString("#######.##"), axMapControl1.MapUnits.ToString().Substring(4))
        End Sub

    #End Region
  End Class
End Namespace