View Javadoc
1   /*
2    * The baseCode project
3    * 
4    * Copyright (c) 2006 University of British Columbia
5    * 
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *       http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   *
18   */
19  package ubic.basecode.graphics;
20  
21  import java.awt.Color;
22  
23  /**
24   * @author Will Braynen
25   * 
26   */
27  public class ColorMap {
28      public static final Color DARK_RED = new Color( 128, 0, 0 );
29  
30      public static final Color[] BLACKBODY_COLORMAP = { Color.black, DARK_RED, Color.orange, Color.yellow, Color.white };
31      public static final Color[] GREENRED_COLORMAP = { Color.green, Color.black, Color.red };
32  
33      public static final int m_defaultSuggestedNumberOfColors = 32;
34      public static final Color[] REDGREEN_COLORMAP = { Color.red, Color.black, Color.green };
35      // color map
36      protected Color[] m_colorPalette;
37      protected Color[] m_currentColorMap = GREENRED_COLORMAP; // reference to a
38      protected Color[] m_customColorMap;
39  
40      /** last color in the current color map */
41      protected Color m_maxColor;
42      /** first color in the current color map */
43      protected Color m_minColor;
44  
45      public ColorMap() {
46  
47          this( m_defaultSuggestedNumberOfColors );
48      }
49  
50      public ColorMap( Color[] colorMap ) {
51  
52          this( m_defaultSuggestedNumberOfColors, colorMap );
53      }
54  
55      public ColorMap( int suggestedNumberOfColors ) {
56  
57          this( suggestedNumberOfColors, GREENRED_COLORMAP );
58      }
59  
60      /**
61       * Pre-condition: suggestedNumberOfColors > colorMap.length
62       * 
63       * @param suggestedNumberOfColors int
64       * @param colorMap Color[]
65       */
66      public ColorMap( int suggestedNumberOfColors, Color[] colorMap ) {
67  
68          m_currentColorMap = colorMap;
69          m_colorPalette = createColorPalette( suggestedNumberOfColors, colorMap );
70      }
71  
72      public Color getColor( int i ) {
73  
74          return m_colorPalette[i];
75      }
76  
77      public Color[] getPalette() {
78  
79          return m_colorPalette;
80      }
81  
82      /**
83       * @return the number of colors in the palette
84       */
85      public int getPaletteSize() {
86  
87          return m_colorPalette.length;
88      }
89  
90      /**
91       * Allocates colors across a range.
92       * 
93       * @param suggestedNumberOfColors palette resolution; if colorPalette.length does not evenly divide into this
94       *        number, the actual number of colors in the palette will be rounded down.
95       * @param colorMap the simplest color map is { minColor, maxColor }; you might, however, want to go through
96       *        intermediate colors instead of following a straight-line route through the color space.
97       * @return Color[] the color palette
98       */
99      protected Color[] createColorPalette( int suggestedNumberOfColors, Color[] colorMap ) {
100 
101         Color[] colorPalette;
102         Color minColor;
103         Color maxColor;
104 
105         // number of segments is one less than the number of points
106         // dividing the line into segments; the color map contains points,
107         // not segments, so for example, if the color map is trivially
108         // { minColor, maxColor }, then there is only one segment
109         int totalSegments = m_currentColorMap.length - 1;
110 
111         // allocate colors across a range; distribute evenly
112         // between intermediate points, if there are any
113         int colorsPerSegment = suggestedNumberOfColors / totalSegments;
114 
115         // make sure all segments are equal by rounding down
116         // the total number of colors if necessary
117         int totalColors = totalSegments * colorsPerSegment;
118 
119         // create color map to return
120         colorPalette = new Color[totalColors];
121 
122         for ( int segment = 0; segment < totalSegments; segment++ ) {
123             // the minimum color for each segment as defined by the current color
124             // map
125             minColor = colorMap[segment];
126             int r = minColor.getRed();
127             int g = minColor.getGreen();
128             int b = minColor.getBlue();
129 
130             // the maximum color for each segment and the step sizes
131             maxColor = colorMap[segment + 1];
132             int redStepSize = getStepSize( r, maxColor.getRed(), colorsPerSegment );
133             int greenStepSize = getStepSize( g, maxColor.getGreen(), colorsPerSegment );
134             int blueStepSize = getStepSize( b, maxColor.getBlue(), colorsPerSegment );
135 
136             for ( int k, i = 0; i < colorsPerSegment; i++ ) {
137                 // clip
138                 r = Math.min( r, 255 );
139                 g = Math.min( g, 255 );
140                 b = Math.min( b, 255 );
141 
142                 // but also make sure it's not less than zero
143                 r = Math.max( r, 0 );
144                 g = Math.max( g, 0 );
145                 b = Math.max( b, 0 );
146 
147                 k = segment * colorsPerSegment + i;
148                 colorPalette[k] = new Color( r, g, b );
149 
150                 r += redStepSize;
151                 g += greenStepSize;
152                 b += blueStepSize;
153             }
154         }
155 
156         return colorPalette;
157 
158     } // end createColorPalette
159 
160     /**
161      * Calculate how fast we have to change color components. Assume min and max colors are different!
162      * 
163      * @param minColor red, green, or blue component of the RGB color
164      * @param maxColor red, green, or blue component of the RGB color
165      * @param totalColors int
166      * @return positive or negative step size
167      */
168     protected int getStepSize( int minColor, int maxColor, int totalColors ) {
169 
170         int colorRange = maxColor - minColor;
171         double stepSize = colorRange / ( double ) ( 1 == totalColors ? 1 : totalColors - 1 );
172         return ( int ) Math.round( stepSize );
173     }
174 }