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 * 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 }