1:
96:
97: package ;
98:
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112: import ;
113: import ;
114: import ;
115:
116: import ;
117: import ;
118: import ;
119: import ;
120: import ;
121: import ;
122: import ;
123: import ;
124: import ;
125: import ;
126: import ;
127: import ;
128: import ;
129: import ;
130: import ;
131: import ;
132: import ;
133: import ;
134: import ;
135: import ;
136: import ;
137: import ;
138: import ;
139: import ;
140:
141:
145: public class BarRenderer3D extends BarRenderer
146: implements Effect3D, Cloneable, PublicCloneable,
147: Serializable {
148:
149:
150: private static final long serialVersionUID = 7686976503536003636L;
151:
152:
153: public static final double DEFAULT_X_OFFSET = 12.0;
154:
155:
156: public static final double DEFAULT_Y_OFFSET = 8.0;
157:
158:
159: public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
160:
161:
162: private double xOffset;
163:
164:
165: private double yOffset;
166:
167:
168: private transient Paint wallPaint;
169:
170:
173: public BarRenderer3D() {
174: this(DEFAULT_X_OFFSET, DEFAULT_Y_OFFSET);
175: }
176:
177:
183: public BarRenderer3D(double xOffset, double yOffset) {
184:
185: super();
186: this.xOffset = xOffset;
187: this.yOffset = yOffset;
188: this.wallPaint = DEFAULT_WALL_PAINT;
189:
190: ItemLabelPosition p1 = new ItemLabelPosition(ItemLabelAnchor.INSIDE12,
191: TextAnchor.TOP_CENTER);
192: setPositiveItemLabelPosition(p1);
193: ItemLabelPosition p2 = new ItemLabelPosition(ItemLabelAnchor.INSIDE12,
194: TextAnchor.TOP_CENTER);
195: setNegativeItemLabelPosition(p2);
196:
197: }
198:
199:
206: public double getXOffset() {
207: return this.xOffset;
208: }
209:
210:
215: public double getYOffset() {
216: return this.yOffset;
217: }
218:
219:
227: public Paint getWallPaint() {
228: return this.wallPaint;
229: }
230:
231:
240: public void setWallPaint(Paint paint) {
241: if (paint == null) {
242: throw new IllegalArgumentException("Null 'paint' argument.");
243: }
244: this.wallPaint = paint;
245: notifyListeners(new RendererChangeEvent(this));
246: }
247:
248:
249:
262: public CategoryItemRendererState initialise(Graphics2D g2,
263: Rectangle2D dataArea,
264: CategoryPlot plot,
265: int rendererIndex,
266: PlotRenderingInfo info) {
267:
268: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
269: dataArea.getY() + getYOffset(), dataArea.getWidth()
270: - getXOffset(), dataArea.getHeight() - getYOffset());
271: CategoryItemRendererState state = super.initialise(g2, adjusted, plot,
272: rendererIndex, info);
273: return state;
274:
275: }
276:
277:
284: public void drawBackground(Graphics2D g2, CategoryPlot plot,
285: Rectangle2D dataArea) {
286:
287: float x0 = (float) dataArea.getX();
288: float x1 = x0 + (float) Math.abs(this.xOffset);
289: float x3 = (float) dataArea.getMaxX();
290: float x2 = x3 - (float) Math.abs(this.xOffset);
291:
292: float y0 = (float) dataArea.getMaxY();
293: float y1 = y0 - (float) Math.abs(this.yOffset);
294: float y3 = (float) dataArea.getMinY();
295: float y2 = y3 + (float) Math.abs(this.yOffset);
296:
297: GeneralPath clip = new GeneralPath();
298: clip.moveTo(x0, y0);
299: clip.lineTo(x0, y2);
300: clip.lineTo(x1, y3);
301: clip.lineTo(x3, y3);
302: clip.lineTo(x3, y1);
303: clip.lineTo(x2, y0);
304: clip.closePath();
305:
306:
307: Paint backgroundPaint = plot.getBackgroundPaint();
308: if (backgroundPaint != null) {
309: g2.setPaint(backgroundPaint);
310: g2.fill(clip);
311: }
312:
313: GeneralPath leftWall = new GeneralPath();
314: leftWall.moveTo(x0, y0);
315: leftWall.lineTo(x0, y2);
316: leftWall.lineTo(x1, y3);
317: leftWall.lineTo(x1, y1);
318: leftWall.closePath();
319: g2.setPaint(getWallPaint());
320: g2.fill(leftWall);
321:
322: GeneralPath bottomWall = new GeneralPath();
323: bottomWall.moveTo(x0, y0);
324: bottomWall.lineTo(x1, y1);
325: bottomWall.lineTo(x3, y1);
326: bottomWall.lineTo(x2, y0);
327: bottomWall.closePath();
328: g2.setPaint(getWallPaint());
329: g2.fill(bottomWall);
330:
331:
332: g2.setPaint(Color.lightGray);
333: Line2D corner = new Line2D.Double(x0, y0, x1, y1);
334: g2.draw(corner);
335: corner.setLine(x1, y1, x1, y3);
336: g2.draw(corner);
337: corner.setLine(x1, y1, x3, y1);
338: g2.draw(corner);
339:
340:
341: Image backgroundImage = plot.getBackgroundImage();
342: if (backgroundImage != null) {
343: Composite originalComposite = g2.getComposite();
344: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC,
345: plot.getBackgroundAlpha()));
346: g2.drawImage(backgroundImage, (int) x1, (int) y3,
347: (int) (x3 - x1 + 1), (int) (y1 - y3 + 1), null);
348: g2.setComposite(originalComposite);
349: }
350:
351: }
352:
353:
360: public void drawOutline(Graphics2D g2, CategoryPlot plot,
361: Rectangle2D dataArea) {
362:
363: float x0 = (float) dataArea.getX();
364: float x1 = x0 + (float) Math.abs(this.xOffset);
365: float x3 = (float) dataArea.getMaxX();
366: float x2 = x3 - (float) Math.abs(this.xOffset);
367:
368: float y0 = (float) dataArea.getMaxY();
369: float y1 = y0 - (float) Math.abs(this.yOffset);
370: float y3 = (float) dataArea.getMinY();
371: float y2 = y3 + (float) Math.abs(this.yOffset);
372:
373: GeneralPath clip = new GeneralPath();
374: clip.moveTo(x0, y0);
375: clip.lineTo(x0, y2);
376: clip.lineTo(x1, y3);
377: clip.lineTo(x3, y3);
378: clip.lineTo(x3, y1);
379: clip.lineTo(x2, y0);
380: clip.closePath();
381:
382:
383: Stroke outlineStroke = plot.getOutlineStroke();
384: Paint outlinePaint = plot.getOutlinePaint();
385: if ((outlineStroke != null) && (outlinePaint != null)) {
386: g2.setStroke(outlineStroke);
387: g2.setPaint(outlinePaint);
388: g2.draw(clip);
389: }
390:
391: }
392:
393:
403: public void drawDomainGridline(Graphics2D g2,
404: CategoryPlot plot,
405: Rectangle2D dataArea,
406: double value) {
407:
408: Line2D line1 = null;
409: Line2D line2 = null;
410: PlotOrientation orientation = plot.getOrientation();
411: if (orientation == PlotOrientation.HORIZONTAL) {
412: double y0 = value;
413: double y1 = value - getYOffset();
414: double x0 = dataArea.getMinX();
415: double x1 = x0 + getXOffset();
416: double x2 = dataArea.getMaxX();
417: line1 = new Line2D.Double(x0, y0, x1, y1);
418: line2 = new Line2D.Double(x1, y1, x2, y1);
419: }
420: else if (orientation == PlotOrientation.VERTICAL) {
421: double x0 = value;
422: double x1 = value + getXOffset();
423: double y0 = dataArea.getMaxY();
424: double y1 = y0 - getYOffset();
425: double y2 = dataArea.getMinY();
426: line1 = new Line2D.Double(x0, y0, x1, y1);
427: line2 = new Line2D.Double(x1, y1, x1, y2);
428: }
429: Paint paint = plot.getDomainGridlinePaint();
430: Stroke stroke = plot.getDomainGridlineStroke();
431: g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
432: g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
433: g2.draw(line1);
434: g2.draw(line2);
435:
436: }
437:
438:
449: public void drawRangeGridline(Graphics2D g2,
450: CategoryPlot plot,
451: ValueAxis axis,
452: Rectangle2D dataArea,
453: double value) {
454:
455: Range range = axis.getRange();
456:
457: if (!range.contains(value)) {
458: return;
459: }
460:
461: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
462: dataArea.getY() + getYOffset(), dataArea.getWidth()
463: - getXOffset(), dataArea.getHeight() - getYOffset());
464:
465: Line2D line1 = null;
466: Line2D line2 = null;
467: PlotOrientation orientation = plot.getOrientation();
468: if (orientation == PlotOrientation.HORIZONTAL) {
469: double x0 = axis.valueToJava2D(value, adjusted,
470: plot.getRangeAxisEdge());
471: double x1 = x0 + getXOffset();
472: double y0 = dataArea.getMaxY();
473: double y1 = y0 - getYOffset();
474: double y2 = dataArea.getMinY();
475: line1 = new Line2D.Double(x0, y0, x1, y1);
476: line2 = new Line2D.Double(x1, y1, x1, y2);
477: }
478: else if (orientation == PlotOrientation.VERTICAL) {
479: double y0 = axis.valueToJava2D(value, adjusted,
480: plot.getRangeAxisEdge());
481: double y1 = y0 - getYOffset();
482: double x0 = dataArea.getMinX();
483: double x1 = x0 + getXOffset();
484: double x2 = dataArea.getMaxX();
485: line1 = new Line2D.Double(x0, y0, x1, y1);
486: line2 = new Line2D.Double(x1, y1, x2, y1);
487: }
488: Paint paint = plot.getRangeGridlinePaint();
489: Stroke stroke = plot.getRangeGridlineStroke();
490: g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
491: g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
492: g2.draw(line1);
493: g2.draw(line2);
494:
495: }
496:
497:
506: public void drawRangeMarker(Graphics2D g2,
507: CategoryPlot plot,
508: ValueAxis axis,
509: Marker marker,
510: Rectangle2D dataArea) {
511:
512: if (marker instanceof ValueMarker) {
513: ValueMarker vm = (ValueMarker) marker;
514: double value = vm.getValue();
515: Range range = axis.getRange();
516: if (!range.contains(value)) {
517: return;
518: }
519:
520: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
521: dataArea.getY() + getYOffset(), dataArea.getWidth()
522: - getXOffset(), dataArea.getHeight() - getYOffset());
523:
524: GeneralPath path = null;
525: PlotOrientation orientation = plot.getOrientation();
526: if (orientation == PlotOrientation.HORIZONTAL) {
527: float x = (float) axis.valueToJava2D(value, adjusted,
528: plot.getRangeAxisEdge());
529: float y = (float) adjusted.getMaxY();
530: path = new GeneralPath();
531: path.moveTo(x, y);
532: path.lineTo((float) (x + getXOffset()),
533: y - (float) getYOffset());
534: path.lineTo((float) (x + getXOffset()),
535: (float) (adjusted.getMinY() - getYOffset()));
536: path.lineTo(x, (float) adjusted.getMinY());
537: path.closePath();
538: }
539: else if (orientation == PlotOrientation.VERTICAL) {
540: float y = (float) axis.valueToJava2D(value, adjusted,
541: plot.getRangeAxisEdge());
542: float x = (float) dataArea.getX();
543: path = new GeneralPath();
544: path.moveTo(x, y);
545: path.lineTo(x + (float) this.xOffset, y - (float) this.yOffset);
546: path.lineTo((float) (adjusted.getMaxX() + this.xOffset),
547: y - (float) this.yOffset);
548: path.lineTo((float) (adjusted.getMaxX()), y);
549: path.closePath();
550: }
551: g2.setPaint(marker.getPaint());
552: g2.fill(path);
553: g2.setPaint(marker.getOutlinePaint());
554: g2.draw(path);
555:
556: String label = marker.getLabel();
557: RectangleAnchor anchor = marker.getLabelAnchor();
558: if (label != null) {
559: Font labelFont = marker.getLabelFont();
560: g2.setFont(labelFont);
561: g2.setPaint(marker.getLabelPaint());
562: Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
563: g2, orientation, dataArea, path.getBounds2D(),
564: marker.getLabelOffset(), LengthAdjustmentType.EXPAND,
565: anchor);
566: TextUtilities.drawAlignedString(label, g2,
567: (float) coordinates.getX(), (float) coordinates.getY(),
568: marker.getLabelTextAnchor());
569: }
570:
571: }
572: else {
573: super.drawRangeMarker(g2, plot, axis, marker, dataArea);
574:
575: }
576: }
577:
578:
592: public void drawItem(Graphics2D g2,
593: CategoryItemRendererState state,
594: Rectangle2D dataArea,
595: CategoryPlot plot,
596: CategoryAxis domainAxis,
597: ValueAxis rangeAxis,
598: CategoryDataset dataset,
599: int row,
600: int column,
601: int pass) {
602:
603:
604: Number dataValue = dataset.getValue(row, column);
605: if (dataValue == null) {
606: return;
607: }
608:
609: double value = dataValue.doubleValue();
610:
611: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
612: dataArea.getY() + getYOffset(),
613: dataArea.getWidth() - getXOffset(),
614: dataArea.getHeight() - getYOffset());
615:
616: PlotOrientation orientation = plot.getOrientation();
617:
618: double barW0 = calculateBarW0(plot, orientation, adjusted, domainAxis,
619: state, row, column);
620: double[] barL0L1 = calculateBarL0L1(value);
621: if (barL0L1 == null) {
622: return;
623: }
624:
625: RectangleEdge edge = plot.getRangeAxisEdge();
626: double transL0 = rangeAxis.valueToJava2D(barL0L1[0], adjusted, edge);
627: double transL1 = rangeAxis.valueToJava2D(barL0L1[1], adjusted, edge);
628: double barL0 = Math.min(transL0, transL1);
629: double barLength = Math.abs(transL1 - transL0);
630:
631:
632: Rectangle2D bar = null;
633: if (orientation == PlotOrientation.HORIZONTAL) {
634: bar = new Rectangle2D.Double(barL0, barW0, barLength,
635: state.getBarWidth());
636: }
637: else {
638: bar = new Rectangle2D.Double(barW0, barL0, state.getBarWidth(),
639: barLength);
640: }
641: Paint itemPaint = getItemPaint(row, column);
642: g2.setPaint(itemPaint);
643: g2.fill(bar);
644:
645: double x0 = bar.getMinX();
646: double x1 = x0 + getXOffset();
647: double x2 = bar.getMaxX();
648: double x3 = x2 + getXOffset();
649:
650: double y0 = bar.getMinY() - getYOffset();
651: double y1 = bar.getMinY();
652: double y2 = bar.getMaxY() - getYOffset();
653: double y3 = bar.getMaxY();
654:
655: GeneralPath bar3dRight = null;
656: GeneralPath bar3dTop = null;
657: if (barLength > 0.0) {
658: bar3dRight = new GeneralPath();
659: bar3dRight.moveTo((float) x2, (float) y3);
660: bar3dRight.lineTo((float) x2, (float) y1);
661: bar3dRight.lineTo((float) x3, (float) y0);
662: bar3dRight.lineTo((float) x3, (float) y2);
663: bar3dRight.closePath();
664:
665: if (itemPaint instanceof Color) {
666: g2.setPaint(((Color) itemPaint).darker());
667: }
668: g2.fill(bar3dRight);
669: }
670:
671: bar3dTop = new GeneralPath();
672: bar3dTop.moveTo((float) x0, (float) y1);
673: bar3dTop.lineTo((float) x1, (float) y0);
674: bar3dTop.lineTo((float) x3, (float) y0);
675: bar3dTop.lineTo((float) x2, (float) y1);
676: bar3dTop.closePath();
677: g2.fill(bar3dTop);
678:
679: if (isDrawBarOutline()
680: && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
681: g2.setStroke(getItemOutlineStroke(row, column));
682: g2.setPaint(getItemOutlinePaint(row, column));
683: g2.draw(bar);
684: if (bar3dRight != null) {
685: g2.draw(bar3dRight);
686: }
687: if (bar3dTop != null) {
688: g2.draw(bar3dTop);
689: }
690: }
691:
692: CategoryItemLabelGenerator generator
693: = getItemLabelGenerator(row, column);
694: if (generator != null && isItemLabelVisible(row, column)) {
695: drawItemLabel(g2, dataset, row, column, plot, generator, bar,
696: (value < 0.0));
697: }
698:
699:
700: EntityCollection entities = state.getEntityCollection();
701: if (entities != null) {
702: GeneralPath barOutline = new GeneralPath();
703: barOutline.moveTo((float) x0, (float) y3);
704: barOutline.lineTo((float) x0, (float) y1);
705: barOutline.lineTo((float) x1, (float) y0);
706: barOutline.lineTo((float) x3, (float) y0);
707: barOutline.lineTo((float) x3, (float) y2);
708: barOutline.lineTo((float) x2, (float) y3);
709: barOutline.closePath();
710: addItemEntity(entities, dataset, row, column, barOutline);
711: }
712:
713: }
714:
715:
722: public boolean equals(Object obj) {
723: if (obj == this) {
724: return true;
725: }
726: if (!(obj instanceof BarRenderer3D)) {
727: return false;
728: }
729: BarRenderer3D that = (BarRenderer3D) obj;
730: if (this.xOffset != that.xOffset) {
731: return false;
732: }
733: if (this.yOffset != that.yOffset) {
734: return false;
735: }
736: if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
737: return false;
738: }
739: return super.equals(obj);
740: }
741:
742:
749: private void writeObject(ObjectOutputStream stream) throws IOException {
750: stream.defaultWriteObject();
751: SerialUtilities.writePaint(this.wallPaint, stream);
752: }
753:
754:
762: private void readObject(ObjectInputStream stream)
763: throws IOException, ClassNotFoundException {
764: stream.defaultReadObject();
765: this.wallPaint = SerialUtilities.readPaint(stream);
766: }
767:
768: }