arcgissamples\display\ShowCompassCommand.java—ArcObjects 10.4 Help for Java | ArcGIS for Desktop
Dynamic compass using OpenGL
arcgissamples\display\ShowCompassCommand.java
/* Copyright 2015 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 at <your ArcGIS install location>/DeveloperKit10.4/userestrictions.txt.
* 
*/
package arcgissamples.display;

import java.io.File;
import java.io.IOException;

import javax.media.opengl.GL;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;

import com.esri.arcgis.carto.Map;
import com.esri.arcgis.controls.BaseCommand;
import com.esri.arcgis.controls.HookHelper;
import com.esri.arcgis.display.DisplayTransformation;
import com.esri.arcgis.display.IDisplay;
import com.esri.arcgis.display.IDynamicMapEventsAdapter;
import com.esri.arcgis.display.IDynamicMapEventsAfterDynamicDrawEvent;
import com.esri.arcgis.display.ITransformEventsAdapter;
import com.esri.arcgis.display.ITransformEventsDeviceFrameUpdatedEvent;
import com.esri.arcgis.display.esriDynamicMapDrawPhase;
import com.esri.arcgis.interop.AutomationException;
import com.esri.arcgis.system.esriDrawPhase;
import com.esri.arcgis.system.tagRECT;

class ShowCompassCommand extends BaseCommand {

  private static final long serialVersionUID = 1L;

  private HookHelper captainHook;

  private boolean checked = false;
  private Map map = null;
  
  public boolean isChecked() {
    return this.checked;
  }
  
  public void onCreate(Object hook) {
    try {
      this.captainHook = new HookHelper();
      this.captainHook.setHookByRef(hook);
    } catch (Exception e) {
      e.printStackTrace();
    }
    this.caption = "Add OpenGL Compass";
    this.enabled = true;
    this.name = "Add OpenGL Compass";
    
    String devKitHome = System.getenv("AGSDEVKITJAVA");
    if(devKitHome == null){
      System.err.println("The Java ArcObjects SDK has not been installed.");
      System.err.println("Please install the ArcObjects SDK for Java, then re-run this sample.");
      System.err.println("Exiting the application...");
      System.exit(-1);
    }
    
    this.bitmapPath = devKitHome + "java" + File.separator + "samples" + File.separator
                        + "data" + File.separator + "display" + File.separator
                        + "compass_command.png";
  }
  @Override
  public void onClick() {
    this.checked = !this.checked;
    this.enabled = !this.enabled;
    
    try {
      
      map = (Map) captainHook.getFocusMap();
      //Enable dynamic mode
      map.setDynamicMapEnabled(true);
      map.setShowScrollBars(false);
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    try {
      if (this.checked) {

        //Add the dynamic map events listener
        //This is where we draw the compass in the AfterDynamicDraw event.
        map.addIDynamicMapEventsListener(new IDynamicMapEventsAdapter() {
          private static final long serialVersionUID = 1L;

          private GL gl = null;

          private GLContext context = null;

          private IDisplay Display;

          private tagRECT deviceFrame;

          private DisplayTransformation displayXformation;

          public void afterDynamicDraw(
              IDynamicMapEventsAfterDynamicDrawEvent theEvent)
          throws IOException, AutomationException {
            //Only react for the dynamic layers draw phase
            if (theEvent.getDynamicMapDrawPhase() != esriDynamicMapDrawPhase.esriDMDPDynamicLayers)
              return;
            try {
              //Setup OpenGL only once, create the display list for the compass
              if (context == null) {
                // Tell JOGL that we are going to use
                // our own OpenGL Context
                context = GLDrawableFactory.getFactory().createExternalGLContext();
                context.makeCurrent();
                gl = context.getGL();
                Display = theEvent.getDisplay();
                displayXformation = (DisplayTransformation) Display
                .getDisplayTransformation();
                // get the device frame size
                deviceFrame = displayXformation
                .getDeviceFrame();

                // start listening to display events
                // This will tell us how much to rotate the compass
                displayXformation.addITransformEventsListener(new ITransformEventsAdapter() {
                  private static final long serialVersionUID = 1L;

                  @Override
                  public void deviceFrameUpdated(
                      ITransformEventsDeviceFrameUpdatedEvent theEvent)
                  throws IOException,
                  AutomationException {
                    deviceFrame = theEvent
                    .getSender()
                    .getDeviceFrame();
                  }

                });

                createDisplayList();
              }
              // Draw the compass display list
              gl.glPushMatrix();
              gl.glLoadIdentity();
              gl.glPushMatrix();
              gl.glTranslatef(
                  (float) deviceFrame.left + 70.0f,
                  (float) deviceFrame.top + 70.0f, 0.0f);
              gl.glScalef(90.0f, 90.0f, 0.0f);
              gl.glRotatef((float) displayXformation
                  .getRotation(), 0.0f, 0.0f, 1.0f);
              gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
              gl.glCallList(compassList);
              gl.glPopMatrix();
              gl.glPopMatrix();
              gl.glFlush();
            } catch (Exception e) {
              e.printStackTrace();
            }

          }

          private int compassList = 0;

          private void createDisplayList() {
            // create the display list for the compass
            // The quad size is set to 1 unit. Therefore you
            // will have to scale it
            // each time before drawing.

            gl.glEnable(GL.GL_TEXTURE_2D);
            final int[] tmp = new int[1];
            gl.glGenTextures(1, tmp, 0);
            int textureId = tmp[0];
            gl.glTexParameteri(GL.GL_TEXTURE_2D,
                GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
            gl.glTexParameteri(GL.GL_TEXTURE_2D,
                GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
            gl.glBindTexture(GL.GL_TEXTURE_2D, textureId);
            // open the compass bitmap
            ImageTexturizer.Texture imageTexture = null;
            
            String devKitHome = System.getenv("AGSDEVKITJAVA");
            if(devKitHome == null){
              System.err.println("The Java ArcObjects SDK has not been installed.");
              System.err.println("Please install the ArcObjects SDK for Java, then re-run this sample.");
              System.err.println("Exiting the application...");
              System.exit(-1);
            }
            
            String compass = devKitHome + "java" + File.separator + "samples" + File.separator
                                + "data" + File.separator + "display" + File.separator
                               + "compass.gif";
            
            try {
              imageTexture = ImageTexturizer.readTexture(
                  compass, true);
            } catch (IOException e) {
              e.printStackTrace();
              throw new RuntimeException(e);
            }
            gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA8,
                imageTexture.getWidth(),
                imageTexture.getHeight(), 0, GL.GL_RGBA,
                GL.GL_UNSIGNED_BYTE, imageTexture.getPixels());
            compassList = gl.glGenLists(1);
            gl.glNewList(compassList, GL.GL_COMPILE);
            gl.glPushMatrix();
            // shift the item 1/2 unit to the middle so that
            // it'll get drawn around the center
            gl.glTranslatef(-0.5f, -0.5f, 0.0f);
            // enable texture in order to allow for texture
            // binding
            gl.glTexEnvi(GL.GL_TEXTURE_ENV,
                GL.GL_TEXTURE_ENV_MODE, (int) GL.GL_MODULATE);

            // bind the texture

            gl.glEnable(GL.GL_TEXTURE_2D);
            gl.glBindTexture(GL.GL_TEXTURE_2D, (int) textureId);

            // create the geometry (quad) and specify the
            // texture coordinates
            gl.glBegin(GL.GL_QUADS);
            gl.glTexCoord2f(0.0f, 0.0f);
            gl.glVertex2f(0.0f, 0.0f);
            gl.glTexCoord2f(1.0f, 0.0f);
            gl.glVertex2f(1.0f, 0.0f);
            gl.glTexCoord2f(1.0f, 1.0f);
            gl.glVertex2f(1.0f, 1.0f);
            gl.glTexCoord2f(0.0f, 1.0f);
            gl.glVertex2f(0.0f, 1.0f);  
            gl.glEnd();
            gl.glPopMatrix();
            gl.glEndList();
          }
        });

      } else {
        // Disable dynamic mode
        map.setDynamicMapEnabled(false);
      }
      this.captainHook.getActiveView().partialRefresh(esriDrawPhase.esriDPGeography, null, null);
      
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}