1:
52:
53: package ;
54:
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: import ;
68: import ;
69: import ;
70:
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85:
86:
89: public class LineRenderer3D extends LineAndShapeRenderer
90: implements Effect3D, Serializable {
91:
92:
93: private static final long serialVersionUID = 5467931468380928736L;
94:
95:
96: public static final double DEFAULT_X_OFFSET = 12.0;
97:
98:
99: public static final double DEFAULT_Y_OFFSET = 8.0;
100:
101:
102: public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
103:
104:
105: private double xOffset;
106:
107:
108: private double yOffset;
109:
110:
111: private transient Paint wallPaint;
112:
113:
116: public LineRenderer3D() {
117: super(true, false);
118: this.xOffset = DEFAULT_X_OFFSET;
119: this.yOffset = DEFAULT_Y_OFFSET;
120: this.wallPaint = DEFAULT_WALL_PAINT;
121: }
122:
123:
131: public double getXOffset() {
132: return this.xOffset;
133: }
134:
135:
143: public double getYOffset() {
144: return this.yOffset;
145: }
146:
147:
155: public void setXOffset(double xOffset) {
156: this.xOffset = xOffset;
157: fireChangeEvent();
158: }
159:
160:
168: public void setYOffset(double yOffset) {
169: this.yOffset = yOffset;
170: fireChangeEvent();
171: }
172:
173:
181: public Paint getWallPaint() {
182: return this.wallPaint;
183: }
184:
185:
194: public void setWallPaint(Paint paint) {
195: if (paint == null) {
196: throw new IllegalArgumentException("Null 'paint' argument.");
197: }
198: this.wallPaint = paint;
199: fireChangeEvent();
200: }
201:
202:
209: public void drawBackground(Graphics2D g2, CategoryPlot plot,
210: Rectangle2D dataArea) {
211:
212: float x0 = (float) dataArea.getX();
213: float x1 = x0 + (float) Math.abs(this.xOffset);
214: float x3 = (float) dataArea.getMaxX();
215: float x2 = x3 - (float) Math.abs(this.xOffset);
216:
217: float y0 = (float) dataArea.getMaxY();
218: float y1 = y0 - (float) Math.abs(this.yOffset);
219: float y3 = (float) dataArea.getMinY();
220: float y2 = y3 + (float) Math.abs(this.yOffset);
221:
222: GeneralPath clip = new GeneralPath();
223: clip.moveTo(x0, y0);
224: clip.lineTo(x0, y2);
225: clip.lineTo(x1, y3);
226: clip.lineTo(x3, y3);
227: clip.lineTo(x3, y1);
228: clip.lineTo(x2, y0);
229: clip.closePath();
230:
231: Composite originalComposite = g2.getComposite();
232: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
233: plot.getBackgroundAlpha()));
234:
235:
236: Paint backgroundPaint = plot.getBackgroundPaint();
237: if (backgroundPaint != null) {
238: g2.setPaint(backgroundPaint);
239: g2.fill(clip);
240: }
241:
242: GeneralPath leftWall = new GeneralPath();
243: leftWall.moveTo(x0, y0);
244: leftWall.lineTo(x0, y2);
245: leftWall.lineTo(x1, y3);
246: leftWall.lineTo(x1, y1);
247: leftWall.closePath();
248: g2.setPaint(getWallPaint());
249: g2.fill(leftWall);
250:
251: GeneralPath bottomWall = new GeneralPath();
252: bottomWall.moveTo(x0, y0);
253: bottomWall.lineTo(x1, y1);
254: bottomWall.lineTo(x3, y1);
255: bottomWall.lineTo(x2, y0);
256: bottomWall.closePath();
257: g2.setPaint(getWallPaint());
258: g2.fill(bottomWall);
259:
260:
261: g2.setPaint(Color.lightGray);
262: Line2D corner = new Line2D.Double(x0, y0, x1, y1);
263: g2.draw(corner);
264: corner.setLine(x1, y1, x1, y3);
265: g2.draw(corner);
266: corner.setLine(x1, y1, x3, y1);
267: g2.draw(corner);
268:
269:
270: Image backgroundImage = plot.getBackgroundImage();
271: if (backgroundImage != null) {
272: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX()
273: + getXOffset(), dataArea.getY(),
274: dataArea.getWidth() - getXOffset(),
275: dataArea.getHeight() - getYOffset());
276: plot.drawBackgroundImage(g2, adjusted);
277: }
278:
279: g2.setComposite(originalComposite);
280:
281: }
282:
283:
290: public void drawOutline(Graphics2D g2, CategoryPlot plot,
291: Rectangle2D dataArea) {
292:
293: float x0 = (float) dataArea.getX();
294: float x1 = x0 + (float) Math.abs(this.xOffset);
295: float x3 = (float) dataArea.getMaxX();
296: float x2 = x3 - (float) Math.abs(this.xOffset);
297:
298: float y0 = (float) dataArea.getMaxY();
299: float y1 = y0 - (float) Math.abs(this.yOffset);
300: float y3 = (float) dataArea.getMinY();
301: float y2 = y3 + (float) Math.abs(this.yOffset);
302:
303: GeneralPath clip = new GeneralPath();
304: clip.moveTo(x0, y0);
305: clip.lineTo(x0, y2);
306: clip.lineTo(x1, y3);
307: clip.lineTo(x3, y3);
308: clip.lineTo(x3, y1);
309: clip.lineTo(x2, y0);
310: clip.closePath();
311:
312:
313: Stroke outlineStroke = plot.getOutlineStroke();
314: Paint outlinePaint = plot.getOutlinePaint();
315: if ((outlineStroke != null) && (outlinePaint != null)) {
316: g2.setStroke(outlineStroke);
317: g2.setPaint(outlinePaint);
318: g2.draw(clip);
319: }
320:
321: }
322:
323:
333: public void drawDomainGridline(Graphics2D g2,
334: CategoryPlot plot,
335: Rectangle2D dataArea,
336: double value) {
337:
338: Line2D line1 = null;
339: Line2D line2 = null;
340: PlotOrientation orientation = plot.getOrientation();
341: if (orientation == PlotOrientation.HORIZONTAL) {
342: double y0 = value;
343: double y1 = value - getYOffset();
344: double x0 = dataArea.getMinX();
345: double x1 = x0 + getXOffset();
346: double x2 = dataArea.getMaxX();
347: line1 = new Line2D.Double(x0, y0, x1, y1);
348: line2 = new Line2D.Double(x1, y1, x2, y1);
349: }
350: else if (orientation == PlotOrientation.VERTICAL) {
351: double x0 = value;
352: double x1 = value + getXOffset();
353: double y0 = dataArea.getMaxY();
354: double y1 = y0 - getYOffset();
355: double y2 = dataArea.getMinY();
356: line1 = new Line2D.Double(x0, y0, x1, y1);
357: line2 = new Line2D.Double(x1, y1, x1, y2);
358: }
359: g2.setPaint(plot.getDomainGridlinePaint());
360: g2.setStroke(plot.getDomainGridlineStroke());
361: g2.draw(line1);
362: g2.draw(line2);
363:
364: }
365:
366:
377: public void drawRangeGridline(Graphics2D g2,
378: CategoryPlot plot,
379: ValueAxis axis,
380: Rectangle2D dataArea,
381: double value) {
382:
383: Range range = axis.getRange();
384:
385: if (!range.contains(value)) {
386: return;
387: }
388:
389: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
390: dataArea.getY() + getYOffset(),
391: dataArea.getWidth() - getXOffset(),
392: dataArea.getHeight() - getYOffset());
393:
394: Line2D line1 = null;
395: Line2D line2 = null;
396: PlotOrientation orientation = plot.getOrientation();
397: if (orientation == PlotOrientation.HORIZONTAL) {
398: double x0 = axis.valueToJava2D(value, adjusted,
399: plot.getRangeAxisEdge());
400: double x1 = x0 + getXOffset();
401: double y0 = dataArea.getMaxY();
402: double y1 = y0 - getYOffset();
403: double y2 = dataArea.getMinY();
404: line1 = new Line2D.Double(x0, y0, x1, y1);
405: line2 = new Line2D.Double(x1, y1, x1, y2);
406: }
407: else if (orientation == PlotOrientation.VERTICAL) {
408: double y0 = axis.valueToJava2D(value, adjusted,
409: plot.getRangeAxisEdge());
410: double y1 = y0 - getYOffset();
411: double x0 = dataArea.getMinX();
412: double x1 = x0 + getXOffset();
413: double x2 = dataArea.getMaxX();
414: line1 = new Line2D.Double(x0, y0, x1, y1);
415: line2 = new Line2D.Double(x1, y1, x2, y1);
416: }
417: g2.setPaint(plot.getRangeGridlinePaint());
418: g2.setStroke(plot.getRangeGridlineStroke());
419: g2.draw(line1);
420: g2.draw(line2);
421:
422: }
423:
424:
433: public void drawRangeMarker(Graphics2D g2,
434: CategoryPlot plot,
435: ValueAxis axis,
436: Marker marker,
437: Rectangle2D dataArea) {
438:
439: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
440: dataArea.getY() + getYOffset(),
441: dataArea.getWidth() - getXOffset(),
442: dataArea.getHeight() - getYOffset());
443:
444: if (marker instanceof ValueMarker) {
445: ValueMarker vm = (ValueMarker) marker;
446: double value = vm.getValue();
447: Range range = axis.getRange();
448: if (!range.contains(value)) {
449: return;
450: }
451:
452: GeneralPath path = null;
453: PlotOrientation orientation = plot.getOrientation();
454: if (orientation == PlotOrientation.HORIZONTAL) {
455: float x = (float) axis.valueToJava2D(value, adjusted,
456: plot.getRangeAxisEdge());
457: float y = (float) adjusted.getMaxY();
458: path = new GeneralPath();
459: path.moveTo(x, y);
460: path.lineTo((float) (x + getXOffset()),
461: y - (float) getYOffset());
462: path.lineTo((float) (x + getXOffset()),
463: (float) (adjusted.getMinY() - getYOffset()));
464: path.lineTo(x, (float) adjusted.getMinY());
465: path.closePath();
466: }
467: else if (orientation == PlotOrientation.VERTICAL) {
468: float y = (float) axis.valueToJava2D(value, adjusted,
469: plot.getRangeAxisEdge());
470: float x = (float) dataArea.getX();
471: path = new GeneralPath();
472: path.moveTo(x, y);
473: path.lineTo(x + (float) this.xOffset, y - (float) this.yOffset);
474: path.lineTo((float) (adjusted.getMaxX() + this.xOffset),
475: y - (float) this.yOffset);
476: path.lineTo((float) (adjusted.getMaxX()), y);
477: path.closePath();
478: }
479: g2.setPaint(marker.getPaint());
480: g2.fill(path);
481: g2.setPaint(marker.getOutlinePaint());
482: g2.draw(path);
483: }
484: else {
485: super.drawRangeMarker(g2, plot, axis, marker, adjusted);
486:
487: }
488: }
489:
490:
504: public void drawItem(Graphics2D g2,
505: CategoryItemRendererState state,
506: Rectangle2D dataArea,
507: CategoryPlot plot,
508: CategoryAxis domainAxis,
509: ValueAxis rangeAxis,
510: CategoryDataset dataset,
511: int row,
512: int column,
513: int pass) {
514:
515: if (!getItemVisible(row, column)) {
516: return;
517: }
518:
519:
520: Number v = dataset.getValue(row, column);
521: if (v == null) {
522: return;
523: }
524:
525: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
526: dataArea.getY() + getYOffset(),
527: dataArea.getWidth() - getXOffset(),
528: dataArea.getHeight() - getYOffset());
529:
530: PlotOrientation orientation = plot.getOrientation();
531:
532:
533: double x1 = domainAxis.getCategoryMiddle(column, getColumnCount(),
534: adjusted, plot.getDomainAxisEdge());
535: double value = v.doubleValue();
536: double y1 = rangeAxis.valueToJava2D(value, adjusted,
537: plot.getRangeAxisEdge());
538:
539: Shape shape = getItemShape(row, column);
540: if (orientation == PlotOrientation.HORIZONTAL) {
541: shape = ShapeUtilities.createTranslatedShape(shape, y1, x1);
542: }
543: else if (orientation == PlotOrientation.VERTICAL) {
544: shape = ShapeUtilities.createTranslatedShape(shape, x1, y1);
545: }
546:
547: if (getItemLineVisible(row, column)) {
548: if (column != 0) {
549:
550: Number previousValue = dataset.getValue(row, column - 1);
551: if (previousValue != null) {
552:
553:
554: double previous = previousValue.doubleValue();
555: double x0 = domainAxis.getCategoryMiddle(column - 1,
556: getColumnCount(), adjusted,
557: plot.getDomainAxisEdge());
558: double y0 = rangeAxis.valueToJava2D(previous, adjusted,
559: plot.getRangeAxisEdge());
560:
561: double x2 = x0 + getXOffset();
562: double y2 = y0 - getYOffset();
563: double x3 = x1 + getXOffset();
564: double y3 = y1 - getYOffset();
565:
566: GeneralPath clip = new GeneralPath();
567:
568: if (orientation == PlotOrientation.HORIZONTAL) {
569: clip.moveTo((float) y0, (float) x0);
570: clip.lineTo((float) y1, (float) x1);
571: clip.lineTo((float) y3, (float) x3);
572: clip.lineTo((float) y2, (float) x2);
573: clip.lineTo((float) y0, (float) x0);
574: clip.closePath();
575: }
576: else if (orientation == PlotOrientation.VERTICAL) {
577: clip.moveTo((float) x0, (float) y0);
578: clip.lineTo((float) x1, (float) y1);
579: clip.lineTo((float) x3, (float) y3);
580: clip.lineTo((float) x2, (float) y2);
581: clip.lineTo((float) x0, (float) y0);
582: clip.closePath();
583: }
584:
585: g2.setPaint(getItemPaint(row, column));
586: g2.fill(clip);
587: g2.setStroke(getItemOutlineStroke(row, column));
588: g2.setPaint(getItemOutlinePaint(row, column));
589: g2.draw(clip);
590: }
591: }
592: }
593:
594:
595: if (isItemLabelVisible(row, column)) {
596: drawItemLabel(g2, orientation, dataset, row, column, x1, y1,
597: (value < 0.0));
598: }
599:
600:
601: EntityCollection entities = state.getEntityCollection();
602: if (entities != null) {
603: addItemEntity(entities, dataset, row, column, shape);
604: }
605:
606: }
607:
608:
615: public boolean equals(Object obj) {
616: if (obj == this) {
617: return true;
618: }
619: if (!(obj instanceof LineRenderer3D)) {
620: return false;
621: }
622: LineRenderer3D that = (LineRenderer3D) obj;
623: if (this.xOffset != that.xOffset) {
624: return false;
625: }
626: if (this.yOffset != that.yOffset) {
627: return false;
628: }
629: if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
630: return false;
631: }
632: return super.equals(obj);
633: }
634:
635:
642: private void writeObject(ObjectOutputStream stream) throws IOException {
643: stream.defaultWriteObject();
644: SerialUtilities.writePaint(this.wallPaint, stream);
645: }
646:
647:
655: private void readObject(ObjectInputStream stream)
656: throws IOException, ClassNotFoundException {
657: stream.defaultReadObject();
658: this.wallPaint = SerialUtilities.readPaint(stream);
659: }
660:
661: }