Source for org.jfree.chart.renderer.DefaultPolarItemRenderer

   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:  * DefaultPolarItemRenderer.java
  29:  * -----------------------------
  30:  * (C) Copyright 2004, 2006, by Solution Engineering, Inc. and Contributors.
  31:  *
  32:  * Original Author:  Daniel Bridenbecker, Solution Engineering, Inc.;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: DefaultPolarItemRenderer.java,v 1.7.2.4 2006/08/04 15:16:50 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 19-Jan-2004 : Version 1, contributed by DB with minor changes by DG (DG);
  40:  * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
  41:  *               getYValue() (DG);
  42:  * 04-Oct-2004 : Renamed BooleanUtils --> BooleanUtilities (DG);
  43:  * 20-Apr-2005 : Update for change to LegendItem class (DG);
  44:  * ------------- JFREECHART 1.0.0 ---------------------------------------------
  45:  * 04-Aug-2006 : Implemented equals() and clone() (DG);
  46:  *
  47:  */
  48: 
  49: package org.jfree.chart.renderer;
  50: 
  51: import java.awt.AlphaComposite;
  52: import java.awt.Composite;
  53: import java.awt.Graphics2D;
  54: import java.awt.Paint;
  55: import java.awt.Point;
  56: import java.awt.Polygon;
  57: import java.awt.Shape;
  58: import java.awt.Stroke;
  59: import java.awt.geom.Ellipse2D;
  60: import java.awt.geom.Rectangle2D;
  61: import java.util.Iterator;
  62: import java.util.List;
  63: 
  64: import org.jfree.chart.LegendItem;
  65: import org.jfree.chart.axis.NumberTick;
  66: import org.jfree.chart.axis.ValueAxis;
  67: import org.jfree.chart.plot.DrawingSupplier;
  68: import org.jfree.chart.plot.PlotRenderingInfo;
  69: import org.jfree.chart.plot.PolarPlot;
  70: import org.jfree.data.xy.XYDataset;
  71: import org.jfree.text.TextUtilities;
  72: import org.jfree.ui.TextAnchor;
  73: import org.jfree.util.BooleanList;
  74: import org.jfree.util.BooleanUtilities;
  75: 
  76: /**
  77:  * A renderer that can be used with the {@link PolarPlot} class.
  78:  *
  79:  * @author  Daniel Bridenbecker, Solution Engineering, Inc.
  80:  */
  81: public class DefaultPolarItemRenderer extends AbstractRenderer  
  82:                                       implements PolarItemRenderer {
  83:        
  84:     /** The plot that the renderer is assigned to. */
  85:     private PolarPlot plot;
  86: 
  87:     /** Flags that control whether the renderer fills each series or not. */
  88:     private BooleanList seriesFilled;
  89:    
  90:     /**
  91:      * Creates a new instance of DefaultPolarItemRenderer
  92:      */
  93:     public DefaultPolarItemRenderer() {
  94:         this.seriesFilled = new BooleanList();
  95:     }
  96:    
  97:     // --------------------------------
  98:     // --- AbstractRenderer Methods ---
  99:     // --------------------------------
 100:    
 101:     /** 
 102:      * Returns the drawing supplier from the plot.
 103:      *
 104:      * @return The drawing supplier.
 105:      */
 106:     public DrawingSupplier getDrawingSupplier() {
 107:         DrawingSupplier result = null;
 108:         PolarPlot p = getPlot();
 109:         if (p != null) {
 110:             result = p.getDrawingSupplier();
 111:         }
 112:         return result;
 113:     }
 114:    
 115:     // ----------------------
 116:     // --- Public Methods ---
 117:     // ----------------------
 118:     /**
 119:      * Set the plot associated with this renderer.
 120:      * 
 121:      * @param plot  the plot.
 122:      */
 123:     public void setPlot(PolarPlot plot) {
 124:         this.plot = plot;
 125:     }
 126: 
 127:     /**
 128:      * Return the plot associated with this renderer.
 129:      * 
 130:      * @return The plot.
 131:      */
 132:     public PolarPlot getPlot() {
 133:         return this.plot;
 134:     }
 135: 
 136:     /**
 137:      * Plots the data for a given series.
 138:      * 
 139:      * @param g2  the drawing surface.
 140:      * @param dataArea  the data area.
 141:      * @param info  collects plot rendering info.
 142:      * @param plot  the plot.
 143:      * @param dataset  the dataset.
 144:      * @param seriesIndex  the series index.
 145:      */
 146:     public void drawSeries(Graphics2D g2, 
 147:                            Rectangle2D dataArea, 
 148:                            PlotRenderingInfo info,
 149:                            PolarPlot plot,
 150:                            XYDataset dataset,
 151:                            int seriesIndex) {
 152:         
 153:         Polygon poly = new Polygon();
 154:         int numPoints = dataset.getItemCount(seriesIndex);
 155:         for (int i = 0; i < numPoints; i++) {
 156:             double theta = dataset.getXValue(seriesIndex, i);
 157:             double radius = dataset.getYValue(seriesIndex, i);
 158:             Point p = plot.translateValueThetaRadiusToJava2D(
 159:                 theta, radius, dataArea
 160:             );
 161:             poly.addPoint(p.x, p.y);
 162:         }
 163:         g2.setPaint(getSeriesPaint(seriesIndex));
 164:         g2.setStroke(getSeriesStroke(seriesIndex));
 165:         if (isSeriesFilled(seriesIndex)) {
 166:             Composite savedComposite = g2.getComposite();
 167:             g2.setComposite(
 168:                 AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)
 169:             );
 170:             g2.fill(poly);
 171:             g2.setComposite(savedComposite);
 172:         }
 173:         else {
 174:             g2.draw(poly);
 175:         }
 176:     }
 177: 
 178:     /**
 179:      * Returns <code>true</code> if the renderer should fill the specified 
 180:      * series, and <code>false</code> otherwise.
 181:      * 
 182:      * @param series  the series index (zero-based).
 183:      * 
 184:      * @return A boolean.
 185:      */
 186:     public boolean isSeriesFilled(int series) {
 187:         boolean result = false;
 188:         Boolean b = this.seriesFilled.getBoolean(series);
 189:         if (b != null) {
 190:             result = b.booleanValue();
 191:         }
 192:         return result;
 193:     }
 194: 
 195:     /**
 196:      * Sets a flag that controls whether or not a series is filled.
 197:      * 
 198:      * @param series  the series index.
 199:      * @param filled  the flag.
 200:      */
 201:     public void setSeriesFilled(int series, boolean filled) {
 202:         this.seriesFilled.setBoolean(series, BooleanUtilities.valueOf(filled));
 203:     }
 204:     
 205:     /**
 206:      * Draw the angular gridlines - the spokes.
 207:      * 
 208:      * @param g2  the drawing surface.
 209:      * @param plot  the plot.
 210:      * @param ticks  the ticks.
 211:      * @param dataArea  the data area.
 212:      */
 213:     public void drawAngularGridLines(Graphics2D g2, 
 214:                                      PolarPlot plot, 
 215:                                      List ticks,
 216:                                      Rectangle2D dataArea) {
 217:         
 218:         g2.setFont(plot.getAngleLabelFont());
 219:         g2.setStroke(plot.getAngleGridlineStroke());
 220:         g2.setPaint(plot.getAngleGridlinePaint());
 221:       
 222:         double axisMin = plot.getAxis().getLowerBound();
 223:         double maxRadius = plot.getMaxRadius();
 224: 
 225:         Point center = plot.translateValueThetaRadiusToJava2D(
 226:             axisMin, axisMin, dataArea
 227:         );
 228:         Iterator iterator = ticks.iterator();
 229:         while (iterator.hasNext()) {
 230:             NumberTick tick = (NumberTick) iterator.next();
 231:             Point p = plot.translateValueThetaRadiusToJava2D(
 232:                 tick.getNumber().doubleValue(), maxRadius, dataArea
 233:             );
 234:             g2.setPaint(plot.getAngleGridlinePaint());
 235:             g2.drawLine(center.x, center.y, p.x, p.y);
 236:             if (plot.isAngleLabelsVisible()) {
 237:                 int x = p.x;
 238:                 int y = p.y;
 239:                 g2.setPaint(plot.getAngleLabelPaint());
 240:                 TextUtilities.drawAlignedString(
 241:                     tick.getText(), g2, x, y, TextAnchor.CENTER
 242:                 );
 243:             }
 244:         }
 245:      }
 246: 
 247:     /**
 248:      * Draw the radial gridlines - the rings.
 249:      * 
 250:      * @param g2  the drawing surface.
 251:      * @param plot  the plot.
 252:      * @param radialAxis  the radial axis.
 253:      * @param ticks  the ticks.
 254:      * @param dataArea  the data area.
 255:      */
 256:     public void drawRadialGridLines(Graphics2D g2, 
 257:                                     PolarPlot plot,
 258:                                     ValueAxis radialAxis,
 259:                                     List ticks,
 260:                                     Rectangle2D dataArea) {
 261:         
 262:         g2.setFont(radialAxis.getTickLabelFont());
 263:         g2.setPaint(plot.getRadiusGridlinePaint());
 264:         g2.setStroke(plot.getRadiusGridlineStroke());
 265: 
 266:         double axisMin = radialAxis.getLowerBound();
 267:         Point center = plot.translateValueThetaRadiusToJava2D(
 268:             axisMin, axisMin, dataArea
 269:         );
 270:         
 271:         Iterator iterator = ticks.iterator();
 272:         while (iterator.hasNext()) {
 273:             NumberTick tick = (NumberTick) iterator.next();
 274:             Point p = plot.translateValueThetaRadiusToJava2D(
 275:                 90.0, tick.getNumber().doubleValue(), dataArea
 276:             );
 277:             int r = p.x - center.x;
 278:             int upperLeftX = center.x - r;
 279:             int upperLeftY = center.y - r;
 280:             int d = 2 * r;
 281:             Ellipse2D ring = new Ellipse2D.Double(upperLeftX, upperLeftY, d, d);
 282:             g2.setPaint(plot.getRadiusGridlinePaint());
 283:             g2.draw(ring);
 284:         }
 285:     }
 286: 
 287:     /**
 288:      * Return the legend for the given series.
 289:      * 
 290:      * @param series  the series index.
 291:      * 
 292:      * @return The legend item.
 293:      */
 294:     public LegendItem getLegendItem(int series) {
 295:         LegendItem result = null;
 296:         PolarPlot polarPlot = getPlot();
 297:         if (polarPlot != null) {
 298:             XYDataset dataset;
 299:             dataset = polarPlot.getDataset();
 300:             if (dataset != null) {
 301:                 String label = dataset.getSeriesKey(series).toString();
 302:                 String description = label;
 303:                 Shape shape = getSeriesShape(series);
 304:                 Paint paint = getSeriesPaint(series);
 305:                 Paint outlinePaint = getSeriesOutlinePaint(series);
 306:                 Stroke outlineStroke = getSeriesOutlineStroke(series);
 307:                 result = new LegendItem(label, description, null, null, 
 308:                         shape, paint, outlineStroke, outlinePaint);
 309:             }
 310:         }
 311:         return result;
 312:     }
 313: 
 314:     /**
 315:      * Tests this renderer for equality with an arbitrary object.
 316:      * 
 317:      * @param obj  the object (<code>null</code> not permitted).
 318:      * 
 319:      * @return <code>true</code> if this renderer is equal to <code>obj</code>,
 320:      *     and <code>false</code> otherwise.
 321:      */
 322:     public boolean equals(Object obj) {
 323:         if (obj == null) {
 324:             return false;
 325:         }
 326:         if (!(obj instanceof DefaultPolarItemRenderer)) {
 327:             return false;
 328:         }
 329:         DefaultPolarItemRenderer that = (DefaultPolarItemRenderer) obj;
 330:         if (!this.seriesFilled.equals(that.seriesFilled)) {
 331:             return false;
 332:         }
 333:         return super.equals(obj);
 334:     }
 335:     
 336:     /**
 337:      * Returns a clone of the renderer.
 338:      *
 339:      * @return A clone.
 340:      *
 341:      * @throws CloneNotSupportedException if the renderer cannot be cloned.
 342:      */
 343:     public Object clone() throws CloneNotSupportedException {
 344:         return super.clone();
 345:     }
 346: 
 347: }