001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2007, 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, 2006, 2007, 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 * $Id: DefaultPolarItemRenderer.java,v 1.7.2.6 2007/02/02 15:52:24 mungady Exp $ 037 * 038 * Changes 039 * ------- 040 * 19-Jan-2004 : Version 1, contributed by DB with minor changes by DG (DG); 041 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 042 * getYValue() (DG); 043 * 04-Oct-2004 : Renamed BooleanUtils --> BooleanUtilities (DG); 044 * 20-Apr-2005 : Update for change to LegendItem class (DG); 045 * ------------- JFREECHART 1.0.x --------------------------------------------- 046 * 04-Aug-2006 : Implemented equals() and clone() (DG); 047 * 02-Feb-2007 : Removed author tags from all over JFreeChart sources (DG); 048 * 049 */ 050 051 package org.jfree.chart.renderer; 052 053 import java.awt.AlphaComposite; 054 import java.awt.Composite; 055 import java.awt.Graphics2D; 056 import java.awt.Paint; 057 import java.awt.Point; 058 import java.awt.Polygon; 059 import java.awt.Shape; 060 import java.awt.Stroke; 061 import java.awt.geom.Ellipse2D; 062 import java.awt.geom.Rectangle2D; 063 import java.util.Iterator; 064 import java.util.List; 065 066 import org.jfree.chart.LegendItem; 067 import org.jfree.chart.axis.NumberTick; 068 import org.jfree.chart.axis.ValueAxis; 069 import org.jfree.chart.plot.DrawingSupplier; 070 import org.jfree.chart.plot.PlotRenderingInfo; 071 import org.jfree.chart.plot.PolarPlot; 072 import org.jfree.data.xy.XYDataset; 073 import org.jfree.text.TextUtilities; 074 import org.jfree.ui.TextAnchor; 075 import org.jfree.util.BooleanList; 076 import org.jfree.util.BooleanUtilities; 077 078 /** 079 * A renderer that can be used with the {@link PolarPlot} class. 080 */ 081 public class DefaultPolarItemRenderer extends AbstractRenderer 082 implements PolarItemRenderer { 083 084 /** The plot that the renderer is assigned to. */ 085 private PolarPlot plot; 086 087 /** Flags that control whether the renderer fills each series or not. */ 088 private BooleanList seriesFilled; 089 090 /** 091 * Creates a new instance of DefaultPolarItemRenderer 092 */ 093 public DefaultPolarItemRenderer() { 094 this.seriesFilled = new BooleanList(); 095 } 096 097 /** 098 * Returns the drawing supplier from the plot. 099 * 100 * @return The drawing supplier. 101 */ 102 public DrawingSupplier getDrawingSupplier() { 103 DrawingSupplier result = null; 104 PolarPlot p = getPlot(); 105 if (p != null) { 106 result = p.getDrawingSupplier(); 107 } 108 return result; 109 } 110 111 /** 112 * Set the plot associated with this renderer. 113 * 114 * @param plot the plot. 115 */ 116 public void setPlot(PolarPlot plot) { 117 this.plot = plot; 118 } 119 120 /** 121 * Return the plot associated with this renderer. 122 * 123 * @return The plot. 124 */ 125 public PolarPlot getPlot() { 126 return this.plot; 127 } 128 129 /** 130 * Plots the data for a given series. 131 * 132 * @param g2 the drawing surface. 133 * @param dataArea the data area. 134 * @param info collects plot rendering info. 135 * @param plot the plot. 136 * @param dataset the dataset. 137 * @param seriesIndex the series index. 138 */ 139 public void drawSeries(Graphics2D g2, 140 Rectangle2D dataArea, 141 PlotRenderingInfo info, 142 PolarPlot plot, 143 XYDataset dataset, 144 int seriesIndex) { 145 146 Polygon poly = new Polygon(); 147 int numPoints = dataset.getItemCount(seriesIndex); 148 for (int i = 0; i < numPoints; i++) { 149 double theta = dataset.getXValue(seriesIndex, i); 150 double radius = dataset.getYValue(seriesIndex, i); 151 Point p = plot.translateValueThetaRadiusToJava2D(theta, radius, 152 dataArea); 153 poly.addPoint(p.x, p.y); 154 } 155 g2.setPaint(getSeriesPaint(seriesIndex)); 156 g2.setStroke(getSeriesStroke(seriesIndex)); 157 if (isSeriesFilled(seriesIndex)) { 158 Composite savedComposite = g2.getComposite(); 159 g2.setComposite(AlphaComposite.getInstance( 160 AlphaComposite.SRC_OVER, 0.5f)); 161 g2.fill(poly); 162 g2.setComposite(savedComposite); 163 } 164 else { 165 g2.draw(poly); 166 } 167 } 168 169 /** 170 * Returns <code>true</code> if the renderer should fill the specified 171 * series, and <code>false</code> otherwise. 172 * 173 * @param series the series index (zero-based). 174 * 175 * @return A boolean. 176 */ 177 public boolean isSeriesFilled(int series) { 178 boolean result = false; 179 Boolean b = this.seriesFilled.getBoolean(series); 180 if (b != null) { 181 result = b.booleanValue(); 182 } 183 return result; 184 } 185 186 /** 187 * Sets a flag that controls whether or not a series is filled. 188 * 189 * @param series the series index. 190 * @param filled the flag. 191 */ 192 public void setSeriesFilled(int series, boolean filled) { 193 this.seriesFilled.setBoolean(series, BooleanUtilities.valueOf(filled)); 194 } 195 196 /** 197 * Draw the angular gridlines - the spokes. 198 * 199 * @param g2 the drawing surface. 200 * @param plot the plot. 201 * @param ticks the ticks. 202 * @param dataArea the data area. 203 */ 204 public void drawAngularGridLines(Graphics2D g2, 205 PolarPlot plot, 206 List ticks, 207 Rectangle2D dataArea) { 208 209 g2.setFont(plot.getAngleLabelFont()); 210 g2.setStroke(plot.getAngleGridlineStroke()); 211 g2.setPaint(plot.getAngleGridlinePaint()); 212 213 double axisMin = plot.getAxis().getLowerBound(); 214 double maxRadius = plot.getMaxRadius(); 215 216 Point center = plot.translateValueThetaRadiusToJava2D(axisMin, axisMin, 217 dataArea); 218 Iterator iterator = ticks.iterator(); 219 while (iterator.hasNext()) { 220 NumberTick tick = (NumberTick) iterator.next(); 221 Point p = plot.translateValueThetaRadiusToJava2D( 222 tick.getNumber().doubleValue(), maxRadius, dataArea); 223 g2.setPaint(plot.getAngleGridlinePaint()); 224 g2.drawLine(center.x, center.y, p.x, p.y); 225 if (plot.isAngleLabelsVisible()) { 226 int x = p.x; 227 int y = p.y; 228 g2.setPaint(plot.getAngleLabelPaint()); 229 TextUtilities.drawAlignedString(tick.getText(), g2, x, y, 230 TextAnchor.CENTER); 231 } 232 } 233 } 234 235 /** 236 * Draw the radial gridlines - the rings. 237 * 238 * @param g2 the drawing surface. 239 * @param plot the plot. 240 * @param radialAxis the radial axis. 241 * @param ticks the ticks. 242 * @param dataArea the data area. 243 */ 244 public void drawRadialGridLines(Graphics2D g2, 245 PolarPlot plot, 246 ValueAxis radialAxis, 247 List ticks, 248 Rectangle2D dataArea) { 249 250 g2.setFont(radialAxis.getTickLabelFont()); 251 g2.setPaint(plot.getRadiusGridlinePaint()); 252 g2.setStroke(plot.getRadiusGridlineStroke()); 253 254 double axisMin = radialAxis.getLowerBound(); 255 Point center = plot.translateValueThetaRadiusToJava2D(axisMin, axisMin, 256 dataArea); 257 258 Iterator iterator = ticks.iterator(); 259 while (iterator.hasNext()) { 260 NumberTick tick = (NumberTick) iterator.next(); 261 Point p = plot.translateValueThetaRadiusToJava2D(90.0, 262 tick.getNumber().doubleValue(), dataArea); 263 int r = p.x - center.x; 264 int upperLeftX = center.x - r; 265 int upperLeftY = center.y - r; 266 int d = 2 * r; 267 Ellipse2D ring = new Ellipse2D.Double(upperLeftX, upperLeftY, d, d); 268 g2.setPaint(plot.getRadiusGridlinePaint()); 269 g2.draw(ring); 270 } 271 } 272 273 /** 274 * Return the legend for the given series. 275 * 276 * @param series the series index. 277 * 278 * @return The legend item. 279 */ 280 public LegendItem getLegendItem(int series) { 281 LegendItem result = null; 282 PolarPlot polarPlot = getPlot(); 283 if (polarPlot != null) { 284 XYDataset dataset; 285 dataset = polarPlot.getDataset(); 286 if (dataset != null) { 287 String label = dataset.getSeriesKey(series).toString(); 288 String description = label; 289 Shape shape = getSeriesShape(series); 290 Paint paint = getSeriesPaint(series); 291 Paint outlinePaint = getSeriesOutlinePaint(series); 292 Stroke outlineStroke = getSeriesOutlineStroke(series); 293 result = new LegendItem(label, description, null, null, 294 shape, paint, outlineStroke, outlinePaint); 295 } 296 } 297 return result; 298 } 299 300 /** 301 * Tests this renderer for equality with an arbitrary object. 302 * 303 * @param obj the object (<code>null</code> not permitted). 304 * 305 * @return <code>true</code> if this renderer is equal to <code>obj</code>, 306 * and <code>false</code> otherwise. 307 */ 308 public boolean equals(Object obj) { 309 if (obj == null) { 310 return false; 311 } 312 if (!(obj instanceof DefaultPolarItemRenderer)) { 313 return false; 314 } 315 DefaultPolarItemRenderer that = (DefaultPolarItemRenderer) obj; 316 if (!this.seriesFilled.equals(that.seriesFilled)) { 317 return false; 318 } 319 return super.equals(obj); 320 } 321 322 /** 323 * Returns a clone of the renderer. 324 * 325 * @return A clone. 326 * 327 * @throws CloneNotSupportedException if the renderer cannot be cloned. 328 */ 329 public Object clone() throws CloneNotSupportedException { 330 return super.clone(); 331 } 332 333 }