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: * StandardDialRange.java
029: * ----------------------
030: * (C) Copyright 2006, 2007, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: StandardDialRange.java,v 1.1.2.3 2007/03/08 16:51:07 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 03-Nov-2006 : Version 1 (DG);
040: * 08-Mar-2007 : Fix in hashCode() (DG);
041: *
042: */
043:
044: package org.jfree.experimental.chart.plot.dial;
045:
046: import java.awt.BasicStroke;
047: import java.awt.Color;
048: import java.awt.Graphics2D;
049: import java.awt.Paint;
050: import java.awt.geom.Arc2D;
051: import java.awt.geom.Rectangle2D;
052: import java.io.IOException;
053: import java.io.ObjectInputStream;
054: import java.io.ObjectOutputStream;
055: import java.io.Serializable;
056:
057: import org.jfree.chart.HashUtilities;
058: import org.jfree.io.SerialUtilities;
059: import org.jfree.util.PaintUtilities;
060: import org.jfree.util.PublicCloneable;
061:
062: /**
063: * A layer that draws a range highlight on a dial plot.
064: */
065: public class StandardDialRange extends AbstractDialLayer implements
066: DialLayer, Cloneable, PublicCloneable, Serializable {
067:
068: /** The minimum data value for the scale. */
069: private double lowerBound;
070:
071: /** The maximum data value for the scale. */
072: private double upperBound;
073:
074: /**
075: * The increment (in data units) for each section.
076: */
077: private double increment;
078:
079: /**
080: * The paint used to draw the range highlight. This field is transient
081: * because it requires special handling for serialization.
082: */
083: private transient Paint paint;
084:
085: /**
086: * The factor (in the range 0.0 to 1.0) that determines the inside limit
087: * of the range highlight.
088: */
089: private double innerRadius;
090:
091: /**
092: * The factor (in the range 0.0 to 1.0) that determines the outside limit
093: * of the range highlight.
094: */
095: private double outerRadius;
096:
097: /**
098: * Creates a new instance of <code>StandardDialRange</code>.
099: */
100: public StandardDialRange() {
101: this (0.0, 100.0, Color.white);
102: }
103:
104: /**
105: * Creates a new instance of <code>StandardDialRange</code>.
106: *
107: * @param lower the lower bound.
108: * @param upper the upper bound.
109: * @param paint the paint (<code>null</code> not permitted).
110: */
111: public StandardDialRange(double lower, double upper, Paint paint) {
112: if (paint == null) {
113: throw new IllegalArgumentException("Null 'paint' argument.");
114: }
115: this .lowerBound = lower;
116: this .upperBound = upper;
117: this .paint = paint;
118: }
119:
120: /**
121: * Returns the lower bound (a data value) of the dial range.
122: *
123: * @return The lower bound of the dial range.
124: *
125: * @see #setLowerBound(double)
126: */
127: public double getLowerBound() {
128: return this .lowerBound;
129: }
130:
131: /**
132: * Sets the lower bound of the dial range.
133: *
134: * @param bound the lower bound.
135: *
136: * @see #getLowerBound()
137: */
138: public void setLowerBound(double bound) {
139: // FIXME: check
140: this .lowerBound = bound;
141: notifyListeners(new DialLayerChangeEvent(this ));
142: }
143:
144: /**
145: * Returns the upper bound of the dial range.
146: *
147: * @return The upper bound.
148: *
149: * @see #setUpperBound(double)
150: */
151: public double getUpperBound() {
152: return this .upperBound;
153: }
154:
155: /**
156: * Sets the upper bound of the dial range.
157: *
158: * @param bound the upper bound.
159: *
160: * @see #getUpperBound()
161: */
162: public void setUpperBound(double bound) {
163: // FIXME: check
164: this .upperBound = bound;
165: notifyListeners(new DialLayerChangeEvent(this ));
166: }
167:
168: /**
169: * Returns the increment between tick marks.
170: *
171: * @return The increment.
172: *
173: * @see #setIncrement(double)
174: */
175: public double getIncrement() {
176: return this .increment;
177: }
178:
179: /**
180: * Sets the increment.
181: *
182: * @param increment the increment.
183: *
184: * @see #getIncrement()
185: */
186: public void setIncrement(double increment) {
187: // FIXME: check
188: this .increment = increment;
189: notifyListeners(new DialLayerChangeEvent(this ));
190: }
191:
192: /**
193: * Returns the paint used to highlight the range.
194: *
195: * @return The paint (never <code>null</code>).
196: *
197: * @see #setPaint(Paint)
198: */
199: public Paint getPaint() {
200: return this .paint;
201: }
202:
203: /**
204: * Sets the paint used to highlight the range.
205: *
206: * @param paint the paint (<code>null</code> not permitted).
207: *
208: * @see #getPaint()
209: */
210: public void setPaint(Paint paint) {
211: if (paint == null) {
212: throw new IllegalArgumentException("Null 'paint' argument.");
213: }
214: this .paint = paint;
215: notifyListeners(new DialLayerChangeEvent(this ));
216: }
217:
218: /**
219: * Returns the inner radius.
220: *
221: * @return The inner radius.
222: *
223: * @see #setInnerRadius(double)
224: */
225: public double getInnerRadius() {
226: return this .innerRadius;
227: }
228:
229: /**
230: * Sets the inner radius.
231: *
232: * @param radius the radius.
233: *
234: * @see #getInnerRadius()
235: */
236: public void setInnerRadius(double radius) {
237: this .innerRadius = radius;
238: notifyListeners(new DialLayerChangeEvent(this ));
239: }
240:
241: /**
242: * Returns the outer radius.
243: *
244: * @return The outer radius.
245: *
246: * @see #setOuterRadius(double)
247: */
248: public double getOuterRadius() {
249: return this .outerRadius;
250: }
251:
252: /**
253: * Sets the outer radius.
254: *
255: * @param radius the radius.
256: *
257: * @see #getOuterRadius()
258: */
259: public void setOuterRadius(double radius) {
260: this .outerRadius = radius;
261: notifyListeners(new DialLayerChangeEvent(this ));
262: }
263:
264: /**
265: * Returns <code>true</code> to indicate that this layer should be
266: * clipped within the dial window.
267: *
268: * @return <code>true</code>.
269: */
270: public boolean isClippedToWindow() {
271: return true;
272: }
273:
274: /**
275: * Draws the range.
276: *
277: * @param g2 the graphics target.
278: * @param plot the plot.
279: * @param frame the dial's reference frame (in Java2D space).
280: * @param view the dial's view rectangle (in Java2D space).
281: */
282: public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame,
283: Rectangle2D view) {
284:
285: Rectangle2D arcRectInner = DialPlot.rectangleByRadius(frame,
286: this .innerRadius, this .innerRadius);
287: Rectangle2D arcRectOuter = DialPlot.rectangleByRadius(frame,
288: this .outerRadius, this .outerRadius);
289: //double range = this.upperBound - this.lowerBound;
290:
291: DialScale scale = plot.getScaleForDataset(0);
292: double angleMin = scale.valueToAngle(this .lowerBound);
293: double angleMax = scale.valueToAngle(this .upperBound);
294:
295: Arc2D arcInner = new Arc2D.Double(arcRectInner, angleMin,
296: angleMax - angleMin, Arc2D.OPEN);
297: Arc2D arcOuter = new Arc2D.Double(arcRectOuter, angleMax,
298: angleMin - angleMax, Arc2D.OPEN);
299:
300: g2.setPaint(this .paint);
301: g2.setStroke(new BasicStroke(2.0f));
302: g2.draw(arcInner);
303: g2.draw(arcOuter);
304: }
305:
306: /**
307: * Tests this instance for equality with an arbitrary object.
308: *
309: * @param obj the object (<code>null</code> permitted).
310: *
311: * @return A boolean.
312: */
313: public boolean equals(Object obj) {
314: if (obj == this ) {
315: return true;
316: }
317: if (!(obj instanceof StandardDialRange)) {
318: return false;
319: }
320: StandardDialRange that = (StandardDialRange) obj;
321: if (this .lowerBound != that.lowerBound) {
322: return false;
323: }
324: if (this .upperBound != that.upperBound) {
325: return false;
326: }
327: if (this .increment != that.increment) {
328: return false;
329: }
330: if (!PaintUtilities.equal(this .paint, that.paint)) {
331: return false;
332: }
333: if (this .innerRadius != that.innerRadius) {
334: return false;
335: }
336: if (this .outerRadius != that.outerRadius) {
337: return false;
338: }
339: return true;
340: }
341:
342: /**
343: * Returns a hash code for this instance.
344: *
345: * @return The hash code.
346: */
347: public int hashCode() {
348: int result = 193;
349: long temp = Double.doubleToLongBits(this .increment);
350: result = 37 * result + (int) (temp ^ (temp >>> 32));
351: temp = Double.doubleToLongBits(this .lowerBound);
352: result = 37 * result + (int) (temp ^ (temp >>> 32));
353: temp = Double.doubleToLongBits(this .upperBound);
354: result = 37 * result + (int) (temp ^ (temp >>> 32));
355: temp = Double.doubleToLongBits(this .innerRadius);
356: result = 37 * result + (int) (temp ^ (temp >>> 32));
357: temp = Double.doubleToLongBits(this .outerRadius);
358: result = 37 * result + (int) (temp ^ (temp >>> 32));
359: result = 37 * result
360: + HashUtilities.hashCodeForPaint(this .paint);
361: return result;
362: }
363:
364: /**
365: * Returns a clone of this instance.
366: *
367: * @return A clone.
368: *
369: * @throws CloneNotSupportedException if any of the attributes of this
370: * instance cannot be cloned.
371: */
372: public Object clone() throws CloneNotSupportedException {
373: return super .clone();
374: }
375:
376: /**
377: * Provides serialization support.
378: *
379: * @param stream the output stream.
380: *
381: * @throws IOException if there is an I/O error.
382: */
383: private void writeObject(ObjectOutputStream stream)
384: throws IOException {
385: stream.defaultWriteObject();
386: SerialUtilities.writePaint(this .paint, stream);
387: }
388:
389: /**
390: * Provides serialization support.
391: *
392: * @param stream the input stream.
393: *
394: * @throws IOException if there is an I/O error.
395: * @throws ClassNotFoundException if there is a classpath problem.
396: */
397: private void readObject(ObjectInputStream stream)
398: throws IOException, ClassNotFoundException {
399: stream.defaultReadObject();
400: this.paint = SerialUtilities.readPaint(stream);
401: }
402:
403: }
|