Actual source code: cmap.c
1: #include <petscsys.h>
2: #include <petscdraw.h>
4: /*
5: Set up a color map, using uniform separation in hue space.
6: Map entries are Red, Green, Blue.
7: Values are "gamma" corrected.
8: */
10: /*
11: Gamma is a monitor dependent value. The value here is an
12: approximate that gives somewhat better results than Gamma = 1.
13: */
14: static PetscReal Gamma = 2.0;
16: /*@
17: PetscDrawUtilitySetGamma - Set the monitor gamma-correction value used by the drawing colormap utilities.
19: Not Collective
21: Input Parameter:
22: . g - the gamma value; a typical value is 2.0
24: Level: developer
26: .seealso: `PetscDraw`, `PetscDrawUtilitySetCmap()`
27: @*/
28: PetscErrorCode PetscDrawUtilitySetGamma(PetscReal g)
29: {
30: PetscFunctionBegin;
31: Gamma = g;
32: PetscFunctionReturn(PETSC_SUCCESS);
33: }
35: static inline double PetscHlsHelper(double m1, double m2, double h)
36: {
37: while (h > 1.0) h -= 1.0;
38: while (h < 0.0) h += 1.0;
39: if (h < 1 / 6.0) return m1 + (m2 - m1) * h * 6;
40: if (h < 1 / 2.0) return m2;
41: if (h < 2 / 3.0) return m1 + (m2 - m1) * (2 / 3.0 - h) * 6;
42: return m1;
43: }
45: static inline void PetscHlsToRgb(double h, double l, double s, double *r, double *g, double *b)
46: {
47: if (s > 0.0) {
48: double m2 = l <= 0.5 ? l * (1.0 + s) : l + s - (l * s);
49: double m1 = 2 * l - m2;
50: *r = PetscHlsHelper(m1, m2, h + 1 / 3.);
51: *g = PetscHlsHelper(m1, m2, h);
52: *b = PetscHlsHelper(m1, m2, h - 1 / 3.);
53: } else {
54: /* ignore hue */
55: *r = *g = *b = l;
56: }
57: }
59: static inline void PetscGammaCorrect(double *r, double *g, double *b)
60: {
61: PetscReal igamma = 1 / Gamma;
62: *r = (double)PetscPowReal((PetscReal)*r, igamma);
63: *g = (double)PetscPowReal((PetscReal)*g, igamma);
64: *b = (double)PetscPowReal((PetscReal)*b, igamma);
65: }
67: static PetscErrorCode PetscDrawCmap_Hue(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
68: {
69: int i;
70: double maxhue = 212.0 / 360, lightness = 0.5, saturation = 1.0;
72: PetscFunctionBegin;
73: for (i = 0; i < mapsize; i++) {
74: double hue = maxhue * (double)i / (mapsize - 1), r, g, b;
75: PetscHlsToRgb(hue, lightness, saturation, &r, &g, &b);
76: PetscGammaCorrect(&r, &g, &b);
77: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
78: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
79: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
80: }
81: PetscFunctionReturn(PETSC_SUCCESS);
82: }
84: static PetscErrorCode PetscDrawCmap_Gray(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
85: {
86: PetscFunctionBegin;
87: for (int i = 0; i < mapsize; i++) R[i] = G[i] = B[i] = (unsigned char)((255.0 * i) / (mapsize - 1));
88: PetscFunctionReturn(PETSC_SUCCESS);
89: }
91: static PetscErrorCode PetscDrawCmap_Jet(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
92: {
93: int i;
94: const double knots[] = {0, 1 / 8., 3 / 8., 5 / 8., 7 / 8., 1};
96: PetscFunctionBegin;
97: for (i = 0; i < mapsize; i++) {
98: double u = (double)i / (mapsize - 1);
99: double m, r = 0, g = 0, b = 0;
100: int k = 0;
101: while (k < 4 && u > knots[k + 1]) k++;
102: m = (u - knots[k]) / (knots[k + 1] - knots[k]);
103: switch (k) {
104: case 0:
105: r = 0;
106: g = 0;
107: b = (m + 1) / 2;
108: break;
109: case 1:
110: r = 0;
111: g = m;
112: b = 1;
113: break;
114: case 2:
115: r = m;
116: g = 1;
117: b = 1 - m;
118: break;
119: case 3:
120: r = 1;
121: g = 1 - m;
122: b = 0;
123: break;
124: case 4:
125: r = 1 - m / 2;
126: g = 0;
127: b = 0;
128: break;
129: }
130: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
131: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
132: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
133: }
134: PetscFunctionReturn(PETSC_SUCCESS);
135: }
137: static PetscErrorCode PetscDrawCmap_Hot(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
138: {
139: int i;
140: const double knots[] = {0, 3 / 8., 3 / 4., 1};
142: PetscFunctionBegin;
143: for (i = 0; i < mapsize; i++) {
144: double u = (double)i / (mapsize - 1);
145: double m, r = 0, g = 0, b = 0;
146: int k = 0;
147: while (k < 2 && u > knots[k + 1]) k++;
148: m = (u - knots[k]) / (knots[k + 1] - knots[k]);
149: switch (k) {
150: case 0:
151: r = m;
152: g = 0;
153: b = 0;
154: break;
155: case 1:
156: r = 1;
157: g = m;
158: b = 0;
159: break;
160: case 2:
161: r = 1;
162: g = 1;
163: b = m;
164: break;
165: }
166: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
167: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
168: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
169: }
170: PetscFunctionReturn(PETSC_SUCCESS);
171: }
173: static PetscErrorCode PetscDrawCmap_Bone(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
174: {
175: PetscFunctionBegin;
176: (void)PetscDrawCmap_Hot(mapsize, R, G, B);
177: for (int i = 0; i < mapsize; i++) {
178: double u = (double)i / (mapsize - 1);
179: double r = (7 * u + B[i] / 255.0) / 8;
180: double g = (7 * u + G[i] / 255.0) / 8;
181: double b = (7 * u + R[i] / 255.0) / 8;
182: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
183: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
184: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
185: }
186: PetscFunctionReturn(PETSC_SUCCESS);
187: }
189: #include "../src/sys/classes/draw/utils/cmap/coolwarm.h"
190: #include "../src/sys/classes/draw/utils/cmap/parula.h"
191: #include "../src/sys/classes/draw/utils/cmap/viridis.h"
192: #include "../src/sys/classes/draw/utils/cmap/plasma.h"
193: #include "../src/sys/classes/draw/utils/cmap/inferno.h"
194: #include "../src/sys/classes/draw/utils/cmap/magma.h"
196: static struct {
197: const char *name;
198: const unsigned char (*data)[3];
199: PetscErrorCode (*cmap)(int, unsigned char[], unsigned char[], unsigned char[]);
200: } PetscDrawCmapTable[] = {
201: {"hue", NULL, PetscDrawCmap_Hue }, /* varying hue with constant lightness and saturation */
202: {"gray", NULL, PetscDrawCmap_Gray}, /* black to white with shades of gray */
203: {"bone", NULL, PetscDrawCmap_Bone}, /* black to white with gray-blue shades */
204: {"jet", NULL, PetscDrawCmap_Jet }, /* rainbow-like colormap from NCSA, University of Illinois */
205: {"hot", NULL, PetscDrawCmap_Hot }, /* black-body radiation */
206: {"coolwarm", PetscDrawCmap_coolwarm, NULL }, /* ParaView default (Cool To Warm with Diverging interpolation) */
207: {"parula", PetscDrawCmap_parula, NULL }, /* MATLAB (default since R2014b) */
208: {"viridis", PetscDrawCmap_viridis, NULL }, /* matplotlib 1.5 (default since 2.0) */
209: {"plasma", PetscDrawCmap_plasma, NULL }, /* matplotlib 1.5 */
210: {"inferno", PetscDrawCmap_inferno, NULL }, /* matplotlib 1.5 */
211: {"magma", PetscDrawCmap_magma, NULL }, /* matplotlib 1.5 */
212: };
214: /*@C
215: PetscDrawUtilitySetCmap - Populate the RGB entries of a colormap from a named palette, honoring options-database
216: overrides for the colormap name, reversal, and brightness.
218: Not Collective
220: Input Parameters:
221: + colormap - the name of the colormap (e.g. `"hue"`, `"gray"`, `"jet"`, `"viridis"`), or `NULL`/empty for the default
222: - mapsize - the number of colormap entries to fill
224: Output Parameters:
225: + R - the red channel of length `mapsize`
226: . G - the green channel of length `mapsize`
227: - B - the blue channel of length `mapsize`
229: Options Database Keys:
230: + -draw_cmap name - select the colormap by name
231: . -draw_cmap_reverse - reverse the colormap
232: - -draw_cmap_brighten value - brighten (positive) or darken (negative) the colormap; value must be in `(-1, 1)`
234: Level: developer
236: .seealso: `PetscDraw`, `PetscDrawUtilitySetGamma()`
237: @*/
238: PetscErrorCode PetscDrawUtilitySetCmap(const char colormap[], int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
239: {
240: int i, j;
241: const char *cmap_name_list[PETSC_STATIC_ARRAY_LENGTH(PetscDrawCmapTable)];
242: PetscInt id = 0, count = PETSC_STATIC_ARRAY_LENGTH(cmap_name_list);
243: PetscBool reverse = PETSC_FALSE, brighten = PETSC_FALSE;
244: PetscReal beta = 0;
246: PetscFunctionBegin;
247: for (i = 0; i < count; i++) cmap_name_list[i] = PetscDrawCmapTable[i].name;
248: if (colormap && colormap[0]) {
249: PetscBool match = PETSC_FALSE;
250: for (id = 0; !match && id < count; id++) PetscCall(PetscStrcasecmp(colormap, cmap_name_list[id], &match));
251: PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Colormap '%s' not found", colormap);
252: }
253: PetscCall(PetscOptionsGetEList(NULL, NULL, "-draw_cmap", cmap_name_list, count, &id, NULL));
254: PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_cmap_reverse", &reverse, NULL));
255: PetscCall(PetscOptionsGetReal(NULL, NULL, "-draw_cmap_brighten", &beta, &brighten));
256: PetscCheck(!brighten || (beta > (PetscReal)-1 && beta < (PetscReal)+1), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "brighten parameter %g must be in the range (-1,1)", (double)beta);
258: if (PetscDrawCmapTable[id].cmap) {
259: PetscCall(PetscDrawCmapTable[id].cmap(mapsize, R, G, B));
260: } else {
261: const unsigned char (*rgb)[3] = PetscDrawCmapTable[id].data;
262: PetscCheck(mapsize == 256 - PETSC_DRAW_BASIC_COLORS, PETSC_COMM_SELF, PETSC_ERR_SUP, "Colormap '%s' with size %d not supported", cmap_name_list[id], mapsize);
263: for (i = 0; i < mapsize; i++) {
264: R[i] = rgb[i][0];
265: G[i] = rgb[i][1];
266: B[i] = rgb[i][2];
267: }
268: }
270: if (reverse) {
271: i = 0;
272: j = mapsize - 1;
273: while (i < j) {
274: #define SWAP(a, i, j) \
275: do { \
276: unsigned char t = a[i]; \
277: a[i] = a[j]; \
278: a[j] = t; \
279: } while (0)
280: SWAP(R, i, j);
281: SWAP(G, i, j);
282: SWAP(B, i, j);
283: #undef SWAP
284: i++;
285: j--;
286: }
287: }
289: if (brighten) {
290: PetscReal gamma = (beta > 0.0) ? (1 - beta) : (1 / (1 + beta));
291: for (i = 0; i < mapsize; i++) {
292: PetscReal r = PetscPowReal((PetscReal)R[i] / 255, gamma);
293: PetscReal g = PetscPowReal((PetscReal)G[i] / 255, gamma);
294: PetscReal b = PetscPowReal((PetscReal)B[i] / 255, gamma);
295: R[i] = (unsigned char)(255 * PetscMin(r, (PetscReal)1.0));
296: G[i] = (unsigned char)(255 * PetscMin(g, (PetscReal)1.0));
297: B[i] = (unsigned char)(255 * PetscMin(b, (PetscReal)1.0));
298: }
299: }
300: PetscFunctionReturn(PETSC_SUCCESS);
301: }