ArcObjects Library Reference  

MainForm

About the Using MOLE symbol-based graphics with interactive maps Sample

[C#]

MainForm.cs

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

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


namespace MoleSymbols
{
	public sealed partial class MainForm : Form
	{

		#region class private members


		private IPoint           m_currentMouseLocation = null;
		private int              m_dragStartTime        = 0;
		private bool             m_firstTime            = true;
		private IPoint           m_lastMouseClick       = new PointClass();
		private IMapControl3     m_mapControl           = null;
		private IDisplayFeedback m_moveFeedBack         = null;
		private Random           m_random               = new Random();
		private IEnvelope        m_selectedBounds       = new EnvelopeClass();
		private DemoSIC          m_sic                  = new DemoSIC();
		private int              m_unitCount            = 0;


		#endregion
		
		#region Constructor
		
		
		public MainForm()
		{
			InitializeComponent();
			
			m_lastMouseClick.PutCoords (0, 0);
			UpdateStatusBar();
			UpdateTitle();
		}
		
		
		#endregion
		
		#region Tool strip button event handlers
		
		
		private void tsbAdd200_Click (object sender, EventArgs e)
		{
			// this one takes a little while, especially when it's the first one chosen
			Cursor = Cursors.WaitCursor;

			// create concentric rings of units centered around where the user last clicked
			double centerLon = m_lastMouseClick.X;
			double centerLat = m_lastMouseClick.Y;
			const double circleRadiusInRad = 1.0;
			const int numberPerCircle = 10;
			for ( int i = 0; i < 200; ++i )
			{
				// draw a random symbol at the next position in the pattern
				double currentRadius = (i / numberPerCircle) * circleRadiusInRad + circleRadiusInRad;
				double currentAngle = (i % numberPerCircle) *  2.0 * 3.1415926536 / (double)numberPerCircle;
				DrawSymbol (
					CreatePoint(
						centerLon + (currentRadius * Math.Sin(currentAngle)),
						centerLat + (currentRadius * Math.Cos(currentAngle))
					),
					m_sic[m_random.Next()],
					true
				);
			}
			//refresh the display and restore the cursor
			axMapControl1.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
			Cursor = Cursors.Default;
		}


		private void tsbAddArea_Click (object sender, EventArgs e)
		{
			// create the symbol using a default symbol ID code (obstacle restricted area)
			IMoleSymbol moleSymbol = new MoleFillSymbolClass();
			moleSymbol.SymbolID = "GUMPOGR-------X";
			moleSymbol.TextLabels = GetLabels();

			// override the default fill color and outline symbol - these settings are optional
			//ILineSymbol lineSymbol = new SimpleLineSymbolClass();
			//lineSymbol.Color = GetRandomColor();
			//lineSymbol.Width = dRandom (1, 5);
			//IFillSymbol fillSymbol = moleSymbol as IFillSymbol;
			//fillSymbol.Outline = lineSymbol;
			//fillSymbol.Color = GetRandomColor();

			// create a new polygon geometry for this symbol (four points in this example)
			IPointCollection pointCollection = new PolygonClass();

			// center the polygon somewhere inside the current map extent
			IEnvelope extent = m_mapControl.ActiveView.Extent;
			double lat = dRandom (extent.YMin, extent.YMax);
			double lon = dRandom (extent.XMin, extent.XMax);
			
			// place the four corners somewhere within a specified threshold of the center
			const double threshold = 20;
			object missing = Type.Missing;
			pointCollection.AddPoint (CreatePoint(lon, dRandom(lat, lat + threshold)), ref missing, ref missing);
			pointCollection.AddPoint (CreatePoint(dRandom(lon, lon + threshold), lat), ref missing, ref missing);
			pointCollection.AddPoint (CreatePoint(lon, dRandom(lat - threshold, lat)), ref missing, ref missing);
			pointCollection.AddPoint (CreatePoint(dRandom(lon - threshold, lon), lat), ref missing, ref missing);

			// set up the graphic element with the random geometry
			IFillShapeElement fillShapeElement = new PolygonElementClass();
			fillShapeElement.Symbol = moleSymbol as IFillSymbol;
			IElement element = fillShapeElement as IElement;
			element.Geometry = pointCollection as IGeometry;

			// add the new element to the map and update the user interface
			m_mapControl.ActiveView.GraphicsContainer.AddElement (element, 0);
			m_mapControl.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
			++m_unitCount;
			UpdateTitle();
		}


		private void tsbAddLine_Click (object sender, EventArgs e)
		{
			// create the symbol using a default symbol ID code (fix task line)
			IMoleSymbol moleSymbol = new MoleLineSymbolClass();
			moleSymbol.SymbolID = "GUTPF---------X";
			moleSymbol.TextLabels = GetLabels();

			// override the default line color and width - these settings are optional
			//ILineSymbol lineSymbol = moleSymbol as ILineSymbol;
			//lineSymbol.Color = GetRandomColor();
			//lineSymbol.Width = dRandom (1, 5);
			
			// create a new line geometry for the symbol - this symbol requires two points
			IPointCollection pointCollection = new PolylineClass();

			// place the first endpoint of the line somewhere inside the current map extent
			IEnvelope ext = m_mapControl.ActiveView.Extent;
			double lat = dRandom (ext.YMin, ext.YMax);
			double lon = dRandom (ext.XMin, ext.XMax);
			object missing = Type.Missing;
			pointCollection.AddPoint (CreatePoint(lon, lat), ref missing, ref missing);

			// place the second endpoint somewhere within a specified threshold of the first
			const double threshold = 20;
			pointCollection.AddPoint (
				CreatePoint(
					dRandom(lon - threshold, lon + threshold),
					dRandom(lat - threshold, lat + threshold)
				),
				ref missing,
				ref missing
			);
			// set up the graphic element with the random geometry
			ILineElement lineElement = new LineElementClass();
			lineElement.Symbol = moleSymbol as ILineSymbol;
			IElement element = lineElement as IElement;
			element.Geometry = pointCollection as IGeometry;

			// add the new element to the map and update the user interface
			m_mapControl.ActiveView.GraphicsContainer.AddElement (element, 0);
			m_mapControl.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
			++m_unitCount;
			UpdateTitle();
		}


		private void tsbAddMoleSymbol_Click (object sender, EventArgs e)
		{
			// make this TSB exclusive both in the tool strip and in the AxToolbarControl
			// the primary logic is in axMapControl1_OnMouseDown
			if ( tsbAddMoleSymbol.Checked )
			{
				axToolbarControl1.SetBuddyControl (null);
				axToolbarControl1.Enabled = false;
				tsbSelect.Checked = false;
			}
			else
			{
				axToolbarControl1.SetBuddyControl (axMapControl1);
				axToolbarControl1.Enabled = true;
			}
		}


		private void tsbMoveUnits_Click (object sender, EventArgs e)
		{
			// MoveGraphics only applies to units in the selection - this will erase any previous selection
			IGraphicsContainerSelect graphicsContainerSelect = m_mapControl.ActiveView.GraphicsContainer as IGraphicsContainerSelect;
			graphicsContainerSelect.SelectAllElements();
			MoveGraphics (0.75, 0.75);
			graphicsContainerSelect.UnselectAllElements();
			m_selectedBounds.SetEmpty();
		}


		private void tsbSelect_Click (object sender, EventArgs e)
		{
			// make this TSB exclusive both in the tool strip and in the AxToolbarControl
			// the primary logic is in axMapControl1_OnMouseDown and axMapControl1_OnMouseMove
			if ( tsbSelect.Checked )
			{
				axToolbarControl1.SetBuddyControl (null);
				axToolbarControl1.Enabled = false;
				tsbAddMoleSymbol.Checked = false;
			}
			else
			{
				axToolbarControl1.SetBuddyControl (axMapControl1);
				axToolbarControl1.Enabled = true;
			}
		}
		
		
		#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 a reference to the MapControl for local use
			m_mapControl = axMapControl1.Object as IMapControl3;

			// get a map from the SDK sample data
            string dataPath = GetSdkDataPath() + @"MilitaryOverlayEditor\";
 
			string defaultMxDoc = dataPath + "molebasemap.mxd";
			if ( m_mapControl.CheckMxFile(defaultMxDoc) )
			{
				// load the map into the map control
				object missing = Type.Missing;
				m_mapControl.LoadMxFile (defaultMxDoc, missing, missing);
			}
			else
			{
				string errorMsg = "Could not load default map document - Application may not work!";
				errorMsg += Environment.NewLine + defaultMxDoc;
				Trace.WriteLine (errorMsg);
				MessageBox.Show (errorMsg);
			}
		}


		private void MainForm_FormClosing (object sender, FormClosingEventArgs e)
		{
			// tell MOLE to save its settings and release its resources
			(new MoleCoreHelperClass()).ReleaseForceElementRenderer();
		}
		
		
		#endregion

		#region Map control event handlers


		private void axMapControl1_OnMapReplaced (object sender, IMapControlEvents2_OnMapReplacedEvent e)
		{
			// initialize the last mouse click point to the center of the map's extent
			IEnvelope extent = m_mapControl.ActiveView.Extent;
			m_lastMouseClick.PutCoords (
				extent.XMin + extent.Width * 0.5,
				extent.YMin + extent.Height * 0.5
			);
			// update the status bar and the title bar
			m_unitCount = 0;
			UpdateStatusBar();
			UpdateTitle();
		}
		
		
		private void axMapControl1_OnMouseDown (object sender, IMapControlEvents2_OnMouseDownEvent e)
		{
			m_lastMouseClick.PutCoords (e.mapX, e.mapY);
			if ( tsbAddMoleSymbol.Checked )
			{
				// "Add MOLE Symbol" command:  draw a symbol at the click point
				DrawSymbol (m_lastMouseClick, tstSIC.Text, false);
				tstSIC.Text = m_sic[m_random.Next()];
			}
			else if (
				tsbSelect.Checked &&
				SelectElements(m_lastMouseClick, m_mapControl.ActiveView, m_selectedBounds)
			)
			{
				// "Select & Drag Graphics" command:  initialize mouse tracking to move the selected elements
				Trace.WriteLine ("Start tracking at (" + m_lastMouseClick.X + ", " + m_lastMouseClick.Y + ")");
				
				// the envelope feedback draws a rectangle of the selected elements' extent following the mouse
				IMoveEnvelopeFeedback moveEnvelopeFeedback = new MoveEnvelopeFeedbackClass();
				moveEnvelopeFeedback.Start (m_selectedBounds, m_lastMouseClick);
				m_moveFeedBack = moveEnvelopeFeedback as IDisplayFeedback;
				m_moveFeedBack.Display = axMapControl1.ActiveView.ScreenDisplay;
				
				// the tick count is used to filter out short, unintentional mouse drags
				m_dragStartTime = Environment.TickCount;
			}
		}


		private void axMapControl1_OnMouseMove (object sender, IMapControlEvents2_OnMouseMoveEvent e)
		{
			// update the current map location of the mouse
			if ( m_currentMouseLocation == null )
				m_currentMouseLocation = new PointClass();
			m_currentMouseLocation.PutCoords (e.mapX, e.mapY);
			UpdateStatusBar();
			
			// "Select & Drag Graphics" command:  move the feedback graphic
			if ( tsbSelect.Checked && e.button == 1 && m_moveFeedBack != null )
				m_moveFeedBack.MoveTo (m_currentMouseLocation);
		}


		private void axMapControl1_OnMouseUp (object sender, IMapControlEvents2_OnMouseUpEvent e)
		{
			if ( m_moveFeedBack != null )
			{
				// stop the feedback graphic and save its geometry for future use
				m_selectedBounds = ((IMoveEnvelopeFeedback)m_moveFeedBack).Stop();
				m_moveFeedBack = null;
				int endTicks = Environment.TickCount - m_dragStartTime;
				if ( endTicks > 250 && m_currentMouseLocation != null )
				{
					// only update the graphics if the minimum move time has elapsed
					Trace.WriteLine ("drag start = (" + m_lastMouseClick.X + ", " + m_lastMouseClick.Y + ")");
					Trace.WriteLine ("drag end = (" + m_currentMouseLocation.X + ", " + m_currentMouseLocation.Y + ")");
					MoveGraphics (
						m_currentMouseLocation.X - m_lastMouseClick.X,
						m_currentMouseLocation.Y - m_lastMouseClick.Y
					);
				}
			}
		}


		#endregion

		#region Helper Methods


		private IPoint CreatePoint (double x, double y)
		{
			// create a new point instance and initialize its coordinates
			IPoint point = new PointClass();
			point.PutCoords (x, y);
			return point;
		}


		private void DrawSymbol (IPoint location, string sic, bool suppressRefresh)
		{
			// the first time we create a symbol, display the wait cursor while MOLE loads up
			System.Windows.Forms.Cursor previousCursor = Cursor;
			if ( m_firstTime )
				Cursor = Cursors.WaitCursor;

			// set up a MOLE symbol for the new graphic; minimally validate the symbol ID code
			IMoleSymbol moleSymbol = new MoleMarkerSymbolClass();
			if ( sic.Length == 15 )
				moleSymbol.SymbolID = sic;
			moleSymbol.TextLabels = GetLabels();

			// to remove the symbol's fill, uncomment this code
			//IMoleMarkerSymbol moleMarkerSymbol = moleSymbol as IMoleMarkerSymbol;
			//moleMarkerSymbol.ShowFill = false;

			// initialize the marker symbol properties
			IMarkerSymbol markerSymbol = moleSymbol as IMarkerSymbol;
			double size;
			if ( Double.TryParse(tstSize.Text, out size) )
				markerSymbol.Size = size;
			else
				markerSymbol.Size = 48;

			// create the graphic element for the marker symbol and add it to the map
			IMarkerElement markerElement = new MarkerElementClass();
			markerElement.Symbol = markerSymbol;
			IElement element = markerElement as IElement;
			element.Geometry = location as IGeometry;
			m_mapControl.ActiveView.GraphicsContainer.AddElement (element, 0);
			if ( ! suppressRefresh )
				m_mapControl.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
			
			// update the user interface
			if ( m_firstTime )
			{
				Cursor = previousCursor;
				m_firstTime = false;
			}
			++m_unitCount;
			UpdateTitle();
		}


		private double dRandom (double low, double high)
		{
			// generate a random floating-point number within the indicated range [low, high)
			return low + m_random.NextDouble() * (high - low);
		}


		private IPropertySet GetLabels()
		{
			IPropertySet labelSet = new PropertySetClass();

			// all of the below are supported - comment and uncomment to experiment
			labelSet.SetProperty ("Name", "Name");
			labelSet.SetProperty ("Comment", "Comment");
			//labelSet.SetProperty ("Parent", "Parent");
			//labelSet.SetProperty ("Info", "Info");
			//labelSet.SetProperty ("Strength", "Strength");
			//labelSet.SetProperty ("EvalRating", "EvalRating");
			//labelSet.SetProperty ("Location", "Location");
			//labelSet.SetProperty ("Alt_Depth", "Alt_Depth");
			//labelSet.SetProperty ("Speed", "Speed");
			//labelSet.SetProperty ("DTG", "DTG");
			//labelSet.SetProperty ("HQ", "HQ");
			//labelSet.SetProperty ("Quantity", "Quantity");
			//labelSet.SetProperty ("EType", "EType");
			//labelSet.SetProperty ("Effective", "Effective");
			//labelSet.SetProperty ("Signature", "Signature");
			//labelSet.SetProperty ("IFFSIF", "IFFSIF");

			return labelSet;
		}


		private IColor GetRandomColor()
		{
			// create a random opaque RGB color
			IRgbColor rgb = new RgbColorClass();
			rgb.Red = m_random.Next (0, 255);
			rgb.Green = m_random.Next (0, 255);
			rgb.Blue = m_random.Next (0, 255);
			return rgb as IColor;
		}
		
		
		private void MoveGraphics (double deltaX, double deltaY)
		{
			try
			{
				// move all selected graphics along a delta (change) vector
				Trace.WriteLine ("moving delta = (" + deltaX + ", " + deltaY + ")");

				// get reference to graphics container and its selected elements
				IGraphicsContainer       graphicsContainer       = axMapControl1.ActiveView.GraphicsContainer;
				IGraphicsContainerSelect graphicsContainerSelect = graphicsContainer as IGraphicsContainerSelect;
				IEnumElement             enumElement             = graphicsContainerSelect.SelectedElements;

				// iterate through the selected elements
				enumElement.Reset();
				IElement element = enumElement.Next();
				while (element != null)
				{
					// apply the delta vector to each element's geometry and update it the container
					IGeometry geometry = element.Geometry;
					(geometry as ITransform2D).Move (deltaX, deltaY);
					element.Geometry = geometry;
					graphicsContainer.UpdateElement (element);
					element = enumElement.Next();
				}
				// refresh the active view
				axMapControl1.ActiveView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
			}
			catch ( Exception ex )
			{
				MessageBox.Show ("Exception:  " + ex.GetBaseException().ToString(), "MoveGraphics");
			}
		}


		private bool SelectElements (IPoint point, IActiveView activeView, IEnvelope selectedBounds)
		{
			// this function is written in such a way that it should be pastable
			Trace.WriteLine ("selecting graphics near (" + point.X + ", " + point.Y + ")");

			IGraphicsContainer       graphicsContainer       = activeView.GraphicsContainer;
			IGraphicsContainerSelect graphicsContainerSelect = graphicsContainer as IGraphicsContainerSelect;
			IScreenDisplay           screenDisplay           = activeView.ScreenDisplay;
			bool                     selected                = false;
			bool                     refreshRequired         = false;
			
			// start with a precise search, and then widen the tolerance if nothing is found
			// (you may need to change these tolerances if using this code in your own application)
			IEnumElement enumElement = graphicsContainer.LocateElements (point, 0.0000001);
			if ( enumElement == null )
				enumElement = graphicsContainer.LocateElements (point, 0.5);
			
			// if no elements were selected
			if ( enumElement == null )
			{
				// if the previous selection is nonempty
				if ( graphicsContainerSelect.ElementSelectionCount > 0 )
				{
					// clear the selection and refresh the display
					Trace.WriteLine ("clearing selection");
					graphicsContainerSelect.UnselectAllElements();
					selectedBounds.SetEmpty();
					refreshRequired = true;
				}
				// else do nothing
			}
			else
			{
				// get the extent of the selected elements
				IEnvelope envelope = new EnvelopeClass();
				enumElement.Reset();
				IElement element = enumElement.Next();
				while ( element != null )
				{
					// establish selectedBounds as the extent of all selected elements
					element.QueryBounds (screenDisplay, envelope);
					selectedBounds.Union (envelope);
					element = enumElement.Next();
				}
				// add all the newly selected elements to the graphics container's selection
				enumElement.Reset();
				graphicsContainerSelect.SelectElements (enumElement);
				refreshRequired = selected = true;
			}
			// refresh the display if anything has changed
			if ( refreshRequired )
				activeView.PartialRefresh (esriViewDrawPhase.esriViewGraphics, null, null);
			
			// return true if any elements on the display are currently selected; selectedBounds has their extent
			return selected;
		}
		
		
		private void UpdateStatusBar()
		{
			if ( m_mapControl != null )
			{
				// put the MXD name and current mouse location in the status bar, if available
				string documentFileName = System.IO.Path.GetFileName (m_mapControl.DocumentFilename);
				if ( documentFileName == null || documentFileName == String.Empty )
					documentFileName = "<no map>";
				if ( m_currentMouseLocation == null )
					statusBarXY.Text = documentFileName;
				else
					statusBarXY.Text = String.Format (
						"{0}:  {1}, {2} {3}",
						documentFileName,
						m_currentMouseLocation.X.ToString("#######.##"),
						m_currentMouseLocation.Y.ToString("#######.##"),
						axMapControl1.MapUnits.ToString().Substring(4)
					);
			}
		}


		private void UpdateTitle()
		{
			// put the number of symbols in the title bar, when there are any
			string title = "MOLE Symbols";
			if ( m_unitCount == 1 )
				title += " (" + m_unitCount + " unit)";
			else if ( m_unitCount > 1 )
				title += " (" + m_unitCount + " units)";
			Text = title;
		}


		#endregion
	}
}
[Visual Basic .NET]

MainForm.vb


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

Imports ESRI.ArcGIS.ADF
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Controls
Imports ESRI.ArcGIS.DataSourcesFile
Imports ESRI.ArcGIS.DefenseSolutions
Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.SystemUI
Imports ESRI.ArcGIS


Namespace MoleSymbols
	Public NotInheritable Partial Class MainForm
		Inherits Form

		#Region "class private members"


		Private m_currentMouseLocation As IPoint = Nothing
		Private m_firstTime As Boolean = True
		Private m_lastMouseClick As IPoint = New PointClass()
		Private m_mapControl As IMapControl3 = Nothing
		Private m_moveFeedBack As IDisplayFeedback = Nothing
		Private m_random As New Random()
		Private m_selectedBounds As IEnvelope = New EnvelopeClass()
		Private m_sic As New DemoSIC()
		Private m_dragStartTime As Integer = 0
		Private m_unitCount As Integer = 0


		#End Region

		#Region "Constructor"


        Public Sub New()
            InitializeComponent()

            m_lastMouseClick.PutCoords(0, 0)
            UpdateStatusBar()
            UpdateTitle()
        End Sub


		#End Region

		#Region "Tool strip button event handlers"


        Private Sub tsbAdd200_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbAdd200.Click
            ' this one takes a little while, especially when it's the first one chosen
            Cursor = Cursors.WaitCursor

            ' create concentric rings of units centered around where the user last clicked
            Dim centerLon As Double = m_lastMouseClick.X
            Dim centerLat As Double = m_lastMouseClick.Y
            Const circleRadiusInRad As Double = 1
            Const numberPerCircle As Integer = 10
            For i As Integer = 0 To 199
                ' draw a random symbol at the next position in the pattern
                Dim currentRadius As Double = (i / numberPerCircle) * circleRadiusInRad + circleRadiusInRad
                Dim currentAngle As Double = (i Mod numberPerCircle) * 2 * 3.1415926536 / CDbl(numberPerCircle)
                DrawSymbol(CreatePoint(centerLon + (currentRadius * Math.Sin(currentAngle)), centerLat + (currentRadius * Math.Cos(currentAngle))), m_sic(m_random.Next()), True)
            Next
            'refresh the display and restore the cursor
            axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
            Cursor = Cursors.Default
        End Sub


        Private Sub tsbAddArea_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbAddArea.Click
            ' create the symbol using a default symbol ID code (obstacle restricted area)
            Dim moleSymbol As IMoleSymbol = New MoleFillSymbolClass()
            moleSymbol.SymbolID = "GUMPOGR-------X"
            moleSymbol.TextLabels = GetLabels()

            ' override the default fill color and outline symbol - these settings are optional
            'Dim lineSymbol As ILineSymbol = New SimpleLineSymbolClass()
            'lineSymbol.Color = GetRandomColor()
            'lineSymbol.Width = dRandom(1, 5)
            'Dim fillSymbol As IFillSymbol = TryCast(moleSymbol, IFillSymbol)
            'fillSymbol.Outline = lineSymbol
            'fillSymbol.Color = GetRandomColor()

            ' create a new polygon geometry for this symbol (four points in this example)
            Dim pointCollection As IPointCollection = New PolygonClass()

            ' center the polygon somewhere inside the current map extent
            Dim extent As IEnvelope = m_mapControl.ActiveView.Extent
            Dim lat As Double = dRandom(extent.YMin, extent.YMax)
            Dim lon As Double = dRandom(extent.XMin, extent.XMax)

            ' place the four corners somewhere within a specified threshold of the center
            Const threshold As Double = 20
            Dim missing As Object = Type.Missing
            pointCollection.AddPoint(CreatePoint(lon, dRandom(lat, lat + threshold)), missing, missing)
            pointCollection.AddPoint(CreatePoint(dRandom(lon, lon + threshold), lat), missing, missing)
            pointCollection.AddPoint(CreatePoint(lon, dRandom(lat - threshold, lat)), missing, missing)
            pointCollection.AddPoint(CreatePoint(dRandom(lon - threshold, lon), lat), missing, missing)

            ' set up the graphic element with the random geometry
            Dim fillShapeElement As IFillShapeElement = New PolygonElementClass()
            fillShapeElement.Symbol = TryCast(moleSymbol, IFillSymbol)
            Dim element As IElement = TryCast(fillShapeElement, IElement)
            element.Geometry = TryCast(pointCollection, IGeometry)

            ' add the new element to the map and update the user interface
            m_mapControl.ActiveView.GraphicsContainer.AddElement(element, 0)
            m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
            m_unitCount += 1
            UpdateTitle()
        End Sub


        Private Sub tsbAddLine_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbAddLine.Click
            ' create the symbol using a default symbol ID code (fix task line)
            Dim moleSymbol As IMoleSymbol = New MoleLineSymbolClass()
            moleSymbol.SymbolID = "GUTPF---------X"
            moleSymbol.TextLabels = GetLabels()

            ' override the default line color and width - these settings are optional
            'Dim lineSymbol As ILineSymbol = TryCast(moleSymbol, ILineSymbol)
            'lineSymbol.Color = GetRandomColor()
            'lineSymbol.Width = dRandom(1, 5)

            ' create a new line geometry for the symbol - this symbol requires two points
            Dim pointCollection As IPointCollection = New PolylineClass()

            ' place the first endpoint of the line somewhere inside the current map extent
            Dim ext As IEnvelope = m_mapControl.ActiveView.Extent
            Dim lat As Double = dRandom(ext.YMin, ext.YMax)
            Dim lon As Double = dRandom(ext.XMin, ext.XMax)
            Dim missing As Object = Type.Missing
            pointCollection.AddPoint(CreatePoint(lon, lat), missing, missing)

            ' place the second endpoint somewhere within a specified threshold of the first
            Const threshold As Double = 20
            pointCollection.AddPoint(CreatePoint(dRandom(lon - threshold, lon + threshold), dRandom(lat - threshold, lat + threshold)), missing, missing)
            ' set up the graphic element with the random geometry
            Dim lineElement As ILineElement = New LineElementClass()
            lineElement.Symbol = TryCast(moleSymbol, ILineSymbol)
            Dim element As IElement = TryCast(lineElement, IElement)
            element.Geometry = TryCast(pointCollection, IGeometry)

            ' add the new element to the map and update the user interface
            m_mapControl.ActiveView.GraphicsContainer.AddElement(element, 0)
            m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
            m_unitCount += 1
            UpdateTitle()
        End Sub


        Private Sub tsbAddMoleSymbol_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbAddMoleSymbol.Click
            ' make this TSB exclusive both in the tool strip and in the AxToolbarControl
            ' the primary logic is in axMapControl1_OnMouseDown
            If tsbAddMoleSymbol.Checked Then
                axToolbarControl1.SetBuddyControl(Nothing)
                axToolbarControl1.Enabled = False
                tsbSelect.Checked = False
            Else
                axToolbarControl1.SetBuddyControl(axMapControl1)
                axToolbarControl1.Enabled = True
            End If
        End Sub


        Private Sub tsbMoveUnits_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbMoveUnits.Click
            ' MoveGraphics only applies to units in the selection - this will erase any previous selection
            Dim graphicsContainerSelect As IGraphicsContainerSelect = TryCast(m_mapControl.ActiveView.GraphicsContainer, IGraphicsContainerSelect)
            graphicsContainerSelect.SelectAllElements()
            MoveGraphics(0.75, 0.75)
            graphicsContainerSelect.UnselectAllElements()
            m_selectedBounds.SetEmpty()
        End Sub


        Private Sub tsbSelect_Click(ByVal sender As Object, ByVal e As EventArgs) Handles tsbSelect.Click
            ' make this TSB exclusive both in the tool strip and in the AxToolbarControl
            ' the primary logic is in axMapControl1_OnMouseDown and axMapControl1_OnMouseMove
            If tsbSelect.Checked Then
                axToolbarControl1.SetBuddyControl(Nothing)
                axToolbarControl1.Enabled = False
                tsbAddMoleSymbol.Checked = False
            Else
                axToolbarControl1.SetBuddyControl(axMapControl1)
                axToolbarControl1.Enabled = True
            End If
        End Sub


		#End Region

		#Region "Form event handlers"

        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 MainForm_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            ' get a reference to the MapControl for local use
            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"
            If m_mapControl.CheckMxFile(defaultMxDoc) Then
                ' load the map into the map control
                Dim missing As Object = System.Reflection.Missing.Value
                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
                Trace.WriteLine(errorMsg)
                MessageBox.Show(errorMsg)
            End If
        End Sub


        Private Sub MainForm_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles MyBase.FormClosing
            ' tell MOLE to save its settings and release its resources
            Dim helper As IMoleCoreHelper = New MoleCoreHelperClass()
            helper.ReleaseForceElementRenderer()
        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
            ' initialize the last mouse click point to the center of the map's extent
            Dim extent As IEnvelope = m_mapControl.ActiveView.Extent
            m_lastMouseClick.PutCoords(extent.XMin + extent.Width * 0.5, extent.YMin + extent.Height * 0.5)
            ' update the status bar and the title bar
            m_unitCount = 0
            UpdateStatusBar()
            UpdateTitle()
        End Sub


        Private Sub axMapControl1_OnMouseDown(ByVal sender As Object, ByVal e As IMapControlEvents2_OnMouseDownEvent) Handles axMapControl1.OnMouseDown
            m_lastMouseClick.PutCoords(e.mapX, e.mapY)
            If tsbAddMoleSymbol.Checked Then
                ' "Add MOLE Symbol" command:  draw a symbol at the click point
                DrawSymbol(m_lastMouseClick, tstSIC.Text, False)
                tstSIC.Text = m_sic(m_random.Next())
            ElseIf tsbSelect.Checked AndAlso SelectElements(m_lastMouseClick, m_mapControl.ActiveView, m_selectedBounds) = True Then
                ' "Select & Drag Graphics" command:  initialize mouse tracking to move the selected elements
                Trace.WriteLine("Start tracking at (" & m_lastMouseClick.X & ", " & m_lastMouseClick.Y & ")")

                ' the envelope feedback draws a rectangle of the selected elements' extent following the mouse
                Dim moveEnvelopeFeedback As IMoveEnvelopeFeedback = New MoveEnvelopeFeedback()
                moveEnvelopeFeedback.Start(m_selectedBounds, m_lastMouseClick)
                m_moveFeedBack = TryCast(moveEnvelopeFeedback, IDisplayFeedback)
                m_moveFeedBack.Display = axMapControl1.ActiveView.ScreenDisplay

                ' the tick count is used to filter out short, unintentional mouse drags
                m_dragStartTime = Environment.TickCount
            End If
        End Sub


        Private Sub axMapControl1_OnMouseMove(ByVal sender As Object, ByVal e As IMapControlEvents2_OnMouseMoveEvent) Handles axMapControl1.OnMouseMove
            ' update the current map location of the mouse
            If m_currentMouseLocation Is Nothing Then
                m_currentMouseLocation = New PointClass()
            End If
            m_currentMouseLocation.PutCoords(e.mapX, e.mapY)
            UpdateStatusBar()

            ' "Select & Drag Graphics" command:  move the feedback graphic
            If tsbSelect.Checked AndAlso e.button = 1 AndAlso m_moveFeedBack IsNot Nothing Then
                m_moveFeedBack.MoveTo(m_currentMouseLocation)
            End If
        End Sub


        Private Sub axMapControl1_OnMouseUp(ByVal sender As Object, ByVal e As IMapControlEvents2_OnMouseUpEvent) Handles axMapControl1.OnMouseUp
            If m_moveFeedBack IsNot Nothing Then
                ' stop the feedback graphic and save its geometry for future use
                m_selectedBounds = DirectCast(m_moveFeedBack, IMoveEnvelopeFeedback).Stop()
                m_moveFeedBack = Nothing
                Dim endTicks As Integer = Environment.TickCount - m_dragStartTime
                If endTicks > 250 AndAlso m_currentMouseLocation IsNot Nothing Then
                    ' only update the graphics if the minimum move time has elapsed
                    Trace.WriteLine("drag start = (" & m_lastMouseClick.X & ", " & m_lastMouseClick.Y & ")")
                    Trace.WriteLine("drag end = (" & m_currentMouseLocation.X & ", " & m_currentMouseLocation.Y & ")")
                    MoveGraphics(m_currentMouseLocation.X - m_lastMouseClick.X, m_currentMouseLocation.Y - m_lastMouseClick.Y)
                End If
            End If
        End Sub


		#End Region

		#Region "Helper Methods"


        Private Function CreatePoint(ByVal x As Double, ByVal y As Double) As IPoint
            ' create a new point instance and initialize its coordinates
            Dim point As IPoint = New PointClass()
            point.PutCoords(x, y)
            Return point
        End Function


		Private Sub DrawSymbol(ByVal location As IPoint, ByVal sic As String, ByVal suppressRefresh As Boolean)
			' the first time we create a symbol, display the wait cursor while MOLE loads up
			Dim previousCursor As System.Windows.Forms.Cursor = Cursor
			If m_firstTime Then
				Cursor = Cursors.WaitCursor
            End If

            ' set up a MOLE symbol for the new graphic; minimally validate the symbol ID code
			Dim moleSymbol As IMoleSymbol = New MoleMarkerSymbolClass()
			If sic.Length = 15 Then
				moleSymbol.SymbolID = sic
			End If
			moleSymbol.TextLabels = GetLabels()

            ' to remove the symbol's fill, uncomment this code
            'Dim moleMarkerSymbol As IMoleMarkerSymbol = TryCast(moleSymbol, IMoleMarkerSymbol)
            'moleMarkerSymbol.ShowFill = False

			' initialize the marker symbol properties
			Dim markerSymbol As IMarkerSymbol = TryCast(moleSymbol, IMarkerSymbol)
			Dim size As Double
            If Double.TryParse(tstSize.Text, size) Then
                markerSymbol.Size = size
            Else
                markerSymbol.Size = 48
            End If

			' create the graphic element for the marker symbol and add it to the map
			Dim markerElement As IMarkerElement = New MarkerElementClass()
			markerElement.Symbol = markerSymbol
			Dim element As IElement = TryCast(markerElement, IElement)
			element.Geometry = TryCast(location, IGeometry)
			m_mapControl.ActiveView.GraphicsContainer.AddElement(element, 0)
			If Not suppressRefresh Then
				m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
			End If

			' update the user interface
			If m_firstTime Then
				Cursor = previousCursor
				m_firstTime = False
			End If
			m_unitCount += 1
			UpdateTitle()
		End Sub


		Private Function dRandom(ByVal low As Double, ByVal high As Double) As Double
			' generate a random floating-point number within the indicated range [low, high)
			Return low + m_random.NextDouble() * (high - low)
		End Function


		Private Function GetLabels() As IPropertySet
			Dim labelSet As IPropertySet = New PropertySetClass()

			' all of the below are supported - comment and uncomment to experiment
			labelSet.SetProperty("Name", "Name")
			labelSet.SetProperty("Comment", "Comment")
			'labelSet.SetProperty ("Parent", "Parent");
			'labelSet.SetProperty ("Info", "Info");
			'labelSet.SetProperty ("Strength", "Strength");
			'labelSet.SetProperty ("EvalRating", "EvalRating");
			'labelSet.SetProperty ("Location", "Location");
			'labelSet.SetProperty ("Alt_Depth", "Alt_Depth");
			'labelSet.SetProperty ("Speed", "Speed");
			'labelSet.SetProperty ("DTG", "DTG");
			'labelSet.SetProperty ("HQ", "HQ");
			'labelSet.SetProperty ("Quantity", "Quantity");
			'labelSet.SetProperty ("EType", "EType");
			'labelSet.SetProperty ("Effective", "Effective");
			'labelSet.SetProperty ("Signature", "Signature");
			'labelSet.SetProperty ("IFFSIF", "IFFSIF");

			Return labelSet
		End Function


		Private Function GetRandomColor() As IColor
			' create a random opaque RGB color
			Dim rgb As IRgbColor = New RgbColorClass()
            rgb.Red = m_random.Next(0, 255)
            rgb.Green = m_random.Next(0, 255)
            rgb.Blue = m_random.Next(0, 255)
			Return TryCast(rgb, IColor)
		End Function


        Private Sub MoveGraphics(ByVal deltaX As Double, ByVal deltaY As Double)
            Try
                ' move all selected graphics along a delta (change) vector
                Trace.WriteLine("moving delta = (" & deltaX & ", " & deltaY & ")")

                ' get reference to graphics container and its selected elements
                Dim graphicsContainer As IGraphicsContainer = axMapControl1.ActiveView.GraphicsContainer
                Dim graphicsContainerSelect As IGraphicsContainerSelect = TryCast(graphicsContainer, IGraphicsContainerSelect)
                Dim enumElement As IEnumElement = graphicsContainerSelect.SelectedElements

                ' iterate through the selected elements
                enumElement.Reset()
                Dim element As IElement = enumElement.Next()
                While element IsNot Nothing
                    ' apply the delta vector to each element's geometry and update it the container
                    Dim geometry As IGeometry = element.Geometry
                    TryCast(geometry, ITransform2D).Move(deltaX, deltaY)
                    element.Geometry = geometry
                    graphicsContainer.UpdateElement(element)
                    element = enumElement.Next()
                End While
                ' refresh the active view
                axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
            Catch ex As Exception
                MessageBox.Show("Exception:  " & ex.GetBaseException().ToString(), "MoveGraphics")
            End Try
        End Sub


        Private Function SelectElements(ByVal point As IPoint, ByVal activeView As IActiveView, ByVal selectedBounds As IEnvelope) As Boolean
            ' this function is written in such a way that it should be pastable
            Trace.WriteLine("selecting graphics near (" & point.X & ", " & point.Y & ")")

            Dim graphicsContainer As IGraphicsContainer = activeView.GraphicsContainer
            Dim graphicsContainerSelect As IGraphicsContainerSelect = TryCast(graphicsContainer, IGraphicsContainerSelect)
            Dim screenDisplay As IScreenDisplay = activeView.ScreenDisplay
            Dim selected As Boolean = False
            Dim refreshRequired As Boolean = False

            ' start with a precise search, and then widen the tolerance if nothing is found
            ' (you may need to change these tolerances if using this code in your own application)
            Dim enumElement As IEnumElement = graphicsContainer.LocateElements(point, 0.0000001)
            If enumElement Is Nothing Then
                enumElement = graphicsContainer.LocateElements(point, 0.5)
            End If

            ' if no elements were selected
            If enumElement Is Nothing Then
                ' if the previous selection is nonempty
                If graphicsContainerSelect.ElementSelectionCount > 0 Then
                    ' clear the selection and refresh the display
                    Trace.WriteLine("clearing selection")
                    graphicsContainerSelect.UnselectAllElements()
                    selectedBounds.SetEmpty()
                    refreshRequired = True
                    ' else do nothing
                End If
            Else
                ' get the extent of the selected elements
                Dim envelope As IEnvelope = New EnvelopeClass()
                enumElement.Reset()
                Dim element As IElement = enumElement.Next()
                While element IsNot Nothing
                    ' establish selectedBounds as the extent of all selected elements
                    element.QueryBounds(screenDisplay, envelope)
                    selectedBounds.Union(envelope)
                    element = enumElement.Next()
                End While
                ' add all the newly selected elements to the graphics container's selection
                enumElement.Reset()
                graphicsContainerSelect.SelectElements(enumElement)
                refreshRequired = True
                selected = True
            End If
            ' refresh the display if anything has changed
            If refreshRequired Then
                activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)
            End If

            ' return true if any elements on the display are currently selected; selectedBounds has their extent
            Return selected
        End Function


		Private Sub UpdateStatusBar()
			If m_mapControl IsNot Nothing Then
				' put the MXD name and current mouse location in the status bar, if available
				Dim documentFileName As String = System.IO.Path.GetFileName(m_mapControl.DocumentFilename)
                If documentFileName Is Nothing OrElse documentFileName = String.Empty Then
                    documentFileName = "<no map>"
                End If
				If m_currentMouseLocation Is Nothing Then
					statusBarXY.Text = documentFileName
				Else
                    statusBarXY.Text = String.Format("{0}:  {1}, {2} {3}", documentFileName, m_currentMouseLocation.X.ToString("#######.##"), m_currentMouseLocation.Y.ToString("#######.##"), axMapControl1.MapUnits.ToString().Substring(4))
				End If
			End If
		End Sub


		Private Sub UpdateTitle()
			' put the number of symbols in the title bar, when there are any
			Dim title As String = "MOLE Symbols"
			If m_unitCount = 1 Then
                title &= " (" & m_unitCount & " unit)"
            ElseIf m_unitCount > 1 Then
                title &= " (" & m_unitCount & " units)"
			End If
			Text = title
		End Sub


		#End Region
	End Class
End Namespace