001 package ui.recognizer;
002
003 import java.awt.Color;
004 //import java.awt.color.ColorSpace;
005
006 /** Represents the color of visible light for a given wavelenth between
007 * between 380 nm and 780 nm. Originally from a program by Dan Bruton at
008 * http://www.physics.sfasu.edu/astro/color/spectra.html
009 *
010 * @author John Talbot
011 */
012 public class MonochromaticColor extends Color {
013
014 public static final double MINIMUM_WAVELENGTH = 380.0 * Units.NANOMETERS;
015 public static final double WAVELENGTH_BLUE = 440.0 * Units.NANOMETERS;
016 public static final double WAVELENGTH_CYAN = 490.0 * Units.NANOMETERS;
017 public static final double WAVELENGTH_GREEN = 510.0 * Units.NANOMETERS;
018 public static final double WAVELENGTH_YELLOW = 580.0 * Units.NANOMETERS;
019 public static final double WAVELENGTH_RED = 645.0 * Units.NANOMETERS;
020 public static final double MAXIMUM_WAVELENGTH = 780.0 * Units.NANOMETERS;
021
022 public static final double BLUE_SENSITIVITY_DROP = 420.0 * Units.NANOMETERS;
023 public static final double RED_SENSITIVITY_DROP = 700.0 * Units.NANOMETERS;
024
025 public static final double TYPICAL_GAMMA = 0.80d;
026 public static final double MAXIMUM_INTENSITY = 1.0d;
027
028 private double wavelength;
029 private double gamma = TYPICAL_GAMMA;
030
031 /** Construct a monochromatic color based on a wavelength between 380 nm and 780 nm
032 * @param aWavelength the wavelength of the visible radiation in meters
033 */
034 public MonochromaticColor(double aWavelength) {
035 this(aWavelength, MAXIMUM_INTENSITY);
036 }
037
038 /** Construct a monochromatic color based on a wavelength between 380 nm and 780 nm and enhance the contrast using a gamma value.
039 * @param aWavelength the wavelength of the visible radiation in meters
040 * @param intensity a number between 0 and 1.0 (MAXIMUM_INTENSITY) which is to multiply the color
041 */
042 public MonochromaticColor(double aWavelength, double intensity) {
043 this(aWavelength, intensity, TYPICAL_GAMMA);
044 }
045
046 /** Construct a monochromatic color based on a wavelength between 380 nm and 780 nm and enhance the contrast using a gamma value.
047 * @param aWavelength the wavelength of the visible radiation in meters
048 * @param intensity a number between 0 and 1.0 (MAXIMUM_INTENSITY) which is to multiply the color
049 * @param aGamma a number which can be used to enhance the contrast of darker colors
050 */
051 public MonochromaticColor(double aWavelength, double intensity, double aGamma) {
052 // the colorspace method of constructing colors is very noisy and non-linear, it was abandonned
053 //super(ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), getColorComponents(aWavelength, intensity, aGamma), 1.0f);
054 //super(ColorSpace.getInstance(ColorSpace.CS_sRGB), getColorComponents(aWavelength, intensity, aGamma), 1.0f);
055
056 // TODO: improve efficiency by reducing this line to one call to getColorComponents()
057 super(getColorComponents(aWavelength, intensity, aGamma)[0],
058 getColorComponents(aWavelength, intensity, aGamma)[1],
059 getColorComponents(aWavelength, intensity, aGamma)[2]);
060 setWavelength(aWavelength);
061 setGamma(aGamma);
062 }
063
064 /** Get a monochromatic color based on a wavelength between 380 nm and 780 nm
065 * and scale the brightness by an intensity parameter between zero and one.
066 * The contrast is enhanced using a gamma value between 0.0 and 1.0.
067 * @param aWavelength the wavelength of the visible radiation in meters
068 * @param intensity a number between 0 and 1.0 which is to multiply the color
069 * @param aGamma a number which can be used to enhance the contrast of darker colors
070 * @return a color which represents one wavelength of visible light
071 */
072 public static float[] getColorComponents(double aWavelength, double intensity, double aGamma) {
073 double red;
074 double green;
075 double blue;
076 if (aWavelength >= MINIMUM_WAVELENGTH && aWavelength <= WAVELENGTH_BLUE) {
077 red = (WAVELENGTH_BLUE - aWavelength) / (WAVELENGTH_BLUE - MINIMUM_WAVELENGTH);
078 green = 0.0d;
079 blue = 1.0d;
080 } else if (aWavelength >= WAVELENGTH_BLUE && aWavelength <= WAVELENGTH_CYAN) {
081 red = 0.0d;
082 green = (aWavelength - WAVELENGTH_BLUE) / (WAVELENGTH_CYAN - WAVELENGTH_BLUE);
083 blue = 1.0d;
084 } else if (aWavelength >= WAVELENGTH_CYAN && aWavelength <= WAVELENGTH_GREEN) {
085 red = 0.0d;
086 green = 1.0d;
087 blue = (WAVELENGTH_GREEN - aWavelength) / (WAVELENGTH_GREEN - WAVELENGTH_CYAN);
088 } else if (aWavelength >= WAVELENGTH_GREEN && aWavelength <= WAVELENGTH_YELLOW) {
089 red = (aWavelength - WAVELENGTH_GREEN) / (WAVELENGTH_YELLOW - WAVELENGTH_GREEN);
090 green = 1.0d;
091 blue = 0.0d;
092 } else if (aWavelength >= WAVELENGTH_YELLOW && aWavelength <= WAVELENGTH_RED) {
093 red = 1.0d;
094 green = (WAVELENGTH_RED - aWavelength) / (WAVELENGTH_RED - WAVELENGTH_YELLOW);
095 blue = 0.0d;
096 } else if (aWavelength >= WAVELENGTH_RED && aWavelength <= MAXIMUM_WAVELENGTH) {
097 red = 1.0d;
098 green = 0.0d;
099 blue = 0.0d;
100 } else {
101 red = 0.0d;
102 green = 0.0d;
103 blue = 0.0d;
104 }
105 double spectralSensitivity;
106
107 if (aWavelength > RED_SENSITIVITY_DROP) {
108 spectralSensitivity = 0.3d + 0.7d * (MAXIMUM_WAVELENGTH - aWavelength) / (MAXIMUM_WAVELENGTH - RED_SENSITIVITY_DROP);
109 } else if (aWavelength < BLUE_SENSITIVITY_DROP) {
110 spectralSensitivity = 0.3d + 0.7d * (aWavelength - MINIMUM_WAVELENGTH) / (BLUE_SENSITIVITY_DROP - MINIMUM_WAVELENGTH);
111 } else {
112 spectralSensitivity = 1.0d;
113 }
114
115 // adjust gamma
116 red = Math.pow(spectralSensitivity * red, aGamma);
117 green = Math.pow(spectralSensitivity * green, aGamma);
118 blue = Math.pow(spectralSensitivity * blue, aGamma);
119
120 float[] colors = new float[] { (float) (intensity * red), (float) (intensity * green), (float) (intensity * blue) };
121 return colors;
122 }
123
124
125 // return new Color((float) (intensity * red), (float) (intensity * green), (float) (intensity * blue));
126
127
128 public static void main(String[] args) {
129 double wavelength, min = 380e-9, max = 780e-9, fraction;
130 int maxpoints = 512;
131 for (int i = 0; i < maxpoints; i++) {
132 fraction = ((double) i) / ((double) maxpoints);
133 wavelength = min + fraction * (max - min);
134 Color aColor = new MonochromaticColor(wavelength);
135 System.out.println(wavelength + " " + aColor.getRed() + " " + aColor.getGreen() + " " + aColor.getBlue() );
136 }
137 }
138
139 //--------------------------accessor methods--------------------------------------------
140
141 /** Get the wavelength in meters which this color represents.
142 * @return a floating point number representing the wavelength in meters
143 */
144 public double getWavelength() {
145 return wavelength;
146 }
147
148 /** Set the wavelength in meters, and change this color to the closest color match.
149 * @param aWavelength a floating point number representing the wavelength in meters
150 */
151 public void setWavelength(double aWavelength) {
152 wavelength = aWavelength;
153 // TODO: change this color to suit the wavelength
154 }
155
156 /** Set the wavelength in nanometers and change this color to the closest color match.
157 * @param aWavelengthInNanoMeters a floating point number representing the wavelength in meters
158 */
159 public void setWavelengthInNanoMeters(double aWavelengthInNanoMeters) {
160 setWavelength(aWavelengthInNanoMeters * Units.NANOMETERS);
161 }
162
163 /** Set the wavelength in angstrom units and change this color to the closest color match.
164 * @param aWavelengthInAngtroms a floating point number representing the wavelength in meters
165 */
166 public void setWavelengthInAngtroms(double aWavelengthInAngtroms) {
167 setWavelength(aWavelengthInAngtroms * Units.ANGSTROMS);
168 }
169
170 /** Set the gamma, a number which can be used to enhance the contrast of darker colors.
171 * @param aGamma a number representing the gamma of the color
172 */
173 public void setGamma(double aGamma) {
174 gamma = aGamma;
175 }
176
177 /** Get the gamma, a number which can be used to enhance the contrast of darker colors.
178 * @return a number representing the gamma of the color
179 */
180 public double getGamma() {
181 return gamma;
182 }
183 }