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