Source for org.jfree.chart.annotations.XYLineAnnotation

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * ---------------------
  28:  * XYLineAnnotation.java
  29:  * ---------------------
  30:  * (C) Copyright 2003-2007, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * Changes:
  36:  * --------
  37:  * 02-Apr-2003 : Version 1 (DG);
  38:  * 19-Aug-2003 : Added equals method, implemented Cloneable, and applied 
  39:  *               serialization fixes (DG);
  40:  * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
  41:  * 14-Apr-2004 : Fixed draw() method to handle plot orientation correctly (DG);
  42:  * 29-Sep-2004 : Added support for tool tips and URLS, now extends 
  43:  *               AbstractXYAnnotation (DG);
  44:  * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
  45:  * 08-Jun-2005 : Fixed equals() method to handle GradientPaint() (DG);
  46:  * 
  47:  */
  48: 
  49: package org.jfree.chart.annotations;
  50: 
  51: import java.awt.BasicStroke;
  52: import java.awt.Color;
  53: import java.awt.Graphics2D;
  54: import java.awt.Paint;
  55: import java.awt.Stroke;
  56: import java.awt.geom.Line2D;
  57: import java.awt.geom.Rectangle2D;
  58: import java.io.IOException;
  59: import java.io.ObjectInputStream;
  60: import java.io.ObjectOutputStream;
  61: import java.io.Serializable;
  62: 
  63: import org.jfree.chart.axis.ValueAxis;
  64: import org.jfree.chart.plot.Plot;
  65: import org.jfree.chart.plot.PlotOrientation;
  66: import org.jfree.chart.plot.PlotRenderingInfo;
  67: import org.jfree.chart.plot.XYPlot;
  68: import org.jfree.io.SerialUtilities;
  69: import org.jfree.ui.RectangleEdge;
  70: import org.jfree.util.ObjectUtilities;
  71: import org.jfree.util.PaintUtilities;
  72: import org.jfree.util.PublicCloneable;
  73: import org.jfree.util.ShapeUtilities;
  74: 
  75: /**
  76:  * A simple line annotation that can be placed on an {@link XYPlot}.
  77:  */
  78: public class XYLineAnnotation extends AbstractXYAnnotation
  79:                               implements Cloneable, PublicCloneable, 
  80:                                          Serializable {
  81: 
  82:     /** For serialization. */
  83:     private static final long serialVersionUID = -80535465244091334L;
  84:     
  85:     /** The x-coordinate. */
  86:     private double x1;
  87: 
  88:     /** The y-coordinate. */
  89:     private double y1;
  90: 
  91:     /** The x-coordinate. */
  92:     private double x2;
  93: 
  94:     /** The y-coordinate. */
  95:     private double y2;
  96: 
  97:     /** The line stroke. */
  98:     private transient Stroke stroke;
  99: 
 100:     /** The line color. */
 101:     private transient Paint paint;
 102: 
 103:     /**
 104:      * Creates a new annotation that draws a line from (x1, y1) to (x2, y2) 
 105:      * where the coordinates are measured in data space (that is, against the 
 106:      * plot's axes).
 107:      * 
 108:      * @param x1  the x-coordinate for the start of the line.
 109:      * @param y1  the y-coordinate for the start of the line.
 110:      * @param x2  the x-coordinate for the end of the line.
 111:      * @param y2  the y-coordinate for the end of the line.
 112:      */
 113:     public XYLineAnnotation(double x1, double y1, double x2, double y2) {
 114:         this(x1, y1, x2, y2, new BasicStroke(1.0f), Color.black);
 115:     }
 116:     
 117:     /**
 118:      * Creates a new annotation that draws a line from (x1, y1) to (x2, y2) 
 119:      * where the coordinates are measured in data space (that is, against the 
 120:      * plot's axes).
 121:      *
 122:      * @param x1  the x-coordinate for the start of the line.
 123:      * @param y1  the y-coordinate for the start of the line.
 124:      * @param x2  the x-coordinate for the end of the line.
 125:      * @param y2  the y-coordinate for the end of the line.
 126:      * @param stroke  the line stroke (<code>null</code> not permitted).
 127:      * @param paint  the line color (<code>null</code> not permitted).
 128:      */
 129:     public XYLineAnnotation(double x1, double y1, double x2, double y2,
 130:                             Stroke stroke, Paint paint) {
 131: 
 132:         if (stroke == null) {
 133:             throw new IllegalArgumentException("Null 'stroke' argument.");   
 134:         }
 135:         if (paint == null) {
 136:             throw new IllegalArgumentException("Null 'paint' argument.");   
 137:         }
 138:         this.x1 = x1;
 139:         this.y1 = y1;
 140:         this.x2 = x2;
 141:         this.y2 = y2;
 142:         this.stroke = stroke;
 143:         this.paint = paint;
 144: 
 145:     }
 146: 
 147:     /**
 148:      * Draws the annotation.  This method is called by the {@link XYPlot} 
 149:      * class, you won't normally need to call it yourself.
 150:      *
 151:      * @param g2  the graphics device.
 152:      * @param plot  the plot.
 153:      * @param dataArea  the data area.
 154:      * @param domainAxis  the domain axis.
 155:      * @param rangeAxis  the range axis.
 156:      * @param rendererIndex  the renderer index.
 157:      * @param info  if supplied, this info object will be populated with
 158:      *              entity information.
 159:      */
 160:     public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea,
 161:                      ValueAxis domainAxis, ValueAxis rangeAxis, 
 162:                      int rendererIndex,
 163:                      PlotRenderingInfo info) {
 164: 
 165:         PlotOrientation orientation = plot.getOrientation();
 166:         RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
 167:                 plot.getDomainAxisLocation(), orientation);
 168:         RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
 169:                 plot.getRangeAxisLocation(), orientation);
 170:         float j2DX1 = 0.0f;
 171:         float j2DX2 = 0.0f;
 172:         float j2DY1 = 0.0f;
 173:         float j2DY2 = 0.0f;
 174:         if (orientation == PlotOrientation.VERTICAL) {
 175:             j2DX1 = (float) domainAxis.valueToJava2D(this.x1, dataArea, 
 176:                     domainEdge);
 177:             j2DY1 = (float) rangeAxis.valueToJava2D(this.y1, dataArea, 
 178:                     rangeEdge);
 179:             j2DX2 = (float) domainAxis.valueToJava2D(this.x2, dataArea, 
 180:                     domainEdge);
 181:             j2DY2 = (float) rangeAxis.valueToJava2D(this.y2, dataArea, 
 182:                     rangeEdge);
 183:         }
 184:         else if (orientation == PlotOrientation.HORIZONTAL) {
 185:             j2DY1 = (float) domainAxis.valueToJava2D(this.x1, dataArea, 
 186:                     domainEdge);
 187:             j2DX1 = (float) rangeAxis.valueToJava2D(this.y1, dataArea, 
 188:                     rangeEdge);
 189:             j2DY2 = (float) domainAxis.valueToJava2D(this.x2, dataArea, 
 190:                     domainEdge);
 191:             j2DX2 = (float) rangeAxis.valueToJava2D(this.y2, dataArea, 
 192:                     rangeEdge);                
 193:         }
 194:         g2.setPaint(this.paint);
 195:         g2.setStroke(this.stroke);
 196:         Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2);
 197:         g2.draw(line);
 198: 
 199:         String toolTip = getToolTipText();
 200:         String url = getURL();
 201:         if (toolTip != null || url != null) {
 202:             addEntity(info, ShapeUtilities.createLineRegion(line, 1.0f), 
 203:                     rendererIndex, toolTip, url);
 204:         }
 205:     }
 206: 
 207:     /**
 208:      * Tests this object for equality with an arbitrary object.
 209:      * 
 210:      * @param obj  the object to test against (<code>null</code> permitted).
 211:      * 
 212:      * @return <code>true</code> or <code>false</code>.
 213:      */
 214:     public boolean equals(Object obj) {
 215:         if (obj == this) {
 216:             return true;
 217:         }
 218:         if (!super.equals(obj)) {
 219:             return false;
 220:         }
 221:         if (!(obj instanceof XYLineAnnotation)) {
 222:             return false;
 223:         }
 224:         XYLineAnnotation that = (XYLineAnnotation) obj;
 225:         if (this.x1 != that.x1) {
 226:             return false;
 227:         }
 228:         if (this.y1 != that.y1) {
 229:             return false;
 230:         }
 231:         if (this.x2 != that.x2) {
 232:             return false;
 233:         }
 234:         if (this.y2 != that.y2) {
 235:             return false;
 236:         }
 237:         if (!PaintUtilities.equal(this.paint, that.paint)) {
 238:             return false;
 239:         }
 240:         if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
 241:             return false;
 242:         }
 243:         // seems to be the same...
 244:         return true;
 245:     }
 246:     
 247:     /**
 248:      * Returns a hash code.
 249:      * 
 250:      * @return A hash code.
 251:      */
 252:     public int hashCode() {
 253:         int result;
 254:         long temp;
 255:         temp = Double.doubleToLongBits(this.x1);
 256:         result = (int) (temp ^ (temp >>> 32));
 257:         temp = Double.doubleToLongBits(this.x2);
 258:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 259:         temp = Double.doubleToLongBits(this.y1);
 260:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 261:         temp = Double.doubleToLongBits(this.y2);
 262:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 263:         return result;
 264:     }
 265: 
 266:     /**
 267:      * Returns a clone of the annotation.
 268:      * 
 269:      * @return A clone.
 270:      * 
 271:      * @throws CloneNotSupportedException  if the annotation can't be cloned.
 272:      */
 273:     public Object clone() throws CloneNotSupportedException {
 274:         return super.clone();
 275:     }
 276:     
 277:     /**
 278:      * Provides serialization support.
 279:      *
 280:      * @param stream  the output stream.
 281:      *
 282:      * @throws IOException  if there is an I/O error.
 283:      */
 284:     private void writeObject(ObjectOutputStream stream) throws IOException {
 285:         stream.defaultWriteObject();
 286:         SerialUtilities.writePaint(this.paint, stream);
 287:         SerialUtilities.writeStroke(this.stroke, stream);
 288:     }
 289: 
 290:     /**
 291:      * Provides serialization support.
 292:      *
 293:      * @param stream  the input stream.
 294:      *
 295:      * @throws IOException  if there is an I/O error.
 296:      * @throws ClassNotFoundException  if there is a classpath problem.
 297:      */
 298:     private void readObject(ObjectInputStream stream) 
 299:         throws IOException, ClassNotFoundException {
 300:         stream.defaultReadObject();
 301:         this.paint = SerialUtilities.readPaint(stream);
 302:         this.stroke = SerialUtilities.readStroke(stream);
 303:     }
 304: 
 305: }