/* * Copyright 2004-2010 Information & Software Engineering Group (188/1) * Institute of Software Technology and Interactive Systems * Vienna University of Technology, Austria * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.tuwien.ifs.somtoolbox.visualization; import java.awt.Color; import java.util.Vector; import at.tuwien.ifs.somtoolbox.SOMToolboxException; /** * This class implements a gradient function to generate different colors, based on an initialisation with at least two * points and colors. {@link #getColor(double)} can be used to get a single color for a given point along the gradient * function, while {@link #toPalette(int)} can be utilised to generate a palette of n numbers. * * @author Michael Dittenbach * @version $Id: ColorGradient.java 3587 2010-05-21 10:35:33Z mayer $ */ public class ColorGradient { private Vector<Color> gradientColors = null; private Vector<Double> gradientPoints = null; private int numGradientPoints; public void setGradientPoint(int index, double c, Color color) { if (c > 0 && c < 1) { gradientPoints.set(index, new Double(c)); } if (color != null) { gradientColors.set(index, color); } } public ColorGradient() { gradientPoints = new Vector<Double>(); gradientColors = new Vector<Color>(); numGradientPoints = 0; try { setGradientPoint(0, Color.black); setGradientPoint(1, Color.white); } catch (SOMToolboxException e) { // TODO: does not happen e.printStackTrace(); } } public void insertGradientPoint(int pos, Color c) { double point = 0.5; if (pos == 0) { setGradientPoint(0, gradientPoints.get(1).doubleValue() / 2, null); point = 0d; } else if (pos >= gradientPoints.size()) { setGradientPoint(gradientPoints.size() - 1, (1d + gradientPoints.get(gradientPoints.size() - 2).doubleValue()) / 2d, null); point = 1d; } else { point = (gradientPoints.get(pos).doubleValue() + gradientPoints.get(pos - 1).doubleValue()) / 2d; } gradientColors.add(pos, c); gradientPoints.add(pos, new Double(point)); numGradientPoints++; } public void deleteGradientPoing(int pos) { if (gradientPoints.size() < 3) { return; } gradientPoints.remove(pos); gradientColors.remove(pos); numGradientPoints--; } public ColorGradient(double[] points, Color[] colors) throws SOMToolboxException { if (points.length > 1 && colors.length > 1 && points.length == colors.length) { gradientPoints = new Vector<Double>(); gradientColors = new Vector<Color>(); numGradientPoints = 0; try { for (int i = 0; i < colors.length; i++) { setGradientPoint(points[i], colors[i]); } } catch (SOMToolboxException e) { // TODO: does not happen e.printStackTrace(); } } else { throw new SOMToolboxException("At least 2 color points have to be defined."); } } public Color getColor(double c) throws SOMToolboxException { if (c >= 0 && c <= 1) { int r, g, b; int right = 0; while (right < numGradientPoints && getGradientPoint(right) <= c) { right++; } int left = right - 1; if (right == numGradientPoints) { left--; right--; } double leftPoint = getGradientPoint(left); double rightPoint = getGradientPoint(right); Color leftCol = getGradientColor(left); Color rightCol = getGradientColor(right); double frac = (c - leftPoint) / (rightPoint - leftPoint); r = leftCol.getRed() + (int) (frac * (rightCol.getRed() - leftCol.getRed())); g = leftCol.getGreen() + (int) (frac * (rightCol.getGreen() - leftCol.getGreen())); b = leftCol.getBlue() + (int) (frac * (rightCol.getBlue() - leftCol.getBlue())); return new Color(r, g, b); } else { throw new SOMToolboxException("Color gradient index out of range."); } } public Color getGradientColor(int i) { return gradientColors.elementAt(i); } public double getGradientPoint(int i) { return gradientPoints.elementAt(i).doubleValue(); } public void setGradientPoint(double c, Color color) throws SOMToolboxException { // FIXME: this seems to be a simple sorting mechanism on insertion? If yes, it can be implemented using a // dedicated collection method from the // java collections framework, which either does sorting on insertion, or sorting is manually called after // insertion. if (c >= 0 && c <= 1) { if (numGradientPoints == 0) { gradientPoints.addElement(new Double(c)); gradientColors.addElement(color); numGradientPoints++; } else if (numGradientPoints == 1) { if (c < getGradientPoint(0)) { gradientPoints.add(0, new Double(c)); gradientColors.add(0, color); numGradientPoints++; } else if (c == getGradientPoint(0)) { gradientColors.setElementAt(color, 0); } else { gradientPoints.add(new Double(c)); gradientColors.add(color); numGradientPoints++; } } else { // if at least 2 points exist int i = 1; while (getGradientPoint(i - 1) < c && i < numGradientPoints) { i++; } i--; if (c == getGradientPoint(i)) { gradientColors.setElementAt(color, i); } else if (c > getGradientPoint(i)) { gradientPoints.add(new Double(c)); gradientColors.add(color); numGradientPoints++; } else { gradientPoints.add(i, new Double(c)); gradientColors.add(i, color); numGradientPoints++; } } } else { throw new SOMToolboxException("Color gradient index out of range."); } } public Color[] toPalette(int numColors) { Color[] palette = new Color[numColors]; try { for (int i = 0; i < numColors; i++) { palette[i] = getColor(i / (numColors - 1.0)); } } catch (SOMToolboxException e) { // TODO: does not happen e.printStackTrace(); } return palette; } public int getNumberOfPoints() { return gradientColors.size(); } }