Source for org.jfree.chart.plot.ColorPalette

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * -----------------
  28:  * ColorPalette.java
  29:  * -----------------
  30:  * (C) Copyright 2002-2005, by David M. O'Donnell and Contributors.
  31:  *
  32:  * Original Author:  David M. O'Donnell;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: ColorPalette.java,v 1.1.2.1 2005/11/24 16:11:49 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG);
  40:  * 26-Mar-2003 : Implemented Serializable (DG);
  41:  * 14-Aug-2003 : Implemented Cloneable (DG);
  42:  *
  43:  */
  44: 
  45: package org.jfree.chart.plot;
  46: 
  47: import java.awt.Color;
  48: import java.awt.Paint;
  49: import java.io.Serializable;
  50: import java.util.Arrays;
  51: 
  52: import org.jfree.chart.axis.ValueTick;
  53: 
  54: /**
  55:  * Defines palette used in Contour Plots.
  56:  *
  57:  * @author David M. O'Donnell.
  58:  */
  59: public abstract class ColorPalette implements Cloneable, Serializable {
  60: 
  61:     /** For serialization. */
  62:     private static final long serialVersionUID = -9029901853079622051L;
  63:     
  64:     /** The min z-axis value. */
  65:     protected double minZ = -1;
  66: 
  67:     /** The max z-axis value. */
  68:     protected double maxZ = -1;
  69: 
  70:     /** Red components. */
  71:     protected int[] r;
  72: 
  73:     /** Green components. */
  74:     protected int[] g;
  75: 
  76:     /** Blue components. */
  77:     protected int[] b;
  78: 
  79:     /** Tick values are stored for use with stepped palette. */
  80:     protected double[] tickValues = null;
  81: 
  82:     /** Logscale? */
  83:     protected boolean logscale = false;
  84: 
  85:     /** Inverse palette (ie, min and max colors are reversed). */
  86:     protected boolean inverse = false;
  87: 
  88:     /** The palette name. */
  89:     protected String paletteName = null;
  90: 
  91:     /** Controls whether palette colors are stepped (not continuous). */
  92:     protected boolean stepped = false;
  93: 
  94:     /** Constant for converting loge to log10. */
  95:     protected static final double log10 = Math.log(10);
  96:     
  97:     /**
  98:      * Default contructor.
  99:      */
 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: }