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: notifyListeners(new RendererChangeEvent(this));
158: }
159:
160:
168: public void setYOffset(double yOffset) {
169: this.yOffset = yOffset;
170: notifyListeners(new RendererChangeEvent(this));
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: notifyListeners(new RendererChangeEvent(this));
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:
232: Paint backgroundPaint = plot.getBackgroundPaint();
233: if (backgroundPaint != null) {
234: g2.setPaint(backgroundPaint);
235: g2.fill(clip);
236: }
237:
238: GeneralPath leftWall = new GeneralPath();
239: leftWall.moveTo(x0, y0);
240: leftWall.lineTo(x0, y2);
241: leftWall.lineTo(x1, y3);
242: leftWall.lineTo(x1, y1);
243: leftWall.closePath();
244: g2.setPaint(getWallPaint());
245: g2.fill(leftWall);
246:
247: GeneralPath bottomWall = new GeneralPath();
248: bottomWall.moveTo(x0, y0);
249: bottomWall.lineTo(x1, y1);
250: bottomWall.lineTo(x3, y1);
251: bottomWall.lineTo(x2, y0);
252: bottomWall.closePath();
253: g2.setPaint(getWallPaint());
254: g2.fill(bottomWall);
255:
256:
257: g2.setPaint(Color.lightGray);
258: Line2D corner = new Line2D.Double(x0, y0, x1, y1);
259: g2.draw(corner);
260: corner.setLine(x1, y1, x1, y3);
261: g2.draw(corner);
262: corner.setLine(x1, y1, x3, y1);
263: g2.draw(corner);
264:
265:
266: Image backgroundImage = plot.getBackgroundImage();
267: if (backgroundImage != null) {
268: Composite originalComposite = g2.getComposite();
269: g2.setComposite(AlphaComposite.getInstance(
270: AlphaComposite.SRC, plot.getBackgroundAlpha()));
271: g2.drawImage(backgroundImage, (int) x1, (int) y3,
272: (int) (x3 - x1 + 1), (int) (y1 - y3 + 1), null);
273: g2.setComposite(originalComposite);
274: }
275:
276: }
277:
278:
285: public void drawOutline(Graphics2D g2, CategoryPlot plot,
286: Rectangle2D dataArea) {
287:
288: float x0 = (float) dataArea.getX();
289: float x1 = x0 + (float) Math.abs(this.xOffset);
290: float x3 = (float) dataArea.getMaxX();
291: float x2 = x3 - (float) Math.abs(this.xOffset);
292:
293: float y0 = (float) dataArea.getMaxY();
294: float y1 = y0 - (float) Math.abs(this.yOffset);
295: float y3 = (float) dataArea.getMinY();
296: float y2 = y3 + (float) Math.abs(this.yOffset);
297:
298: GeneralPath clip = new GeneralPath();
299: clip.moveTo(x0, y0);
300: clip.lineTo(x0, y2);
301: clip.lineTo(x1, y3);
302: clip.lineTo(x3, y3);
303: clip.lineTo(x3, y1);
304: clip.lineTo(x2, y0);
305: clip.closePath();
306:
307:
308: Stroke outlineStroke = plot.getOutlineStroke();
309: Paint outlinePaint = plot.getOutlinePaint();
310: if ((outlineStroke != null) && (outlinePaint != null)) {
311: g2.setStroke(outlineStroke);
312: g2.setPaint(outlinePaint);
313: g2.draw(clip);
314: }
315:
316: }
317:
318:
328: public void drawDomainGridline(Graphics2D g2,
329: CategoryPlot plot,
330: Rectangle2D dataArea,
331: double value) {
332:
333: Line2D line1 = null;
334: Line2D line2 = null;
335: PlotOrientation orientation = plot.getOrientation();
336: if (orientation == PlotOrientation.HORIZONTAL) {
337: double y0 = value;
338: double y1 = value - getYOffset();
339: double x0 = dataArea.getMinX();
340: double x1 = x0 + getXOffset();
341: double x2 = dataArea.getMaxX();
342: line1 = new Line2D.Double(x0, y0, x1, y1);
343: line2 = new Line2D.Double(x1, y1, x2, y1);
344: }
345: else if (orientation == PlotOrientation.VERTICAL) {
346: double x0 = value;
347: double x1 = value + getXOffset();
348: double y0 = dataArea.getMaxY();
349: double y1 = y0 - getYOffset();
350: double y2 = dataArea.getMinY();
351: line1 = new Line2D.Double(x0, y0, x1, y1);
352: line2 = new Line2D.Double(x1, y1, x1, y2);
353: }
354: g2.setPaint(plot.getDomainGridlinePaint());
355: g2.setStroke(plot.getDomainGridlineStroke());
356: g2.draw(line1);
357: g2.draw(line2);
358:
359: }
360:
361:
372: public void drawRangeGridline(Graphics2D g2,
373: CategoryPlot plot,
374: ValueAxis axis,
375: Rectangle2D dataArea,
376: double value) {
377:
378: Range range = axis.getRange();
379:
380: if (!range.contains(value)) {
381: return;
382: }
383:
384: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
385: dataArea.getY() + getYOffset(),
386: dataArea.getWidth() - getXOffset(),
387: dataArea.getHeight() - getYOffset());
388:
389: Line2D line1 = null;
390: Line2D line2 = null;
391: PlotOrientation orientation = plot.getOrientation();
392: if (orientation == PlotOrientation.HORIZONTAL) {
393: double x0 = axis.valueToJava2D(value, adjusted,
394: plot.getRangeAxisEdge());
395: double x1 = x0 + getXOffset();
396: double y0 = dataArea.getMaxY();
397: double y1 = y0 - getYOffset();
398: double y2 = dataArea.getMinY();
399: line1 = new Line2D.Double(x0, y0, x1, y1);
400: line2 = new Line2D.Double(x1, y1, x1, y2);
401: }
402: else if (orientation == PlotOrientation.VERTICAL) {
403: double y0 = axis.valueToJava2D(value, adjusted,
404: plot.getRangeAxisEdge());
405: double y1 = y0 - getYOffset();
406: double x0 = dataArea.getMinX();
407: double x1 = x0 + getXOffset();
408: double x2 = dataArea.getMaxX();
409: line1 = new Line2D.Double(x0, y0, x1, y1);
410: line2 = new Line2D.Double(x1, y1, x2, y1);
411: }
412: g2.setPaint(plot.getRangeGridlinePaint());
413: g2.setStroke(plot.getRangeGridlineStroke());
414: g2.draw(line1);
415: g2.draw(line2);
416:
417: }
418:
419:
428: public void drawRangeMarker(Graphics2D g2,
429: CategoryPlot plot,
430: ValueAxis axis,
431: Marker marker,
432: Rectangle2D dataArea) {
433:
434: if (marker instanceof ValueMarker) {
435: ValueMarker vm = (ValueMarker) marker;
436: double value = vm.getValue();
437: Range range = axis.getRange();
438: if (!range.contains(value)) {
439: return;
440: }
441:
442: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
443: dataArea.getY() + getYOffset(),
444: dataArea.getWidth() - getXOffset(),
445: dataArea.getHeight() - getYOffset());
446:
447: GeneralPath path = null;
448: PlotOrientation orientation = plot.getOrientation();
449: if (orientation == PlotOrientation.HORIZONTAL) {
450: float x = (float) axis.valueToJava2D(value, adjusted,
451: plot.getRangeAxisEdge());
452: float y = (float) adjusted.getMaxY();
453: path = new GeneralPath();
454: path.moveTo(x, y);
455: path.lineTo((float) (x + getXOffset()),
456: y - (float) getYOffset());
457: path.lineTo((float) (x + getXOffset()),
458: (float) (adjusted.getMinY() - getYOffset()));
459: path.lineTo(x, (float) adjusted.getMinY());
460: path.closePath();
461: }
462: else if (orientation == PlotOrientation.VERTICAL) {
463: float y = (float) axis.valueToJava2D(value, adjusted,
464: plot.getRangeAxisEdge());
465: float x = (float) dataArea.getX();
466: path = new GeneralPath();
467: path.moveTo(x, y);
468: path.lineTo(x + (float) this.xOffset, y - (float) this.yOffset);
469: path.lineTo((float) (adjusted.getMaxX() + this.xOffset),
470: y - (float) this.yOffset);
471: path.lineTo((float) (adjusted.getMaxX()), y);
472: path.closePath();
473: }
474: g2.setPaint(marker.getPaint());
475: g2.fill(path);
476: g2.setPaint(marker.getOutlinePaint());
477: g2.draw(path);
478: }
479: }
480:
481:
495: public void drawItem(Graphics2D g2,
496: CategoryItemRendererState state,
497: Rectangle2D dataArea,
498: CategoryPlot plot,
499: CategoryAxis domainAxis,
500: ValueAxis rangeAxis,
501: CategoryDataset dataset,
502: int row,
503: int column,
504: int pass) {
505:
506: if (!getItemVisible(row, column)) {
507: return;
508: }
509:
510:
511: Number v = dataset.getValue(row, column);
512: if (v == null) {
513: return;
514: }
515:
516: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
517: dataArea.getY() + getYOffset(),
518: dataArea.getWidth() - getXOffset(),
519: dataArea.getHeight() - getYOffset());
520:
521: PlotOrientation orientation = plot.getOrientation();
522:
523:
524: double x1 = domainAxis.getCategoryMiddle(column, getColumnCount(),
525: adjusted, plot.getDomainAxisEdge());
526: double value = v.doubleValue();
527: double y1 = rangeAxis.valueToJava2D(value, adjusted,
528: plot.getRangeAxisEdge());
529:
530: Shape shape = getItemShape(row, column);
531: if (orientation == PlotOrientation.HORIZONTAL) {
532: shape = ShapeUtilities.createTranslatedShape(shape, y1, x1);
533: }
534: else if (orientation == PlotOrientation.VERTICAL) {
535: shape = ShapeUtilities.createTranslatedShape(shape, x1, y1);
536: }
537:
538: if (getItemLineVisible(row, column)) {
539: if (column != 0) {
540:
541: Number previousValue = dataset.getValue(row, column - 1);
542: if (previousValue != null) {
543:
544:
545: double previous = previousValue.doubleValue();
546: double x0 = domainAxis.getCategoryMiddle(column - 1,
547: getColumnCount(), adjusted,
548: plot.getDomainAxisEdge());
549: double y0 = rangeAxis.valueToJava2D(previous, adjusted,
550: plot.getRangeAxisEdge());
551:
552: double x2 = x0 + getXOffset();
553: double y2 = y0 - getYOffset();
554: double x3 = x1 + getXOffset();
555: double y3 = y1 - getYOffset();
556:
557: GeneralPath clip = new GeneralPath();
558:
559: if (orientation == PlotOrientation.HORIZONTAL) {
560: clip.moveTo((float) y0, (float) x0);
561: clip.lineTo((float) y1, (float) x1);
562: clip.lineTo((float) y3, (float) x3);
563: clip.lineTo((float) y2, (float) x2);
564: clip.lineTo((float) y0, (float) x0);
565: clip.closePath();
566: }
567: else if (orientation == PlotOrientation.VERTICAL) {
568: clip.moveTo((float) x0, (float) y0);
569: clip.lineTo((float) x1, (float) y1);
570: clip.lineTo((float) x3, (float) y3);
571: clip.lineTo((float) x2, (float) y2);
572: clip.lineTo((float) x0, (float) y0);
573: clip.closePath();
574: }
575:
576: g2.setPaint(getItemPaint(row, column));
577: g2.fill(clip);
578: g2.setStroke(getItemOutlineStroke(row, column));
579: g2.setPaint(getItemOutlinePaint(row, column));
580: g2.draw(clip);
581: }
582: }
583: }
584:
585:
586: if (isItemLabelVisible(row, column)) {
587: drawItemLabel(g2, orientation, dataset, row, column, x1, y1,
588: (value < 0.0));
589: }
590:
591:
592: EntityCollection entities = state.getEntityCollection();
593: if (entities != null) {
594: addItemEntity(entities, dataset, row, column, shape);
595: }
596:
597: }
598:
599:
606: public boolean equals(Object obj) {
607: if (obj == this) {
608: return true;
609: }
610: if (!(obj instanceof LineRenderer3D)) {
611: return false;
612: }
613: LineRenderer3D that = (LineRenderer3D) obj;
614: if (this.xOffset != that.xOffset) {
615: return false;
616: }
617: if (this.yOffset != that.yOffset) {
618: return false;
619: }
620: if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
621: return false;
622: }
623: return super.equals(obj);
624: }
625:
626:
633: private void writeObject(ObjectOutputStream stream) throws IOException {
634: stream.defaultWriteObject();
635: SerialUtilities.writePaint(this.wallPaint, stream);
636: }
637:
638:
646: private void readObject(ObjectInputStream stream)
647: throws IOException, ClassNotFoundException {
648: stream.defaultReadObject();
649: this.wallPaint = SerialUtilities.readPaint(stream);
650: }
651:
652: }