Dynamic layers
arcgissamples\display\MyDynamicLayer.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.display;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Vector;

import com.esri.arcgis.carto.IDynamicLayer;
import com.esri.arcgis.carto.ILayer;
import com.esri.arcgis.display.CharacterMarkerSymbol;
import com.esri.arcgis.display.IDisplay;
import com.esri.arcgis.display.IDynamicDisplay;
import com.esri.arcgis.display.IDynamicGlyph;
import com.esri.arcgis.display.IDynamicGlyphFactory;
import com.esri.arcgis.display.IDynamicSymbolProperties;
import com.esri.arcgis.display.IDynamicSymbolProperties2;
import com.esri.arcgis.display.ISymbol;
import com.esri.arcgis.display.RgbColor;
import com.esri.arcgis.display.esriDynamicDrawPhase;
import com.esri.arcgis.display.esriDynamicSymbolRotationAlignment;
import com.esri.arcgis.display.esriDynamicSymbolType;
import com.esri.arcgis.geodatabase.IGeoDataset;
import com.esri.arcgis.geometry.Envelope;
import com.esri.arcgis.geometry.IEnvelopeGEN;
import com.esri.arcgis.geometry.ISpatialReference;
import com.esri.arcgis.geometry.Point;
import com.esri.arcgis.interop.AutomationException;
import com.esri.arcgis.system.ITrackCancel;
import com.esri.arcgis.system.IUID;
import com.esri.arcgis.system.IVariantStream;
import com.esri.arcgis.system._WKSPoint;
import com.esri.arcgis.system.esriDrawPhase;

public class MyDynamicLayer implements Runnable, IDynamicLayer,ILayer,IGeoDataset{

  private static final long serialVersionUID = 1L;
  private boolean dynamicGlyphsCreated = false;
    private Vector <_WKSPoint> points = new Vector<_WKSPoint>();
    private IDynamicSymbolProperties dynamicSymbolProps = null;
    private IDynamicGlyphFactory dynamicGlyphFactory= null;
    //private IDynamicCompoundMarker2 dynamicCompoundMarker =null;
    private int index=0;
    private String name="";
  private IEnvelopeGEN extent=null;
  private ISpatialReference spatialRef = null;
  private boolean isCached = false;
  @SuppressWarnings("unused")
  private boolean isValid, isVisible = true;
  private double maximumScale, minimumScale = 0;
  private boolean showTips = false;
  private boolean isDirtyImmediate;
  private boolean isDirtyCompiled;
  private int recompileRate;
  private IDynamicGlyph markerGlyph;
  private Point point=null;
  private IDisplay display;
  private boolean endOfData=false;
    
   public MyDynamicLayer(Vector<_WKSPoint> points) {
      try {
        //set Name of the Layer
        this.setName("Dynamic Layer");
        //Assign the data value
        this.points=points;
        //instantiate necessary variables
        point=new Point();
        //Start the thread
        Thread dirtybitThread=new Thread(this);
        dirtybitThread.start();
      } catch (UnknownHostException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
      
    }
  
  
  //This method sets the dirty flag for the layer every 300ms
  public void run() {
    try {
      while(!endOfData){
        if(isVisible()){
         //Step 1: Get the current location of the item 
        _WKSPoint currPoint = points.elementAt(index++);
            point.putCoords(currPoint.x, currPoint.y);
        if (display!=null){
           //pan the map programmatically, so the marker will always be at the center
               centerMap(display);
        }
        //set the dirty property to true, so the marker can be drawn in new location
        this.setDynamicLayerDirty(esriDynamicDrawPhase.esriDDPImmediate,true);
        Thread.sleep(30);
        }
      }
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    
    
  }
  
   // This method renders the dynamic layer
  public void drawDynamicLayer(int phase, IDisplay display, IDynamicDisplay dynamicDisplay) throws IOException, AutomationException {
    try{
      //Need to draw layers only in one phase for performance reasons
      if(phase==esriDynamicDrawPhase.esriDDPCompiled)
        return;
      //Assign the display variable to center map
      this.display=display;
      //Draw Dynamic marker at the current location of the item using Dynamic Display API's
      drawDynamicSymbols(dynamicDisplay);
      //Step 3: set the dirty bit to false 
      this.setDynamicLayerDirty(esriDynamicDrawPhase.esriDDPImmediate,false);


    }catch(Exception e){
      e.printStackTrace();
    }

  }
  
  //This method creates a glyph from CharacterMarkerSymbol
   
  private void createDynamicSymbols()
    {
      try{
     
      // Create Character Marker Symbols
      CharacterMarkerSymbol characterMarkerSymbol = new CharacterMarkerSymbol();
      RgbColor color=new RgbColor();
    color.setRGB(0xFFFFFF);
      characterMarkerSymbol.setColor(color);
      characterMarkerSymbol.setSize(40);
      characterMarkerSymbol.setAngle(0);
      characterMarkerSymbol.setCharacterIndex(73);
      
      //Create Glyph from symbol
      markerGlyph = dynamicGlyphFactory.createDynamicGlyph((ISymbol)characterMarkerSymbol);
     
      
    }catch(Exception e){
      e.printStackTrace();
    }
      }
  
  //This method draws the dynamic marker on the layer
  private void drawDynamicSymbols(IDynamicDisplay dynamicDisplay) throws AutomationException, IOException{
    // Step 1: Create Glyphs & Symbols
    /* Best Practice:Need to do it only once to 
     * avoid reinitializing variables
     * and creating glyphs,( glyphs are expensive)
     */
    if (!dynamicGlyphsCreated)
        {
          dynamicSymbolProps = (IDynamicSymbolProperties2) dynamicDisplay;
          dynamicGlyphFactory =dynamicDisplay.getDynamicGlyphFactory();
          //dynamicCompoundMarker = (IDynamicCompoundMarker2)dynamicDisplay;
          this.createDynamicSymbols();
          dynamicGlyphsCreated = true;
          
        }
    
    //Step 2. Set the symbol alignment so that it will align with the screen
    dynamicSymbolProps.setRotationAlignment(esriDynamicSymbolType.esriDSymbolMarker, esriDynamicSymbolRotationAlignment.esriDSRAScreen);

    //Step 3. Scale the item
    dynamicSymbolProps.setScale(esriDynamicSymbolType.esriDSymbolMarker, 0.8f,0.8F);
    
    //Step 4. set the items' color 
    dynamicSymbolProps.setColor(esriDynamicSymbolType.esriDSymbolMarker, 1.0f, 0.0f, 0.0f, 1.0f);
    
    
    //Step 5. assign the glyph to the dynamic-symbol
    dynamicSymbolProps.setDynamicGlyphByRef(esriDynamicSymbolType.esriDSymbolMarker, markerGlyph);
    
    
    //Step 6: draw the symbol
    dynamicDisplay.drawMarker(point);
    //
      
    //draw the item as a compound marker. This mean that you do not have to draw the items and its
    //accompanying labels separately, and thus allow you to write less code as well as get better
    //performance.
    //dynamicCompoundMarker.drawCompoundMarker2(point,  String.valueOf(point.getX()) ,String.valueOf(point.getX()));
        }

  
    /* This method pans the map,
    * so that the dynamic marker will always be at the center
    */
   public void centerMap(IDisplay display) throws Exception
      {
     if (index == (points.size() - 1))
        {
       System.out.println("stopping...");
       endOfData=true;
          return;
        }
        //get the current map visible extent
        IEnvelopeGEN envelope = (IEnvelopeGEN)display.getDisplayTransformation().getVisibleBounds();
        //center the map around the current coordinate
        envelope.centerAt(point);
        _WKSPoint nextPoint=points.elementAt(index);
        //Calculate the azimuth and setRotation of the map
        double azimuth = (180.0 / Math.PI) * Math.atan2(nextPoint.x - point.getX(), nextPoint.y - point.getY());
        display.getDisplayTransformation().setVisibleBounds((Envelope)envelope);
        display.getDisplayTransformation().setRotation(azimuth);
        
      }
   
   /*
     * @see com.esri.arcgis.carto.IDynamicLayer#isDynamicLayerDirty(int)
     * This method is called by the DD framework every draw cycle to check whether the layer is dirty
     * If the layer is dirty the DD framework calls the drawDynamicLayer() method to render the layer
     */
   
   public boolean isDynamicLayerDirty(int drawPhase) throws IOException, AutomationException {
      if (drawPhase == esriDynamicDrawPhase.esriDDPImmediate)
            return isDirtyImmediate;
      else
          return isDirtyCompiled;
  }
   
   /*
    * @see com.esri.arcgis.carto.IDynamicLayer#setDynamicLayerDirty(int, boolean)
    * This method sets the dirty flag for the dynamic layer for the corresponding phases
    */

  public void setDynamicLayerDirty(int drawPhase, boolean dirtyBit) throws IOException, AutomationException {
     if (drawPhase == esriDynamicDrawPhase.esriDDPImmediate)
            isDirtyImmediate = dirtyBit;
     else
       isDirtyCompiled = dirtyBit;
  }
  /*
   * @see com.esri.arcgis.carto.IDynamicLayer#getDynamicRecompileRate()
   * This method is called by the DD framework to determine the recompile rate for the layer
   */
  public int getDynamicRecompileRate() throws IOException, AutomationException {
    return this.recompileRate;
  }


  public String getName() throws IOException, AutomationException {
    return name;
  }

  public void setName(String layerName) throws IOException, AutomationException {
    name = layerName;
  }

  public boolean isValid() throws IOException, AutomationException {
    return true;
  }

  public double getMinimumScale() throws IOException, AutomationException {
    return minimumScale;
  }

  public void setMinimumScale(double scale) throws IOException, AutomationException {
    minimumScale = scale;    
  }

  public double getMaximumScale() throws IOException, AutomationException {
    return maximumScale;
  }

  public void setMaximumScale(double scale) throws IOException, AutomationException {
    maximumScale = scale;
  }

  public boolean isVisible() throws IOException, AutomationException {
    return isVisible;
  }

  public void setVisible(boolean visible) throws IOException, AutomationException {
    isVisible = visible;
  }

  public boolean isShowTips() throws IOException, AutomationException {
    return showTips;
  }

  public void setShowTips(boolean tips) throws IOException, AutomationException {
  showTips = tips;
  }

  public boolean isCached() throws IOException, AutomationException {
  
    return isCached;
  }

  public void setCached(boolean cached) throws IOException, AutomationException {
    isCached = cached;  
  }
  
  public void setSpatialReferenceByRef(ISpatialReference spatialRef) throws IOException, AutomationException {
    this.spatialRef = spatialRef;  
  }
  
  public ISpatialReference getSpatialReference() throws IOException, AutomationException {
    return spatialRef;
  }

  public Envelope getExtent() throws IOException, AutomationException {
    return (Envelope)extent;
  }

  public IUID getID() throws IOException, AutomationException {
    return null;
  }
  
public void load(IVariantStream arg0) throws IOException, AutomationException {
    //Not Supported in Java
  }

  public void save(IVariantStream arg0) throws IOException, AutomationException {
    //Not Supported in Java
  }
  
  public Envelope getAreaOfInterest() throws IOException, AutomationException {
    return (Envelope)extent;
  }
  
  public double getLastMinimumScale() throws IOException, AutomationException {
    return 0;
  }

  public double getLastMaximumScale() throws IOException, AutomationException {
    return 0;
  }

  public String ILayerGeneralProperties_getLayerDescription() throws IOException, AutomationException {
    return null;
  }
  
public void setLayerDescription(String arg0) throws IOException, AutomationException {
    
  }
  
  public String getTipText(double arg0, double arg1, double arg2) throws IOException, AutomationException {
    return null;
  }
  
  public int getSupportedDrawPhases() throws IOException, AutomationException {
    return esriDrawPhase.esriDPAnnotation;
  }

//  Method not implemented;Layer will be drawn only in dynamic mode
public void draw(int arg0, IDisplay arg1, ITrackCancel arg2) throws IOException, AutomationException{
  
}


}