KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > experimental > chart > plot > dial > StandardDialScale


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2006, 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  * StandardDialScale.java
29  * ----------------------
30  * (C) Copyright 2006, by Object Refinery Limited.
31  *
32  * Original Author: David Gilbert (for Object Refinery Limited);
33  * Contributor(s): -;
34  *
35  * $Id: StandardDialScale.java,v 1.1.2.3 2006/11/17 11:06:44 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 03-Nov-2006 : Version 1 (DG);
40  * 17-Nov-2006 : Added flags for tick label visibility (DG);
41  *
42  */

43
44 package org.jfree.experimental.chart.plot.dial;
45
46 import java.awt.BasicStroke JavaDoc;
47 import java.awt.Color JavaDoc;
48 import java.awt.Font JavaDoc;
49 import java.awt.Graphics2D JavaDoc;
50 import java.awt.Paint JavaDoc;
51 import java.awt.Stroke JavaDoc;
52 import java.awt.geom.Arc2D JavaDoc;
53 import java.awt.geom.Line2D JavaDoc;
54 import java.awt.geom.Point2D JavaDoc;
55 import java.awt.geom.Rectangle2D JavaDoc;
56 import java.io.IOException JavaDoc;
57 import java.io.ObjectInputStream JavaDoc;
58 import java.io.ObjectOutputStream JavaDoc;
59 import java.io.Serializable JavaDoc;
60
61 import org.jfree.io.SerialUtilities;
62 import org.jfree.text.TextUtilities;
63 import org.jfree.ui.TextAnchor;
64 import org.jfree.util.PaintUtilities;
65 import org.jfree.util.PublicCloneable;
66
67 /**
68  * A scale for a {@link DialPlot}.
69  */

70 public class StandardDialScale extends AbstractDialLayer implements DialScale,
71         DialLayer, Cloneable JavaDoc, PublicCloneable, Serializable JavaDoc {
72     
73     /** The minimum data value for the scale. */
74     private double lowerBound;
75     
76     /** The maximum data value for the scale. */
77     private double upperBound;
78     
79     /**
80      * The start angle for the scale display, in degrees (using the same
81      * encoding as Arc2D).
82      */

83     private double startAngle;
84     
85     /** The extent of the scale display. */
86     private double extent;
87     
88     /**
89      * The factor (in the range 0.0 to 1.0) that determines the outside limit
90      * of the tick marks.
91      */

92     private double tickRadius;
93
94     /**
95      * The increment (in data units) between major tick marks.
96      */

97     private double majorTickIncrement;
98
99     /**
100      * The factor that is subtracted from the tickRadius to determine the
101      * inner point of the major ticks.
102      */

103     private double majorTickLength;
104     
105     /**
106      * The paint to use for major tick marks. This field is transient because
107      * it requires special handling for serialization.
108      */

109     private transient Paint JavaDoc majorTickPaint;
110     
111     /**
112      * The stroke to use for major tick marks. This field is transient because
113      * it requires special handling for serialization.
114      */

115     private transient Stroke JavaDoc majorTickStroke;
116
117     /**
118      * The number of minor ticks between each major tick.
119      */

120     private int minorTickCount;
121     
122     /**
123      * The factor that is subtracted from the tickRadius to determine the
124      * inner point of the minor ticks.
125      */

126     private double minorTickLength;
127     
128     /**
129      * The tick label offset.
130      */

131     private double tickLabelOffset;
132     
133     /**
134      * The tick label font.
135      */

136     private Font JavaDoc tickLabelFont;
137     
138     /**
139      * A flag that controls whether or not the tick labels are
140      * displayed.
141      */

142     private boolean tickLabelsVisible;
143     
144     /**
145      * A flag that controls whether or not the first tick label is
146      * displayed.
147      */

148     private boolean firstTickLabelVisible;
149     
150     /**
151      * The tick label paint. This field is transient because it requires
152      * special handling for serialization.
153      */

154     private transient Paint JavaDoc tickLabelPaint;
155     
156     /**
157      * Creates a new instance of DialScale.
158      */

159     public StandardDialScale() {
160         this(0.0, 100.0, 175, -170);
161     }
162     
163     /**
164      * Creates a new instance.
165      *
166      * @param lowerBound the lower bound of the scale.
167      * @param upperBound the upper bound of the scale.
168      * @param startAngle the start angle (in degrees, using the same
169      * orientation as Java's <code>Arc2D</code> class).
170      * @param extent the extent (in degrees, counter-clockwise).
171      */

172     public StandardDialScale(double lowerBound, double upperBound,
173             double startAngle, double extent) {
174         this.startAngle = startAngle;
175         this.extent = extent;
176         this.lowerBound = lowerBound;
177         this.upperBound = upperBound;
178         this.majorTickPaint = Color.black;
179         this.majorTickStroke = new BasicStroke JavaDoc(3.0f);
180         this.tickLabelFont = new Font JavaDoc("Dialog", Font.BOLD, 16);
181         this.tickLabelPaint = Color.blue;
182         this.minorTickCount = 4;
183         this.minorTickLength = 0.02;
184         this.tickLabelOffset = 0.10;
185         this.majorTickIncrement = 10.0;
186         this.tickRadius = 0.70;
187         this.tickLabelsVisible = true;
188         this.firstTickLabelVisible = true;
189     }
190     
191     /**
192      * Returns the start angle for the scale (in degrees using the same
193      * orientation as Java's <code>Arc2D</code> class).
194      *
195      * @return The start angle.
196      *
197      * @see #setStartAngle(double)
198      */

199     public double getStartAngle() {
200         return this.startAngle;
201     }
202     
203     /**
204      * Sets the start angle for the scale.
205      *
206      * @param angle the angle.
207      *
208      * @see #getStartAngle()
209      */

210     public void setStartAngle(double angle) {
211         this.startAngle = angle;
212         notifyListeners(new DialLayerChangeEvent(this));
213     }
214     
215     /**
216      * Returns the extent.
217      *
218      * @return The extent.
219      */

220     public double getExtent() {
221         return this.extent;
222     }
223     
224     /**
225      * Sets the extent.
226      *
227      * @param extent the extent.
228      *
229      * @see #getExtent()
230      */

231     public void setExtent(double extent) {
232         this.extent = extent;
233         notifyListeners(new DialLayerChangeEvent(this));
234     }
235     
236     /**
237      * Returns the radius (as a percentage of the maximum space available) of
238      * the outer limit of the tick marks.
239      *
240      * @return The tick radius.
241      *
242      * @see #setTickRadius(double)
243      */

244     public double getTickRadius() {
245         return this.tickRadius;
246     }
247     
248     /**
249      * Sets the tick radius.
250      *
251      * @param radius the radius.
252      *
253      * @see #getTickRadius()
254      */

255     public void setTickRadius(double radius) {
256         // TODO: Validate
257
this.tickRadius = radius;
258         notifyListeners(new DialLayerChangeEvent(this));
259     }
260     
261     /**
262      * Returns the increment (in data units) between major tick labels.
263      *
264      * @return The increment between major tick labels.
265      *
266      * @see #setMajorTickIncrement(double)
267      */

268     public double getMajorTickIncrement() {
269         return this.majorTickIncrement;
270     }
271     
272     /**
273      * Sets the increment (in data units) between major tick labels.
274      *
275      * @param increment the increment.
276      *
277      * @see #getMajorTickIncrement()
278      */

279     public void setMajorTickIncrement(double increment) {
280         // TODO: validation
281
this.majorTickIncrement = increment;
282         notifyListeners(new DialLayerChangeEvent(this));
283     }
284     
285     /**
286      * Returns the length factor for the major tick marks. The value is
287      * subtracted from the tick radius to determine the inner starting point
288      * for the tick marks.
289      *
290      * @return The length factor.
291      *
292      * @see #setMajorTickLength(double)
293      */

294     public double getMajorTickLength() {
295         return this.majorTickLength;
296     }
297     
298     /**
299      * Sets the length factor for the major tick marks.
300      *
301      * @param length the length.
302      *
303      * @see #getMajorTickLength()
304      */

305     public void setMajorTickLength(double length) {
306         // TODO: validation
307
this.majorTickLength = length;
308         notifyListeners(new DialLayerChangeEvent(this));
309     }
310     
311     /**
312      * Returns the major tick paint.
313      *
314      * @return The major tick paint (never <code>null</code>).
315      *
316      * @see #setMajorTickPaint(Paint)
317      */

318     public Paint JavaDoc getMajorTickPaint() {
319         return this.majorTickPaint;
320     }
321     
322     /**
323      * Sets the major tick paint.
324      *
325      * @param paint the paint (<code>null</code> not permitted).
326      *
327      * @see #getMajorTickPaint()
328      */

329     public void setMajorTickPaint(Paint JavaDoc paint) {
330         if (paint == null) {
331             throw new IllegalArgumentException JavaDoc("Null 'paint' argument.");
332         }
333         this.majorTickPaint = paint;
334         notifyListeners(new DialLayerChangeEvent(this));
335     }
336     
337     /**
338      * Returns the stroke used to draw the major tick marks.
339      *
340      * @return The stroke (never <code>null</code>).
341      *
342      * @see #setMajorTickStroke(Stroke)
343      */

344     public Stroke JavaDoc getMajorTickStroke() {
345         return this.majorTickStroke;
346     }
347     
348     /**
349      * Sets the stroke used to draw the major tick marks.
350      *
351      * @param stroke the stroke (<code>null</code> not permitted).
352      *
353      * @see #getMajorTickStroke()
354      */

355     public void setMajorTickStroke(Stroke JavaDoc stroke) {
356         if (stroke == null) {
357             throw new IllegalArgumentException JavaDoc("Null 'stroke' argument.");
358         }
359         this.majorTickStroke = stroke;
360         notifyListeners(new DialLayerChangeEvent(this));
361     }
362     
363     /**
364      * Returns the number of minor tick marks between major tick marks.
365      *
366      * @return The number of minor tick marks between major tick marks.
367      *
368      * @see #setMinorTickCount(int)
369      */

370     public int getMinorTickCount() {
371         return this.minorTickCount;
372     }
373     
374     /**
375      * Sets the number of minor tick marks between major tick marks.
376      *
377      * @param count the count.
378      *
379      * @see #getMinorTickCount()
380      */

381     public void setMinorTickCount(int count) {
382         // TODO: validation
383
this.minorTickCount = count;
384         notifyListeners(new DialLayerChangeEvent(this));
385     }
386     
387     /**
388      * Returns the length factor for the minor tick marks. The value is
389      * subtracted from the tick radius to determine the inner starting point
390      * for the tick marks.
391      *
392      * @return The length factor.
393      *
394      * @see #setMinorTickLength(double)
395      */

396     public double getMinorTickLength() {
397         return this.minorTickLength;
398     }
399     
400     /**
401      * Sets the length factor for the minor tick marks.
402      *
403      * @param length the length.
404      *
405      * @see #getMinorTickLength()
406      */

407     public void setMinorTickLength(double length) {
408         // TODO: validation
409
this.minorTickLength = length;
410         notifyListeners(new DialLayerChangeEvent(this));
411     }
412     
413     /**
414      * Returns the tick label offset.
415      *
416      * @return The tick label offset.
417      *
418      * @see #setTickLabelOffset(double)
419      */

420     public double getTickLabelOffset() {
421         return this.tickLabelOffset;
422     }
423     
424     /**
425      * Sets the tick label offset.
426      *
427      * @param offset the offset.
428      *
429      * @see #getTickLabelOffset()
430      */

431     public void setTickLabelOffset(double offset) {
432         this.tickLabelOffset = offset;
433         notifyListeners(new DialLayerChangeEvent(this));
434     }
435     
436     /**
437      * Returns the font used to draw the tick labels.
438      *
439      * @return The font (never <code>null</code>).
440      *
441      * @see #setTickLabelFont(Font)
442      */

443     public Font JavaDoc getTickLabelFont() {
444         return this.tickLabelFont;
445     }
446     
447     /**
448      * Sets the font used to display the tick labels.
449      *
450      * @param font the font (<code>null</code> not permitted).
451      *
452      * @see #getTickLabelFont()
453      */

454     public void setTickLabelFont(Font JavaDoc font) {
455         if (font == null) {
456             throw new IllegalArgumentException JavaDoc("Null 'font' argument.");
457         }
458         this.tickLabelFont = font;
459         notifyListeners(new DialLayerChangeEvent(this));
460     }
461     
462     /**
463      * Returns the paint used to draw the tick labels.
464      *
465      * @return The paint (<code>null</code> not permitted).
466      */

467     public Paint JavaDoc getTickLabelPaint() {
468         return this.tickLabelPaint;
469     }
470     
471     /**
472      * Sets the paint used to draw the tick labels.
473      *
474      * @param paint the paint (<code>null</code> not permitted).
475      */

476     public void setTickLabelPaint(Paint JavaDoc paint) {
477         // TODO: validation
478
this.tickLabelPaint = paint;
479         notifyListeners(new DialLayerChangeEvent(this));
480     }
481     
482     /**
483      * Returns <code>true</code> if the tick labels should be displayed,
484      * and <code>false</code> otherwise.
485      *
486      * @return A boolean.
487      */

488     public boolean getTickLabelsVisible() {
489         return this.tickLabelsVisible;
490     }
491     
492     /**
493      * Sets the flag that controls whether or not the tick labels are
494      * displayed, and sends a {@link DialLayerChangeEvent} to all registered
495      * listeners.
496      *
497      * @param visible the new flag value.
498      */

499     public void setTickLabelsVisible(boolean visible) {
500         this.tickLabelsVisible = visible;
501         notifyListeners(new DialLayerChangeEvent(this));
502     }
503     
504     /**
505      * Returns a flag that controls whether or not the first tick label is
506      * visible.
507      *
508      * @return A boolean.
509      */

510     public boolean getFirstTickLabelVisible() {
511         return this.firstTickLabelVisible;
512     }
513     
514     /**
515      * Sets a flag that controls whether or not the first tick label is
516      * visible, and sends a {@link DialLayerChangeEvent} to all registered
517      * listeners.
518      *
519      * @param visible the new flag value.
520      */

521     public void setFirstTickLabelVisible(boolean visible) {
522         this.firstTickLabelVisible = visible;
523         notifyListeners(new DialLayerChangeEvent(this));
524     }
525     
526     /**
527      * Returns <code>true</code> to indicate that this layer should be
528      * clipped within the dial window.
529      *
530      * @return <code>true</code>.
531      */

532     public boolean isClippedToWindow() {
533         return true;
534     }
535     
536     /**
537      * Draws the scale on the dial plot.
538      *
539      * @param g2 the graphics target (<code>null</code> not permitted).
540      * @param plot the dial plot (<code>null</code> not permitted).
541      * @param frame the reference frame that is used to construct the
542      * geometry of the plot (<code>null</code> not permitted).
543      * @param view the visible part of the plot (<code>null</code> not
544      * permitted).
545      */

546     public void draw(Graphics2D JavaDoc g2, DialPlot plot, Rectangle2D JavaDoc frame,
547             Rectangle2D JavaDoc view) {
548         
549         Rectangle2D JavaDoc arcRect = DialPlot.rectangleByRadius(frame,
550                 this.tickRadius, this.tickRadius);
551         Rectangle2D JavaDoc arcRectInner = DialPlot.rectangleByRadius(frame,
552                 this.tickRadius - this.minorTickLength,
553                 this.tickRadius - this.minorTickLength);
554         Rectangle2D JavaDoc arcRectForLabels = DialPlot.rectangleByRadius(frame,
555                 this.tickRadius - this.tickLabelOffset,
556                 this.tickRadius - this.tickLabelOffset);
557         
558         boolean firstLabel = true;
559         
560         Arc2D JavaDoc arc = new Arc2D.Double JavaDoc();
561         for (double v = this.lowerBound; v <= this.upperBound;
562                 v += this.majorTickIncrement) {
563             arc.setArc(arcRect, this.startAngle, valueToAngle(v)
564                     - this.startAngle, Arc2D.OPEN);
565             Point2D JavaDoc pt0 = arc.getEndPoint();
566             arc.setArc(arcRectInner, this.startAngle, valueToAngle(v)
567                     - this.startAngle, Arc2D.OPEN);
568             Point2D JavaDoc pt1 = arc.getEndPoint();
569             g2.setPaint(this.majorTickPaint);
570             g2.setStroke(this.majorTickStroke);
571             g2.draw(new Line2D.Double JavaDoc(pt0, pt1));
572             arc.setArc(arcRectForLabels, this.startAngle, valueToAngle(v)
573                     - this.startAngle, Arc2D.OPEN);
574             Point2D JavaDoc pt2 = arc.getEndPoint();
575             
576             if (tickLabelsVisible) {
577                 if (!firstLabel || this.firstTickLabelVisible) {
578                     g2.setFont(this.tickLabelFont);
579                     TextUtilities.drawAlignedString(String.valueOf(v), g2,
580                             (float) pt2.getX(), (float) pt2.getY(),
581                             TextAnchor.CENTER);
582                 }
583             }
584             firstLabel = false;
585             
586             // now do the minor tick marks
587
if (this.minorTickCount > 0) {
588                 double minorTickIncrement = this.majorTickIncrement
589                         / (this.minorTickCount + 1);
590                 for (int i = 0; i < this.minorTickCount; i++) {
591                     double vv = v + ((i + 1) * minorTickIncrement);
592                     if (vv >= this.upperBound) {
593                         break;
594                     }
595                     double angle = valueToAngle(vv);
596                    
597                     arc.setArc(arcRect, this.startAngle, angle
598                             - this.startAngle, Arc2D.OPEN);
599                     pt0 = arc.getEndPoint();
600                     arc.setArc(arcRectInner, this.startAngle, angle
601                             - this.startAngle, Arc2D.OPEN);
602                     Point2D JavaDoc pt3 = arc.getEndPoint();
603                     g2.setStroke(new BasicStroke JavaDoc(1.0f));
604                     g2.draw(new Line2D.Double JavaDoc(pt0, pt3));
605                 }
606             }
607             
608         }
609     }
610     
611     /**
612      * Converts a data value to an angle against this scale.
613      *
614      * @param value the data value.
615      *
616      * @return The angle (in degrees, using the same specification as Java's
617      * Arc2D class).
618      */

619     public double valueToAngle(double value) {
620         double range = this.upperBound - this.lowerBound;
621         double unit = this.extent / range;
622         return this.startAngle + unit * (value - this.lowerBound);
623     }
624
625     public double angleToValue(double angle) {
626         return Double.NaN; // FIXME
627
}
628
629     /**
630      * Tests this <code>StandardDialScale</code> for equality with an arbitrary
631      * object.
632      *
633      * @param obj the object (<code>null</code> permitted).
634      *
635      * @return A boolean.
636      */

637     public boolean equals(Object JavaDoc obj) {
638         if (obj == this) {
639             return true;
640         }
641         if (!(obj instanceof StandardDialScale)) {
642             return false;
643         }
644         StandardDialScale that = (StandardDialScale) obj;
645         if (this.lowerBound != that.lowerBound) {
646             return false;
647         }
648         if (this.upperBound != that.upperBound) {
649             return false;
650         }
651         if (this.startAngle != that.startAngle) {
652             return false;
653         }
654         if (this.extent != that.extent) {
655             return false;
656         }
657         if (this.tickRadius != that.tickRadius) {
658             return false;
659         }
660         if (this.majorTickIncrement != that.majorTickIncrement) {
661             return false;
662         }
663         if (this.majorTickLength != that.majorTickLength) {
664             return false;
665         }
666         if (!PaintUtilities.equal(this.majorTickPaint, that.majorTickPaint)) {
667             return false;
668         }
669         if (!this.majorTickStroke.equals(that.majorTickStroke)) {
670             return false;
671         }
672         if (this.minorTickCount != that.minorTickCount) {
673             return false;
674         }
675         if (this.minorTickLength != that.minorTickLength) {
676             return false;
677         }
678         if (this.tickLabelOffset != that.tickLabelOffset) {
679             return false;
680         }
681         if (!this.tickLabelFont.equals(that.tickLabelFont)) {
682             return false;
683         }
684         if (!PaintUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) {
685             return false;
686         }
687         return true;
688     }
689
690     /**
691      * Returns a clone of this instance.
692      *
693      * @return A clone.
694      *
695      * @throws CloneNotSupportedException if this instance is not cloneable.
696      */

697     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
698         return super.clone();
699     }
700     
701     /**
702      * Provides serialization support.
703      *
704      * @param stream the output stream.
705      *
706      * @throws IOException if there is an I/O error.
707      */

708     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
709         stream.defaultWriteObject();
710         SerialUtilities.writePaint(this.majorTickPaint, stream);
711         SerialUtilities.writeStroke(this.majorTickStroke, stream);
712         SerialUtilities.writePaint(this.tickLabelPaint, stream);
713     }
714
715     /**
716      * Provides serialization support.
717      *
718      * @param stream the input stream.
719      *
720      * @throws IOException if there is an I/O error.
721      * @throws ClassNotFoundException if there is a classpath problem.
722      */

723     private void readObject(ObjectInputStream JavaDoc stream)
724             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
725         stream.defaultReadObject();
726         this.majorTickPaint = SerialUtilities.readPaint(stream);
727         this.majorTickStroke = SerialUtilities.readStroke(stream);
728         this.tickLabelPaint = SerialUtilities.readPaint(stream);
729     }
730
731 }
732
Popular Tags