001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------------------------- 028 * DefaultPolarItemRenderer.java 029 * ----------------------------- 030 * (C) Copyright 2004-2008, by Solution Engineering, Inc. and 031 * Contributors. 032 * 033 * Original Author: Daniel Bridenbecker, Solution Engineering, Inc.; 034 * Contributor(s): David Gilbert (for Object Refinery Limited); 035 * 036 * Changes 037 * ------- 038 * 19-Jan-2004 : Version 1, contributed by DB with minor changes by DG (DG); 039 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 040 * getYValue() (DG); 041 * 04-Oct-2004 : Renamed BooleanUtils --> BooleanUtilities (DG); 042 * 20-Apr-2005 : Update for change to LegendItem class (DG); 043 * ------------- JFREECHART 1.0.x --------------------------------------------- 044 * 04-Aug-2006 : Implemented equals() and clone() (DG); 045 * 02-Feb-2007 : Removed author tags from all over JFreeChart sources (DG); 046 * 14-Mar-2007 : Fixed clone() method (DG); 047 * 04-May-2007 : Fixed lookup for series paint and stroke (DG); 048 * 18-May-2007 : Set dataset for LegendItem (DG); 049 * 050 */ 051 052 package org.jfree.chart.renderer; 053 054 import java.awt.AlphaComposite; 055 import java.awt.Composite; 056 import java.awt.Graphics2D; 057 import java.awt.Paint; 058 import java.awt.Point; 059 import java.awt.Polygon; 060 import java.awt.Shape; 061 import java.awt.Stroke; 062 import java.awt.geom.Ellipse2D; 063 import java.awt.geom.Rectangle2D; 064 import java.util.Iterator; 065 import java.util.List; 066 067 import org.jfree.chart.LegendItem; 068 import org.jfree.chart.axis.NumberTick; 069 import org.jfree.chart.axis.ValueAxis; 070 import org.jfree.chart.plot.DrawingSupplier; 071 import org.jfree.chart.plot.PlotRenderingInfo; 072 import org.jfree.chart.plot.PolarPlot; 073 import org.jfree.data.xy.XYDataset; 074 import org.jfree.text.TextUtilities; 075 import org.jfree.ui.TextAnchor; 076 import org.jfree.util.BooleanList; 077 import org.jfree.util.BooleanUtilities; 078 079 /** 080 * A renderer that can be used with the {@link PolarPlot} class. 081 */ 082 public class DefaultPolarItemRenderer extends AbstractRenderer 083 implements PolarItemRenderer { 084 085 /** The plot that the renderer is assigned to. */ 086 private PolarPlot plot; 087 088 /** Flags that control whether the renderer fills each series or not. */ 089 private BooleanList seriesFilled; 090 091 /** 092 * Creates a new instance of DefaultPolarItemRenderer 093 */ 094 public DefaultPolarItemRenderer() { 095 this.seriesFilled = new BooleanList(); 096 } 097 098 /** 099 * Set the plot associated with this renderer. 100 * 101 * @param plot the plot. 102 * 103 * @see #getPlot() 104 */ 105 public void setPlot(PolarPlot plot) { 106 this.plot = plot; 107 } 108 109 /** 110 * Return the plot associated with this renderer. 111 * 112 * @return The plot. 113 * 114 * @see #setPlot(PolarPlot) 115 */ 116 public PolarPlot getPlot() { 117 return this.plot; 118 } 119 120 /** 121 * Returns the drawing supplier from the plot. 122 * 123 * @return The drawing supplier. 124 */ 125 public DrawingSupplier getDrawingSupplier() { 126 DrawingSupplier result = null; 127 PolarPlot p = getPlot(); 128 if (p != null) { 129 result = p.getDrawingSupplier(); 130 } 131 return result; 132 } 133 134 /** 135 * Returns <code>true</code> if the renderer should fill the specified 136 * series, and <code>false</code> otherwise. 137 * 138 * @param series the series index (zero-based). 139 * 140 * @return A boolean. 141 */ 142 public boolean isSeriesFilled(int series) { 143 boolean result = false; 144 Boolean b = this.seriesFilled.getBoolean(series); 145 if (b != null) { 146 result = b.booleanValue(); 147 } 148 return result; 149 } 150 151 /** 152 * Sets a flag that controls whether or not a series is filled. 153 * 154 * @param series the series index. 155 * @param filled the flag. 156 */ 157 public void setSeriesFilled(int series, boolean filled) { 158 this.seriesFilled.setBoolean(series, BooleanUtilities.valueOf(filled)); 159 } 160 161 /** 162 * Plots the data for a given series. 163 * 164 * @param g2 the drawing surface. 165 * @param dataArea the data area. 166 * @param info collects plot rendering info. 167 * @param plot the plot. 168 * @param dataset the dataset. 169 * @param seriesIndex the series index. 170 */ 171 public void drawSeries(Graphics2D g2, 172 Rectangle2D dataArea, 173 PlotRenderingInfo info, 174 PolarPlot plot, 175 XYDataset dataset, 176 int seriesIndex) { 177 178 Polygon poly = new Polygon(); 179 int numPoints = dataset.getItemCount(seriesIndex); 180 for (int i = 0; i < numPoints; i++) { 181 double theta = dataset.getXValue(seriesIndex, i); 182 double radius = dataset.getYValue(seriesIndex, i); 183 Point p = plot.translateValueThetaRadiusToJava2D(theta, radius, 184 dataArea); 185 poly.addPoint(p.x, p.y); 186 } 187 g2.setPaint(lookupSeriesPaint(seriesIndex)); 188 g2.setStroke(lookupSeriesStroke(seriesIndex)); 189 if (isSeriesFilled(seriesIndex)) { 190 Composite savedComposite = g2.getComposite(); 191 g2.setComposite(AlphaComposite.getInstance( 192 AlphaComposite.SRC_OVER, 0.5f)); 193 g2.fill(poly); 194 g2.setComposite(savedComposite); 195 } 196 else { 197 g2.draw(poly); 198 } 199 } 200 201 /** 202 * Draw the angular gridlines - the spokes. 203 * 204 * @param g2 the drawing surface. 205 * @param plot the plot. 206 * @param ticks the ticks. 207 * @param dataArea the data area. 208 */ 209 public void drawAngularGridLines(Graphics2D g2, 210 PolarPlot plot, 211 List ticks, 212 Rectangle2D dataArea) { 213 214 g2.setFont(plot.getAngleLabelFont()); 215 g2.setStroke(plot.getAngleGridlineStroke()); 216 g2.setPaint(plot.getAngleGridlinePaint()); 217 218 double axisMin = plot.getAxis().getLowerBound(); 219 double maxRadius = plot.getMaxRadius(); 220 221 Point center = plot.translateValueThetaRadiusToJava2D(axisMin, axisMin, 222 dataArea); 223 Iterator iterator = ticks.iterator(); 224 while (iterator.hasNext()) { 225 NumberTick tick = (NumberTick) iterator.next(); 226 Point p = plot.translateValueThetaRadiusToJava2D( 227 tick.getNumber().doubleValue(), maxRadius, dataArea); 228 g2.setPaint(plot.getAngleGridlinePaint()); 229 g2.drawLine(center.x, center.y, p.x, p.y); 230 if (plot.isAngleLabelsVisible()) { 231 int x = p.x; 232 int y = p.y; 233 g2.setPaint(plot.getAngleLabelPaint()); 234 TextUtilities.drawAlignedString(tick.getText(), g2, x, y, 235 TextAnchor.CENTER); 236 } 237 } 238 } 239 240 /** 241 * Draw the radial gridlines - the rings. 242 * 243 * @param g2 the drawing surface. 244 * @param plot the plot. 245 * @param radialAxis the radial axis. 246 * @param ticks the ticks. 247 * @param dataArea the data area. 248 */ 249 public void drawRadialGridLines(Graphics2D g2, 250 PolarPlot plot, 251 ValueAxis radialAxis, 252 List ticks, 253 Rectangle2D dataArea) { 254 255 g2.setFont(radialAxis.getTickLabelFont()); 256 g2.setPaint(plot.getRadiusGridlinePaint()); 257 g2.setStroke(plot.getRadiusGridlineStroke()); 258 259 double axisMin = radialAxis.getLowerBound(); 260 Point center = plot.translateValueThetaRadiusToJava2D(axisMin, axisMin, 261 dataArea); 262 263 Iterator iterator = ticks.iterator(); 264 while (iterator.hasNext()) { 265 NumberTick tick = (NumberTick) iterator.next(); 266 Point p = plot.translateValueThetaRadiusToJava2D(90.0, 267 tick.getNumber().doubleValue(), dataArea); 268 int r = p.x - center.x; 269 int upperLeftX = center.x - r; 270 int upperLeftY = center.y - r; 271 int d = 2 * r; 272 Ellipse2D ring = new Ellipse2D.Double(upperLeftX, upperLeftY, d, d); 273 g2.setPaint(plot.getRadiusGridlinePaint()); 274 g2.draw(ring); 275 } 276 } 277 278 /** 279 * Return the legend for the given series. 280 * 281 * @param series the series index. 282 * 283 * @return The legend item. 284 */ 285 public LegendItem getLegendItem(int series) { 286 LegendItem result = null; 287 PolarPlot polarPlot = getPlot(); 288 if (polarPlot != null) { 289 XYDataset dataset = polarPlot.getDataset(); 290 if (dataset != null) { 291 String label = dataset.getSeriesKey(series).toString(); 292 String description = label; 293 Shape shape = lookupSeriesShape(series); 294 Paint paint = lookupSeriesPaint(series); 295 Paint outlinePaint = lookupSeriesOutlinePaint(series); 296 Stroke outlineStroke = lookupSeriesOutlineStroke(series); 297 result = new LegendItem(label, description, null, null, 298 shape, paint, outlineStroke, outlinePaint); 299 result.setDataset(dataset); 300 } 301 } 302 return result; 303 } 304 305 /** 306 * Tests this renderer for equality with an arbitrary object. 307 * 308 * @param obj the object (<code>null</code> not permitted). 309 * 310 * @return <code>true</code> if this renderer is equal to <code>obj</code>, 311 * and <code>false</code> otherwise. 312 */ 313 public boolean equals(Object obj) { 314 if (obj == null) { 315 return false; 316 } 317 if (!(obj instanceof DefaultPolarItemRenderer)) { 318 return false; 319 } 320 DefaultPolarItemRenderer that = (DefaultPolarItemRenderer) obj; 321 if (!this.seriesFilled.equals(that.seriesFilled)) { 322 return false; 323 } 324 return super.equals(obj); 325 } 326 327 /** 328 * Returns a clone of the renderer. 329 * 330 * @return A clone. 331 * 332 * @throws CloneNotSupportedException if the renderer cannot be cloned. 333 */ 334 public Object clone() throws CloneNotSupportedException { 335 DefaultPolarItemRenderer clone 336 = (DefaultPolarItemRenderer) super.clone(); 337 clone.seriesFilled = (BooleanList) this.seriesFilled.clone(); 338 return clone; 339 } 340 341 }