    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    }