Actual source code: cmap.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      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: {
     19:   Gamma = g;
     20:   return(0);
     21: }

     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: }

     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: }

     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: }

     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;

     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:   return(0);
     70: }

     72: static PetscErrorCode PetscDrawCmap_Gray(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[])
     73: {
     74:   int i;
     76:   for (i=0; i<mapsize; i++) R[i] = G[i] = B[i] = (unsigned char)((255.0*i)/(mapsize-1));
     77:   return(0);
     78: }

     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};

     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:   return(0);
    103: }

    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};

    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:   return(0);
    126: }

    128: static PetscErrorCode PetscDrawCmap_Bone(int mapsize,unsigned char R[],unsigned char G[],unsigned char B[])
    129: {
    130:   int i;
    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:   return(0);
    143: }

    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"

    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: };

    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;

    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++) {PetscStrcasecmp(colormap,cmap_name_list[id],&match);}
    184:     if (!match) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Colormap '%s' not found",colormap);
    185:   }
    186:   PetscOptionsGetEList(NULL,NULL,"-draw_cmap",cmap_name_list,count,&id,NULL);
    187:   PetscOptionsGetBool(NULL,NULL,"-draw_cmap_reverse",&reverse,NULL);
    188:   PetscOptionsGetReal(NULL,NULL,"-draw_cmap_brighten",&beta,&brighten);
    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);

    191:   if (PetscDrawCmapTable[id].cmap) {
    192:     PetscDrawCmapTable[id].cmap(mapsize,R,G,B);
    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:   }

    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:   }

    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:   return(0);
    223: }