About the Displaying MOLE symbology with the GlobeControl Sample
[C#]
MainForm.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Threading; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.GlobeCore; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.SystemUI; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.DataSourcesGDB; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.DefenseSolutions; namespace GlobeControlApp { public sealed partial class MainForm : Form { #region private class members private IGlobeControl m_globeControl = null; private IGlobeViewUtil m_globeViewUtil = null; #endregion #region class constructor public MainForm() { InitializeComponent(); } #endregion #region Main Menu event handlers private void menuOpenDoc_Click(object sender, EventArgs e) { //execute Open Document command ICommand command = new ControlsGlobeOpenDocCommandClass(); command.OnCreate(m_globeControl.Object); command.OnClick(); } private void menuExitApp_Click(object sender, EventArgs e) { //exit the application Application.Exit(); } #endregion /// <summary> /// Mouse move event handler /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void axGlobeControl1_OnMouseMove(object sender, IGlobeControlEvents_OnMouseMoveEvent e) { double dLon, dLat, dAlt; //convert the window coordinate into geographic coordinates m_globeViewUtil.WindowToGeographic( m_globeControl.GlobeDisplay, m_globeControl.GlobeDisplay.ActiveViewer, e.x, e.y, true, out dLon, out dLat, out dAlt); //report the mouse geographic coordinate onto the statusbar statusBarXY.Text = string.Format("{0} {1} {2}", dLon.ToString("###.###"), dLat.ToString("###.###"), dAlt.ToString("###.###")); } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { } // ================================================================= // The following code was added to a default(wizard generated) // Globe Control Application in order to obtain a MOLE Layer in 3D, // insert a feature, and refresh the layer. // ================================================================= IFeatureClass m_MoleFC = null; private static string m_DataPath = null; private int m_addedUnitCt = 0; /// <summary> /// Form Load event handler /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MainForm_Load(object sender, EventArgs e) { m_globeControl = axGlobeControl1.Object as IGlobeControl; //cast the GlobeViewUtil from the GlobeCamera m_globeViewUtil = m_globeControl.GlobeCamera as IGlobeViewUtil; } /// <summary> /// Add a "Add Unit" button and use this as its event handler /// </summary> private void butTest_Click(object sender, EventArgs e) { if (!MoleFcIsValid()) return; AddUnitToFC( m_MoleFC ); IGlobeDisplay globeDisplay = axGlobeControl1.GlobeDisplay; RefreshMoleLayers( globeDisplay ); } /// <summary> /// Add a "Move All Units" button and use this as its event handler /// </summary> private void butTest2_Click(object sender, EventArgs e) { if (!MoleFcIsValid()) return; MoveAllUnits( m_MoleFC ); IGlobeDisplay globeDisplay = axGlobeControl1.GlobeDisplay; RefreshMoleLayers( globeDisplay ); } /// <summary> /// Refreshes all MOLE Layers in a GlobeDisplay/Globe /// </summary> private void RefreshMoleLayers(IGlobeDisplay globeDisplay) { try { IBasicMap map = globeDisplay.Globe as IBasicMap; // find the mole Force Element layers and refresh them IEnumLayer enumLayer = map.get_Layers(null, true); enumLayer.Reset(); ILayer layer = null; while ((layer = enumLayer.Next()) != null) { if (layer is IForceElementLayer) { // Code required to get a MOLE Layer to rebuild & refresh in Globe ICachedGraphicLayer MoleLayer = layer as ICachedGraphicLayer; MoleLayer.Refresh(); globeDisplay.SuspendTileFetch(); I3DSettings layer3DSettings = MoleLayer as I3DSettings; if ((layer3DSettings != null) && (layer3DSettings.DisplayOption == mole3DDisplayEnum.mole3DDisplayExtrude)) { // use optimized refresh ESRI.ArcGIS.Display.IDisplay display = globeDisplay as ESRI.ArcGIS.Display.IDisplay; layer.Draw(esriDrawPhase.esriDPGeography, display, null); } else { // Use normal GlobeDisplay refresh (Does not perform as well) (globeDisplay as IGlobeDisplayLayers).RefreshLayer(layer); } globeDisplay.ResumeTileFetch(); } } } catch (Exception e) { Trace.WriteLine(e.Message); } } /// <summary> /// Adds a Unit to a feature class with the MOLE data model /// </summary> private void AddUnitToFC(IFeatureClass featureClass) { try { // Random Number Generation (so each new unit shows up at a different point) const double maxRandom = 5.0; System.Random randomGenerator = new System.Random(); double dRandom = randomGenerator.NextDouble() * maxRandom; // create the new feature IFeature newFeature = featureClass.CreateFeature(); // get an insert cursor IFeatureCursor insertCursor = featureClass.Insert( false ); if (newFeature != null) { // create a random point for the unit's location IPoint point = new PointClass(); point.PutCoords( -117.0 + dRandom, 35.0 + dRandom / 2.0 ); point.Z = 100.0; IZAware za = point as IZAware; za.ZAware = true; // set the feature's shape newFeature.Shape = (point as IGeometry); // set feature fields (SIC, name) string symbolIdCode = "S"; char affilCode = 'F'; // Set a different affiliation for each new unit added. int affil = m_addedUnitCt % 4; switch (affil) { case 0: affilCode = 'F'; break; case 1: affilCode = 'H'; break; case 2: affilCode = 'N'; break; case 3: affilCode = 'U'; break; default: break; } // Set the Symbol ID code. symbolIdCode = symbolIdCode + affilCode + "GPUCI-----USG"; newFeature.set_Value( newFeature.Table.FindField( "Symbol_ID" ), symbolIdCode ); // Increment the unit counter used for the unit label. m_addedUnitCt++; // Set the label for the unit's graphic. string testName = "Test Insert Unit " + m_addedUnitCt; newFeature.set_Value( newFeature.Table.FindField( "Name" ), testName ); insertCursor.InsertFeature( newFeature as IFeatureBuffer ); } insertCursor.Flush(); // make sure changes are committed before we exit } catch (Exception e) { Trace.WriteLine( e.Message ); } } /// <summary> /// Moves all point geometries in a Feature Class /// </summary> private void MoveAllUnits(IFeatureClass featureClass) { try { // get all features IFeatureCursor updateCursor = featureClass.Update( null, false ); IFeature updateFeature = updateCursor.NextFeature(); while (updateFeature != null) { IGeometry geometry = updateFeature.Shape; IPoint point = geometry as IPoint; // make sure not an empty/corrupt geometry if ((geometry != null) && (point != null) && (!geometry.IsEmpty)) { point.X += 0.20; updateFeature.Shape = geometry; updateCursor.UpdateFeature( updateFeature ); } updateFeature = updateCursor.NextFeature(); } } catch (Exception e) { Trace.WriteLine( e.Message ); } } /// <summary> /// Loads a MOLE Layer in Globe /// </summary> /// <remarks> /// This is very similar to the 2D usage with additional code to /// set the I3DSettings properties for the layer /// </remarks> private IFeatureClass LoadMoleFeatureClassInGlobe(IGlobe globe) { string dbPath = MoleMDB; IFeatureClass fc = LoadAccessFeatureClass( dbPath, "FriendlyForces"); Debug.WriteLine("Attempting to Add MOLE Layer"); IGeoFeatureLayer pFeatureLayer = new FeatureLayer() as IGeoFeatureLayer; pFeatureLayer.FeatureClass = fc; //Create a MOLE layer and attach the feature layer to it ICachedGraphicFeatureLayer pLayer = new ForceElementLayer() as ICachedGraphicFeatureLayer; pLayer.FeatureLayer = pFeatureLayer; //Set the size for symbols in the layer IForceElementLayer pForceElementLayer = pLayer as IForceElementLayer; pForceElementLayer.Size = 0.20; // Set 3D Settings I3DSettings p3DSettings = pForceElementLayer as I3DSettings; p3DSettings.DisplayOption = mole3DDisplayEnum.mole3DDisplayExtrude; // or .mole3DDisplayBoth; // or .mole3DDisplayDrape p3DSettings.EnableCallouts = true; p3DSettings.DefaultElevationMeters = 10000; ILayer layer = pLayer as ILayer; layer.Name = "MOLE 3D Unit Layer"; globe.AddLayerType(layer, ESRI.ArcGIS.GlobeCore.esriGlobeLayerType.esriGlobeLayerTypeDraped, true); System.Diagnostics.Debug.WriteLine("Layer Added"); return fc; } /// <summary> /// Opens a Feature Class from an Access PGDB /// </summary> private IFeatureClass LoadAccessFeatureClass(string dbPath, string featureClassName) { // open the access database IWorkspaceFactory pWSF = new AccessWorkspaceFactoryClass(); IWorkspace pWS = pWSF.OpenFromFile(dbPath, 0); // make sure the database was opened if (pWS == null) { MessageBox.Show("Could not locate and/or open database at: \"" + dbPath + "\"", "Error!"); return null; } IFeatureWorkspace pFWS = pWS as IFeatureWorkspace; IFeatureClass pFC; lock (pFWS) // lock to prevent multi-process access { // open the feature class pFC = pFWS.OpenFeatureClass(featureClassName); } // make sure the feature class was opened if (pFC == null) { MessageBox.Show("Could not open feature class: " + featureClassName + ".", "Error!"); return null; } return pFC; } /// <summary> /// Path to ArcGIS Install /// </summary> private static 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; } /// <summary> /// Path to MOLE Globe Access PGDB data file /// </summary> public static string MoleMDB { get { if (m_DataPath == null) { m_DataPath = GetSdkDataPath() + @"MilitaryOverlayEditor\mole_globe.mdb"; } return m_DataPath; } } // Checks if a valid MOLE feature class has been loaded onto the globe. private bool MoleFcIsValid() { if (m_MoleFC == null) { MessageBox.Show("Please open an ArcGlobe (.3dd) document\nbefore pressing this button.", "MOLE Globe", MessageBoxButtons.OK, MessageBoxIcon.Information); return false; } return true; } // Called when a Globe document is opened. private void axGlobeControl1_OnGlobeReplaced(object sender, IGlobeControlEvents_OnGlobeReplacedEvent e) { // Load the MOLE Unit Feature Class m_MoleFC = LoadMoleFeatureClassInGlobe(this.axGlobeControl1.Globe as IGlobe); } } }
[Visual Basic .NET]
MainForm.vb
Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Data Imports System.Drawing Imports System.Text Imports System.Windows.Forms Imports System.Diagnostics Imports ESRI.ArcGIS.Controls Imports ESRI.ArcGIS.GlobeCore Imports ESRI.ArcGIS.esriSystem Imports ESRI.ArcGIS.SystemUI Imports ESRI.ArcGIS Imports ESRI.ArcGIS.Carto Imports ESRI.ArcGIS.DataSourcesGDB Imports ESRI.ArcGIS.Geometry Imports ESRI.ArcGIS.Geodatabase Imports ESRI.ArcGIS.DefenseSolutions Namespace GlobeControlApp Public NotInheritable Partial Class MainForm Inherits Form #Region "private class members" Private m_globeControl As IGlobeControl = Nothing Private m_globeViewUtil As IGlobeViewUtil = Nothing #End Region #Region "class constructor" Public Sub New() RuntimeManager.Bind(ProductCode.Engine) InitializeComponent() End Sub #End Region #Region "Main Menu event handlers" Private Sub menuOpenDoc_Click(ByVal sender As Object, ByVal e As EventArgs) Handles menuOpenDoc.Click 'execute Open Document command Dim command As ICommand = New ControlsGlobeOpenDocCommandClass() command.OnCreate(m_globeControl.[Object]) command.OnClick() End Sub Private Sub menuExitApp_Click(ByVal sender As Object, ByVal e As EventArgs) Handles menuExitApp.Click 'exit the application Application.[Exit]() End Sub #End Region ''' <summary> ''' Mouse move event handler ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> Private Sub axGlobeControl1_OnMouseMove(ByVal sender As Object, ByVal e As IGlobeControlEvents_OnMouseMoveEvent) Handles axGlobeControl1.OnMouseMove Dim dLon As Double, dLat As Double, dAlt As Double 'convert the window coordinate into geographic coordinates m_globeViewUtil.WindowToGeographic(m_globeControl.GlobeDisplay, m_globeControl.GlobeDisplay.ActiveViewer, e.x, e.y, True, dLon, _ dLat, dAlt) 'report the mouse geographic coordinate onto the statusbar statusBarXY.Text = String.Format("{0} {1} {2}", dLon.ToString("###.###"), dLat.ToString("###.###"), dAlt.ToString("###.###")) End Sub ' Called when a globe document is opened using the file open button or menu. Private Sub axGlobeControl1_OnGlobeReplaced(ByVal sender As System.Object, ByVal e As IGlobeControlEvents_OnGlobeReplacedEvent) Handles axGlobeControl1.OnGlobeReplaced ' Load the MOLE Unit Feature Class Dim globe As IGlobe = Me.axGlobeControl1.Globe m_MoleFC = LoadMoleFeatureClassInGlobe(globe) End Sub ' Checks if a valid MOLE feature class has been loaded onto the globe. Private Function MoleFcIsValid() As Boolean If m_MoleFC Is Nothing Then MessageBox.Show("Please open an ArcGlobe (.3dd) document" & Environment.NewLine & "before pressing this button.", _ "MOLE Globe", MessageBoxButtons.OK, MessageBoxIcon.Information) Return False End If Return True End Function Private Sub MainForm_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles MyBase.FormClosing End Sub ' The following code was added to a default(wizard generated) ' Globe Control Application in order to obtain a MOLE Layer in 3D, ' insert a feature, and refresh the layer. Private m_MoleFC As IFeatureClass = Nothing Private m_addedUnitCt As Integer = 0 ''' <summary> ''' Form Load event handler ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> Private Sub MainForm_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load m_globeControl = TryCast(axGlobeControl1.[Object], IGlobeControl) 'cast the GlobeViewUtil from the GlobeCamera m_globeViewUtil = TryCast(m_globeControl.GlobeCamera, IGlobeViewUtil) End Sub ''' <summary> ''' Add a "Add Unit" button and use this as its event handler ''' </summary> Private Sub butTest_Click(ByVal sender As Object, ByVal e As EventArgs) Handles butTest.Click If (Not MoleFcIsValid()) Then Return End If AddUnitToFC(m_MoleFC) Dim globeDisplay As IGlobeDisplay = axGlobeControl1.GlobeDisplay RefreshMoleLayers(globeDisplay) End Sub ''' <summary> ''' Add a "Move All Units" button and use this as its event handler ''' </summary> Private Sub butTest2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles butTest2.Click If (Not MoleFcIsValid()) Then Return End If MoveAllUnits(m_MoleFC) Dim globeDisplay As IGlobeDisplay = axGlobeControl1.GlobeDisplay RefreshMoleLayers(globeDisplay) End Sub ''' <summary> ''' Refreshes all MOLE Layers in a GlobeControl ''' </summary> Private Sub RefreshMoleLayers(ByVal globeDisplay As IGlobeDisplay) Dim map As IBasicMap = TryCast(globeDisplay.Globe, IBasicMap) ' find the mole Force Element layers and refresh them Dim enumLayer As IEnumLayer = map.Layers(Nothing, True) enumLayer.Reset() Dim layer As ILayer = enumLayer.Next() While layer IsNot Nothing If TypeOf layer Is IForceElementLayer Then ' Code required to get a MOLE Layer to rebuild & refresh in Globe Dim MoleLayer As ICachedGraphicLayer = TryCast(layer, ICachedGraphicLayer) MoleLayer.Refresh() globeDisplay.SuspendTileFetch() Dim layer3DSettings As I3DSettings = TryCast(MoleLayer, I3DSettings) If layer3DSettings IsNot Nothing And layer3DSettings.DisplayOption <> mole3DDisplayEnum.mole3DDisplayExtrude Then ' use optimized refresh Dim display As ESRI.ArcGIS.Display.IDisplay = TryCast(globeDisplay, ESRI.ArcGIS.Display.IDisplay) layer.Draw(esriDrawPhase.esriDPGeography, display, Nothing) Else ' Use normal GlobeDisplay refresh (Does not perform as well) TryCast(globeDisplay, IGlobeDisplayLayers).RefreshLayer(layer) End If globeDisplay.ResumeTileFetch() End If layer = enumLayer.Next() End While End Sub ''' <summary> ''' Adds a Unit to a feature class with the MOLE data model ''' </summary> Private Sub AddUnitToFC(ByVal featureClass As IFeatureClass) Try ' Random Number Generation (so each new unit shows up at a different point) Const maxRandom As Double = 5 Dim randomGenerator As New System.Random() Dim dRandom As Double = randomGenerator.NextDouble() * maxRandom ' create the new feature Dim newFeature As IFeature = featureClass.CreateFeature() ' get an insert cursor Dim insertCursor As IFeatureCursor = featureClass.Insert(False) If newFeature IsNot Nothing Then ' create a random point for the unit's location Dim point As IPoint = New PointClass() point.PutCoords(-117 + dRandom, 35 + dRandom / 2) point.Z = 100 Dim za As IZAware = TryCast(point, IZAware) za.ZAware = True ' set the feature's shape newFeature.Shape = TryCast(point, IGeometry) ' set feature fields (SIC, name) Dim symbolIdCode As String = "S" Dim affilCode As Char = "F"c ' Set a different affiliation for each new unit added. Dim affil As Integer = m_addedUnitCt Mod 4 Select Case affil Case 0 affilCode = "F"c Case 1 affilCode = "H"c Case 2 affilCode = "N"c Case 3 affilCode = "U"c Case Else End Select ' Set the symbol ID code symbolIdCode = symbolIdCode & affilCode & "GPUCI-----USG" newFeature.Value(newFeature.Table.FindField("Symbol_ID")) = symbolIdCode ' Increment the unit counter used for the unit label. m_addedUnitCt += 1 ' Set the label for the unit graphic. Dim testName As String = "Test Insert Unit " & m_addedUnitCt newFeature.Value(newFeature.Table.FindField("Name")) = testName insertCursor.InsertFeature(TryCast(newFeature, IFeatureBuffer)) End If ' make sure changes are committed before we exit insertCursor.Flush() Catch e As Exception Trace.WriteLine(e.Message) End Try End Sub ''' <summary> ''' Moves all point geometries in a Feature Class ''' </summary> Private Sub MoveAllUnits(ByVal featureClass As IFeatureClass) Try ' get all features Dim updateCursor As IFeatureCursor = featureClass.Update(Nothing, False) Dim updateFeature As IFeature = updateCursor.NextFeature() While updateFeature IsNot Nothing Dim geometry As IGeometry = updateFeature.Shape Dim point As IPoint = TryCast(geometry, IPoint) ' make sure not an empty/corrupt geometry If (geometry IsNot Nothing) AndAlso (point IsNot Nothing) AndAlso (Not geometry.IsEmpty) Then point.X += 0.2 updateFeature.Shape = geometry updateCursor.UpdateFeature(updateFeature) End If updateFeature = updateCursor.NextFeature() End While Catch e As Exception Trace.WriteLine(e.Message) End Try End Sub ''' <summary> ''' Loads a MOLE Layer in Globe ''' </summary> ''' <remarks> ''' This is very similar to the 2D usage with additional code to ''' set the I3DSettings properties for the layer ''' </remarks> Private Function LoadMoleFeatureClassInGlobe(ByVal globe As IGlobe) As IFeatureClass Dim dbPath As String = MoleMDB Dim fc As IFeatureClass = LoadAccessFeatureClass(dbPath, "FriendlyForces") Debug.WriteLine("Attempting to Add MOLE Layer") Dim pFeatureLayer As IGeoFeatureLayer = TryCast(New FeatureLayer(), IGeoFeatureLayer) pFeatureLayer.FeatureClass = fc 'Create a MOLE layer and attach the feature layer to it Dim pLayer As ICachedGraphicFeatureLayer = TryCast(New ForceElementLayer(), ICachedGraphicFeatureLayer) pLayer.FeatureLayer = pFeatureLayer 'Set the size for symbols in the layer Dim pForceElementLayer As IForceElementLayer = TryCast(pLayer, IForceElementLayer) pForceElementLayer.Size = 0.2 ' Set 3D Settings Dim p3DSettings As I3DSettings = TryCast(pForceElementLayer, I3DSettings) p3DSettings.DisplayOption = mole3DDisplayEnum.mole3DDisplayBoth ' or .mole3DDisplayExtrude; // or mole3DDisplayDrape p3DSettings.EnableCallouts = True p3DSettings.DefaultElevationMeters = 10000 Dim layer As ILayer = TryCast(pLayer, ILayer) layer.Name = "MOLE 3D Unit Layer" globe.AddLayerType(layer, ESRI.ArcGIS.GlobeCore.esriGlobeLayerType.esriGlobeLayerTypeDraped, True) System.Diagnostics.Debug.WriteLine("Layer Added") Return fc End Function ''' <summary> ''' Opens a Feature Class from an Access PGDB ''' </summary> Private Function LoadAccessFeatureClass(ByVal dbPath As String, ByVal featureClassName As String) As IFeatureClass ' open the access database Dim pWSF As IWorkspaceFactory = New AccessWorkspaceFactoryClass() Dim pWS As IWorkspace = pWSF.OpenFromFile(dbPath, 0) ' make sure the database was opened If pWS Is Nothing Then MessageBox.Show("Could not locate and/or open database at: """ + dbPath + """", "Error!") Return Nothing End If Dim pFWS As IFeatureWorkspace = TryCast(pWS, IFeatureWorkspace) Dim pFC As IFeatureClass SyncLock pFWS ' lock to prevent multi-process access ' open the feature class pFC = pFWS.OpenFeatureClass(featureClassName) End SyncLock ' make sure the feature class was opened If pFC Is Nothing Then MessageBox.Show("Could not open feature class: " + featureClassName + ".", "Error!") Return Nothing End If Return pFC End Function ''' <summary> ''' Path to ArcGIS Install ''' </summary> 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 ''' <summary> ''' Path to MOLE globe Access PGDB data file ''' </summary> Public ReadOnly Property MoleMDB() As String Get If m_DataPath Is Nothing Then m_DataPath = GetSdkDataPath() + "MilitaryOverlayEditor\mole_globe.mdb" End If Return m_DataPath End Get End Property Private Shared m_DataPath As String = Nothing End Class End Namespace