How to draw a geographical object on the globe using direct OpenGL plug-in


Summary OpenGL drawing can be used in two places: in GlobeDisplay’s BeforeDraw or AfterDraw event handlers and in CustomGlobeLayers’ DrawImmediate method implementations. This article shows you how to draw a geographical object on the globe’s surface using OpenGL in the context of a user-defined command.

Development licensing Deployment licensing
Engine Developer Kit Engine Runtime: 3D
ArcView: 3D Analyst ArcView: 3D Analyst
ArcEditor: 3D Analyst ArcEditor: 3D Analyst
ArcInfo: 3D Analyst ArcInfo: 3D Analyst

Additional Requirements
  • It is assumed that you have an OpenGL wrapper library (such as CsGL) that allows you to make the OpenGL calls.
  • This article assumes that you are familiar with the C# programming language and have basic OpenGL programming knowledge, as well as knowledge of creating commands and tools for ArcGIS Engine and Desktop.

Drawing a geographical object on the globe

This document will guide you through the steps needed to draw geographical items on the globe. For a working sample of this document's content, please see Globe digitize tool.
 
  1. In Visual Studio's Solution Explorer, add a new ArcGIS command. You should use the Visual Studio .NET IDE integration framework in order to implement a BaseCommand for ArcGlobe and GlobeControl. 
  2. Add references to your OpenGL wrapper library and to the ESRI GlobeCore and Analyst3D assemblies. For more information see How To get and install an OpenGL wrapper for .NET.
  3. If possible, use the IGlobeHookHelper to allow your command to work in the Engine and ArcGlobe applications.
  4. In your class, set a member variable for IGlobeDisplay, IGlobeViewUtil, and ISceneViewer interfaces. In addition, set an array list to store the input coordinates information. See the following:

[C#]
private IGlobeViewUtil m_globeViewUtil = null;
private IGlobeDisplay m_globeDisplay = null;
private ISceneViewer m_sceneViwer = null;
private ArrayList m_array = null;
  1. Declare a structure to store the input coordinate information. See the following:

[C#]
private struct GLPoint
{
  public string Name;
  public double geoX;
  public double geoY;
  public double geoZ;
  public double glX;
  public double glY;
  public double glZ;
}
You can use any other data structure such as ADO.Net DataTable or a HashTable (this is dependent on the specific requirements).
  1. In the OnCreate method, initialize the ArrayList. See the following:

[C#]
m_array = new ArrayList(100);
  1. In the command OnCreate() method, cache GlobeDisplay, SceneViewer, and GlobeViewUtil and start listening to Globe’s AfterDraw event. See the following:

[C#]
m_globeViewUtil = m_globeHookHelper.Camera as IGlobeViewUtil;

m_globeDisplay = m_globeHookHelper.GlobeDisplay;
m_sceneViwer = m_globeHookHelper.ActiveViewer;
//Start listening to globe display events.
((IGlobeDisplayEvents_Event)m_globeDisplay).AfterDraw += new
  IGlobeDisplayEvents_AfterDrawEventHandler(OnAfterDraw);
The code in the following steps is implemented inside the OnClick() method.
  1. In the OnClick event handler, open a dialog box and request the input coordinate from the user. The code below assumes that you are having a windows forms dialog called 'InputCoordinateDlg' which allow to get an input coordinate from the user (Longitude, Latitude and Altitude).  See the following code:

[C#]
// Open an input dialog box for the user to set the geographical point.       
InputCoordinateDlg dlg = new InputCoordinateDlg();
if (DialogResult.OK != dlg.ShowDialog())
  return ;
  1. Get the geographical point from the dialog box and convert it into a geocentric coordinate (OpenGl’s coordinate system). See the following:

[C#]
// Get the geo coordinate from the form.
GLPoint glPnt = new GLPoint();
glPnt.geoX = dlg.Longitude;
glPnt.geoY = dlg.Latitude;
glPnt.geoZ = dlg.Altitude;

// Convert the geopgraphical coordinate into a geocentric (OpenGL) coordinate system.
m_globeViewUtil.GeographicToGeocentric(glPnt.geoX, glPnt.geoY, glPnt.geoZ, out
  glPnt.glX, out glPnt.glY, out glPnt.glY);
  1. Add the new element to the coordinates list. See the following:

[C#]
m_array.Add(glPnt);
  1. Refresh the display. See the following:

[C#]
// Refresh the display so that the AfterDraw will get called.
m_sceneViwer.Redraw(false);

Implementing the OnAfterDraw event handler

The actual drawing takes place in the OnAfterDraw event handler. The AfterDraw and BeforeDraw events are the only place where you are guaranteed to safely make OpenGL calls (the OpenGL state is ready for the custom calls).
 
  1. Iterate through the list items.
  2. Draw the list items directly on the globe. See the following:

[C#]
public void OnAfterDraw(ISceneViewer pViewer)
{
  foreach (GLPoint p in m_array)
  {
    GL.glPointSize(10.0f);
    GL.glColor3ub(0, 255, 0);
    GL.glBegin(GL.GL_POINTS);
    GL.glVertex3f((float)p.glX, (float)p.glY, (float)p.glZ);
    GL.glEnd();
  }
}


See Also:

How to draw mouse feedback on the globe using direct OpenGL plug-in
Sample: RSS weather 3D layer
How to get and install an OpenGL wrapper for .NET
Sample: Globe digitize tool
Implementing custom globe layers with dynamic feed