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-2005, 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-2005, 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.2 2005/10/25 16:51:15 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:         );
 171:         RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
 172:             plot.getRangeAxisLocation(), orientation
 173:         );
 174:         float j2DX1 = 0.0f;
 175:         float j2DX2 = 0.0f;
 176:         float j2DY1 = 0.0f;
 177:         float j2DY2 = 0.0f;
 178:         if (orientation == PlotOrientation.VERTICAL) {
 179:             j2DX1 = (float) domainAxis.valueToJava2D(
 180:                 this.x1, dataArea, domainEdge
 181:             );
 182:             j2DY1 = (float) rangeAxis.valueToJava2D(
 183:                 this.y1, dataArea, rangeEdge
 184:             );
 185:             j2DX2 = (float) domainAxis.valueToJava2D(
 186:                 this.x2, dataArea, domainEdge
 187:             );
 188:             j2DY2 = (float) rangeAxis.valueToJava2D(
 189:                 this.y2, dataArea, rangeEdge
 190:             );
 191:         }
 192:         else if (orientation == PlotOrientation.HORIZONTAL) {
 193:             j2DY1 = (float) domainAxis.valueToJava2D(
 194:                 this.x1, dataArea, domainEdge
 195:             );
 196:             j2DX1 = (float) rangeAxis.valueToJava2D(
 197:                 this.y1, dataArea, rangeEdge
 198:             );
 199:             j2DY2 = (float) domainAxis.valueToJava2D(
 200:                 this.x2, dataArea, domainEdge
 201:             );
 202:             j2DX2 = (float) rangeAxis.valueToJava2D(
 203:                 this.y2, dataArea, rangeEdge
 204:             );                
 205:         }
 206:         g2.setPaint(this.paint);
 207:         g2.setStroke(this.stroke);
 208:         Line2D line = new Line2D.Float(j2DX1, j2DY1, j2DX2, j2DY2);
 209:         g2.draw(line);
 210: 
 211:         String toolTip = getToolTipText();
 212:         String url = getURL();
 213:         if (toolTip != null || url != null) {
 214:             addEntity(
 215:                 info, ShapeUtilities.createLineRegion(line, 1.0f), 
 216:                 rendererIndex, toolTip, url
 217:             );
 218:         }
 219:     }
 220: 
 221:     /**
 222:      * Tests this object for equality with an arbitrary object.
 223:      * 
 224:      * @param obj  the object to test against (<code>null</code> permitted).
 225:      * 
 226:      * @return <code>true</code> or <code>false</code>.
 227:      */
 228:     public boolean equals(Object obj) {
 229:         if (obj == this) {
 230:             return true;
 231:         }
 232:         if (!super.equals(obj)) {
 233:             return false;
 234:         }
 235:         if (!(obj instanceof XYLineAnnotation)) {
 236:             return false;
 237:         }
 238:         XYLineAnnotation that = (XYLineAnnotation) obj;
 239:         if (this.x1 != that.x1) {
 240:             return false;
 241:         }
 242:         if (this.y1 != that.y1) {
 243:             return false;
 244:         }
 245:         if (this.x2 != that.x2) {
 246:             return false;
 247:         }
 248:         if (this.y2 != that.y2) {
 249:             return false;
 250:         }
 251:         if (!PaintUtilities.equal(this.paint, that.paint)) {
 252:             return false;
 253:         }
 254:         if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
 255:             return false;
 256:         }
 257:         // seems to be the same...
 258:         return true;
 259:     }
 260:     
 261:     /**
 262:      * Returns a hash code.
 263:      * 
 264:      * @return A hash code.
 265:      */
 266:     public int hashCode() {
 267:         int result;
 268:         long temp;
 269:         temp = Double.doubleToLongBits(this.x1);
 270:         result = (int) (temp ^ (temp >>> 32));
 271:         temp = Double.doubleToLongBits(this.x2);
 272:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 273:         temp = Double.doubleToLongBits(this.y1);
 274:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 275:         temp = Double.doubleToLongBits(this.y2);
 276:         result = 29 * result + (int) (temp ^ (temp >>> 32));
 277:         return result;
 278:     }
 279: 
 280:     /**
 281:      * Returns a clone of the annotation.
 282:      * 
 283:      * @return A clone.
 284:      * 
 285:      * @throws CloneNotSupportedException  if the annotation can't be cloned.
 286:      */
 287:     public Object clone() throws CloneNotSupportedException {
 288:         return super.clone();
 289:     }
 290:     
 291:     /**
 292:      * Provides serialization support.
 293:      *
 294:      * @param stream  the output stream.
 295:      *
 296:      * @throws IOException  if there is an I/O error.
 297:      */
 298:     private void writeObject(ObjectOutputStream stream) throws IOException {
 299: 
 300:         stream.defaultWriteObject();
 301:         SerialUtilities.writePaint(this.paint, stream);
 302:         SerialUtilities.writeStroke(this.stroke, stream);
 303: 
 304:     }
 305: 
 306:     /**
 307:      * Provides serialization support.
 308:      *
 309:      * @param stream  the input stream.
 310:      *
 311:      * @throws IOException  if there is an I/O error.
 312:      * @throws ClassNotFoundException  if there is a classpath problem.
 313:      */
 314:     private void readObject(ObjectInputStream stream) 
 315:         throws IOException, ClassNotFoundException {
 316:         stream.defaultReadObject();
 317:         this.paint = SerialUtilities.readPaint(stream);
 318:         this.stroke = SerialUtilities.readStroke(stream);
 319:     }
 320: 
 321: }