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