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