001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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     * 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    
049    package org.jfree.chart.needle;
050    
051    import java.awt.BasicStroke;
052    import java.awt.Color;
053    import java.awt.Graphics2D;
054    import java.awt.Paint;
055    import java.awt.Shape;
056    import java.awt.Stroke;
057    import java.awt.geom.AffineTransform;
058    import java.awt.geom.Point2D;
059    import java.awt.geom.Rectangle2D;
060    import java.io.IOException;
061    import java.io.ObjectInputStream;
062    import java.io.ObjectOutputStream;
063    import java.io.Serializable;
064    
065    import org.jfree.chart.HashUtilities;
066    import org.jfree.io.SerialUtilities;
067    import org.jfree.util.ObjectUtilities;
068    import 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     */
074    public 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    }