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