source: josm/trunk/src/org/openstreetmap/josm/tools/ColorScale.java@ 15547

Last change on this file since 15547 was 15292, checked in by Don-vip, 5 years ago

checkstyle/pmd/sonar

  • Property svn:eol-style set to native
File size: 7.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.awt.Color;
5import java.awt.FontMetrics;
6import java.awt.Graphics2D;
7
8/**
9 * Utility class that helps to work with color scale for coloring GPX tracks etc.
10 * @since 7319
11 */
12public final class ColorScale {
13 private double min, max;
14 private Color noDataColor;
15 private Color belowMinColor;
16 private Color aboveMaxColor;
17
18 private Color[] colors;
19 private String title = "";
20 private int intervalCount = 5;
21
22 private ColorScale() {
23
24 }
25
26 /**
27 * Gets a fixed color range.
28 * @param colors the fixed colors list
29 * @return The scale
30 * @since 15247
31 */
32 public static ColorScale createFixedScale(Color[] colors) {
33 ColorScale sc = new ColorScale();
34 sc.colors = Utils.copyArray(colors);
35 sc.setRange(0, colors.length - 1d);
36 sc.addBounds();
37 return sc;
38 }
39
40 /**
41 * Gets a HSB color range.
42 * @param count The number of colors the scale should have
43 * @return The scale
44 */
45 public static ColorScale createHSBScale(int count) {
46 ColorScale sc = new ColorScale();
47 sc.colors = new Color[count];
48 for (int i = 0; i < count; i++) {
49 sc.colors[i] = Color.getHSBColor(i / 300.0f, 1, 1);
50 }
51 sc.setRange(0, 255);
52 sc.addBounds();
53 return sc;
54 }
55
56 /**
57 * Creates a cyclic color scale (red yellow green blue red)
58 * @param count The number of colors the scale should have
59 * @return The scale
60 */
61 public static ColorScale createCyclicScale(int count) {
62 ColorScale sc = new ColorScale();
63 // CHECKSTYLE.OFF: SingleSpaceSeparator
64 // red yellow green blue red
65 int[] h = new int[] {0, 59, 127, 244, 360};
66 int[] s = new int[] {100, 84, 99, 100};
67 int[] b = new int[] {90, 93, 74, 83};
68 // CHECKSTYLE.ON: SingleSpaceSeparator
69
70 sc.colors = new Color[count];
71 for (int i = 0; i < sc.colors.length; i++) {
72
73 float angle = i / 256f * 4;
74 int quadrant = (int) angle;
75 angle -= quadrant;
76 quadrant = Utils.mod(quadrant+1, 4);
77
78 float vh = h[quadrant] * weighted(angle) + h[quadrant+1] * (1 - weighted(angle));
79 float vs = s[quadrant] * weighted(angle) + s[Utils.mod(quadrant+1, 4)] * (1 - weighted(angle));
80 float vb = b[quadrant] * weighted(angle) + b[Utils.mod(quadrant+1, 4)] * (1 - weighted(angle));
81
82 sc.colors[i] = Color.getHSBColor(vh/360f, vs/100f, vb/100f);
83 }
84 sc.setRange(0, 2*Math.PI);
85 sc.addBounds();
86 return sc;
87 }
88
89 /**
90 * transition function:
91 * w(0)=1, w(1)=0, 0&lt;=w(x)&lt;=1
92 * @param x number: 0&lt;=x&lt;=1
93 * @return the weighted value
94 */
95 private static float weighted(float x) {
96 if (x < 0.5)
97 return 1 - 2*x*x;
98 else
99 return 2*(1-x)*(1-x);
100 }
101
102 /**
103 * Sets the hint on the range this scale is for
104 * @param min The minimum value
105 * @param max The maximum value
106 */
107 public void setRange(double min, double max) {
108 this.min = min;
109 this.max = max;
110 }
111
112 /**
113 * Add standard colors for values below min or above max value
114 */
115 public void addBounds() {
116 aboveMaxColor = colors[colors.length-1];
117 belowMinColor = colors[0];
118 }
119
120 /**
121 * Gets a color for the given value.
122 * @param value The value
123 * @return The color for this value, this may be a special color if the value is outside the range but never null.
124 */
125 public Color getColor(double value) {
126 if (value < min) return belowMinColor;
127 if (value > max) return aboveMaxColor;
128 if (Double.isNaN(value)) return noDataColor;
129 final int n = colors.length;
130 int idx = (int) ((value-min)*colors.length / (max-min));
131 if (idx < colors.length) {
132 return colors[idx];
133 } else {
134 return colors[n-1]; // this happens when value==max
135 }
136 }
137
138 /**
139 * Gets a color for the given value.
140 * @param value The value, may be <code>null</code>
141 * @return The color for this value, this may be a special color if the value is outside the range or the value is null but never null.
142 */
143 public Color getColor(Number value) {
144 return (value == null) ? noDataColor : getColor(value.doubleValue());
145 }
146
147 /**
148 * Get the color to use if there is no data
149 * @return The color
150 */
151 public Color getNoDataColor() {
152 return noDataColor;
153 }
154
155 /**
156 * Sets the color to use if there is no data
157 * @param noDataColor The color
158 */
159 public void setNoDataColor(Color noDataColor) {
160 this.noDataColor = noDataColor;
161 }
162
163 /**
164 * Make all colors transparent
165 * @param alpha The alpha value all colors in the range should have, range 0..255
166 * @return This scale, for chaining
167 */
168 public ColorScale makeTransparent(int alpha) {
169 for (int i = 0; i < colors.length; i++) {
170 colors[i] = new Color((colors[i].getRGB() & 0xFFFFFF) | ((alpha & 0xFF) << 24), true);
171 }
172 return this;
173 }
174
175 /**
176 * Adds a title to this scale
177 * @param title The new title
178 * @return This scale, for chaining
179 */
180 public ColorScale addTitle(String title) {
181 this.title = title;
182 return this;
183 }
184
185 /**
186 * Sets the interval count for this scale
187 * @param intervalCount The interval count hint
188 * @return This scale, for chaining
189 */
190 public ColorScale setIntervalCount(int intervalCount) {
191 this.intervalCount = intervalCount;
192 return this;
193 }
194
195 /**
196 * Reverses this scale
197 * @return This scale, for chaining
198 */
199 public ColorScale makeReversed() {
200 int n = colors.length;
201 Color tmp;
202 for (int i = 0; i < n/2; i++) {
203 tmp = colors[i];
204 colors[i] = colors[n-1-i];
205 colors[n-1-i] = tmp;
206 }
207 tmp = belowMinColor;
208 belowMinColor = aboveMaxColor;
209 aboveMaxColor = tmp;
210 return this;
211 }
212
213 /**
214 * Draws a color bar representing this scale on the given graphics
215 * @param g The graphics to draw on
216 * @param x Rect x
217 * @param y Rect y
218 * @param w Rect width
219 * @param h Rect height
220 * @param valueScale The scale factor of the values
221 */
222 public void drawColorBar(Graphics2D g, int x, int y, int w, int h, double valueScale) {
223 int n = colors.length;
224
225 for (int i = 0; i < n; i++) {
226 g.setColor(colors[i]);
227 if (w < h) {
228 g.fillRect(x, y+i*h/n, w, h/n+1);
229 } else {
230 g.fillRect(x+i*w/n, y, w/n+1, h);
231 }
232 }
233
234 int fw, fh;
235 FontMetrics fm = g.getFontMetrics();
236 fh = fm.getHeight()/2;
237 fw = fm.stringWidth(String.valueOf(Math.max((int) Math.abs(max*valueScale),
238 (int) Math.abs(min*valueScale)))) + fm.stringWidth("0.123");
239 g.setColor(noDataColor);
240 if (title != null) {
241 g.drawString(title, x-fw-3, y-fh*3/2);
242 }
243 for (int i = 0; i <= intervalCount; i++) {
244 g.setColor(colors[(int) (1.0*i*n/intervalCount-1e-10)]);
245 final double val = min+i*(max-min)/intervalCount;
246 final String txt = String.format("%.3f", val*valueScale);
247 if (w < h) {
248 g.drawString(txt, x-fw-3, y+i*h/intervalCount+fh/2);
249 } else {
250 g.drawString(txt, x+i*w/intervalCount-fw/2, y+fh-3);
251 }
252 }
253 }
254}
Note: See TracBrowser for help on using the repository browser.