1:
43:
44: package ;
45:
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:
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71:
72:
87: public class CategoryPointerAnnotation extends CategoryTextAnnotation
88: implements Cloneable, PublicCloneable,
89: Serializable {
90:
91:
92: private static final long serialVersionUID = -4031161445009858551L;
93:
94:
95: public static final double DEFAULT_TIP_RADIUS = 10.0;
96:
97:
98: public static final double DEFAULT_BASE_RADIUS = 30.0;
99:
100:
101: public static final double DEFAULT_LABEL_OFFSET = 3.0;
102:
103:
104: public static final double DEFAULT_ARROW_LENGTH = 5.0;
105:
106:
107: public static final double DEFAULT_ARROW_WIDTH = 3.0;
108:
109:
110: private double angle;
111:
112:
116: private double tipRadius;
117:
118:
122: private double baseRadius;
123:
124:
125: private double arrowLength;
126:
127:
128: private double arrowWidth;
129:
130:
131: private transient Stroke arrowStroke;
132:
133:
134: private transient Paint arrowPaint;
135:
136:
137: private double labelOffset;
138:
139:
147: public CategoryPointerAnnotation(String label, Comparable key, double value,
148: double angle) {
149:
150: super(label, key, value);
151: this.angle = angle;
152: this.tipRadius = DEFAULT_TIP_RADIUS;
153: this.baseRadius = DEFAULT_BASE_RADIUS;
154: this.arrowLength = DEFAULT_ARROW_LENGTH;
155: this.arrowWidth = DEFAULT_ARROW_WIDTH;
156: this.labelOffset = DEFAULT_LABEL_OFFSET;
157: this.arrowStroke = new BasicStroke(1.0f);
158: this.arrowPaint = Color.black;
159:
160: }
161:
162:
169: public double getAngle() {
170: return this.angle;
171: }
172:
173:
180: public void setAngle(double angle) {
181: this.angle = angle;
182: }
183:
184:
191: public double getTipRadius() {
192: return this.tipRadius;
193: }
194:
195:
202: public void setTipRadius(double radius) {
203: this.tipRadius = radius;
204: }
205:
206:
213: public double getBaseRadius() {
214: return this.baseRadius;
215: }
216:
217:
224: public void setBaseRadius(double radius) {
225: this.baseRadius = radius;
226: }
227:
228:
235: public double getLabelOffset() {
236: return this.labelOffset;
237: }
238:
239:
247: public void setLabelOffset(double offset) {
248: this.labelOffset = offset;
249: }
250:
251:
258: public double getArrowLength() {
259: return this.arrowLength;
260: }
261:
262:
269: public void setArrowLength(double length) {
270: this.arrowLength = length;
271: }
272:
273:
280: public double getArrowWidth() {
281: return this.arrowWidth;
282: }
283:
284:
291: public void setArrowWidth(double width) {
292: this.arrowWidth = width;
293: }
294:
295:
302: public Stroke getArrowStroke() {
303: return this.arrowStroke;
304: }
305:
306:
313: public void setArrowStroke(Stroke stroke) {
314: if (stroke == null) {
315: throw new IllegalArgumentException("Null 'stroke' not permitted.");
316: }
317: this.arrowStroke = stroke;
318: }
319:
320:
327: public Paint getArrowPaint() {
328: return this.arrowPaint;
329: }
330:
331:
338: public void setArrowPaint(Paint paint) {
339: if (paint == null) {
340: throw new IllegalArgumentException("Null 'paint' argument.");
341: }
342: this.arrowPaint = paint;
343: }
344:
345:
354: public void draw(Graphics2D g2, CategoryPlot plot, Rectangle2D dataArea,
355: CategoryAxis domainAxis, ValueAxis rangeAxis) {
356:
357: PlotOrientation orientation = plot.getOrientation();
358: RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
359: plot.getDomainAxisLocation(), orientation);
360: RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
361: plot.getRangeAxisLocation(), orientation);
362: CategoryDataset dataset = plot.getDataset();
363: int catIndex = dataset.getColumnIndex(getCategory());
364: int catCount = dataset.getColumnCount();
365: double j2DX = domainAxis.getCategoryMiddle(catIndex, catCount,
366: dataArea, domainEdge);
367: double j2DY = rangeAxis.valueToJava2D(getValue(), dataArea, rangeEdge);
368: if (orientation == PlotOrientation.HORIZONTAL) {
369: double temp = j2DX;
370: j2DX = j2DY;
371: j2DY = temp;
372: }
373: double startX = j2DX + Math.cos(this.angle) * this.baseRadius;
374: double startY = j2DY + Math.sin(this.angle) * this.baseRadius;
375:
376: double endX = j2DX + Math.cos(this.angle) * this.tipRadius;
377: double endY = j2DY + Math.sin(this.angle) * this.tipRadius;
378:
379: double arrowBaseX = endX + Math.cos(this.angle) * this.arrowLength;
380: double arrowBaseY = endY + Math.sin(this.angle) * this.arrowLength;
381:
382: double arrowLeftX = arrowBaseX
383: + Math.cos(this.angle + Math.PI / 2.0) * this.arrowWidth;
384: double arrowLeftY = arrowBaseY
385: + Math.sin(this.angle + Math.PI / 2.0) * this.arrowWidth;
386:
387: double arrowRightX = arrowBaseX
388: - Math.cos(this.angle + Math.PI / 2.0) * this.arrowWidth;
389: double arrowRightY = arrowBaseY
390: - Math.sin(this.angle + Math.PI / 2.0) * this.arrowWidth;
391:
392: GeneralPath arrow = new GeneralPath();
393: arrow.moveTo((float) endX, (float) endY);
394: arrow.lineTo((float) arrowLeftX, (float) arrowLeftY);
395: arrow.lineTo((float) arrowRightX, (float) arrowRightY);
396: arrow.closePath();
397:
398: g2.setStroke(this.arrowStroke);
399: g2.setPaint(this.arrowPaint);
400: Line2D line = new Line2D.Double(startX, startY, endX, endY);
401: g2.draw(line);
402: g2.fill(arrow);
403:
404:
405: g2.setFont(getFont());
406: g2.setPaint(getPaint());
407: double labelX = j2DX
408: + Math.cos(this.angle) * (this.baseRadius + this.labelOffset);
409: double labelY = j2DY
410: + Math.sin(this.angle) * (this.baseRadius + this.labelOffset);
411: TextUtilities.drawAlignedString(getText(),
412: g2, (float) labelX, (float) labelY, getTextAnchor());
413:
414:
415: }
416:
417:
424: public boolean equals(Object obj) {
425:
426: if (obj == this) {
427: return true;
428: }
429: if (!(obj instanceof CategoryPointerAnnotation)) {
430: return false;
431: }
432: if (!super.equals(obj)) {
433: return false;
434: }
435: CategoryPointerAnnotation that = (CategoryPointerAnnotation) obj;
436: if (this.angle != that.angle) {
437: return false;
438: }
439: if (this.tipRadius != that.tipRadius) {
440: return false;
441: }
442: if (this.baseRadius != that.baseRadius) {
443: return false;
444: }
445: if (this.arrowLength != that.arrowLength) {
446: return false;
447: }
448: if (this.arrowWidth != that.arrowWidth) {
449: return false;
450: }
451: if (!this.arrowPaint.equals(that.arrowPaint)) {
452: return false;
453: }
454: if (!ObjectUtilities.equal(this.arrowStroke, that.arrowStroke)) {
455: return false;
456: }
457: if (this.labelOffset != that.labelOffset) {
458: return false;
459: }
460: return true;
461: }
462:
463:
468: public int hashCode() {
469: int result = 193;
470: long temp = Double.doubleToLongBits(this.angle);
471: result = 37 * result + (int) (temp ^ (temp >>> 32));
472: temp = Double.doubleToLongBits(this.tipRadius);
473: result = 37 * result + (int) (temp ^ (temp >>> 32));
474: temp = Double.doubleToLongBits(this.baseRadius);
475: result = 37 * result + (int) (temp ^ (temp >>> 32));
476: temp = Double.doubleToLongBits(this.arrowLength);
477: result = 37 * result + (int) (temp ^ (temp >>> 32));
478: temp = Double.doubleToLongBits(this.arrowWidth);
479: result = 37 * result + (int) (temp ^ (temp >>> 32));
480: result = 37 * result + HashUtilities.hashCodeForPaint(this.arrowPaint);
481: result = 37 * result + this.arrowStroke.hashCode();
482: temp = Double.doubleToLongBits(this.labelOffset);
483: result = 37 * result + (int) (temp ^ (temp >>> 32));
484: return result;
485: }
486:
487:
494: public Object clone() throws CloneNotSupportedException {
495: return super.clone();
496: }
497:
498:
505: private void writeObject(ObjectOutputStream stream) throws IOException {
506: stream.defaultWriteObject();
507: SerialUtilities.writePaint(this.arrowPaint, stream);
508: SerialUtilities.writeStroke(this.arrowStroke, stream);
509: }
510:
511:
519: private void readObject(ObjectInputStream stream)
520: throws IOException, ClassNotFoundException {
521: stream.defaultReadObject();
522: this.arrowPaint = SerialUtilities.readPaint(stream);
523: this.arrowStroke = SerialUtilities.readStroke(stream);
524: }
525:
526: }