1 60 61 package org.jfree.chart.plot; 62 63 import java.awt.AlphaComposite ; 64 import java.awt.BasicStroke ; 65 import java.awt.Color ; 66 import java.awt.Composite ; 67 import java.awt.Font ; 68 import java.awt.FontMetrics ; 69 import java.awt.Graphics2D ; 70 import java.awt.Insets ; 71 import java.awt.Paint ; 72 import java.awt.Polygon ; 73 import java.awt.Shape ; 74 import java.awt.geom.Arc2D ; 75 import java.awt.geom.Area ; 76 import java.awt.geom.Ellipse2D ; 77 import java.awt.geom.Point2D ; 78 import java.awt.geom.Rectangle2D ; 79 import java.io.Serializable ; 80 import java.util.ArrayList ; 81 import java.util.Iterator ; 82 import java.util.List ; 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 99 public class Pie3DPlot extends PiePlot implements Serializable { 100 101 102 private double depthFactor = 0.2; 103 104 109 public Pie3DPlot(PieDataset data) { 110 super(data); 111 setCircularAttribute(false); 112 } 113 114 119 public void setDepthFactor(double newDepthFactor) { 120 this.depthFactor = newDepthFactor; 121 } 122 123 128 public double getDepthFactor () { 129 return depthFactor; 130 } 131 132 140 public void draw(Graphics2D g2, Rectangle2D plotArea, PlotState parentState, 141 PlotRenderingInfo info) { 142 143 Shape savedClip = g2.getClip(); 144 Rectangle2D clipArea = savedClip != null 145 ? savedClip.getBounds2D().createIntersection(plotArea) 146 : plotArea; 147 148 Insets 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 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 explodedPieArea = new Rectangle2D.Double (pieX, pieY, pieW, pieH); 181 double radiusPercent = getRadius(); 182 double explodeHorizontal = (1 - radiusPercent) * pieW; 183 double explodeVertical = (1 - radiusPercent) * pieH; 184 Rectangle2D pieArea = new Rectangle2D.Double (pieX + explodeHorizontal / 2, 185 pieY + explodeVertical / 2, 186 pieW - explodeHorizontal, 187 pieH - explodeVertical); 188 189 drawBackground(g2, plotArea); 190 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 (dataset.getKeys().size() > plotArea.getWidth()) { 201 String text = "Too many elements"; 202 Font sfont = new Font ("dialog", Font.BOLD, 10); 203 g2.setFont(sfont); 204 FontMetrics 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 (isCircular()) { 216 double min = Math.min(plotArea.getWidth(), plotArea.getHeight()) / 2; 217 plotArea = new Rectangle2D.Double (plotArea.getCenterX() - min, 218 plotArea.getCenterY() - min, 2 * min, 2 * min); 219 } 220 List sectionKeys = dataset.getKeys(); 222 223 if (sectionKeys.size() == 0) { 224 return; 225 } 226 227 double arcX = pieArea.getX(); 229 double arcY = pieArea.getY(); 230 231 g2.clip(clipArea); 232 Composite 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; } 241 242 ArrayList arcList = new ArrayList (); 243 Arc2D.Double arc; 244 Paint paint; 245 Paint outlinePaint; 246 247 Iterator iterator = sectionKeys.iterator(); 248 while (iterator.hasNext()) { 249 250 Comparable currentKey = (Comparable ) iterator.next(); 251 Number 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 (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 oldClip = g2.getClip(); 278 279 Ellipse2D top = new Ellipse2D.Double (pieArea.getX(), 280 pieArea.getY(), 281 pieArea.getWidth(), 282 pieArea.getHeight() - depth); 283 284 Ellipse2D bottom = new Ellipse2D.Double (pieArea.getX(), 285 pieArea.getY() + depth, 286 pieArea.getWidth(), 287 pieArea.getHeight() - depth); 288 289 Rectangle2D lower = new Rectangle2D.Double (top.getX(), 290 top.getCenterY(), 291 pieArea.getWidth(), 292 bottom.getMaxY() - top.getCenterY()); 293 294 Rectangle2D upper = new Rectangle2D.Double (pieArea.getX(), 295 top.getY(), 296 pieArea.getWidth(), 297 bottom.getCenterY() - top.getY()); 298 299 Area a = new Area (top); 300 a.add(new Area (lower)); 301 Area b = new Area (bottom); 302 b.add(new Area (upper)); 303 Area pie = new Area (a); 304 pie.intersect(b); 305 306 Area front = new Area (pie); 307 front.subtract(new Area (top)); 308 309 Area back = new Area (pie); 310 back.subtract(new Area (bottom)); 311 312 int[] xs; 314 int[] ys; 315 outlinePaint = getSectionOutlinePaint(0); 316 arc = new Arc2D.Double (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 ) 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 p1 = arc.getStartPoint(); 338 339 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 polygon = new Polygon (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 int cat = 0; 359 iterator = arcList.iterator(); 360 while (iterator.hasNext()) { 361 Arc2D segment = (Arc2D ) 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 cat = 0; 372 iterator = arcList.iterator(); 373 while (iterator.hasNext()) { 374 Arc2D segment = (Arc2D ) 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 Arc2D upperArc; 387 for (int sectionIndex = 0; sectionIndex < categoryCount; sectionIndex++) { 388 arc = (Arc2D.Double ) arcList.get(sectionIndex); 389 if (arc == null) { 390 continue; 391 } 392 upperArc = new Arc2D.Double (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 ()); 404 g2.setPaint(outlinePaint); 405 g2.draw(upperArc); 406 407 Comparable currentKey = (Comparable ) 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 tip = getItemLabelGenerator().generateToolTip(dataset, currentKey, 0); 416 String 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 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 453 public void drawSide(Graphics2D g2, 454 Rectangle2D plotArea, Arc2D arc, Area front, Area back, 455 Paint paint, Paint outlinePaint, 456 boolean drawFront, boolean drawBack) { 457 458 double start = arc.getAngleStart(); 459 double extent = arc.getAngleExtent(); 460 double end = start + extent; 461 462 if (extent < 0.0) { 464 465 if (isAngleAtFront(start)) { 467 if (!isAngleAtBack(end)) { 468 469 if (extent > -180.0) { if (drawFront) { 471 Area side = new Area ( 472 new Rectangle2D.Double (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 { Area side1 = new Area ( 486 new Rectangle2D.Double (plotArea.getX(), plotArea.getY(), 487 arc.getStartPoint().getX() - plotArea.getX(), 488 plotArea.getHeight())); 489 side1.intersect(front); 490 491 Area side2 = new Area ( 492 new Rectangle2D.Double (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 { 522 if (drawBack) { 523 Area side2 = new Area ( 524 new Rectangle2D.Double (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 side1 = new Area ( 536 new Rectangle2D.Double (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 { 549 if (!isAngleAtFront(end)) { 550 if (extent > -180.0) { if (drawBack) { 552 Area side = new Area ( 553 new Rectangle2D.Double (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 { Area side1 = new Area ( 566 new Rectangle2D.Double (arc.getStartPoint().getX(), plotArea.getY(), 567 plotArea.getMaxX() 568 - arc.getStartPoint().getX(), 569 plotArea.getHeight())); 570 side1.intersect(back); 571 572 Area side2 = new Area ( 573 new Rectangle2D.Double (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 { 604 if (drawBack) { 605 Area side1 = new Area ( 606 new Rectangle2D.Double (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 side2 = new Area ( 618 new Rectangle2D.Double (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) { 633 if (isAngleAtFront(start)) { 635 if (!isAngleAtBack(end)) { 637 if (extent < 180.0) { if (drawFront) { 639 Area side = new Area ( 640 new Rectangle2D.Double (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 { Area side1 = new Area ( 653 new Rectangle2D.Double (arc.getStartPoint().getX(), plotArea.getY(), 654 plotArea.getMaxX() - arc.getStartPoint().getX(), 655 plotArea.getHeight())); 656 side1.intersect(front); 657 658 Area side2 = new Area ( 659 new Rectangle2D.Double (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 { if (drawBack) { 690 Area side2 = new Area ( 691 new Rectangle2D.Double (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 side1 = new Area ( 703 new Rectangle2D.Double (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 { 716 if (!isAngleAtFront(end)) { 717 if (extent < 180.0) { if (drawBack) { 719 Area side = new Area ( 720 new Rectangle2D.Double (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 { Area side1 = new Area ( 733 new Rectangle2D.Double (arc.getStartPoint().getX(), plotArea.getY(), 734 plotArea.getX() - arc.getStartPoint().getX(), 735 plotArea.getHeight())); 736 side1.intersect(back); 737 738 Area side2 = new Area ( 739 new Rectangle2D.Double (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 { if (drawBack) { 769 Area side1 = new Area ( 770 new Rectangle2D.Double (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 side2 = new Area ( 782 new Rectangle2D.Double (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 803 public String getPlotType () { 804 return localizationResources.getString("Pie_3D_Plot"); 805 } 806 807 815 private boolean isAngleAtFront(double angle) { 816 817 return (Math.sin(Math.toRadians(angle)) < 0.0); 818 819 } 820 821 829 private boolean isAngleAtBack(double angle) { 830 831 return (Math.sin(Math.toRadians(angle)) > 0.0); 832 833 } 834 835 } 836 | Popular Tags |