1:
41:
42: package ;
43:
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56:
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69:
70:
85: public class CategoryPointerAnnotation extends CategoryTextAnnotation
86: implements Cloneable, PublicCloneable,
87: Serializable {
88:
89:
90: private static final long serialVersionUID = -4031161445009858551L;
91:
92:
93: public static final double DEFAULT_TIP_RADIUS = 10.0;
94:
95:
96: public static final double DEFAULT_BASE_RADIUS = 30.0;
97:
98:
99: public static final double DEFAULT_LABEL_OFFSET = 3.0;
100:
101:
102: public static final double DEFAULT_ARROW_LENGTH = 5.0;
103:
104:
105: public static final double DEFAULT_ARROW_WIDTH = 3.0;
106:
107:
108: private double angle;
109:
110:
114: private double tipRadius;
115:
116:
120: private double baseRadius;
121:
122:
123: private double arrowLength;
124:
125:
126: private double arrowWidth;
127:
128:
129: private transient Stroke arrowStroke;
130:
131:
132: private transient Paint arrowPaint;
133:
134:
135: private double labelOffset;
136:
137:
145: public CategoryPointerAnnotation(String label, Comparable key, double value,
146: double angle) {
147:
148: super(label, key, value);
149: this.angle = angle;
150: this.tipRadius = DEFAULT_TIP_RADIUS;
151: this.baseRadius = DEFAULT_BASE_RADIUS;
152: this.arrowLength = DEFAULT_ARROW_LENGTH;
153: this.arrowWidth = DEFAULT_ARROW_WIDTH;
154: this.labelOffset = DEFAULT_LABEL_OFFSET;
155: this.arrowStroke = new BasicStroke(1.0f);
156: this.arrowPaint = Color.black;
157:
158: }
159:
160:
167: public double getAngle() {
168: return this.angle;
169: }
170:
171:
178: public void setAngle(double angle) {
179: this.angle = angle;
180: }
181:
182:
189: public double getTipRadius() {
190: return this.tipRadius;
191: }
192:
193:
200: public void setTipRadius(double radius) {
201: this.tipRadius = radius;
202: }
203:
204:
211: public double getBaseRadius() {
212: return this.baseRadius;
213: }
214:
215:
222: public void setBaseRadius(double radius) {
223: this.baseRadius = radius;
224: }
225:
226:
233: public double getLabelOffset() {
234: return this.labelOffset;
235: }
236:
237:
245: public void setLabelOffset(double offset) {
246: this.labelOffset = offset;
247: }
248:
249:
256: public double getArrowLength() {
257: return this.arrowLength;
258: }
259:
260:
267: public void setArrowLength(double length) {
268: this.arrowLength = length;
269: }
270:
271:
278: public double getArrowWidth() {
279: return this.arrowWidth;
280: }
281:
282:
289: public void setArrowWidth(double width) {
290: this.arrowWidth = width;
291: }
292:
293:
300: public Stroke getArrowStroke() {
301: return this.arrowStroke;
302: }
303:
304:
311: public void setArrowStroke(Stroke stroke) {
312: if (stroke == null) {
313: throw new IllegalArgumentException("Null 'stroke' not permitted.");
314: }
315: this.arrowStroke = stroke;
316: }
317:
318:
325: public Paint getArrowPaint() {
326: return this.arrowPaint;
327: }
328:
329:
336: public void setArrowPaint(Paint paint) {
337: if (paint == null) {
338: throw new IllegalArgumentException("Null 'paint' argument.");
339: }
340: this.arrowPaint = paint;
341: }
342:
343:
352: public void draw(Graphics2D g2, CategoryPlot plot, Rectangle2D dataArea,
353: CategoryAxis domainAxis, ValueAxis rangeAxis) {
354:
355: PlotOrientation orientation = plot.getOrientation();
356: RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
357: plot.getDomainAxisLocation(), orientation);
358: RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
359: plot.getRangeAxisLocation(), orientation);
360: CategoryDataset dataset = plot.getDataset();
361: int catIndex = dataset.getColumnIndex(getCategory());
362: int catCount = dataset.getColumnCount();
363: double j2DX = domainAxis.getCategoryMiddle(catIndex, catCount,
364: dataArea, domainEdge);
365: double j2DY = rangeAxis.valueToJava2D(getValue(), dataArea, rangeEdge);
366: if (orientation == PlotOrientation.HORIZONTAL) {
367: double temp = j2DX;
368: j2DX = j2DY;
369: j2DY = temp;
370: }
371: double startX = j2DX + Math.cos(this.angle) * this.baseRadius;
372: double startY = j2DY + Math.sin(this.angle) * this.baseRadius;
373:
374: double endX = j2DX + Math.cos(this.angle) * this.tipRadius;
375: double endY = j2DY + Math.sin(this.angle) * this.tipRadius;
376:
377: double arrowBaseX = endX + Math.cos(this.angle) * this.arrowLength;
378: double arrowBaseY = endY + Math.sin(this.angle) * this.arrowLength;
379:
380: double arrowLeftX = arrowBaseX
381: + Math.cos(this.angle + Math.PI / 2.0) * this.arrowWidth;
382: double arrowLeftY = arrowBaseY
383: + Math.sin(this.angle + Math.PI / 2.0) * this.arrowWidth;
384:
385: double arrowRightX = arrowBaseX
386: - Math.cos(this.angle + Math.PI / 2.0) * this.arrowWidth;
387: double arrowRightY = arrowBaseY
388: - Math.sin(this.angle + Math.PI / 2.0) * this.arrowWidth;
389:
390: GeneralPath arrow = new GeneralPath();
391: arrow.moveTo((float) endX, (float) endY);
392: arrow.lineTo((float) arrowLeftX, (float) arrowLeftY);
393: arrow.lineTo((float) arrowRightX, (float) arrowRightY);
394: arrow.closePath();
395:
396: g2.setStroke(this.arrowStroke);
397: g2.setPaint(this.arrowPaint);
398: Line2D line = new Line2D.Double(startX, startY, endX, endY);
399: g2.draw(line);
400: g2.fill(arrow);
401:
402:
403: g2.setFont(getFont());
404: g2.setPaint(getPaint());
405: double labelX = j2DX
406: + Math.cos(this.angle) * (this.baseRadius + this.labelOffset);
407: double labelY = j2DY
408: + Math.sin(this.angle) * (this.baseRadius + this.labelOffset);
409: TextUtilities.drawAlignedString(getText(),
410: g2, (float) labelX, (float) labelY, getTextAnchor());
411:
412:
413: }
414:
415:
422: public boolean equals(Object obj) {
423:
424: if (obj == this) {
425: return true;
426: }
427: if (!(obj instanceof CategoryPointerAnnotation)) {
428: return false;
429: }
430: if (!super.equals(obj)) {
431: return false;
432: }
433: CategoryPointerAnnotation that = (CategoryPointerAnnotation) obj;
434: if (this.angle != that.angle) {
435: return false;
436: }
437: if (this.tipRadius != that.tipRadius) {
438: return false;
439: }
440: if (this.baseRadius != that.baseRadius) {
441: return false;
442: }
443: if (this.arrowLength != that.arrowLength) {
444: return false;
445: }
446: if (this.arrowWidth != that.arrowWidth) {
447: return false;
448: }
449: if (!this.arrowPaint.equals(that.arrowPaint)) {
450: return false;
451: }
452: if (!ObjectUtilities.equal(this.arrowStroke, that.arrowStroke)) {
453: return false;
454: }
455: if (this.labelOffset != that.labelOffset) {
456: return false;
457: }
458: return true;
459: }
460:
461:
466: public int hashCode() {
467: int result = 193;
468: long temp = Double.doubleToLongBits(this.angle);
469: result = 37 * result + (int) (temp ^ (temp >>> 32));
470: temp = Double.doubleToLongBits(this.tipRadius);
471: result = 37 * result + (int) (temp ^ (temp >>> 32));
472: temp = Double.doubleToLongBits(this.baseRadius);
473: result = 37 * result + (int) (temp ^ (temp >>> 32));
474: temp = Double.doubleToLongBits(this.arrowLength);
475: result = 37 * result + (int) (temp ^ (temp >>> 32));
476: temp = Double.doubleToLongBits(this.arrowWidth);
477: result = 37 * result + (int) (temp ^ (temp >>> 32));
478: result = 37 * result + HashUtilities.hashCodeForPaint(this.arrowPaint);
479: result = 37 * result + this.arrowStroke.hashCode();
480: temp = Double.doubleToLongBits(this.labelOffset);
481: result = 37 * result + (int) (temp ^ (temp >>> 32));
482: return result;
483: }
484:
485:
492: public Object clone() throws CloneNotSupportedException {
493: return super.clone();
494: }
495:
496:
503: private void writeObject(ObjectOutputStream stream) throws IOException {
504: stream.defaultWriteObject();
505: SerialUtilities.writePaint(this.arrowPaint, stream);
506: SerialUtilities.writeStroke(this.arrowStroke, stream);
507: }
508:
509:
517: private void readObject(ObjectInputStream stream)
518: throws IOException, ClassNotFoundException {
519: stream.defaultReadObject();
520: this.arrowPaint = SerialUtilities.readPaint(stream);
521: this.arrowStroke = SerialUtilities.readStroke(stream);
522: }
523:
524: }