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