1:
42:
43: package ;
44:
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61:
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67:
68:
71: public class StandardDialScale extends AbstractDialLayer implements DialScale,
72: Cloneable, PublicCloneable, Serializable {
73:
74:
75: static final long serialVersionUID = 3715644629665918516L;
76:
77:
78: private double lowerBound;
79:
80:
81: private double upperBound;
82:
83:
87: private double startAngle;
88:
89:
90: private double extent;
91:
92:
96: private double tickRadius;
97:
98:
101: private double majorTickIncrement;
102:
103:
107: private double majorTickLength;
108:
109:
113: private transient Paint majorTickPaint;
114:
115:
119: private transient Stroke majorTickStroke;
120:
121:
124: private int minorTickCount;
125:
126:
130: private double minorTickLength;
131:
132:
136: private transient Paint minorTickPaint;
137:
138:
142: private transient Stroke minorTickStroke;
143:
144:
147: private double tickLabelOffset;
148:
149:
152: private Font tickLabelFont;
153:
154:
158: private boolean tickLabelsVisible;
159:
160:
163: private NumberFormat tickLabelFormatter;
164:
165:
169: private boolean firstTickLabelVisible;
170:
171:
175: private transient Paint tickLabelPaint;
176:
177:
180: public StandardDialScale() {
181: this(0.0, 100.0, 175, -170, 10.0, 4);
182: }
183:
184:
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:
228: public double getStartAngle() {
229: return this.startAngle;
230: }
231:
232:
240: public void setStartAngle(double angle) {
241: this.startAngle = angle;
242: notifyListeners(new DialLayerChangeEvent(this));
243: }
244:
245:
252: public double getExtent() {
253: return this.extent;
254: }
255:
256:
264: public void setExtent(double extent) {
265: this.extent = extent;
266: notifyListeners(new DialLayerChangeEvent(this));
267: }
268:
269:
277: public double getTickRadius() {
278: return this.tickRadius;
279: }
280:
281:
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:
305: public double getMajorTickIncrement() {
306: return this.majorTickIncrement;
307: }
308:
309:
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:
335: public double getMajorTickLength() {
336: return this.majorTickLength;
337: }
338:
339:
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:
362: public Paint getMajorTickPaint() {
363: return this.majorTickPaint;
364: }
365:
366:
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:
389: public Stroke getMajorTickStroke() {
390: return this.majorTickStroke;
391: }
392:
393:
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:
416: public int getMinorTickCount() {
417: return this.minorTickCount;
418: }
419:
420:
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:
446: public double getMinorTickLength() {
447: return this.minorTickLength;
448: }
449:
450:
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:
473: public Paint getMinorTickPaint() {
474: return this.minorTickPaint;
475: }
476:
477:
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:
500: public double getTickLabelOffset() {
501: return this.tickLabelOffset;
502: }
503:
504:
512: public void setTickLabelOffset(double offset) {
513: this.tickLabelOffset = offset;
514: notifyListeners(new DialLayerChangeEvent(this));
515: }
516:
517:
524: public Font getTickLabelFont() {
525: return this.tickLabelFont;
526: }
527:
528:
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:
551: public Paint getTickLabelPaint() {
552: return this.tickLabelPaint;
553: }
554:
555:
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:
577: public boolean getTickLabelsVisible() {
578: return this.tickLabelsVisible;
579: }
580:
581:
590: public void setTickLabelsVisible(boolean visible) {
591: this.tickLabelsVisible = visible;
592: notifyListeners(new DialLayerChangeEvent(this));
593: }
594:
595:
603: public NumberFormat getTickLabelFormatter() {
604: return this.tickLabelFormatter;
605: }
606:
607:
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:
632: public boolean getFirstTickLabelVisible() {
633: return this.firstTickLabelVisible;
634: }
635:
636:
645: public void setFirstTickLabelVisible(boolean visible) {
646: this.firstTickLabelVisible = visible;
647: notifyListeners(new DialLayerChangeEvent(this));
648: }
649:
650:
656: public boolean isClippedToWindow() {
657: return true;
658: }
659:
660:
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:
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:
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:
771: public double angleToValue(double angle) {
772: return Double.NaN;
773: }
774:
775:
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:
850: public int hashCode() {
851: int result = 193;
852:
853: long temp = Double.doubleToLongBits(this.lowerBound);
854: result = 37 * result + (int) (temp ^ (temp >>> 32));
855:
856: temp = Double.doubleToLongBits(this.upperBound);
857: result = 37 * result + (int) (temp ^ (temp >>> 32));
858:
859: temp = Double.doubleToLongBits(this.startAngle);
860: result = 37 * result + (int) (temp ^ (temp >>> 32));
861:
862: temp = Double.doubleToLongBits(this.extent);
863: result = 37 * result + (int) (temp ^ (temp >>> 32));
864:
865: temp = Double.doubleToLongBits(this.tickRadius);
866: result = 37 * result + (int) (temp ^ (temp >>> 32));
867:
868:
869:
870:
871:
872:
873:
874:
875:
876:
877:
878:
879:
880: return result;
881: }
882:
883:
890: public Object clone() throws CloneNotSupportedException {
891: return super.clone();
892: }
893:
894:
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:
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: }