home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnuplapi.zip / gnuplot-api-os2 / build / color.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-06-15  |  14.2 KB  |  463 lines

  1. /* GNUPLOT - color.c */
  2.  
  3. /*[
  4.  *
  5.  * Petr Mikulik, December 1998 -- June 1999
  6.  * Copyright: open source as much as possible
  7.  *
  8.  * 
  9.  * What is here: #defines, global variables and declaration of routines for 
  10.  * colours---required by the pm3d splotting mode and coloured filled contours
  11.  *
  12. ]*/
  13.  
  14.  
  15. /*
  16.  *
  17.  * What is here:
  18.  *   - Global variables declared in .h are initialized here
  19.  *   - Palette routines
  20.  *   - Colour box drawing
  21.  *
  22.  */
  23.  
  24.  
  25. /** NOTICE: currently, this file is included only if PM3D is defined **/
  26. #ifdef PM3D
  27.  
  28. #include "plot.h"
  29. #include "pm3d.h"
  30.    /* need to access used_pm3d_zmin, used_pm3d_zmax; */
  31.  
  32.  
  33. /* COLOUR MODES - GLOBAL VARIABLES */
  34.  
  35. t_sm_palette sm_palette = {
  36.   33, /* colorFormulae---must be changed if changed GetColorValueFromFormula() */
  37.   SMPAL_COLOR_MODE_RGB, /* colorMode */
  38.   7, 5, 15, /* formulaR, formulaG, formulaB */
  39.   SMPAL_POSITIVE, /* positive */
  40.   0, 0, 0, /* use_maxcolors, colors, rgb_table */
  41.   0, /* offset */
  42.   0 /* ps_allcF */
  43.   };
  44.  
  45.  
  46. /* SMOOTH COLOUR BOX - GLOBAL VARIABLE */
  47.  
  48. color_box_struct color_box = {
  49.   SMCOLOR_BOX_DEFAULT,    /* draw at default_pos */
  50.   'v'    /* vertical change (gradient) of colours */
  51.   };
  52.  
  53.  
  54.  
  55. /********************************************************************
  56.   ROUTINES
  57. */
  58.  
  59. double GetColorValueFromFormula (int formula, double x)
  60. {
  61. /* the input gray x is supposed to be in interval [0,1] */
  62. if (formula < 0) { /* negate the value for negative formula */
  63.   x = 1 - x;
  64.   formula = -formula;
  65.   }
  66. switch (formula) {
  67.   case 0:  return 0;
  68.   case 1:  return 0.5;
  69.   case 2:  return 1;
  70.   case 3:  /* x = x */ break;
  71.   case 4:  x = x*x; break;
  72.   case 5:  x = x*x*x; break;
  73.   case 6:  x = x*x*x*x; break;
  74.   case 7:  x = sqrt(x); break;
  75.   case 8:  x = sqrt(sqrt(x)); break;
  76.   case 9:  x = sin(90*x *DEG2RAD); break;
  77.   case 10: x = cos(90*x *DEG2RAD); break;
  78.   case 11: x = fabs(x-0.5); break;
  79.   case 12: x = (2*x-1)*(2.0*x-1); break;
  80.   case 13: x = sin(180*x *DEG2RAD); break;
  81.   case 14: x = fabs(cos(180*x *DEG2RAD)); break;
  82.   case 15: x = sin(360*x *DEG2RAD); break;
  83.   case 16: x = cos(360*x *DEG2RAD); break;
  84.   case 17: x = fabs( sin(360*x *DEG2RAD) ); break;
  85.   case 18: x = fabs( cos(360*x *DEG2RAD) ); break;
  86.   case 19: x = fabs( sin(720*x *DEG2RAD) ); break;
  87.   case 20: x = fabs( cos(720*x *DEG2RAD) ); break;
  88.   case 21: x = 3*x; break;
  89.   case 22: x = 3*x-1; break;
  90.   case 23: x = 3*x-2; break;
  91.   case 24: x = fabs(3*x-1); break;
  92.   case 25: x = fabs(3*x-2); break;
  93.   case 26: x = (1.5*x-0.5); break;
  94.   case 27: x = (1.5*x-1); break;
  95.   case 28: x = fabs(1.5*x-0.5); break;
  96.   case 29: x = fabs(1.5*x-1); break;
  97.   case 30: if (x <= 0.25) return 0;
  98.        if (x >= 0.57) return 1;
  99.        x = x/0.32-0.78125; break;
  100.   case 31: if (x <= 0.42) return 0;
  101.        if (x >= 0.92) return 1;
  102.        x = 2*x-0.84; break;
  103.   case 32: if (x <= 0.42) x *= 4;
  104.          else x = (x <= 0.92) ? -2*x+1.84 : x/0.08-11.5;
  105.        break;
  106.   /*
  107.   Important: if any new formula is added here, then:
  108.     (1) its postscript counterpart must be added into term/post.trm,
  109.         search for "PostScriptColorFormulae[]"
  110.     (2) number of colours must be incremented in color.c: variable
  111.         sm_palette, first item---search for "t_sm_palette sm_palette = "
  112.   */
  113.   default: fprintf(stderr,"Fatal: undefined color formula (can be 0--%i)\n", sm_palette.colorFormulae-1);
  114.        exit(1);
  115.   }
  116. if (x <= 0) return 0;
  117. if (x >= 1) return 1;
  118. return x;
  119. }
  120.  
  121.  
  122. /*
  123.   Make the colour palette. Return 0 on success
  124.   Put number of allocated colours into sm_palette.colors
  125. */
  126. int make_palette ()
  127. {
  128. int i;
  129. double gray;
  130. #if 0
  131. GIF_show_current_palette();
  132. #endif
  133.  
  134. if (!term->make_palette) {
  135.   fprintf(stderr,"Error: your terminal does not support continous colors!\n");
  136.   return 1;
  137.   }
  138.  
  139. /* ask for suitable number of colours in the palette */
  140. i = term->make_palette(NULL);
  141.  
  142. if (i == 0) {
  143.   /* terminal with its own mapping (PostScript, for instance)
  144.      It will not change palette passed below, but non-NULL has to be
  145.      passed there to create the header or force its initialization
  146.   */
  147.   term->make_palette(&sm_palette);
  148.   return 0;
  149.   }
  150.  
  151. /* set the number of colours to be used (allocated) */
  152. sm_palette.colors = i;
  153. if (sm_palette.use_maxcolors>0 && i>sm_palette.use_maxcolors)
  154.   sm_palette.colors = sm_palette.use_maxcolors;
  155.   fprintf(stderr,"smooth palette in %s: available %i color positions; using %i of them\n",
  156.   term->name,i,sm_palette.colors);
  157.  
  158. #if TODOSOMEHOW_OTHERWISE_MEMORY_LEAKS
  159. if (sm_palette.color != NULL ) free( sm_palette.color );
  160.   /* is it sure that there is NULL in the beginning??!!
  161.      That should be released somewhen... after the whole plot
  162.      is there end_plot somewhere? Will there be several palettes
  163.      in the future, i.e. multiplots with various colour schemes?
  164.   */
  165. #endif
  166. sm_palette.color = malloc( sm_palette.colors * sizeof(rgb_color) );
  167.  
  168. for (i = 0; i < sm_palette.colors; i++) {
  169.   gray = (double)i / (sm_palette.colors - 1); /* rescale to [0;1] */
  170.   if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) /* gray scale only */
  171.      sm_palette.color[i].r = sm_palette.color[i].g = sm_palette.color[i].b = gray;
  172.   else { /* i.e. sm_palette.colorMode == SMPAL_COLOR_MODE_RGB */
  173.      sm_palette.color[i].r = GetColorValueFromFormula(sm_palette.formulaR, gray);
  174.      sm_palette.color[i].g = GetColorValueFromFormula(sm_palette.formulaG, gray);
  175.      sm_palette.color[i].b = GetColorValueFromFormula(sm_palette.formulaB, gray);
  176.     }
  177.   }
  178. /* let the terminal make the palette from the supplied RGB triplets */
  179. term->make_palette(&sm_palette);
  180.  
  181. #if 0
  182. GIF_show_current_palette();
  183. #endif
  184.  
  185. return 0;
  186. }
  187.  
  188.  
  189. /*
  190.    Set the colour on the terminal
  191.    Currently, each terminal takes care of remembering the current colour,
  192.    so there is not much to do here---well, except for reversing the gray
  193.    according to sm_palette.positive == SMPAL_POSITIVE or SMPAL_NEGATIVE
  194. */
  195. void set_color ( double gray )
  196. {
  197. if (sm_palette.positive == SMPAL_NEGATIVE)
  198.   gray = 1 - gray;
  199. term->set_color( gray );
  200. }
  201.  
  202.  
  203. /*
  204.    Makes mapping from real 3D coordinates to 2D terminal coordinates,
  205.    then draws filled polygon
  206. */
  207. void filled_polygon ( int points, gpdPoint *corners )
  208. {
  209. int i;
  210. gpiPoint *icorners;
  211. icorners = malloc(points * sizeof(gpiPoint));
  212. for (i = 0; i < points; i++)
  213.   map3d_xy(corners[i].x, corners[i].y, corners[i].z,
  214.     &icorners[i].x, &icorners[i].y);
  215. term->filled_polygon( points, icorners );
  216. free( icorners );
  217. }
  218.  
  219.  
  220. /*
  221.    The routine above for 4 points explicitly
  222. */
  223. void filled_quadrangle ( gpdPoint *corners )
  224. {
  225. int i;
  226. gpiPoint icorners[4];
  227. for (i = 0; i < 4; i++)
  228.   map3d_xy(corners[i].x, corners[i].y, corners[i].z,
  229.     &icorners[i].x, &icorners[i].y);
  230. term->filled_polygon( 4, icorners );
  231. }
  232.  
  233.  
  234. /*
  235.    Makes mapping from real 3D coordinates, passed as coords array,
  236.    to 2D terminal coordinates, then draws filled polygon
  237. */
  238. void filled_polygon_3dcoords ( int points, struct coordinate GPHUGE *coords )
  239. {
  240. int i;
  241. gpiPoint *icorners;
  242. icorners = malloc(points * sizeof(gpiPoint));
  243. for (i = 0; i < points; i++)
  244.   map3d_xy(coords[i].x, coords[i].y, coords[i].z,
  245.     &icorners[i].x, &icorners[i].y);
  246. term->filled_polygon( points, icorners );
  247. free( icorners );
  248. }
  249.  
  250.  
  251. /*
  252.    Makes mapping from real 3D coordinates, passed as coords array, but at z coordinate
  253.    fixed (base_z, for instance) to 2D terminal coordinates, then draws filled polygon
  254. */
  255. void filled_polygon_3dcoords_zfixed ( int points, struct coordinate GPHUGE *coords, double z )
  256. {
  257. int i;
  258. gpiPoint *icorners;
  259. icorners = malloc(points * sizeof(gpiPoint));
  260. for (i = 0; i < points; i++)
  261.   map3d_xy(coords[i].x, coords[i].y, z,
  262.     &icorners[i].x, &icorners[i].y);
  263. term->filled_polygon( points, icorners );
  264. free( icorners );
  265. }
  266.  
  267.  
  268. /*
  269.   Draw colour smooth box
  270.  
  271. Firstly two helper routines for plotting inside of the box + the border
  272. for postscript and for other terminals, finally the main routine
  273. */
  274.  
  275.  
  276. /* plot the colour smooth box for from terminal's integer coordinates
  277.    [x_from,y_from] to [x_to,y_to].
  278.    This routine is for postscript files --- actually, it writes a small
  279.    PS routine
  280. */
  281. void draw_inside_color_smooth_box_postscript
  282.  ( int x_from, int y_from, int x_to, int y_to )
  283. {
  284. extern FILE *gpoutfile;
  285. int scale_x = (x_to-x_from), scale_y = (y_to-y_from);
  286. fprintf(gpoutfile,"gsave /imax 1024 def\t%% draw gray scale smooth box\n");
  287.   /* nb. of discrete steps (counted in the loop) */
  288. fprintf(gpoutfile,"%i %i translate %i %i scale 0 setlinewidth\n",
  289.   x_from, y_from, scale_x, scale_y);
  290.   /* define left bottom corner and scale of the box so that all coordinates
  291.      of the box are from [0,0] up to [1,1]. Further, this normalization
  292.      makes it possible to pass y from [0,1] as parameter to setgray */
  293. fprintf(gpoutfile,"/ystep 1 imax div def /y0 0 def /ii 0 def\n");
  294.   /* local variables; y-step, current y position and counter ii;  */
  295. if (sm_palette.positive == SMPAL_NEGATIVE) /* inverted gray for negative figure */
  296.        fprintf(gpoutfile,"{ 1 y0 sub g ");
  297.   else fprintf(gpoutfile,"{ y0 g ");
  298. if (color_box.rotation == 'v')
  299.     fprintf(gpoutfile,"0 y0 N 1 0 V 0 ystep V -1 0 f\n");
  300.   else
  301.     fprintf(gpoutfile,"y0 0 N 0 1 V ystep 0 V 0 -1 f\n");
  302. fprintf(gpoutfile,"/y0 y0 ystep add def /ii ii 1 add def\n");
  303. fprintf(gpoutfile,"ii imax gt {exit} if } loop\n");
  304. /* now black boundary around the box */
  305. fprintf(gpoutfile,"0 setgray gnulinewidth %i div 2 mul setlinewidth 0 0 M 1 0 L 0 1 M 1 1 L stroke\n",scale_y);
  306. fprintf(gpoutfile,"\tgnulinewidth %i div 2 mul setlinewidth 0 0 M 0 1 L 1 0 M 1 1 L stroke\n",scale_x);
  307.   /* that strange  2 mul  is there because grid is twice thicker, see /BL */
  308. fprintf(gpoutfile,"grestore 0 setgray\n");
  309. } /* end of optimized PS output */
  310.  
  311.  
  312.  
  313. /* plot the colour smooth box for from terminal's integer coordinates
  314.    [x_from,y_from] to [x_to,y_to].
  315.    This routine is for non-postscript files, as it does explicitly the loop
  316.    over all thin rectangles
  317. */
  318. void draw_inside_color_smooth_box_bitmap
  319.  ( int x_from, int y_from, int x_to, int y_to )
  320. {
  321. int steps = 128; /* I think that nobody can distinguish more colours from the palette */
  322. int i, xy, xy2, xy_from, xy_to;
  323. double xy_step, gray;
  324. gpiPoint corners[4];
  325. if (color_box.rotation == 'v') {
  326.     corners[0].x = corners[3].x = x_from;
  327.     corners[1].x = corners[2].x = x_to;
  328.     xy_from = y_from;
  329.     xy_to = y_to;
  330.     }
  331.   else {
  332.     corners[0].y = corners[1].y = y_from;
  333.     corners[2].y = corners[3].y = y_to;
  334.     xy_from = x_from;
  335.     xy_to = x_to;
  336.     }
  337. xy_step = ( color_box.rotation == 'h' ? x_to - x_from : y_to - y_from ) / (double)steps;
  338.  
  339. for (i = 0; i < steps; i++) {
  340.   gray = (double)i / (steps-1); /* colours equidistantly from [0,1] */
  341.   set_color( gray ); /* set the colour */
  342.   xy  = xy_from + (int)(xy_step * i);
  343.   xy2 = xy_from + (int)(xy_step * (i+1));
  344.   if (color_box.rotation == 'v') {
  345.       corners[0].y = corners[1].y = xy;
  346.       corners[2].y = corners[3].y = (i==steps-1) ? xy_to : xy2;
  347.       }
  348.     else {
  349.       corners[0].x = corners[3].x = xy;
  350.       corners[1].x = corners[2].x = (i==steps-1) ? xy_to : xy2;
  351.       }
  352.   /* print the rectangle with the given colour */
  353.   term->filled_polygon( 4, corners );
  354.   }
  355.  
  356. /* now make boundary around the colour box */
  357. { /* black solid colour should be chosen, so it's border linetype */
  358.   extern struct lp_style_type border_lp;
  359.   term_apply_lp_properties(&border_lp);
  360. }
  361. (term->move) (x_from,y_from);
  362. (term->vector) (x_to,y_from);
  363. (term->vector) (x_to,y_to);
  364. (term->vector) (x_from,y_to);
  365. (term->vector) (x_from,y_from);
  366. }
  367.  
  368.  
  369. /*
  370.   Finally the main colour smooth box drawing routine
  371. */
  372. void draw_color_smooth_box ()
  373. {
  374. int x_from, x_to, y_from, y_to;
  375. double tmp;
  376. char s[64];
  377. extern double base_z, ceiling_z;
  378. extern char zformat[];
  379. extern double log_base_array[];
  380.  
  381. if (color_box.where == SMCOLOR_BOX_NO) return;
  382.  
  383. /*
  384. firstly, choose some good position of the color box
  385.  
  386. user's position like that (?):
  387.   else {
  388.     x_from = color_box.xlow;
  389.     x_to   = color_box.xhigh;
  390.     }
  391. */
  392. if (color_box.where == SMCOLOR_BOX_USER) {
  393.     fprintf(stderr,"color box can be NO or DEFAULT. Programmer wanted!\n");
  394.     return;
  395.     /* LATER (when it works for COORDVAL)
  396.     x_from = color_box.xlow; x_to = color_box.xhigh  or xlow+xsize;
  397.     y_from = color_box.ylow; y_to = color_box.yhigh  OR yhigh+ysize;
  398.     */
  399.     }
  400.   else { /* color_box.where == SMCOLOR_BOX_DEFAULT */
  401.     double dx = ( max_array[FIRST_X_AXIS] - min_array[FIRST_X_AXIS] );
  402.     double dz = ( used_pm3d_zmax - used_pm3d_zmin );
  403.     map3d_xy(max_array[FIRST_X_AXIS]+dx*0.05,max_array[FIRST_Y_AXIS],base_z+dz*0.35, &x_from,&y_from);
  404.     map3d_xy(max_array[FIRST_X_AXIS]+dx*0.20,max_array[FIRST_Y_AXIS],ceiling_z-dz*0.0, &x_to,&y_to);
  405.     if (y_from == y_to || x_from == x_to) { /* map, i.e. plot with "set view 0,0 or 180,0" */
  406.     dz = max_array[FIRST_Y_AXIS] - min_array[FIRST_Y_AXIS];
  407.     map3d_xy(max_array[FIRST_X_AXIS]+dx*0.04,min_array[FIRST_Y_AXIS]+dz*0.25,base_z, &x_from,&y_from);
  408.     map3d_xy(max_array[FIRST_X_AXIS]+dx*0.18,max_array[FIRST_Y_AXIS]-dz*0.25,ceiling_z, &x_to,&y_to);
  409.     }
  410.     }
  411.  
  412. if (y_from > y_to) { /* switch them */
  413.   tmp = y_to;
  414.   y_to = y_from;
  415.   y_from = tmp;
  416.   }
  417.  
  418. /* optimized version of the smooth colour box in postscript. Advantage:
  419.    only few lines of code is written into the output file.
  420. */
  421. if (!strcmp(term->name,"postscript") || !strcmp(term->name,"pstex"))
  422.     draw_inside_color_smooth_box_postscript( x_from, y_from, x_to, y_to );
  423.   else
  424.     draw_inside_color_smooth_box_bitmap ( x_from, y_from, x_to, y_to );
  425.  
  426. /* and finally place text of min z and max z below and above wrt
  427.    colour box, respectively
  428. */
  429. if (term->justify_text) term->justify_text(LEFT);
  430.  
  431. tmp = 0.75; /* rel. distance between bottom label and the bottom edge of
  432.            the box (in term->v_char units) */
  433. #if 0
  434. sprintf(s,"%g",used_pm3d_zmin);
  435. #else /* format the label using `set format z` */
  436. gprintf(s, sizeof(s), zformat, log_base_array[FIRST_Z_AXIS], used_pm3d_zmin);
  437. if (strchr(s,'^') != NULL) /* adjust it = sth like JUSTIFY_TOP */
  438.   tmp = 1.15; /* the string contains upper index, so shift the string down */
  439. #endif
  440. (term->put_text) (x_from,y_from - term->v_char * tmp,s);
  441.  
  442. tmp = 0.6; /* rel. distance between lower label and the lower edge of the box */
  443. #if 0
  444. sprintf(s,"%g",used_pm3d_zmax);
  445. #else
  446. gprintf(s, sizeof(s), zformat, log_base_array[FIRST_Z_AXIS], used_pm3d_zmax);
  447. if (strchr(s,'_') != NULL) /* adjust it = sth like JUSTIFY_BOTTOM */
  448.   tmp = 1.0; /* the string contains lower index, so shift the string up */
  449. #endif
  450. if (color_box.rotation == 'v')
  451.     (term->put_text) (x_from,y_to + term->v_char * tmp,s);
  452.   else {
  453.     if (term->justify_text) term->justify_text(RIGHT);
  454.     (term->put_text) (x_to,y_to + term->v_char * tmp,s);
  455.     }
  456.  
  457. }
  458.  
  459.  
  460. #endif /* PM3D */
  461.  
  462. /* eof color.c */
  463.