    001/* ===========================================================
    002 * JFreeChart : a free chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C) Copyright 2000-2011, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    025 * Other names may be trademarks of their respective owners.]
    026 *
    027 * ----------------
    028 * MeterNeedle.java
    029 * ----------------
    030 * (C) Copyright 2002-2008, by the Australian Antarctic Division and
    031 *                          Contributors.
    032 *
    033 * Original Author:  Bryan Scott (for the Australian Antarctic Division);
    034 * Contributor(s):   David Gilbert (for Object Refinery Limited);
    035 *                   Nicolas Brodu (for Astrium and EADS Corporate Research
    036 *                   Center);
    037 *
    038 * Changes:
    039 * --------
    040 * 25-Sep-2002 : Version 1, contributed by Bryan Scott (DG);
    041 * 07-Nov-2002 : Fixed errors reported by Checkstyle (DG);
    042 * 01-Sep-2003 : Implemented Serialization (NB);
    043 * 16-Mar-2004 : Changed transform from private to protected (BRS);
    044 * 08-Jun-2005 : Fixed equals() method to handle GradientPaint (DG);
    045 * 22-Nov-2007 : Implemented hashCode() (DG);
    046 *
    047 */
    048
    049package org.jfree.chart.needle;
    050
    051import java.awt.BasicStroke;
    052import java.awt.Color;
    053import java.awt.Graphics2D;
    054import java.awt.Paint;
    055import java.awt.Shape;
    056import java.awt.Stroke;
    057import java.awt.geom.AffineTransform;
    058import java.awt.geom.Point2D;
    059import java.awt.geom.Rectangle2D;
    060import java.io.IOException;
    061import java.io.ObjectInputStream;
    062import java.io.ObjectOutputStream;
    063import java.io.Serializable;
    064
    065import org.jfree.chart.HashUtilities;
    066import org.jfree.io.SerialUtilities;
    067import org.jfree.util.ObjectUtilities;
    068import org.jfree.util.PaintUtilities;
    069
    070/**
    071 * The base class used to represent the needle on a
    072 * {@link org.jfree.chart.plot.CompassPlot}.
    073 */
    074public abstract class MeterNeedle implements Serializable {
    075
    076    /** For serialization. */
    077    private static final long serialVersionUID = 5203064851510951052L;
    078
    079    /** The outline paint. */
    080    private transient Paint outlinePaint = Color.black;
    081
    082    /** The outline stroke. */
    083    private transient Stroke outlineStroke = new BasicStroke(2);
    084
    085    /** The fill paint. */
    086    private transient Paint fillPaint = null;
    087
    088    /** The highlight paint. */
    089    private transient Paint highlightPaint = null;
    090
    091    /** The size. */
    092    private int size = 5;
    093
    094    /** Scalar to aply to locate the rotation x point. */
    095    private double rotateX = 0.5;
    096
    097    /** Scalar to aply to locate the rotation y point. */
    098    private double rotateY = 0.5;
    099
    100    /** A transform. */
    101    protected static AffineTransform transform = new AffineTransform();
    102
    103    /**
    104     * Creates a new needle.
    105     */
    106    public MeterNeedle() {
    107        this(null, null, null);
    108    }
    109
    110    /**
    111     * Creates a new needle.
    112     *
    113     * @param outline  the outline paint (<code>null</code> permitted).
    114     * @param fill  the fill paint (<code>null</code> permitted).
    115     * @param highlight  the highlight paint (<code>null</code> permitted).
    116     */
    117    public MeterNeedle(Paint outline, Paint fill, Paint highlight) {
    118        this.fillPaint = fill;
    119        this.highlightPaint = highlight;
    120        this.outlinePaint = outline;
    121    }
    122
    123    /**
    124     * Returns the outline paint.
    125     *
    126     * @return The outline paint.
    127     */
    128    public Paint getOutlinePaint() {
    129        return this.outlinePaint;
    130    }
    131
    132    /**
    133     * Sets the outline paint.
    134     *
    135     * @param p  the new paint.
    136     */
    137    public void setOutlinePaint(Paint p) {
    138        if (p != null) {
    139            this.outlinePaint = p;
    140        }
    141    }
    142
    143    /**
    144     * Returns the outline stroke.
    145     *
    146     * @return The outline stroke.
    147     */
    148    public Stroke getOutlineStroke() {
    149        return this.outlineStroke;
    150    }
    151
    152    /**
    153     * Sets the outline stroke.
    154     *
    155     * @param s  the new stroke.
    156     */
    157    public void setOutlineStroke(Stroke s) {
    158        if (s != null) {
    159            this.outlineStroke = s;
    160        }
    161    }
    162
    163    /**
    164     * Returns the fill paint.
    165     *
    166     * @return The fill paint.
    167     */
    168    public Paint getFillPaint() {
    169        return this.fillPaint;
    170    }
    171
    172    /**
    173     * Sets the fill paint.
    174     *
    175     * @param p  the fill paint.
    176     */
    177    public void setFillPaint(Paint p) {
    178        if (p != null) {
    179            this.fillPaint = p;
    180        }
    181    }
    182
    183    /**
    184     * Returns the highlight paint.
    185     *
    186     * @return The highlight paint.
    187     */
    188    public Paint getHighlightPaint() {
    189        return this.highlightPaint;
    190    }
    191
    192    /**
    193     * Sets the highlight paint.
    194     *
    195     * @param p  the highlight paint.
    196     */
    197    public void setHighlightPaint(Paint p) {
    198        if (p != null) {
    199            this.highlightPaint = p;
    200        }
    201    }
    202
    203    /**
    204     * Returns the scalar used for determining the rotation x value.
    205     *
    206     * @return The x rotate scalar.
    207     */
    208    public double getRotateX() {
    209        return this.rotateX;
    210    }
    211
    212    /**
    213     * Sets the rotateX value.
    214     *
    215     * @param x  the new value.
    216     */
    217    public void setRotateX(double x) {
    218        this.rotateX = x;
    219    }
    220
    221    /**
    222     * Sets the rotateY value.
    223     *
    224     * @param y  the new value.
    225     */
    226    public void setRotateY(double y) {
    227        this.rotateY = y;
    228    }
    229
    230    /**
    231     * Returns the scalar used for determining the rotation y value.
    232     *
    233     * @return The y rotate scalar.
    234     */
    235    public double getRotateY() {
    236        return this.rotateY;
    237    }
    238
    239    /**
    240     * Draws the needle.
    241     *
    242     * @param g2  the graphics device.
    243     * @param plotArea  the plot area.
    244     */
    245    public void draw(Graphics2D g2, Rectangle2D plotArea) {
    246        draw(g2, plotArea, 0);
    247    }
    248
    249    /**
    250     * Draws the needle.
    251     *
    252     * @param g2  the graphics device.
    253     * @param plotArea  the plot area.
    254     * @param angle  the angle.
    255     */
    256    public void draw(Graphics2D g2, Rectangle2D plotArea, double angle) {
    257
    258        Point2D.Double pt = new Point2D.Double();
    259        pt.setLocation(
    260            plotArea.getMinX() + this.rotateX * plotArea.getWidth(),
    261            plotArea.getMinY() + this.rotateY * plotArea.getHeight()
    262        );
    263        draw(g2, plotArea, pt, angle);
    264
    265    }
    266
    267    /**
    268     * Draws the needle.
    269     *
    270     * @param g2  the graphics device.
    271     * @param plotArea  the plot area.
    272     * @param rotate  the rotation point.
    273     * @param angle  the angle.
    274     */
    275    public void draw(Graphics2D g2, Rectangle2D plotArea, Point2D rotate,
    276                     double angle) {
    277
    278        Paint savePaint = g2.getColor();
    279        Stroke saveStroke = g2.getStroke();
    280
    281        drawNeedle(g2, plotArea, rotate, Math.toRadians(angle));
    282
    283        g2.setStroke(saveStroke);
    284        g2.setPaint(savePaint);
    285
    286    }
    287
    288    /**
    289     * Draws the needle.
    290     *
    291     * @param g2  the graphics device.
    292     * @param plotArea  the plot area.
    293     * @param rotate  the rotation point.
    294     * @param angle  the angle.
    295     */
    296    protected abstract void drawNeedle(Graphics2D g2,
    297                                       Rectangle2D plotArea, Point2D rotate,
    298                                       double angle);
    299
    300    /**
    301     * Displays a shape.
    302     *
    303     * @param g2  the graphics device.
    304     * @param shape  the shape.
    305     */
    306    protected void defaultDisplay(Graphics2D g2, Shape shape) {
    307
    308        if (this.fillPaint != null) {
    309            g2.setPaint(this.fillPaint);
    310            g2.fill(shape);
    311        }
    312
    313        if (this.outlinePaint != null) {
    314            g2.setStroke(this.outlineStroke);
    315            g2.setPaint(this.outlinePaint);
    316            g2.draw(shape);
    317        }
    318
    319    }
    320
    321    /**
    322     * Returns the size.
    323     *
    324     * @return The size.
    325     */
    326    public int getSize() {
    327        return this.size;
    328    }
    329
    330    /**
    331     * Sets the size.
    332     *
    333     * @param pixels  the new size.
    334     */
    335    public void setSize(int pixels) {
    336        this.size = pixels;
    337    }
    338
    339    /**
    340     * Returns the transform.
    341     *
    342     * @return The transform.
    343     */
    344    public AffineTransform getTransform() {
    345        return MeterNeedle.transform;
    346    }
    347
    348    /**
    349     * Tests another object for equality with this object.
    350     *
    351     * @param obj the object to test (<code>null</code> permitted).
    352     *
    353     * @return A boolean.
    354     */
    355    public boolean equals(Object obj) {
    356        if (obj == this) {
    357            return true;
    358        }
    359        if (!(obj instanceof MeterNeedle)) {
    360            return false;
    361        }
    362        MeterNeedle that = (MeterNeedle) obj;
    363        if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
    364            return false;
    365        }
    366        if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
    367            return false;
    368        }
    369        if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) {
    370            return false;
    371        }
    372        if (!PaintUtilities.equal(this.highlightPaint, that.highlightPaint)) {
    373            return false;
    374        }
    375        if (this.size != that.size) {
    376            return false;
    377        }
    378        if (this.rotateX != that.rotateX) {
    379            return false;
    380        }
    381        if (this.rotateY != that.rotateY) {
    382            return false;
    383        }
    384        return true;
    385    }
    386
    387    /**
    388     * Returns a hash code for this instance.
    389     *
    390     * @return A hash code.
    391     */
    392    public int hashCode() {
    393        int result = HashUtilities.hashCode(193, this.fillPaint);
    394        result = HashUtilities.hashCode(result, this.highlightPaint);
    395        result = HashUtilities.hashCode(result, this.outlinePaint);
    396        result = HashUtilities.hashCode(result, this.outlineStroke);
    397        result = HashUtilities.hashCode(result, this.rotateX);
    398        result = HashUtilities.hashCode(result, this.rotateY);
    399        result = HashUtilities.hashCode(result, this.size);
    400        return result;
    401    }
    402
    403    /**
    404     * Provides serialization support.
    405     *
    406     * @param stream  the output stream.
    407     *
    408     * @throws IOException  if there is an I/O error.
    409     */
    410    private void writeObject(ObjectOutputStream stream) throws IOException {
    411        stream.defaultWriteObject();
    412        SerialUtilities.writeStroke(this.outlineStroke, stream);
    413        SerialUtilities.writePaint(this.outlinePaint, stream);
    414        SerialUtilities.writePaint(this.fillPaint, stream);
    415        SerialUtilities.writePaint(this.highlightPaint, stream);
    416    }
    417
    418    /**
    419     * Provides serialization support.
    420     *
    421     * @param stream  the input stream.
    422     *
    423     * @throws IOException  if there is an I/O error.
    424     * @throws ClassNotFoundException  if there is a classpath problem.
    425     */
    426    private void readObject(ObjectInputStream stream)
    427        throws IOException, ClassNotFoundException {
    428        stream.defaultReadObject();
    429        this.outlineStroke = SerialUtilities.readStroke(stream);
    430        this.outlinePaint = SerialUtilities.readPaint(stream);
    431        this.fillPaint = SerialUtilities.readPaint(stream);
    432        this.highlightPaint = SerialUtilities.readPaint(stream);
    433    }
    434
    435}