1:
92:
93: package ;
94:
95: import ;
96: import ;
97: import ;
98: import ;
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:
112: import ;
113: import ;
114: import ;
115: import ;
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:
135:
141: public class BarRenderer3D extends BarRenderer
142: implements Effect3D, Cloneable, PublicCloneable,
143: Serializable {
144:
145:
146: private static final long serialVersionUID = 7686976503536003636L;
147:
148:
149: public static final double DEFAULT_X_OFFSET = 12.0;
150:
151:
152: public static final double DEFAULT_Y_OFFSET = 8.0;
153:
154:
155: public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
156:
157:
158: private double xOffset;
159:
160:
161: private double yOffset;
162:
163:
164: private transient Paint wallPaint;
165:
166:
169: public BarRenderer3D() {
170: this(DEFAULT_X_OFFSET, DEFAULT_Y_OFFSET);
171: }
172:
173:
179: public BarRenderer3D(double xOffset, double yOffset) {
180:
181: super();
182: this.xOffset = xOffset;
183: this.yOffset = yOffset;
184: this.wallPaint = DEFAULT_WALL_PAINT;
185:
186: ItemLabelPosition p1 = new ItemLabelPosition(
187: ItemLabelAnchor.INSIDE12, TextAnchor.TOP_CENTER
188: );
189: setPositiveItemLabelPosition(p1);
190: ItemLabelPosition p2 = new ItemLabelPosition(
191: ItemLabelAnchor.INSIDE12, TextAnchor.TOP_CENTER
192: );
193: setNegativeItemLabelPosition(p2);
194:
195: }
196:
197:
202: public double getXOffset() {
203: return this.xOffset;
204: }
205:
206:
211: public double getYOffset() {
212: return this.yOffset;
213: }
214:
215:
221: public Paint getWallPaint() {
222: return this.wallPaint;
223: }
224:
225:
231: public void setWallPaint(Paint paint) {
232: this.wallPaint = paint;
233: }
234:
235:
236:
249: public CategoryItemRendererState initialise(Graphics2D g2,
250: Rectangle2D dataArea,
251: CategoryPlot plot,
252: int rendererIndex,
253: PlotRenderingInfo info) {
254:
255: Rectangle2D adjusted = new Rectangle2D.Double(
256: dataArea.getX(), dataArea.getY() + getYOffset(),
257: dataArea.getWidth() - getXOffset(),
258: dataArea.getHeight() - getYOffset()
259: );
260: CategoryItemRendererState state = super.initialise(
261: g2, adjusted, plot, rendererIndex, info
262: );
263: return state;
264:
265: }
266:
267:
274: public void drawBackground(Graphics2D g2, CategoryPlot plot,
275: Rectangle2D dataArea) {
276:
277: float x0 = (float) dataArea.getX();
278: float x1 = x0 + (float) Math.abs(this.xOffset);
279: float x3 = (float) dataArea.getMaxX();
280: float x2 = x3 - (float) Math.abs(this.xOffset);
281:
282: float y0 = (float) dataArea.getMaxY();
283: float y1 = y0 - (float) Math.abs(this.yOffset);
284: float y3 = (float) dataArea.getMinY();
285: float y2 = y3 + (float) Math.abs(this.yOffset);
286:
287: GeneralPath clip = new GeneralPath();
288: clip.moveTo(x0, y0);
289: clip.lineTo(x0, y2);
290: clip.lineTo(x1, y3);
291: clip.lineTo(x3, y3);
292: clip.lineTo(x3, y1);
293: clip.lineTo(x2, y0);
294: clip.closePath();
295:
296:
297: Paint backgroundPaint = plot.getBackgroundPaint();
298: if (backgroundPaint != null) {
299: g2.setPaint(backgroundPaint);
300: g2.fill(clip);
301: }
302:
303: GeneralPath leftWall = new GeneralPath();
304: leftWall.moveTo(x0, y0);
305: leftWall.lineTo(x0, y2);
306: leftWall.lineTo(x1, y3);
307: leftWall.lineTo(x1, y1);
308: leftWall.closePath();
309: g2.setPaint(getWallPaint());
310: g2.fill(leftWall);
311:
312: GeneralPath bottomWall = new GeneralPath();
313: bottomWall.moveTo(x0, y0);
314: bottomWall.lineTo(x1, y1);
315: bottomWall.lineTo(x3, y1);
316: bottomWall.lineTo(x2, y0);
317: bottomWall.closePath();
318: g2.setPaint(getWallPaint());
319: g2.fill(bottomWall);
320:
321:
322: g2.setPaint(Color.lightGray);
323: Line2D corner = new Line2D.Double(x0, y0, x1, y1);
324: g2.draw(corner);
325: corner.setLine(x1, y1, x1, y3);
326: g2.draw(corner);
327: corner.setLine(x1, y1, x3, y1);
328: g2.draw(corner);
329:
330:
331: Image backgroundImage = plot.getBackgroundImage();
332: if (backgroundImage != null) {
333: Composite originalComposite = g2.getComposite();
334: g2.setComposite(
335: AlphaComposite.getInstance(
336: AlphaComposite.SRC, plot.getBackgroundAlpha()
337: )
338: );
339: g2.drawImage(
340: backgroundImage,
341: (int) x1, (int) y3,
342: (int) (x3 - x1 + 1), (int) (y1 - y3 + 1),
343: null
344: );
345: g2.setComposite(originalComposite);
346: }
347:
348: }
349:
350:
357: public void drawOutline(Graphics2D g2, CategoryPlot plot,
358: Rectangle2D dataArea) {
359:
360: float x0 = (float) dataArea.getX();
361: float x1 = x0 + (float) Math.abs(this.xOffset);
362: float x3 = (float) dataArea.getMaxX();
363: float x2 = x3 - (float) Math.abs(this.xOffset);
364:
365: float y0 = (float) dataArea.getMaxY();
366: float y1 = y0 - (float) Math.abs(this.yOffset);
367: float y3 = (float) dataArea.getMinY();
368: float y2 = y3 + (float) Math.abs(this.yOffset);
369:
370: GeneralPath clip = new GeneralPath();
371: clip.moveTo(x0, y0);
372: clip.lineTo(x0, y2);
373: clip.lineTo(x1, y3);
374: clip.lineTo(x3, y3);
375: clip.lineTo(x3, y1);
376: clip.lineTo(x2, y0);
377: clip.closePath();
378:
379:
380: Stroke outlineStroke = plot.getOutlineStroke();
381: Paint outlinePaint = plot.getOutlinePaint();
382: if ((outlineStroke != null) && (outlinePaint != null)) {
383: g2.setStroke(outlineStroke);
384: g2.setPaint(outlinePaint);
385: g2.draw(clip);
386: }
387:
388: }
389:
390:
400: public void drawDomainGridline(Graphics2D g2,
401: CategoryPlot plot,
402: Rectangle2D dataArea,
403: double value) {
404:
405: Line2D line1 = null;
406: Line2D line2 = null;
407: PlotOrientation orientation = plot.getOrientation();
408: if (orientation == PlotOrientation.HORIZONTAL) {
409: double y0 = value;
410: double y1 = value - getYOffset();
411: double x0 = dataArea.getMinX();
412: double x1 = x0 + getXOffset();
413: double x2 = dataArea.getMaxY();
414: line1 = new Line2D.Double(x0, y0, x1, y1);
415: line2 = new Line2D.Double(x1, y1, x2, y1);
416: }
417: else if (orientation == PlotOrientation.VERTICAL) {
418: double x0 = value;
419: double x1 = value + getXOffset();
420: double y0 = dataArea.getMaxY();
421: double y1 = y0 - getYOffset();
422: double y2 = dataArea.getMinY();
423: line1 = new Line2D.Double(x0, y0, x1, y1);
424: line2 = new Line2D.Double(x1, y1, x1, y2);
425: }
426: Paint paint = plot.getDomainGridlinePaint();
427: Stroke stroke = plot.getDomainGridlineStroke();
428: g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
429: g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
430: g2.draw(line1);
431: g2.draw(line2);
432:
433: }
434:
435:
446: public void drawRangeGridline(Graphics2D g2,
447: CategoryPlot plot,
448: ValueAxis axis,
449: Rectangle2D dataArea,
450: double value) {
451:
452: Range range = axis.getRange();
453:
454: if (!range.contains(value)) {
455: return;
456: }
457:
458: Rectangle2D adjusted = new Rectangle2D.Double(
459: dataArea.getX(),
460: dataArea.getY() + getYOffset(),
461: dataArea.getWidth() - getXOffset(),
462: dataArea.getHeight() - getYOffset()
463: );
464:
465: Line2D line1 = null;
466: Line2D line2 = null;
467: PlotOrientation orientation = plot.getOrientation();
468: if (orientation == PlotOrientation.HORIZONTAL) {
469: double x0 = axis.valueToJava2D(
470: value, adjusted, plot.getRangeAxisEdge()
471: );
472: double x1 = x0 + getXOffset();
473: double y0 = dataArea.getMaxY();
474: double y1 = y0 - getYOffset();
475: double y2 = dataArea.getMinY();
476: line1 = new Line2D.Double(x0, y0, x1, y1);
477: line2 = new Line2D.Double(x1, y1, x1, y2);
478: }
479: else if (orientation == PlotOrientation.VERTICAL) {
480: double y0 = axis.valueToJava2D(
481: value, adjusted, plot.getRangeAxisEdge()
482: );
483: double y1 = y0 - getYOffset();
484: double x0 = dataArea.getMinX();
485: double x1 = x0 + getXOffset();
486: double x2 = dataArea.getMaxX();
487: line1 = new Line2D.Double(x0, y0, x1, y1);
488: line2 = new Line2D.Double(x1, y1, x2, y1);
489: }
490: Paint paint = plot.getRangeGridlinePaint();
491: Stroke stroke = plot.getRangeGridlineStroke();
492: g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT);
493: g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE);
494: g2.draw(line1);
495: g2.draw(line2);
496:
497: }
498:
499:
508: public void drawRangeMarker(Graphics2D g2,
509: CategoryPlot plot,
510: ValueAxis axis,
511: Marker marker,
512: Rectangle2D dataArea) {
513:
514: if (marker instanceof ValueMarker) {
515: ValueMarker vm = (ValueMarker) marker;
516: double value = vm.getValue();
517: Range range = axis.getRange();
518: if (!range.contains(value)) {
519: return;
520: }
521:
522: Rectangle2D adjusted = new Rectangle2D.Double(
523: dataArea.getX(), dataArea.getY() + getYOffset(),
524: dataArea.getWidth() - getXOffset(),
525: dataArea.getHeight() - getYOffset()
526: );
527:
528: GeneralPath path = null;
529: PlotOrientation orientation = plot.getOrientation();
530: if (orientation == PlotOrientation.HORIZONTAL) {
531: float x = (float) axis.valueToJava2D(
532: value, adjusted, plot.getRangeAxisEdge()
533: );
534: float y = (float) adjusted.getMaxY();
535: path = new GeneralPath();
536: path.moveTo(x, y);
537: path.lineTo(
538: (float) (x + getXOffset()), y - (float) getYOffset()
539: );
540: path.lineTo(
541: (float) (x + getXOffset()),
542: (float) (adjusted.getMinY() - getYOffset())
543: );
544: path.lineTo(x, (float) adjusted.getMinY());
545: path.closePath();
546: }
547: else if (orientation == PlotOrientation.VERTICAL) {
548: float y = (float) axis.valueToJava2D(
549: value, adjusted, plot.getRangeAxisEdge()
550: );
551: float x = (float) dataArea.getX();
552: path = new GeneralPath();
553: path.moveTo(x, y);
554: path.lineTo(x + (float) this.xOffset, y - (float) this.yOffset);
555: path.lineTo(
556: (float) (adjusted.getMaxX() + this.xOffset),
557: y - (float) this.yOffset
558: );
559: path.lineTo((float) (adjusted.getMaxX()), y);
560: path.closePath();
561: }
562: g2.setPaint(marker.getPaint());
563: g2.fill(path);
564: g2.setPaint(marker.getOutlinePaint());
565: g2.draw(path);
566:
567: String label = marker.getLabel();
568: RectangleAnchor anchor = marker.getLabelAnchor();
569: if (label != null) {
570: Font labelFont = marker.getLabelFont();
571: g2.setFont(labelFont);
572: g2.setPaint(marker.getLabelPaint());
573: Point2D coordinates = calculateRangeMarkerTextAnchorPoint(
574: g2, orientation, dataArea, path.getBounds2D(),
575: marker.getLabelOffset(), LengthAdjustmentType.EXPAND, anchor
576: );
577: TextUtilities.drawAlignedString(
578: label, g2,
579: (float) coordinates.getX(), (float) coordinates.getY(),
580: marker.getLabelTextAnchor()
581: );
582: }
583:
584: }
585: else {
586: super.drawRangeMarker(g2, plot, axis, marker, dataArea);
587:
588: }
589: }
590:
591:
605: public void drawItem(Graphics2D g2,
606: CategoryItemRendererState state,
607: Rectangle2D dataArea,
608: CategoryPlot plot,
609: CategoryAxis domainAxis,
610: ValueAxis rangeAxis,
611: CategoryDataset dataset,
612: int row,
613: int column,
614: int pass) {
615:
616:
617: Number dataValue = dataset.getValue(row, column);
618: if (dataValue == null) {
619: return;
620: }
621:
622: double value = dataValue.doubleValue();
623:
624: Rectangle2D adjusted = new Rectangle2D.Double(
625: dataArea.getX(),
626: dataArea.getY() + getYOffset(),
627: dataArea.getWidth() - getXOffset(),
628: dataArea.getHeight() - getYOffset()
629: );
630:
631: PlotOrientation orientation = plot.getOrientation();
632:
633: double barW0 = calculateBarW0(
634: plot, orientation, adjusted, domainAxis, state, row, column
635: );
636: double[] barL0L1 = calculateBarL0L1(value);
637: if (barL0L1 == null) {
638: return;
639: }
640:
641: RectangleEdge edge = plot.getRangeAxisEdge();
642: double transL0 = rangeAxis.valueToJava2D(barL0L1[0], adjusted, edge);
643: double transL1 = rangeAxis.valueToJava2D(barL0L1[1], adjusted, edge);
644: double barL0 = Math.min(transL0, transL1);
645: double barLength = Math.abs(transL1 - transL0);
646:
647:
648: Rectangle2D bar = null;
649: if (orientation == PlotOrientation.HORIZONTAL) {
650: bar = new Rectangle2D.Double(
651: barL0, barW0, barLength, state.getBarWidth()
652: );
653: }
654: else {
655: bar = new Rectangle2D.Double(
656: barW0, barL0, state.getBarWidth(), barLength
657: );
658: }
659: Paint itemPaint = getItemPaint(row, column);
660: g2.setPaint(itemPaint);
661: g2.fill(bar);
662:
663: double x0 = bar.getMinX();
664: double x1 = x0 + getXOffset();
665: double x2 = bar.getMaxX();
666: double x3 = x2 + getXOffset();
667:
668: double y0 = bar.getMinY() - getYOffset();
669: double y1 = bar.getMinY();
670: double y2 = bar.getMaxY() - getYOffset();
671: double y3 = bar.getMaxY();
672:
673: GeneralPath bar3dRight = null;
674: GeneralPath bar3dTop = null;
675: if (barLength > 0.0) {
676: bar3dRight = new GeneralPath();
677: bar3dRight.moveTo((float) x2, (float) y3);
678: bar3dRight.lineTo((float) x2, (float) y1);
679: bar3dRight.lineTo((float) x3, (float) y0);
680: bar3dRight.lineTo((float) x3, (float) y2);
681: bar3dRight.closePath();
682:
683: if (itemPaint instanceof Color) {
684: g2.setPaint(((Color) itemPaint).darker());
685: }
686: g2.fill(bar3dRight);
687: }
688:
689: bar3dTop = new GeneralPath();
690: bar3dTop.moveTo((float) x0, (float) y1);
691: bar3dTop.lineTo((float) x1, (float) y0);
692: bar3dTop.lineTo((float) x3, (float) y0);
693: bar3dTop.lineTo((float) x2, (float) y1);
694: bar3dTop.closePath();
695: g2.fill(bar3dTop);
696:
697: if (isDrawBarOutline()
698: && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
699: g2.setStroke(getItemOutlineStroke(row, column));
700: g2.setPaint(getItemOutlinePaint(row, column));
701: g2.draw(bar);
702: if (bar3dRight != null) {
703: g2.draw(bar3dRight);
704: }
705: if (bar3dTop != null) {
706: g2.draw(bar3dTop);
707: }
708: }
709:
710: CategoryItemLabelGenerator generator
711: = getItemLabelGenerator(row, column);
712: if (generator != null && isItemLabelVisible(row, column)) {
713: drawItemLabel(
714: g2, dataset, row, column, plot, generator, bar, (value < 0.0)
715: );
716: }
717:
718:
719: EntityCollection entities = state.getEntityCollection();
720: if (entities != null) {
721: GeneralPath barOutline = new GeneralPath();
722: barOutline.moveTo((float) x0, (float) y3);
723: barOutline.lineTo((float) x0, (float) y1);
724: barOutline.lineTo((float) x1, (float) y0);
725: barOutline.lineTo((float) x3, (float) y0);
726: barOutline.lineTo((float) x3, (float) y2);
727: barOutline.lineTo((float) x2, (float) y3);
728: barOutline.closePath();
729: addItemEntity(entities, dataset, row, column, barOutline);
730: }
731:
732: }
733:
734:
741: private void writeObject(ObjectOutputStream stream) throws IOException {
742: stream.defaultWriteObject();
743: SerialUtilities.writePaint(this.wallPaint, stream);
744: }
745:
746:
754: private void readObject(ObjectInputStream stream)
755: throws IOException, ClassNotFoundException {
756: stream.defaultReadObject();
757: this.wallPaint = SerialUtilities.readPaint(stream);
758: }
759:
760:
761: }