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 * StandardDialScale.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 * Changes 036 * ------- 037 * 03-Nov-2006 : Version 1 (DG); 038 * 17-Nov-2006 : Added flags for tick label visibility (DG); 039 * 24-Oct-2007 : Added tick label formatter (DG); 040 * 041 */ 042 043package org.jfree.chart.plot.dial; 044 045import java.awt.BasicStroke; 046import java.awt.Color; 047import java.awt.Font; 048import java.awt.Graphics2D; 049import java.awt.Paint; 050import java.awt.Stroke; 051import java.awt.geom.Arc2D; 052import java.awt.geom.Line2D; 053import java.awt.geom.Point2D; 054import java.awt.geom.Rectangle2D; 055import java.io.IOException; 056import java.io.ObjectInputStream; 057import java.io.ObjectOutputStream; 058import java.io.Serializable; 059import java.text.DecimalFormat; 060import java.text.NumberFormat; 061 062import org.jfree.io.SerialUtilities; 063import org.jfree.text.TextUtilities; 064import org.jfree.ui.TextAnchor; 065import org.jfree.util.PaintUtilities; 066import org.jfree.util.PublicCloneable; 067 068/** 069 * A scale for a {@link DialPlot}. 070 */ 071public class StandardDialScale extends AbstractDialLayer implements DialScale, 072 Cloneable, PublicCloneable, Serializable { 073 074 /** For serialization. */ 075 static final long serialVersionUID = 3715644629665918516L; 076 077 /** The minimum data value for the scale. */ 078 private double lowerBound; 079 080 /** The maximum data value for the scale. */ 081 private double upperBound; 082 083 /** 084 * The start angle for the scale display, in degrees (using the same 085 * encoding as Arc2D). 086 */ 087 private double startAngle; 088 089 /** The extent of the scale display. */ 090 private double extent; 091 092 /** 093 * The factor (in the range 0.0 to 1.0) that determines the outside limit 094 * of the tick marks. 095 */ 096 private double tickRadius; 097 098 /** 099 * The increment (in data units) between major tick marks. 100 */ 101 private double majorTickIncrement; 102 103 /** 104 * The factor that is subtracted from the tickRadius to determine the 105 * inner point of the major ticks. 106 */ 107 private double majorTickLength; 108 109 /** 110 * The paint to use for major tick marks. This field is transient because 111 * it requires special handling for serialization. 112 */ 113 private transient Paint majorTickPaint; 114 115 /** 116 * The stroke to use for major tick marks. This field is transient because 117 * it requires special handling for serialization. 118 */ 119 private transient Stroke majorTickStroke; 120 121 /** 122 * The number of minor ticks between each major tick. 123 */ 124 private int minorTickCount; 125 126 /** 127 * The factor that is subtracted from the tickRadius to determine the 128 * inner point of the minor ticks. 129 */ 130 private double minorTickLength; 131 132 /** 133 * The paint to use for minor tick marks. This field is transient because 134 * it requires special handling for serialization. 135 */ 136 private transient Paint minorTickPaint; 137 138 /** 139 * The stroke to use for minor tick marks. This field is transient because 140 * it requires special handling for serialization. 141 */ 142 private transient Stroke minorTickStroke; 143 144 /** 145 * The tick label offset. 146 */ 147 private double tickLabelOffset; 148 149 /** 150 * The tick label font. 151 */ 152 private Font tickLabelFont; 153 154 /** 155 * A flag that controls whether or not the tick labels are 156 * displayed. 157 */ 158 private boolean tickLabelsVisible; 159 160 /** 161 * The number formatter for the tick labels. 162 */ 163 private NumberFormat tickLabelFormatter; 164 165 /** 166 * A flag that controls whether or not the first tick label is 167 * displayed. 168 */ 169 private boolean firstTickLabelVisible; 170 171 /** 172 * The tick label paint. This field is transient because it requires 173 * special handling for serialization. 174 */ 175 private transient Paint tickLabelPaint; 176 177 /** 178 * Creates a new instance of DialScale. 179 */ 180 public StandardDialScale() { 181 this(0.0, 100.0, 175, -170, 10.0, 4); 182 } 183 184 /** 185 * Creates a new instance. 186 * 187 * @param lowerBound the lower bound of the scale. 188 * @param upperBound the upper bound of the scale. 189 * @param startAngle the start angle (in degrees, using the same 190 * orientation as Java's <code>Arc2D</code> class). 191 * @param extent the extent (in degrees, counter-clockwise). 192 * @param majorTickIncrement the interval between major tick marks 193 * @param minorTickCount the number of minor ticks between major tick 194 * marks. 195 */ 196 public StandardDialScale(double lowerBound, double upperBound, 197 double startAngle, double extent, double majorTickIncrement, 198 int minorTickCount) { 199 this.startAngle = startAngle; 200 this.extent = extent; 201 this.lowerBound = lowerBound; 202 this.upperBound = upperBound; 203 this.tickRadius = 0.70; 204 this.tickLabelsVisible = true; 205 this.tickLabelFormatter = new DecimalFormat("0.0"); 206 this.firstTickLabelVisible = true; 207 this.tickLabelFont = new Font("Dialog", Font.BOLD, 16); 208 this.tickLabelPaint = Color.blue; 209 this.tickLabelOffset = 0.10; 210 this.majorTickIncrement = majorTickIncrement; 211 this.majorTickLength = 0.04; 212 this.majorTickPaint = Color.black; 213 this.majorTickStroke = new BasicStroke(3.0f); 214 this.minorTickCount = minorTickCount; 215 this.minorTickLength = 0.02; 216 this.minorTickPaint = Color.black; 217 this.minorTickStroke = new BasicStroke(1.0f); 218 } 219 220 /** 221 * Returns the start angle for the scale (in degrees using the same 222 * orientation as Java's <code>Arc2D</code> class). 223 * 224 * @return The start angle. 225 * 226 * @see #setStartAngle(double) 227 */ 228 public double getStartAngle() { 229 return this.startAngle; 230 } 231 232 /** 233 * Sets the start angle for the scale and sends a 234 * {@link DialLayerChangeEvent} to all registered listeners. 235 * 236 * @param angle the angle (in degrees). 237 * 238 * @see #getStartAngle() 239 */ 240 public void setStartAngle(double angle) { 241 this.startAngle = angle; 242 notifyListeners(new DialLayerChangeEvent(this)); 243 } 244 245 /** 246 * Returns the extent. 247 * 248 * @return The extent. 249 * 250 * @see #setExtent(double) 251 */ 252 public double getExtent() { 253 return this.extent; 254 } 255 256 /** 257 * Sets the extent and sends a {@link DialLayerChangeEvent} to all 258 * registered listeners. 259 * 260 * @param extent the extent. 261 * 262 * @see #getExtent() 263 */ 264 public void setExtent(double extent) { 265 this.extent = extent; 266 notifyListeners(new DialLayerChangeEvent(this)); 267 } 268 269 /** 270 * Returns the radius (as a percentage of the maximum space available) of 271 * the outer limit of the tick marks. 272 * 273 * @return The tick radius. 274 * 275 * @see #setTickRadius(double) 276 */ 277 public double getTickRadius() { 278 return this.tickRadius; 279 } 280 281 /** 282 * Sets the tick radius and sends a {@link DialLayerChangeEvent} to all 283 * registered listeners. 284 * 285 * @param radius the radius. 286 * 287 * @see #getTickRadius() 288 */ 289 public void setTickRadius(double radius) { 290 if (radius <= 0.0) { 291 throw new IllegalArgumentException( 292 "The 'radius' must be positive."); 293 } 294 this.tickRadius = radius; 295 notifyListeners(new DialLayerChangeEvent(this)); 296 } 297 298 /** 299 * Returns the increment (in data units) between major tick labels. 300 * 301 * @return The increment between major tick labels. 302 * 303 * @see #setMajorTickIncrement(double) 304 */ 305 public double getMajorTickIncrement() { 306 return this.majorTickIncrement; 307 } 308 309 /** 310 * Sets the increment (in data units) between major tick labels and sends a 311 * {@link DialLayerChangeEvent} to all registered listeners. 312 * 313 * @param increment the increment. 314 * 315 * @see #getMajorTickIncrement() 316 */ 317 public void setMajorTickIncrement(double increment) { 318 if (increment <= 0.0) { 319 throw new IllegalArgumentException( 320 "The 'increment' must be positive."); 321 } 322 this.majorTickIncrement = increment; 323 notifyListeners(new DialLayerChangeEvent(this)); 324 } 325 326 /** 327 * Returns the length factor for the major tick marks. The value is 328 * subtracted from the tick radius to determine the inner starting point 329 * for the tick marks. 330 * 331 * @return The length factor. 332 * 333 * @see #setMajorTickLength(double) 334 */ 335 public double getMajorTickLength() { 336 return this.majorTickLength; 337 } 338 339 /** 340 * Sets the length factor for the major tick marks and sends a 341 * {@link DialLayerChangeEvent} to all registered listeners. 342 * 343 * @param length the length. 344 * 345 * @see #getMajorTickLength() 346 */ 347 public void setMajorTickLength(double length) { 348 if (length < 0.0) { 349 throw new IllegalArgumentException("Negative 'length' argument."); 350 } 351 this.majorTickLength = length; 352 notifyListeners(new DialLayerChangeEvent(this)); 353 } 354 355 /** 356 * Returns the major tick paint. 357 * 358 * @return The major tick paint (never <code>null</code>). 359 * 360 * @see #setMajorTickPaint(Paint) 361 */ 362 public Paint getMajorTickPaint() { 363 return this.majorTickPaint; 364 } 365 366 /** 367 * Sets the major tick paint and sends a {@link DialLayerChangeEvent} to 368 * all registered listeners. 369 * 370 * @param paint the paint (<code>null</code> not permitted). 371 * 372 * @see #getMajorTickPaint() 373 */ 374 public void setMajorTickPaint(Paint paint) { 375 if (paint == null) { 376 throw new IllegalArgumentException("Null 'paint' argument."); 377 } 378 this.majorTickPaint = paint; 379 notifyListeners(new DialLayerChangeEvent(this)); 380 } 381 382 /** 383 * Returns the stroke used to draw the major tick marks. 384 * 385 * @return The stroke (never <code>null</code>). 386 * 387 * @see #setMajorTickStroke(Stroke) 388 */ 389 public Stroke getMajorTickStroke() { 390 return this.majorTickStroke; 391 } 392 393 /** 394 * Sets the stroke used to draw the major tick marks and sends a 395 * {@link DialLayerChangeEvent} to all registered listeners. 396 * 397 * @param stroke the stroke (<code>null</code> not permitted). 398 * 399 * @see #getMajorTickStroke() 400 */ 401 public void setMajorTickStroke(Stroke stroke) { 402 if (stroke == null) { 403 throw new IllegalArgumentException("Null 'stroke' argument."); 404 } 405 this.majorTickStroke = stroke; 406 notifyListeners(new DialLayerChangeEvent(this)); 407 } 408 409 /** 410 * Returns the number of minor tick marks between major tick marks. 411 * 412 * @return The number of minor tick marks between major tick marks. 413 * 414 * @see #setMinorTickCount(int) 415 */ 416 public int getMinorTickCount() { 417 return this.minorTickCount; 418 } 419 420 /** 421 * Sets the number of minor tick marks between major tick marks and sends 422 * a {@link DialLayerChangeEvent} to all registered listeners. 423 * 424 * @param count the count. 425 * 426 * @see #getMinorTickCount() 427 */ 428 public void setMinorTickCount(int count) { 429 if (count < 0) { 430 throw new IllegalArgumentException( 431 "The 'count' cannot be negative."); 432 } 433 this.minorTickCount = count; 434 notifyListeners(new DialLayerChangeEvent(this)); 435 } 436 437 /** 438 * Returns the length factor for the minor tick marks. The value is 439 * subtracted from the tick radius to determine the inner starting point 440 * for the tick marks. 441 * 442 * @return The length factor. 443 * 444 * @see #setMinorTickLength(double) 445 */ 446 public double getMinorTickLength() { 447 return this.minorTickLength; 448 } 449 450 /** 451 * Sets the length factor for the minor tick marks and sends 452 * a {@link DialLayerChangeEvent} to all registered listeners. 453 * 454 * @param length the length. 455 * 456 * @see #getMinorTickLength() 457 */ 458 public void setMinorTickLength(double length) { 459 if (length < 0.0) { 460 throw new IllegalArgumentException("Negative 'length' argument."); 461 } 462 this.minorTickLength = length; 463 notifyListeners(new DialLayerChangeEvent(this)); 464 } 465 466 /** 467 * Returns the paint used to draw the minor tick marks. 468 * 469 * @return The paint (never <code>null</code>). 470 * 471 * @see #setMinorTickPaint(Paint) 472 */ 473 public Paint getMinorTickPaint() { 474 return this.minorTickPaint; 475 } 476 477 /** 478 * Sets the paint used to draw the minor tick marks and sends a 479 * {@link DialLayerChangeEvent} to all registered listeners. 480 * 481 * @param paint the paint (<code>null</code> not permitted). 482 * 483 * @see #getMinorTickPaint() 484 */ 485 public void setMinorTickPaint(Paint paint) { 486 if (paint == null) { 487 throw new IllegalArgumentException("Null 'paint' argument."); 488 } 489 this.minorTickPaint = paint; 490 notifyListeners(new DialLayerChangeEvent(this)); 491 } 492 493 /** 494 * Returns the tick label offset. 495 * 496 * @return The tick label offset. 497 * 498 * @see #setTickLabelOffset(double) 499 */ 500 public double getTickLabelOffset() { 501 return this.tickLabelOffset; 502 } 503 504 /** 505 * Sets the tick label offset and sends a {@link DialLayerChangeEvent} to 506 * all registered listeners. 507 * 508 * @param offset the offset. 509 * 510 * @see #getTickLabelOffset() 511 */ 512 public void setTickLabelOffset(double offset) { 513 this.tickLabelOffset = offset; 514 notifyListeners(new DialLayerChangeEvent(this)); 515 } 516 517 /** 518 * Returns the font used to draw the tick labels. 519 * 520 * @return The font (never <code>null</code>). 521 * 522 * @see #setTickLabelFont(Font) 523 */ 524 public Font getTickLabelFont() { 525 return this.tickLabelFont; 526 } 527 528 /** 529 * Sets the font used to display the tick labels and sends a 530 * {@link DialLayerChangeEvent} to all registered listeners. 531 * 532 * @param font the font (<code>null</code> not permitted). 533 * 534 * @see #getTickLabelFont() 535 */ 536 public void setTickLabelFont(Font font) { 537 if (font == null) { 538 throw new IllegalArgumentException("Null 'font' argument."); 539 } 540 this.tickLabelFont = font; 541 notifyListeners(new DialLayerChangeEvent(this)); 542 } 543 544 /** 545 * Returns the paint used to draw the tick labels. 546 * 547 * @return The paint (<code>null</code> not permitted). 548 * 549 * @see #setTickLabelPaint(Paint) 550 */ 551 public Paint getTickLabelPaint() { 552 return this.tickLabelPaint; 553 } 554 555 /** 556 * Sets the paint used to draw the tick labels and sends a 557 * {@link DialLayerChangeEvent} to all registered listeners. 558 * 559 * @param paint the paint (<code>null</code> not permitted). 560 */ 561 public void setTickLabelPaint(Paint paint) { 562 if (paint == null) { 563 throw new IllegalArgumentException("Null 'paint' argument."); 564 } 565 this.tickLabelPaint = paint; 566 notifyListeners(new DialLayerChangeEvent(this)); 567 } 568 569 /** 570 * Returns <code>true</code> if the tick labels should be displayed, 571 * and <code>false</code> otherwise. 572 * 573 * @return A boolean. 574 * 575 * @see #setTickLabelsVisible(boolean) 576 */ 577 public boolean getTickLabelsVisible() { 578 return this.tickLabelsVisible; 579 } 580 581 /** 582 * Sets the flag that controls whether or not the tick labels are 583 * displayed, and sends a {@link DialLayerChangeEvent} to all registered 584 * listeners. 585 * 586 * @param visible the new flag value. 587 * 588 * @see #getTickLabelsVisible() 589 */ 590 public void setTickLabelsVisible(boolean visible) { 591 this.tickLabelsVisible = visible; 592 notifyListeners(new DialLayerChangeEvent(this)); 593 } 594 595 /** 596 * Returns the number formatter used to convert the tick label values to 597 * strings. 598 * 599 * @return The formatter (never <code>null</code>). 600 * 601 * @see #setTickLabelFormatter(NumberFormat) 602 */ 603 public NumberFormat getTickLabelFormatter() { 604 return this.tickLabelFormatter; 605 } 606 607 /** 608 * Sets the number formatter used to convert the tick label values to 609 * strings, and sends a {@link DialLayerChangeEvent} to all registered 610 * listeners. 611 * 612 * @param formatter the formatter (<code>null</code> not permitted). 613 * 614 * @see #getTickLabelFormatter() 615 */ 616 public void setTickLabelFormatter(NumberFormat formatter) { 617 if (formatter == null) { 618 throw new IllegalArgumentException("Null 'formatter' argument."); 619 } 620 this.tickLabelFormatter = formatter; 621 notifyListeners(new DialLayerChangeEvent(this)); 622 } 623 624 /** 625 * Returns a flag that controls whether or not the first tick label is 626 * visible. 627 * 628 * @return A boolean. 629 * 630 * @see #setFirstTickLabelVisible(boolean) 631 */ 632 public boolean getFirstTickLabelVisible() { 633 return this.firstTickLabelVisible; 634 } 635 636 /** 637 * Sets a flag that controls whether or not the first tick label is 638 * visible, and sends a {@link DialLayerChangeEvent} to all registered 639 * listeners. 640 * 641 * @param visible the new flag value. 642 * 643 * @see #getFirstTickLabelVisible() 644 */ 645 public void setFirstTickLabelVisible(boolean visible) { 646 this.firstTickLabelVisible = visible; 647 notifyListeners(new DialLayerChangeEvent(this)); 648 } 649 650 /** 651 * Returns <code>true</code> to indicate that this layer should be 652 * clipped within the dial window. 653 * 654 * @return <code>true</code>. 655 */ 656 public boolean isClippedToWindow() { 657 return true; 658 } 659 660 /** 661 * Draws the scale on the dial plot. 662 * 663 * @param g2 the graphics target (<code>null</code> not permitted). 664 * @param plot the dial plot (<code>null</code> not permitted). 665 * @param frame the reference frame that is used to construct the 666 * geometry of the plot (<code>null</code> not permitted). 667 * @param view the visible part of the plot (<code>null</code> not 668 * permitted). 669 */ 670 public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, 671 Rectangle2D view) { 672 673 Rectangle2D arcRect = DialPlot.rectangleByRadius(frame, 674 this.tickRadius, this.tickRadius); 675 Rectangle2D arcRectMajor = DialPlot.rectangleByRadius(frame, 676 this.tickRadius - this.majorTickLength, 677 this.tickRadius - this.majorTickLength); 678 Rectangle2D arcRectMinor = arcRect; 679 if (this.minorTickCount > 0 && this.minorTickLength > 0.0) { 680 arcRectMinor = DialPlot.rectangleByRadius(frame, 681 this.tickRadius - this.minorTickLength, 682 this.tickRadius - this.minorTickLength); 683 } 684 Rectangle2D arcRectForLabels = DialPlot.rectangleByRadius(frame, 685 this.tickRadius - this.tickLabelOffset, 686 this.tickRadius - this.tickLabelOffset); 687 688 boolean firstLabel = true; 689 690 Arc2D arc = new Arc2D.Double(); 691 Line2D workingLine = new Line2D.Double(); 692 for (double v = this.lowerBound; v <= this.upperBound; 693 v += this.majorTickIncrement) { 694 arc.setArc(arcRect, this.startAngle, valueToAngle(v) 695 - this.startAngle, Arc2D.OPEN); 696 Point2D pt0 = arc.getEndPoint(); 697 arc.setArc(arcRectMajor, this.startAngle, valueToAngle(v) 698 - this.startAngle, Arc2D.OPEN); 699 Point2D pt1 = arc.getEndPoint(); 700 g2.setPaint(this.majorTickPaint); 701 g2.setStroke(this.majorTickStroke); 702 workingLine.setLine(pt0, pt1); 703 g2.draw(workingLine); 704 arc.setArc(arcRectForLabels, this.startAngle, valueToAngle(v) 705 - this.startAngle, Arc2D.OPEN); 706 Point2D pt2 = arc.getEndPoint(); 707 708 if (this.tickLabelsVisible) { 709 if (!firstLabel || this.firstTickLabelVisible) { 710 g2.setFont(this.tickLabelFont); 711 TextUtilities.drawAlignedString( 712 this.tickLabelFormatter.format(v), g2, 713 (float) pt2.getX(), (float) pt2.getY(), 714 TextAnchor.CENTER); 715 } 716 } 717 firstLabel = false; 718 719 // now do the minor tick marks 720 if (this.minorTickCount > 0 && this.minorTickLength > 0.0) { 721 double minorTickIncrement = this.majorTickIncrement 722 / (this.minorTickCount + 1); 723 for (int i = 0; i < this.minorTickCount; i++) { 724 double vv = v + ((i + 1) * minorTickIncrement); 725 if (vv >= this.upperBound) { 726 break; 727 } 728 double angle = valueToAngle(vv); 729 730 arc.setArc(arcRect, this.startAngle, angle 731 - this.startAngle, Arc2D.OPEN); 732 pt0 = arc.getEndPoint(); 733 arc.setArc(arcRectMinor, this.startAngle, angle 734 - this.startAngle, Arc2D.OPEN); 735 Point2D pt3 = arc.getEndPoint(); 736 g2.setStroke(this.minorTickStroke); 737 g2.setPaint(this.minorTickPaint); 738 workingLine.setLine(pt0, pt3); 739 g2.draw(workingLine); 740 } 741 } 742 743 } 744 } 745 746 /** 747 * Converts a data value to an angle against this scale. 748 * 749 * @param value the data value. 750 * 751 * @return The angle (in degrees, using the same specification as Java's 752 * Arc2D class). 753 * 754 * @see #angleToValue(double) 755 */ 756 public double valueToAngle(double value) { 757 double range = this.upperBound - this.lowerBound; 758 double unit = this.extent / range; 759 return this.startAngle + unit * (value - this.lowerBound); 760 } 761 762 /** 763 * Converts the given angle to a data value, based on this scale. 764 * 765 * @param angle the angle. 766 * 767 * @return The data value. 768 * 769 * @see #valueToAngle(double) 770 */ 771 public double angleToValue(double angle) { 772 return Double.NaN; // FIXME 773 } 774 775 /** 776 * Tests this <code>StandardDialScale</code> for equality with an arbitrary 777 * object. 778 * 779 * @param obj the object (<code>null</code> permitted). 780 * 781 * @return A boolean. 782 */ 783 public boolean equals(Object obj) { 784 if (obj == this) { 785 return true; 786 } 787 if (!(obj instanceof StandardDialScale)) { 788 return false; 789 } 790 StandardDialScale that = (StandardDialScale) obj; 791 if (this.lowerBound != that.lowerBound) { 792 return false; 793 } 794 if (this.upperBound != that.upperBound) { 795 return false; 796 } 797 if (this.startAngle != that.startAngle) { 798 return false; 799 } 800 if (this.extent != that.extent) { 801 return false; 802 } 803 if (this.tickRadius != that.tickRadius) { 804 return false; 805 } 806 if (this.majorTickIncrement != that.majorTickIncrement) { 807 return false; 808 } 809 if (this.majorTickLength != that.majorTickLength) { 810 return false; 811 } 812 if (!PaintUtilities.equal(this.majorTickPaint, that.majorTickPaint)) { 813 return false; 814 } 815 if (!this.majorTickStroke.equals(that.majorTickStroke)) { 816 return false; 817 } 818 if (this.minorTickCount != that.minorTickCount) { 819 return false; 820 } 821 if (this.minorTickLength != that.minorTickLength) { 822 return false; 823 } 824 if (!PaintUtilities.equal(this.minorTickPaint, that.minorTickPaint)) { 825 return false; 826 } 827 if (!this.minorTickStroke.equals(that.minorTickStroke)) { 828 return false; 829 } 830 if (this.tickLabelsVisible != that.tickLabelsVisible) { 831 return false; 832 } 833 if (this.tickLabelOffset != that.tickLabelOffset) { 834 return false; 835 } 836 if (!this.tickLabelFont.equals(that.tickLabelFont)) { 837 return false; 838 } 839 if (!PaintUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) { 840 return false; 841 } 842 return super.equals(obj); 843 } 844 845 /** 846 * Returns a hash code for this instance. 847 * 848 * @return A hash code. 849 */ 850 public int hashCode() { 851 int result = 193; 852 // lowerBound 853 long temp = Double.doubleToLongBits(this.lowerBound); 854 result = 37 * result + (int) (temp ^ (temp >>> 32)); 855 // upperBound 856 temp = Double.doubleToLongBits(this.upperBound); 857 result = 37 * result + (int) (temp ^ (temp >>> 32)); 858 // startAngle 859 temp = Double.doubleToLongBits(this.startAngle); 860 result = 37 * result + (int) (temp ^ (temp >>> 32)); 861 // extent 862 temp = Double.doubleToLongBits(this.extent); 863 result = 37 * result + (int) (temp ^ (temp >>> 32)); 864 // tickRadius 865 temp = Double.doubleToLongBits(this.tickRadius); 866 result = 37 * result + (int) (temp ^ (temp >>> 32)); 867 // majorTickIncrement 868 // majorTickLength 869 // majorTickPaint 870 // majorTickStroke 871 // minorTickCount 872 // minorTickLength 873 // minorTickPaint 874 // minorTickStroke 875 // tickLabelOffset 876 // tickLabelFont 877 // tickLabelsVisible 878 // tickLabelFormatter 879 // firstTickLabelsVisible 880 return result; 881 } 882 883 /** 884 * Returns a clone of this instance. 885 * 886 * @return A clone. 887 * 888 * @throws CloneNotSupportedException if this instance is not cloneable. 889 */ 890 public Object clone() throws CloneNotSupportedException { 891 return super.clone(); 892 } 893 894 /** 895 * Provides serialization support. 896 * 897 * @param stream the output stream. 898 * 899 * @throws IOException if there is an I/O error. 900 */ 901 private void writeObject(ObjectOutputStream stream) throws IOException { 902 stream.defaultWriteObject(); 903 SerialUtilities.writePaint(this.majorTickPaint, stream); 904 SerialUtilities.writeStroke(this.majorTickStroke, stream); 905 SerialUtilities.writePaint(this.minorTickPaint, stream); 906 SerialUtilities.writeStroke(this.minorTickStroke, stream); 907 SerialUtilities.writePaint(this.tickLabelPaint, stream); 908 } 909 910 /** 911 * Provides serialization support. 912 * 913 * @param stream the input stream. 914 * 915 * @throws IOException if there is an I/O error. 916 * @throws ClassNotFoundException if there is a classpath problem. 917 */ 918 private void readObject(ObjectInputStream stream) 919 throws IOException, ClassNotFoundException { 920 stream.defaultReadObject(); 921 this.majorTickPaint = SerialUtilities.readPaint(stream); 922 this.majorTickStroke = SerialUtilities.readStroke(stream); 923 this.minorTickPaint = SerialUtilities.readPaint(stream); 924 this.minorTickStroke = SerialUtilities.readStroke(stream); 925 this.tickLabelPaint = SerialUtilities.readPaint(stream); 926 } 927 928}