KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > plot > Pie3DPlot


1 /* ======================================
2  * JFreeChart : a free Java chart library
3  * ======================================
4  *
5  * Project Info: http://www.jfree.org/jfreechart/index.html
6  * Project Lead: David Gilbert (david.gilbert@object-refinery.com);
7  *
8  * (C) Copyright 2000-2003, by Object Refinery Limited and Contributors.
9  *
10  * This library is free software; you can redistribute it and/or modify it under the terms
11  * of the GNU Lesser General Public License as published by the Free Software Foundation;
12  * either version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License along with this
19  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * --------------
23  * PiePlot3D.java
24  * --------------
25  * (C) Copyright 2000-2003, by Object Refinery and Contributors.
26  *
27  * Original Author: Tomer Peretz;
28  * Contributor(s): Richard Atkinson;
29  * David Gilbert (for Object Refinery Limited);
30  * Xun Kang;
31  * Christian W. Zuckschwerdt;
32  * Arnaud Lelievre;
33  * Dave Crane;
34  *
35  * $Id: Pie3DPlot.java,v 1.18 2003/11/25 14:14:30 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 21-Jun-2002 : Version 1;
40  * 31-Jul-2002 : Modified to use startAngle and direction, drawing modified so that charts
41  * render with foreground alpha < 1.0 (DG);
42  * 05-Aug-2002 : Small modification to draw method to support URLs for HTML image maps (RA);
43  * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
44  * 18-Oct-2002 : Added drawing bug fix sent in by Xun Kang, and made a couple of other related
45  * fixes (DG);
46  * 30-Oct-2002 : Changed the PieDataset interface. Fixed another drawing bug (DG);
47  * 12-Nov-2002 : Fixed null pointer exception for zero or negative values (DG);
48  * 07-Mar-2003 : Modified to pass pieIndex on to PieSectionEntity (DG);
49  * 21-Mar-2003 : Added workaround for bug id 620031 (DG);
50  * 26-Mar-2003 : Implemented Serializable (DG);
51  * 30-Jul-2003 : Modified entity constructor (CZ);
52  * 29-Aug-2003 : Small changes for API updates in PiePlot class (DG);
53  * 02-Sep-2003 : Fixed bug where the 'no data' message is not displayed (DG);
54  * 08-Sep-2003 : Added internationalization via use of properties resourceBundle (RFE 690236) (AL);
55  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
56  * 20-Nov-2003 : Fixed bug 845289 (sides not showing) (DG);
57  * 25-Nov-2003 : Added patch (845095) to fix outline paint issues (DG);
58  *
59  */

60
61 package org.jfree.chart.plot;
62
63 import java.awt.AlphaComposite JavaDoc;
64 import java.awt.BasicStroke JavaDoc;
65 import java.awt.Color JavaDoc;
66 import java.awt.Composite JavaDoc;
67 import java.awt.Font JavaDoc;
68 import java.awt.FontMetrics JavaDoc;
69 import java.awt.Graphics2D JavaDoc;
70 import java.awt.Insets JavaDoc;
71 import java.awt.Paint JavaDoc;
72 import java.awt.Polygon JavaDoc;
73 import java.awt.Shape JavaDoc;
74 import java.awt.geom.Arc2D JavaDoc;
75 import java.awt.geom.Area JavaDoc;
76 import java.awt.geom.Ellipse2D JavaDoc;
77 import java.awt.geom.Point2D JavaDoc;
78 import java.awt.geom.Rectangle2D JavaDoc;
79 import java.io.Serializable JavaDoc;
80 import java.util.ArrayList JavaDoc;
81 import java.util.Iterator JavaDoc;
82 import java.util.List JavaDoc;
83
84 import org.jfree.chart.entity.EntityCollection;
85 import org.jfree.chart.entity.PieSectionEntity;
86 import org.jfree.chart.labels.StandardPieItemLabelGenerator;
87 import org.jfree.data.DatasetUtilities;
88 import org.jfree.data.PieDataset;
89
90 /**
91  * A plot that displays data in the form of a 3D pie chart, using data from
92  * any class that implements the {@link PieDataset} interface.
93  * <P>
94  * Although this class extends {@link PiePlot}, it does not currently support
95  * exploded sections or the display of multiple pie charts within one plot.
96  *
97  * @author Tomer Peretz
98  */

99 public class Pie3DPlot extends PiePlot implements Serializable JavaDoc {
100
101     /** The factor of the depth of the pie from the plot height */
102     private double depthFactor = 0.2;
103
104     /**
105      * Creates a 3D pie chart with default attributes.
106      *
107      * @param data the data for the chart.
108      */

109     public Pie3DPlot(PieDataset data) {
110         super(data);
111         setCircularAttribute(false);
112     }
113
114     /**
115      * Sets the factor of the pie depth from the plot height.
116      *
117      * @param newDepthFactor the new depth factor.
118      */

119     public void setDepthFactor(double newDepthFactor) {
120         this.depthFactor = newDepthFactor;
121     }
122
123     /**
124      * The depth factor for the chart.
125      *
126      * @return the current depth factor.
127      */

128     public double getDepthFactor () {
129         return depthFactor;
130     }
131
132     /**
133      * Draws the plot on a Java 2D graphics device (such as the screen or a printer).
134      *
135      * @param g2 the graphics device.
136      * @param plotArea the area within which the plot should be drawn.
137      * @param parentState the state from the parent plot, if there is one.
138      * @param info collects info about the drawing.
139      */

140     public void draw(Graphics2D JavaDoc g2, Rectangle2D JavaDoc plotArea, PlotState parentState,
141                      PlotRenderingInfo info) {
142         
143         Shape JavaDoc savedClip = g2.getClip();
144         Rectangle2D JavaDoc clipArea = savedClip != null
145             ? savedClip.getBounds2D().createIntersection(plotArea)
146             : plotArea;
147
148         // adjust for insets...
149
Insets JavaDoc insets = getInsets();
150         if (insets != null) {
151             plotArea.setRect(plotArea.getX() + insets.left,
152                              plotArea.getY() + insets.top,
153                              plotArea.getWidth() - insets.left - insets.right,
154                              plotArea.getHeight() - insets.top - insets.bottom);
155         }
156
157         if (info != null) {
158             info.setPlotArea(plotArea);
159             info.setDataArea(plotArea);
160         }
161
162         // adjust the plot area by the interior spacing value
163
double gapPercent = getInteriorGap();
164         double gapHorizontal = plotArea.getWidth() * gapPercent;
165         double gapVertical = plotArea.getHeight() * gapPercent;
166
167         double pieX = plotArea.getX() + gapHorizontal / 2;
168         double pieY = plotArea.getY() + gapVertical / 2;
169         double pieW = plotArea.getWidth() - gapHorizontal;
170         double pieH = plotArea.getHeight() - gapVertical;
171
172         if (isCircular()) {
173             double min = Math.min(pieW, pieH) / 2;
174             pieX = (pieX + pieX + pieW) / 2 - min;
175             pieY = (pieY + pieY + pieH) / 2 - min;
176             pieW = 2 * min;
177             pieH = 2 * min;
178         }
179
180         Rectangle2D JavaDoc explodedPieArea = new Rectangle2D.Double JavaDoc(pieX, pieY, pieW, pieH);
181         double radiusPercent = getRadius();
182         double explodeHorizontal = (1 - radiusPercent) * pieW;
183         double explodeVertical = (1 - radiusPercent) * pieH;
184         Rectangle2D JavaDoc pieArea = new Rectangle2D.Double JavaDoc(pieX + explodeHorizontal / 2,
185                                                      pieY + explodeVertical / 2,
186                                                      pieW - explodeHorizontal,
187                                                      pieH - explodeVertical);
188
189         drawBackground(g2, plotArea);
190         // get the data source - return if null;
191
PieDataset dataset = getPieDataset();
192         if (DatasetUtilities.isEmptyOrNull(getDataset())) {
193             drawNoDataMessage(g2, plotArea);
194             g2.setClip(savedClip);
195             drawOutline(g2, plotArea);
196             return;
197         }
198
199         // if too any elements
200
if (dataset.getKeys().size() > plotArea.getWidth()) {
201             String JavaDoc text = "Too many elements";
202             Font JavaDoc sfont = new Font JavaDoc("dialog", Font.BOLD, 10);
203             g2.setFont(sfont);
204             FontMetrics JavaDoc fm = g2.getFontMetrics(sfont);
205             int stringWidth = (int) fm.getStringBounds(text, g2).getWidth();
206
207             g2.drawString(text,
208                           (int) (plotArea.getX() + (plotArea.getWidth() - stringWidth) / 2),
209                           (int) (plotArea.getY() + (plotArea.getHeight() / 2)));
210             return;
211         }
212         // if we are drawing a perfect circle, we need to readjust the top left
213
// coordinates of the drawing area for the arcs to arrive at this
214
// effect.
215
if (isCircular()) {
216             double min = Math.min(plotArea.getWidth(), plotArea.getHeight()) / 2;
217             plotArea = new Rectangle2D.Double JavaDoc(plotArea.getCenterX() - min,
218                                               plotArea.getCenterY() - min, 2 * min, 2 * min);
219         }
220         // get a list of keys...
221
List JavaDoc sectionKeys = dataset.getKeys();
222
223         if (sectionKeys.size() == 0) {
224             return;
225         }
226
227         // establish the coordinates of the top left corner of the drawing area
228
double arcX = pieArea.getX();
229         double arcY = pieArea.getY();
230
231         g2.clip(clipArea);
232         Composite JavaDoc originalComposite = g2.getComposite();
233         g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getForegroundAlpha()));
234
235         double totalValue = DatasetUtilities.getPieDatasetTotal(dataset);
236         double runningTotal = 0;
237         int depth = (int) (pieArea.getHeight() * depthFactor);
238         if (depth < 0) {
239             return; // if depth is negative don't draw anything
240
}
241
242         ArrayList JavaDoc arcList = new ArrayList JavaDoc();
243         Arc2D.Double JavaDoc arc;
244         Paint JavaDoc paint;
245         Paint JavaDoc outlinePaint;
246
247         Iterator JavaDoc iterator = sectionKeys.iterator();
248         while (iterator.hasNext()) {
249
250             Comparable JavaDoc currentKey = (Comparable JavaDoc) iterator.next();
251             Number JavaDoc dataValue = dataset.getValue(currentKey);
252             double value = dataValue.doubleValue();
253             if (value <= 0) {
254                 arcList.add(null);
255                 continue;
256             }
257             double startAngle = getStartAngle();
258             double direction = getDirection().getFactor();
259             double angle1 = startAngle + (direction * (runningTotal * 360)) / totalValue;
260             double angle2 = startAngle + (direction * (runningTotal + value) * 360) / totalValue;
261             if (Math.abs(angle2 - angle1) > getMinimumArcAngleToDraw()) {
262
263                 arcList.add(new Arc2D.Double JavaDoc(arcX,
264                                              arcY + depth,
265                                              pieArea.getWidth(),
266                                              pieArea.getHeight() - depth,
267                                              angle1,
268                                              angle2 - angle1,
269                                              Arc2D.PIE));
270             }
271             else {
272                 arcList.add(null);
273             }
274             runningTotal += value;
275         }
276
277         Shape JavaDoc oldClip = g2.getClip();
278
279         Ellipse2D JavaDoc top = new Ellipse2D.Double JavaDoc(pieArea.getX(),
280                                              pieArea.getY(),
281                                              pieArea.getWidth(),
282                                              pieArea.getHeight() - depth);
283
284         Ellipse2D JavaDoc bottom = new Ellipse2D.Double JavaDoc(pieArea.getX(),
285                                                 pieArea.getY() + depth,
286                                                 pieArea.getWidth(),
287                                                 pieArea.getHeight() - depth);
288
289         Rectangle2D JavaDoc lower = new Rectangle2D.Double JavaDoc(top.getX(),
290                                                    top.getCenterY(),
291                                                    pieArea.getWidth(),
292                                                    bottom.getMaxY() - top.getCenterY());
293
294         Rectangle2D JavaDoc upper = new Rectangle2D.Double JavaDoc(pieArea.getX(),
295                                                    top.getY(),
296                                                    pieArea.getWidth(),
297                                                    bottom.getCenterY() - top.getY());
298
299         Area JavaDoc a = new Area JavaDoc(top);
300         a.add(new Area JavaDoc(lower));
301         Area JavaDoc b = new Area JavaDoc(bottom);
302         b.add(new Area JavaDoc(upper));
303         Area JavaDoc pie = new Area JavaDoc(a);
304         pie.intersect(b);
305
306         Area JavaDoc front = new Area JavaDoc(pie);
307         front.subtract(new Area JavaDoc(top));
308
309         Area JavaDoc back = new Area JavaDoc(pie);
310         back.subtract(new Area JavaDoc(bottom));
311
312         // draw the bottom circle
313
int[] xs;
314         int[] ys;
315         outlinePaint = getSectionOutlinePaint(0);
316         arc = new Arc2D.Double JavaDoc(arcX,
317                                arcY + depth,
318                                pieArea.getWidth(),
319                                pieArea.getHeight() - depth,
320                                0, 360, Arc2D.PIE);
321
322         int categoryCount = arcList.size();
323         for (int categoryIndex = 0; categoryIndex < categoryCount; categoryIndex++) {
324             arc = (Arc2D.Double JavaDoc) arcList.get(categoryIndex);
325             if (arc == null) {
326                 continue;
327             }
328             paint = getSectionPaint(categoryIndex);
329             outlinePaint = getSectionOutlinePaint(categoryIndex);
330
331             g2.setPaint(paint);
332             g2.fill(arc);
333             g2.setPaint(outlinePaint);
334             g2.draw(arc);
335             g2.setPaint(paint);
336
337             Point2D JavaDoc p1 = arc.getStartPoint();
338
339             // draw the height
340
xs = new int[] {(int) arc.getCenterX(), (int) arc.getCenterX(),
341                             (int) p1.getX(), (int) p1.getX() };
342             ys = new int[] {(int) arc.getCenterY(), (int) arc.getCenterY() - depth,
343                             (int) p1.getY() - depth, (int) p1.getY() };
344             Polygon JavaDoc polygon = new Polygon JavaDoc(xs, ys, 4);
345             g2.setPaint(java.awt.Color.lightGray);
346             g2.fill(polygon);
347             g2.setPaint(outlinePaint);
348             g2.draw(polygon);
349             g2.setPaint(paint);
350
351         }
352
353         g2.setPaint(Color.gray);
354         g2.fill(back);
355         g2.fill(front);
356
357         // cycle through once drawing only the sides at the back...
358
int cat = 0;
359         iterator = arcList.iterator();
360         while (iterator.hasNext()) {
361             Arc2D JavaDoc segment = (Arc2D JavaDoc) iterator.next();
362             if (segment != null) {
363                 paint = getSectionPaint(cat);
364                 outlinePaint = getSectionOutlinePaint(cat);
365                 drawSide(g2, pieArea, segment, front, back, paint, outlinePaint, false, true);
366             }
367             cat++;
368         }
369
370         // cycle through again drawing only the sides at the front...
371
cat = 0;
372         iterator = arcList.iterator();
373         while (iterator.hasNext()) {
374             Arc2D JavaDoc segment = (Arc2D JavaDoc) iterator.next();
375             if (segment != null) {
376                 paint = getSectionPaint(cat);
377                 outlinePaint = getSectionOutlinePaint(cat);
378                 drawSide(g2, pieArea, segment, front, back, paint, outlinePaint, true, false);
379             }
380             cat++;
381         }
382
383         g2.setClip(oldClip);
384
385         // draw the sections at the top of the pie (and set up tooltips)...
386
Arc2D JavaDoc upperArc;
387         for (int sectionIndex = 0; sectionIndex < categoryCount; sectionIndex++) {
388             arc = (Arc2D.Double JavaDoc) arcList.get(sectionIndex);
389             if (arc == null) {
390                 continue;
391             }
392             upperArc = new Arc2D.Double JavaDoc(arcX, arcY,
393                                         pieArea.getWidth(),
394                                         pieArea.getHeight() - depth,
395                                         arc.getAngleStart(),
396                                         arc.getAngleExtent(),
397                                         Arc2D.PIE);
398             paint = getSectionPaint(sectionIndex);
399             outlinePaint = getSectionOutlinePaint(sectionIndex);
400
401             g2.setPaint(paint);
402             g2.fill(upperArc);
403             g2.setStroke(new BasicStroke JavaDoc());
404             g2.setPaint(outlinePaint);
405             g2.draw(upperArc);
406
407            // add a tooltip for the section...
408
Comparable JavaDoc currentKey = (Comparable JavaDoc) sectionKeys.get(sectionIndex);
409             if (info != null) {
410                 EntityCollection entities = info.getOwner().getEntityCollection();
411                 if (entities != null) {
412                     if (getItemLabelGenerator() == null) {
413                         setItemLabelGenerator(new StandardPieItemLabelGenerator());
414                     }
415                     String JavaDoc tip = getItemLabelGenerator().generateToolTip(dataset, currentKey, 0);
416                     String JavaDoc url = null;
417                     if (getURLGenerator() != null) {
418                         url = getURLGenerator().generateURL(dataset, currentKey, 0);
419                     }
420                     PieSectionEntity entity = new PieSectionEntity(
421                         upperArc, dataset, 0, sectionIndex, currentKey, tip, url
422                     );
423                     entities.addEntity(entity);
424                 }
425             }
426
427             // then draw the label...
428
if (getSectionLabelType() != NO_LABELS) {
429                 drawLabel(g2, pieArea, explodedPieArea, dataset,
430                           dataset.getValue(currentKey).doubleValue(),
431                           sectionIndex, arc.getAngleStart(), arc.getAngleExtent());
432             }
433         }
434
435         g2.clip(savedClip);
436         g2.setComposite(originalComposite);
437         drawOutline(g2, plotArea);
438
439     }
440
441     /**
442      * Draws the side of a pie section.
443      *
444      * @param g2 the graphics device.
445      * @param plotArea the plot area.
446      * @param arc the arc.
447      * @param front the front of the pie.
448      * @param back the back of the pie.
449      * @param paint the color.
450      * @param drawFront draw the front?
451      * @param drawBack draw the back?
452      */

453     public void drawSide(Graphics2D JavaDoc g2,
454                          Rectangle2D JavaDoc plotArea, Arc2D JavaDoc arc, Area JavaDoc front, Area JavaDoc back,
455                          Paint JavaDoc paint, Paint JavaDoc outlinePaint,
456                          boolean drawFront, boolean drawBack) {
457
458         double start = arc.getAngleStart();
459         double extent = arc.getAngleExtent();
460         double end = start + extent;
461
462         // for CLOCKWISE charts, the extent will be negative...
463
if (extent < 0.0) {
464
465             if (isAngleAtFront(start)) { // start at front
466

467                 if (!isAngleAtBack(end)) {
468
469                     if (extent > -180.0) { // the segment is entirely at the front of the chart
470
if (drawFront) {
471                             Area JavaDoc side = new Area JavaDoc(
472                                 new Rectangle2D.Double JavaDoc(arc.getEndPoint().getX(), plotArea.getY(),
473                                                        arc.getStartPoint().getX()
474                                                        - arc.getEndPoint().getX(),
475                                                        plotArea.getHeight()));
476                             side.intersect(front);
477                             g2.setPaint(paint);
478                             g2.fill(side);
479                             g2.setPaint(outlinePaint);
480                             g2.draw(side);
481                         }
482                     }
483                     else { // the segment starts at the front, and wraps all the way around
484
// the back and finishes at the front again
485
Area JavaDoc side1 = new Area JavaDoc(
486                             new Rectangle2D.Double JavaDoc(plotArea.getX(), plotArea.getY(),
487                                                    arc.getStartPoint().getX() - plotArea.getX(),
488                                                    plotArea.getHeight()));
489                         side1.intersect(front);
490
491                         Area JavaDoc side2 = new Area JavaDoc(
492                             new Rectangle2D.Double JavaDoc(arc.getEndPoint().getX(),
493                                                    plotArea.getY(),
494                                                    plotArea.getMaxX() - arc.getEndPoint().getX(),
495                                                    plotArea.getHeight()));
496
497                         side2.intersect(front);
498                         g2.setPaint(paint);
499                         if (drawFront) {
500                             g2.fill(side1);
501                             g2.fill(side2);
502                         }
503
504                         if (drawBack) {
505                             g2.fill(back);
506                         }
507
508                         g2.setPaint(outlinePaint);
509                         if (drawFront) {
510                             g2.draw(side1);
511                             g2.draw(side2);
512                         }
513
514                         if (drawBack) {
515                             g2.draw(back);
516                         }
517
518                     }
519                 }
520                 else { // starts at the front, finishes at the back (going around the left side)
521

522                     if (drawBack) {
523                         Area JavaDoc side2 = new Area JavaDoc(
524                             new Rectangle2D.Double JavaDoc(plotArea.getX(), plotArea.getY(),
525                                                    arc.getEndPoint().getX() - plotArea.getX(),
526                                                    plotArea.getHeight()));
527                         side2.intersect(back);
528                         g2.setPaint(paint);
529                         g2.fill(side2);
530                         g2.setPaint(outlinePaint);
531                         g2.draw(side2);
532                     }
533
534                     if (drawFront) {
535                         Area JavaDoc side1 = new Area JavaDoc(
536                             new Rectangle2D.Double JavaDoc(plotArea.getX(), plotArea.getY(),
537                                                    arc.getStartPoint().getX() - plotArea.getX(),
538                                                    plotArea.getHeight()));
539                         side1.intersect(front);
540                         g2.setPaint(paint);
541                         g2.fill(side1);
542                         g2.setPaint(outlinePaint);
543                         g2.draw(side1);
544                     }
545                 }
546             }
547             else { // the segment starts at the back (still extending CLOCKWISE)
548

549                 if (!isAngleAtFront(end)) {
550                     if (extent > -180.0) { // whole segment stays at the back
551
if (drawBack) {
552                             Area JavaDoc side = new Area JavaDoc(
553                                 new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
554                                                        arc.getEndPoint().getX()
555                                                        - arc.getStartPoint().getX(),
556                                                        plotArea.getHeight()));
557                             side.intersect(back);
558                             g2.setPaint(paint);
559                             g2.fill(side);
560                             g2.setPaint(outlinePaint);
561                             g2.draw(side);
562                         }
563                     }
564                     else { // starts at the back, wraps around front, and finishes at back again
565
Area JavaDoc side1 = new Area JavaDoc(
566                             new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
567                                                    plotArea.getMaxX()
568                                                    - arc.getStartPoint().getX(),
569                                                    plotArea.getHeight()));
570                         side1.intersect(back);
571
572                         Area JavaDoc side2 = new Area JavaDoc(
573                             new Rectangle2D.Double JavaDoc(plotArea.getX(),
574                                                    plotArea.getY(),
575                                                    arc.getEndPoint().getX() - plotArea.getX(),
576                                                    plotArea.getHeight()));
577
578                         side2.intersect(back);
579
580                         g2.setPaint(paint);
581                         if (drawBack) {
582                             g2.fill(side1);
583                             g2.fill(side2);
584                         }
585
586                         if (drawFront) {
587                             g2.fill(front);
588                         }
589
590                         g2.setPaint(outlinePaint);
591                         if (drawBack) {
592                             g2.draw(side1);
593                             g2.draw(side2);
594                         }
595
596                         if (drawFront) {
597                             g2.draw(front);
598                         }
599
600                     }
601                 }
602                 else { // starts at back, finishes at front (CLOCKWISE)
603

604                     if (drawBack) {
605                         Area JavaDoc side1 = new Area JavaDoc(
606                             new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
607                                                    plotArea.getMaxX() - arc.getStartPoint().getX(),
608                                                    plotArea.getHeight()));
609                         side1.intersect(back);
610                         g2.setPaint(paint);
611                         g2.fill(side1);
612                         g2.setPaint(outlinePaint);
613                         g2.draw(side1);
614                     }
615
616                     if (drawFront) {
617                         Area JavaDoc side2 = new Area JavaDoc(
618                             new Rectangle2D.Double JavaDoc(arc.getEndPoint().getX(), plotArea.getY(),
619                                                    plotArea.getMaxX() - arc.getEndPoint().getX(),
620                                                    plotArea.getHeight()));
621                         side2.intersect(front);
622                         g2.setPaint(paint);
623                         g2.fill(side2);
624                         g2.setPaint(outlinePaint);
625                         g2.draw(side2);
626                     }
627
628                 }
629             }
630         }
631         else if (extent > 0.0) { // the pie sections are arranged ANTICLOCKWISE
632

633             if (isAngleAtFront(start)) { // segment starts at the front
634

635                 if (!isAngleAtBack(end)) { // and finishes at the front
636

637                     if (extent < 180.0) { // segment only occupies the front
638
if (drawFront) {
639                             Area JavaDoc side = new Area JavaDoc(
640                                 new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
641                                                        arc.getEndPoint().getX()
642                                                        - arc.getStartPoint().getX(),
643                                                        plotArea.getHeight()));
644                             side.intersect(front);
645                             g2.setPaint(paint);
646                             g2.fill(side);
647                             g2.setPaint(outlinePaint);
648                             g2.draw(side);
649                         }
650                     }
651                     else { // segments wraps right around the back...
652
Area JavaDoc side1 = new Area JavaDoc(
653                             new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
654                                                    plotArea.getMaxX() - arc.getStartPoint().getX(),
655                                                    plotArea.getHeight()));
656                         side1.intersect(front);
657
658                         Area JavaDoc side2 = new Area JavaDoc(
659                             new Rectangle2D.Double JavaDoc(plotArea.getX(),
660                                                    plotArea.getY(),
661                                                    arc.getEndPoint().getX() - plotArea.getX(),
662                                                    plotArea.getHeight()));
663                         side2.intersect(front);
664
665                         g2.setPaint(paint);
666                         if (drawFront) {
667                             g2.fill(side1);
668                             g2.fill(side2);
669                         }
670
671                         if (drawBack) {
672                             g2.fill(back);
673                         }
674
675
676                         g2.setPaint(outlinePaint);
677                         if (drawFront) {
678                             g2.draw(side1);
679                             g2.draw(side2);
680                         }
681
682                         if (drawBack) {
683                             g2.draw(back);
684                         }
685
686                     }
687                 }
688                 else { // segments starts at front and finishes at back...
689
if (drawBack) {
690                         Area JavaDoc side2 = new Area JavaDoc(
691                             new Rectangle2D.Double JavaDoc(arc.getEndPoint().getX(), plotArea.getY(),
692                                                    plotArea.getMaxX() - arc.getEndPoint().getX(),
693                                                    plotArea.getHeight()));
694                         side2.intersect(back);
695                         g2.setPaint(paint);
696                         g2.fill(side2);
697                         g2.setPaint(outlinePaint);
698                         g2.draw(side2);
699                     }
700
701                     if (drawFront) {
702                         Area JavaDoc side1 = new Area JavaDoc(
703                             new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
704                                                    plotArea.getMaxX() - arc.getStartPoint().getX(),
705                                                    plotArea.getHeight()));
706                         side1.intersect(front);
707                         g2.setPaint(paint);
708                         g2.fill(side1);
709                         g2.setPaint(outlinePaint);
710                         g2.draw(side1);
711                     }
712                 }
713             }
714             else { // segment starts at back
715

716                 if (!isAngleAtFront(end)) {
717                     if (extent < 180.0) { // and finishes at back
718
if (drawBack) {
719                             Area JavaDoc side = new Area JavaDoc(
720                                 new Rectangle2D.Double JavaDoc(arc.getEndPoint().getX(), plotArea.getY(),
721                                                        arc.getStartPoint().getX()
722                                                        - arc.getEndPoint().getX(),
723                                                        plotArea.getHeight()));
724                             side.intersect(back);
725                             g2.setPaint(paint);
726                             g2.fill(side);
727                             g2.setPaint(outlinePaint);
728                             g2.draw(side);
729                         }
730                     }
731                     else { // starts at back and wraps right around to the back again
732
Area JavaDoc side1 = new Area JavaDoc(
733                             new Rectangle2D.Double JavaDoc(arc.getStartPoint().getX(), plotArea.getY(),
734                                                    plotArea.getX() - arc.getStartPoint().getX(),
735                                                    plotArea.getHeight()));
736                         side1.intersect(back);
737
738                         Area JavaDoc side2 = new Area JavaDoc(
739                             new Rectangle2D.Double JavaDoc(arc.getEndPoint().getX(),
740                                                    plotArea.getY(),
741                                                    plotArea.getMaxX() - arc.getEndPoint().getX(),
742                                                    plotArea.getHeight()));
743                         side2.intersect(back);
744
745                         g2.setPaint(paint);
746                         if (drawBack) {
747                             g2.fill(side1);
748                             g2.fill(side2);
749                         }
750
751                         if (drawFront) {
752                             g2.fill(front);
753                         }
754
755                         g2.setPaint(outlinePaint);
756                         if (drawBack) {
757                             g2.draw(side1);
758                             g2.draw(side2);
759                         }
760
761                         if (drawFront) {
762                             g2.draw(front);
763                         }
764
765                     }
766                 }
767                 else { // starts at the back and finishes at the front (wrapping the left side)
768
if (drawBack) {
769                         Area JavaDoc side1 = new Area JavaDoc(
770                             new Rectangle2D.Double JavaDoc(plotArea.getX(), plotArea.getY(),
771                                                    arc.getStartPoint().getX() - plotArea.getX(),
772                                                    plotArea.getHeight()));
773                         side1.intersect(back);
774                         g2.setPaint(paint);
775                         g2.fill(side1);
776                         g2.setPaint(outlinePaint);
777                         g2.draw(side1);
778                     }
779
780                     if (drawFront) {
781                         Area JavaDoc side2 = new Area JavaDoc(
782                             new Rectangle2D.Double JavaDoc(plotArea.getX(), plotArea.getY(),
783                                                    arc.getEndPoint().getX() - plotArea.getX(),
784                                                    plotArea.getHeight()));
785                         side2.intersect(front);
786                         g2.setPaint(paint);
787                         g2.fill(side2);
788                         g2.setPaint(outlinePaint);
789                         g2.draw(side2);
790                     }
791                 }
792             }
793
794         }
795
796     }
797
798     /**
799      * Returns a short string describing the type of plot.
800      *
801      * @return <i>Pie 3D Plot</i>.
802      */

803     public String JavaDoc getPlotType () {
804         return localizationResources.getString("Pie_3D_Plot");
805     }
806
807     /**
808      * A utility method that returns true if the angle represents a point at the front of the
809      * 3D pie chart. 0 - 180 degrees is the back, 180 - 360 is the front.
810      *
811      * @param angle the angle.
812      *
813      * @return true if the angle is at the front of the pie.
814      */

815     private boolean isAngleAtFront(double angle) {
816
817         return (Math.sin(Math.toRadians(angle)) < 0.0);
818
819     }
820
821     /**
822      * A utility method that returns true if the angle represents a point at the back of the
823      * 3D pie chart. 0 - 180 degrees is the back, 180 - 360 is the front.
824      *
825      * @param angle the angle.
826      *
827      * @return true if the angle is at the back of the pie.
828      */

829     private boolean isAngleAtBack(double angle) {
830
831         return (Math.sin(Math.toRadians(angle)) > 0.0);
832
833     }
834
835 }
836
Popular Tags