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: PetscErrorCode PetscDrawUtilitySetGamma(PetscReal g)
17: {
18: PetscFunctionBegin;
19: Gamma = g;
20: PetscFunctionReturn(PETSC_SUCCESS);
21: }
23: static inline double PetscHlsHelper(double m1, double m2, double h)
24: {
25: while (h > 1.0) h -= 1.0;
26: while (h < 0.0) h += 1.0;
27: if (h < 1 / 6.0) return m1 + (m2 - m1) * h * 6;
28: if (h < 1 / 2.0) return m2;
29: if (h < 2 / 3.0) return m1 + (m2 - m1) * (2 / 3.0 - h) * 6;
30: return m1;
31: }
33: static inline void PetscHlsToRgb(double h, double l, double s, double *r, double *g, double *b)
34: {
35: if (s > 0.0) {
36: double m2 = l <= 0.5 ? l * (1.0 + s) : l + s - (l * s);
37: double m1 = 2 * l - m2;
38: *r = PetscHlsHelper(m1, m2, h + 1 / 3.);
39: *g = PetscHlsHelper(m1, m2, h);
40: *b = PetscHlsHelper(m1, m2, h - 1 / 3.);
41: } else {
42: /* ignore hue */
43: *r = *g = *b = l;
44: }
45: }
47: static inline void PetscGammaCorrect(double *r, double *g, double *b)
48: {
49: PetscReal igamma = 1 / Gamma;
50: *r = (double)PetscPowReal((PetscReal)*r, igamma);
51: *g = (double)PetscPowReal((PetscReal)*g, igamma);
52: *b = (double)PetscPowReal((PetscReal)*b, igamma);
53: }
55: static PetscErrorCode PetscDrawCmap_Hue(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
56: {
57: int i;
58: double maxhue = 212.0 / 360, lightness = 0.5, saturation = 1.0;
60: PetscFunctionBegin;
61: for (i = 0; i < mapsize; i++) {
62: double hue = maxhue * (double)i / (mapsize - 1), r, g, b;
63: PetscHlsToRgb(hue, lightness, saturation, &r, &g, &b);
64: PetscGammaCorrect(&r, &g, &b);
65: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
66: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
67: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
68: }
69: PetscFunctionReturn(PETSC_SUCCESS);
70: }
72: static PetscErrorCode PetscDrawCmap_Gray(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
73: {
74: PetscFunctionBegin;
75: for (int i = 0; i < mapsize; i++) R[i] = G[i] = B[i] = (unsigned char)((255.0 * i) / (mapsize - 1));
76: PetscFunctionReturn(PETSC_SUCCESS);
77: }
79: static PetscErrorCode PetscDrawCmap_Jet(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
80: {
81: int i;
82: const double knots[] = {0, 1 / 8., 3 / 8., 5 / 8., 7 / 8., 1};
84: PetscFunctionBegin;
85: for (i = 0; i < mapsize; i++) {
86: double u = (double)i / (mapsize - 1);
87: double m, r = 0, g = 0, b = 0;
88: int k = 0;
89: while (k < 4 && u > knots[k + 1]) k++;
90: m = (u - knots[k]) / (knots[k + 1] - knots[k]);
91: switch (k) {
92: case 0:
93: r = 0;
94: g = 0;
95: b = (m + 1) / 2;
96: break;
97: case 1:
98: r = 0;
99: g = m;
100: b = 1;
101: break;
102: case 2:
103: r = m;
104: g = 1;
105: b = 1 - m;
106: break;
107: case 3:
108: r = 1;
109: g = 1 - m;
110: b = 0;
111: break;
112: case 4:
113: r = 1 - m / 2;
114: g = 0;
115: b = 0;
116: break;
117: }
118: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
119: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
120: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
121: }
122: PetscFunctionReturn(PETSC_SUCCESS);
123: }
125: static PetscErrorCode PetscDrawCmap_Hot(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
126: {
127: int i;
128: const double knots[] = {0, 3 / 8., 3 / 4., 1};
130: PetscFunctionBegin;
131: for (i = 0; i < mapsize; i++) {
132: double u = (double)i / (mapsize - 1);
133: double m, r = 0, g = 0, b = 0;
134: int k = 0;
135: while (k < 2 && u > knots[k + 1]) k++;
136: m = (u - knots[k]) / (knots[k + 1] - knots[k]);
137: switch (k) {
138: case 0:
139: r = m;
140: g = 0;
141: b = 0;
142: break;
143: case 1:
144: r = 1;
145: g = m;
146: b = 0;
147: break;
148: case 2:
149: r = 1;
150: g = 1;
151: b = m;
152: break;
153: }
154: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
155: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
156: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
157: }
158: PetscFunctionReturn(PETSC_SUCCESS);
159: }
161: static PetscErrorCode PetscDrawCmap_Bone(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
162: {
163: PetscFunctionBegin;
164: (void)PetscDrawCmap_Hot(mapsize, R, G, B);
165: for (int i = 0; i < mapsize; i++) {
166: double u = (double)i / (mapsize - 1);
167: double r = (7 * u + B[i] / 255.0) / 8;
168: double g = (7 * u + G[i] / 255.0) / 8;
169: double b = (7 * u + R[i] / 255.0) / 8;
170: R[i] = (unsigned char)(255 * PetscMin(r, 1.0));
171: G[i] = (unsigned char)(255 * PetscMin(g, 1.0));
172: B[i] = (unsigned char)(255 * PetscMin(b, 1.0));
173: }
174: PetscFunctionReturn(PETSC_SUCCESS);
175: }
177: #include "../src/sys/classes/draw/utils/cmap/coolwarm.h"
178: #include "../src/sys/classes/draw/utils/cmap/parula.h"
179: #include "../src/sys/classes/draw/utils/cmap/viridis.h"
180: #include "../src/sys/classes/draw/utils/cmap/plasma.h"
181: #include "../src/sys/classes/draw/utils/cmap/inferno.h"
182: #include "../src/sys/classes/draw/utils/cmap/magma.h"
184: static struct {
185: const char *name;
186: const unsigned char (*data)[3];
187: PetscErrorCode (*cmap)(int, unsigned char[], unsigned char[], unsigned char[]);
188: } PetscDrawCmapTable[] = {
189: {"hue", NULL, PetscDrawCmap_Hue }, /* varying hue with constant lightness and saturation */
190: {"gray", NULL, PetscDrawCmap_Gray}, /* black to white with shades of gray */
191: {"bone", NULL, PetscDrawCmap_Bone}, /* black to white with gray-blue shades */
192: {"jet", NULL, PetscDrawCmap_Jet }, /* rainbow-like colormap from NCSA, University of Illinois */
193: {"hot", NULL, PetscDrawCmap_Hot }, /* black-body radiation */
194: {"coolwarm", PetscDrawCmap_coolwarm, NULL }, /* ParaView default (Cool To Warm with Diverging interpolation) */
195: {"parula", PetscDrawCmap_parula, NULL }, /* MATLAB (default since R2014b) */
196: {"viridis", PetscDrawCmap_viridis, NULL }, /* matplotlib 1.5 (default since 2.0) */
197: {"plasma", PetscDrawCmap_plasma, NULL }, /* matplotlib 1.5 */
198: {"inferno", PetscDrawCmap_inferno, NULL }, /* matplotlib 1.5 */
199: {"magma", PetscDrawCmap_magma, NULL }, /* matplotlib 1.5 */
200: };
202: PetscErrorCode PetscDrawUtilitySetCmap(const char colormap[], int mapsize, unsigned char R[], unsigned char G[], unsigned char B[])
203: {
204: int i, j;
205: const char *cmap_name_list[PETSC_STATIC_ARRAY_LENGTH(PetscDrawCmapTable)];
206: PetscInt id = 0, count = PETSC_STATIC_ARRAY_LENGTH(cmap_name_list);
207: PetscBool reverse = PETSC_FALSE, brighten = PETSC_FALSE;
208: PetscReal beta = 0;
210: PetscFunctionBegin;
211: for (i = 0; i < count; i++) cmap_name_list[i] = PetscDrawCmapTable[i].name;
212: if (colormap && colormap[0]) {
213: PetscBool match = PETSC_FALSE;
214: for (id = 0; !match && id < count; id++) PetscCall(PetscStrcasecmp(colormap, cmap_name_list[id], &match));
215: PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Colormap '%s' not found", colormap);
216: }
217: PetscCall(PetscOptionsGetEList(NULL, NULL, "-draw_cmap", cmap_name_list, count, &id, NULL));
218: PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_cmap_reverse", &reverse, NULL));
219: PetscCall(PetscOptionsGetReal(NULL, NULL, "-draw_cmap_brighten", &beta, &brighten));
220: 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);
222: if (PetscDrawCmapTable[id].cmap) {
223: PetscCall(PetscDrawCmapTable[id].cmap(mapsize, R, G, B));
224: } else {
225: const unsigned char(*rgb)[3] = PetscDrawCmapTable[id].data;
226: 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);
227: for (i = 0; i < mapsize; i++) {
228: R[i] = rgb[i][0];
229: G[i] = rgb[i][1];
230: B[i] = rgb[i][2];
231: }
232: }
234: if (reverse) {
235: i = 0;
236: j = mapsize - 1;
237: while (i < j) {
238: #define SWAP(a, i, j) \
239: do { \
240: unsigned char t = a[i]; \
241: a[i] = a[j]; \
242: a[j] = t; \
243: } while (0)
244: SWAP(R, i, j);
245: SWAP(G, i, j);
246: SWAP(B, i, j);
247: #undef SWAP
248: i++;
249: j--;
250: }
251: }
253: if (brighten) {
254: PetscReal gamma = (beta > 0.0) ? (1 - beta) : (1 / (1 + beta));
255: for (i = 0; i < mapsize; i++) {
256: PetscReal r = PetscPowReal((PetscReal)R[i] / 255, gamma);
257: PetscReal g = PetscPowReal((PetscReal)G[i] / 255, gamma);
258: PetscReal b = PetscPowReal((PetscReal)B[i] / 255, gamma);
259: R[i] = (unsigned char)(255 * PetscMin(r, (PetscReal)1.0));
260: G[i] = (unsigned char)(255 * PetscMin(g, (PetscReal)1.0));
261: B[i] = (unsigned char)(255 * PetscMin(b, (PetscReal)1.0));
262: }
263: }
264: PetscFunctionReturn(PETSC_SUCCESS);
265: }