/* * InterpolatingColourDecorator.java * * Copyright (C) 2006-2014 Andrew Rambaut * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package figtree.treeviewer.decorators; import jebl.util.Attributable; import java.awt.*; import java.util.Set; /** * This decorator takes an attribute name and a set of attibutable Objects. It * autodetects the type of attributes and then provides a colouring scheme for them * based on a gradient between color1 & color2. * * @author Andrew Rambaut * @version $Id$ * * $HeadURL$ * * $LastChangedBy$ * $LastChangedDate$ * $LastChangedRevision$ */ public class InterpolatingColourDecorator extends ContinuousColourDecorator { public static final Color DEFAULT_COLOR_1 = Color.getHSBColor(0.01F, 0.7F, 0.85F); public static final Color DEFAULT_COLOR_2 = Color.getHSBColor(0.63F, 0.7F, 0.85F); public static final Color DEFAULT_COLOR_3 = Color.BLACK; public InterpolatingColourDecorator(String attribute, String settings) { super(attribute); setup(settings); } public InterpolatingColourDecorator(ContinuousScale continuousScale) throws NumberFormatException { super(continuousScale); setColours(DEFAULT_COLOR_1, DEFAULT_COLOR_2); } public InterpolatingColourDecorator(ContinuousScale continuousScale, Color color1, Color color2) throws NumberFormatException { super(continuousScale); setColours(color1, color2); } public InterpolatingColourDecorator(ContinuousScale continuousScale, Color color1, Color color2, Color color3) throws NumberFormatException { super(continuousScale); setColours(color1, color2, color3); } public void setColours(Color color1, Color color2) { this.color1 = new float[4]; color1.getRGBComponents(this.color1); this.color2 = new float[4]; color2.getRGBComponents(this.color2); this.color3 = null; } public void setColours(Color color1, Color color2, Color color3) { this.color1 = new float[4]; color1.getRGBComponents(this.color1); this.color2 = new float[4]; color2.getRGBComponents(this.color2); this.color3 = new float[4]; color3.getRGBComponents(this.color3); } public Color getColor1() { if (color1 == null) { return null; } return new Color(color1[0], color1[1], color1[2], color1[3]); } public Color getColor2() { if (color2 == null) { return null; } return new Color(color2[0], color2[1], color2[2], color2[3]); } public Color getColor3() { if (color3 == null) { return null; } return new Color(color3[0], color3[1], color3[2], color3[3]); } // Private methods public Color getColourForScaledValue(double value) { if (!Double.isNaN(value)) { if (color3 != null) { if (value < 0.5) { float p = (float)value * 2; float q = 1.0F - p; return new Color( color2[0] * p + color1[0] * q, color2[1] * p + color1[1] * q, color2[2] * p + color1[2] * q, color2[3] * p + color1[3] * q); } else { float p = (float)(value - 0.5) * 2; float q = 1.0F - p; return new Color( color3[0] * p + color2[0] * q, color3[1] * p + color2[1] * q, color3[2] * p + color2[2] * q, color3[3] * p + color2[3] * q); } } else { float p = (float)value; float q = 1.0F - p; return new Color( color2[0] * p + color1[0] * q, color2[1] * p + color1[1] * q, color2[2] * p + color1[2] * q, color2[3] * p + color1[3] * q); } } else { return null; } } private float[] color1; private float[] color2; private float[] color3; @Override public void setup(String settings) { if (!settings.startsWith("{") || !settings.endsWith("}")) { throw new IllegalArgumentException("InterpolatingColourDecorator settings string not in correct format"); } String[] parts1 = settings.substring(1, settings.length() - 1).split("}[, ]+"); if (parts1.length != 2) { throw new IllegalArgumentException("InterpolatingColourDecorator settings string not in correct format"); } String[] parts2 = parts1[1].split("[, ]+"); if (parts2.length != 2 && parts2.length != 3) { throw new IllegalArgumentException("InterpolatingColourDecorator settings string not in correct format"); } try { setContinuousScale(new ContinuousScale(parts1[0])); if (parts2.length == 3) { setColours(parseColor(parts2[0]), parseColor(parts2[1]), parseColor(parts2[2])); } else { setColours(parseColor(parts2[0]), parseColor(parts2[1])); } } catch (NumberFormatException nfe) { throw new IllegalArgumentException("InterpolatingColourDecorator settings string not in correct format"); } catch (IllegalArgumentException iae) { throw new IllegalArgumentException("InterpolatingColourDecorator settings string not in correct format"); } } private Color parseColor(String value) { if (value.startsWith("#")) { try { return Color.decode(value.substring(1)); } catch (NumberFormatException nfe) { } } return null; } /** * Create a string representation suitable for writing to a text file * @return the string */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{"); sb.append(getContinuousScale().toString()); sb.append(",#"); sb.append(new Color(color1[0], color1[1], color1[2], color1[3]).getRGB()); sb.append(",#"); sb.append(new Color(color2[0], color2[1], color2[2], color2[3]).getRGB()); if (color3 != null) { sb.append(",#"); sb.append(new Color(color3[0], color3[1], color3[2], color3[3]).getRGB()); } sb.append("}"); return sb.toString(); } }