arcgissamples\cartography\CustomCircleCallout.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.cartography; import java.io.IOException; import com.esri.arcgis.display.ICallout; import com.esri.arcgis.display.IColor; import com.esri.arcgis.display.IDisplayName; import com.esri.arcgis.display.IDisplayTransformation; import com.esri.arcgis.display.IQueryGeometry; import com.esri.arcgis.display.ITextBackground; import com.esri.arcgis.display.ITextSymbol; import com.esri.arcgis.display.RgbColor; import com.esri.arcgis.display.SimpleFillSymbol; import com.esri.arcgis.display.SimpleLineSymbol; import com.esri.arcgis.geometry.CircularArc; import com.esri.arcgis.geometry.Envelope; import com.esri.arcgis.geometry.IEnvelope; import com.esri.arcgis.geometry.IGeometry; import com.esri.arcgis.geometry.IPoint; import com.esri.arcgis.geometry.IPolygon; import com.esri.arcgis.geometry.ITransformation; import com.esri.arcgis.geometry.Point; import com.esri.arcgis.geometry.Polygon; import com.esri.arcgis.geometry.Polyline; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.system.IClone; /** * This sample shows how you can extend ArcObjects to build a new custom textbackground. * ArcMap ships with several textbackgrounds including: Balloon Callout, Line Callout, * Marker Text Background, and Simple Line Callout. * This new textbackground is a Circle Line Callout and it is very similar to * the Balloon callout except, like its name suggests, it is circle and for simplicity sake, * its leader line is just a straight line. * The class implements IClone, ICallout, ITextBackground, IQueryGeometry, IDisplayName interfaces. */ public class CustomCircleCallout implements IClone, ICallout, ITextBackground, IQueryGeometry, IDisplayName { private static final long serialVersionUID = 1L; // These members are controlled by properties double size; IColor color; double leaderTolerance; Envelope textBox; IPoint anchorPoint; IGeometry geometry; SimpleFillSymbol fillSymbol; IPoint textBoxCenterPt; SimpleLineSymbol leaderSymbol; /** * Default constructor. */ CustomCircleCallout() { try { this.fillSymbol = new SimpleFillSymbol(); this.leaderSymbol = new SimpleLineSymbol(); this.size = 20; // default size // default color RgbColor rgbColor = new RgbColor(); rgbColor.setRed(255); rgbColor.setGreen(255); this.color = rgbColor; this.fillSymbol.setColor(rgbColor); } catch( IOException e) { // never happened } } // IClone interface /** * @see IClone#esri_clone * @return IClone */ public IClone esri_clone() { CustomCircleCallout textCallout = new CustomCircleCallout(); textCallout.setSize(this.size); textCallout.setColor(this.color); textCallout.setAnchorPoint(this.anchorPoint); textCallout.setLeaderTolerance(this.leaderTolerance); return textCallout; } /** * @see IClone#assign * @param clone */ public void assign(IClone clone) { // no implement } /** * @see IClone#isEqual * @param clone * @return boolean */ public boolean isEqual(IClone clone) { return false; } /** * @see IClone#isIdentical * @param clone * @return boolean */ public boolean isIdentical(IClone clone) { return false; } // ICallout interface /** * @see ICallout#getAnchorPoint * @return boolean */ public IPoint getAnchorPoint() { return this.anchorPoint; } /** * @see ICallout#setAnchorPoint * @param point */ public void setAnchorPoint(IPoint point) { this.anchorPoint = point; } /** * @see ICallout#getLeaderTolerance * @return double */ public double getLeaderTolerance() { return this.leaderTolerance; } /** * @see ICallout#setLeaderTolerance * @param v */ public void setLeaderTolerance(double v) { this.leaderTolerance = v; } // ITextBackground interface /** * @see ITextBackground#getTextSymbol * @return ITextSymbol */ public ITextSymbol getTextSymbol() { // no implement return null; } /** * @see ITextBackground#setTextSymbolByRef * @param textSymbol */ public void setTextSymbolByRef(ITextSymbol textSymbol) { // no implement } /** * @see ITextBackground#setTextBoxByRef * @param envelope * @throws IOException * @throws AutomationException */ @SuppressWarnings("deprecation") public void setTextBoxByRef(IEnvelope envelope) throws IOException, AutomationException { this.textBox = (Envelope) envelope; this.textBoxCenterPt = new Point(); this.textBoxCenterPt.setX((this.textBox.getXMin() + this.textBox.getXMax()) / 2); this.textBoxCenterPt.setY((this.textBox.getYMin() + this.textBox.getYMax()) / 2); } /** * @see ITextBackground#queryBoundary * @param hDC * @param transformation * @param boundary * @throws IOException * @throws AutomationException */ public void queryBoundary(int hDC, ITransformation transformation, IPolygon boundary) throws IOException, AutomationException { //Forward the call down do the symbol //This will populate Boundary with a polygon based on the circle's envelope IDisplayTransformation displayTransformation = (IDisplayTransformation)(transformation); this.fillSymbol.queryBoundary(hDC, transformation, CreateGeometry(this.textBoxCenterPt, displayTransformation).getEnvelope(), boundary); Polygon polygon = (Polygon) boundary; polygon.simplify(); //Make sure it's simple //Create a polygon buffer around the leader line Polyline polyline = CreateLeader(); double dBufferSize = displayTransformation.fromPoints(1); Polygon bufferedLeader = (Polygon) polyline.buffer(dBufferSize); bufferedLeader.simplify(); //Union the buffered leader with the circle geometry //to create the final shape that needs refreshing bufferedLeader = (Polygon) polygon.union(bufferedLeader); //Don't want to pass back a different Boundary reference //Set our new geometry into the passed in Boundary reference - performance! IClone clone = (polygon); IClone bufLead = (bufferedLeader); clone.assign(bufLead); } /** * @see ITextBackground#draw * @param hDC * @param transformation * @throws IOException * @throws AutomationException */ public void draw(int hDC, ITransformation transformation) throws IOException, AutomationException { //Draw the leader Polyline line = CreateLeader(); IDisplayTransformation displayTransform = (IDisplayTransformation)(transformation); //Only draw the leader if it is longer than the tolerance if (line != null) { if (line.getLength() > displayTransform.fromPoints(this.leaderTolerance)) { this.leaderSymbol.setupDC(hDC, transformation); this.leaderSymbol.draw(line); this.leaderSymbol.resetDC(); } } IDisplayTransformation displayTransformation = (IDisplayTransformation)(transformation); Polygon polygon = CreateGeometry(this.textBoxCenterPt, displayTransformation); this.geometry = polygon; //Draw the circle if (this.geometry == null) return; this.fillSymbol.setColor(this.color); //use the color property this.fillSymbol.setupDC(hDC, transformation); this.fillSymbol.draw(this.geometry); this.fillSymbol.resetDC(); } // IQueryGeometry interface /** * @see IQueryGeometry#getGeometry * @param i * @param transformation * @param geom * @throws IOException * @throws AutomationException * @return IGeometry */ public IGeometry getGeometry( int i, ITransformation transformation, IGeometry geom) throws IOException, AutomationException { return CreateLeader(); } /** * @see IQueryGeometry#queryEnvelope * @param i * @param transformation * @param geom * @param envelope */ @SuppressWarnings("deprecation") public void queryEnvelope(int i, ITransformation transformation, IGeometry geom, IEnvelope envelope) { // no implement } // IDisplayName interface /** * @see IDisplayName#getNameString * @return String */ public String getNameString() { return "Circle Line Callout"; } // own public methods /** * Set symbool size. * @param sz double */ public void setSize(double sz) { this.size = sz; } /** * Return simbol size. * @return double */ public double getSize() { return this.size; } /** * Set symbol color. * @param clr is IColor object */ public void setColor(IColor clr) { this.color = clr; } /** * Return symbol color. * @return IColor object */ public IColor getColor() { return this.color; } // private methods private Polygon CreateGeometry(IPoint point, IDisplayTransformation displayTransformation) throws IOException, AutomationException { CircularArc circularArc = new CircularArc(); //Access radius from property circularArc.constructCircle(point, displayTransformation.fromPoints(this.size), true); Polygon polygon = new Polygon(); polygon.addSegment(circularArc,null,null); polygon.simplify(); return polygon; } private Polyline CreateLeader() throws IOException, AutomationException { if (this.anchorPoint == null || this.textBoxCenterPt == null) { return null; } Polyline polyline = new Polyline(); polyline.addPoint(this.anchorPoint, null, null); polyline.addPoint(this.textBoxCenterPt, null, null); return polyline; } }