package colorMap; import java.awt.Color; import java.awt.Graphics; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * A class which facilitates mapping values to colors. This mapping includes * gradients between an arbitrary number of colors. * * @author Curran Kelleher * */ public class ColorMap { List<ColorNode> colorNodes; float[] rgba_current = new float[4]; float[] rgba_next = new float[4]; float[] rgba_result = new float[4]; Color[] colors = new Color[512]; /** * Construct a ColorMap with the specified ColorNodes * * @param colorNodes * the color nodes which will comprise this color map initially */ public ColorMap(ColorNode[] colorNodes) { this.colorNodes = new ArrayList<ColorNode>(colorNodes.length); for (int i = 0; i < colorNodes.length; i++) this.colorNodes.add(colorNodes[i]); calculateColors(); } /** * Construct a ColorMap with the specified ColorNodes * * @param colorNodes * the color nodes which will comprise this color map initially */ public ColorMap(List<ColorNode> colorNodes) { this.colorNodes = new ArrayList<ColorNode>(colorNodes.size()); this.colorNodes.addAll(colorNodes); calculateColors(); } /** * Populates the color array based on the current color nodes * */ public void calculateColors() { Collections.sort(this.colorNodes); for (int i = 0; i < colors.length; i++) colors[i] = createColorForValue((double) i / colors.length); } /** * Creates a new Color object based on the current color nodes * * @param value * the value between 0 and 1 for which to generate the * corresponding Color. * @return a new Color object corresponding to the specified value on this * color map. */ private Color createColorForValue(double value) { if (colorNodes.size() == 1) return colorNodes.get(0).color; for (int i = 0; i < colorNodes.size() - 1; i++) { ColorNode current = colorNodes.get(i); double min = current.value; rgba_current = current.color.getComponents(rgba_current); ColorNode next = colorNodes.get(i + 1); double max = next.value; rgba_next = next.color.getComponents(rgba_next); // if the value is in the current range between color node // values... if (value >= min && value <= max) { // assign the color properly for (int c = 0; c < rgba_current.length; c++) { double percentBtwMinAndMax = (value - min) / (max - min); rgba_result[c] = (float) ((1.0 - percentBtwMinAndMax) * rgba_current[c] + percentBtwMinAndMax * rgba_next[c]); } }// if it is lower than the lowest node value else if (i == 0 && value < min) return current.color; else // if it is greater than the greatest node if (i == colorNodes.size() - 2 && value > max) return next.color; } return new Color(rgba_result[0], rgba_result[1], rgba_result[2], rgba_result[3]); } /** * Gets the Color corresponging to the specified value in this color map. * * @param value * the value between 0 and 1 for which this method will return * the corresponding Color. If this value is less than 0 or * greater than 1, 0 or 1 (respectively) will be used instead. * @return the Color corresponding to the specified value. (No new Color * object is allocated, a Color object from a pre-calculated array * is returned. see getColorArray()) */ public Color getColorAtValue(double value) { return colors[(int) ((value<0?0:value>1?1:value) * (colors.length - 1))]; } /** * Returns the array of Color objects which represent this color map. * * @return */ public Color[] getColorArray() { return colors; } /** * Draws this color map horizontally (leftmost = 0, rightmost = 1) in a * rectangle with the specified x, y, width, and height. * * @param g * the Graphics on which to draw the color map rectangle * @param x * the x pixel coordinate of the rectangle * @param y * the y pixel coordinate of the rectangle * @param width * the width of the rectangle * @param height * the height of the rectangle */ public void paintOnThis(Graphics g, int x, int y, int width, int height) { for (int col = 0; col < width; col++) { g.setColor(getColorAtValue((double) col / (width - 1))); g.drawLine(col, y, col, y + height); } } /** * Gets the color nodes that comprise this color map. * * @return */ public List<ColorNode> getColorNodes() { return colorNodes; } /** * Generates the default color map. * * @return a newly allocated ColorMap object with default settings */ public static ColorMap generateDefaultColorMap() { ColorNode[] colorNodes = { new ColorNode(Color.blue, 0), new ColorNode(Color.green, 0.5), new ColorNode(Color.red, 1) }; return new ColorMap(colorNodes); } }