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.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