    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jfreechart/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * ---------------------
    028     * XYLineAnnotation.java
    029     * ---------------------
    030     * (C) Copyright 2003-2007, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * Changes:
    036     * --------
    037     * 02-Apr-2003 : Version 1 (DG);
    038     * 19-Aug-2003 : Added equals method, implemented Cloneable, and applied
    039     *               serialization fixes (DG);
    040     * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
    041     * 14-Apr-2004 : Fixed draw() method to handle plot orientation correctly (DG);
    042     * 29-Sep-2004 : Added support for tool tips and URLS, now extends
    043     *               AbstractXYAnnotation (DG);
    044     * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
    045     * 08-Jun-2005 : Fixed equals() method to handle GradientPaint() (DG);
    046     *
    047     */
    048
    049    package org.jfree.chart.annotations;
    050
    051    import java.awt.BasicStroke;
    052    import java.awt.Color;
    053    import java.awt.Graphics2D;
    054    import java.awt.Paint;
    055    import java.awt.Stroke;
    056    import java.awt.geom.Line2D;
    057    import java.awt.geom.Rectangle2D;
    058    import java.io.IOException;
    059    import java.io.ObjectInputStream;
    060    import java.io.ObjectOutputStream;
    061    import java.io.Serializable;
    062
    063    import org.jfree.chart.axis.ValueAxis;
    064    import org.jfree.chart.plot.Plot;
    065    import org.jfree.chart.plot.PlotOrientation;
    066    import org.jfree.chart.plot.PlotRenderingInfo;
    067    import org.jfree.chart.plot.XYPlot;
    068    import org.jfree.io.SerialUtilities;
    069    import org.jfree.ui.RectangleEdge;
    070    import org.jfree.util.ObjectUtilities;
    071    import org.jfree.util.PaintUtilities;
    072    import org.jfree.util.PublicCloneable;
    073    import org.jfree.util.ShapeUtilities;
    074
    075    /**
    076     * A simple line annotation that can be placed on an {@link XYPlot}.
    077     */
    078    public class XYLineAnnotation extends AbstractXYAnnotation
    079                                  implements Cloneable, PublicCloneable,
    080                                             Serializable {
    081
    082        /** For serialization. */
    083        private static final long serialVersionUID = -80535465244091334L;
    084
    085        /** The x-coordinate. */
    086        private double x1;
    087
    088        /** The y-coordinate. */
    089        private double y1;
    090
    091        /** The x-coordinate. */
    092        private double x2;
    093
    094        /** The y-coordinate. */
    095        private double y2;
    096
    097        /** The line stroke. */
    098        private transient Stroke stroke;
    099
    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    }