    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    }