home *** CD-ROM | disk | FTP | other *** search
- /* GNUPLOT - color.c */
-
- /*[
- *
- * Petr Mikulik, December 1998 -- June 1999
- * Copyright: open source as much as possible
- *
- *
- * What is here: #defines, global variables and declaration of routines for
- * colours---required by the pm3d splotting mode and coloured filled contours
- *
- ]*/
-
-
- /*
- *
- * What is here:
- * - Global variables declared in .h are initialized here
- * - Palette routines
- * - Colour box drawing
- *
- */
-
-
- /** NOTICE: currently, this file is included only if PM3D is defined **/
- #ifdef PM3D
-
- #include "plot.h"
- #include "pm3d.h"
- /* need to access used_pm3d_zmin, used_pm3d_zmax; */
-
-
- /* COLOUR MODES - GLOBAL VARIABLES */
-
- t_sm_palette sm_palette = {
- 33, /* colorFormulae---must be changed if changed GetColorValueFromFormula() */
- SMPAL_COLOR_MODE_RGB, /* colorMode */
- 7, 5, 15, /* formulaR, formulaG, formulaB */
- SMPAL_POSITIVE, /* positive */
- 0, 0, 0, /* use_maxcolors, colors, rgb_table */
- 0, /* offset */
- 0 /* ps_allcF */
- };
-
-
- /* SMOOTH COLOUR BOX - GLOBAL VARIABLE */
-
- color_box_struct color_box = {
- SMCOLOR_BOX_DEFAULT, /* draw at default_pos */
- 'v' /* vertical change (gradient) of colours */
- };
-
-
-
- /********************************************************************
- ROUTINES
- */
-
- double GetColorValueFromFormula (int formula, double x)
- {
- /* the input gray x is supposed to be in interval [0,1] */
- if (formula < 0) { /* negate the value for negative formula */
- x = 1 - x;
- formula = -formula;
- }
- switch (formula) {
- case 0: return 0;
- case 1: return 0.5;
- case 2: return 1;
- case 3: /* x = x */ break;
- case 4: x = x*x; break;
- case 5: x = x*x*x; break;
- case 6: x = x*x*x*x; break;
- case 7: x = sqrt(x); break;
- case 8: x = sqrt(sqrt(x)); break;
- case 9: x = sin(90*x *DEG2RAD); break;
- case 10: x = cos(90*x *DEG2RAD); break;
- case 11: x = fabs(x-0.5); break;
- case 12: x = (2*x-1)*(2.0*x-1); break;
- case 13: x = sin(180*x *DEG2RAD); break;
- case 14: x = fabs(cos(180*x *DEG2RAD)); break;
- case 15: x = sin(360*x *DEG2RAD); break;
- case 16: x = cos(360*x *DEG2RAD); break;
- case 17: x = fabs( sin(360*x *DEG2RAD) ); break;
- case 18: x = fabs( cos(360*x *DEG2RAD) ); break;
- case 19: x = fabs( sin(720*x *DEG2RAD) ); break;
- case 20: x = fabs( cos(720*x *DEG2RAD) ); break;
- case 21: x = 3*x; break;
- case 22: x = 3*x-1; break;
- case 23: x = 3*x-2; break;
- case 24: x = fabs(3*x-1); break;
- case 25: x = fabs(3*x-2); break;
- case 26: x = (1.5*x-0.5); break;
- case 27: x = (1.5*x-1); break;
- case 28: x = fabs(1.5*x-0.5); break;
- case 29: x = fabs(1.5*x-1); break;
- case 30: if (x <= 0.25) return 0;
- if (x >= 0.57) return 1;
- x = x/0.32-0.78125; break;
- case 31: if (x <= 0.42) return 0;
- if (x >= 0.92) return 1;
- x = 2*x-0.84; break;
- case 32: if (x <= 0.42) x *= 4;
- else x = (x <= 0.92) ? -2*x+1.84 : x/0.08-11.5;
- break;
- /*
- Important: if any new formula is added here, then:
- (1) its postscript counterpart must be added into term/post.trm,
- search for "PostScriptColorFormulae[]"
- (2) number of colours must be incremented in color.c: variable
- sm_palette, first item---search for "t_sm_palette sm_palette = "
- */
- default: fprintf(stderr,"Fatal: undefined color formula (can be 0--%i)\n", sm_palette.colorFormulae-1);
- exit(1);
- }
- if (x <= 0) return 0;
- if (x >= 1) return 1;
- return x;
- }
-
-
- /*
- Make the colour palette. Return 0 on success
- Put number of allocated colours into sm_palette.colors
- */
- int make_palette ()
- {
- int i;
- double gray;
- #if 0
- GIF_show_current_palette();
- #endif
-
- if (!term->make_palette) {
- fprintf(stderr,"Error: your terminal does not support continous colors!\n");
- return 1;
- }
-
- /* ask for suitable number of colours in the palette */
- i = term->make_palette(NULL);
-
- if (i == 0) {
- /* terminal with its own mapping (PostScript, for instance)
- It will not change palette passed below, but non-NULL has to be
- passed there to create the header or force its initialization
- */
- term->make_palette(&sm_palette);
- return 0;
- }
-
- /* set the number of colours to be used (allocated) */
- sm_palette.colors = i;
- if (sm_palette.use_maxcolors>0 && i>sm_palette.use_maxcolors)
- sm_palette.colors = sm_palette.use_maxcolors;
- fprintf(stderr,"smooth palette in %s: available %i color positions; using %i of them\n",
- term->name,i,sm_palette.colors);
-
- #if TODOSOMEHOW_OTHERWISE_MEMORY_LEAKS
- if (sm_palette.color != NULL ) free( sm_palette.color );
- /* is it sure that there is NULL in the beginning??!!
- That should be released somewhen... after the whole plot
- is there end_plot somewhere? Will there be several palettes
- in the future, i.e. multiplots with various colour schemes?
- */
- #endif
- sm_palette.color = malloc( sm_palette.colors * sizeof(rgb_color) );
-
- for (i = 0; i < sm_palette.colors; i++) {
- gray = (double)i / (sm_palette.colors - 1); /* rescale to [0;1] */
- if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) /* gray scale only */
- sm_palette.color[i].r = sm_palette.color[i].g = sm_palette.color[i].b = gray;
- else { /* i.e. sm_palette.colorMode == SMPAL_COLOR_MODE_RGB */
- sm_palette.color[i].r = GetColorValueFromFormula(sm_palette.formulaR, gray);
- sm_palette.color[i].g = GetColorValueFromFormula(sm_palette.formulaG, gray);
- sm_palette.color[i].b = GetColorValueFromFormula(sm_palette.formulaB, gray);
- }
- }
- /* let the terminal make the palette from the supplied RGB triplets */
- term->make_palette(&sm_palette);
-
- #if 0
- GIF_show_current_palette();
- #endif
-
- return 0;
- }
-
-
- /*
- Set the colour on the terminal
- Currently, each terminal takes care of remembering the current colour,
- so there is not much to do here---well, except for reversing the gray
- according to sm_palette.positive == SMPAL_POSITIVE or SMPAL_NEGATIVE
- */
- void set_color ( double gray )
- {
- if (sm_palette.positive == SMPAL_NEGATIVE)
- gray = 1 - gray;
- term->set_color( gray );
- }
-
-
- /*
- Makes mapping from real 3D coordinates to 2D terminal coordinates,
- then draws filled polygon
- */
- void filled_polygon ( int points, gpdPoint *corners )
- {
- int i;
- gpiPoint *icorners;
- icorners = malloc(points * sizeof(gpiPoint));
- for (i = 0; i < points; i++)
- map3d_xy(corners[i].x, corners[i].y, corners[i].z,
- &icorners[i].x, &icorners[i].y);
- term->filled_polygon( points, icorners );
- free( icorners );
- }
-
-
- /*
- The routine above for 4 points explicitly
- */
- void filled_quadrangle ( gpdPoint *corners )
- {
- int i;
- gpiPoint icorners[4];
- for (i = 0; i < 4; i++)
- map3d_xy(corners[i].x, corners[i].y, corners[i].z,
- &icorners[i].x, &icorners[i].y);
- term->filled_polygon( 4, icorners );
- }
-
-
- /*
- Makes mapping from real 3D coordinates, passed as coords array,
- to 2D terminal coordinates, then draws filled polygon
- */
- void filled_polygon_3dcoords ( int points, struct coordinate GPHUGE *coords )
- {
- int i;
- gpiPoint *icorners;
- icorners = malloc(points * sizeof(gpiPoint));
- for (i = 0; i < points; i++)
- map3d_xy(coords[i].x, coords[i].y, coords[i].z,
- &icorners[i].x, &icorners[i].y);
- term->filled_polygon( points, icorners );
- free( icorners );
- }
-
-
- /*
- Makes mapping from real 3D coordinates, passed as coords array, but at z coordinate
- fixed (base_z, for instance) to 2D terminal coordinates, then draws filled polygon
- */
- void filled_polygon_3dcoords_zfixed ( int points, struct coordinate GPHUGE *coords, double z )
- {
- int i;
- gpiPoint *icorners;
- icorners = malloc(points * sizeof(gpiPoint));
- for (i = 0; i < points; i++)
- map3d_xy(coords[i].x, coords[i].y, z,
- &icorners[i].x, &icorners[i].y);
- term->filled_polygon( points, icorners );
- free( icorners );
- }
-
-
- /*
- Draw colour smooth box
-
- Firstly two helper routines for plotting inside of the box + the border
- for postscript and for other terminals, finally the main routine
- */
-
-
- /* plot the colour smooth box for from terminal's integer coordinates
- [x_from,y_from] to [x_to,y_to].
- This routine is for postscript files --- actually, it writes a small
- PS routine
- */
- void draw_inside_color_smooth_box_postscript
- ( int x_from, int y_from, int x_to, int y_to )
- {
- extern FILE *gpoutfile;
- int scale_x = (x_to-x_from), scale_y = (y_to-y_from);
- fprintf(gpoutfile,"gsave /imax 1024 def\t%% draw gray scale smooth box\n");
- /* nb. of discrete steps (counted in the loop) */
- fprintf(gpoutfile,"%i %i translate %i %i scale 0 setlinewidth\n",
- x_from, y_from, scale_x, scale_y);
- /* define left bottom corner and scale of the box so that all coordinates
- of the box are from [0,0] up to [1,1]. Further, this normalization
- makes it possible to pass y from [0,1] as parameter to setgray */
- fprintf(gpoutfile,"/ystep 1 imax div def /y0 0 def /ii 0 def\n");
- /* local variables; y-step, current y position and counter ii; */
- if (sm_palette.positive == SMPAL_NEGATIVE) /* inverted gray for negative figure */
- fprintf(gpoutfile,"{ 1 y0 sub g ");
- else fprintf(gpoutfile,"{ y0 g ");
- if (color_box.rotation == 'v')
- fprintf(gpoutfile,"0 y0 N 1 0 V 0 ystep V -1 0 f\n");
- else
- fprintf(gpoutfile,"y0 0 N 0 1 V ystep 0 V 0 -1 f\n");
- fprintf(gpoutfile,"/y0 y0 ystep add def /ii ii 1 add def\n");
- fprintf(gpoutfile,"ii imax gt {exit} if } loop\n");
- /* now black boundary around the box */
- 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);
- fprintf(gpoutfile,"\tgnulinewidth %i div 2 mul setlinewidth 0 0 M 0 1 L 1 0 M 1 1 L stroke\n",scale_x);
- /* that strange 2 mul is there because grid is twice thicker, see /BL */
- fprintf(gpoutfile,"grestore 0 setgray\n");
- } /* end of optimized PS output */
-
-
-
- /* plot the colour smooth box for from terminal's integer coordinates
- [x_from,y_from] to [x_to,y_to].
- This routine is for non-postscript files, as it does explicitly the loop
- over all thin rectangles
- */
- void draw_inside_color_smooth_box_bitmap
- ( int x_from, int y_from, int x_to, int y_to )
- {
- int steps = 128; /* I think that nobody can distinguish more colours from the palette */
- int i, xy, xy2, xy_from, xy_to;
- double xy_step, gray;
- gpiPoint corners[4];
- if (color_box.rotation == 'v') {
- corners[0].x = corners[3].x = x_from;
- corners[1].x = corners[2].x = x_to;
- xy_from = y_from;
- xy_to = y_to;
- }
- else {
- corners[0].y = corners[1].y = y_from;
- corners[2].y = corners[3].y = y_to;
- xy_from = x_from;
- xy_to = x_to;
- }
- xy_step = ( color_box.rotation == 'h' ? x_to - x_from : y_to - y_from ) / (double)steps;
-
- for (i = 0; i < steps; i++) {
- gray = (double)i / (steps-1); /* colours equidistantly from [0,1] */
- set_color( gray ); /* set the colour */
- xy = xy_from + (int)(xy_step * i);
- xy2 = xy_from + (int)(xy_step * (i+1));
- if (color_box.rotation == 'v') {
- corners[0].y = corners[1].y = xy;
- corners[2].y = corners[3].y = (i==steps-1) ? xy_to : xy2;
- }
- else {
- corners[0].x = corners[3].x = xy;
- corners[1].x = corners[2].x = (i==steps-1) ? xy_to : xy2;
- }
- /* print the rectangle with the given colour */
- term->filled_polygon( 4, corners );
- }
-
- /* now make boundary around the colour box */
- { /* black solid colour should be chosen, so it's border linetype */
- extern struct lp_style_type border_lp;
- term_apply_lp_properties(&border_lp);
- }
- (term->move) (x_from,y_from);
- (term->vector) (x_to,y_from);
- (term->vector) (x_to,y_to);
- (term->vector) (x_from,y_to);
- (term->vector) (x_from,y_from);
- }
-
-
- /*
- Finally the main colour smooth box drawing routine
- */
- void draw_color_smooth_box ()
- {
- int x_from, x_to, y_from, y_to;
- double tmp;
- char s[64];
- extern double base_z, ceiling_z;
- extern char zformat[];
- extern double log_base_array[];
-
- if (color_box.where == SMCOLOR_BOX_NO) return;
-
- /*
- firstly, choose some good position of the color box
-
- user's position like that (?):
- else {
- x_from = color_box.xlow;
- x_to = color_box.xhigh;
- }
- */
- if (color_box.where == SMCOLOR_BOX_USER) {
- fprintf(stderr,"color box can be NO or DEFAULT. Programmer wanted!\n");
- return;
- /* LATER (when it works for COORDVAL)
- x_from = color_box.xlow; x_to = color_box.xhigh or xlow+xsize;
- y_from = color_box.ylow; y_to = color_box.yhigh OR yhigh+ysize;
- */
- }
- else { /* color_box.where == SMCOLOR_BOX_DEFAULT */
- double dx = ( max_array[FIRST_X_AXIS] - min_array[FIRST_X_AXIS] );
- double dz = ( used_pm3d_zmax - used_pm3d_zmin );
- map3d_xy(max_array[FIRST_X_AXIS]+dx*0.05,max_array[FIRST_Y_AXIS],base_z+dz*0.35, &x_from,&y_from);
- map3d_xy(max_array[FIRST_X_AXIS]+dx*0.20,max_array[FIRST_Y_AXIS],ceiling_z-dz*0.0, &x_to,&y_to);
- if (y_from == y_to || x_from == x_to) { /* map, i.e. plot with "set view 0,0 or 180,0" */
- dz = max_array[FIRST_Y_AXIS] - min_array[FIRST_Y_AXIS];
- map3d_xy(max_array[FIRST_X_AXIS]+dx*0.04,min_array[FIRST_Y_AXIS]+dz*0.25,base_z, &x_from,&y_from);
- map3d_xy(max_array[FIRST_X_AXIS]+dx*0.18,max_array[FIRST_Y_AXIS]-dz*0.25,ceiling_z, &x_to,&y_to);
- }
- }
-
- if (y_from > y_to) { /* switch them */
- tmp = y_to;
- y_to = y_from;
- y_from = tmp;
- }
-
- /* optimized version of the smooth colour box in postscript. Advantage:
- only few lines of code is written into the output file.
- */
- if (!strcmp(term->name,"postscript") || !strcmp(term->name,"pstex"))
- draw_inside_color_smooth_box_postscript( x_from, y_from, x_to, y_to );
- else
- draw_inside_color_smooth_box_bitmap ( x_from, y_from, x_to, y_to );
-
- /* and finally place text of min z and max z below and above wrt
- colour box, respectively
- */
- if (term->justify_text) term->justify_text(LEFT);
-
- tmp = 0.75; /* rel. distance between bottom label and the bottom edge of
- the box (in term->v_char units) */
- #if 0
- sprintf(s,"%g",used_pm3d_zmin);
- #else /* format the label using `set format z` */
- gprintf(s, sizeof(s), zformat, log_base_array[FIRST_Z_AXIS], used_pm3d_zmin);
- if (strchr(s,'^') != NULL) /* adjust it = sth like JUSTIFY_TOP */
- tmp = 1.15; /* the string contains upper index, so shift the string down */
- #endif
- (term->put_text) (x_from,y_from - term->v_char * tmp,s);
-
- tmp = 0.6; /* rel. distance between lower label and the lower edge of the box */
- #if 0
- sprintf(s,"%g",used_pm3d_zmax);
- #else
- gprintf(s, sizeof(s), zformat, log_base_array[FIRST_Z_AXIS], used_pm3d_zmax);
- if (strchr(s,'_') != NULL) /* adjust it = sth like JUSTIFY_BOTTOM */
- tmp = 1.0; /* the string contains lower index, so shift the string up */
- #endif
- if (color_box.rotation == 'v')
- (term->put_text) (x_from,y_to + term->v_char * tmp,s);
- else {
- if (term->justify_text) term->justify_text(RIGHT);
- (term->put_text) (x_to,y_to + term->v_char * tmp,s);
- }
-
- }
-
-
- #endif /* PM3D */
-
- /* eof color.c */
-