KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > axis > NumberAxis


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, 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 License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ---------------
27  * NumberAxis.java
28  * ---------------
29  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): Laurence Vanhelsuwe;
33  *
34  * $Id: NumberAxis.java,v 1.16 2005/05/19 13:58:11 mungady Exp $
35  *
36  * Changes (from 18-Sep-2001)
37  * --------------------------
38  * 18-Sep-2001 : Added standard header and fixed DOS encoding problem (DG);
39  * 22-Sep-2001 : Changed setMinimumAxisValue() and setMaximumAxisValue() so
40  * that they clear the autoRange flag (DG);
41  * 27-Nov-2001 : Removed old, redundant code (DG);
42  * 30-Nov-2001 : Added accessor methods for the standard tick units (DG);
43  * 08-Jan-2002 : Added setAxisRange() method (since renamed setRange()) (DG);
44  * 16-Jan-2002 : Added setTickUnit() method. Extended ValueAxis to support an
45  * optional cross-hair (DG);
46  * 08-Feb-2002 : Fixes bug to ensure the autorange is recalculated if the
47  * setAutoRangeIncludesZero flag is changed (DG);
48  * 25-Feb-2002 : Added a new flag autoRangeStickyZero to provide further
49  * control over margins in the auto-range mechanism. Updated
50  * constructors. Updated import statements. Moved the
51  * createStandardTickUnits() method to the TickUnits class (DG);
52  * 19-Apr-2002 : Updated Javadoc comments (DG);
53  * 01-May-2002 : Updated for changes to TickUnit class, removed valueToString()
54  * method (DG);
55  * 25-Jul-2002 : Moved the lower and upper margin attributes, and the
56  * auto-range minimum size, up one level to the ValueAxis
57  * class (DG);
58  * 05-Sep-2002 : Updated constructor to match changes in Axis class (DG);
59  * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
60  * 04-Oct-2002 : Moved standardTickUnits from NumberAxis --> ValueAxis (DG);
61  * 24-Oct-2002 : Added a number format override (DG);
62  * 08-Nov-2002 : Moved to new package com.jrefinery.chart.axis (DG);
63  * 19-Nov-2002 : Removed grid settings (now controlled by the plot) (DG);
64  * 14-Jan-2003 : Changed autoRangeMinimumSize from Number --> double, and moved
65  * crosshair settings to the plot classes (DG);
66  * 20-Jan-2003 : Removed the monolithic constructor (DG);
67  * 26-Mar-2003 : Implemented Serializable (DG);
68  * 16-Jul-2003 : Reworked to allow for multiple secondary axes (DG);
69  * 13-Aug-2003 : Implemented Cloneable (DG);
70  * 07-Oct-2003 : Fixed bug (815028) in the auto range calculation (DG);
71  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
72  * 07-Nov-2003 : Modified to use NumberTick class (DG);
73  * 21-Jan-2004 : Renamed translateJava2DToValue --> java2DToValue, and
74  * translateValueToJava2D --> valueToJava2D (DG);
75  * 03-Mar-2004 : Added plotState to draw() method (DG);
76  * 07-Apr-2004 : Changed string width calculation (DG);
77  * 11-Jan-2005 : Removed deprecated methods in preparation for 1.0.0
78  * release (DG);
79  * 28-Mar-2005 : Renamed autoRangeIncludesZero() --> getAutoRangeIncludesZero()
80  * and autoRangeStickyZero() --> getAutoRangeStickyZero() (DG);
81  * 21-Apr-2005 : Removed redundant argument from selectAutoTickUnit() (DG);
82  * 22-Apr-2005 : Renamed refreshHorizontalTicks --> refreshTicksHorizontal
83  * (and likewise the vertical version) for consistency with
84  * other axis classes (DG);
85  *
86  */

87
88 package org.jfree.chart.axis;
89
90 import java.awt.Font JavaDoc;
91 import java.awt.FontMetrics JavaDoc;
92 import java.awt.Graphics2D JavaDoc;
93 import java.awt.font.FontRenderContext JavaDoc;
94 import java.awt.font.LineMetrics JavaDoc;
95 import java.awt.geom.Rectangle2D JavaDoc;
96 import java.io.Serializable JavaDoc;
97 import java.text.DecimalFormat JavaDoc;
98 import java.text.NumberFormat JavaDoc;
99 import java.util.List JavaDoc;
100 import java.util.Locale JavaDoc;
101
102 import org.jfree.chart.event.AxisChangeEvent;
103 import org.jfree.chart.plot.Plot;
104 import org.jfree.chart.plot.PlotRenderingInfo;
105 import org.jfree.chart.plot.ValueAxisPlot;
106 import org.jfree.data.Range;
107 import org.jfree.data.RangeType;
108 import org.jfree.ui.RectangleEdge;
109 import org.jfree.ui.RectangleInsets;
110 import org.jfree.ui.TextAnchor;
111 import org.jfree.util.ObjectUtilities;
112
113 /**
114  * An axis for displaying numerical data.
115  * <P>
116  * If the axis is set up to automatically determine its range to fit the data,
117  * you can ensure that the range includes zero (statisticians usually prefer
118  * this) by setting the <code>autoRangeIncludesZero</code> flag to
119  * <code>true</code>.
120  * <P>
121  * The <code>NumberAxis</code> class has a mechanism for automatically
122  * selecting a tick unit that is appropriate for the current axis range. This
123  * mechanism is an adaptation of code suggested by Laurence Vanhelsuwe.
124  */

125 public class NumberAxis extends ValueAxis implements Cloneable JavaDoc, Serializable JavaDoc {
126
127     /** For serialization. */
128     private static final long serialVersionUID = 2805933088476185789L;
129     
130     /** The default value for the autoRangeIncludesZero flag. */
131     public static final boolean DEFAULT_AUTO_RANGE_INCLUDES_ZERO = true;
132
133     /** The default value for the autoRangeStickyZero flag. */
134     public static final boolean DEFAULT_AUTO_RANGE_STICKY_ZERO = true;
135
136     /** The default tick unit. */
137     public static final NumberTickUnit
138         DEFAULT_TICK_UNIT = new NumberTickUnit(1.0, new DecimalFormat JavaDoc("0"));
139
140     /** The default setting for the vertical tick labels flag. */
141     public static final boolean DEFAULT_VERTICAL_TICK_LABELS = false;
142
143     /**
144      * The range type (can be used to force the axis to display only positive
145      * values or only negative values.
146      */

147     private RangeType rangeType;
148     
149     /**
150      * A flag that affects the axis range when the range is determined
151      * automatically. If the auto range does NOT include zero and this flag
152      * is TRUE, then the range is changed to include zero.
153      */

154     private boolean autoRangeIncludesZero;
155
156     /**
157      * A flag that affects the size of the margins added to the axis range when
158      * the range is determined automatically. If the value 0 falls within the
159      * margin and this flag is TRUE, then the margin is truncated at zero.
160      */

161     private boolean autoRangeStickyZero;
162
163     /** The tick unit for the axis. */
164     private NumberTickUnit tickUnit;
165
166     /** The override number format. */
167     private NumberFormat JavaDoc numberFormatOverride;
168
169     /** An optional band for marking regions on the axis. */
170     private MarkerAxisBand markerBand;
171
172     /**
173      * Default constructor.
174      */

175     public NumberAxis() {
176         this(null);
177     }
178     
179     /**
180      * Constructs a number axis, using default values where necessary.
181      *
182      * @param label the axis label (<code>null</code> permitted).
183      */

184     public NumberAxis(String JavaDoc label) {
185         super(label, NumberAxis.createStandardTickUnits());
186         this.rangeType = RangeType.FULL;
187         this.autoRangeIncludesZero = DEFAULT_AUTO_RANGE_INCLUDES_ZERO;
188         this.autoRangeStickyZero = DEFAULT_AUTO_RANGE_STICKY_ZERO;
189         this.tickUnit = DEFAULT_TICK_UNIT;
190         this.numberFormatOverride = null;
191         this.markerBand = null;
192     }
193     
194     /**
195      * Returns the axis range type.
196      *
197      * @return The axis range type (never <code>null</code>).
198      */

199     public RangeType getRangeType() {
200         return this.rangeType;
201     }
202     
203     /**
204      * Sets the axis range type.
205      *
206      * @param rangeType the range type (<code>null</code> not permitted).
207      */

208     public void setRangeType(RangeType rangeType) {
209         if (rangeType == null) {
210             throw new IllegalArgumentException JavaDoc("Null 'rangeType' argument.");
211         }
212         this.rangeType = rangeType;
213         notifyListeners(new AxisChangeEvent(this));
214     }
215     
216     /**
217      * Returns the flag that indicates whether or not the automatic axis range
218      * (if indeed it is determined automatically) is forced to include zero.
219      *
220      * @return The flag.
221      */

222     public boolean getAutoRangeIncludesZero() {
223         return this.autoRangeIncludesZero;
224     }
225
226     /**
227      * Sets the flag that indicates whether or not the axis range, if
228      * automatically calculated, is forced to include zero.
229      * <p>
230      * If the flag is changed to <code>true</code>, the axis range is
231      * recalculated.
232      * <p>
233      * Any change to the flag will trigger an {@link AxisChangeEvent}.
234      *
235      * @param flag the new value of the flag.
236      */

237     public void setAutoRangeIncludesZero(boolean flag) {
238         if (this.autoRangeIncludesZero != flag) {
239             this.autoRangeIncludesZero = flag;
240             if (isAutoRange()) {
241                 autoAdjustRange();
242             }
243             notifyListeners(new AxisChangeEvent(this));
244         }
245     }
246
247     /**
248      * Returns a flag that affects the auto-range when zero falls outside the
249      * data range but inside the margins defined for the axis.
250      *
251      * @return The flag.
252      */

253     public boolean getAutoRangeStickyZero() {
254         return this.autoRangeStickyZero;
255     }
256
257     /**
258      * Sets a flag that affects the auto-range when zero falls outside the data
259      * range but inside the margins defined for the axis.
260      *
261      * @param flag the new flag.
262      */

263     public void setAutoRangeStickyZero(boolean flag) {
264         if (this.autoRangeStickyZero != flag) {
265             this.autoRangeStickyZero = flag;
266             if (isAutoRange()) {
267                 autoAdjustRange();
268             }
269             notifyListeners(new AxisChangeEvent(this));
270         }
271     }
272
273     /**
274      * Returns the tick unit for the axis.
275      *
276      * @return The tick unit for the axis.
277      */

278     public NumberTickUnit getTickUnit() {
279         return this.tickUnit;
280     }
281
282     /**
283      * Sets the tick unit for the axis and sends an {@link AxisChangeEvent} to
284      * all registered listeners. A side effect of calling this method is that
285      * the "auto-select" feature for tick units is switched off (you can
286      * restore it using the {@link ValueAxis#setAutoTickUnitSelection(boolean)}
287      * method).
288      *
289      * @param unit the new tick unit (<code>null</code> not permitted).
290      */

291     public void setTickUnit(NumberTickUnit unit) {
292         // defer argument checking...
293
setTickUnit(unit, true, true);
294     }
295
296     /**
297      * Sets the tick unit for the axis and, if requested, sends an
298      * {@link AxisChangeEvent} to all registered listeners. In addition, an
299      * option is provided to turn off the "auto-select" feature for tick units
300      * (you can restore it using the
301      * {@link ValueAxis#setAutoTickUnitSelection(boolean)} method).
302      *
303      * @param unit the new tick unit (<code>null</code> not permitted).
304      * @param notify notify listeners?
305      * @param turnOffAutoSelect turn off the auto-tick selection?
306      */

307     public void setTickUnit(NumberTickUnit unit, boolean notify,
308                             boolean turnOffAutoSelect) {
309
310         if (unit == null) {
311             throw new IllegalArgumentException JavaDoc("Null 'unit' argument.");
312         }
313         this.tickUnit = unit;
314         if (turnOffAutoSelect) {
315             setAutoTickUnitSelection(false, false);
316         }
317         if (notify) {
318             notifyListeners(new AxisChangeEvent(this));
319         }
320
321     }
322
323     /**
324      * Returns the number format override. If this is non-null, then it will
325      * be used to format the numbers on the axis.
326      *
327      * @return The number formatter (possibly <code>null</code>).
328      */

329     public NumberFormat JavaDoc getNumberFormatOverride() {
330         return this.numberFormatOverride;
331     }
332
333     /**
334      * Sets the number format override. If this is non-null, then it will be
335      * used to format the numbers on the axis.
336      *
337      * @param formatter the number formatter (<code>null</code> permitted).
338      */

339     public void setNumberFormatOverride(NumberFormat JavaDoc formatter) {
340         this.numberFormatOverride = formatter;
341         notifyListeners(new AxisChangeEvent(this));
342     }
343
344     /**
345      * Returns the (optional) marker band for the axis.
346      *
347      * @return The marker band (possibly <code>null</code>).
348      */

349     public MarkerAxisBand getMarkerBand() {
350         return this.markerBand;
351     }
352
353     /**
354      * Sets the marker band for the axis.
355      * <P>
356      * The marker band is optional, leave it set to <code>null</code> if you
357      * don't require it.
358      *
359      * @param band the new band (<code>null<code> permitted).
360      */

361     public void setMarkerBand(MarkerAxisBand band) {
362         this.markerBand = band;
363         notifyListeners(new AxisChangeEvent(this));
364     }
365
366     /**
367      * Configures the axis to work with the specified plot. If the axis has
368      * auto-scaling, then sets the maximum and minimum values.
369      */

370     public void configure() {
371         if (isAutoRange()) {
372             autoAdjustRange();
373         }
374     }
375
376     /**
377      * Rescales the axis to ensure that all data is visible.
378      */

379     protected void autoAdjustRange() {
380
381         Plot plot = getPlot();
382         if (plot == null) {
383             return; // no plot, no data
384
}
385
386         if (plot instanceof ValueAxisPlot) {
387             ValueAxisPlot vap = (ValueAxisPlot) plot;
388
389             Range r = vap.getDataRange(this);
390             if (r == null) {
391                 r = new Range(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND);
392             }
393             
394             double upper = r.getUpperBound();
395             double lower = r.getLowerBound();
396             if (this.rangeType == RangeType.POSITIVE) {
397                 lower = Math.max(0.0, lower);
398                 upper = Math.max(0.0, upper);
399             }
400             else if (this.rangeType == RangeType.NEGATIVE) {
401                 lower = Math.min(0.0, lower);
402                 upper = Math.min(0.0, upper);
403             }
404             
405             if (getAutoRangeIncludesZero()) {
406                 lower = Math.min(lower, 0.0);
407                 upper = Math.max(upper, 0.0);
408             }
409             double range = upper - lower;
410
411             // if fixed auto range, then derive lower bound...
412
double fixedAutoRange = getFixedAutoRange();
413             if (fixedAutoRange > 0.0) {
414                 lower = upper - fixedAutoRange;
415             }
416             else {
417                 // ensure the autorange is at least <minRange> in size...
418
double minRange = getAutoRangeMinimumSize();
419                 if (range < minRange) {
420                     double expand = (minRange - range) / 2;
421                     upper = upper + expand;
422                     lower = lower - expand;
423                     if (this.rangeType == RangeType.POSITIVE) {
424                         if (lower < 0.0) {
425                             upper = upper - lower;
426                             lower = 0.0;
427                         }
428                     }
429                     else if (this.rangeType == RangeType.NEGATIVE) {
430                         if (upper > 0.0) {
431                             lower = lower - upper;
432                             upper = 0.0;
433                         }
434                     }
435                 }
436
437                 if (getAutoRangeStickyZero()) {
438                     if (upper <= 0.0) {
439                         upper = Math.min(0.0, upper + getUpperMargin() * range);
440                     }
441                     else {
442                         upper = upper + getUpperMargin() * range;
443                     }
444                     if (lower >= 0.0) {
445                         lower = Math.max(0.0, lower - getLowerMargin() * range);
446                     }
447                     else {
448                         lower = lower - getLowerMargin() * range;
449                     }
450                 }
451                 else {
452                     upper = upper + getUpperMargin() * range;
453                     lower = lower - getLowerMargin() * range;
454                 }
455             }
456
457             setRange(new Range(lower, upper), false, false);
458         }
459
460     }
461
462     /**
463      * Converts a data value to a coordinate in Java2D space, assuming that the
464      * axis runs along one edge of the specified dataArea.
465      * <p>
466      * Note that it is possible for the coordinate to fall outside the plotArea.
467      *
468      * @param value the data value.
469      * @param area the area for plotting the data.
470      * @param edge the axis location.
471      *
472      * @return The Java2D coordinate.
473      */

474     public double valueToJava2D(double value, Rectangle2D JavaDoc area,
475                                 RectangleEdge edge) {
476         
477         Range range = getRange();
478         double axisMin = range.getLowerBound();
479         double axisMax = range.getUpperBound();
480
481         double min = 0.0;
482         double max = 0.0;
483         if (RectangleEdge.isTopOrBottom(edge)) {
484             min = area.getX();
485             max = area.getMaxX();
486         }
487         else if (RectangleEdge.isLeftOrRight(edge)) {
488             max = area.getMinY();
489             min = area.getMaxY();
490         }
491         if (isInverted()) {
492             return max
493                    - ((value - axisMin) / (axisMax - axisMin)) * (max - min);
494         }
495         else {
496             return min
497                    + ((value - axisMin) / (axisMax - axisMin)) * (max - min);
498         }
499
500     }
501
502     /**
503      * Converts a coordinate in Java2D space to the corresponding data value,
504      * assuming that the axis runs along one edge of the specified dataArea.
505      *
506      * @param java2DValue the coordinate in Java2D space.
507      * @param area the area in which the data is plotted.
508      * @param edge the location.
509      *
510      * @return The data value.
511      */

512     public double java2DToValue(double java2DValue, Rectangle2D JavaDoc area,
513                                 RectangleEdge edge) {
514         
515         Range range = getRange();
516         double axisMin = range.getLowerBound();
517         double axisMax = range.getUpperBound();
518
519         double min = 0.0;
520         double max = 0.0;
521         if (RectangleEdge.isTopOrBottom(edge)) {
522             min = area.getX();
523             max = area.getMaxX();
524         }
525         else if (RectangleEdge.isLeftOrRight(edge)) {
526             min = area.getMaxY();
527             max = area.getY();
528         }
529         if (isInverted()) {
530             return axisMax
531                    - (java2DValue - min) / (max - min) * (axisMax - axisMin);
532         }
533         else {
534             return axisMin
535                    + (java2DValue - min) / (max - min) * (axisMax - axisMin);
536         }
537
538     }
539
540     /**
541      * Calculates the value of the lowest visible tick on the axis.
542      *
543      * @return The value of the lowest visible tick on the axis.
544      */

545     protected double calculateLowestVisibleTickValue() {
546
547         double unit = getTickUnit().getSize();
548         double index = Math.ceil(getRange().getLowerBound() / unit);
549         return index * unit;
550
551     }
552
553     /**
554      * Calculates the value of the highest visible tick on the axis.
555      *
556      * @return The value of the highest visible tick on the axis.
557      */

558     protected double calculateHighestVisibleTickValue() {
559
560         double unit = getTickUnit().getSize();
561         double index = Math.floor(getRange().getUpperBound() / unit);
562         return index * unit;
563
564     }
565
566     /**
567      * Calculates the number of visible ticks.
568      *
569      * @return The number of visible ticks on the axis.
570      */

571     protected int calculateVisibleTickCount() {
572
573         double unit = getTickUnit().getSize();
574         Range range = getRange();
575         return (int) (Math.floor(range.getUpperBound() / unit)
576                       - Math.ceil(range.getLowerBound() / unit) + 1);
577
578     }
579
580     /**
581      * Draws the axis on a Java 2D graphics device (such as the screen or a
582      * printer).
583      *
584      * @param g2 the graphics device (<code>null</code> not permitted).
585      * @param cursor the cursor location.
586      * @param plotArea the area within which the axes and data should be drawn
587      * (<code>null</code> not permitted).
588      * @param dataArea the area within which the data should be drawn
589      * (<code>null</code> not permitted).
590      * @param edge the location of the axis (<code>null</code> not permitted).
591      * @param plotState collects information about the plot
592      * (<code>null</code> permitted).
593      *
594      * @return The axis state (never <code>null</code>).
595      */

596     public AxisState draw(Graphics2D JavaDoc g2,
597                           double cursor,
598                           Rectangle2D JavaDoc plotArea,
599                           Rectangle2D JavaDoc dataArea,
600                           RectangleEdge edge,
601                           PlotRenderingInfo plotState) {
602
603         AxisState state = null;
604         // if the axis is not visible, don't draw it...
605
if (!isVisible()) {
606             state = new AxisState(cursor);
607             // even though the axis is not visible, we need ticks for the
608
// gridlines...
609
List JavaDoc ticks = refreshTicks(g2, state, dataArea, edge);
610             state.setTicks(ticks);
611             return state;
612         }
613
614         // draw the tick marks and labels...
615
state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge);
616
617 // // draw the marker band (if there is one)...
618
// if (getMarkerBand() != null) {
619
// if (edge == RectangleEdge.BOTTOM) {
620
// cursor = cursor - getMarkerBand().getHeight(g2);
621
// }
622
// getMarkerBand().draw(g2, plotArea, dataArea, 0, cursor);
623
// }
624

625         // draw the axis label...
626
state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state);
627
628         return state;
629         
630     }
631
632     /**
633      * Creates the standard tick units.
634      * <P>
635      * If you don't like these defaults, create your own instance of TickUnits
636      * and then pass it to the setStandardTickUnits() method in the
637      * NumberAxis class.
638      *
639      * @return The standard tick units.
640      */

641     public static TickUnitSource createStandardTickUnits() {
642
643         TickUnits units = new TickUnits();
644         DecimalFormat JavaDoc df0 = new DecimalFormat JavaDoc("0.00000000");
645         DecimalFormat JavaDoc df1 = new DecimalFormat JavaDoc("0.0000000");
646         DecimalFormat JavaDoc df2 = new DecimalFormat JavaDoc("0.000000");
647         DecimalFormat JavaDoc df3 = new DecimalFormat JavaDoc("0.00000");
648         DecimalFormat JavaDoc df4 = new DecimalFormat JavaDoc("0.0000");
649         DecimalFormat JavaDoc df5 = new DecimalFormat JavaDoc("0.000");
650         DecimalFormat JavaDoc df6 = new DecimalFormat JavaDoc("0.00");
651         DecimalFormat JavaDoc df7 = new DecimalFormat JavaDoc("0.0");
652         DecimalFormat JavaDoc df8 = new DecimalFormat JavaDoc("#,##0");
653         DecimalFormat JavaDoc df9 = new DecimalFormat JavaDoc("#,###,##0");
654         DecimalFormat JavaDoc df10 = new DecimalFormat JavaDoc("#,###,###,##0");
655         
656         // we can add the units in any order, the TickUnits collection will
657
// sort them...
658
units.add(new NumberTickUnit(0.0000001, df1));
659         units.add(new NumberTickUnit(0.000001, df2));
660         units.add(new NumberTickUnit(0.00001, df3));
661         units.add(new NumberTickUnit(0.0001, df4));
662         units.add(new NumberTickUnit(0.001, df5));
663         units.add(new NumberTickUnit(0.01, df6));
664         units.add(new NumberTickUnit(0.1, df7));
665         units.add(new NumberTickUnit(1, df8));
666         units.add(new NumberTickUnit(10, df8));
667         units.add(new NumberTickUnit(100, df8));
668         units.add(new NumberTickUnit(1000, df8));
669         units.add(new NumberTickUnit(10000, df8));
670         units.add(new NumberTickUnit(100000, df8));
671         units.add(new NumberTickUnit(1000000, df9));
672         units.add(new NumberTickUnit(10000000, df9));
673         units.add(new NumberTickUnit(100000000, df9));
674         units.add(new NumberTickUnit(1000000000, df10));
675         units.add(new NumberTickUnit(10000000000.0, df10));
676         units.add(new NumberTickUnit(100000000000.0, df10));
677         
678         units.add(new NumberTickUnit(0.00000025, df0));
679         units.add(new NumberTickUnit(0.0000025, df1));
680         units.add(new NumberTickUnit(0.000025, df2));
681         units.add(new NumberTickUnit(0.00025, df3));
682         units.add(new NumberTickUnit(0.0025, df4));
683         units.add(new NumberTickUnit(0.025, df5));
684         units.add(new NumberTickUnit(0.25, df6));
685         units.add(new NumberTickUnit(2.5, df7));
686         units.add(new NumberTickUnit(25, df8));
687         units.add(new NumberTickUnit(250, df8));
688         units.add(new NumberTickUnit(2500, df8));
689         units.add(new NumberTickUnit(25000, df8));
690         units.add(new NumberTickUnit(250000, df8));
691         units.add(new NumberTickUnit(2500000, df9));
692         units.add(new NumberTickUnit(25000000, df9));
693         units.add(new NumberTickUnit(250000000, df9));
694         units.add(new NumberTickUnit(2500000000.0, df10));
695         units.add(new NumberTickUnit(25000000000.0, df10));
696         units.add(new NumberTickUnit(250000000000.0, df10));
697
698         units.add(new NumberTickUnit(0.0000005, df1));
699         units.add(new NumberTickUnit(0.000005, df2));
700         units.add(new NumberTickUnit(0.00005, df3));
701         units.add(new NumberTickUnit(0.0005, df4));
702         units.add(new NumberTickUnit(0.005, df5));
703         units.add(new NumberTickUnit(0.05, df6));
704         units.add(new NumberTickUnit(0.5, df7));
705         units.add(new NumberTickUnit(5L, df8));
706         units.add(new NumberTickUnit(50L, df8));
707         units.add(new NumberTickUnit(500L, df8));
708         units.add(new NumberTickUnit(5000L, df8));
709         units.add(new NumberTickUnit(50000L, df8));
710         units.add(new NumberTickUnit(500000L, df8));
711         units.add(new NumberTickUnit(5000000L, df9));
712         units.add(new NumberTickUnit(50000000L, df9));
713         units.add(new NumberTickUnit(500000000L, df9));
714         units.add(new NumberTickUnit(5000000000L, df10));
715         units.add(new NumberTickUnit(50000000000L, df10));
716         units.add(new NumberTickUnit(500000000000L, df10));
717
718         return units;
719
720     }
721
722     /**
723      * Returns a collection of tick units for integer values.
724      *
725      * @return A collection of tick units for integer values.
726      */

727     public static TickUnitSource createIntegerTickUnits() {
728
729         TickUnits units = new TickUnits();
730         DecimalFormat JavaDoc df0 = new DecimalFormat JavaDoc("0");
731         DecimalFormat JavaDoc df1 = new DecimalFormat JavaDoc("#,##0");
732         units.add(new NumberTickUnit(1, df0));
733         units.add(new NumberTickUnit(2, df0));
734         units.add(new NumberTickUnit(5, df0));
735         units.add(new NumberTickUnit(10, df0));
736         units.add(new NumberTickUnit(20, df0));
737         units.add(new NumberTickUnit(50, df0));
738         units.add(new NumberTickUnit(100, df0));
739         units.add(new NumberTickUnit(200, df0));
740         units.add(new NumberTickUnit(500, df0));
741         units.add(new NumberTickUnit(1000, df1));
742         units.add(new NumberTickUnit(2000, df1));
743         units.add(new NumberTickUnit(5000, df1));
744         units.add(new NumberTickUnit(10000, df1));
745         units.add(new NumberTickUnit(20000, df1));
746         units.add(new NumberTickUnit(50000, df1));
747         units.add(new NumberTickUnit(100000, df1));
748         units.add(new NumberTickUnit(200000, df1));
749         units.add(new NumberTickUnit(500000, df1));
750         units.add(new NumberTickUnit(1000000, df1));
751         units.add(new NumberTickUnit(2000000, df1));
752         units.add(new NumberTickUnit(5000000, df1));
753         units.add(new NumberTickUnit(10000000, df1));
754         units.add(new NumberTickUnit(20000000, df1));
755         units.add(new NumberTickUnit(50000000, df1));
756         units.add(new NumberTickUnit(100000000, df1));
757         units.add(new NumberTickUnit(200000000, df1));
758         units.add(new NumberTickUnit(500000000, df1));
759         units.add(new NumberTickUnit(1000000000, df1));
760         units.add(new NumberTickUnit(2000000000, df1));
761         units.add(new NumberTickUnit(5000000000.0, df1));
762         units.add(new NumberTickUnit(10000000000.0, df1));
763
764         return units;
765
766     }
767
768     /**
769      * Creates a collection of standard tick units. The supplied locale is
770      * used to create the number formatter (a localised instance of
771      * <code>NumberFormat</code>).
772      * <P>
773      * If you don't like these defaults, create your own instance of
774      * {@link TickUnits} and then pass it to the
775      * <code>setStandardTickUnits()</code> method.
776      *
777      * @param locale the locale.
778      *
779      * @return A tick unit collection.
780      */

781     public static TickUnitSource createStandardTickUnits(Locale JavaDoc locale) {
782
783         TickUnits units = new TickUnits();
784
785         NumberFormat JavaDoc numberFormat = NumberFormat.getNumberInstance(locale);
786
787         // we can add the units in any order, the TickUnits collection will
788
// sort them...
789
units.add(new NumberTickUnit(0.0000001, numberFormat));
790         units.add(new NumberTickUnit(0.000001, numberFormat));
791         units.add(new NumberTickUnit(0.00001, numberFormat));
792         units.add(new NumberTickUnit(0.0001, numberFormat));
793         units.add(new NumberTickUnit(0.001, numberFormat));
794         units.add(new NumberTickUnit(0.01, numberFormat));
795         units.add(new NumberTickUnit(0.1, numberFormat));
796         units.add(new NumberTickUnit(1, numberFormat));
797         units.add(new NumberTickUnit(10, numberFormat));
798         units.add(new NumberTickUnit(100, numberFormat));
799         units.add(new NumberTickUnit(1000, numberFormat));
800         units.add(new NumberTickUnit(10000, numberFormat));
801         units.add(new NumberTickUnit(100000, numberFormat));
802         units.add(new NumberTickUnit(1000000, numberFormat));
803         units.add(new NumberTickUnit(10000000, numberFormat));
804         units.add(new NumberTickUnit(100000000, numberFormat));
805         units.add(new NumberTickUnit(1000000000, numberFormat));
806         units.add(new NumberTickUnit(10000000000.0, numberFormat));
807
808         units.add(new NumberTickUnit(0.00000025, numberFormat));
809         units.add(new NumberTickUnit(0.0000025, numberFormat));
810         units.add(new NumberTickUnit(0.000025, numberFormat));
811         units.add(new NumberTickUnit(0.00025, numberFormat));
812         units.add(new NumberTickUnit(0.0025, numberFormat));
813         units.add(new NumberTickUnit(0.025, numberFormat));
814         units.add(new NumberTickUnit(0.25, numberFormat));
815         units.add(new NumberTickUnit(2.5, numberFormat));
816         units.add(new NumberTickUnit(25, numberFormat));
817         units.add(new NumberTickUnit(250, numberFormat));
818         units.add(new NumberTickUnit(2500, numberFormat));
819         units.add(new NumberTickUnit(25000, numberFormat));
820         units.add(new NumberTickUnit(250000, numberFormat));
821         units.add(new NumberTickUnit(2500000, numberFormat));
822         units.add(new NumberTickUnit(25000000, numberFormat));
823         units.add(new NumberTickUnit(250000000, numberFormat));
824         units.add(new NumberTickUnit(2500000000.0, numberFormat));
825         units.add(new NumberTickUnit(25000000000.0, numberFormat));
826
827         units.add(new NumberTickUnit(0.0000005, numberFormat));
828         units.add(new NumberTickUnit(0.000005, numberFormat));
829         units.add(new NumberTickUnit(0.00005, numberFormat));
830         units.add(new NumberTickUnit(0.0005, numberFormat));
831         units.add(new NumberTickUnit(0.005, numberFormat));
832         units.add(new NumberTickUnit(0.05, numberFormat));
833         units.add(new NumberTickUnit(0.5, numberFormat));
834         units.add(new NumberTickUnit(5L, numberFormat));
835         units.add(new NumberTickUnit(50L, numberFormat));
836         units.add(new NumberTickUnit(500L, numberFormat));
837         units.add(new NumberTickUnit(5000L, numberFormat));
838         units.add(new NumberTickUnit(50000L, numberFormat));
839         units.add(new NumberTickUnit(500000L, numberFormat));
840         units.add(new NumberTickUnit(5000000L, numberFormat));
841         units.add(new NumberTickUnit(50000000L, numberFormat));
842         units.add(new NumberTickUnit(500000000L, numberFormat));
843         units.add(new NumberTickUnit(5000000000L, numberFormat));
844         units.add(new NumberTickUnit(50000000000L, numberFormat));
845
846         return units;
847
848     }
849
850     /**
851      * Returns a collection of tick units for integer values.
852      * Uses a given Locale to create the DecimalFormats.
853      *
854      * @param locale the locale to use to represent Numbers.
855      *
856      * @return A collection of tick units for integer values.
857      */

858     public static TickUnitSource createIntegerTickUnits(Locale JavaDoc locale) {
859
860         TickUnits units = new TickUnits();
861
862         NumberFormat JavaDoc numberFormat = NumberFormat.getNumberInstance(locale);
863
864         units.add(new NumberTickUnit(1, numberFormat));
865         units.add(new NumberTickUnit(2, numberFormat));
866         units.add(new NumberTickUnit(5, numberFormat));
867         units.add(new NumberTickUnit(10, numberFormat));
868         units.add(new NumberTickUnit(20, numberFormat));
869         units.add(new NumberTickUnit(50, numberFormat));
870         units.add(new NumberTickUnit(100, numberFormat));
871         units.add(new NumberTickUnit(200, numberFormat));
872         units.add(new NumberTickUnit(500, numberFormat));
873         units.add(new NumberTickUnit(1000, numberFormat));
874         units.add(new NumberTickUnit(2000, numberFormat));
875         units.add(new NumberTickUnit(5000, numberFormat));
876         units.add(new NumberTickUnit(10000, numberFormat));
877         units.add(new NumberTickUnit(20000, numberFormat));
878         units.add(new NumberTickUnit(50000, numberFormat));
879         units.add(new NumberTickUnit(100000, numberFormat));
880         units.add(new NumberTickUnit(200000, numberFormat));
881         units.add(new NumberTickUnit(500000, numberFormat));
882         units.add(new NumberTickUnit(1000000, numberFormat));
883         units.add(new NumberTickUnit(2000000, numberFormat));
884         units.add(new NumberTickUnit(5000000, numberFormat));
885         units.add(new NumberTickUnit(10000000, numberFormat));
886         units.add(new NumberTickUnit(20000000, numberFormat));
887         units.add(new NumberTickUnit(50000000, numberFormat));
888         units.add(new NumberTickUnit(100000000, numberFormat));
889         units.add(new NumberTickUnit(200000000, numberFormat));
890         units.add(new NumberTickUnit(500000000, numberFormat));
891         units.add(new NumberTickUnit(1000000000, numberFormat));
892         units.add(new NumberTickUnit(2000000000, numberFormat));
893         units.add(new NumberTickUnit(5000000000.0, numberFormat));
894         units.add(new NumberTickUnit(10000000000.0, numberFormat));
895
896         return units;
897
898     }
899
900     /**
901      * Estimates the maximum tick label height.
902      *
903      * @param g2 the graphics device.
904      *
905      * @return The maximum height.
906      */

907     protected double estimateMaximumTickLabelHeight(Graphics2D JavaDoc g2) {
908
909         RectangleInsets tickLabelInsets = getTickLabelInsets();
910         double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom();
911         
912         Font JavaDoc tickLabelFont = getTickLabelFont();
913         FontRenderContext JavaDoc frc = g2.getFontRenderContext();
914         result += tickLabelFont.getLineMetrics("123", frc).getHeight();
915         return result;
916         
917     }
918
919     /**
920      * Estimates the maximum width of the tick labels, assuming the specified
921      * tick unit is used.
922      * <P>
923      * Rather than computing the string bounds of every tick on the axis, we
924      * just look at two values: the lower bound and the upper bound for the
925      * axis. These two values will usually be representative.
926      *
927      * @param g2 the graphics device.
928      * @param unit the tick unit to use for calculation.
929      *
930      * @return The estimated maximum width of the tick labels.
931      */

932     protected double estimateMaximumTickLabelWidth(Graphics2D JavaDoc g2,
933                                                    TickUnit unit) {
934
935         RectangleInsets tickLabelInsets = getTickLabelInsets();
936         double result = tickLabelInsets.getLeft() + tickLabelInsets.getRight();
937
938         if (isVerticalTickLabels()) {
939             // all tick labels have the same width (equal to the height of the
940
// font)...
941
FontRenderContext JavaDoc frc = g2.getFontRenderContext();
942             LineMetrics JavaDoc lm = getTickLabelFont().getLineMetrics("0", frc);
943             result += lm.getHeight();
944         }
945         else {
946             // look at lower and upper bounds...
947
FontMetrics JavaDoc fm = g2.getFontMetrics(getTickLabelFont());
948             Range range = getRange();
949             double lower = range.getLowerBound();
950             double upper = range.getUpperBound();
951             String JavaDoc lowerStr = unit.valueToString(lower);
952             String JavaDoc upperStr = unit.valueToString(upper);
953             double w1 = fm.stringWidth(lowerStr);
954             double w2 = fm.stringWidth(upperStr);
955             result += Math.max(w1, w2);
956         }
957
958         return result;
959
960     }
961     
962     /**
963      * Selects an appropriate tick value for the axis. The strategy is to
964      * display as many ticks as possible (selected from an array of 'standard'
965      * tick units) without the labels overlapping.
966      *
967      * @param g2 the graphics device.
968      * @param dataArea the area defined by the axes.
969      * @param edge the axis location.
970      */

971     protected void selectAutoTickUnit(Graphics2D JavaDoc g2,
972                                       Rectangle2D JavaDoc dataArea,
973                                       RectangleEdge edge) {
974
975         if (RectangleEdge.isTopOrBottom(edge)) {
976             selectHorizontalAutoTickUnit(g2, dataArea, edge);
977         }
978         else if (RectangleEdge.isLeftOrRight(edge)) {
979             selectVerticalAutoTickUnit(g2, dataArea, edge);
980         }
981
982     }
983
984     /**
985      * Selects an appropriate tick value for the axis. The strategy is to
986      * display as many ticks as possible (selected from an array of 'standard'
987      * tick units) without the labels overlapping.
988      *
989      * @param g2 the graphics device.
990      * @param dataArea the area defined by the axes.
991      * @param edge the axis location.
992      */

993    protected void selectHorizontalAutoTickUnit(Graphics2D JavaDoc g2,
994                                                Rectangle2D JavaDoc dataArea,
995                                                RectangleEdge edge) {
996
997         double tickLabelWidth = estimateMaximumTickLabelWidth(
998             g2, getTickUnit()
999         );
1000
1001        // start with the current tick unit...
1002
TickUnitSource tickUnits = getStandardTickUnits();
1003        TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1004        double unit1Width = lengthToJava2D(unit1.getSize(), dataArea, edge);
1005
1006        // then extrapolate...
1007
double guess = (tickLabelWidth / unit1Width) * unit1.getSize();
1008
1009        NumberTickUnit unit2
1010            = (NumberTickUnit) tickUnits.getCeilingTickUnit(guess);
1011        double unit2Width = lengthToJava2D(unit2.getSize(), dataArea, edge);
1012
1013        tickLabelWidth = estimateMaximumTickLabelWidth(g2, unit2);
1014        if (tickLabelWidth > unit2Width) {
1015            unit2 = (NumberTickUnit) tickUnits.getLargerTickUnit(unit2);
1016        }
1017
1018        setTickUnit(unit2, false, false);
1019
1020    }
1021
1022    /**
1023     * Selects an appropriate tick value for the axis. The strategy is to
1024     * display as many ticks as possible (selected from an array of 'standard'
1025     * tick units) without the labels overlapping.
1026     *
1027     * @param g2 the graphics device.
1028     * @param dataArea the area in which the plot should be drawn.
1029     * @param edge the axis location.
1030     */

1031    protected void selectVerticalAutoTickUnit(Graphics2D JavaDoc g2,
1032                                              Rectangle2D JavaDoc dataArea,
1033                                              RectangleEdge edge) {
1034
1035        double tickLabelHeight = estimateMaximumTickLabelHeight(g2);
1036
1037        // start with the current tick unit...
1038
TickUnitSource tickUnits = getStandardTickUnits();
1039        TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
1040        double unitHeight = lengthToJava2D(unit1.getSize(), dataArea, edge);
1041
1042        // then extrapolate...
1043
double guess = (tickLabelHeight / unitHeight) * unit1.getSize();
1044        
1045        NumberTickUnit unit2
1046            = (NumberTickUnit) tickUnits.getCeilingTickUnit(guess);
1047        double unit2Height = lengthToJava2D(unit2.getSize(), dataArea, edge);
1048
1049        tickLabelHeight = estimateMaximumTickLabelHeight(g2);
1050        if (tickLabelHeight > unit2Height) {
1051            unit2 = (NumberTickUnit) tickUnits.getLargerTickUnit(unit2);
1052        }
1053
1054        setTickUnit(unit2, false, false);
1055
1056    }
1057    
1058    /**
1059     * Calculates the positions of the tick labels for the axis, storing the
1060     * results in the tick label list (ready for drawing).
1061     *
1062     * @param g2 the graphics device.
1063     * @param state the axis state.
1064     * @param dataArea the area in which the plot should be drawn.
1065     * @param edge the location of the axis.
1066     *
1067     * @return A list of ticks.
1068     *
1069     */

1070    public List JavaDoc refreshTicks(Graphics2D JavaDoc g2,
1071                             AxisState state,
1072                             Rectangle2D JavaDoc dataArea,
1073                             RectangleEdge edge) {
1074
1075        List JavaDoc result = new java.util.ArrayList JavaDoc();
1076        if (RectangleEdge.isTopOrBottom(edge)) {
1077            result = refreshTicksHorizontal(g2, dataArea, edge);
1078        }
1079        else if (RectangleEdge.isLeftOrRight(edge)) {
1080            result = refreshTicksVertical(g2, dataArea, edge);
1081        }
1082        return result;
1083
1084    }
1085
1086    /**
1087     * Calculates the positions of the tick labels for the axis, storing the
1088     * results in the tick label list (ready for drawing).
1089     *
1090     * @param g2 the graphics device.
1091     * @param dataArea the area in which the data should be drawn.
1092     * @param edge the location of the axis.
1093     *
1094     * @return A list of ticks.
1095     */

1096    protected List JavaDoc refreshTicksHorizontal(Graphics2D JavaDoc g2,
1097                                          Rectangle2D JavaDoc dataArea,
1098                                          RectangleEdge edge) {
1099
1100        List JavaDoc result = new java.util.ArrayList JavaDoc();
1101
1102        Font JavaDoc tickLabelFont = getTickLabelFont();
1103        g2.setFont(tickLabelFont);
1104        
1105        if (isAutoTickUnitSelection()) {
1106            selectAutoTickUnit(g2, dataArea, edge);
1107        }
1108
1109        double size = getTickUnit().getSize();
1110        int count = calculateVisibleTickCount();
1111        double lowestTickValue = calculateLowestVisibleTickValue();
1112
1113        if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
1114            for (int i = 0; i < count; i++) {
1115                double currentTickValue = lowestTickValue + (i * size);
1116                String JavaDoc tickLabel;
1117                NumberFormat JavaDoc formatter = getNumberFormatOverride();
1118                if (formatter != null) {
1119                    tickLabel = formatter.format(currentTickValue);
1120                }
1121                else {
1122                    tickLabel = getTickUnit().valueToString(currentTickValue);
1123                }
1124                TextAnchor anchor = null;
1125                TextAnchor rotationAnchor = null;
1126                double angle = 0.0;
1127                if (isVerticalTickLabels()) {
1128                    anchor = TextAnchor.CENTER_RIGHT;
1129                    rotationAnchor = TextAnchor.CENTER_RIGHT;
1130                    if (edge == RectangleEdge.TOP) {
1131                        angle = Math.PI / 2.0;
1132                    }
1133                    else {
1134                        angle = -Math.PI / 2.0;
1135                    }
1136                }
1137                else {
1138                    if (edge == RectangleEdge.TOP) {
1139                        anchor = TextAnchor.BOTTOM_CENTER;
1140                        rotationAnchor = TextAnchor.BOTTOM_CENTER;
1141                    }
1142                    else {
1143                        anchor = TextAnchor.TOP_CENTER;
1144                        rotationAnchor = TextAnchor.TOP_CENTER;
1145                    }
1146                }
1147
1148                Tick tick = new NumberTick(
1149                    new Double JavaDoc(currentTickValue), tickLabel, anchor,
1150                    rotationAnchor, angle
1151                );
1152                result.add(tick);
1153            }
1154        }
1155        return result;
1156
1157    }
1158
1159    /**
1160     * Calculates the positions of the tick labels for the axis, storing the
1161     * results in the tick label list (ready for drawing).
1162     *
1163     * @param g2 the graphics device.
1164     * @param dataArea the area in which the plot should be drawn.
1165     * @param edge the location of the axis.
1166     *
1167     * @return A list of ticks.
1168     *
1169     */

1170    protected List JavaDoc refreshTicksVertical(Graphics2D JavaDoc g2,
1171                                        Rectangle2D JavaDoc dataArea,
1172                                        RectangleEdge edge) {
1173
1174        List JavaDoc result = new java.util.ArrayList JavaDoc();
1175        result.clear();
1176
1177        Font JavaDoc tickLabelFont = getTickLabelFont();
1178        g2.setFont(tickLabelFont);
1179        if (isAutoTickUnitSelection()) {
1180            selectAutoTickUnit(g2, dataArea, edge);
1181        }
1182
1183        double size = getTickUnit().getSize();
1184        int count = calculateVisibleTickCount();
1185        double lowestTickValue = calculateLowestVisibleTickValue();
1186
1187        if (count <= ValueAxis.MAXIMUM_TICK_COUNT) {
1188            for (int i = 0; i < count; i++) {
1189                double currentTickValue = lowestTickValue + (i * size);
1190                String JavaDoc tickLabel;
1191                NumberFormat JavaDoc formatter = getNumberFormatOverride();
1192                if (formatter != null) {
1193                    tickLabel = formatter.format(currentTickValue);
1194                }
1195                else {
1196                    tickLabel = getTickUnit().valueToString(currentTickValue);
1197                }
1198
1199                TextAnchor anchor = null;
1200                TextAnchor rotationAnchor = null;
1201                double angle = 0.0;
1202                if (isVerticalTickLabels()) {
1203                    if (edge == RectangleEdge.LEFT) {
1204                        anchor = TextAnchor.BOTTOM_CENTER;
1205                        rotationAnchor = TextAnchor.BOTTOM_CENTER;
1206                        angle = -Math.PI / 2.0;
1207                    }
1208                    else {
1209                        anchor = TextAnchor.BOTTOM_CENTER;
1210                        rotationAnchor = TextAnchor.BOTTOM_CENTER;
1211                        angle = Math.PI / 2.0;
1212                    }
1213                }
1214                else {
1215                    if (edge == RectangleEdge.LEFT) {
1216                        anchor = TextAnchor.CENTER_RIGHT;
1217                        rotationAnchor = TextAnchor.CENTER_RIGHT;
1218                    }
1219                    else {
1220                        anchor = TextAnchor.CENTER_LEFT;
1221                        rotationAnchor = TextAnchor.CENTER_LEFT;
1222                    }
1223                }
1224
1225                Tick tick = new NumberTick(
1226                    new Double JavaDoc(currentTickValue), tickLabel, anchor,
1227                    rotationAnchor, angle
1228                );
1229                result.add(tick);
1230            }
1231        }
1232        return result;
1233
1234    }
1235    
1236    /**
1237     * Returns a clone of the axis.
1238     *
1239     * @return A clone
1240     *
1241     * @throws CloneNotSupportedException if some component of the axis does
1242     * not support cloning.
1243     */

1244    public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
1245        NumberAxis clone = (NumberAxis) super.clone();
1246        if (this.numberFormatOverride != null) {
1247            clone.numberFormatOverride
1248                = (NumberFormat JavaDoc) this.numberFormatOverride.clone();
1249        }
1250        return clone;
1251    }
1252
1253    /**
1254     * Tests an object for equality with this instance.
1255     *
1256     * @param obj the object.
1257     *
1258     * @return A boolean.
1259     */

1260    public boolean equals(Object JavaDoc obj) {
1261        if (obj == this) {
1262            return true;
1263        }
1264        if (!(obj instanceof NumberAxis)) {
1265            return false;
1266        }
1267        if (!super.equals(obj)) {
1268            return false;
1269        }
1270        NumberAxis that = (NumberAxis) obj;
1271        if (this.autoRangeIncludesZero != that.autoRangeIncludesZero) {
1272            return false;
1273        }
1274        if (this.autoRangeStickyZero != that.autoRangeStickyZero) {
1275            return false;
1276        }
1277        if (!ObjectUtilities.equal(this.tickUnit, that.tickUnit)) {
1278            return false;
1279        }
1280        if (!ObjectUtilities.equal(this.numberFormatOverride,
1281                that.numberFormatOverride)) {
1282            return false;
1283        }
1284        return true;
1285    }
1286    
1287    /**
1288     * Returns a hash code for this object.
1289     *
1290     * @return A hash code.
1291     */

1292    public int hashCode() {
1293        if (getLabel() != null) {
1294            return getLabel().hashCode();
1295        }
1296        else {
1297            return 0;
1298        }
1299    }
1300
1301}
1302
Popular Tags