100d931feSLisandro Dalcin #include <petscsys.h> /*I "petscsys.h" I*/ 200d931feSLisandro Dalcin #include <petscdraw.h> 300d931feSLisandro Dalcin 400d931feSLisandro Dalcin /* 500d931feSLisandro Dalcin Set up a color map, using uniform separation in hue space. 600d931feSLisandro Dalcin Map entries are Red, Green, Blue. 700d931feSLisandro Dalcin Values are "gamma" corrected. 800d931feSLisandro Dalcin */ 900d931feSLisandro Dalcin 1000d931feSLisandro Dalcin /* 1100d931feSLisandro Dalcin Gamma is a monitor dependent value. The value here is an 1200d931feSLisandro Dalcin approximate that gives somewhat better results than Gamma = 1. 1300d931feSLisandro Dalcin */ 1400d931feSLisandro Dalcin static PetscReal Gamma = 2.0; 1500d931feSLisandro Dalcin 16*9371c9d4SSatish Balay PetscErrorCode PetscDrawUtilitySetGamma(PetscReal g) { 1700d931feSLisandro Dalcin PetscFunctionBegin; 1800d931feSLisandro Dalcin Gamma = g; 1900d931feSLisandro Dalcin PetscFunctionReturn(0); 2000d931feSLisandro Dalcin } 2100d931feSLisandro Dalcin 22*9371c9d4SSatish Balay static inline double PetscHlsHelper(double m1, double m2, double h) { 2383b97956SLisandro Dalcin while (h > 1.0) h -= 1.0; 2483b97956SLisandro Dalcin while (h < 0.0) h += 1.0; 2583b97956SLisandro Dalcin if (h < 1 / 6.0) return m1 + (m2 - m1) * h * 6; 2683b97956SLisandro Dalcin if (h < 1 / 2.0) return m2; 2783b97956SLisandro Dalcin if (h < 2 / 3.0) return m1 + (m2 - m1) * (2 / 3.0 - h) * 6; 2800d931feSLisandro Dalcin return m1; 2900d931feSLisandro Dalcin } 3000d931feSLisandro Dalcin 31*9371c9d4SSatish Balay static inline void PetscHlsToRgb(double h, double l, double s, double *r, double *g, double *b) { 3283b97956SLisandro Dalcin if (s > 0.0) { 3383b97956SLisandro Dalcin double m2 = l <= 0.5 ? l * (1.0 + s) : l + s - (l * s); 3483b97956SLisandro Dalcin double m1 = 2 * l - m2; 3583b97956SLisandro Dalcin *r = PetscHlsHelper(m1, m2, h + 1 / 3.); 3683b97956SLisandro Dalcin *g = PetscHlsHelper(m1, m2, h); 3783b97956SLisandro Dalcin *b = PetscHlsHelper(m1, m2, h - 1 / 3.); 3800d931feSLisandro Dalcin } else { 3983b97956SLisandro Dalcin /* ignore hue */ 4083b97956SLisandro Dalcin *r = *g = *b = l; 4100d931feSLisandro Dalcin } 4200d931feSLisandro Dalcin } 4300d931feSLisandro Dalcin 44*9371c9d4SSatish Balay static inline void PetscGammaCorrect(double *r, double *g, double *b) { 4583b97956SLisandro Dalcin PetscReal igamma = 1 / Gamma; 4683b97956SLisandro Dalcin *r = (double)PetscPowReal((PetscReal)*r, igamma); 4783b97956SLisandro Dalcin *g = (double)PetscPowReal((PetscReal)*g, igamma); 4883b97956SLisandro Dalcin *b = (double)PetscPowReal((PetscReal)*b, igamma); 4983b97956SLisandro Dalcin } 5083b97956SLisandro Dalcin 51*9371c9d4SSatish Balay static PetscErrorCode PetscDrawCmap_Hue(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[]) { 5283b97956SLisandro Dalcin int i; 5383b97956SLisandro Dalcin double maxhue = 212.0 / 360, lightness = 0.5, saturation = 1.0; 5400d931feSLisandro Dalcin 5500d931feSLisandro Dalcin PetscFunctionBegin; 5600d931feSLisandro Dalcin for (i = 0; i < mapsize; i++) { 5783b97956SLisandro Dalcin double hue = maxhue * (double)i / (mapsize - 1), r, g, b; 5883b97956SLisandro Dalcin PetscHlsToRgb(hue, lightness, saturation, &r, &g, &b); 5983b97956SLisandro Dalcin PetscGammaCorrect(&r, &g, &b); 6083b97956SLisandro Dalcin R[i] = (unsigned char)(255 * PetscMin(r, 1.0)); 6183b97956SLisandro Dalcin G[i] = (unsigned char)(255 * PetscMin(g, 1.0)); 6283b97956SLisandro Dalcin B[i] = (unsigned char)(255 * PetscMin(b, 1.0)); 6300d931feSLisandro Dalcin } 6400d931feSLisandro Dalcin PetscFunctionReturn(0); 6500d931feSLisandro Dalcin } 6600d931feSLisandro Dalcin 67*9371c9d4SSatish Balay static PetscErrorCode PetscDrawCmap_Gray(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[]) { 6800d931feSLisandro Dalcin int i; 6900d931feSLisandro Dalcin PetscFunctionBegin; 7000d931feSLisandro Dalcin for (i = 0; i < mapsize; i++) R[i] = G[i] = B[i] = (unsigned char)((255.0 * i) / (mapsize - 1)); 7100d931feSLisandro Dalcin PetscFunctionReturn(0); 7200d931feSLisandro Dalcin } 7300d931feSLisandro Dalcin 74*9371c9d4SSatish Balay static PetscErrorCode PetscDrawCmap_Jet(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[]) { 7500d931feSLisandro Dalcin int i; 7600d931feSLisandro Dalcin const double knots[] = {0, 1 / 8., 3 / 8., 5 / 8., 7 / 8., 1}; 7700d931feSLisandro Dalcin 7800d931feSLisandro Dalcin PetscFunctionBegin; 7900d931feSLisandro Dalcin for (i = 0; i < mapsize; i++) { 8000d931feSLisandro Dalcin double u = (double)i / (mapsize - 1); 81*9371c9d4SSatish Balay double m, r = 0, g = 0, b = 0; 82*9371c9d4SSatish Balay int k = 0; 8300d931feSLisandro Dalcin while (k < 4 && u > knots[k + 1]) k++; 8400d931feSLisandro Dalcin m = (u - knots[k]) / (knots[k + 1] - knots[k]); 8500d931feSLisandro Dalcin switch (k) { 86*9371c9d4SSatish Balay case 0: 87*9371c9d4SSatish Balay r = 0; 88*9371c9d4SSatish Balay g = 0; 89*9371c9d4SSatish Balay b = (m + 1) / 2; 90*9371c9d4SSatish Balay break; 91*9371c9d4SSatish Balay case 1: 92*9371c9d4SSatish Balay r = 0; 93*9371c9d4SSatish Balay g = m; 94*9371c9d4SSatish Balay b = 1; 95*9371c9d4SSatish Balay break; 96*9371c9d4SSatish Balay case 2: 97*9371c9d4SSatish Balay r = m; 98*9371c9d4SSatish Balay g = 1; 99*9371c9d4SSatish Balay b = 1 - m; 100*9371c9d4SSatish Balay break; 101*9371c9d4SSatish Balay case 3: 102*9371c9d4SSatish Balay r = 1; 103*9371c9d4SSatish Balay g = 1 - m; 104*9371c9d4SSatish Balay b = 0; 105*9371c9d4SSatish Balay break; 106*9371c9d4SSatish Balay case 4: 107*9371c9d4SSatish Balay r = 1 - m / 2; 108*9371c9d4SSatish Balay g = 0; 109*9371c9d4SSatish Balay b = 0; 110*9371c9d4SSatish Balay break; 11100d931feSLisandro Dalcin } 11200d931feSLisandro Dalcin R[i] = (unsigned char)(255 * PetscMin(r, 1.0)); 11300d931feSLisandro Dalcin G[i] = (unsigned char)(255 * PetscMin(g, 1.0)); 11400d931feSLisandro Dalcin B[i] = (unsigned char)(255 * PetscMin(b, 1.0)); 11500d931feSLisandro Dalcin } 11600d931feSLisandro Dalcin PetscFunctionReturn(0); 11700d931feSLisandro Dalcin } 11800d931feSLisandro Dalcin 119*9371c9d4SSatish Balay static PetscErrorCode PetscDrawCmap_Hot(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[]) { 12000d931feSLisandro Dalcin int i; 12100d931feSLisandro Dalcin const double knots[] = {0, 3 / 8., 3 / 4., 1}; 12200d931feSLisandro Dalcin 12300d931feSLisandro Dalcin PetscFunctionBegin; 12400d931feSLisandro Dalcin for (i = 0; i < mapsize; i++) { 12500d931feSLisandro Dalcin double u = (double)i / (mapsize - 1); 126*9371c9d4SSatish Balay double m, r = 0, g = 0, b = 0; 127*9371c9d4SSatish Balay int k = 0; 12800d931feSLisandro Dalcin while (k < 2 && u > knots[k + 1]) k++; 12900d931feSLisandro Dalcin m = (u - knots[k]) / (knots[k + 1] - knots[k]); 13000d931feSLisandro Dalcin switch (k) { 131*9371c9d4SSatish Balay case 0: 132*9371c9d4SSatish Balay r = m; 133*9371c9d4SSatish Balay g = 0; 134*9371c9d4SSatish Balay b = 0; 135*9371c9d4SSatish Balay break; 136*9371c9d4SSatish Balay case 1: 137*9371c9d4SSatish Balay r = 1; 138*9371c9d4SSatish Balay g = m; 139*9371c9d4SSatish Balay b = 0; 140*9371c9d4SSatish Balay break; 141*9371c9d4SSatish Balay case 2: 142*9371c9d4SSatish Balay r = 1; 143*9371c9d4SSatish Balay g = 1; 144*9371c9d4SSatish Balay b = m; 145*9371c9d4SSatish Balay break; 14600d931feSLisandro Dalcin } 14700d931feSLisandro Dalcin R[i] = (unsigned char)(255 * PetscMin(r, 1.0)); 14800d931feSLisandro Dalcin G[i] = (unsigned char)(255 * PetscMin(g, 1.0)); 14900d931feSLisandro Dalcin B[i] = (unsigned char)(255 * PetscMin(b, 1.0)); 15000d931feSLisandro Dalcin } 15100d931feSLisandro Dalcin PetscFunctionReturn(0); 15200d931feSLisandro Dalcin } 15300d931feSLisandro Dalcin 154*9371c9d4SSatish Balay static PetscErrorCode PetscDrawCmap_Bone(int mapsize, unsigned char R[], unsigned char G[], unsigned char B[]) { 15500d931feSLisandro Dalcin int i; 15600d931feSLisandro Dalcin PetscFunctionBegin; 15700d931feSLisandro Dalcin (void)PetscDrawCmap_Hot(mapsize, R, G, B); 15800d931feSLisandro Dalcin for (i = 0; i < mapsize; i++) { 15900d931feSLisandro Dalcin double u = (double)i / (mapsize - 1); 16000d931feSLisandro Dalcin double r = (7 * u + B[i] / 255.0) / 8; 16100d931feSLisandro Dalcin double g = (7 * u + G[i] / 255.0) / 8; 16200d931feSLisandro Dalcin double b = (7 * u + R[i] / 255.0) / 8; 16300d931feSLisandro Dalcin R[i] = (unsigned char)(255 * PetscMin(r, 1.0)); 16400d931feSLisandro Dalcin G[i] = (unsigned char)(255 * PetscMin(g, 1.0)); 16500d931feSLisandro Dalcin B[i] = (unsigned char)(255 * PetscMin(b, 1.0)); 16600d931feSLisandro Dalcin } 16700d931feSLisandro Dalcin PetscFunctionReturn(0); 16800d931feSLisandro Dalcin } 16900d931feSLisandro Dalcin 170575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/coolwarm.h" 171575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/parula.h" 172575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/viridis.h" 173575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/plasma.h" 174575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/inferno.h" 175575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/magma.h" 17600d931feSLisandro Dalcin 17700d931feSLisandro Dalcin static struct { 17800d931feSLisandro Dalcin const char *name; 17900d931feSLisandro Dalcin const unsigned char (*data)[3]; 18000d931feSLisandro Dalcin PetscErrorCode (*cmap)(int, unsigned char[], unsigned char[], unsigned char[]); 18100d931feSLisandro Dalcin } PetscDrawCmapTable[] = { 18200d931feSLisandro Dalcin {"hue", NULL, PetscDrawCmap_Hue }, /* varying hue with constant lightness and saturation */ 18300d931feSLisandro Dalcin {"gray", NULL, PetscDrawCmap_Gray}, /* black to white with shades of gray */ 18400d931feSLisandro Dalcin {"bone", NULL, PetscDrawCmap_Bone}, /* black to white with gray-blue shades */ 18500d931feSLisandro Dalcin {"jet", NULL, PetscDrawCmap_Jet }, /* rainbow-like colormap from NCSA, University of Illinois */ 18600d931feSLisandro Dalcin {"hot", NULL, PetscDrawCmap_Hot }, /* black-body radiation */ 18700d931feSLisandro Dalcin {"coolwarm", PetscDrawCmap_coolwarm, NULL }, /* ParaView default (Cool To Warm with Diverging interpolation) */ 18800d931feSLisandro Dalcin {"parula", PetscDrawCmap_parula, NULL }, /* MATLAB (default since R2014b) */ 18900d931feSLisandro Dalcin {"viridis", PetscDrawCmap_viridis, NULL }, /* matplotlib 1.5 (default since 2.0) */ 19000d931feSLisandro Dalcin {"plasma", PetscDrawCmap_plasma, NULL }, /* matplotlib 1.5 */ 19100d931feSLisandro Dalcin {"inferno", PetscDrawCmap_inferno, NULL }, /* matplotlib 1.5 */ 19200d931feSLisandro Dalcin {"magma", PetscDrawCmap_magma, NULL }, /* matplotlib 1.5 */ 19300d931feSLisandro Dalcin }; 19400d931feSLisandro Dalcin 195*9371c9d4SSatish Balay PetscErrorCode PetscDrawUtilitySetCmap(const char colormap[], int mapsize, unsigned char R[], unsigned char G[], unsigned char B[]) { 19600d931feSLisandro Dalcin int i, j; 197dd39110bSPierre Jolivet const char *cmap_name_list[PETSC_STATIC_ARRAY_LENGTH(PetscDrawCmapTable)]; 19800d931feSLisandro Dalcin PetscInt id = 0, count = (PetscInt)(sizeof(cmap_name_list) / sizeof(char *)); 19900d931feSLisandro Dalcin PetscBool reverse = PETSC_FALSE, brighten = PETSC_FALSE; 20000d931feSLisandro Dalcin PetscReal beta = 0; 20100d931feSLisandro Dalcin 20200d931feSLisandro Dalcin PetscFunctionBegin; 20300d931feSLisandro Dalcin for (i = 0; i < count; i++) cmap_name_list[i] = PetscDrawCmapTable[i].name; 20400d931feSLisandro Dalcin if (colormap && colormap[0]) { 20500d931feSLisandro Dalcin PetscBool match = PETSC_FALSE; 2069566063dSJacob Faibussowitsch for (id = 0; !match && id < count; id++) PetscCall(PetscStrcasecmp(colormap, cmap_name_list[id], &match)); 20728b400f6SJacob Faibussowitsch PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Colormap '%s' not found", colormap); 20800d931feSLisandro Dalcin } 2099566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetEList(NULL, NULL, "-draw_cmap", cmap_name_list, count, &id, NULL)); 2109566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL, NULL, "-draw_cmap_reverse", &reverse, NULL)); 2119566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetReal(NULL, NULL, "-draw_cmap_brighten", &beta, &brighten)); 212cc73adaaSBarry Smith 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); 21300d931feSLisandro Dalcin 21400d931feSLisandro Dalcin if (PetscDrawCmapTable[id].cmap) { 2159566063dSJacob Faibussowitsch PetscCall(PetscDrawCmapTable[id].cmap(mapsize, R, G, B)); 21600d931feSLisandro Dalcin } else { 21700d931feSLisandro Dalcin const unsigned char(*rgb)[3] = PetscDrawCmapTable[id].data; 21808401ef6SPierre Jolivet 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); 219*9371c9d4SSatish Balay for (i = 0; i < mapsize; i++) { 220*9371c9d4SSatish Balay R[i] = rgb[i][0]; 221*9371c9d4SSatish Balay G[i] = rgb[i][1]; 222*9371c9d4SSatish Balay B[i] = rgb[i][2]; 223*9371c9d4SSatish Balay } 22400d931feSLisandro Dalcin } 22500d931feSLisandro Dalcin 22600d931feSLisandro Dalcin if (reverse) { 227*9371c9d4SSatish Balay i = 0; 228*9371c9d4SSatish Balay j = mapsize - 1; 22900d931feSLisandro Dalcin while (i < j) { 230*9371c9d4SSatish Balay #define SWAP(a, i, j) \ 231*9371c9d4SSatish Balay do { \ 232*9371c9d4SSatish Balay unsigned char t = a[i]; \ 233*9371c9d4SSatish Balay a[i] = a[j]; \ 234*9371c9d4SSatish Balay a[j] = t; \ 235*9371c9d4SSatish Balay } while (0) 23600d931feSLisandro Dalcin SWAP(R, i, j); 23700d931feSLisandro Dalcin SWAP(G, i, j); 23800d931feSLisandro Dalcin SWAP(B, i, j); 23900d931feSLisandro Dalcin #undef SWAP 240*9371c9d4SSatish Balay i++; 241*9371c9d4SSatish Balay j--; 24200d931feSLisandro Dalcin } 24300d931feSLisandro Dalcin } 24400d931feSLisandro Dalcin 24500d931feSLisandro Dalcin if (brighten) { 24600d931feSLisandro Dalcin PetscReal gamma = (beta > 0.0) ? (1 - beta) : (1 / (1 + beta)); 24700d931feSLisandro Dalcin for (i = 0; i < mapsize; i++) { 24800d931feSLisandro Dalcin PetscReal r = PetscPowReal((PetscReal)R[i] / 255, gamma); 24900d931feSLisandro Dalcin PetscReal g = PetscPowReal((PetscReal)G[i] / 255, gamma); 25000d931feSLisandro Dalcin PetscReal b = PetscPowReal((PetscReal)B[i] / 255, gamma); 25100d931feSLisandro Dalcin R[i] = (unsigned char)(255 * PetscMin(r, (PetscReal)1.0)); 25200d931feSLisandro Dalcin G[i] = (unsigned char)(255 * PetscMin(g, (PetscReal)1.0)); 25300d931feSLisandro Dalcin B[i] = (unsigned char)(255 * PetscMin(b, (PetscReal)1.0)); 25400d931feSLisandro Dalcin } 25500d931feSLisandro Dalcin } 25600d931feSLisandro Dalcin PetscFunctionReturn(0); 25700d931feSLisandro Dalcin } 258