1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2013, 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  * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
25  * Other names may be trademarks of their respective owners.]
26  *
27  * --------------------
28  * XYBoxAnnotation.java
29  * --------------------
30  * (C) Copyright 2005-2013, by Object Refinery Limited and Contributors.
31  *
32  * Original Author:  David Gilbert (for Object Refinery Limited);
33  * Contributor(s):   Peter Kolb (see patch 2809117);
34  *
35  * Changes:
36  * --------
37  * 19-Jan-2005 : Version 1 (DG);
38  * 06-Jun-2005 : Fixed equals() method to handle GradientPaint (DG);
39  *
40  */
41 
42 package org.jfree.chart.annotations;
43 
44 import java.awt.BasicStroke;
45 import java.awt.Color;
46 import java.awt.Graphics2D;
47 import java.awt.Paint;
48 import java.awt.Stroke;
49 import java.awt.geom.Rectangle2D;
50 import java.io.IOException;
51 import java.io.ObjectInputStream;
52 import java.io.ObjectOutputStream;
53 import java.io.Serializable;
54 
55 import org.jfree.chart.axis.ValueAxis;
56 import org.jfree.chart.plot.Plot;
57 import org.jfree.chart.plot.PlotOrientation;
58 import org.jfree.chart.plot.PlotRenderingInfo;
59 import org.jfree.chart.plot.XYPlot;
60 import org.jfree.io.SerialUtilities;
61 import org.jfree.ui.RectangleEdge;
62 import org.jfree.util.ObjectUtilities;
63 import org.jfree.util.PaintUtilities;
64 import org.jfree.util.PublicCloneable;
65 
66 /**
67  * A box annotation that can be placed on an {@link XYPlot}.  The
68  * box coordinates are specified in data space.
69  */
70 public class XYBoxAnnotation extends AbstractXYAnnotation
71         implements Cloneable, PublicCloneable, Serializable {
72 
73     /** For serialization. */
74     private static final long serialVersionUID = 6764703772526757457L;
75 
76     /** The lower x-coordinate. */
77     private double x0;
78 
79     /** The lower y-coordinate. */
80     private double y0;
81 
82     /** The upper x-coordinate. */
83     private double x1;
84 
85     /** The upper y-coordinate. */
86     private double y1;
87 
88     /** The stroke used to draw the box outline. */
89     private transient Stroke stroke;
90 
91     /** The paint used to draw the box outline. */
92     private transient Paint outlinePaint;
93 
94     /** The paint used to fill the box. */
95     private transient Paint fillPaint;
96 
97     /**
98      * Creates a new annotation (where, by default, the box is drawn
99      * 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      */
XYBoxAnnotation(double x0, double y0, double x1, double y1)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      */
XYBoxAnnotation(double x0, double y0, double x1, double y1, Stroke stroke, Paint outlinePaint)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      */
XYBoxAnnotation(double x0, double y0, double x1, double y1, Stroke stroke, Paint outlinePaint, Paint fillPaint)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     @Override
draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, ValueAxis domainAxis, ValueAxis rangeAxis, int rendererIndex, PlotRenderingInfo info)163     public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea,
164                      ValueAxis domainAxis, ValueAxis rangeAxis,
165                      int rendererIndex, 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 
173         double transX0 = domainAxis.valueToJava2D(this.x0, dataArea,
174                 domainEdge);
175         double transY0 = rangeAxis.valueToJava2D(this.y0, dataArea, rangeEdge);
176         double transX1 = domainAxis.valueToJava2D(this.x1, dataArea,
177                 domainEdge);
178         double transY1 = rangeAxis.valueToJava2D(this.y1, dataArea, rangeEdge);
179 
180         Rectangle2D box = null;
181         if (orientation == PlotOrientation.HORIZONTAL) {
182             box = new Rectangle2D.Double(transY0, transX1, transY1 - transY0,
183                     transX0 - transX1);
184         }
185         else if (orientation == PlotOrientation.VERTICAL) {
186             box = new Rectangle2D.Double(transX0, transY1, transX1 - transX0,
187                     transY0 - transY1);
188         }
189 
190         if (this.fillPaint != null) {
191             g2.setPaint(this.fillPaint);
192             g2.fill(box);
193         }
194 
195         if (this.stroke != null && this.outlinePaint != null) {
196             g2.setPaint(this.outlinePaint);
197             g2.setStroke(this.stroke);
198             g2.draw(box);
199         }
200         addEntity(info, box, rendererIndex, getToolTipText(), getURL());
201 
202     }
203 
204     /**
205      * Tests this annotation for equality with an arbitrary object.
206      *
207      * @param obj  the object (<code>null</code> permitted).
208      *
209      * @return A boolean.
210      */
211     @Override
equals(Object obj)212     public boolean equals(Object obj) {
213         if (obj == this) {
214             return true;
215         }
216         // now try to reject equality
217         if (!super.equals(obj)) {
218             return false;
219         }
220         if (!(obj instanceof XYBoxAnnotation)) {
221             return false;
222         }
223         XYBoxAnnotation that = (XYBoxAnnotation) obj;
224         if (!(this.x0 == that.x0)) {
225             return false;
226         }
227         if (!(this.y0 == that.y0)) {
228             return false;
229         }
230         if (!(this.x1 == that.x1)) {
231             return false;
232         }
233         if (!(this.y1 == that.y1)) {
234             return false;
235         }
236         if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
237             return false;
238         }
239         if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
240             return false;
241         }
242         if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) {
243             return false;
244         }
245         // seem to be the same
246         return true;
247     }
248 
249     /**
250      * Returns a hash code.
251      *
252      * @return A hash code.
253      */
254     @Override
hashCode()255     public int hashCode() {
256         int result;
257         long temp;
258         temp = Double.doubleToLongBits(this.x0);
259         result = (int) (temp ^ (temp >>> 32));
260         temp = Double.doubleToLongBits(this.x1);
261         result = 29 * result + (int) (temp ^ (temp >>> 32));
262         temp = Double.doubleToLongBits(this.y0);
263         result = 29 * result + (int) (temp ^ (temp >>> 32));
264         temp = Double.doubleToLongBits(this.y1);
265         result = 29 * result + (int) (temp ^ (temp >>> 32));
266         return result;
267     }
268 
269     /**
270      * Returns a clone.
271      *
272      * @return A clone.
273      *
274      * @throws CloneNotSupportedException not thrown by this class, but may be
275      *                                    by subclasses.
276      */
277     @Override
clone()278     public Object clone() throws CloneNotSupportedException {
279         return super.clone();
280     }
281 
282     /**
283      * Provides serialization support.
284      *
285      * @param stream  the output stream (<code>null</code> not permitted).
286      *
287      * @throws IOException if there is an I/O error.
288      */
writeObject(ObjectOutputStream stream)289     private void writeObject(ObjectOutputStream stream) throws IOException {
290         stream.defaultWriteObject();
291         SerialUtilities.writeStroke(this.stroke, stream);
292         SerialUtilities.writePaint(this.outlinePaint, stream);
293         SerialUtilities.writePaint(this.fillPaint, stream);
294     }
295 
296     /**
297      * Provides serialization support.
298      *
299      * @param stream  the input stream (<code>null</code> not permitted).
300      *
301      * @throws IOException  if there is an I/O error.
302      * @throws ClassNotFoundException  if there is a classpath problem.
303      */
readObject(ObjectInputStream stream)304     private void readObject(ObjectInputStream stream)
305         throws IOException, ClassNotFoundException {
306 
307         stream.defaultReadObject();
308         this.stroke = SerialUtilities.readStroke(stream);
309         this.outlinePaint = SerialUtilities.readPaint(stream);
310         this.fillPaint = SerialUtilities.readPaint(stream);
311     }
312 
313 }
314