Track GPS
arcgissamples\mapbean\TrackGPS.java
/* 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.
* 
*/
package arcgissamples.mapbean;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;

import com.esri.arcgis.beans.map.MapBean;
import com.esri.arcgis.carto.FeatureLayer;
import com.esri.arcgis.carto.IElement;
import com.esri.arcgis.carto.IGraphicsContainer;
import com.esri.arcgis.carto.ILayer;
import com.esri.arcgis.carto.MarkerElement;
import com.esri.arcgis.carto.SimpleRenderer;
import com.esri.arcgis.carto.esriViewDrawPhase;
import com.esri.arcgis.controls.IMapControlEvents2Adapter;
import com.esri.arcgis.controls.IMapControlEvents2OnMouseDownEvent;
import com.esri.arcgis.display.CharacterMarkerSymbol;
import com.esri.arcgis.display.IRgbColor;
import com.esri.arcgis.display.RgbColor;
import com.esri.arcgis.display.SimpleFillSymbol;
import com.esri.arcgis.display.SimpleLineSymbol;
import com.esri.arcgis.geometry.IGeographicCoordinateSystem;
import com.esri.arcgis.geometry.IProjectedCoordinateSystem;
import com.esri.arcgis.geometry.Point;
import com.esri.arcgis.geometry.Polygon;
import com.esri.arcgis.geometry.SpatialReferenceEnvironment;
import com.esri.arcgis.geometry.esriSRGeoCSType;
import com.esri.arcgis.geometry.esriSRProjCSType;
import com.esri.arcgis.interop.AutomationException;
import com.esri.arcgis.support.ms.stdole.StdFont;
import com.esri.arcgis.system.AoInitialize;
import com.esri.arcgis.system.EngineInitializer;
import com.esri.arcgis.system.esriLicenseProductCode;
import com.esri.arcgis.system.esriLicenseStatus;

/**
 * Description:This sample demonstrates adding elements to a Map's GraphicsContainer, and then moving them in response
 * to a timer. It also demonstrates setting a coordinatate systems and projecting data.
 */
public class TrackGPS extends JFrame implements ActionListener
{
  /**
   * 
   */
  private static final long serialVersionUID = 1L;
  JPanel mainPanel = null;
  JPanel bottomPanel = null;

  IGeographicCoordinateSystem geographicCoordinateSystem = null;
  IProjectedCoordinateSystem projectedCoordinateSystem = null;
  IGraphicsContainer graphicsContainer = null;
  MapBean mapBean;
  AgentInField agentArray[];

  String helpString = "<HTML> Use the left mouse button to zoom in. Use the other mouse buttons to <BR> click on an agent and change the symbology.   </HTML>";
  JLabel helpLabel = null;
  JButton zoomFullExtentButton = null;
  JCheckBox gpsTrackingCheck = null;
  Timer timer = null;

  public TrackGPS(){
    super("Geo Events");
    buildFrame();
    setSize(800, 500);
    setVisible(true);
    initControl();
  }

  /**
   * Initializes control and member variables.
   */
  public void initControl()
  {
    //Get the developer kit home location
    String devKitHome = System.getenv("AGSDEVKITJAVA");
    
    String filePath = devKitHome + File.separator + "java" + File.separator + "samples" + 
                     File.separator + "data" + File.separator + "world";

    try
    {
      // Add sample shapefile data
      mapBean.addShapeFile(filePath, "world30");
      mapBean.addShapeFile(filePath, "continent");

      mapBean.addIMapControlEvents2Listener(new MapControlListener());

      // Symbolize the data
      symbolizeData(mapBean.getLayer(0), 0.1, getRGBColor(0, 0, 0), getRGBColor(0, 128, 0));
      symbolizeData(mapBean.getLayer(1), 0.1, getRGBColor(0, 0, 0), getRGBColor(140, 196, 254));
      // mapBean.refresh(esriViewDrawPhase.esriViewBackground, null, null);
      // Set up a global Geographic Coordinate System
      makeCoordinateSystem();
      // Get the MapBean's graphics container and get the IGraphicsContainer interface
      // mapBean.refresh(esriViewDrawPhase.esriViewBackground, null, null);
      graphicsContainer = mapBean.getActiveView().getGraphicsContainer();

      agentArray = new AgentInField[20];
      // Populate an array with agent id's and locations
      loadAgentArray();

      // Loop through the array and display each agent location
      for (int i = 0; i < agentArray.length - 1; i++)
        createContainerElements(agentArray[i]);

      mapBean.refresh(esriViewDrawPhase.esriViewBackground, null, null);

      // Create timer object
      timer = new Timer(1000, new TimerListener());
      timer.stop();
    }
    catch (IOException ex)
    {
      System.out.println("Exception in initConrol #" + ex);
      ex.printStackTrace();
    }
  }

  public void buildFrame(){
    mainPanel = new JPanel();
    bottomPanel = new JPanel();

    mainPanel.setLayout(new BorderLayout());
    bottomPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

    gpsTrackingCheck = new JCheckBox("Enable GPS Tracking");
    gpsTrackingCheck.addActionListener(this);

    helpLabel = new JLabel(helpString);
    zoomFullExtentButton = new JButton("Zoom to Full Extent");
    zoomFullExtentButton.addActionListener(this);

    bottomPanel.add(gpsTrackingCheck);
    bottomPanel.add(helpLabel);
    bottomPanel.add(zoomFullExtentButton);

    // Create map control add it to the center of the main panel.
    mapBean = new MapBean();
    mainPanel.add(mapBean, BorderLayout.CENTER);
    mainPanel.add(bottomPanel, BorderLayout.SOUTH);
    mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

    getContentPane().add(mainPanel, BorderLayout.CENTER);

  }

  /**
   * @see java.awt.event.ActionListener#actionPerformed(ActionEvent event)
   * @param event
   */
  public void actionPerformed(ActionEvent event)
  {
    if (event.getSource() == gpsTrackingCheck)
    {
      if (gpsTrackingCheck.isSelected())
      {
        timer.start();
      }
      else
      {
        if (timer.isRunning())
        {
          timer.stop();
        }
      }
    }
    if (event.getSource() == zoomFullExtentButton)
    {
      try
      {
        // Assign map controls extent property to the full extent of all the layers
        mapBean.setExtent(mapBean.getFullExtent());
      }
      catch (Exception ex)
      {
        System.out.println("Exception in zoomFullExtentButton action performed : " + ex);
        ex.printStackTrace();
      }
    }
  }

  /**
   * Uses agent data to create a point object. The point object is then projected onto projected coordinates on the
   * map control and added to graphic container.
   * 
   * @param agent
   */
  public void createContainerElements(AgentInField agent)
  {
    try
    {
      Point point = new Point();
      point.putCoords(agent.Longitude, agent.Latitude);
      // Set the points spatial reference - WHERE the point is coming FROM
      point.setSpatialReferenceByRef(geographicCoordinateSystem);
      // Project the point onto the display's current spatial reference - WHERE the point is going TO
      point.project(projectedCoordinateSystem);

      // Create a marker element
      MarkerElement element = new MarkerElement();
      // Set the elements geometry
      element.setGeometry(point);
      element.setSymbol(getMarkerSymbol(agent.Located));
      // set the agent located to element properties
      if (agent.Located)
      {
        element.setName("True");
      }
      else
      {
        element.setName("False");
      }

      // Add the element to the graphics containe
      graphicsContainer.addElement(element, 0);
    }
    catch (IOException ex)
    {
      System.out.println("Exception in displayAgentLocation : " + ex);
      ex.printStackTrace();
    }
  }

  /**
   * Creates a symbol based on the agent location.
   */
  public CharacterMarkerSymbol getMarkerSymbol(boolean located)
  {

    try
    {
      // Create a new font
      StdFont font = new StdFont();
      font.setName("ESRI Crime Analysis");
      font.setBold(true);
      // Create a new CharacterMarkerSymbol
      CharacterMarkerSymbol characterMarkerSymbol = new CharacterMarkerSymbol();
      characterMarkerSymbol.setFont(font);
      // Set the marker symbol properties
      if (located)
      {
        characterMarkerSymbol.setCharacterIndex(56);
        characterMarkerSymbol.setColor(getRGBColor(255, 0, 0));
        characterMarkerSymbol.setSize(30);
      }
      else
      {
        characterMarkerSymbol.setCharacterIndex(46);
        characterMarkerSymbol.setColor(getRGBColor(0, 0, 0));
        characterMarkerSymbol.setSize(30);
      }
      return characterMarkerSymbol;
    }
    catch (IOException ex)
    {
      ex.printStackTrace();
      return null;
    }
  }

  /**
   * Creates array of latitude and longitude values.
   */
  public void loadAgentArray()
  {
    // Populate an array of agent locations and id's.
    // The locations are in decimal degrees,
    // based on the WGS1984 geographic coordinate system. (ie unprojected).
    // Obviously, these values could be read directly from a GPS unit.
    for (int i = 0; i < agentArray.length; i++)
    {
      agentArray[i] = new AgentInField();
    }
    agentArray[0].CodeNumber = "001";
    agentArray[0].Latitude = 56.185128983308;
    agentArray[0].Longitude = 37.556904400607;
    agentArray[0].Located = false;
    agentArray[1].CodeNumber = "002";
    agentArray[1].Latitude = 48.3732928679818;
    agentArray[1].Longitude = 6.91047040971168;
    agentArray[1].Located = false;
    agentArray[2].CodeNumber = "003";
    agentArray[2].Latitude = 32.1487101669196;
    agentArray[2].Longitude = 39.3596358118361;
    agentArray[2].Located = false;
    agentArray[3].CodeNumber = "004";
    agentArray[3].Latitude = 29.7450682852807;
    agentArray[3].Longitude = 71.2078907435508;
    agentArray[3].Located = false;
    agentArray[4].CodeNumber = "005";
    agentArray[4].Latitude = 38.7587253414264;
    agentArray[4].Longitude = 138.509863429439;
    agentArray[4].Located = false;
    agentArray[5].CodeNumber = "006";
    agentArray[5].Latitude = 35.1532625189681;
    agentArray[5].Longitude = -82.0242792109256;
    agentArray[5].Located = false;
    agentArray[6].CodeNumber = "007";
    agentArray[6].Latitude = -26.1396054628225;
    agentArray[6].Longitude = 28.5432473444613;
    agentArray[6].Located = true;
    agentArray[7].CodeNumber = "008";
    agentArray[7].Latitude = 33.9514415781487;
    agentArray[7].Longitude = 3.90591805766313;
    agentArray[7].Located = false;
    agentArray[8].CodeNumber = "009";
    agentArray[8].Latitude = 29.7450682852807;
    agentArray[8].Longitude = 16.5250379362671;
    agentArray[8].Located = false;
    agentArray[9].CodeNumber = "010";
    agentArray[9].Latitude = 45.9696509863429;
    agentArray[9].Longitude = 23.1350531107739;
    agentArray[9].Located = false;
    agentArray[10].CodeNumber = "011";
    agentArray[10].Latitude = 48.9742033383915;
    agentArray[10].Longitude = 14.1213960546282;
    agentArray[10].Located = false;
    agentArray[11].CodeNumber = "012";
    agentArray[11].Latitude = 29.7450682852807;
    agentArray[11].Longitude = 79.0197268588771;
    agentArray[11].Located = false;
    agentArray[12].CodeNumber = "013";
    agentArray[12].Latitude = 43.5660091047041;
    agentArray[12].Longitude = 125.289833080425;
    agentArray[12].Located = false;
    agentArray[13].CodeNumber = "014";
    agentArray[13].Latitude = 7.5113808801214;
    agentArray[13].Longitude = -68.2033383915023;
    agentArray[13].Located = false;
    agentArray[14].CodeNumber = "015";
    agentArray[14].Latitude = 9.31411229135053;
    agentArray[14].Longitude = -79.6206373292868;
    agentArray[14].Located = false;
    agentArray[15].CodeNumber = "016";
    agentArray[15].Latitude = 8.71320182094082;
    agentArray[15].Longitude = -9.31411229135053;
    agentArray[15].Located = true;
    agentArray[16].CodeNumber = "017";
    agentArray[16].Latitude = 22.5341426403642;
    agentArray[16].Longitude = 53.7814871016692;
    agentArray[16].Located = false;
    agentArray[17].CodeNumber = "018";
    agentArray[17].Latitude = 42.3641881638847;
    agentArray[17].Longitude = 45.9696509863429;
    agentArray[17].Located = false;
    agentArray[18].CodeNumber = "019";
    agentArray[18].Latitude = 39.3596358118361;
    agentArray[18].Longitude = 27.9423368740516;
    agentArray[18].Located = false;
    agentArray[19].CodeNumber = "020";
    agentArray[19].Latitude = 22.5341426403642;
    agentArray[19].Longitude = 104.257966616085;
    agentArray[19].Located = false;
  }

  /**
   * Adds symbology to map
   */
  private void symbolizeData(ILayer layer, double width, IRgbColor colorLine, IRgbColor colorFill)
  {
    try
    {
      // Create a simple line symbol
      SimpleLineSymbol simpleLineSymbol = new SimpleLineSymbol();
      simpleLineSymbol.setWidth(width);
      simpleLineSymbol.setColor(colorLine);

      // Create a fill symbol
      SimpleFillSymbol fillSymbol = new SimpleFillSymbol();
      // Set the fill symbol properties
      fillSymbol.setOutline(simpleLineSymbol);
      fillSymbol.setColor(colorFill);

      // Create a simple renderer
      SimpleRenderer simpleRenderer = new SimpleRenderer();
      // Set the simple renderer properties
      simpleRenderer.setSymbolByRef(fillSymbol);

      // Create Featurelayer using layer Object
      FeatureLayer featureLayer = (FeatureLayer) layer;
      // Set featurelayer properties
      featureLayer.setRendererByRef(simpleRenderer);

    }
    catch (IOException ex)
    {
      System.out.println("Exception in symbolizeData : " + ex);
      ex.printStackTrace();
    }
  }

  /**
   * Sets the spatial reference property of the map control to projected coordinate system.
   */
  public void makeCoordinateSystem()
  {
    try
    {
      // Create a spatial reference environment
      SpatialReferenceEnvironment spatialReferenceEnvironment = new SpatialReferenceEnvironment();
      // Create a geographic coordinate system and get the IGeographicCoordinateSystem interface
      geographicCoordinateSystem = spatialReferenceEnvironment
          .createGeographicCoordinateSystem(esriSRGeoCSType.esriSRGeoCS_WGS1984);

      // Create a projected coordinate system
      projectedCoordinateSystem = spatialReferenceEnvironment
          .createProjectedCoordinateSystem(esriSRProjCSType.esriSRProjCS_World_Mollweide);
      // Set the map controls spatial reference property
      mapBean.setSpatialReferenceByRef(projectedCoordinateSystem);
    }
    catch (IOException ex)
    {
      System.out.println("Exception in makeCoordinateSystem : " + ex);
      ex.printStackTrace();
    }
  }

  /**
   * creates an rgb color object
   * 
   * @param red
   * @param green
   * @param blue
   * @return RgbColor
   */
  private RgbColor getRGBColor(int red, int green, int blue)
  {
    RgbColor rgbColor = null;
    try
    {
      // Create rgb color and grab hold of the IRGBColor interface
      rgbColor = new RgbColor();
      rgbColor.setRed(red);
      rgbColor.setGreen(green);
      rgbColor.setBlue(blue);
      rgbColor.setUseWindowsDithering(true);
    }
    catch (Exception ex)
    {
      System.out.println("Error in getRGBFunction :" + ex);
      ex.printStackTrace();
    }
    return rgbColor;
  }

  /**
   * Class which is to hold agent information
   */
  class AgentInField
  {
    public double Latitude;
    public double Longitude;
    public String CodeNumber;
    public boolean Located;
  }

  /**
   * Class which extends map control event class IMapControlEvents2Adapter
   * 
   * @see com.esri.arcgis.beans.map.IMapControlEvents2Adapter
   */
  class MapControlListener extends IMapControlEvents2Adapter
  {
    private static final long serialVersionUID = 1L;

    /**
     * @see com.esri.arcgis.beans.map.IMapControlEvents2Adapter#onMouseDown(IMapControlEvents2OnMouseDownEvent
     *      theEvent)
     * @param theEvent
     */
    public void onMouseDown(IMapControlEvents2OnMouseDownEvent theEvent)
    {
      try
      {
        // If left mouse button then zoom in
        if (theEvent.getButton() == 1)
        {
          mapBean.setExtent(mapBean.trackRectangle());
        }
        else
        {
          // Create a point
          Point point = new Point();
          point.putCoords(theEvent.getMapX(), theEvent.getMapY());
          // Create a polygon by buffering the point
          Polygon polygon = (Polygon) point.buffer(mapBean.getExtent().getWidth() * 0.02);
          // Draw the polygon
          mapBean.drawShape(polygon, null);
          // Loop through the elements in the GraphicContainer and get the IElement interface
          graphicsContainer.reset();
          IElement element = graphicsContainer.next();
          while (element != null)
          {
            // If the polygon contains the point
            if (polygon.contains(element.getGeometry()))
            {
              // Create a marker symbol using IElement inteface
              MarkerElement markerElement = (MarkerElement) element;
              markerElement.setSymbol(getMarkerSymbol(true));
              // Get Elmentproperties and set the value to true
              markerElement.setName("True");
            }
            element = graphicsContainer.next();
          }

          if (!gpsTrackingCheck.isSelected())
          {
            // Refresh the graphics
            mapBean.refresh(esriViewDrawPhase.esriViewGraphics, null, null);
          }
        }
      }
      catch (Exception ex)
      {
        System.out.println("Exception in MapControlListener#onMouseDown : " + ex);
        ex.printStackTrace();
      }
    }
  }// End of MapControlListener class

  /**
   * Timer listener which extends from ActionListner. Used to randomly assign new x and y coordinates to each point
   * within the GraphicsContainer after a specified time interval
   */
  class TimerListener implements ActionListener
  {
    public void actionPerformed(ActionEvent event)
    {
      Random random = new Random();

      //
      // Loop through the elements in the GraphicContainer and move them a little,
      // but keep them within the limits of the projection.
      //
      try
      {
        graphicsContainer.reset();
        IElement element = null;
        for (element = graphicsContainer.next(); element != null; element = graphicsContainer.next())
        {
          MarkerElement markerElement = (MarkerElement) element;
          if (markerElement.getName().equalsIgnoreCase("True"))
          {
            continue;
          }
          moveElement(element, random);
        }
        mapBean.refresh(esriViewDrawPhase.esriViewGraphics, null, null);
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
    }

    void moveElement(IElement element, Random random) throws UnknownHostException, IOException
    {
      double maxLatChange = 10.0;
      double maxLngChange = 20.0;
      double x = 0, y = 0;
      Point point = new Point();
      point = (Point) element.getGeometry();
      point.project(geographicCoordinateSystem);
      //
      // An AutomationException can be thrown when calling getX or getY on
      // a point that has been "invalidated" by doing a projection on it when
      // it had bad coordinates. This happens when the latitute is beyond or
      // very near the poles. If this happens, we just reset the point to 0,0.
      // In the longitude direction, this doesn't happen as often because
      // these wrap around. That is, you can set a value greater than 180 or
      // less than -180 and the point doesn't get invalidated upon projection.
      // There is a limit, however.
      //
      try
      {
        x = point.getX() - (maxLngChange * (random.nextDouble() - 0.5));
        y = point.getY() - (maxLatChange * (random.nextDouble() - 0.5));
      }
      catch (AutomationException e)
      {
        // The point was invalidated, so x & y are 0
      }
      point.setX(x);
      point.setY(y);
      point.project(projectedCoordinateSystem);
      element.setGeometry(point);
    }
  }

  public static void main(String s[]){
    try{
      EngineInitializer.initializeVisualBeans();
      // Set the system look and feel
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

      initializeArcGISLicenses();

      TrackGPS geoEvents = new TrackGPS();
      geoEvents.setDefaultCloseOperation(TrackGPS.EXIT_ON_CLOSE);
    }catch (Exception ex){
      ex.printStackTrace();
    }
  }

  static void initializeArcGISLicenses() {
    try {
      AoInitialize ao = new AoInitialize();
      
      if (ao.isProductCodeAvailable(esriLicenseProductCode.esriLicenseProductCodeEngine) 
          == esriLicenseStatus.esriLicenseAvailable)
        ao.initialize(esriLicenseProductCode.esriLicenseProductCodeEngine);
      else if (ao.isProductCodeAvailable(esriLicenseProductCode.esriLicenseProductCodeArcView) 
          == esriLicenseStatus.esriLicenseAvailable)
        ao.initialize(esriLicenseProductCode.esriLicenseProductCodeArcView);
    } catch (Exception e) {e.printStackTrace();}
  }
}