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