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: setBasePositiveItemLabelPosition(p1);
193: ItemLabelPosition p2 = new ItemLabelPosition(ItemLabelAnchor.INSIDE12,
194: TextAnchor.TOP_CENTER);
195: setBaseNegativeItemLabelPosition(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: Composite originalComposite = g2.getComposite();
307: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
308: plot.getBackgroundAlpha()));
309:
310:
311: Paint backgroundPaint = plot.getBackgroundPaint();
312: if (backgroundPaint != null) {
313: g2.setPaint(backgroundPaint);
314: g2.fill(clip);
315: }
316:
317: GeneralPath leftWall = new GeneralPath();
318: leftWall.moveTo(x0, y0);
319: leftWall.lineTo(x0, y2);
320: leftWall.lineTo(x1, y3);
321: leftWall.lineTo(x1, y1);
322: leftWall.closePath();
323: g2.setPaint(getWallPaint());
324: g2.fill(leftWall);
325:
326: GeneralPath bottomWall = new GeneralPath();
327: bottomWall.moveTo(x0, y0);
328: bottomWall.lineTo(x1, y1);
329: bottomWall.lineTo(x3, y1);
330: bottomWall.lineTo(x2, y0);
331: bottomWall.closePath();
332: g2.setPaint(getWallPaint());
333: g2.fill(bottomWall);
334:
335:
336: g2.setPaint(Color.lightGray);
337: Line2D corner = new Line2D.Double(x0, y0, x1, y1);
338: g2.draw(corner);
339: corner.setLine(x1, y1, x1, y3);
340: g2.draw(corner);
341: corner.setLine(x1, y1, x3, y1);
342: g2.draw(corner);
343:
344:
345: Image backgroundImage = plot.getBackgroundImage();
346: if (backgroundImage != null) {
347: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX()
348: + getXOffset(), dataArea.getY(),
349: dataArea.getWidth() - getXOffset(),
350: dataArea.getHeight() - getYOffset());
351: plot.drawBackgroundImage(g2, adjusted);
352: }
353:
354: g2.setComposite(originalComposite);
355:
356: }
357:
358:
365: public void drawOutline(Graphics2D g2, CategoryPlot plot,
366: Rectangle2D dataArea) {
367:
368: float x0 = (float) dataArea.getX();
369: float x1 = x0 + (float) Math.abs(this.xOffset);
370: float x3 = (float) dataArea.getMaxX();
371: float x2 = x3 - (float) Math.abs(this.xOffset);
372:
373: float y0 = (float) dataArea.getMaxY();
374: float y1 = y0 - (float) Math.abs(this.yOffset);
375: float y3 = (float) dataArea.getMinY();
376: float y2 = y3 + (float) Math.abs(this.yOffset);
377:
378: GeneralPath clip = new GeneralPath();
379: clip.moveTo(x0, y0);
380: clip.lineTo(x0, y2);
381: clip.lineTo(x1, y3);
382: clip.lineTo(x3, y3);
383: clip.lineTo(x3, y1);
384: clip.lineTo(x2, y0);
385: clip.closePath();
386:
387:
388: Stroke outlineStroke = plot.getOutlineStroke();
389: Paint outlinePaint = plot.getOutlinePaint();
390: if ((outlineStroke != null) && (outlinePaint != null)) {
391: g2.setStroke(outlineStroke);
392: g2.setPaint(outlinePaint);
393: g2.draw(clip);
394: }
395:
396: }
397:
398:
408: public void drawDomainGridline(Graphics2D g2,
409: CategoryPlot plot,
410: Rectangle2D dataArea,
411: double value) {
412:
413: Line2D line1 = null;
414: Line2D line2 = null;
415: PlotOrientation orientation = plot.getOrientation();
416: if (orientation == PlotOrientation.HORIZONTAL) {
417: double y0 = value;
418: double y1 = value - getYOffset();
419: double x0 = dataArea.getMinX();
420: double x1 = x0 + getXOffset();
421: double x2 = dataArea.getMaxX();
422: line1 = new Line2D.Double(x0, y0, x1, y1);
423: line2 = new Line2D.Double(x1, y1, x2, y1);
424: }
425: else if (orientation == PlotOrientation.VERTICAL) {
426: double x0 = value;
427: double x1 = value + getXOffset();
428: double y0 = dataArea.getMaxY();
429: double y1 = y0 - getYOffset();
430: double y2 = dataArea.getMinY();
431: line1 = new Line2D.Double(x0, y0, x1, y1);
432: line2 = new Line2D.Double(x1, y1, x1, y2);
433: }
434: Paint paint = plot.getDomainGridlinePaint();
435: Stroke stroke = plot.getDomainGridlineStroke();
436: g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
437: g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
438: g2.draw(line1);
439: g2.draw(line2);
440:
441: }
442:
443:
454: public void drawRangeGridline(Graphics2D g2,
455: CategoryPlot plot,
456: ValueAxis axis,
457: Rectangle2D dataArea,
458: double value) {
459:
460: Range range = axis.getRange();
461:
462: if (!range.contains(value)) {
463: return;
464: }
465:
466: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
467: dataArea.getY() + getYOffset(), dataArea.getWidth()
468: - getXOffset(), dataArea.getHeight() - getYOffset());
469:
470: Line2D line1 = null;
471: Line2D line2 = null;
472: PlotOrientation orientation = plot.getOrientation();
473: if (orientation == PlotOrientation.HORIZONTAL) {
474: double x0 = axis.valueToJava2D(value, adjusted,
475: plot.getRangeAxisEdge());
476: double x1 = x0 + getXOffset();
477: double y0 = dataArea.getMaxY();
478: double y1 = y0 - getYOffset();
479: double y2 = dataArea.getMinY();
480: line1 = new Line2D.Double(x0, y0, x1, y1);
481: line2 = new Line2D.Double(x1, y1, x1, y2);
482: }
483: else if (orientation == PlotOrientation.VERTICAL) {
484: double y0 = axis.valueToJava2D(value, adjusted,
485: plot.getRangeAxisEdge());
486: double y1 = y0 - getYOffset();
487: double x0 = dataArea.getMinX();
488: double x1 = x0 + getXOffset();
489: double x2 = dataArea.getMaxX();
490: line1 = new Line2D.Double(x0, y0, x1, y1);
491: line2 = new Line2D.Double(x1, y1, x2, y1);
492: }
493: Paint paint = plot.getRangeGridlinePaint();
494: Stroke stroke = plot.getRangeGridlineStroke();
495: g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
496: g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
497: g2.draw(line1);
498: g2.draw(line2);
499:
500: }
501:
502:
511: public void drawRangeMarker(Graphics2D g2,
512: CategoryPlot plot,
513: ValueAxis axis,
514: Marker marker,
515: Rectangle2D dataArea) {
516:
517:
518: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
519: dataArea.getY() + getYOffset(), dataArea.getWidth()
520: - getXOffset(), dataArea.getHeight() - getYOffset());
521: if (marker instanceof ValueMarker) {
522: ValueMarker vm = (ValueMarker) marker;
523: double value = vm.getValue();
524: Range range = axis.getRange();
525: if (!range.contains(value)) {
526: return;
527: }
528:
529: GeneralPath path = null;
530: PlotOrientation orientation = plot.getOrientation();
531: if (orientation == PlotOrientation.HORIZONTAL) {
532: float x = (float) axis.valueToJava2D(value, adjusted,
533: plot.getRangeAxisEdge());
534: float y = (float) adjusted.getMaxY();
535: path = new GeneralPath();
536: path.moveTo(x, y);
537: path.lineTo((float) (x + getXOffset()),
538: y - (float) getYOffset());
539: path.lineTo((float) (x + getXOffset()),
540: (float) (adjusted.getMinY() - getYOffset()));
541: path.lineTo(x, (float) adjusted.getMinY());
542: path.closePath();
543: }
544: else if (orientation == PlotOrientation.VERTICAL) {
545: float y = (float) axis.valueToJava2D(value, adjusted,
546: plot.getRangeAxisEdge());
547: float x = (float) dataArea.getX();
548: path = new GeneralPath();
549: path.moveTo(x, y);
550: path.lineTo(x + (float) this.xOffset, y - (float) this.yOffset);
551: path.lineTo((float) (adjusted.getMaxX() + this.xOffset),
552: y - (float) this.yOffset);
553: path.lineTo((float) (adjusted.getMaxX()), y);
554: path.closePath();
555: }
556: g2.setPaint(marker.getPaint());
557: g2.fill(path);
558: g2.setPaint(marker.getOutlinePaint());
559: g2.draw(path);
560:
561: String label = marker.getLabel();
562: RectangleAnchor anchor = marker.getLabelAnchor();
563: if (label != null) {
564: Font labelFont = marker.getLabelFont();
565: g2.setFont(labelFont);
566: g2.setPaint(marker.getLabelPaint());
567: Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
568: g2, orientation, dataArea, path.getBounds2D(),
569: marker.getLabelOffset(), LengthAdjustmentType.EXPAND,
570: anchor);
571: TextUtilities.drawAlignedString(label, g2,
572: (float) coordinates.getX(), (float) coordinates.getY(),
573: marker.getLabelTextAnchor());
574: }
575:
576: }
577: else {
578: super.drawRangeMarker(g2, plot, axis, marker, adjusted);
579:
580: }
581: }
582:
583:
597: public void drawItem(Graphics2D g2,
598: CategoryItemRendererState state,
599: Rectangle2D dataArea,
600: CategoryPlot plot,
601: CategoryAxis domainAxis,
602: ValueAxis rangeAxis,
603: CategoryDataset dataset,
604: int row,
605: int column,
606: int pass) {
607:
608:
609: Number dataValue = dataset.getValue(row, column);
610: if (dataValue == null) {
611: return;
612: }
613:
614: double value = dataValue.doubleValue();
615:
616: Rectangle2D adjusted = new Rectangle2D.Double(dataArea.getX(),
617: dataArea.getY() + getYOffset(),
618: dataArea.getWidth() - getXOffset(),
619: dataArea.getHeight() - getYOffset());
620:
621: PlotOrientation orientation = plot.getOrientation();
622:
623: double barW0 = calculateBarW0(plot, orientation, adjusted, domainAxis,
624: state, row, column);
625: double[] barL0L1 = calculateBarL0L1(value);
626: if (barL0L1 == null) {
627: return;
628: }
629:
630: RectangleEdge edge = plot.getRangeAxisEdge();
631: double transL0 = rangeAxis.valueToJava2D(barL0L1[0], adjusted, edge);
632: double transL1 = rangeAxis.valueToJava2D(barL0L1[1], adjusted, edge);
633: double barL0 = Math.min(transL0, transL1);
634: double barLength = Math.abs(transL1 - transL0);
635:
636:
637: Rectangle2D bar = null;
638: if (orientation == PlotOrientation.HORIZONTAL) {
639: bar = new Rectangle2D.Double(barL0, barW0, barLength,
640: state.getBarWidth());
641: }
642: else {
643: bar = new Rectangle2D.Double(barW0, barL0, state.getBarWidth(),
644: barLength);
645: }
646: Paint itemPaint = getItemPaint(row, column);
647: g2.setPaint(itemPaint);
648: g2.fill(bar);
649:
650: double x0 = bar.getMinX();
651: double x1 = x0 + getXOffset();
652: double x2 = bar.getMaxX();
653: double x3 = x2 + getXOffset();
654:
655: double y0 = bar.getMinY() - getYOffset();
656: double y1 = bar.getMinY();
657: double y2 = bar.getMaxY() - getYOffset();
658: double y3 = bar.getMaxY();
659:
660: GeneralPath bar3dRight = null;
661: GeneralPath bar3dTop = null;
662: if (barLength > 0.0) {
663: bar3dRight = new GeneralPath();
664: bar3dRight.moveTo((float) x2, (float) y3);
665: bar3dRight.lineTo((float) x2, (float) y1);
666: bar3dRight.lineTo((float) x3, (float) y0);
667: bar3dRight.lineTo((float) x3, (float) y2);
668: bar3dRight.closePath();
669:
670: if (itemPaint instanceof Color) {
671: g2.setPaint(((Color) itemPaint).darker());
672: }
673: g2.fill(bar3dRight);
674: }
675:
676: bar3dTop = new GeneralPath();
677: bar3dTop.moveTo((float) x0, (float) y1);
678: bar3dTop.lineTo((float) x1, (float) y0);
679: bar3dTop.lineTo((float) x3, (float) y0);
680: bar3dTop.lineTo((float) x2, (float) y1);
681: bar3dTop.closePath();
682: g2.fill(bar3dTop);
683:
684: if (isDrawBarOutline()
685: && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
686: g2.setStroke(getItemOutlineStroke(row, column));
687: g2.setPaint(getItemOutlinePaint(row, column));
688: g2.draw(bar);
689: if (bar3dRight != null) {
690: g2.draw(bar3dRight);
691: }
692: if (bar3dTop != null) {
693: g2.draw(bar3dTop);
694: }
695: }
696:
697: CategoryItemLabelGenerator generator
698: = getItemLabelGenerator(row, column);
699: if (generator != null && isItemLabelVisible(row, column)) {
700: drawItemLabel(g2, dataset, row, column, plot, generator, bar,
701: (value < 0.0));
702: }
703:
704:
705: EntityCollection entities = state.getEntityCollection();
706: if (entities != null) {
707: GeneralPath barOutline = new GeneralPath();
708: barOutline.moveTo((float) x0, (float) y3);
709: barOutline.lineTo((float) x0, (float) y1);
710: barOutline.lineTo((float) x1, (float) y0);
711: barOutline.lineTo((float) x3, (float) y0);
712: barOutline.lineTo((float) x3, (float) y2);
713: barOutline.lineTo((float) x2, (float) y3);
714: barOutline.closePath();
715: addItemEntity(entities, dataset, row, column, barOutline);
716: }
717:
718: }
719:
720:
727: public boolean equals(Object obj) {
728: if (obj == this) {
729: return true;
730: }
731: if (!(obj instanceof BarRenderer3D)) {
732: return false;
733: }
734: BarRenderer3D that = (BarRenderer3D) obj;
735: if (this.xOffset != that.xOffset) {
736: return false;
737: }
738: if (this.yOffset != that.yOffset) {
739: return false;
740: }
741: if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
742: return false;
743: }
744: return super.equals(obj);
745: }
746:
747:
754: private void writeObject(ObjectOutputStream stream) throws IOException {
755: stream.defaultWriteObject();
756: SerialUtilities.writePaint(this.wallPaint, stream);
757: }
758:
759:
767: private void readObject(ObjectInputStream stream)
768: throws IOException, ClassNotFoundException {
769: stream.defaultReadObject();
770: this.wallPaint = SerialUtilities.readPaint(stream);
771: }
772:
773: }