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

Last change on this file since 12718 was 12538, checked in by Don-vip, 7 years ago

PMD - ShortMethodName

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