/*
* 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();
}
}