KickJava   Java API By Example, From Geeks To Geeks.

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


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * --------------
28  * PiePlot3D.java
29  * --------------
30  * (C) Copyright 2000-2006, by Object Refinery and Contributors.
31  *
32  * Original Author: Tomer Peretz;
33  * Contributor(s): Richard Atkinson;
34  * David Gilbert (for Object Refinery Limited);
35  * Xun Kang;
36  * Christian W. Zuckschwerdt;
37  * Arnaud Lelievre;
38  * Dave Crane;
39  *
40  * $Id: PiePlot3D.java,v 1.10.2.5 2006/09/27 17:06:59 mungady Exp $
41  *
42  * Changes
43  * -------
44  * 21-Jun-2002 : Version 1;
45  * 31-Jul-2002 : Modified to use startAngle and direction, drawing modified so
46  * that charts render with foreground alpha < 1.0 (DG);
47  * 05-Aug-2002 : Small modification to draw method to support URLs for HTML
48  * image maps (RA);
49  * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
50  * 18-Oct-2002 : Added drawing bug fix sent in by Xun Kang, and made a couple
51  * of other related fixes (DG);
52  * 30-Oct-2002 : Changed the PieDataset interface. Fixed another drawing
53  * bug (DG);
54  * 12-Nov-2002 : Fixed null pointer exception for zero or negative values (DG);
55  * 07-Mar-2003 : Modified to pass pieIndex on to PieSectionEntity (DG);
56  * 21-Mar-2003 : Added workaround for bug id 620031 (DG);
57  * 26-Mar-2003 : Implemented Serializable (DG);
58  * 30-Jul-2003 : Modified entity constructor (CZ);
59  * 29-Aug-2003 : Small changes for API updates in PiePlot class (DG);
60  * 02-Sep-2003 : Fixed bug where the 'no data' message is not displayed (DG);
61  * 08-Sep-2003 : Added internationalization via use of properties
62  * resourceBundle (RFE 690236) (AL);
63  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
64  * 20-Nov-2003 : Fixed bug 845289 (sides not showing) (DG);
65  * 25-Nov-2003 : Added patch (845095) to fix outline paint issues (DG);
66  * 10-Mar-2004 : Numerous changes to enhance labelling (DG);
67  * 31-Mar-2004 : Adjusted plot area when label generator is null (DG);
68  * 08-Apr-2004 : Added flag to PiePlot class to control the treatment of null
69  * values (DG);
70  * Added pieIndex to PieSectionEntity (DG);
71  * 15-Nov-2004 : Removed creation of default tool tip generator (DG);
72  * 16-Jun-2005 : Added default constructor (DG);
73  * ------------- JFREECHART 1.0.0 ---------------------------------------------
74  * 27-Sep-2006 : Updated draw() method for new lookup methods (DG);
75  *
76  *
77  */

78
79 package org.jfree.chart.plot;
80
81 import java.awt.AlphaComposite JavaDoc;
82 import java.awt.Color JavaDoc;
83 import java.awt.Composite JavaDoc;
84 import java.awt.Font JavaDoc;
85 import java.awt.FontMetrics JavaDoc;
86 import java.awt.Graphics2D JavaDoc;
87 import java.awt.Paint JavaDoc;
88 import java.awt.Polygon JavaDoc;
89 import java.awt.Shape JavaDoc;
90 import java.awt.Stroke JavaDoc;
91 import java.awt.geom.Arc2D JavaDoc;
92 import java.awt.geom.Area JavaDoc;
93 import java.awt.geom.Ellipse2D JavaDoc;
94 import java.awt.geom.Point2D JavaDoc;
95 import java.awt.geom.Rectangle2D JavaDoc;
96 import java.io.Serializable JavaDoc;
97 import java.util.ArrayList JavaDoc;
98 import java.util.Iterator JavaDoc;
99 import java.util.List JavaDoc;
100
101 import org.jfree.chart.entity.EntityCollection;
102 import org.jfree.chart.entity.PieSectionEntity;
103 import org.jfree.chart.labels.PieToolTipGenerator;
104 import org.jfree.data.general.DatasetUtilities;
105 import org.jfree.data.general.PieDataset;
106 import org.jfree.ui.RectangleInsets;
107
108 /**
109  * A plot that displays data in the form of a 3D pie chart, using data from
110  * any class that implements the {@link PieDataset} interface.
111  * <P>
112  * Although this class extends {@link PiePlot}, it does not currently support
113  * exploded sections.
114  */

115 public class PiePlot3D extends PiePlot implements Serializable JavaDoc {
116
117     /** For serialization. */
118     private static final long serialVersionUID = 3408984188945161432L;
119     
120     /** The factor of the depth of the pie from the plot height */
121     private double depthFactor = 0.2;
122
123     /**
124      * Creates a new instance with no dataset.
125      */

126     public PiePlot3D() {
127         this(null);
128     }
129     
130     /**
131      * Creates a pie chart with a three dimensional effect using the specified
132      * dataset.
133      *
134      * @param dataset the dataset (<code>null</code> permitted).
135      */

136     public PiePlot3D(PieDataset dataset) {
137         super(dataset);
138         setCircular(false, false);
139     }
140
141     /**
142      * Sets the pie depth as a percentage of the height of the plot area.
143      *
144      * @param factor the depth factor (for example, 0.20 is twenty percent).
145      */

146     public void setDepthFactor(double factor) {
147         this.depthFactor = factor;
148     }
149
150     /**
151      * The depth factor for the chart.
152      *
153      * @return The depth factor.
154      */

155     public double getDepthFactor () {
156         return this.depthFactor;
157     }
158
159     /**
160      * Draws the plot on a Java 2D graphics device (such as the screen or a
161      * printer). This method is called by the
162      * {@link org.jfree.chart.JFreeChart} class, you don't normally need
163      * to call it yourself.
164      *
165      * @param g2 the graphics device.
166      * @param plotArea the area within which the plot should be drawn.
167      * @param anchor the anchor point.
168      * @param parentState the state from the parent plot, if there is one.
169      * @param info collects info about the drawing
170      * (<code>null</code> permitted).
171      */

172     public void draw(Graphics2D JavaDoc g2, Rectangle2D JavaDoc plotArea, Point2D JavaDoc anchor,
173                      PlotState parentState,
174                      PlotRenderingInfo info) {
175
176         // adjust for insets...
177
RectangleInsets insets = getInsets();
178         insets.trim(plotArea);
179
180         Rectangle2D JavaDoc originalPlotArea = (Rectangle2D JavaDoc) plotArea.clone();
181         if (info != null) {
182             info.setPlotArea(plotArea);
183             info.setDataArea(plotArea);
184         }
185
186         Shape JavaDoc savedClip = g2.getClip();
187         g2.clip(plotArea);
188
189         // adjust the plot area by the interior spacing value
190
double gapPercent = getInteriorGap();
191         double labelPercent = 0.0;
192         if (getLabelGenerator() != null) {
193             labelPercent = getLabelGap() + getMaximumLabelWidth()
194                            + getLabelLinkMargin();
195         }
196         double gapHorizontal = plotArea.getWidth()
197                                * (gapPercent + labelPercent);
198         double gapVertical = plotArea.getHeight() * gapPercent;
199
200         double linkX = plotArea.getX() + gapHorizontal / 2;
201         double linkY = plotArea.getY() + gapVertical / 2;
202         double linkW = plotArea.getWidth() - gapHorizontal;
203         double linkH = plotArea.getHeight() - gapVertical;
204         
205         // make the link area a square if the pie chart is to be circular...
206
if (isCircular()) { // is circular?
207
double min = Math.min(linkW, linkH) / 2;
208             linkX = (linkX + linkX + linkW) / 2 - min;
209             linkY = (linkY + linkY + linkH) / 2 - min;
210             linkW = 2 * min;
211             linkH = 2 * min;
212         }
213         
214         PiePlotState state = initialise(g2, plotArea, this, null, info);
215         // the explode area defines the max circle/ellipse for the exploded pie
216
// sections.
217
// it is defined by shrinking the linkArea by the linkMargin factor.
218
double hh = linkW * getLabelLinkMargin();
219         double vv = linkH * getLabelLinkMargin();
220         Rectangle2D JavaDoc explodeArea = new Rectangle2D.Double JavaDoc(linkX + hh / 2.0,
221                 linkY + vv / 2.0, linkW - hh, linkH - vv);
222        
223         state.setExplodedPieArea(explodeArea);
224         
225         // the pie area defines the circle/ellipse for regular pie sections.
226
// it is defined by shrinking the explodeArea by the explodeMargin
227
// factor.
228
double maximumExplodePercent = getMaximumExplodePercent();
229         double percent = maximumExplodePercent / (1.0 + maximumExplodePercent);
230         
231         double h1 = explodeArea.getWidth() * percent;
232         double v1 = explodeArea.getHeight() * percent;
233         Rectangle2D JavaDoc pieArea = new Rectangle2D.Double JavaDoc(explodeArea.getX()
234                 + h1 / 2.0, explodeArea.getY() + v1 / 2.0,
235                 explodeArea.getWidth() - h1, explodeArea.getHeight() - v1);
236
237         int depth = (int) (pieArea.getHeight() * this.depthFactor);
238         // the link area defines the dog-leg point for the linking lines to
239
// the labels
240
Rectangle2D JavaDoc linkArea = new Rectangle2D.Double JavaDoc(linkX, linkY, linkW,
241                 linkH - depth);
242         state.setLinkArea(linkArea);
243
244         state.setPieArea(pieArea);
245         state.setPieCenterX(pieArea.getCenterX());
246         state.setPieCenterY(pieArea.getCenterY() - depth / 2.0);
247         state.setPieWRadius(pieArea.getWidth() / 2.0);
248         state.setPieHRadius((pieArea.getHeight() - depth) / 2.0);
249
250         drawBackground(g2, plotArea);
251         // get the data source - return if null;
252
PieDataset dataset = getDataset();
253         if (DatasetUtilities.isEmptyOrNull(getDataset())) {
254             drawNoDataMessage(g2, plotArea);
255             g2.setClip(savedClip);
256             drawOutline(g2, plotArea);
257             return;
258         }
259
260         // if too any elements
261
if (dataset.getKeys().size() > plotArea.getWidth()) {
262             String JavaDoc text = "Too many elements";
263             Font JavaDoc sfont = new Font JavaDoc("dialog", Font.BOLD, 10);
264             g2.setFont(sfont);
265             FontMetrics JavaDoc fm = g2.getFontMetrics(sfont);
266             int stringWidth = fm.stringWidth(text);
267
268             g2.drawString(text, (int) (plotArea.getX() + (plotArea.getWidth()
269                     - stringWidth) / 2), (int) (plotArea.getY()
270                     + (plotArea.getHeight() / 2)));
271             return;
272         }
273         // if we are drawing a perfect circle, we need to readjust the top left
274
// coordinates of the drawing area for the arcs to arrive at this
275
// effect.
276
if (isCircular()) {
277             double min = Math.min(plotArea.getWidth(),
278                     plotArea.getHeight()) / 2;
279             plotArea = new Rectangle2D.Double JavaDoc(plotArea.getCenterX() - min,
280                     plotArea.getCenterY() - min, 2 * min, 2 * min);
281         }
282         // get a list of keys...
283
List JavaDoc sectionKeys = dataset.getKeys();
284
285         if (sectionKeys.size() == 0) {
286             return;
287         }
288
289         // establish the coordinates of the top left corner of the drawing area
290
double arcX = pieArea.getX();
291         double arcY = pieArea.getY();
292
293         //g2.clip(clipArea);
294
Composite JavaDoc originalComposite = g2.getComposite();
295         g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
296                 getForegroundAlpha()));
297
298         double totalValue = DatasetUtilities.calculatePieDatasetTotal(dataset);
299         double runningTotal = 0;
300         if (depth < 0) {
301             return; // if depth is negative don't draw anything
302
}
303
304         ArrayList JavaDoc arcList = new ArrayList JavaDoc();
305         Arc2D.Double JavaDoc arc;
306         Paint JavaDoc paint;
307         Paint JavaDoc outlinePaint;
308         Stroke JavaDoc outlineStroke;
309
310         Iterator JavaDoc iterator = sectionKeys.iterator();
311         while (iterator.hasNext()) {
312
313             Comparable JavaDoc currentKey = (Comparable JavaDoc) iterator.next();
314             Number JavaDoc dataValue = dataset.getValue(currentKey);
315             if (dataValue == null) {
316                 arcList.add(null);
317                 continue;
318             }
319             double value = dataValue.doubleValue();
320             if (value <= 0) {
321                 arcList.add(null);
322                 continue;
323             }
324             double startAngle = getStartAngle();
325             double direction = getDirection().getFactor();
326             double angle1 = startAngle + (direction * (runningTotal * 360))
327                     / totalValue;
328             double angle2 = startAngle + (direction * (runningTotal + value)
329                     * 360) / totalValue;
330             if (Math.abs(angle2 - angle1) > getMinimumArcAngleToDraw()) {
331                 arcList.add(new Arc2D.Double JavaDoc(arcX, arcY + depth,
332                         pieArea.getWidth(), pieArea.getHeight() - depth,
333                         angle1, angle2 - angle1, Arc2D.PIE));
334             }
335             else {
336                 arcList.add(null);
337             }
338             runningTotal += value;
339         }
340
341         Shape JavaDoc oldClip = g2.getClip();
342
343         Ellipse2D JavaDoc top = new Ellipse2D.Double JavaDoc(pieArea.getX(), pieArea.getY(),
344                 pieArea.getWidth(), pieArea.getHeight() - depth);
345
346         Ellipse2D JavaDoc bottom = new Ellipse2D.Double JavaDoc(pieArea.getX(), pieArea.getY()
347                 + depth, pieArea.getWidth(), pieArea.getHeight() - depth);
348
349         Rectangle2D JavaDoc lower = new Rectangle2D.Double JavaDoc(top.getX(),
350                 top.getCenterY(), pieArea.getWidth(), bottom.getMaxY()
351                 - top.getCenterY());
352
353         Rectangle2D JavaDoc upper = new Rectangle2D.Double JavaDoc(pieArea.getX(), top.getY(),
354                 pieArea.getWidth(), bottom.getCenterY() - top.getY());
355
356         Area JavaDoc a = new Area JavaDoc(top);
357         a.add(new Area JavaDoc(lower));
358         Area JavaDoc b = new Area JavaDoc(bottom);
359         b.add(new Area JavaDoc(upper));
360         Area JavaDoc pie = new Area JavaDoc(a);
361         pie.intersect(b);
362
363         Area JavaDoc front = new Area JavaDoc(pie);
364         front.subtract(new Area JavaDoc(top));
365
366         Area JavaDoc back = new Area JavaDoc(pie);
367         back.subtract(new Area JavaDoc(bottom));
368
369         // draw the bottom circle
370
int[] xs;
371         int[] ys;
372         arc = new Arc2D.Double JavaDoc(arcX, arcY + depth, pieArea.getWidth(),
373                 pieArea.getHeight() - depth, 0, 360, Arc2D.PIE);
374
375         int categoryCount = arcList.size();
376         for (int categoryIndex = 0; categoryIndex < categoryCount;
377                  categoryIndex++) {
378             arc = (Arc2D.Double JavaDoc) arcList.get(categoryIndex);
379             if (arc == null) {
380                 continue;
381             }
382             Comparable JavaDoc key = getSectionKey(categoryIndex);
383             paint = lookupSectionPaint(key, true);
384             outlinePaint = lookupSectionOutlinePaint(key);
385             outlineStroke = lookupSectionOutlineStroke(key);
386             g2.setPaint(paint);
387             g2.fill(arc);
388             g2.setPaint(outlinePaint);
389             g2.setStroke(outlineStroke);
390             g2.draw(arc);
391             g2.setPaint(paint);
392
393             Point2D JavaDoc p1 = arc.getStartPoint();
394
395             // draw the height
396
xs = new int[] {(int) arc.getCenterX(), (int) arc.getCenterX(),
397                     (int) p1.getX(), (int) p1.getX()};
398             ys = new int[] {(int) arc.getCenterY(), (int) arc.getCenterY()
399                     - depth, (int) p1.getY() - depth, (int) p1.getY()};
400             Polygon JavaDoc polygon = new Polygon JavaDoc(xs, ys, 4);
401             g2.setPaint(java.awt.Color.lightGray);
402             g2.fill(polygon);
403             g2.setPaint(outlinePaint);
404             g2.setStroke(outlineStroke);
405             g2.draw(polygon);
406             g2.setPaint(paint);
407
408         }
409
410         g2.setPaint(Color.gray);
411         g2.fill(back);
412         g2.fill(front);
413
414         // cycle through once drawing only the sides at the back...
415
int cat = 0;
416         iterator = arcList.iterator();
417         while (iterator.hasNext()) {
418             Arc2D JavaDoc segment = (Arc2D JavaDoc) iterator.next();
419             if (segment != null) {
420                 Comparable JavaDoc key = getSectionKey(cat);
421                 paint = lookupSectionPaint(key, true);
422                 outlinePaint = lookupSectionOutlinePaint(key);
423                 outlineStroke = lookupSectionOutlineStroke(key);
424                 drawSide(g2, pieArea, segment, front, back, paint,
425                         outlinePaint, outlineStroke, false, true);
426             }
427             cat++;
428         }
429
430         // cycle through again drawing only the sides at the front...
431
cat = 0;
432         iterator = arcList.iterator();
433         while (iterator.hasNext()) {
434             Arc2D JavaDoc segment = (Arc2D JavaDoc) iterator.next();
435             if (segment != null) {
436                 Comparable JavaDoc key = getSectionKey(cat);
437                 paint = lookupSectionPaint(key);
438                 outlinePaint = lookupSectionOutlinePaint(key);
439                 outlineStroke = lookupSectionOutlineStroke(key);
440                 drawSide(g2, pieArea, segment, front, back, paint,
441                         outlinePaint, outlineStroke, true, false);
442             }
443             cat++;
444         }
445
446         g2.setClip(oldClip);
447
448         // draw the sections at the top of the pie (and set up tooltips)...
449
Arc2D JavaDoc upperArc;
450         for (int sectionIndex = 0; sectionIndex < categoryCount;
451                  sectionIndex++) {
452             arc = (Arc2D.Double JavaDoc) arcList.get(sectionIndex);
453             if (arc == null) {
454                 continue;
455             }
456             upperArc = new Arc2D.Double JavaDoc(arcX, arcY, pieArea.getWidth(),
457                     pieArea.getHeight() - depth, arc.getAngleStart(),
458                     arc.getAngleExtent(), Arc2D.PIE);
459             
460             Comparable JavaDoc currentKey = (Comparable JavaDoc) sectionKeys.get(sectionIndex);
461             paint = lookupSectionPaint(currentKey, true);
462             outlinePaint = lookupSectionOutlinePaint(currentKey);
463             outlineStroke = lookupSectionOutlineStroke(currentKey);
464             g2.setPaint(paint);
465             g2.fill(upperArc);
466             g2.setStroke(outlineStroke);
467             g2.setPaint(outlinePaint);
468             g2.draw(upperArc);
469
470            // add a tooltip for the section...
471
if (info != null) {
472                 EntityCollection entities
473                         = info.getOwner().getEntityCollection();
474                 if (entities != null) {
475                     String JavaDoc tip = null;
476                     PieToolTipGenerator tipster = getToolTipGenerator();
477                     if (tipster != null) {
478                         // @mgs: using the method's return value was missing
479
tip = tipster.generateToolTip(dataset, currentKey);
480                     }
481                     String JavaDoc url = null;
482                     if (getURLGenerator() != null) {
483                         url = getURLGenerator().generateURL(dataset, currentKey,
484                                 getPieIndex());
485                     }
486                     PieSectionEntity entity = new PieSectionEntity(
487                             upperArc, dataset, getPieIndex(), sectionIndex,
488                             currentKey, tip, url);
489                     entities.add(entity);
490                 }
491             }
492             List JavaDoc keys = dataset.getKeys();
493             Rectangle2D JavaDoc adjustedPlotArea = new Rectangle2D.Double JavaDoc(
494                     originalPlotArea.getX(), originalPlotArea.getY(),
495                     originalPlotArea.getWidth(), originalPlotArea.getHeight()
496                     - depth);
497             drawLabels(g2, keys, totalValue, adjustedPlotArea, linkArea, state);
498         }
499
500         g2.setClip(savedClip);
501         g2.setComposite(originalComposite);
502         drawOutline(g2, originalPlotArea);
503
504     }
505
506     /**
507      * Draws the side of a pie section.
508      *
509      * @param g2 the graphics device.
510      * @param plotArea the plot area.
511      * @param arc the arc.
512      * @param front the front of the pie.
513      * @param back the back of the pie.
514      * @param paint the color.
515      * @param outlinePaint the outline paint.
516      * @param outlineStroke the outline stroke.
517      * @param drawFront draw the front?
518      * @param drawBack draw the back?
519      */

520     protected void drawSide(Graphics2D JavaDoc g2,
521                             Rectangle2D JavaDoc plotArea,
522                             Arc2D JavaDoc arc,
523                             Area JavaDoc front,
524                             Area JavaDoc back,
525                             Paint JavaDoc paint,
526                             Paint JavaDoc outlinePaint,
527                             Stroke JavaDoc outlineStroke,
528                             boolean drawFront,
529                             boolean drawBack) {
530
531         double start = arc.getAngleStart();
532         double extent = arc.getAngleExtent();
533         double end = start + extent;
534
535         g2.setStroke(outlineStroke);
536         
537         // for CLOCKWISE charts, the extent will be negative...
538
if (extent < 0.0) {
539
540             if (isAngleAtFront(start)) { // start at front
541

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

599                     if (drawBack) {
600                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
601                                 plotArea.getX(), plotArea.getY(),
602                                 arc.getEndPoint().getX() - plotArea.getX(),
603                                 plotArea.getHeight()));
604                         side2.intersect(back);
605                         g2.setPaint(paint);
606                         g2.fill(side2);
607                         g2.setPaint(outlinePaint);
608                         g2.draw(side2);
609                     }
610
611                     if (drawFront) {
612                         Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
613                                 plotArea.getX(), plotArea.getY(),
614                                 arc.getStartPoint().getX() - plotArea.getX(),
615                                 plotArea.getHeight()));
616                         side1.intersect(front);
617                         g2.setPaint(paint);
618                         g2.fill(side1);
619                         g2.setPaint(outlinePaint);
620                         g2.draw(side1);
621                     }
622                 }
623             }
624             else { // the segment starts at the back (still extending
625
// CLOCKWISE)
626

627                 if (!isAngleAtFront(end)) {
628                     if (extent > -180.0) { // whole segment stays at the back
629
if (drawBack) {
630                             Area JavaDoc side = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
631                                     arc.getStartPoint().getX(), plotArea.getY(),
632                                     arc.getEndPoint().getX()
633                                     - arc.getStartPoint().getX(),
634                                     plotArea.getHeight()));
635                             side.intersect(back);
636                             g2.setPaint(paint);
637                             g2.fill(side);
638                             g2.setPaint(outlinePaint);
639                             g2.draw(side);
640                         }
641                     }
642                     else { // starts at the back, wraps around front, and
643
// finishes at back again
644
Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
645                                 arc.getStartPoint().getX(), plotArea.getY(),
646                                 plotArea.getMaxX() - arc.getStartPoint().getX(),
647                                 plotArea.getHeight()));
648                         side1.intersect(back);
649
650                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
651                                 plotArea.getX(), plotArea.getY(),
652                                 arc.getEndPoint().getX() - plotArea.getX(),
653                                 plotArea.getHeight()));
654
655                         side2.intersect(back);
656
657                         g2.setPaint(paint);
658                         if (drawBack) {
659                             g2.fill(side1);
660                             g2.fill(side2);
661                         }
662
663                         if (drawFront) {
664                             g2.fill(front);
665                         }
666
667                         g2.setPaint(outlinePaint);
668                         if (drawBack) {
669                             g2.draw(side1);
670                             g2.draw(side2);
671                         }
672
673                         if (drawFront) {
674                             g2.draw(front);
675                         }
676
677                     }
678                 }
679                 else { // starts at back, finishes at front (CLOCKWISE)
680

681                     if (drawBack) {
682                         Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
683                                 arc.getStartPoint().getX(), plotArea.getY(),
684                                 plotArea.getMaxX() - arc.getStartPoint().getX(),
685                                 plotArea.getHeight()));
686                         side1.intersect(back);
687                         g2.setPaint(paint);
688                         g2.fill(side1);
689                         g2.setPaint(outlinePaint);
690                         g2.draw(side1);
691                     }
692
693                     if (drawFront) {
694                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
695                                 arc.getEndPoint().getX(), plotArea.getY(),
696                                 plotArea.getMaxX() - arc.getEndPoint().getX(),
697                                 plotArea.getHeight()));
698                         side2.intersect(front);
699                         g2.setPaint(paint);
700                         g2.fill(side2);
701                         g2.setPaint(outlinePaint);
702                         g2.draw(side2);
703                     }
704
705                 }
706             }
707         }
708         else if (extent > 0.0) { // the pie sections are arranged ANTICLOCKWISE
709

710             if (isAngleAtFront(start)) { // segment starts at the front
711

712                 if (!isAngleAtBack(end)) { // and finishes at the front
713

714                     if (extent < 180.0) { // segment only occupies the front
715
if (drawFront) {
716                             Area JavaDoc side = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
717                                     arc.getStartPoint().getX(), plotArea.getY(),
718                                     arc.getEndPoint().getX()
719                                     - arc.getStartPoint().getX(),
720                                     plotArea.getHeight()));
721                             side.intersect(front);
722                             g2.setPaint(paint);
723                             g2.fill(side);
724                             g2.setPaint(outlinePaint);
725                             g2.draw(side);
726                         }
727                     }
728                     else { // segments wraps right around the back...
729
Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
730                                 arc.getStartPoint().getX(), plotArea.getY(),
731                                 plotArea.getMaxX() - arc.getStartPoint().getX(),
732                                 plotArea.getHeight()));
733                         side1.intersect(front);
734
735                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
736                                 plotArea.getX(), plotArea.getY(),
737                                 arc.getEndPoint().getX() - plotArea.getX(),
738                                 plotArea.getHeight()));
739                         side2.intersect(front);
740
741                         g2.setPaint(paint);
742                         if (drawFront) {
743                             g2.fill(side1);
744                             g2.fill(side2);
745                         }
746
747                         if (drawBack) {
748                             g2.fill(back);
749                         }
750
751                         g2.setPaint(outlinePaint);
752                         if (drawFront) {
753                             g2.draw(side1);
754                             g2.draw(side2);
755                         }
756
757                         if (drawBack) {
758                             g2.draw(back);
759                         }
760
761                     }
762                 }
763                 else { // segments starts at front and finishes at back...
764
if (drawBack) {
765                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
766                                 arc.getEndPoint().getX(), plotArea.getY(),
767                                 plotArea.getMaxX() - arc.getEndPoint().getX(),
768                                 plotArea.getHeight()));
769                         side2.intersect(back);
770                         g2.setPaint(paint);
771                         g2.fill(side2);
772                         g2.setPaint(outlinePaint);
773                         g2.draw(side2);
774                     }
775
776                     if (drawFront) {
777                         Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
778                                 arc.getStartPoint().getX(), plotArea.getY(),
779                                 plotArea.getMaxX() - arc.getStartPoint().getX(),
780                                 plotArea.getHeight()));
781                         side1.intersect(front);
782                         g2.setPaint(paint);
783                         g2.fill(side1);
784                         g2.setPaint(outlinePaint);
785                         g2.draw(side1);
786                     }
787                 }
788             }
789             else { // segment starts at back
790

791                 if (!isAngleAtFront(end)) {
792                     if (extent < 180.0) { // and finishes at back
793
if (drawBack) {
794                             Area JavaDoc side = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
795                                     arc.getEndPoint().getX(), plotArea.getY(),
796                                     arc.getStartPoint().getX()
797                                     - arc.getEndPoint().getX(),
798                                     plotArea.getHeight()));
799                             side.intersect(back);
800                             g2.setPaint(paint);
801                             g2.fill(side);
802                             g2.setPaint(outlinePaint);
803                             g2.draw(side);
804                         }
805                     }
806                     else { // starts at back and wraps right around to the
807
// back again
808
Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
809                                 arc.getStartPoint().getX(), plotArea.getY(),
810                                 plotArea.getX() - arc.getStartPoint().getX(),
811                                 plotArea.getHeight()));
812                         side1.intersect(back);
813
814                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
815                                 arc.getEndPoint().getX(), plotArea.getY(),
816                                 plotArea.getMaxX() - arc.getEndPoint().getX(),
817                                 plotArea.getHeight()));
818                         side2.intersect(back);
819
820                         g2.setPaint(paint);
821                         if (drawBack) {
822                             g2.fill(side1);
823                             g2.fill(side2);
824                         }
825
826                         if (drawFront) {
827                             g2.fill(front);
828                         }
829
830                         g2.setPaint(outlinePaint);
831                         if (drawBack) {
832                             g2.draw(side1);
833                             g2.draw(side2);
834                         }
835
836                         if (drawFront) {
837                             g2.draw(front);
838                         }
839
840                     }
841                 }
842                 else { // starts at the back and finishes at the front
843
// (wrapping the left side)
844
if (drawBack) {
845                         Area JavaDoc side1 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
846                                 plotArea.getX(), plotArea.getY(),
847                                 arc.getStartPoint().getX() - plotArea.getX(),
848                                 plotArea.getHeight()));
849                         side1.intersect(back);
850                         g2.setPaint(paint);
851                         g2.fill(side1);
852                         g2.setPaint(outlinePaint);
853                         g2.draw(side1);
854                     }
855
856                     if (drawFront) {
857                         Area JavaDoc side2 = new Area JavaDoc(new Rectangle2D.Double JavaDoc(
858                                 plotArea.getX(), plotArea.getY(),
859                                 arc.getEndPoint().getX() - plotArea.getX(),
860                                 plotArea.getHeight()));
861                         side2.intersect(front);
862                         g2.setPaint(paint);
863                         g2.fill(side2);
864                         g2.setPaint(outlinePaint);
865                         g2.draw(side2);
866                     }
867                 }
868             }
869
870         }
871
872     }
873
874     /**
875      * Returns a short string describing the type of plot.
876      *
877      * @return <i>Pie 3D Plot</i>.
878      */

879     public String JavaDoc getPlotType () {
880         return localizationResources.getString("Pie_3D_Plot");
881     }
882
883     /**
884      * A utility method that returns true if the angle represents a point at
885      * the front of the 3D pie chart. 0 - 180 degrees is the back, 180 - 360
886      * is the front.
887      *
888      * @param angle the angle.
889      *
890      * @return A boolean.
891      */

892     private boolean isAngleAtFront(double angle) {
893         return (Math.sin(Math.toRadians(angle)) < 0.0);
894     }
895
896     /**
897      * A utility method that returns true if the angle represents a point at
898      * the back of the 3D pie chart. 0 - 180 degrees is the back, 180 - 360
899      * is the front.
900      *
901      * @param angle the angle.
902      *
903      * @return <code>true</code> if the angle is at the back of the pie.
904      */

905     private boolean isAngleAtBack(double angle) {
906         return (Math.sin(Math.toRadians(angle)) > 0.0);
907     }
908
909 }
910
Popular Tags