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 1600d931feSLisandro Dalcin PetscErrorCode PetscDrawUtilitySetGamma(PetscReal g) 1700d931feSLisandro Dalcin { 1800d931feSLisandro Dalcin PetscFunctionBegin; 1900d931feSLisandro Dalcin Gamma = g; 2000d931feSLisandro Dalcin PetscFunctionReturn(0); 2100d931feSLisandro Dalcin } 2200d931feSLisandro Dalcin 23*9fbee547SJacob Faibussowitsch static inline double PetscHlsHelper(double m1,double m2,double h) 2400d931feSLisandro Dalcin { 2583b97956SLisandro Dalcin while (h > 1.0) h -= 1.0; 2683b97956SLisandro Dalcin while (h < 0.0) h += 1.0; 2783b97956SLisandro Dalcin if (h < 1/6.0) return m1 + (m2-m1)*h*6; 2883b97956SLisandro Dalcin if (h < 1/2.0) return m2; 2983b97956SLisandro Dalcin if (h < 2/3.0) return m1 + (m2-m1)*(2/3.0-h)*6; 3000d931feSLisandro Dalcin return m1; 3100d931feSLisandro Dalcin } 3200d931feSLisandro Dalcin 33*9fbee547SJacob Faibussowitsch static inline void PetscHlsToRgb(double h,double l,double s,double *r,double *g,double *b) 3400d931feSLisandro Dalcin { 3583b97956SLisandro Dalcin if (s > 0.0) { 3683b97956SLisandro Dalcin double m2 = l <= 0.5 ? l * (1.0+s) : l+s-(l*s); 3783b97956SLisandro Dalcin double m1 = 2*l - m2; 3883b97956SLisandro Dalcin *r = PetscHlsHelper(m1,m2,h+1/3.); 3983b97956SLisandro Dalcin *g = PetscHlsHelper(m1,m2,h); 4083b97956SLisandro Dalcin *b = PetscHlsHelper(m1,m2,h-1/3.); 4100d931feSLisandro Dalcin } else { 4283b97956SLisandro Dalcin /* ignore hue */ 4383b97956SLisandro Dalcin *r = *g = *b = l; 4400d931feSLisandro Dalcin } 4500d931feSLisandro Dalcin } 4600d931feSLisandro Dalcin 47*9fbee547SJacob Faibussowitsch static inline void PetscGammaCorrect(double *r,double *g,double *b) 4883b97956SLisandro Dalcin { 4983b97956SLisandro Dalcin PetscReal igamma = 1/Gamma; 5083b97956SLisandro Dalcin *r = (double)PetscPowReal((PetscReal)*r,igamma); 5183b97956SLisandro Dalcin *g = (double)PetscPowReal((PetscReal)*g,igamma); 5283b97956SLisandro Dalcin *b = (double)PetscPowReal((PetscReal)*b,igamma); 5383b97956SLisandro Dalcin } 5483b97956SLisandro Dalcin 5500d931feSLisandro Dalcin static PetscErrorCode PetscDrawCmap_Hue(int mapsize, unsigned char R[],unsigned char G[],unsigned char B[]) 5600d931feSLisandro Dalcin { 5783b97956SLisandro Dalcin int i; 5883b97956SLisandro Dalcin double maxhue = 212.0/360,lightness = 0.5,saturation = 1.0; 5900d931feSLisandro Dalcin 6000d931feSLisandro Dalcin PetscFunctionBegin; 6100d931feSLisandro Dalcin for (i=0; i<mapsize; i++) { 6283b97956SLisandro Dalcin double hue = maxhue*(double)i/(mapsize-1),r,g,b; 6383b97956SLisandro Dalcin PetscHlsToRgb(hue,lightness,saturation,&r,&g,&b); 6483b97956SLisandro Dalcin PetscGammaCorrect(&r,&g,&b); 6583b97956SLisandro Dalcin R[i] = (unsigned char)(255*PetscMin(r,1.0)); 6683b97956SLisandro Dalcin G[i] = (unsigned char)(255*PetscMin(g,1.0)); 6783b97956SLisandro Dalcin B[i] = (unsigned char)(255*PetscMin(b,1.0)); 6800d931feSLisandro Dalcin } 6900d931feSLisandro Dalcin PetscFunctionReturn(0); 7000d931feSLisandro Dalcin } 7100d931feSLisandro Dalcin 7200d931feSLisandro Dalcin static PetscErrorCode PetscDrawCmap_Gray(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 7300d931feSLisandro Dalcin { 7400d931feSLisandro Dalcin int i; 7500d931feSLisandro Dalcin PetscFunctionBegin; 7600d931feSLisandro Dalcin for (i=0; i<mapsize; i++) R[i] = G[i] = B[i] = (unsigned char)((255.0*i)/(mapsize-1)); 7700d931feSLisandro Dalcin PetscFunctionReturn(0); 7800d931feSLisandro Dalcin } 7900d931feSLisandro Dalcin 8000d931feSLisandro Dalcin static PetscErrorCode PetscDrawCmap_Jet(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 8100d931feSLisandro Dalcin { 8200d931feSLisandro Dalcin int i; 8300d931feSLisandro Dalcin const double knots[] = {0, 1/8., 3/8., 5/8., 7/8., 1}; 8400d931feSLisandro Dalcin 8500d931feSLisandro Dalcin PetscFunctionBegin; 8600d931feSLisandro Dalcin for (i=0; i<mapsize; i++) { 8700d931feSLisandro Dalcin double u = (double)i/(mapsize-1); 8800d931feSLisandro Dalcin double m, r=0, g=0, b=0; int k = 0; 8900d931feSLisandro Dalcin while (k < 4 && u > knots[k+1]) k++; 9000d931feSLisandro Dalcin m = (u-knots[k])/(knots[k+1]-knots[k]); 9100d931feSLisandro Dalcin switch(k) { 9200d931feSLisandro Dalcin case 0: r = 0; g = 0; b = (m+1)/2; break; 9300d931feSLisandro Dalcin case 1: r = 0; g = m; b = 1; break; 9400d931feSLisandro Dalcin case 2: r = m; g = 1; b = 1-m; break; 9500d931feSLisandro Dalcin case 3: r = 1; g = 1-m; b = 0; break; 9600d931feSLisandro Dalcin case 4: r = 1-m/2; g = 0; b = 0; break; 9700d931feSLisandro Dalcin } 9800d931feSLisandro Dalcin R[i] = (unsigned char)(255*PetscMin(r,1.0)); 9900d931feSLisandro Dalcin G[i] = (unsigned char)(255*PetscMin(g,1.0)); 10000d931feSLisandro Dalcin B[i] = (unsigned char)(255*PetscMin(b,1.0)); 10100d931feSLisandro Dalcin } 10200d931feSLisandro Dalcin PetscFunctionReturn(0); 10300d931feSLisandro Dalcin } 10400d931feSLisandro Dalcin 10500d931feSLisandro Dalcin static PetscErrorCode PetscDrawCmap_Hot(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 10600d931feSLisandro Dalcin { 10700d931feSLisandro Dalcin int i; 10800d931feSLisandro Dalcin const double knots[] = {0, 3/8., 3/4., 1}; 10900d931feSLisandro Dalcin 11000d931feSLisandro Dalcin PetscFunctionBegin; 11100d931feSLisandro Dalcin for (i=0; i<mapsize; i++) { 11200d931feSLisandro Dalcin double u = (double)i/(mapsize-1); 11300d931feSLisandro Dalcin double m, r=0, g=0, b=0; int k = 0; 11400d931feSLisandro Dalcin while (k < 2 && u > knots[k+1]) k++; 11500d931feSLisandro Dalcin m = (u-knots[k])/(knots[k+1]-knots[k]); 11600d931feSLisandro Dalcin switch(k) { 11700d931feSLisandro Dalcin case 0: r = m; g = 0; b = 0; break; 11800d931feSLisandro Dalcin case 1: r = 1; g = m; b = 0; break; 11900d931feSLisandro Dalcin case 2: r = 1; g = 1; b = m; break; 12000d931feSLisandro Dalcin } 12100d931feSLisandro Dalcin R[i] = (unsigned char)(255*PetscMin(r,1.0)); 12200d931feSLisandro Dalcin G[i] = (unsigned char)(255*PetscMin(g,1.0)); 12300d931feSLisandro Dalcin B[i] = (unsigned char)(255*PetscMin(b,1.0)); 12400d931feSLisandro Dalcin } 12500d931feSLisandro Dalcin PetscFunctionReturn(0); 12600d931feSLisandro Dalcin } 12700d931feSLisandro Dalcin 12800d931feSLisandro Dalcin static PetscErrorCode PetscDrawCmap_Bone(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 12900d931feSLisandro Dalcin { 13000d931feSLisandro Dalcin int i; 13100d931feSLisandro Dalcin PetscFunctionBegin; 13200d931feSLisandro Dalcin (void)PetscDrawCmap_Hot(mapsize,R,G,B); 13300d931feSLisandro Dalcin for (i=0; i<mapsize; i++) { 13400d931feSLisandro Dalcin double u = (double)i/(mapsize-1); 13500d931feSLisandro Dalcin double r = (7*u + B[i]/255.0)/8; 13600d931feSLisandro Dalcin double g = (7*u + G[i]/255.0)/8; 13700d931feSLisandro Dalcin double b = (7*u + R[i]/255.0)/8; 13800d931feSLisandro Dalcin R[i] = (unsigned char)(255*PetscMin(r,1.0)); 13900d931feSLisandro Dalcin G[i] = (unsigned char)(255*PetscMin(g,1.0)); 14000d931feSLisandro Dalcin B[i] = (unsigned char)(255*PetscMin(b,1.0)); 14100d931feSLisandro Dalcin } 14200d931feSLisandro Dalcin PetscFunctionReturn(0); 14300d931feSLisandro Dalcin } 14400d931feSLisandro Dalcin 145575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/coolwarm.h" 146575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/parula.h" 147575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/viridis.h" 148575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/plasma.h" 149575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/inferno.h" 150575a0592SBarry Smith #include "../src/sys/classes/draw/utils/cmap/magma.h" 15100d931feSLisandro Dalcin 15200d931feSLisandro Dalcin static struct { 15300d931feSLisandro Dalcin const char *name; 15400d931feSLisandro Dalcin const unsigned char (*data)[3]; 15500d931feSLisandro Dalcin PetscErrorCode (*cmap)(int,unsigned char[],unsigned char[],unsigned char[]); 15600d931feSLisandro Dalcin } PetscDrawCmapTable[] = { 15700d931feSLisandro Dalcin {"hue", NULL, PetscDrawCmap_Hue }, /* varying hue with constant lightness and saturation */ 15800d931feSLisandro Dalcin {"gray", NULL, PetscDrawCmap_Gray}, /* black to white with shades of gray */ 15900d931feSLisandro Dalcin {"bone", NULL, PetscDrawCmap_Bone}, /* black to white with gray-blue shades */ 16000d931feSLisandro Dalcin {"jet", NULL, PetscDrawCmap_Jet }, /* rainbow-like colormap from NCSA, University of Illinois */ 16100d931feSLisandro Dalcin {"hot", NULL, PetscDrawCmap_Hot }, /* black-body radiation */ 16200d931feSLisandro Dalcin {"coolwarm", PetscDrawCmap_coolwarm, NULL}, /* ParaView default (Cool To Warm with Diverging interpolation) */ 16300d931feSLisandro Dalcin {"parula", PetscDrawCmap_parula, NULL}, /* MATLAB (default since R2014b) */ 16400d931feSLisandro Dalcin {"viridis", PetscDrawCmap_viridis, NULL}, /* matplotlib 1.5 (default since 2.0) */ 16500d931feSLisandro Dalcin {"plasma", PetscDrawCmap_plasma, NULL}, /* matplotlib 1.5 */ 16600d931feSLisandro Dalcin {"inferno", PetscDrawCmap_inferno, NULL}, /* matplotlib 1.5 */ 16700d931feSLisandro Dalcin {"magma", PetscDrawCmap_magma, NULL}, /* matplotlib 1.5 */ 16800d931feSLisandro Dalcin }; 16900d931feSLisandro Dalcin 17000d931feSLisandro Dalcin PetscErrorCode PetscDrawUtilitySetCmap(const char colormap[],int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 17100d931feSLisandro Dalcin { 17200d931feSLisandro Dalcin int i,j; 17300d931feSLisandro Dalcin const char *cmap_name_list[sizeof(PetscDrawCmapTable)/sizeof(PetscDrawCmapTable[0])]; 17400d931feSLisandro Dalcin PetscInt id = 0, count = (PetscInt)(sizeof(cmap_name_list)/sizeof(char*)); 17500d931feSLisandro Dalcin PetscBool reverse = PETSC_FALSE, brighten = PETSC_FALSE; 17600d931feSLisandro Dalcin PetscReal beta = 0; 17700d931feSLisandro Dalcin PetscErrorCode ierr; 17800d931feSLisandro Dalcin 17900d931feSLisandro Dalcin PetscFunctionBegin; 18000d931feSLisandro Dalcin for (i=0; i<count; i++) cmap_name_list[i] = PetscDrawCmapTable[i].name; 18100d931feSLisandro Dalcin if (colormap && colormap[0]) { 18200d931feSLisandro Dalcin PetscBool match = PETSC_FALSE; 18300d931feSLisandro Dalcin for (id=0; !match && id<count; id++) {ierr = PetscStrcasecmp(colormap,cmap_name_list[id],&match);CHKERRQ(ierr);} 1849ace16cdSJacob Faibussowitsch PetscAssertFalse(!match,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Colormap '%s' not found",colormap); 18500d931feSLisandro Dalcin } 18600d931feSLisandro Dalcin ierr = PetscOptionsGetEList(NULL,NULL,"-draw_cmap",cmap_name_list,count,&id,NULL);CHKERRQ(ierr); 18700d931feSLisandro Dalcin ierr = PetscOptionsGetBool(NULL,NULL,"-draw_cmap_reverse",&reverse,NULL);CHKERRQ(ierr); 18800d931feSLisandro Dalcin ierr = PetscOptionsGetReal(NULL,NULL,"-draw_cmap_brighten",&beta,&brighten);CHKERRQ(ierr); 1899ace16cdSJacob Faibussowitsch PetscAssertFalse(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); 19000d931feSLisandro Dalcin 19100d931feSLisandro Dalcin if (PetscDrawCmapTable[id].cmap) { 19200d931feSLisandro Dalcin ierr = PetscDrawCmapTable[id].cmap(mapsize,R,G,B);CHKERRQ(ierr); 19300d931feSLisandro Dalcin } else { 19400d931feSLisandro Dalcin const unsigned char (*rgb)[3] = PetscDrawCmapTable[id].data; 1959ace16cdSJacob Faibussowitsch PetscAssertFalse(mapsize != 256-PETSC_DRAW_BASIC_COLORS,PETSC_COMM_SELF,PETSC_ERR_SUP,"Colormap '%s' with size %d not supported",cmap_name_list[id],mapsize); 19600d931feSLisandro Dalcin for (i=0; i<mapsize; i++) {R[i] = rgb[i][0]; G[i] = rgb[i][1]; B[i] = rgb[i][2];} 19700d931feSLisandro Dalcin } 19800d931feSLisandro Dalcin 19900d931feSLisandro Dalcin if (reverse) { 20000d931feSLisandro Dalcin i = 0; j = mapsize-1; 20100d931feSLisandro Dalcin while (i < j) { 20200d931feSLisandro Dalcin #define SWAP(a,i,j) do { unsigned char t = a[i]; a[i] = a[j]; a[j] = t; } while (0) 20300d931feSLisandro Dalcin SWAP(R,i,j); 20400d931feSLisandro Dalcin SWAP(G,i,j); 20500d931feSLisandro Dalcin SWAP(B,i,j); 20600d931feSLisandro Dalcin #undef SWAP 20700d931feSLisandro Dalcin i++; j--; 20800d931feSLisandro Dalcin } 20900d931feSLisandro Dalcin } 21000d931feSLisandro Dalcin 21100d931feSLisandro Dalcin if (brighten) { 21200d931feSLisandro Dalcin PetscReal gamma = (beta > 0.0) ? (1 - beta) : (1 / (1 + beta)); 21300d931feSLisandro Dalcin for (i=0; i<mapsize; i++) { 21400d931feSLisandro Dalcin PetscReal r = PetscPowReal((PetscReal)R[i]/255,gamma); 21500d931feSLisandro Dalcin PetscReal g = PetscPowReal((PetscReal)G[i]/255,gamma); 21600d931feSLisandro Dalcin PetscReal b = PetscPowReal((PetscReal)B[i]/255,gamma); 21700d931feSLisandro Dalcin R[i] = (unsigned char)(255*PetscMin(r,(PetscReal)1.0)); 21800d931feSLisandro Dalcin G[i] = (unsigned char)(255*PetscMin(g,(PetscReal)1.0)); 21900d931feSLisandro Dalcin B[i] = (unsigned char)(255*PetscMin(b,(PetscReal)1.0)); 22000d931feSLisandro Dalcin } 22100d931feSLisandro Dalcin } 22200d931feSLisandro Dalcin PetscFunctionReturn(0); 22300d931feSLisandro Dalcin } 224