Blame src/color.c

Packit 0986c0
/* GNUPLOT - color.c */
Packit 0986c0
Packit 0986c0
/*[
Packit 0986c0
 *
Packit 0986c0
 * Petr Mikulik, since December 1998
Packit 0986c0
 * Copyright: open source as much as possible
Packit 0986c0
 *
Packit 0986c0
 * What is here:
Packit 0986c0
 *   - Global variables declared in .h are initialized here
Packit 0986c0
 *   - Palette routines
Packit 0986c0
 *   - Colour box drawing
Packit 0986c0
 *
Packit 0986c0
]*/
Packit 0986c0
Packit 0986c0
Packit 0986c0
#ifdef HAVE_CONFIG_H
Packit 0986c0
#include "config.h"
Packit 0986c0
#endif
Packit 0986c0
Packit 0986c0
#include "color.h"
Packit 0986c0
#include "getcolor.h"
Packit 0986c0
Packit 0986c0
#include "axis.h"
Packit 0986c0
#include "gadgets.h"
Packit 0986c0
#include "graphics.h"
Packit 0986c0
#include "plot.h"
Packit 0986c0
#include "graph3d.h"
Packit 0986c0
#include "pm3d.h"
Packit 0986c0
#include "term_api.h"
Packit 0986c0
#include "util3d.h"
Packit 0986c0
#include "alloc.h"
Packit 0986c0
Packit 0986c0
/* COLOUR MODES - GLOBAL VARIABLES */
Packit 0986c0
Packit 0986c0
t_sm_palette sm_palette;  /* initialized in plot.c on program entry */
Packit 0986c0
Packit 0986c0
/* Copy of palette previously in use.
Packit 0986c0
 * Exported so that change_term() can invalidate contents
Packit 0986c0
 * FIXME: better naming 
Packit 0986c0
 */
Packit 0986c0
static t_sm_palette prev_palette = {
Packit 0986c0
	-1, -1, -1, -1, -1, -1, -1, -1,
Packit 0986c0
	(rgb_color *) 0, -1
Packit 0986c0
    };
Packit 0986c0
Packit 0986c0
/* Internal prototype declarations: */
Packit 0986c0
Packit 0986c0
static void draw_inside_color_smooth_box_postscript __PROTO((void));
Packit 0986c0
static void draw_inside_color_smooth_box_bitmap __PROTO((void));
Packit 0986c0
static void cbtick_callback __PROTO((struct axis *, double place, char *text, int ticlevel,
Packit 0986c0
			struct lp_style_type grid, struct ticmark *userlabels));
Packit 0986c0
Packit 0986c0
Packit 0986c0
Packit 0986c0
/* *******************************************************************
Packit 0986c0
  ROUTINES
Packit 0986c0
 */
Packit 0986c0
Packit 0986c0
Packit 0986c0
void
Packit 0986c0
init_color()
Packit 0986c0
{
Packit 0986c0
  /* initialize global palette */
Packit 0986c0
  sm_palette.colorFormulae = 37;  /* const */
Packit 0986c0
  sm_palette.formulaR = 7;
Packit 0986c0
  sm_palette.formulaG = 5;
Packit 0986c0
  sm_palette.formulaB = 15;
Packit 0986c0
  sm_palette.positive = SMPAL_POSITIVE;
Packit 0986c0
  sm_palette.use_maxcolors = 0;
Packit 0986c0
  sm_palette.colors = 0;
Packit 0986c0
  sm_palette.color = NULL;
Packit 0986c0
  sm_palette.ps_allcF = FALSE;
Packit 0986c0
  sm_palette.gradient_num = 0;
Packit 0986c0
  sm_palette.gradient = NULL;
Packit 0986c0
  sm_palette.cmodel = C_MODEL_RGB;
Packit 0986c0
  sm_palette.Afunc.at = sm_palette.Bfunc.at = sm_palette.Cfunc.at = NULL;
Packit 0986c0
  sm_palette.colorMode = SMPAL_COLOR_MODE_RGB;
Packit 0986c0
  sm_palette.gamma = 1.5;
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
   Make the colour palette. Return 0 on success
Packit 0986c0
   Put number of allocated colours into sm_palette.colors
Packit 0986c0
 */
Packit 0986c0
int
Packit 0986c0
make_palette()
Packit 0986c0
{
Packit 0986c0
    int i;
Packit 0986c0
    double gray;
Packit 0986c0
Packit 0986c0
    if (!term->make_palette) {
Packit 0986c0
	return 1;
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* ask for suitable number of colours in the palette */
Packit 0986c0
    i = term->make_palette(NULL);
Packit 0986c0
    sm_palette.colors = i;
Packit 0986c0
    if (i == 0) {
Packit 0986c0
	/* terminal with its own mapping (PostScript, for instance)
Packit 0986c0
	   It will not change palette passed below, but non-NULL has to be
Packit 0986c0
	   passed there to create the header or force its initialization
Packit 0986c0
	 */
Packit 0986c0
	if (memcmp(&prev_palette, &sm_palette, sizeof(t_sm_palette))) {
Packit 0986c0
	    term->make_palette(&sm_palette);
Packit 0986c0
	    prev_palette = sm_palette;
Packit 0986c0
	    FPRINTF((stderr,"make_palette: calling term->make_palette for term with ncolors == 0\n"));
Packit 0986c0
	} else {
Packit 0986c0
	    FPRINTF((stderr,"make_palette: skipping duplicate palette for term with ncolors == 0\n"));
Packit 0986c0
	}
Packit 0986c0
	return 0;
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* set the number of colours to be used (allocated) */
Packit 0986c0
    if (sm_palette.use_maxcolors > 0) {
Packit 0986c0
	if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRADIENT)
Packit 0986c0
	    sm_palette.colors = i;	/* EAM Sep 2010 - could this be a constant? */
Packit 0986c0
	else if (i > sm_palette.use_maxcolors)
Packit 0986c0
	    sm_palette.colors = sm_palette.use_maxcolors;
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    if (prev_palette.colorFormulae < 0
Packit 0986c0
	|| sm_palette.colorFormulae != prev_palette.colorFormulae
Packit 0986c0
	|| sm_palette.colorMode != prev_palette.colorMode
Packit 0986c0
	|| sm_palette.formulaR != prev_palette.formulaR
Packit 0986c0
	|| sm_palette.formulaG != prev_palette.formulaG
Packit 0986c0
	|| sm_palette.formulaB != prev_palette.formulaB
Packit 0986c0
	|| sm_palette.positive != prev_palette.positive
Packit 0986c0
	|| sm_palette.colors != prev_palette.colors) {
Packit 0986c0
	/* print the message only if colors have changed */
Packit 0986c0
	if (interactive)
Packit 0986c0
	    fprintf(stderr, "smooth palette in %s: using %i of %i available color positions\n",
Packit 0986c0
	    		term->name, sm_palette.colors, i);
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    prev_palette = sm_palette;
Packit 0986c0
Packit 0986c0
    if (sm_palette.color != NULL) {
Packit 0986c0
	free(sm_palette.color);
Packit 0986c0
	sm_palette.color = NULL;
Packit 0986c0
    }
Packit 0986c0
    sm_palette.color = gp_alloc( sm_palette.colors * sizeof(rgb_color),
Packit 0986c0
				 "pm3d palette color");
Packit 0986c0
Packit 0986c0
    /*  fill sm_palette.color[]  */
Packit 0986c0
    for (i = 0; i < sm_palette.colors; i++) {
Packit 0986c0
	gray = (double) i / (sm_palette.colors - 1);	/* rescale to [0;1] */
Packit 0986c0
	rgb1_from_gray( gray, &(sm_palette.color[i]) );
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* let the terminal make the palette from the supplied RGB triplets */
Packit 0986c0
    term->make_palette(&sm_palette);
Packit 0986c0
Packit 0986c0
    return 0;
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
 * Force a mismatch between the current palette and whatever is sent next,
Packit 0986c0
 * so that the new one will always be loaded 
Packit 0986c0
 */
Packit 0986c0
void
Packit 0986c0
invalidate_palette()
Packit 0986c0
{
Packit 0986c0
    prev_palette.colors = -1;
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
   Set the colour on the terminal
Packit 0986c0
   Each terminal takes care of remembering the current colour,
Packit 0986c0
   so there is not much to do here.
Packit 0986c0
   FIXME: NaN could alternatively map to LT_NODRAW or TC_RGB full transparency
Packit 0986c0
 */
Packit 0986c0
void
Packit 0986c0
set_color(double gray)
Packit 0986c0
{
Packit 0986c0
    t_colorspec color;
Packit 0986c0
    color.value = gray;
Packit 0986c0
    color.lt = LT_BACKGROUND;
Packit 0986c0
    color.type = (isnan(gray)) ? TC_LT : TC_FRAC;
Packit 0986c0
    term->set_color(&color;;
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
void
Packit 0986c0
set_rgbcolor_var(unsigned int rgbvalue)
Packit 0986c0
{
Packit 0986c0
    t_colorspec color;
Packit 0986c0
    color.type = TC_RGB;
Packit 0986c0
    *(unsigned int *)(&color.lt) = rgbvalue;
Packit 0986c0
    color.value = -1;	/* -1 flags that this came from "rgb variable" */
Packit 0986c0
    apply_pm3dcolor(&color;;
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
void
Packit 0986c0
set_rgbcolor_const(unsigned int rgbvalue)
Packit 0986c0
{
Packit 0986c0
    t_colorspec color;
Packit 0986c0
    color.type = TC_RGB;
Packit 0986c0
    *(unsigned int *)(&color.lt) = rgbvalue;
Packit 0986c0
    color.value = 0;	/* 0 flags that this is a constant color */
Packit 0986c0
    apply_pm3dcolor(&color;;
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
void
Packit 0986c0
ifilled_quadrangle(gpiPoint* icorners)
Packit 0986c0
{
Packit 0986c0
    if (default_fillstyle.fillstyle == FS_EMPTY)
Packit 0986c0
	icorners->style = FS_OPAQUE;
Packit 0986c0
    else
Packit 0986c0
	icorners->style = style_from_fill(&default_fillstyle);
Packit 0986c0
    term->filled_polygon(4, icorners);
Packit 0986c0
Packit 0986c0
    if (pm3d.border.l_type != LT_NODRAW) {
Packit 0986c0
	int i;
Packit 0986c0
Packit 0986c0
	/* LT_DEFAULT means draw border in current color */
Packit 0986c0
	/* FIXME: currently there is no obvious way to set LT_DEFAULT  */
Packit 0986c0
	if (pm3d.border.l_type != LT_DEFAULT) {
Packit 0986c0
	    /* It should be sufficient to set only the color, but for some */
Packit 0986c0
	    /* reason this causes the svg terminal to lose the fill type.  */
Packit 0986c0
	    term_apply_lp_properties(&pm3d_border_lp);
Packit 0986c0
	}
Packit 0986c0
Packit 0986c0
	term->move(icorners[0].x, icorners[0].y);
Packit 0986c0
	for (i = 3; i >= 0; i--) {
Packit 0986c0
	    term->vector(icorners[i].x, icorners[i].y);
Packit 0986c0
	}
Packit 0986c0
    }
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
Packit 0986c0
/* The routine above for 4 points explicitly.
Packit 0986c0
 * This is the only routine which supportes extended
Packit 0986c0
 * color specs currently.
Packit 0986c0
 */
Packit 0986c0
#ifdef EXTENDED_COLOR_SPECS
Packit 0986c0
void
Packit 0986c0
filled_quadrangle(gpdPoint * corners, gpiPoint * icorners)
Packit 0986c0
#else
Packit 0986c0
void
Packit 0986c0
filled_quadrangle(gpdPoint * corners)
Packit 0986c0
#endif
Packit 0986c0
{
Packit 0986c0
    int i;
Packit 0986c0
    double x, y;
Packit 0986c0
#ifndef EXTENDED_COLOR_SPECS
Packit 0986c0
    gpiPoint icorners[4];
Packit 0986c0
#endif
Packit 0986c0
    for (i = 0; i < 4; i++) {
Packit 0986c0
	map3d_xy_double(corners[i].x, corners[i].y, corners[i].z, &x, &y);
Packit 0986c0
	icorners[i].x = x;
Packit 0986c0
	icorners[i].y = y;
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    ifilled_quadrangle(icorners);
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
#ifdef PM3D_CONTOURS
Packit 0986c0
/*
Packit 0986c0
   Makes mapping from real 3D coordinates, passed as coords array,
Packit 0986c0
   to 2D terminal coordinates, then draws filled polygon
Packit 0986c0
 */
Packit 0986c0
void
Packit 0986c0
filled_polygon_common(int points, struct coordinate GPHUGE * coords, TBOOLEAN fixed, double z)
Packit 0986c0
{
Packit 0986c0
    int i;
Packit 0986c0
    double x, y;
Packit 0986c0
    gpiPoint *icorners;
Packit 0986c0
    icorners = gp_alloc(points * sizeof(gpiPoint), "filled_polygon3d corners");
Packit 0986c0
    for (i = 0; i < points; i++) {
Packit 0986c0
	if (fixed)
Packit 0986c0
	    z = coords[i].z;
Packit 0986c0
	map3d_xy_double(coords[i].x, coords[i].y, z, &x, &y);
Packit 0986c0
	icorners[i].x = x;
Packit 0986c0
	icorners[i].y = y;
Packit 0986c0
    }
Packit 0986c0
#ifdef EXTENDED_COLOR_SPECS
Packit 0986c0
    if ((term->flags & TERM_EXTENDED_COLOR)) {
Packit 0986c0
	icorners[0].spec.gray = -1;	/* force solid color */
Packit 0986c0
    }
Packit 0986c0
#endif
Packit 0986c0
    if (default_fillstyle.fillstyle == FS_EMPTY)
Packit 0986c0
	icorners->style = FS_OPAQUE;
Packit 0986c0
    else
Packit 0986c0
	icorners->style = style_from_fill(&default_fillstyle);
Packit 0986c0
    term->filled_polygon(points, icorners);
Packit 0986c0
    free(icorners);
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
void
Packit 0986c0
filled_polygon_3dcoords(int points, struct coordinate GPHUGE * coords)
Packit 0986c0
{
Packit 0986c0
    filled_polygon_common(points, coords, FALSE, 0.0);
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
   Makes mapping from real 3D coordinates, passed as coords array, but at z coordinate
Packit 0986c0
   fixed (base_z, for instance) to 2D terminal coordinates, then draws filled polygon
Packit 0986c0
 */
Packit 0986c0
void
Packit 0986c0
filled_polygon_3dcoords_zfixed(int points, struct coordinate GPHUGE * coords, double z)
Packit 0986c0
{
Packit 0986c0
    filled_polygon_common(points, coords, TRUE, z);
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
#endif /* PM3D_CONTOURS */
Packit 0986c0
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
   Draw colour smooth box
Packit 0986c0
Packit 0986c0
   Firstly two helper routines for plotting inside of the box
Packit 0986c0
   for postscript and for other terminals, finally the main routine
Packit 0986c0
 */
Packit 0986c0
Packit 0986c0
Packit 0986c0
/* plot the colour smooth box for from terminal's integer coordinates
Packit 0986c0
   This routine is for postscript files --- actually, it writes a small
Packit 0986c0
   PS routine.
Packit 0986c0
 */
Packit 0986c0
static void
Packit 0986c0
draw_inside_color_smooth_box_postscript()
Packit 0986c0
{
Packit 0986c0
    int scale_x = (color_box.bounds.xright - color_box.bounds.xleft), scale_y = (color_box.bounds.ytop - color_box.bounds.ybot);
Packit 0986c0
    fputs("stroke gsave\t%% draw gray scale smooth box\n"
Packit 0986c0
	  "maxcolors 0 gt {/imax maxcolors def} {/imax 1024 def} ifelse\n", gppsfile);
Packit 0986c0
Packit 0986c0
    /* nb. of discrete steps (counted in the loop) */
Packit 0986c0
    fprintf(gppsfile, "%i %i translate %i %i scale 0 setlinewidth\n", color_box.bounds.xleft, color_box.bounds.ybot, scale_x, scale_y);
Packit 0986c0
    /* define left bottom corner and scale of the box so that all coordinates
Packit 0986c0
       of the box are from [0,0] up to [1,1]. Further, this normalization
Packit 0986c0
       makes it possible to pass y from [0,1] as parameter to setgray */
Packit 0986c0
    fprintf(gppsfile, "/ystep 1 imax div def /y0 0 def /ii 0 def\n");
Packit 0986c0
    /* local variables; y-step, current y position and counter ii;  */
Packit 0986c0
    if (sm_palette.positive == SMPAL_NEGATIVE)	/* inverted gray for negative figure */
Packit 0986c0
	fputs("{ 0.99999 y0 sub g ", gppsfile); /* 1 > x > 1-1.0/1024 */
Packit 0986c0
    else
Packit 0986c0
	fputs("{ y0 g ", gppsfile);
Packit 0986c0
    if (color_box.rotation == 'v')
Packit 0986c0
	fputs("0 y0 N 1 0 V 0 ystep V -1 0 f\n", gppsfile);
Packit 0986c0
    else
Packit 0986c0
	fputs("y0 0 N 0 1 V ystep 0 V 0 -1 f\n", gppsfile);
Packit 0986c0
    fputs("/y0 y0 ystep add def /ii ii 1 add def\n"
Packit 0986c0
	  "ii imax ge {exit} if } loop\n"
Packit 0986c0
	  "grestore 0 setgray\n", gppsfile);
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
Packit 0986c0
Packit 0986c0
/* plot a colour smooth box bounded by the terminal's integer coordinates
Packit 0986c0
   [x_from,y_from] to [x_to,y_to].
Packit 0986c0
   This routine is for non-postscript files, as it does an explicit loop
Packit 0986c0
   over all thin rectangles
Packit 0986c0
 */
Packit 0986c0
static void
Packit 0986c0
draw_inside_color_smooth_box_bitmap()
Packit 0986c0
{
Packit 0986c0
    int steps = 128; /* I think that nobody can distinguish more colours drawn in the palette */
Packit 0986c0
    int i, j, xy, xy2, xy_from, xy_to;
Packit 0986c0
    int jmin = 0;
Packit 0986c0
    double xy_step, gray, range;
Packit 0986c0
    gpiPoint corners[4];
Packit 0986c0
Packit 0986c0
    if (color_box.rotation == 'v') {
Packit 0986c0
	corners[0].x = corners[3].x = color_box.bounds.xleft;
Packit 0986c0
	corners[1].x = corners[2].x = color_box.bounds.xright;
Packit 0986c0
	xy_from = color_box.bounds.ybot;
Packit 0986c0
	xy_to = color_box.bounds.ytop;
Packit 0986c0
	xy_step = (color_box.bounds.ytop - color_box.bounds.ybot) / (double)steps;
Packit 0986c0
    } else {
Packit 0986c0
	corners[0].y = corners[1].y = color_box.bounds.ybot;
Packit 0986c0
	corners[2].y = corners[3].y = color_box.bounds.ytop;
Packit 0986c0
	xy_from = color_box.bounds.xleft;
Packit 0986c0
	xy_to = color_box.bounds.xright;
Packit 0986c0
	xy_step = (color_box.bounds.xright - color_box.bounds.xleft) / (double)steps;
Packit 0986c0
    }
Packit 0986c0
    range = (xy_to - xy_from);
Packit 0986c0
Packit 0986c0
    for (i = 0, xy2 = xy_from; i < steps; i++) {
Packit 0986c0
Packit 0986c0
	/* Start from one pixel beyond the previous box */
Packit 0986c0
	xy = xy2;
Packit 0986c0
	xy2 = xy_from + (int) (xy_step * (i + 1));
Packit 0986c0
Packit 0986c0
	/* Set the colour for the next range increment */
Packit 0986c0
	/* FIXME - The "1 +" seems wrong, yet it improves the placement in gd */
Packit 0986c0
	gray = (double)(1 + xy - xy_from) / range;
Packit 0986c0
	if (sm_palette.positive == SMPAL_NEGATIVE)
Packit 0986c0
	    gray = 1 - gray;
Packit 0986c0
	set_color(gray);
Packit 0986c0
Packit 0986c0
	/* If this is a defined palette, make sure that the range increment */
Packit 0986c0
	/* does not straddle a palette segment boundary. If it does, split  */
Packit 0986c0
	/* it into two parts.                                               */
Packit 0986c0
	if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRADIENT)
Packit 0986c0
	    for (j=jmin; j
Packit 0986c0
		int boundary = xy_from + (int)(sm_palette.gradient[j].pos * range);
Packit 0986c0
		if (xy >= boundary) {
Packit 0986c0
		    jmin = j;
Packit 0986c0
		} else {
Packit 0986c0
		    if (xy2 > boundary) {
Packit 0986c0
			xy2 = boundary;
Packit 0986c0
			i--;
Packit 0986c0
			break;
Packit 0986c0
		    }
Packit 0986c0
		}
Packit 0986c0
		if (xy2 < boundary)
Packit 0986c0
		    break;
Packit 0986c0
	    }
Packit 0986c0
Packit 0986c0
	if (color_box.rotation == 'v') {
Packit 0986c0
	    corners[0].y = corners[1].y = xy;
Packit 0986c0
	    corners[2].y = corners[3].y = GPMIN(xy_to,xy2+1);
Packit 0986c0
	} else {
Packit 0986c0
	    corners[0].x = corners[3].x = xy;
Packit 0986c0
	    corners[1].x = corners[2].x = GPMIN(xy_to,xy2+1);
Packit 0986c0
	}
Packit 0986c0
#ifdef EXTENDED_COLOR_SPECS
Packit 0986c0
	if ((term->flags & TERM_EXTENDED_COLOR))
Packit 0986c0
	    corners[0].spec.gray = -1;	/* force solid color */
Packit 0986c0
#endif
Packit 0986c0
	/* print the rectangle with the given colour */
Packit 0986c0
	if (default_fillstyle.fillstyle == FS_EMPTY)
Packit 0986c0
	    corners->style = FS_OPAQUE;
Packit 0986c0
	else
Packit 0986c0
	    corners->style = style_from_fill(&default_fillstyle);
Packit 0986c0
	term->filled_polygon(4, corners);
Packit 0986c0
    }
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
static void
Packit 0986c0
cbtick_callback(
Packit 0986c0
    struct axis *this_axis,
Packit 0986c0
    double place,
Packit 0986c0
    char *text,
Packit 0986c0
    int ticlevel,
Packit 0986c0
    struct lp_style_type grid, /* linetype or -2 for no grid */
Packit 0986c0
    struct ticmark *userlabels)
Packit 0986c0
{
Packit 0986c0
    int len = tic_scale(ticlevel, this_axis)
Packit 0986c0
	* (this_axis->tic_in ? -1 : 1) * (term->h_tic);
Packit 0986c0
    unsigned int x1, y1, x2, y2;
Packit 0986c0
    double cb_place;
Packit 0986c0
Packit 0986c0
    /* position of tic as a fraction of the full palette range */
Packit 0986c0
#ifdef NONLINEAR_AXES
Packit 0986c0
    if (this_axis->linked_to_primary) {
Packit 0986c0
	AXIS * primary = this_axis->linked_to_primary;
Packit 0986c0
	place = eval_link_function(primary, place);
Packit 0986c0
	cb_place = (place - primary->min) / (primary->max - primary->min);
Packit 0986c0
    } else 
Packit 0986c0
#endif
Packit 0986c0
    cb_place = (place - this_axis->min) / (this_axis->max - this_axis->min);
Packit 0986c0
Packit 0986c0
    /* calculate tic position */
Packit 0986c0
    if (color_box.rotation == 'h') {
Packit 0986c0
	x1 = x2 = color_box.bounds.xleft + cb_place * (color_box.bounds.xright - color_box.bounds.xleft);
Packit 0986c0
	y1 = color_box.bounds.ybot;
Packit 0986c0
	y2 = color_box.bounds.ybot - len;
Packit 0986c0
    } else {
Packit 0986c0
	x1 = color_box.bounds.xright;
Packit 0986c0
	x2 = color_box.bounds.xright + len;
Packit 0986c0
	y1 = y2 = color_box.bounds.ybot + cb_place * (color_box.bounds.ytop - color_box.bounds.ybot);
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* draw grid line */
Packit 0986c0
    if (grid.l_type > LT_NODRAW) {
Packit 0986c0
	term_apply_lp_properties(&grid);	/* grid linetype */
Packit 0986c0
	if (color_box.rotation == 'h') {
Packit 0986c0
	    (*term->move) (x1, color_box.bounds.ybot);
Packit 0986c0
	    (*term->vector) (x1, color_box.bounds.ytop);
Packit 0986c0
	} else {
Packit 0986c0
	    (*term->move) (color_box.bounds.xleft, y1);
Packit 0986c0
	    (*term->vector) (color_box.bounds.xright, y1);
Packit 0986c0
	}
Packit 0986c0
	term_apply_lp_properties(&border_lp);	/* border linetype */
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* draw tic */
Packit 0986c0
    (*term->move) (x1, y1);
Packit 0986c0
    (*term->vector) (x2, y2);
Packit 0986c0
Packit 0986c0
    /* draw label */
Packit 0986c0
    if (text) {
Packit 0986c0
	int just;
Packit 0986c0
	int offsetx, offsety;
Packit 0986c0
Packit 0986c0
	/* Skip label if we've already written a user-specified one here */
Packit 0986c0
#	define MINIMUM_SEPARATION 0.001
Packit 0986c0
	while (userlabels) {
Packit 0986c0
	    if (fabs((place - userlabels->position) / (CB_AXIS.max - CB_AXIS.min))
Packit 0986c0
		<= MINIMUM_SEPARATION) {
Packit 0986c0
		text = NULL;
Packit 0986c0
		break;
Packit 0986c0
	    }
Packit 0986c0
	    userlabels = userlabels->next;
Packit 0986c0
	}
Packit 0986c0
#	undef MINIMUM_SEPARATION
Packit 0986c0
Packit 0986c0
	/* get offset */
Packit 0986c0
	map3d_position_r(&(this_axis->ticdef.offset),
Packit 0986c0
			 &offsetx, &offsety, "cbtics");
Packit 0986c0
	/* User-specified different color for the tics text */
Packit 0986c0
	if (this_axis->ticdef.textcolor.type != TC_DEFAULT)
Packit 0986c0
	    apply_pm3dcolor(&(this_axis->ticdef.textcolor));
Packit 0986c0
	if (color_box.rotation == 'h') {
Packit 0986c0
	    int y3 = color_box.bounds.ybot - (term->v_char);
Packit 0986c0
	    int hrotate = 0;
Packit 0986c0
Packit 0986c0
	    if (this_axis->tic_rotate
Packit 0986c0
		&& (*term->text_angle)(this_axis->tic_rotate))
Packit 0986c0
		    hrotate = this_axis->tic_rotate;
Packit 0986c0
	    if (len > 0) y3 -= len; /* add outer tics len */
Packit 0986c0
	    if (y3<0) y3 = 0;
Packit 0986c0
	    just = hrotate ? LEFT : CENTRE;
Packit 0986c0
	    if (this_axis->manual_justify)
Packit 0986c0
		just = this_axis->tic_pos;
Packit 0986c0
	    write_multiline(x2+offsetx, y3+offsety, text,
Packit 0986c0
			    just, JUST_CENTRE, hrotate,
Packit 0986c0
			    this_axis->ticdef.font);
Packit 0986c0
	    if (hrotate)
Packit 0986c0
		(*term->text_angle)(0);
Packit 0986c0
	} else {
Packit 0986c0
	    unsigned int x3 = color_box.bounds.xright + (term->h_char);
Packit 0986c0
	    if (len > 0) x3 += len; /* add outer tics len */
Packit 0986c0
	    just = LEFT;
Packit 0986c0
	    if (this_axis->manual_justify)
Packit 0986c0
		just = this_axis->tic_pos;	    
Packit 0986c0
	    write_multiline(x3+offsetx, y2+offsety, text,
Packit 0986c0
			    just, JUST_CENTRE, 0.0,
Packit 0986c0
			    this_axis->ticdef.font);
Packit 0986c0
	}
Packit 0986c0
	term_apply_lp_properties(&border_lp);	/* border linetype */
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* draw tic on the mirror side */
Packit 0986c0
    if (this_axis->ticmode & TICS_MIRROR) {
Packit 0986c0
	if (color_box.rotation == 'h') {
Packit 0986c0
	    y1 = color_box.bounds.ytop;
Packit 0986c0
	    y2 = color_box.bounds.ytop + len;
Packit 0986c0
	} else {
Packit 0986c0
	    x1 = color_box.bounds.xleft;
Packit 0986c0
	    x2 = color_box.bounds.xleft - len;
Packit 0986c0
	}
Packit 0986c0
	(*term->move) (x1, y1);
Packit 0986c0
	(*term->vector) (x2, y2);
Packit 0986c0
    }
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
   Finally the main colour smooth box drawing routine
Packit 0986c0
 */
Packit 0986c0
void
Packit 0986c0
draw_color_smooth_box(int plot_mode)
Packit 0986c0
{
Packit 0986c0
    if (color_box.where == SMCOLOR_BOX_NO)
Packit 0986c0
	return;
Packit 0986c0
    if (!term->filled_polygon)
Packit 0986c0
	return;
Packit 0986c0
Packit 0986c0
    /*
Packit 0986c0
       firstly, choose some good position of the color box
Packit 0986c0
Packit 0986c0
       user's position like that (?):
Packit 0986c0
       else {
Packit 0986c0
       x_from = color_box.xlow;
Packit 0986c0
       x_to   = color_box.xhigh;
Packit 0986c0
       }
Packit 0986c0
     */
Packit 0986c0
    if (color_box.where == SMCOLOR_BOX_USER) {
Packit 0986c0
	if (!is_3d_plot) {
Packit 0986c0
	    double xtemp, ytemp;
Packit 0986c0
	    map_position(&color_box.origin, &color_box.bounds.xleft, &color_box.bounds.ybot, "cbox");
Packit 0986c0
	    map_position_r(&color_box.size, &xtemp, &ytemp, "cbox");
Packit 0986c0
	    color_box.bounds.xright = xtemp;
Packit 0986c0
	    color_box.bounds.ytop = ytemp;
Packit 0986c0
	} else if (splot_map && is_3d_plot) {
Packit 0986c0
	    /* In map view mode we allow any coordinate system for placement */
Packit 0986c0
	    double xtemp, ytemp;
Packit 0986c0
	    map3d_position_double(&color_box.origin, &xtemp, &ytemp, "cbox");
Packit 0986c0
	    color_box.bounds.xleft = xtemp;
Packit 0986c0
	    color_box.bounds.ybot = ytemp;
Packit 0986c0
	    map3d_position_r(&color_box.size, &color_box.bounds.xright, &color_box.bounds.ytop, "cbox");
Packit 0986c0
	} else {
Packit 0986c0
	    /* But in full 3D mode we only allow screen coordinates */
Packit 0986c0
	    color_box.bounds.xleft = color_box.origin.x * (term->xmax) + 0.5;
Packit 0986c0
	    color_box.bounds.ybot = color_box.origin.y * (term->ymax) + 0.5;
Packit 0986c0
	    color_box.bounds.xright = color_box.size.x * (term->xmax-1) + 0.5;
Packit 0986c0
	    color_box.bounds.ytop = color_box.size.y * (term->ymax-1) + 0.5;
Packit 0986c0
	}
Packit 0986c0
	color_box.bounds.xright += color_box.bounds.xleft;
Packit 0986c0
	color_box.bounds.ytop += color_box.bounds.ybot;
Packit 0986c0
Packit 0986c0
    } else { /* color_box.where == SMCOLOR_BOX_DEFAULT */
Packit 0986c0
	if (plot_mode == MODE_SPLOT && !splot_map) {
Packit 0986c0
	    /* general 3D plot */
Packit 0986c0
	    color_box.bounds.xleft = xmiddle + 0.709 * xscaler;
Packit 0986c0
	    color_box.bounds.xright   = xmiddle + 0.778 * xscaler;
Packit 0986c0
	    color_box.bounds.ybot = ymiddle - 0.147 * yscaler;
Packit 0986c0
	    color_box.bounds.ytop   = ymiddle + 0.497 * yscaler;
Packit 0986c0
	} else {
Packit 0986c0
	    /* 2D plot (including splot map) */
Packit 0986c0
	    struct position default_origin = {graph,graph,graph, 1.025, 0, 0};
Packit 0986c0
	    struct position default_size = {graph,graph,graph, 0.05, 1.0, 0};
Packit 0986c0
	    double xtemp, ytemp;
Packit 0986c0
	    map_position(&default_origin, &color_box.bounds.xleft, &color_box.bounds.ybot, "cbox");
Packit 0986c0
	    color_box.bounds.xleft += color_box.xoffset;
Packit 0986c0
	    map_position_r(&default_size, &xtemp, &ytemp, "cbox");
Packit 0986c0
	    color_box.bounds.xright = xtemp + color_box.bounds.xleft;
Packit 0986c0
	    color_box.bounds.ytop = ytemp + color_box.bounds.ybot;
Packit 0986c0
	}
Packit 0986c0
Packit 0986c0
	/* now corrections for outer tics */
Packit 0986c0
	if (color_box.rotation == 'v') {
Packit 0986c0
	    int cblen = (CB_AXIS.tic_in ? -1 : 1) * CB_AXIS.ticscale * 
Packit 0986c0
		(term->h_tic); /* positive for outer tics */
Packit 0986c0
	    int ylen = (Y_AXIS.tic_in ? -1 : 1) * Y_AXIS.ticscale * 
Packit 0986c0
		(term->h_tic); /* positive for outer tics */
Packit 0986c0
	    if ((cblen > 0) && (CB_AXIS.ticmode & TICS_MIRROR)) {
Packit 0986c0
		color_box.bounds.xleft += cblen;
Packit 0986c0
		color_box.bounds.xright += cblen;
Packit 0986c0
	    }
Packit 0986c0
	    if ((ylen > 0) && 
Packit 0986c0
		(axis_array[FIRST_Y_AXIS].ticmode & TICS_MIRROR)) {
Packit 0986c0
		color_box.bounds.xleft += ylen;
Packit 0986c0
		color_box.bounds.xright += ylen;
Packit 0986c0
	    }
Packit 0986c0
	}
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    if (color_box.bounds.ybot > color_box.bounds.ytop) {
Packit 0986c0
	double tmp = color_box.bounds.ytop;
Packit 0986c0
	color_box.bounds.ytop = color_box.bounds.ybot;
Packit 0986c0
	color_box.bounds.ybot = tmp;
Packit 0986c0
    }
Packit 0986c0
    if (color_box.invert && color_box.rotation == 'v') {
Packit 0986c0
	double tmp = color_box.bounds.ytop;
Packit 0986c0
	color_box.bounds.ytop = color_box.bounds.ybot;
Packit 0986c0
	color_box.bounds.ybot = tmp;
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    term->layer(TERM_LAYER_BEGIN_COLORBOX);
Packit 0986c0
Packit 0986c0
    /* The PostScript terminal has an Optimized version */
Packit 0986c0
    if ((term->flags & TERM_IS_POSTSCRIPT) != 0)
Packit 0986c0
	draw_inside_color_smooth_box_postscript();
Packit 0986c0
    else
Packit 0986c0
	draw_inside_color_smooth_box_bitmap();
Packit 0986c0
Packit 0986c0
    term->layer(TERM_LAYER_END_COLORBOX);
Packit 0986c0
Packit 0986c0
    if (color_box.border) {
Packit 0986c0
	/* now make boundary around the colour box */
Packit 0986c0
	if (color_box.border_lt_tag >= 0) {
Packit 0986c0
	    /* user specified line type */
Packit 0986c0
	    struct lp_style_type lp = border_lp;
Packit 0986c0
	    lp_use_properties(&lp, color_box.border_lt_tag);
Packit 0986c0
	    term_apply_lp_properties(&lp);
Packit 0986c0
	} else {
Packit 0986c0
	    /* black solid colour should be chosen, so it's border linetype */
Packit 0986c0
	    term_apply_lp_properties(&border_lp);
Packit 0986c0
	}
Packit 0986c0
	newpath();
Packit 0986c0
	(term->move) (color_box.bounds.xleft, color_box.bounds.ybot);
Packit 0986c0
	(term->vector) (color_box.bounds.xright, color_box.bounds.ybot);
Packit 0986c0
	(term->vector) (color_box.bounds.xright, color_box.bounds.ytop);
Packit 0986c0
	(term->vector) (color_box.bounds.xleft, color_box.bounds.ytop);
Packit 0986c0
	(term->vector) (color_box.bounds.xleft, color_box.bounds.ybot);
Packit 0986c0
	closepath();
Packit 0986c0
Packit 0986c0
	/* Set line properties to some value, this also draws lines in postscript terminals. */
Packit 0986c0
	    term_apply_lp_properties(&border_lp);
Packit 0986c0
	}
Packit 0986c0
Packit 0986c0
    /* draw tics */
Packit 0986c0
    if (axis_array[COLOR_AXIS].ticmode) {
Packit 0986c0
	term_apply_lp_properties(&border_lp); /* border linetype */
Packit 0986c0
	gen_tics(&axis_array[COLOR_AXIS], cbtick_callback );
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
    /* write the colour box label */
Packit 0986c0
    if (CB_AXIS.label.text) {
Packit 0986c0
	int x, y;
Packit 0986c0
	int len;
Packit 0986c0
	int save_rotation = CB_AXIS.label.rotate;
Packit 0986c0
	apply_pm3dcolor(&(CB_AXIS.label.textcolor));
Packit 0986c0
	if (color_box.rotation == 'h') {
Packit 0986c0
	    len = CB_AXIS.ticscale * (CB_AXIS.tic_in ? 1 : -1) * (term->v_tic);
Packit 0986c0
Packit 0986c0
	    x = (color_box.bounds.xleft + color_box.bounds.xright) / 2;
Packit 0986c0
	    y = color_box.bounds.ybot - 2.7 * term->v_char;
Packit 0986c0
Packit 0986c0
	    if (len < 0) y += len;
Packit 0986c0
	    if (CB_AXIS.label.rotate == TEXT_VERTICAL)
Packit 0986c0
		CB_AXIS.label.rotate = 0;
Packit 0986c0
	} else {
Packit 0986c0
	    len = CB_AXIS.ticscale * (CB_AXIS.tic_in ? -1 : 1) * (term->h_tic);
Packit 0986c0
	    /* calculate max length of cb-tics labels */
Packit 0986c0
	    widest_tic_strlen = 0;
Packit 0986c0
	    if (CB_AXIS.ticmode & TICS_ON_BORDER) /* Recalculate widest_tic_strlen */
Packit 0986c0
		gen_tics(&axis_array[COLOR_AXIS], widest_tic_callback);
Packit 0986c0
	    x = color_box.bounds.xright + (widest_tic_strlen + 1.5) * term->h_char;
Packit 0986c0
	    if (len > 0) x += len;
Packit 0986c0
	    y = (color_box.bounds.ybot + color_box.bounds.ytop) / 2;
Packit 0986c0
	}
Packit 0986c0
	if (x<0) x = 0;
Packit 0986c0
	if (y<0) y = 0;
Packit 0986c0
	write_label(x, y, &(CB_AXIS.label));
Packit 0986c0
	reset_textcolor(&(CB_AXIS.label.textcolor));
Packit 0986c0
	CB_AXIS.label.rotate = save_rotation;
Packit 0986c0
    }
Packit 0986c0
Packit 0986c0
}
Packit 0986c0
Packit 0986c0
/*
Packit 0986c0
 * User-callable builtin color conversion 
Packit 0986c0
 */
Packit 0986c0
void
Packit 0986c0
f_hsv2rgb(union argument *arg)
Packit 0986c0
{
Packit 0986c0
    struct value h, s, v, result;
Packit 0986c0
    rgb_color color = {0., 0., 0.};
Packit 0986c0
Packit 0986c0
    (void) arg;
Packit 0986c0
    (void) pop(&v);
Packit 0986c0
    (void) pop(&s);
Packit 0986c0
    (void) pop(&h);
Packit 0986c0
Packit 0986c0
    if (h.type == INTGR)
Packit 0986c0
	color.r = h.v.int_val;
Packit 0986c0
    else if (h.type == CMPLX)
Packit 0986c0
	color.r = h.v.cmplx_val.real;
Packit 0986c0
    if (s.type == INTGR)
Packit 0986c0
	color.g = s.v.int_val;
Packit 0986c0
    else if (s.type == CMPLX)
Packit 0986c0
	color.g = s.v.cmplx_val.real;
Packit 0986c0
    if (v.type == INTGR)
Packit 0986c0
	color.b = v.v.int_val;
Packit 0986c0
    else if (v.type == CMPLX)
Packit 0986c0
	color.b = v.v.cmplx_val.real;
Packit 0986c0
Packit 0986c0
    if (color.r < 0)
Packit 0986c0
	color.r = 0;
Packit 0986c0
    if (color.g < 0)
Packit 0986c0
	color.g = 0;
Packit 0986c0
    if (color.b < 0)
Packit 0986c0
	color.b = 0;
Packit 0986c0
    if (color.r > 1.)
Packit 0986c0
	color.r = 1.;
Packit 0986c0
    if (color.g > 1.)
Packit 0986c0
	color.g = 1.;
Packit 0986c0
    if (color.b > 1.)
Packit 0986c0
	color.b = 1.;
Packit 0986c0
Packit 0986c0
    (void) Ginteger(&result, hsv2rgb(&color));
Packit 0986c0
    push(&result);
Packit 0986c0
}