1 #include <petscsys.h> /*I "petscsys.h" I*/ 2 #include <petscdraw.h> 3 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 */ 9 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; 15 16 PetscErrorCode PetscDrawUtilitySetGamma(PetscReal g) 17 { 18 PetscFunctionBegin; 19 Gamma = g; 20 PetscFunctionReturn(0); 21 } 22 23 PETSC_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 } 32 33 PETSC_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 } 46 47 PETSC_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 } 54 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; 59 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(0); 70 } 71 72 static PetscErrorCode PetscDrawCmap_Gray(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 73 { 74 int i; 75 PetscFunctionBegin; 76 for (i=0; i<mapsize; i++) R[i] = G[i] = B[i] = (unsigned char)((255.0*i)/(mapsize-1)); 77 PetscFunctionReturn(0); 78 } 79 80 static PetscErrorCode PetscDrawCmap_Jet(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 81 { 82 int i; 83 const double knots[] = {0, 1/8., 3/8., 5/8., 7/8., 1}; 84 85 PetscFunctionBegin; 86 for (i=0; i<mapsize; i++) { 87 double u = (double)i/(mapsize-1); 88 double m, r=0, g=0, b=0; 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: r = 0; g = 0; b = (m+1)/2; break; 93 case 1: r = 0; g = m; b = 1; break; 94 case 2: r = m; g = 1; b = 1-m; break; 95 case 3: r = 1; g = 1-m; b = 0; break; 96 case 4: r = 1-m/2; g = 0; b = 0; break; 97 } 98 R[i] = (unsigned char)(255*PetscMin(r,1.0)); 99 G[i] = (unsigned char)(255*PetscMin(g,1.0)); 100 B[i] = (unsigned char)(255*PetscMin(b,1.0)); 101 } 102 PetscFunctionReturn(0); 103 } 104 105 static PetscErrorCode PetscDrawCmap_Hot(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 106 { 107 int i; 108 const double knots[] = {0, 3/8., 3/4., 1}; 109 110 PetscFunctionBegin; 111 for (i=0; i<mapsize; i++) { 112 double u = (double)i/(mapsize-1); 113 double m, r=0, g=0, b=0; int k = 0; 114 while (k < 2 && u > knots[k+1]) k++; 115 m = (u-knots[k])/(knots[k+1]-knots[k]); 116 switch(k) { 117 case 0: r = m; g = 0; b = 0; break; 118 case 1: r = 1; g = m; b = 0; break; 119 case 2: r = 1; g = 1; b = m; break; 120 } 121 R[i] = (unsigned char)(255*PetscMin(r,1.0)); 122 G[i] = (unsigned char)(255*PetscMin(g,1.0)); 123 B[i] = (unsigned char)(255*PetscMin(b,1.0)); 124 } 125 PetscFunctionReturn(0); 126 } 127 128 static PetscErrorCode PetscDrawCmap_Bone(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 129 { 130 int i; 131 PetscFunctionBegin; 132 (void)PetscDrawCmap_Hot(mapsize,R,G,B); 133 for (i=0; i<mapsize; i++) { 134 double u = (double)i/(mapsize-1); 135 double r = (7*u + B[i]/255.0)/8; 136 double g = (7*u + G[i]/255.0)/8; 137 double b = (7*u + R[i]/255.0)/8; 138 R[i] = (unsigned char)(255*PetscMin(r,1.0)); 139 G[i] = (unsigned char)(255*PetscMin(g,1.0)); 140 B[i] = (unsigned char)(255*PetscMin(b,1.0)); 141 } 142 PetscFunctionReturn(0); 143 } 144 145 #include "../src/sys/classes/draw/utils/cmap/coolwarm.h" 146 #include "../src/sys/classes/draw/utils/cmap/parula.h" 147 #include "../src/sys/classes/draw/utils/cmap/viridis.h" 148 #include "../src/sys/classes/draw/utils/cmap/plasma.h" 149 #include "../src/sys/classes/draw/utils/cmap/inferno.h" 150 #include "../src/sys/classes/draw/utils/cmap/magma.h" 151 152 static struct { 153 const char *name; 154 const unsigned char (*data)[3]; 155 PetscErrorCode (*cmap)(int,unsigned char[],unsigned char[],unsigned char[]); 156 } PetscDrawCmapTable[] = { 157 {"hue", NULL, PetscDrawCmap_Hue }, /* varying hue with constant lightness and saturation */ 158 {"gray", NULL, PetscDrawCmap_Gray}, /* black to white with shades of gray */ 159 {"bone", NULL, PetscDrawCmap_Bone}, /* black to white with gray-blue shades */ 160 {"jet", NULL, PetscDrawCmap_Jet }, /* rainbow-like colormap from NCSA, University of Illinois */ 161 {"hot", NULL, PetscDrawCmap_Hot }, /* black-body radiation */ 162 {"coolwarm", PetscDrawCmap_coolwarm, NULL}, /* ParaView default (Cool To Warm with Diverging interpolation) */ 163 {"parula", PetscDrawCmap_parula, NULL}, /* MATLAB (default since R2014b) */ 164 {"viridis", PetscDrawCmap_viridis, NULL}, /* matplotlib 1.5 (default since 2.0) */ 165 {"plasma", PetscDrawCmap_plasma, NULL}, /* matplotlib 1.5 */ 166 {"inferno", PetscDrawCmap_inferno, NULL}, /* matplotlib 1.5 */ 167 {"magma", PetscDrawCmap_magma, NULL}, /* matplotlib 1.5 */ 168 }; 169 170 PetscErrorCode PetscDrawUtilitySetCmap(const char colormap[],int mapsize,unsigned char R[],unsigned char G[],unsigned char B[]) 171 { 172 int i,j; 173 const char *cmap_name_list[sizeof(PetscDrawCmapTable)/sizeof(PetscDrawCmapTable[0])]; 174 PetscInt id = 0, count = (PetscInt)(sizeof(cmap_name_list)/sizeof(char*)); 175 PetscBool reverse = PETSC_FALSE, brighten = PETSC_FALSE; 176 PetscReal beta = 0; 177 PetscErrorCode ierr; 178 179 PetscFunctionBegin; 180 for (i=0; i<count; i++) cmap_name_list[i] = PetscDrawCmapTable[i].name; 181 if (colormap && colormap[0]) { 182 PetscBool match = PETSC_FALSE; 183 for (id=0; !match && id<count; id++) {ierr = PetscStrcasecmp(colormap,cmap_name_list[id],&match);CHKERRQ(ierr);} 184 if (!match) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Colormap '%s' not found",colormap); 185 } 186 ierr = PetscOptionsGetEList(NULL,NULL,"-draw_cmap",cmap_name_list,count,&id,NULL);CHKERRQ(ierr); 187 ierr = PetscOptionsGetBool(NULL,NULL,"-draw_cmap_reverse",&reverse,NULL);CHKERRQ(ierr); 188 ierr = PetscOptionsGetReal(NULL,NULL,"-draw_cmap_brighten",&beta,&brighten);CHKERRQ(ierr); 189 if (brighten && (beta <= (PetscReal)-1 || beta >= (PetscReal)+1)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"brighten parameter %g must be in the range (-1,1)",(double)beta); 190 191 if (PetscDrawCmapTable[id].cmap) { 192 ierr = PetscDrawCmapTable[id].cmap(mapsize,R,G,B);CHKERRQ(ierr); 193 } else { 194 const unsigned char (*rgb)[3] = PetscDrawCmapTable[id].data; 195 if (mapsize != 256-PETSC_DRAW_BASIC_COLORS) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Colormap '%s' with size %d not supported",cmap_name_list[id],mapsize); 196 for (i=0; i<mapsize; i++) {R[i] = rgb[i][0]; G[i] = rgb[i][1]; B[i] = rgb[i][2];} 197 } 198 199 if (reverse) { 200 i = 0; j = mapsize-1; 201 while (i < j) { 202 #define SWAP(a,i,j) do { unsigned char t = a[i]; a[i] = a[j]; a[j] = t; } while (0) 203 SWAP(R,i,j); 204 SWAP(G,i,j); 205 SWAP(B,i,j); 206 #undef SWAP 207 i++; j--; 208 } 209 } 210 211 if (brighten) { 212 PetscReal gamma = (beta > 0.0) ? (1 - beta) : (1 / (1 + beta)); 213 for (i=0; i<mapsize; i++) { 214 PetscReal r = PetscPowReal((PetscReal)R[i]/255,gamma); 215 PetscReal g = PetscPowReal((PetscReal)G[i]/255,gamma); 216 PetscReal b = PetscPowReal((PetscReal)B[i]/255,gamma); 217 R[i] = (unsigned char)(255*PetscMin(r,(PetscReal)1.0)); 218 G[i] = (unsigned char)(255*PetscMin(g,(PetscReal)1.0)); 219 B[i] = (unsigned char)(255*PetscMin(b,(PetscReal)1.0)); 220 } 221 } 222 PetscFunctionReturn(0); 223 } 224