Arranging MOLE graphics using manual decluttering
MainForm.cs
// 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.
// 

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;

using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.DefenseSolutions;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.SystemUI;


namespace ManualGroupDraw
{
  public sealed partial class MainForm : Form
  {
    #region class private members

    private IMapControl3 m_mapControl = null;
    private Random m_Random = new Random();
    private IMoleGroupElement m_MoleGroup = new MoleGroupElementClass();

    #endregion

    #region Constructor

    public MainForm()
    {
      InitializeComponent();
    }

    #endregion

    #region Form Event Handlers


        private string GetSdkDataPath()
        {
            //get the ArcGIS path from the registry
            Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ESRI\ArcGIS_SXS_SDK");
            string path = Convert.ToString(key.GetValue("InstallDir"));

            //set the of the logo
            string str = System.IO.Path.Combine(path, @"Samples\data\");

            if (!System.IO.Directory.Exists(str))
            {
                MessageBox.Show("Path :" + str + " does not exist!");
                return string.Empty;
            }

            return str;
        }

    private void MainForm_Load(object sender, EventArgs e)
    {
      // get the MapControl
      m_mapControl = (IMapControl3) axMapControl1.Object;

      // get a map from the SDK sample data
            string dataPath = GetSdkDataPath() + @"MilitaryOverlayEditor\";
      string defaultMxDoc = dataPath + "molebasemap.mxd";

      // load the map into the map control
      if (this.m_mapControl.CheckMxFile(defaultMxDoc))
      {
        object missing = System.Reflection.Missing.Value;
        this.m_mapControl.LoadMxFile (defaultMxDoc, missing, missing);
      }
      else
      {
        string errorMsg = "Could not load default map document - Application may not work!";
        errorMsg += "\n" + defaultMxDoc;
        System.Diagnostics.Trace.WriteLine (errorMsg);
        MessageBox.Show (errorMsg);
      }
      // begin with no decluttering
      cbDeclutter.SelectedIndex = 0;
    }
    
    private void cbDeclutter_SelectedIndexChanged(object sender, EventArgs e)
    {
      // get the selected option from the combo box
      moleDeclutterOptionEnum[] options = {
        moleDeclutterOptionEnum.moleDeclutterNone,
        moleDeclutterOptionEnum.moleDeclutterLeader,
        moleDeclutterOptionEnum.moleDeclutterManual,
        moleDeclutterOptionEnum.moleDeclutterStack
      };
      moleDeclutterOptionEnum option = options[cbDeclutter.SelectedIndex];
      if ( m_MoleGroup.DeclutterOption != option )
      {
        // the option has changed - set the new option and recalculate if necessary
        m_MoleGroup.DeclutterOption = option;
        m_MoleGroup.EnableDeclutter = ( option != moleDeclutterOptionEnum.moleDeclutterNone );
        IGroupElement groupElement = m_MoleGroup as IGroupElement;
        if ( option == moleDeclutterOptionEnum.moleDeclutterManual && groupElement.ElementCount > 0 )
        {
          // calculate the decluttered positions manually - in decimal degrees
          double xStep = 25;
          double xDeclutter = -0.5 * groupElement.ElementCount * xStep;
          if ( xDeclutter < -180 )
          {
            // don't fall off the end of the world
            xStep = 360 / groupElement.ElementCount;
            xDeclutter = -180 - 0.5 * xStep;
          }
          else
            xDeclutter -= 0.5 * xStep;
          IPoint point = new PointClass();
          IMoleDeclutterElement moleDeclutterElement = m_MoleGroup as IMoleDeclutterElement;
          for ( int i = 0; i < groupElement.ElementCount; ++i )
          {
            // set a declutter point for each element
            // these lines of code have no effect in stack or leader mode
            IElement element = groupElement.get_Element (i);
            xDeclutter += xStep;
            point.PutCoords (xDeclutter, 45);
            moleDeclutterElement.DeclutterElement (element, point as IGeometry);
          }
        }
        // update the display
        m_mapControl.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
      }
    }
    
    private void btnAddGroup_Click(object sender, EventArgs e)
    {
      // 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)
      IPoint point = new PointClass();
      IGroupElement groupElement = m_MoleGroup as IGroupElement;
      DemoSymbolIDs symIDs = new DemoSymbolIDs();
      for ( int i = 0; i < 10; ++i )
      {
        // create a MarkerElement with a MOLE symbol
        IMoleSymbol moleSymbol = new MoleMarkerSymbolClass();
        moleSymbol.SymbolID = symIDs[i];
        IMarkerElement markerElement = new MarkerElementClass();
        markerElement.Symbol = moleSymbol as IMarkerSymbol;
        IElement element = markerElement as 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 = point as IGeometry;
        groupElement.AddElement (element);
      }
      // add the group to the map and update the view
      m_mapControl.ActiveView.GraphicsContainer.AddElement (m_MoleGroup as IElement, 0);
      m_mapControl.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
      
      // tell the user that we are no longer busy
      Cursor = Cursors.Default;
    }

    #endregion

    #region Map Control Event Handlers

    private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
    {
      //put the current document name in the status bar
      if (m_mapControl.DocumentFilename != null)
        statusBarXY.Text = System.IO.Path.GetFileName(m_mapControl.DocumentFilename);
    }

    private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
    {
      statusBarXY.Text = string.Format("{0}, {1}  {2}", e.mapX.ToString("#######.##"), e.mapY.ToString("#######.##"), axMapControl1.MapUnits.ToString().Substring(4));
    }

    #endregion
  }
}