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.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.HashMap; import javax.swing.Timer; 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.IDynamicCompoundMarker; 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.RgbColor; import com.esri.arcgis.display.esriDynamicDrawPhase; import com.esri.arcgis.display.esriDynamicGlyphType; 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.support.ms.stdole.StdFont; import com.esri.arcgis.system.ITrackCancel; import com.esri.arcgis.system.IUID; import com.esri.arcgis.system.esriDrawPhase; public class MyDynamicLayer implements IDynamicLayer, ILayer, IGeoDataset{ private static final long serialVersionUID = 1L; private Point point = null; private boolean dynamicGlyphsCreated = false; private ActionListener task = null; private double extentMaxX = 1000.0; private double extentMinX =0; private double extentMaxY = 1000.0; private double extentMinY= 0; private HashMap<Integer, NavigationData> dataMap; 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 Timer timer = null; private IDynamicSymbolProperties dynamicSymbolProps = null; private IDynamicGlyphFactory dynamicGlyphFactory= null; private IDynamicCompoundMarker dynamicCompoundMarker =null; private IDynamicGlyph[] markerGlyphs = null; private IDynamicGlyph textglyphs = null; private boolean isDirtyImmediate; private boolean isDirtyCompiled; public MyDynamicLayer(HashMap<Integer, NavigationData> map) { try { //set the name of the layer this.setName("Tracks"); //instantiate necessary variables point = new Point(); markerGlyphs = new IDynamicGlyph[3]; this.dataMap=map; } catch (IOException e) { System.out.println("Exception in MyDynamicLayer#MyDynamicLayer"); e.printStackTrace(); } //Create a timer and attach a listener that would fire events every 30ms. task = new ActionListener() { public void actionPerformed(ActionEvent evt) { try { //The dirty flag is set to true every 30ms //to force the DD framework to redraw the layer setDynamicLayerDirty(esriDynamicDrawPhase.esriDDPImmediate, true); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; timer = new Timer(30, task); } /* * @see com.esri.arcgis.carto.IDynamicLayer#drawDynamicLayer(int, com.esri.arcgis.display.IDisplay, com.esri.arcgis.display.IDynamicDisplay) * This method is invoked by the DD framework to render the dynamic layer */ public void drawDynamicLayer(int phase, IDisplay display, IDynamicDisplay dynamicDisplay) throws IOException, AutomationException { if (display == null) { System.out.println("Error, could not render layer"); return; } if (!isVisible()||!isValid()) { System.out.println("Not Visisble or Not valid: Could not render layer"); return; } //It is recommended to draw layers only in one phase for performance reasons if (esriDynamicDrawPhase.esriDDPImmediate != phase) { return; } //get the display fitted bounds to generate random location for the items extentMaxX = ((Envelope)display.getDisplayTransformation().getFittedBounds()).getXMax(); extentMaxY = ((Envelope)display.getDisplayTransformation().getFittedBounds()).getYMax(); extentMinX = ((Envelope)display.getDisplayTransformation().getFittedBounds()).getXMin(); extentMinY = ((Envelope)display.getDisplayTransformation().getFittedBounds()).getYMin(); //updates the current location of all 100 dynamic items onUpdate(); //Draw the symbols in the random generated location drawDynamicSymbols(dynamicDisplay); //the dirty flag is set to false to avoid drawing in subsequent draw cycles. this.setDynamicLayerDirty(esriDynamicDrawPhase.esriDDPImmediate, false); } /* * This method draws 100 items on a random location * generated from the visible bounds of the current map */ private void drawDynamicSymbols(IDynamicDisplay dynamicDisplay) throws IOException { if (!dynamicGlyphsCreated) { dynamicSymbolProps = (IDynamicSymbolProperties)dynamicDisplay; dynamicGlyphFactory = dynamicDisplay.getDynamicGlyphFactory(); dynamicCompoundMarker = (IDynamicCompoundMarker)dynamicDisplay; //Glyphs are expensive hence should be created only once this.createDynamicSymbols(dynamicGlyphFactory); dynamicGlyphsCreated = true; } double X, Y, heading; int type; //draw the 100 items whose location is provided by the dataMap for(int i=0;i<this.dataMap.size();i++){ NavigationData navData = this.dataMap.get(new Integer(i)); X = navData.x; Y = navData.y; heading = navData.azimuth; type = navData.type; point.putCoords(X,Y); //set the symbol's properties switch (type) { case 0: //set the heading of the current symbols' text dynamicSymbolProps.setHeading(esriDynamicSymbolType.esriDSymbolText, (float)heading); //set the symbol alignment so that it will align with the screen dynamicSymbolProps.setRotationAlignment(esriDynamicSymbolType.esriDSymbolMarker, esriDynamicSymbolRotationAlignment.esriDSRAScreen); //set the text alignment so that it will also align with the screen dynamicSymbolProps.setRotationAlignment(esriDynamicSymbolType.esriDSymbolText, esriDynamicSymbolRotationAlignment.esriDSRAScreen); //scale the item dynamicSymbolProps.setScale(esriDynamicSymbolType.esriDSymbolMarker, 0.8f,0.8F); //set the items' color (blue) dynamicSymbolProps.setColor(esriDynamicSymbolType.esriDSymbolMarker, 0.0f, 0.0f, 1.0f, 1.0f); // Blue //assign the item's glyph to the dynamic-symbol dynamicSymbolProps.setDynamicGlyphByRef(esriDynamicSymbolType.esriDSymbolMarker, markerGlyphs[0]); dynamicSymbolProps.setDynamicGlyphByRef(esriDynamicSymbolType.esriDSymbolText, textglyphs); //set the color of the text dynamicSymbolProps.setColor(esriDynamicSymbolType.esriDSymbolText, 1.0f, 0.0f, 0.0f, 1.0f); // Yellow //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.drawCompoundMarker6 (point, "TOP", "BOTTOM", "Item " + i, String.valueOf(heading), String.valueOf(X), String.valueOf(Y)); break; case 1: //set the heading of the current symbol dynamicSymbolProps.setHeading(esriDynamicSymbolType.esriDSymbolMarker, (float)heading); //set the symbol alignment so that it will align towards the symbol heading dynamicSymbolProps.setRotationAlignment(esriDynamicSymbolType.esriDSymbolMarker, esriDynamicSymbolRotationAlignment.esriDSRANorth); dynamicSymbolProps.setScale(esriDynamicSymbolType.esriDSymbolMarker, 1.0f,1.0F); dynamicSymbolProps.setColor(esriDynamicSymbolType.esriDSymbolMarker, 0.0f, 1.0f, 0.6f, 1.0f); // GREEN dynamicSymbolProps.setDynamicGlyphByRef(esriDynamicSymbolType.esriDSymbolMarker, markerGlyphs[1]); //draw the current location dynamicDisplay.drawMarker(point); break; case 2: //set the heading of the current symbol dynamicSymbolProps.setHeading(esriDynamicSymbolType.esriDSymbolMarker, (float)heading + 180.0f); //set the symbol alignment so that it will align with towards the symbol heading dynamicSymbolProps.setRotationAlignment(esriDynamicSymbolType.esriDSymbolMarker, esriDynamicSymbolRotationAlignment.esriDSRANorth); dynamicSymbolProps.setScale(esriDynamicSymbolType.esriDSymbolMarker, 1.5f, 1.5F); dynamicSymbolProps.setColor(esriDynamicSymbolType.esriDSymbolMarker, 1.0f, 1.0f, 1.0f, 1.0f); // WHITE dynamicSymbolProps.setDynamicGlyphByRef(esriDynamicSymbolType.esriDSymbolMarker, markerGlyphs[2]); //draw the current location dynamicDisplay.drawMarker(point); break; } } } /* * This method creates three different dynamic glyphs from graphic resources */ private void createDynamicSymbols(IDynamicGlyphFactory dynamicGlyphFactory) throws IOException, AutomationException { // Create Character Marker Symbols StdFont fontEsri = new StdFont(); fontEsri.setName("ESRI Environmental & Icons"); fontEsri.setSize(32); CharacterMarkerSymbol characterMarkerSymbol = new CharacterMarkerSymbol(); RgbColor color = new RgbColor(); color.setRed(255); color.setGreen(255); color.setBlue(255); characterMarkerSymbol.setColor(color); characterMarkerSymbol.setFont(fontEsri); characterMarkerSymbol.setSize(40); characterMarkerSymbol.setAngle(0); characterMarkerSymbol.setCharacterIndex(36); //Create glyphs from character marker symbol markerGlyphs[0] = dynamicGlyphFactory.createDynamicGlyph(characterMarkerSymbol); textglyphs = dynamicGlyphFactory.getDynamicGlyph(1,esriDynamicGlyphType.esriDGlyphText,1); characterMarkerSymbol.setSize(32); characterMarkerSymbol.setCharacterIndex(224); markerGlyphs[1] = dynamicGlyphFactory.createDynamicGlyph(characterMarkerSymbol); //Create gylph from bitmap // Sets the transparency color RgbColor tranparencyColor = new RgbColor(); tranparencyColor.setRed( 0); tranparencyColor.setGreen(0); tranparencyColor.setBlue(0); tranparencyColor.setGreen(255); tranparencyColor.setBlue(255); 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 bitmapPath = devKitHome + "java" + File.separator + "samples" + File.separator + "data" + File.separator + "display" + File.separator + "B2.bmp"; markerGlyphs[2] = dynamicGlyphFactory.createDynamicGlyphFromFile(esriDynamicGlyphType.esriDGlyphMarker,bitmapPath,tranparencyColor); } /* * This method updates the location of the 100 dynamic items stored in the hash map */ public void onUpdate(){ try{ double X, Y, stepX, stepY, heading; //iterate through the layers' records for (int i=0;i<this.dataMap.size();i++) { NavigationData navdata = this.dataMap.get(new Integer(i)); //get the current item location and the item's steps X =navdata.x; Y = navdata.y; stepX = navdata.stepx; stepY = navdata.stepy; //increment the item's location X += stepX; Y += stepY; //test that the item's location is within the fitted bounds if (X > extentMaxX) stepX = -Math.abs(stepX); if (X < extentMinX) stepX = Math.abs(stepX); if (Y > extentMaxY) stepY = -Math.abs(stepY); if (Y < extentMinY) stepY = Math.abs(stepY); //calculate the item's heading heading = (360.0 + 90.0 - Math.atan2(stepY, stepX) *( 180 / Math.PI)) % 360.0; //update the item's record navdata.x = X; navdata.y = Y; navdata.stepx = stepX; navdata.stepy= stepY; navdata.azimuth= heading; this.dataMap.put(new Integer(i), navdata); } }catch(Exception e){ e.printStackTrace(); } } /* * This method starts the timer and fires the timer event at specified intervals */ public void start(){ timer.start(); } /* * This method stops the timer */ public void stop(){ timer.stop(); } /* * @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 phase) throws IOException, AutomationException { if (phase == esriDynamicDrawPhase.esriDDPImmediate) return isDirtyImmediate; 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 phase, boolean dirtyFlag) throws IOException, AutomationException { if (phase == esriDynamicDrawPhase.esriDDPImmediate) isDirtyImmediate = dirtyFlag; else isDirtyCompiled=dirtyFlag; } /* * @see com.esri.arcgis.carto.IDynamicLayer#getDynamicRecompileRate() * This method is called by the DD framework to determine the recompile rate for the layer * Since the layer is always drawn in immediate phase it is set to -1 */ public int getDynamicRecompileRate() throws IOException, AutomationException { return -1; } public int getSupportedDrawPhases() throws IOException, AutomationException { return esriDrawPhase.esriDPAnnotation; } /* * @see com.esri.arcgis.carto.ILayer#draw(int, com.esri.arcgis.display.IDisplay, com.esri.arcgis.system.ITrackCancel) * This method is not implemented and hence will not draw in non-dynamic mode */ public void draw(int arg0, IDisplay arg1, ITrackCancel arg2) throws IOException, AutomationException{ } public String getName() throws IOException, AutomationException { return name; } public void setName(String name) throws IOException, AutomationException { this.name = name; } 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 showTips) throws IOException, AutomationException { this.showTips = showTips; } public boolean isCached() throws IOException, AutomationException { return isCached; } public void setCached(boolean cache) throws IOException, AutomationException { isCached = cache; } 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 Envelope getAreaOfInterest() throws IOException, AutomationException { return (Envelope)extent; } public String getTipText(double arg0, double arg1, double arg2) throws IOException, AutomationException { return null; } }