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 under the terms
  10. * of the GNU Lesser General Public License as published by the Free Software Foundation;
  11. * either version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  14. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License along with this
  18. * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. *
  21. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  22. * in the United States and other countries.]
  23. *
  24. * -----------------
  25. * ColorPalette.java
  26. * -----------------
  27. * (C) Copyright 2002-2005, by David M. O'Donnell and Contributors.
  28. *
  29. * Original Author: David M. O'Donnell;
  30. * Contributor(s): David Gilbert (for Object Refinery Limited);
  31. *
  32. * $Id: ColorPalette.java,v 1.2 2005/01/14 17:33:24 mungady Exp $
  33. *
  34. * Changes
  35. * -------
  36. * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG);
  37. * 26-Mar-2003 : Implemented Serializable (DG);
  38. * 14-Aug-2003 : Implemented Cloneable (DG);
  39. *
  40. */
  41. package org.jfree.chart.ui;
  42. import java.awt.Color;
  43. import java.awt.Paint;
  44. import java.io.Serializable;
  45. import java.util.Arrays;
  46. import org.jfree.chart.axis.ValueTick;
  47. /**
  48. * Defines palette used in Contour Plots.
  49. *
  50. * @author David M. O'Donnell.
  51. */
  52. public abstract class ColorPalette implements Cloneable, Serializable {
  53. /** The min z-axis value. */
  54. protected double minZ = -1;
  55. /** The max z-axis value. */
  56. protected double maxZ = -1;
  57. /** Red components. */
  58. protected int[] r;
  59. /** Green components. */
  60. protected int[] g;
  61. /** Blue components. */
  62. protected int[] b;
  63. /** Tick values are stored for use with stepped palette. */
  64. protected double[] tickValues = null;
  65. /** Logscale? */
  66. protected boolean logscale = false;
  67. /** Inverse palette (ie, min and max colors are reversed). */
  68. protected boolean inverse = false;
  69. /** The palette name. */
  70. protected String paletteName = null;
  71. /** Controls whether palette colors are stepped (not continuous). */
  72. protected boolean stepped = false;
  73. /** Constant for converting loge to log10. */
  74. protected static final double log10 = Math.log(10);
  75. /**
  76. * Default contructor.
  77. */
  78. public ColorPalette() {
  79. super();
  80. }
  81. /**
  82. * Returns the color associated with a value.
  83. *
  84. * @param value the value.
  85. *
  86. * @return the color.
  87. */
  88. public Paint getColor(double value) {
  89. int izV = (int) (253 * (value - this.minZ) / (this.maxZ - this.minZ)) + 2;
  90. return new Color(this.r[izV], this.g[izV], this.b[izV]);
  91. }
  92. /**
  93. * Returns a color.
  94. *
  95. * @param izV ??.
  96. *
  97. * @return the color.
  98. */
  99. public Color getColor(int izV) {
  100. return new Color(this.r[izV], this.g[izV], this.b[izV]);
  101. }
  102. /**
  103. * Returns Color by mapping a given value to a linear palette.
  104. *
  105. * @param value the value.
  106. *
  107. * @return The color.
  108. */
  109. public Color getColorLinear(double value) {
  110. int izV = 0;
  111. if (this.stepped) {
  112. int index = Arrays.binarySearch(this.tickValues, value);
  113. if (index < 0) {
  114. index = -1 * index - 2;
  115. }
  116. if (index < 0) { // For the case were the first tick is greater than minZ
  117. value = this.minZ;
  118. }
  119. else {
  120. value = this.tickValues[index];
  121. }
  122. }
  123. izV = (int) (253 * (value - this.minZ) / (this.maxZ - this.minZ)) + 2;
  124. izV = Math.min(izV, 255);
  125. izV = Math.max(izV, 2);
  126. return getColor(izV);
  127. }
  128. /**
  129. * Returns Color by mapping a given value to a common log palette.
  130. *
  131. * @param value the value.
  132. *
  133. * @return The color.
  134. */
  135. public Color getColorLog(double value) {
  136. int izV = 0;
  137. double minZtmp = this.minZ;
  138. double maxZtmp = this.maxZ;
  139. if (this.minZ <= 0.0) {
  140. // negatives = true;
  141. this.maxZ = maxZtmp - minZtmp + 1;
  142. this.minZ = 1;
  143. value = value - minZtmp + 1;
  144. }
  145. double minZlog = Math.log(this.minZ) / log10;
  146. double maxZlog = Math.log(this.maxZ) / log10;
  147. value = Math.log(value) / log10;
  148. // value = Math.pow(10,value);
  149. if (this.stepped) {
  150. int numSteps = this.tickValues.length;
  151. int steps = 256 / (numSteps - 1);
  152. izV = steps * (int) (numSteps * (value - minZlog) / (maxZlog - minZlog)) + 2;
  153. // izV = steps*numSteps*(int)((value/minZ)/(maxZlog-minZlog)) + 2;
  154. }
  155. else {
  156. izV = (int) (253 * (value - minZlog) / (maxZlog - minZlog)) + 2;
  157. }
  158. izV = Math.min(izV, 255);
  159. izV = Math.max(izV, 2);
  160. this.minZ = minZtmp;
  161. this.maxZ = maxZtmp;
  162. return getColor(izV);
  163. }
  164. /**
  165. * Returns the maximum Z value.
  166. *
  167. * @return the value.
  168. */
  169. public double getMaxZ() {
  170. return this.maxZ;
  171. }
  172. /**
  173. * Returns the minimum Z value.
  174. *
  175. * @return the value.
  176. */
  177. public double getMinZ() {
  178. return this.minZ;
  179. }
  180. /**
  181. * Returns Paint by mapping a given value to a either a linear or common log palette
  182. * as controlled by the value logscale.
  183. *
  184. * @param value the value.
  185. *
  186. * @return The paint.
  187. */
  188. public Paint getPaint(double value) {
  189. if (isLogscale()) {
  190. return getColorLog(value);
  191. }
  192. else {
  193. return getColorLinear(value);
  194. }
  195. }
  196. /**
  197. * Returns the palette name.
  198. *
  199. * @return the palette name.
  200. */
  201. public String getPaletteName () {
  202. return this.paletteName;
  203. }
  204. /**
  205. * Returns the tick values.
  206. *
  207. * @return the tick values.
  208. */
  209. public double[] getTickValues() {
  210. return this.tickValues;
  211. }
  212. /**
  213. * Called to initialize the palette's color indexes
  214. */
  215. public abstract void initialize();
  216. /**
  217. * Inverts Palette
  218. */
  219. public void invertPalette() {
  220. int[] red = new int[256];
  221. int[] green = new int[256];
  222. int[] blue = new int[256];
  223. for (int i = 0; i < 256; i++) {
  224. red[i] = this.r[i];
  225. green[i] = this.g[i];
  226. blue[i] = this.b[i];
  227. }
  228. for (int i = 2; i < 256; i++) {
  229. this.r[i] = red[257 - i];
  230. this.g[i] = green[257 - i];
  231. this.b[i] = blue[257 - i];
  232. }
  233. }
  234. /**
  235. * Returns the inverse flag.
  236. *
  237. * @return the flag.
  238. */
  239. public boolean isInverse () {
  240. return this.inverse;
  241. }
  242. /**
  243. * Returns the log-scale flag.
  244. *
  245. * @return the flag.
  246. */
  247. public boolean isLogscale() {
  248. return this.logscale;
  249. }
  250. /**
  251. * Returns the 'is-stepped' flag.
  252. *
  253. * @return the flag.
  254. */
  255. public boolean isStepped () {
  256. return this.stepped;
  257. }
  258. /**
  259. * Sets the inverse flag.
  260. *
  261. * @param inverse the new value.
  262. */
  263. public void setInverse (boolean inverse) {
  264. this.inverse = inverse;
  265. initialize();
  266. if (inverse) {
  267. invertPalette();
  268. }
  269. return;
  270. }
  271. /**
  272. * Sets the 'log-scale' flag.
  273. *
  274. * @param logscale the new value.
  275. */
  276. public void setLogscale(boolean logscale) {
  277. this.logscale = logscale;
  278. }
  279. /**
  280. * Sets the maximum Z value.
  281. *
  282. * @param newMaxZ the new value.
  283. */
  284. public void setMaxZ(double newMaxZ) {
  285. this.maxZ = newMaxZ;
  286. }
  287. /**
  288. * Sets the minimum Z value.
  289. *
  290. * @param newMinZ the new value.
  291. */
  292. public void setMinZ(double newMinZ) {
  293. this.minZ = newMinZ;
  294. }
  295. /**
  296. * Sets the palette name.
  297. *
  298. * @param paletteName the name.
  299. */
  300. public void setPaletteName (String paletteName) {
  301. //String oldValue = this.paletteName;
  302. this.paletteName = paletteName;
  303. return;
  304. }
  305. /**
  306. * Sets the stepped flag.
  307. *
  308. * @param stepped the flag.
  309. */
  310. public void setStepped (boolean stepped) {
  311. this.stepped = stepped;
  312. return;
  313. }
  314. /**
  315. * Sets the tick values.
  316. *
  317. * @param newTickValues the tick values.
  318. */
  319. public void setTickValues(double[] newTickValues) {
  320. this.tickValues = newTickValues;
  321. }
  322. /**
  323. * Store ticks. Required when doing stepped axis
  324. *
  325. * @param ticks the ticks.
  326. */
  327. public void setTickValues(java.util.List ticks) {
  328. this.tickValues = new double[ticks.size()];
  329. for (int i = 0; i < this.tickValues.length; i++) {
  330. this.tickValues[i] = ((ValueTick) ticks.get(i)).getValue();
  331. }
  332. }
  333. /**
  334. * Tests an object for equality with this instance.
  335. *
  336. * @param o the object to test.
  337. *
  338. * @return A boolean.
  339. */
  340. public boolean equals(Object o) {
  341. if (this == o) {
  342. return true;
  343. }
  344. if (!(o instanceof ColorPalette)) {
  345. return false;
  346. }
  347. ColorPalette colorPalette = (ColorPalette) o;
  348. if (this.inverse != colorPalette.inverse) {
  349. return false;
  350. }
  351. if (this.logscale != colorPalette.logscale) {
  352. return false;
  353. }
  354. if (this.maxZ != colorPalette.maxZ) {
  355. return false;
  356. }
  357. if (this.minZ != colorPalette.minZ) {
  358. return false;
  359. }
  360. if (this.stepped != colorPalette.stepped) {
  361. return false;
  362. }
  363. if (!Arrays.equals(this.b, colorPalette.b)) {
  364. return false;
  365. }
  366. if (!Arrays.equals(this.g, colorPalette.g)) {
  367. return false;
  368. }
  369. if (this.paletteName != null
  370. ? !this.paletteName.equals(colorPalette.paletteName)
  371. : colorPalette.paletteName != null) {
  372. return false;
  373. }
  374. if (!Arrays.equals(this.r, colorPalette.r)) {
  375. return false;
  376. }
  377. if (!Arrays.equals(this.tickValues, colorPalette.tickValues)) {
  378. return false;
  379. }
  380. return true;
  381. }
  382. /**
  383. * Returns a hash code.
  384. *
  385. * @return a hash code.
  386. */
  387. public int hashCode() {
  388. int result;
  389. long temp;
  390. temp = Double.doubleToLongBits(this.minZ);
  391. result = (int) (temp ^ (temp >>> 32));
  392. temp = Double.doubleToLongBits(this.maxZ);
  393. result = 29 * result + (int) (temp ^ (temp >>> 32));
  394. result = 29 * result + (this.logscale ? 1 : 0);
  395. result = 29 * result + (this.inverse ? 1 : 0);
  396. result = 29 * result + (this.paletteName != null ? this.paletteName.hashCode() : 0);
  397. result = 29 * result + (this.stepped ? 1 : 0);
  398. return result;
  399. }
  400. /**
  401. * Returns a clone of the palette.
  402. *
  403. * @return A clone.
  404. *
  405. * @throws CloneNotSupportedException never.
  406. */
  407. public Object clone() throws CloneNotSupportedException {
  408. ColorPalette clone = (ColorPalette) super.clone();
  409. return clone;
  410. }
  411. }