    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     * ColorPalette.java
    029     * -----------------
    030     * (C) Copyright 2002-2005, by David M. O'Donnell and Contributors.
    031     *
    032     * Original Author:  David M. O'Donnell;
    033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034     *
    035     * $Id: ColorPalette.java,v 1.1.2.1 2005/11/24 16:11:49 mungady Exp $
    036     *
    037     * Changes
    038     * -------
    039     * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG);
    040     * 26-Mar-2003 : Implemented Serializable (DG);
    041     * 14-Aug-2003 : Implemented Cloneable (DG);
    042     *
    043     */
    044
    045    package org.jfree.chart.plot;
    046
    047    import java.awt.Color;
    048    import java.awt.Paint;
    049    import java.io.Serializable;
    050    import java.util.Arrays;
    051
    052    import org.jfree.chart.axis.ValueTick;
    053
    054    /**
    055     * Defines palette used in Contour Plots.
    056     *
    057     * @author David M. O'Donnell.
    058     */
    059    public abstract class ColorPalette implements Cloneable, Serializable {
    060
    061        /** For serialization. */
    062        private static final long serialVersionUID = -9029901853079622051L;
    063
    064        /** The min z-axis value. */
    065        protected double minZ = -1;
    066
    067        /** The max z-axis value. */
    068        protected double maxZ = -1;
    069
    070        /** Red components. */
    071        protected int[] r;
    072
    073        /** Green components. */
    074        protected int[] g;
    075
    076        /** Blue components. */
    077        protected int[] b;
    078
    079        /** Tick values are stored for use with stepped palette. */
    080        protected double[] tickValues = null;
    081
    082        /** Logscale? */
    083        protected boolean logscale = false;
    084
    085        /** Inverse palette (ie, min and max colors are reversed). */
    086        protected boolean inverse = false;
    087
    088        /** The palette name. */
    089        protected String paletteName = null;
    090
    091        /** Controls whether palette colors are stepped (not continuous). */
    092        protected boolean stepped = false;
    093
    094        /** Constant for converting loge to log10. */
    095        protected static final double log10 = Math.log(10);
    096
    097        /**
    098         * Default contructor.
    099         */
    100        public ColorPalette() {
    101            super();
    102        }
    103
    104        /**
    105         * Returns the color associated with a value.
    106         *
    107         * @param value  the value.
    108         *
    109         * @return The color.
    110         */
    111        public Paint getColor(double value) {
    112            int izV = (int) (253 * (value - this.minZ)
    113                        / (this.maxZ - this.minZ)) + 2;
    114            return new Color(this.r[izV], this.g[izV], this.b[izV]);
    115        }
    116
    117        /**
    118         * Returns a color.
    119         *
    120         * @param izV  ??.
    121         *
    122         * @return The color.
    123         */
    124        public Color getColor(int izV) {
    125            return new Color(this.r[izV], this.g[izV], this.b[izV]);
    126        }
    127
    128        /**
    129         * Returns Color by mapping a given value to a linear palette.
    130         *
    131         * @param value  the value.
    132         *
    133         * @return The color.
    134         */
    135        public Color getColorLinear(double value) {
    136            int izV = 0;
    137            if (this.stepped) {
    138                int index = Arrays.binarySearch(this.tickValues, value);
    139                if (index < 0) {
    140                    index = -1 * index - 2;
    141                }
    142
    143                if (index < 0) { // For the case were the first tick is greater
    144                                 // than minZ
    145                    value = this.minZ;
    146                }
    147                else {
    148                    value = this.tickValues[index];
    149                }
    150            }
    151            izV = (int) (253 * (value - this.minZ) / (this.maxZ - this.minZ)) + 2;
    152            izV = Math.min(izV, 255);
    153            izV = Math.max(izV, 2);
    154            return getColor(izV);
    155        }
    156
    157        /**
    158         * Returns Color by mapping a given value to a common log palette.
    159         *
    160         * @param value  the value.
    161         *
    162         * @return The color.
    163         */
    164        public Color getColorLog(double value) {
    165            int izV = 0;
    166            double minZtmp = this.minZ;
    167            double maxZtmp = this.maxZ;
    168            if (this.minZ <= 0.0) {
    169    //          negatives = true;
    170                this.maxZ = maxZtmp - minZtmp + 1;
    171                this.minZ = 1;
    172                value = value - minZtmp + 1;
    173            }
    174            double minZlog = Math.log(this.minZ) / log10;
    175            double maxZlog = Math.log(this.maxZ) / log10;
    176            value = Math.log(value) / log10;
    177            //  value = Math.pow(10,value);
    178            if (this.stepped) {
    179                int numSteps = this.tickValues.length;
    180                int steps = 256 / (numSteps - 1);
    181                izV = steps * (int) (numSteps * (value - minZlog)
    182                        / (maxZlog - minZlog)) + 2;
    183                //  izV = steps*numSteps*(int)((value/minZ)/(maxZlog-minZlog)) + 2;
    184            }
    185            else {
    186                izV = (int) (253 * (value - minZlog) / (maxZlog - minZlog)) + 2;
    187            }
    188            izV = Math.min(izV, 255);
    189            izV = Math.max(izV, 2);
    190
    191            this.minZ = minZtmp;
    192            this.maxZ = maxZtmp;
    193
    194            return getColor(izV);
    195        }
    196
    197        /**
    198         * Returns the maximum Z value.
    199         *
    200         * @return The value.
    201         */
    202        public double getMaxZ() {
    203            return this.maxZ;
    204        }
    205
    206        /**
    207         * Returns the minimum Z value.
    208         *
    209         * @return The value.
    210         */
    211        public double getMinZ() {
    212            return this.minZ;
    213        }
    214
    215        /**
    216         * Returns Paint by mapping a given value to a either a linear or common
    217         * log palette as controlled by the value logscale.
    218         *
    219         * @param value  the value.
    220         *
    221         * @return The paint.
    222         */
    223        public Paint getPaint(double value) {
    224            if (isLogscale()) {
    225                return getColorLog(value);
    226            }
    227            else {
    228                return getColorLinear(value);
    229            }
    230        }
    231
    232        /**
    233         * Returns the palette name.
    234         *
    235         * @return The palette name.
    236         */
    237        public String getPaletteName () {
    238            return this.paletteName;
    239        }
    240
    241        /**
    242         * Returns the tick values.
    243         *
    244         * @return The tick values.
    245         */
    246        public double[] getTickValues() {
    247            return this.tickValues;
    248        }
    249
    250        /**
    251         * Called to initialize the palette's color indexes
    252         */
    253        public abstract void initialize();
    254
    255        /**
    256         * Inverts Palette
    257         */
    258        public void invertPalette() {
    259
    260            int[] red = new int[256];
    261            int[] green = new int[256];
    262            int[] blue = new int[256];
    263            for (int i = 0; i < 256; i++) {
    264                red[i] = this.r[i];
    265                green[i] = this.g[i];
    266                blue[i] = this.b[i];
    267            }
    268
    269            for (int i = 2; i < 256; i++) {
    270                this.r[i] = red[257 - i];
    271                this.g[i] = green[257 - i];
    272                this.b[i] = blue[257 - i];
    273            }
    274        }
    275
    276        /**
    277         * Returns the inverse flag.
    278         *
    279         * @return The flag.
    280         */
    281        public boolean isInverse () {
    282            return this.inverse;
    283        }
    284
    285        /**
    286         * Returns the log-scale flag.
    287         *
    288         * @return The flag.
    289         */
    290        public boolean isLogscale() {
    291            return this.logscale;
    292        }
    293
    294        /**
    295         * Returns the 'is-stepped' flag.
    296         *
    297         * @return The flag.
    298         */
    299        public boolean isStepped () {
    300            return this.stepped;
    301        }
    302
    303        /**
    304         * Sets the inverse flag.
    305         *
    306         * @param inverse  the new value.
    307         */
    308        public void setInverse (boolean inverse) {
    309            this.inverse = inverse;
    310            initialize();
    311            if (inverse) {
    312                invertPalette();
    313            }
    314            return;
    315        }
    316
    317        /**
    318         * Sets the 'log-scale' flag.
    319         *
    320         * @param logscale  the new value.
    321         */
    322        public void setLogscale(boolean logscale) {
    323            this.logscale = logscale;
    324        }
    325
    326        /**
    327         * Sets the maximum Z value.
    328         *
    329         * @param newMaxZ  the new value.
    330         */
    331        public void setMaxZ(double newMaxZ) {
    332            this.maxZ = newMaxZ;
    333        }
    334
    335        /**
    336         * Sets the minimum Z value.
    337         *
    338         * @param newMinZ  the new value.
    339         */
    340        public void setMinZ(double newMinZ) {
    341            this.minZ = newMinZ;
    342        }
    343
    344        /**
    345         * Sets the palette name.
    346         *
    347         * @param paletteName  the name.
    348         */
    349        public void setPaletteName (String paletteName) {
    350            //String oldValue = this.paletteName;
    351            this.paletteName = paletteName;
    352            return;
    353        }
    354
    355        /**
    356         * Sets the stepped flag.
    357         *
    358         * @param stepped  the flag.
    359         */
    360        public void setStepped (boolean stepped) {
    361            this.stepped = stepped;
    362            return;
    363        }
    364
    365        /**
    366         * Sets the tick values.
    367         *
    368         * @param newTickValues  the tick values.
    369         */
    370        public void setTickValues(double[] newTickValues) {
    371            this.tickValues = newTickValues;
    372        }
    373
    374        /**
    375         * Store ticks. Required when doing stepped axis
    376         *
    377         * @param ticks  the ticks.
    378         */
    379        public void setTickValues(java.util.List ticks) {
    380            this.tickValues = new double[ticks.size()];
    381            for (int i = 0; i < this.tickValues.length; i++) {
    382                this.tickValues[i] = ((ValueTick) ticks.get(i)).getValue();
    383            }
    384        }
    385
    386        /**
    387         * Tests an object for equality with this instance.
    388         *
    389         * @param o  the object to test.
    390         *
    391         * @return A boolean.
    392         */
    393        public boolean equals(Object o) {
    394            if (this == o) {
    395                return true;
    396            }
    397            if (!(o instanceof ColorPalette)) {
    398                return false;
    399            }
    400
    401            ColorPalette colorPalette = (ColorPalette) o;
    402
    403            if (this.inverse != colorPalette.inverse) {
    404                return false;
    405            }
    406            if (this.logscale != colorPalette.logscale) {
    407                return false;
    408            }
    409            if (this.maxZ != colorPalette.maxZ) {
    410                return false;
    411            }
    412            if (this.minZ != colorPalette.minZ) {
    413                return false;
    414            }
    415            if (this.stepped != colorPalette.stepped) {
    416                return false;
    417            }
    418            if (!Arrays.equals(this.b, colorPalette.b)) {
    419                return false;
    420            }
    421            if (!Arrays.equals(this.g, colorPalette.g)) {
    422                return false;
    423            }
    424            if (this.paletteName != null
    425                    ? !this.paletteName.equals(colorPalette.paletteName)
    426                    : colorPalette.paletteName != null) {
    427                return false;
    428            }
    429            if (!Arrays.equals(this.r, colorPalette.r)) {
    430                return false;
    431            }
    432            if (!Arrays.equals(this.tickValues, colorPalette.tickValues)) {
    433                return false;
    434            }
    435
    436            return true;
    437        }
    438
    439        /**
    440         * Returns a hash code.
    441         *
    442         * @return A hash code.
    443         */
    444        public int hashCode() {
    445            int result;
    446            long temp;
    447            temp = Double.doubleToLongBits(this.minZ);
    448            result = (int) (temp ^ (temp >>> 32));
    449            temp = Double.doubleToLongBits(this.maxZ);
    450            result = 29 * result + (int) (temp ^ (temp >>> 32));
    451            result = 29 * result + (this.logscale ? 1 : 0);
    452            result = 29 * result + (this.inverse ? 1 : 0);
    453            result = 29 * result
    454                     + (this.paletteName != null ? this.paletteName.hashCode() : 0);
    455            result = 29 * result + (this.stepped ? 1 : 0);
    456            return result;
    457        }
    458
    459        /**
    460         * Returns a clone of the palette.
    461         *
    462         * @return A clone.
    463         *
    464         * @throws CloneNotSupportedException never.
    465         */
    466        public Object clone() throws CloneNotSupportedException {
    467
    468            ColorPalette clone = (ColorPalette) super.clone();
    469            return clone;
    470
    471        }
    472
    473    }