1 48 49 package org.jfree.chart.axis; 50 51 import java.awt.BasicStroke ; 52 import java.awt.Color ; 53 import java.awt.Font ; 54 import java.awt.FontMetrics ; 55 import java.awt.Graphics2D ; 56 import java.awt.Paint ; 57 import java.awt.Stroke ; 58 import java.awt.geom.Line2D ; 59 import java.awt.geom.Rectangle2D ; 60 import java.io.IOException ; 61 import java.io.ObjectInputStream ; 62 import java.io.ObjectOutputStream ; 63 import java.text.NumberFormat ; 64 import java.util.List ; 65 66 import org.jfree.chart.plot.Plot; 67 import org.jfree.chart.plot.PlotRenderingInfo; 68 import org.jfree.data.Range; 69 import org.jfree.io.SerialUtilities; 70 import org.jfree.text.TextUtilities; 71 import org.jfree.ui.RectangleEdge; 72 import org.jfree.ui.TextAnchor; 73 import org.jfree.util.ObjectUtilities; 74 75 124 public class CyclicNumberAxis extends NumberAxis { 125 126 127 public static Stroke DEFAULT_ADVANCE_LINE_STROKE = new BasicStroke (1.0f); 128 129 130 public static final Paint DEFAULT_ADVANCE_LINE_PAINT = Color.gray; 131 132 133 protected double offset; 134 135 136 protected double period; 137 138 139 protected boolean boundMappedToLastCycle; 140 141 142 protected boolean advanceLineVisible; 143 144 145 protected transient Stroke advanceLineStroke = DEFAULT_ADVANCE_LINE_STROKE; 146 147 148 protected transient Paint advanceLinePaint; 149 150 private transient boolean internalMarkerWhenTicksOverlap; 151 private transient Tick internalMarkerCycleBoundTick; 152 153 158 public CyclicNumberAxis(double period) { 159 this(period, 0.0); 160 } 161 162 168 public CyclicNumberAxis(double period, double offset) { 169 this(period, offset, null); 170 } 171 172 178 public CyclicNumberAxis(double period, String label) { 179 this(0, period, label); 180 } 181 182 189 public CyclicNumberAxis(double period, double offset, String label) { 190 super(label); 191 this.period = period; 192 this.offset = offset; 193 setFixedAutoRange(period); 194 this.advanceLineVisible = true; 195 this.advanceLinePaint = DEFAULT_ADVANCE_LINE_PAINT; 196 } 197 198 204 public boolean isAdvanceLineVisible() { 205 return this.advanceLineVisible; 206 } 207 208 214 public void setAdvanceLineVisible(boolean visible) { 215 this.advanceLineVisible = visible; 216 } 217 218 224 public Paint getAdvanceLinePaint() { 225 return this.advanceLinePaint; 226 } 227 228 234 public void setAdvanceLinePaint(Paint paint) { 235 if (paint == null) { 236 throw new IllegalArgumentException ("Null 'paint' argument."); 237 } 238 this.advanceLinePaint = paint; 239 } 240 241 247 public Stroke getAdvanceLineStroke() { 248 return this.advanceLineStroke; 249 } 250 256 public void setAdvanceLineStroke(Stroke stroke) { 257 if (stroke == null) { 258 throw new IllegalArgumentException ("Null 'stroke' argument."); 259 } 260 this.advanceLineStroke = stroke; 261 } 262 263 277 public boolean isBoundMappedToLastCycle() { 278 return this.boundMappedToLastCycle; 279 } 280 281 294 public void setBoundMappedToLastCycle(boolean boundMappedToLastCycle) { 295 this.boundMappedToLastCycle = boundMappedToLastCycle; 296 } 297 298 306 protected void selectHorizontalAutoTickUnit(Graphics2D g2, 307 Rectangle2D drawArea, 308 Rectangle2D dataArea, 309 RectangleEdge edge) { 310 311 double tickLabelWidth 312 = estimateMaximumTickLabelWidth(g2, getTickUnit()); 313 314 double n = getRange().getLength() 316 * tickLabelWidth / dataArea.getWidth(); 317 318 setTickUnit( 319 (NumberTickUnit) getStandardTickUnits().getCeilingTickUnit(n), 320 false, false 321 ); 322 323 } 324 325 333 protected void selectVerticalAutoTickUnit(Graphics2D g2, 334 Rectangle2D drawArea, 335 Rectangle2D dataArea, 336 RectangleEdge edge) { 337 338 double tickLabelWidth 339 = estimateMaximumTickLabelWidth(g2, getTickUnit()); 340 341 double n = getRange().getLength() 343 * tickLabelWidth / dataArea.getHeight(); 344 345 setTickUnit( 346 (NumberTickUnit) getStandardTickUnits().getCeilingTickUnit(n), 347 false, false 348 ); 349 350 } 351 352 358 protected static class CycleBoundTick extends NumberTick { 359 360 361 public boolean mapToLastCycle; 362 363 373 public CycleBoundTick(boolean mapToLastCycle, Number number, 374 String label, TextAnchor textAnchor, 375 TextAnchor rotationAnchor, double angle) { 376 super(number, label, textAnchor, rotationAnchor, angle); 377 this.mapToLastCycle = mapToLastCycle; 378 } 379 } 380 381 391 protected float[] calculateAnchorPoint(ValueTick tick, double cursor, 392 Rectangle2D dataArea, 393 RectangleEdge edge) { 394 if (tick instanceof CycleBoundTick) { 395 boolean mapsav = this.boundMappedToLastCycle; 396 this.boundMappedToLastCycle 397 = ((CycleBoundTick) tick).mapToLastCycle; 398 float[] ret = super.calculateAnchorPoint( 399 tick, cursor, dataArea, edge 400 ); 401 this.boundMappedToLastCycle = mapsav; 402 return ret; 403 } 404 return super.calculateAnchorPoint(tick, cursor, dataArea, edge); 405 } 406 407 408 409 419 protected List refreshTicksHorizontal(Graphics2D g2, 420 Rectangle2D dataArea, 421 RectangleEdge edge) { 422 423 List result = new java.util.ArrayList (); 424 425 Font tickLabelFont = getTickLabelFont(); 426 g2.setFont(tickLabelFont); 427 428 if (isAutoTickUnitSelection()) { 429 selectAutoTickUnit(g2, dataArea, edge); 430 } 431 432 double unit = getTickUnit().getSize(); 433 double cycleBound = getCycleBound(); 434 double currentTickValue = Math.ceil(cycleBound / unit) * unit; 435 double upperValue = getRange().getUpperBound(); 436 boolean cycled = false; 437 438 boolean boundMapping = this.boundMappedToLastCycle; 439 this.boundMappedToLastCycle = false; 440 441 CycleBoundTick lastTick = null; 442 float lastX = 0.0f; 443 444 if (upperValue == cycleBound) { 445 currentTickValue = calculateLowestVisibleTickValue(); 446 cycled = true; 447 this.boundMappedToLastCycle = true; 448 } 449 450 while (currentTickValue <= upperValue) { 451 452 boolean cyclenow = false; 454 if ((currentTickValue + unit > upperValue) && !cycled) { 455 cyclenow = true; 456 } 457 458 double xx = valueToJava2D(currentTickValue, dataArea, edge); 459 String tickLabel; 460 NumberFormat formatter = getNumberFormatOverride(); 461 if (formatter != null) { 462 tickLabel = formatter.format(currentTickValue); 463 } 464 else { 465 tickLabel = getTickUnit().valueToString(currentTickValue); 466 } 467 float x = (float) xx; 468 TextAnchor anchor = null; 469 TextAnchor rotationAnchor = null; 470 double angle = 0.0; 471 if (isVerticalTickLabels()) { 472 if (edge == RectangleEdge.TOP) { 473 angle = Math.PI / 2.0; 474 } 475 else { 476 angle = -Math.PI / 2.0; 477 } 478 anchor = TextAnchor.CENTER_RIGHT; 479 if ((lastTick != null) && (lastX == x) 481 && (currentTickValue != cycleBound)) { 482 anchor = isInverted() 483 ? TextAnchor.TOP_RIGHT : TextAnchor.BOTTOM_RIGHT; 484 result.remove(result.size() - 1); 485 result.add(new CycleBoundTick( 486 this.boundMappedToLastCycle, lastTick.getNumber(), 487 lastTick.getText(), anchor, anchor, 488 lastTick.getAngle()) 489 ); 490 this.internalMarkerWhenTicksOverlap = true; 491 anchor = isInverted() 492 ? TextAnchor.BOTTOM_RIGHT : TextAnchor.TOP_RIGHT; 493 } 494 rotationAnchor = anchor; 495 } 496 else { 497 if (edge == RectangleEdge.TOP) { 498 anchor = TextAnchor.BOTTOM_CENTER; 499 if ((lastTick != null) && (lastX == x) 500 && (currentTickValue != cycleBound)) { 501 anchor = isInverted() 502 ? TextAnchor.BOTTOM_LEFT : TextAnchor.BOTTOM_RIGHT; 503 result.remove(result.size() - 1); 504 result.add(new CycleBoundTick( 505 this.boundMappedToLastCycle, lastTick.getNumber(), 506 lastTick.getText(), anchor, anchor, 507 lastTick.getAngle()) 508 ); 509 this.internalMarkerWhenTicksOverlap = true; 510 anchor = isInverted() 511 ? TextAnchor.BOTTOM_RIGHT : TextAnchor.BOTTOM_LEFT; 512 } 513 rotationAnchor = anchor; 514 } 515 else { 516 anchor = TextAnchor.TOP_CENTER; 517 if ((lastTick != null) && (lastX == x) 518 && (currentTickValue != cycleBound)) { 519 anchor = isInverted() 520 ? TextAnchor.TOP_LEFT : TextAnchor.TOP_RIGHT; 521 result.remove(result.size() - 1); 522 result.add(new CycleBoundTick( 523 this.boundMappedToLastCycle, lastTick.getNumber(), 524 lastTick.getText(), anchor, anchor, 525 lastTick.getAngle()) 526 ); 527 this.internalMarkerWhenTicksOverlap = true; 528 anchor = isInverted() 529 ? TextAnchor.TOP_RIGHT : TextAnchor.TOP_LEFT; 530 } 531 rotationAnchor = anchor; 532 } 533 } 534 535 CycleBoundTick tick = new CycleBoundTick( 536 this.boundMappedToLastCycle, 537 new Double (currentTickValue), tickLabel, anchor, 538 rotationAnchor, angle 539 ); 540 if (currentTickValue == cycleBound) { 541 this.internalMarkerCycleBoundTick = tick; 542 } 543 result.add(tick); 544 lastTick = tick; 545 lastX = x; 546 547 currentTickValue += unit; 548 549 if (cyclenow) { 550 currentTickValue = calculateLowestVisibleTickValue(); 551 upperValue = cycleBound; 552 cycled = true; 553 this.boundMappedToLastCycle = true; 554 } 555 556 } 557 this.boundMappedToLastCycle = boundMapping; 558 return result; 559 560 } 561 562 572 protected List refreshVerticalTicks(Graphics2D g2, 573 Rectangle2D dataArea, 574 RectangleEdge edge) { 575 576 List result = new java.util.ArrayList (); 577 result.clear(); 578 579 Font tickLabelFont = getTickLabelFont(); 580 g2.setFont(tickLabelFont); 581 if (isAutoTickUnitSelection()) { 582 selectAutoTickUnit(g2, dataArea, edge); 583 } 584 585 double unit = getTickUnit().getSize(); 586 double cycleBound = getCycleBound(); 587 double currentTickValue = Math.ceil(cycleBound / unit) * unit; 588 double upperValue = getRange().getUpperBound(); 589 boolean cycled = false; 590 591 boolean boundMapping = this.boundMappedToLastCycle; 592 this.boundMappedToLastCycle = true; 593 594 NumberTick lastTick = null; 595 float lastY = 0.0f; 596 597 if (upperValue == cycleBound) { 598 currentTickValue = calculateLowestVisibleTickValue(); 599 cycled = true; 600 this.boundMappedToLastCycle = true; 601 } 602 603 while (currentTickValue <= upperValue) { 604 605 boolean cyclenow = false; 607 if ((currentTickValue + unit > upperValue) && !cycled) { 608 cyclenow = true; 609 } 610 611 double yy = valueToJava2D(currentTickValue, dataArea, edge); 612 String tickLabel; 613 NumberFormat formatter = getNumberFormatOverride(); 614 if (formatter != null) { 615 tickLabel = formatter.format(currentTickValue); 616 } 617 else { 618 tickLabel = getTickUnit().valueToString(currentTickValue); 619 } 620 621 float y = (float) yy; 622 TextAnchor anchor = null; 623 TextAnchor rotationAnchor = null; 624 double angle = 0.0; 625 if (isVerticalTickLabels()) { 626 627 if (edge == RectangleEdge.LEFT) { 628 anchor = TextAnchor.BOTTOM_CENTER; 629 if ((lastTick != null) && (lastY == y) 630 && (currentTickValue != cycleBound)) { 631 anchor = isInverted() 632 ? TextAnchor.BOTTOM_LEFT : TextAnchor.BOTTOM_RIGHT; 633 result.remove(result.size() - 1); 634 result.add(new CycleBoundTick( 635 this.boundMappedToLastCycle, lastTick.getNumber(), 636 lastTick.getText(), anchor, anchor, 637 lastTick.getAngle()) 638 ); 639 this.internalMarkerWhenTicksOverlap = true; 640 anchor = isInverted() 641 ? TextAnchor.BOTTOM_RIGHT : TextAnchor.BOTTOM_LEFT; 642 } 643 rotationAnchor = anchor; 644 angle = -Math.PI / 2.0; 645 } 646 else { 647 anchor = TextAnchor.BOTTOM_CENTER; 648 if ((lastTick != null) && (lastY == y) 649 && (currentTickValue != cycleBound)) { 650 anchor = isInverted() 651 ? TextAnchor.BOTTOM_RIGHT : TextAnchor.BOTTOM_LEFT; 652 result.remove(result.size() - 1); 653 result.add(new CycleBoundTick( 654 this.boundMappedToLastCycle, lastTick.getNumber(), 655 lastTick.getText(), anchor, anchor, 656 lastTick.getAngle()) 657 ); 658 this.internalMarkerWhenTicksOverlap = true; 659 anchor = isInverted() 660 ? TextAnchor.BOTTOM_LEFT : TextAnchor.BOTTOM_RIGHT; 661 } 662 rotationAnchor = anchor; 663 angle = Math.PI / 2.0; 664 } 665 } 666 else { 667 if (edge == RectangleEdge.LEFT) { 668 anchor = TextAnchor.CENTER_RIGHT; 669 if ((lastTick != null) && (lastY == y) 670 && (currentTickValue != cycleBound)) { 671 anchor = isInverted() 672 ? TextAnchor.BOTTOM_RIGHT : TextAnchor.TOP_RIGHT; 673 result.remove(result.size() - 1); 674 result.add(new CycleBoundTick( 675 this.boundMappedToLastCycle, lastTick.getNumber(), 676 lastTick.getText(), anchor, anchor, 677 lastTick.getAngle()) 678 ); 679 this.internalMarkerWhenTicksOverlap = true; 680 anchor = isInverted() 681 ? TextAnchor.TOP_RIGHT : TextAnchor.BOTTOM_RIGHT; 682 } 683 rotationAnchor = anchor; 684 } 685 else { 686 anchor = TextAnchor.CENTER_LEFT; 687 if ((lastTick != null) && (lastY == y) 688 && (currentTickValue != cycleBound)) { 689 anchor = isInverted() 690 ? TextAnchor.BOTTOM_LEFT : TextAnchor.TOP_LEFT; 691 result.remove(result.size() - 1); 692 result.add(new CycleBoundTick( 693 this.boundMappedToLastCycle, lastTick.getNumber(), 694 lastTick.getText(), anchor, anchor, 695 lastTick.getAngle()) 696 ); 697 this.internalMarkerWhenTicksOverlap = true; 698 anchor = isInverted() 699 ? TextAnchor.TOP_LEFT : TextAnchor.BOTTOM_LEFT; 700 } 701 rotationAnchor = anchor; 702 } 703 } 704 705 CycleBoundTick tick = new CycleBoundTick( 706 this.boundMappedToLastCycle, new Double (currentTickValue), 707 tickLabel, anchor, rotationAnchor, angle 708 ); 709 if (currentTickValue == cycleBound) { 710 this.internalMarkerCycleBoundTick = tick; 711 } 712 result.add(tick); 713 lastTick = tick; 714 lastY = y; 715 716 if (currentTickValue == cycleBound) { 717 this.internalMarkerCycleBoundTick = tick; 718 } 719 720 currentTickValue += unit; 721 722 if (cyclenow) { 723 currentTickValue = calculateLowestVisibleTickValue(); 724 upperValue = cycleBound; 725 cycled = true; 726 this.boundMappedToLastCycle = false; 727 } 728 729 } 730 this.boundMappedToLastCycle = boundMapping; 731 return result; 732 } 733 734 743 public double java2DToValue(double java2DValue, Rectangle2D dataArea, 744 RectangleEdge edge) { 745 Range range = getRange(); 746 747 double vmax = range.getUpperBound(); 748 double vp = getCycleBound(); 749 750 double jmin = 0.0; 751 double jmax = 0.0; 752 if (RectangleEdge.isTopOrBottom(edge)) { 753 jmin = dataArea.getMinX(); 754 jmax = dataArea.getMaxX(); 755 } 756 else if (RectangleEdge.isLeftOrRight(edge)) { 757 jmin = dataArea.getMaxY(); 758 jmax = dataArea.getMinY(); 759 } 760 761 if (isInverted()) { 762 double jbreak = jmax - (vmax - vp) * (jmax - jmin) / this.period; 763 if (java2DValue >= jbreak) { 764 return vp + (jmax - java2DValue) * this.period / (jmax - jmin); 765 } 766 else { 767 return vp - (java2DValue - jmin) * this.period / (jmax - jmin); 768 } 769 } 770 else { 771 double jbreak = (vmax - vp) * (jmax - jmin) / this.period + jmin; 772 if (java2DValue <= jbreak) { 773 return vp + (java2DValue - jmin) * this.period / (jmax - jmin); 774 } 775 else { 776 return vp - (jmax - java2DValue) * this.period / (jmax - jmin); 777 } 778 } 779 } 780 781 790 public double valueToJava2D(double value, Rectangle2D dataArea, 791 RectangleEdge edge) { 792 Range range = getRange(); 793 794 double vmin = range.getLowerBound(); 795 double vmax = range.getUpperBound(); 796 double vp = getCycleBound(); 797 798 if ((value < vmin) || (value > vmax)) { 799 return Double.NaN; 800 } 801 802 803 double jmin = 0.0; 804 double jmax = 0.0; 805 if (RectangleEdge.isTopOrBottom(edge)) { 806 jmin = dataArea.getMinX(); 807 jmax = dataArea.getMaxX(); 808 } 809 else if (RectangleEdge.isLeftOrRight(edge)) { 810 jmax = dataArea.getMinY(); 811 jmin = dataArea.getMaxY(); 812 } 813 814 if (isInverted()) { 815 if (value == vp) { 816 return this.boundMappedToLastCycle ? jmin : jmax; 817 } 818 else if (value > vp) { 819 return jmax - (value - vp) * (jmax - jmin) / this.period; 820 } 821 else { 822 return jmin + (vp - value) * (jmax - jmin) / this.period; 823 } 824 } 825 else { 826 if (value == vp) { 827 return this.boundMappedToLastCycle ? jmax : jmin; 828 } 829 else if (value >= vp) { 830 return jmin + (value - vp) * (jmax - jmin) / this.period; 831 } 832 else { 833 return jmax - (vp - value) * (jmax - jmin) / this.period; 834 } 835 } 836 } 837 838 843 public void centerRange(double value) { 844 setRange(value - this.period / 2.0, value + this.period / 2.0); 845 } 846 847 858 public void setAutoRangeMinimumSize(double size, boolean notify) { 859 if (size > this.period) { 860 this.period = size; 861 } 862 super.setAutoRangeMinimumSize(size, notify); 863 } 864 865 873 public void setFixedAutoRange(double length) { 874 this.period = length; 875 super.setFixedAutoRange(length); 876 } 877 878 888 public void setRange(Range range, boolean turnOffAutoRange, 889 boolean notify) { 890 double size = range.getUpperBound() - range.getLowerBound(); 891 if (size > this.period) { 892 this.period = size; 893 } 894 super.setRange(range, turnOffAutoRange, notify); 895 } 896 897 907 public double getCycleBound() { 908 return Math.floor( 909 (getRange().getUpperBound() - this.offset) / this.period 910 ) * this.period + this.offset; 911 } 912 913 923 public double getOffset() { 924 return this.offset; 925 } 926 927 937 public void setOffset(double offset) { 938 this.offset = offset; 939 } 940 941 951 public double getPeriod() { 952 return this.period; 953 } 954 955 965 public void setPeriod(double period) { 966 this.period = period; 967 } 968 969 980 protected AxisState drawTickMarksAndLabels(Graphics2D g2, double cursor, 981 Rectangle2D plotArea, 982 Rectangle2D dataArea, 983 RectangleEdge edge) { 984 this.internalMarkerWhenTicksOverlap = false; 985 AxisState ret = super.drawTickMarksAndLabels( 986 g2, cursor, plotArea, dataArea, edge 987 ); 988 989 if (!this.internalMarkerWhenTicksOverlap) { 991 return ret; 992 } 993 994 double ol = getTickMarkOutsideLength(); 995 FontMetrics fm = g2.getFontMetrics(getTickLabelFont()); 996 997 if (isVerticalTickLabels()) { 998 ol = fm.getMaxAdvance(); 999 } 1000 else { 1001 ol = fm.getHeight(); 1002 } 1003 1004 double il = 0; 1005 if (isTickMarksVisible()) { 1006 float xx = (float) valueToJava2D( 1007 getRange().getUpperBound(), dataArea, edge 1008 ); 1009 Line2D mark = null; 1010 g2.setStroke(getTickMarkStroke()); 1011 g2.setPaint(getTickMarkPaint()); 1012 if (edge == RectangleEdge.LEFT) { 1013 mark = new Line2D.Double (cursor - ol, xx, cursor + il, xx); 1014 } 1015 else if (edge == RectangleEdge.RIGHT) { 1016 mark = new Line2D.Double (cursor + ol, xx, cursor - il, xx); 1017 } 1018 else if (edge == RectangleEdge.TOP) { 1019 mark = new Line2D.Double (xx, cursor - ol, xx, cursor + il); 1020 } 1021 else if (edge == RectangleEdge.BOTTOM) { 1022 mark = new Line2D.Double (xx, cursor + ol, xx, cursor - il); 1023 } 1024 g2.draw(mark); 1025 } 1026 return ret; 1027 } 1028 1029 1042 public AxisState draw(Graphics2D g2, 1043 double cursor, 1044 Rectangle2D plotArea, 1045 Rectangle2D dataArea, 1046 RectangleEdge edge, 1047 PlotRenderingInfo plotState) { 1048 1049 AxisState ret = super.draw( 1050 g2, cursor, plotArea, dataArea, edge, plotState 1051 ); 1052 if (isAdvanceLineVisible()) { 1053 double xx = valueToJava2D( 1054 getRange().getUpperBound(), dataArea, edge 1055 ); 1056 Line2D mark = null; 1057 g2.setStroke(getAdvanceLineStroke()); 1058 g2.setPaint(getAdvanceLinePaint()); 1059 if (edge == RectangleEdge.LEFT) { 1060 mark = new Line2D.Double ( 1061 cursor, xx, cursor + dataArea.getWidth(), xx 1062 ); 1063 } 1064 else if (edge == RectangleEdge.RIGHT) { 1065 mark = new Line2D.Double ( 1066 cursor - dataArea.getWidth(), xx, cursor, xx 1067 ); 1068 } 1069 else if (edge == RectangleEdge.TOP) { 1070 mark = new Line2D.Double ( 1071 xx, cursor + dataArea.getHeight(), xx, cursor 1072 ); 1073 } 1074 else if (edge == RectangleEdge.BOTTOM) { 1075 mark = new Line2D.Double ( 1076 xx, cursor, xx, cursor - dataArea.getHeight() 1077 ); 1078 } 1079 g2.draw(mark); 1080 } 1081 return ret; 1082 } 1083 1084 1096 public AxisSpace reserveSpace(Graphics2D g2, 1097 Plot plot, 1098 Rectangle2D plotArea, 1099 RectangleEdge edge, 1100 AxisSpace space) { 1101 1102 this.internalMarkerCycleBoundTick = null; 1103 AxisSpace ret = super.reserveSpace(g2, plot, plotArea, edge, space); 1104 if (this.internalMarkerCycleBoundTick == null) { 1105 return ret; 1106 } 1107 1108 FontMetrics fm = g2.getFontMetrics(getTickLabelFont()); 1109 Rectangle2D r = TextUtilities.getTextBounds( 1110 this.internalMarkerCycleBoundTick.getText(), g2, fm 1111 ); 1112 1113 if (RectangleEdge.isTopOrBottom(edge)) { 1114 if (isVerticalTickLabels()) { 1115 space.add(r.getHeight() / 2, RectangleEdge.RIGHT); 1116 } 1117 else { 1118 space.add(r.getWidth() / 2, RectangleEdge.RIGHT); 1119 } 1120 } 1121 else if (RectangleEdge.isLeftOrRight(edge)) { 1122 if (isVerticalTickLabels()) { 1123 space.add(r.getWidth() / 2, RectangleEdge.TOP); 1124 } 1125 else { 1126 space.add(r.getHeight() / 2, RectangleEdge.TOP); 1127 } 1128 } 1129 1130 return ret; 1131 1132 } 1133 1134 1141 private void writeObject(ObjectOutputStream stream) throws IOException { 1142 1143 stream.defaultWriteObject(); 1144 SerialUtilities.writePaint(this.advanceLinePaint, stream); 1145 SerialUtilities.writeStroke(this.advanceLineStroke, stream); 1146 1147 } 1148 1149 1157 private void readObject(ObjectInputStream stream) 1158 throws IOException , ClassNotFoundException { 1159 1160 stream.defaultReadObject(); 1161 this.advanceLinePaint = SerialUtilities.readPaint(stream); 1162 this.advanceLineStroke = SerialUtilities.readStroke(stream); 1163 1164 } 1165 1166 1167 1174 public boolean equals(Object object) { 1175 if (object == this) { 1176 return true; 1177 } 1178 if (!(object instanceof CyclicNumberAxis)) { 1179 return false; 1180 } 1181 if (!super.equals(object)) { 1182 return false; 1183 } 1184 CyclicNumberAxis axis = (CyclicNumberAxis) object; 1185 1186 if (this.period != axis.period) { 1187 return false; 1188 } 1189 if (this.offset != axis.offset) { 1190 return false; 1191 } 1192 if (!ObjectUtilities.equal(this.advanceLinePaint, 1193 axis.advanceLinePaint)) { 1194 return false; 1195 } 1196 if (!ObjectUtilities.equal(this.advanceLineStroke, 1197 axis.advanceLineStroke)) { 1198 return false; 1199 } 1200 if (this.advanceLineVisible != axis.advanceLineVisible) { 1201 return false; 1202 } 1203 if (this.boundMappedToLastCycle != axis.boundMappedToLastCycle) { 1204 return false; 1205 } 1206 return true; 1207 } 1208} 1209 | Popular Tags |