/** * Copyright Copyright 2007-13 Simon Andrews * * This file is part of BamQC. * * BamQC 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 3 of the License, or * (at your option) any later version. * * BamQC 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 BamQC; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Changelog: * - Simon Andrews: Class creation. */ package uk.ac.babraham.BamQC.Utilities; import java.awt.Color; /** * Provides a range of colours which form a smooth gradient * from Blue through Green to Red. * @author Simon Andrews */ public class HotColdColourGradient { // To save generating ridiculous numbers of colours and wasting // memory we're going to make up a pool of 100 colours and pick // the closest one from that set to return. private final Color [] colors = makeColors(); @Override public String toString() { return "Hot Cold Colour Gradient"; } /** * A method initially called to create a palette of 100 pre-cached * colours from which the closest match will be selected to * return for future queries. Setting the colours this way * saves on the overhead of generating a lot of new objects * * @return An array of colours crossing the full palette. */ protected Color [] makeColors() { /* * We pre-generate a list of 100 colours we're going to * use for this display. * * Because a linear gradient ends up leaving too much * green in the spectrum we put this on a log scale * to emphasise low and high values so the display * is clearer. */ Color [] colors = new Color[100]; // We base colors on the square root of their raw value double min = 0 - Math.pow(50, 0.5); double max = Math.pow(99-50,0.5); for (int c=0;c<100;c++) { int actualC = c-50; if (actualC < 0) actualC = 0-actualC; double corrected = Math.pow(actualC, 0.5); if (c<50 && corrected > 0) corrected = 0-corrected; RGB r = getRGB(corrected, min, max); colors[c] = new Color(r.r,r.g,r.b); } return colors; } /** * Gets a colour from the gradient * * @param value The value for which you want a colour * @param min The minimum value in the gradient * @param max The maximum value in the gradient * @return A colour from the appropriate part of the gradient */ public Color getColor (double value,double min, double max) { if (colors[0] == null) makeColors(); int percentage = (int)((100 * (value-min)) / (max-min)); if (percentage > 100) percentage = 100; if (percentage < 1) percentage = 1; return colors[percentage-1]; } /** * Gets an RGB object for separate colour values * * @param value The value stored * @param min The minimum value in the gradient * @param max The maximum value in the gradient * @return An RGB object representing the colour */ private RGB getRGB (double value, double min, double max) { int red; int green; int blue; double diff = max - min; // Red // Red is 0 for the first 50%, scales from 0-200 over 50-75% // and stays at 200 from 75-100% // Green // Green scales from 0-200 over the first 25%, stays at // 200 from 25-75% and then scales from 200-0 from 75-100% // Blue // Blue starts at 200 until 25%, then scales from 200-0 // from 25-50%, then stays at 0 until 100% // Since all transitions happen in quarters of the spectrum // range it's easiest to deal with colour values in those // ranges if (value < (min+(diff*0.25))) { red = 0; blue = 200; green = (int)(200 * ((value-min) / (diff*0.25))); } else if (value < (min+(diff*0.5))) { red = 0; green = 200; blue = (int)(200 - (200 * ((value-(min+(diff*0.25))) / (diff*0.25)))); } else if (value < (min+(diff*0.75))) { green = 200; blue = 0; red = (int)(200 * ((value-(min+(diff*0.5))) / (diff*0.25))); } else { red = 200; blue = 0; green = (int)(200 - (200 * ((value-(min+(diff*0.75))) / (diff*0.25)))); } return new RGB(red,green,blue); } }