001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2011, 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     * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025     * Other names may be trademarks of their respective owners.]
026     *
027     * --------------------
028     * XYBoxAnnotation.java
029     * --------------------
030     * (C) Copyright 2005-2009, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   Peter Kolb (see patch 2809117);
034     *
035     * Changes:
036     * --------
037     * 19-Jan-2005 : Version 1 (DG);
038     * 06-Jun-2005 : Fixed equals() method to handle GradientPaint (DG);
039     *
040     */
041    
042    package org.jfree.chart.annotations;
043    
044    import java.awt.BasicStroke;
045    import java.awt.Color;
046    import java.awt.Graphics2D;
047    import java.awt.Paint;
048    import java.awt.Stroke;
049    import java.awt.geom.Rectangle2D;
050    import java.io.IOException;
051    import java.io.ObjectInputStream;
052    import java.io.ObjectOutputStream;
053    import java.io.Serializable;
054    
055    import org.jfree.chart.axis.ValueAxis;
056    import org.jfree.chart.plot.Plot;
057    import org.jfree.chart.plot.PlotOrientation;
058    import org.jfree.chart.plot.PlotRenderingInfo;
059    import org.jfree.chart.plot.XYPlot;
060    import org.jfree.io.SerialUtilities;
061    import org.jfree.ui.RectangleEdge;
062    import org.jfree.util.ObjectUtilities;
063    import org.jfree.util.PaintUtilities;
064    import org.jfree.util.PublicCloneable;
065    
066    /**
067     * A box annotation that can be placed on an {@link XYPlot}.  The
068     * box coordinates are specified in data space.
069     */
070    public class XYBoxAnnotation extends AbstractXYAnnotation
071            implements Cloneable, PublicCloneable, Serializable {
072    
073        /** For serialization. */
074        private static final long serialVersionUID = 6764703772526757457L;
075    
076        /** The lower x-coordinate. */
077        private double x0;
078    
079        /** The lower y-coordinate. */
080        private double y0;
081    
082        /** The upper x-coordinate. */
083        private double x1;
084    
085        /** The upper y-coordinate. */
086        private double y1;
087    
088        /** The stroke used to draw the box outline. */
089        private transient Stroke stroke;
090    
091        /** The paint used to draw the box outline. */
092        private transient Paint outlinePaint;
093    
094        /** The paint used to fill the box. */
095        private transient Paint fillPaint;
096    
097        /**
098         * Creates a new annotation (where, by default, the box is drawn
099         * with a black outline).
100         *
101         * @param x0  the lower x-coordinate of the box (in data space).
102         * @param y0  the lower y-coordinate of the box (in data space).
103         * @param x1  the upper x-coordinate of the box (in data space).
104         * @param y1  the upper y-coordinate of the box (in data space).
105         */
106        public XYBoxAnnotation(double x0, double y0, double x1, double y1) {
107            this(x0, y0, x1, y1, new BasicStroke(1.0f), Color.black);
108        }
109    
110        /**
111         * Creates a new annotation where the box is drawn as an outline using
112         * the specified <code>stroke</code> and <code>outlinePaint</code>.
113         *
114         * @param x0  the lower x-coordinate of the box (in data space).
115         * @param y0  the lower y-coordinate of the box (in data space).
116         * @param x1  the upper x-coordinate of the box (in data space).
117         * @param y1  the upper y-coordinate of the box (in data space).
118         * @param stroke  the shape stroke (<code>null</code> permitted).
119         * @param outlinePaint  the shape color (<code>null</code> permitted).
120         */
121        public XYBoxAnnotation(double x0, double y0, double x1, double y1,
122                               Stroke stroke, Paint outlinePaint) {
123            this(x0, y0, x1, y1, stroke, outlinePaint, null);
124        }
125    
126        /**
127         * Creates a new annotation.
128         *
129         * @param x0  the lower x-coordinate of the box (in data space).
130         * @param y0  the lower y-coordinate of the box (in data space).
131         * @param x1  the upper x-coordinate of the box (in data space).
132         * @param y1  the upper y-coordinate of the box (in data space).
133         * @param stroke  the shape stroke (<code>null</code> permitted).
134         * @param outlinePaint  the shape color (<code>null</code> permitted).
135         * @param fillPaint  the paint used to fill the shape (<code>null</code>
136         *                   permitted).
137         */
138        public XYBoxAnnotation(double x0, double y0, double x1, double y1,
139                               Stroke stroke, Paint outlinePaint, Paint fillPaint) {
140            super();
141            this.x0 = x0;
142            this.y0 = y0;
143            this.x1 = x1;
144            this.y1 = y1;
145            this.stroke = stroke;
146            this.outlinePaint = outlinePaint;
147            this.fillPaint = fillPaint;
148        }
149    
150        /**
151         * Draws the annotation.  This method is usually called by the
152         * {@link XYPlot} class, you shouldn't need to call it directly.
153         *
154         * @param g2  the graphics device.
155         * @param plot  the plot.
156         * @param dataArea  the data area.
157         * @param domainAxis  the domain axis.
158         * @param rangeAxis  the range axis.
159         * @param rendererIndex  the renderer index.
160         * @param info  the plot rendering info.
161         */
162        public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea,
163                         ValueAxis domainAxis, ValueAxis rangeAxis,
164                         int rendererIndex, PlotRenderingInfo info) {
165    
166            PlotOrientation orientation = plot.getOrientation();
167            RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
168                    plot.getDomainAxisLocation(), orientation);
169            RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
170                    plot.getRangeAxisLocation(), orientation);
171    
172            double transX0 = domainAxis.valueToJava2D(this.x0, dataArea,
173                    domainEdge);
174            double transY0 = rangeAxis.valueToJava2D(this.y0, dataArea, rangeEdge);
175            double transX1 = domainAxis.valueToJava2D(this.x1, dataArea,
176                    domainEdge);
177            double transY1 = rangeAxis.valueToJava2D(this.y1, dataArea, rangeEdge);
178    
179            Rectangle2D box = null;
180            if (orientation == PlotOrientation.HORIZONTAL) {
181                box = new Rectangle2D.Double(transY0, transX1, transY1 - transY0,
182                        transX0 - transX1);
183            }
184            else if (orientation == PlotOrientation.VERTICAL) {
185                box = new Rectangle2D.Double(transX0, transY1, transX1 - transX0,
186                        transY0 - transY1);
187            }
188    
189            if (this.fillPaint != null) {
190                g2.setPaint(this.fillPaint);
191                g2.fill(box);
192            }
193    
194            if (this.stroke != null && this.outlinePaint != null) {
195                g2.setPaint(this.outlinePaint);
196                g2.setStroke(this.stroke);
197                g2.draw(box);
198            }
199            addEntity(info, box, rendererIndex, getToolTipText(), getURL());
200    
201        }
202    
203        /**
204         * Tests this annotation for equality with an arbitrary object.
205         *
206         * @param obj  the object (<code>null</code> permitted).
207         *
208         * @return A boolean.
209         */
210        public boolean equals(Object obj) {
211            if (obj == this) {
212                return true;
213            }
214            // now try to reject equality
215            if (!super.equals(obj)) {
216                return false;
217            }
218            if (!(obj instanceof XYBoxAnnotation)) {
219                return false;
220            }
221            XYBoxAnnotation that = (XYBoxAnnotation) obj;
222            if (!(this.x0 == that.x0)) {
223                return false;
224            }
225            if (!(this.y0 == that.y0)) {
226                return false;
227            }
228            if (!(this.x1 == that.x1)) {
229                return false;
230            }
231            if (!(this.y1 == that.y1)) {
232                return false;
233            }
234            if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
235                return false;
236            }
237            if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
238                return false;
239            }
240            if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) {
241                return false;
242            }
243            // seem 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.x0);
256            result = (int) (temp ^ (temp >>> 32));
257            temp = Double.doubleToLongBits(this.x1);
258            result = 29 * result + (int) (temp ^ (temp >>> 32));
259            temp = Double.doubleToLongBits(this.y0);
260            result = 29 * result + (int) (temp ^ (temp >>> 32));
261            temp = Double.doubleToLongBits(this.y1);
262            result = 29 * result + (int) (temp ^ (temp >>> 32));
263            return result;
264        }
265    
266        /**
267         * Returns a clone.
268         *
269         * @return A clone.
270         *
271         * @throws CloneNotSupportedException not thrown by this class, but may be
272         *                                    by subclasses.
273         */
274        public Object clone() throws CloneNotSupportedException {
275            return super.clone();
276        }
277    
278        /**
279         * Provides serialization support.
280         *
281         * @param stream  the output stream (<code>null</code> not permitted).
282         *
283         * @throws IOException if there is an I/O error.
284         */
285        private void writeObject(ObjectOutputStream stream) throws IOException {
286            stream.defaultWriteObject();
287            SerialUtilities.writeStroke(this.stroke, stream);
288            SerialUtilities.writePaint(this.outlinePaint, stream);
289            SerialUtilities.writePaint(this.fillPaint, stream);
290        }
291    
292        /**
293         * Provides serialization support.
294         *
295         * @param stream  the input stream (<code>null</code> not permitted).
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    
303            stream.defaultReadObject();
304            this.stroke = SerialUtilities.readStroke(stream);
305            this.outlinePaint = SerialUtilities.readPaint(stream);
306            this.fillPaint = SerialUtilities.readPaint(stream);
307        }
308    
309    }