X-Git-Url: http://git.maemo.org/git/?p=gnuplot;a=blobdiff_plain;f=src%2Fgadgets.c;fp=src%2Fgadgets.c;h=0be2e97ddf474327913c0ce3bae7c0aff675028a;hp=0000000000000000000000000000000000000000;hb=39ec1247a71f61152a4a7f502a30f06a3896c5da;hpb=06be459be4f5f6a7c6ff878e84f355fb2575caa8 diff --git a/src/gadgets.c b/src/gadgets.c new file mode 100644 index 0000000..0be2e97 --- /dev/null +++ b/src/gadgets.c @@ -0,0 +1,562 @@ +#ifndef lint +static char *RCSid() { return RCSid("gadgets.c,v 1.1.3.1 2000/05/03 21:47:15 hbb Exp"); } +#endif + +/* GNUPLOT - gadgets.c */ + +/*[ + * Copyright 2000, 2004 Thomas Williams, Colin Kelley + * + * Permission to use, copy, and distribute this software and its + * documentation for any purpose with or without fee is hereby granted, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. + * + * Permission to modify the software is granted, but not the right to + * distribute the complete modified source code. Modifications are to + * be distributed as patches to the released version. Permission to + * distribute binaries produced by compiling modified sources is granted, + * provided you + * 1. distribute the corresponding source modifications from the + * released version in the form of a patch file along with the binaries, + * 2. add special version identification to distinguish your version + * in addition to the base release version number, + * 3. provide your name and address as the primary contact for the + * support of your modified version, and + * 4. retain our contact information in regard to use of the base + * software. + * Permission to distribute the released version of the source code along + * with corresponding source modifications in the form of a patch file is + * granted with same provisions 2 through 4 for binary distributions. + * + * This software is provided "as is" without express or implied warranty + * to the extent permitted by applicable law. +]*/ + +#include "gadgets.h" +#include "command.h" +#include "graph3d.h" /* for map3d_position_r() */ +#include "graphics.h" +#include "plot3d.h" /* For is_plot_with_palette() */ + +#include "pm3d.h" + +/* This file contains mainly a collection of global variables that + * used to be in 'set.c', where they didn't really belong. They + * describe the status of several parts of the gnuplot plotting engine + * that are used by both 2D and 3D plots, and thus belong neither to + * graphics.c nor graph3d.c, alone. This is not a very clean solution, + * but better than mixing internal status and the user interface as we + * used to have it, in set.c and setshow.h */ + +legend_key keyT = DEFAULT_KEY_PROPS; + +/* Description of the color box associated with CB_AXIS */ +color_box_struct color_box; /* initialized in init_color() */ +color_box_struct default_color_box = {SMCOLOR_BOX_DEFAULT, 'v', 1, LT_BLACK, LAYER_FRONT, + {screen, screen, screen, 0.90, 0.2, 0.0}, + {screen, screen, screen, 0.05, 0.6, 0.0}}; + +/* The graph box, in terminal coordinates, as calculated by boundary() + * or boundary3d(): */ +BoundingBox plot_bounds; + +/* The bounding box for the entire drawable area of current terminal */ +BoundingBox canvas; + +/* The bounding box against which clipping is to be done */ +BoundingBox *clip_area = &plot_bounds; + +/* 'set size', 'set origin' setttings */ +float xsize = 1.0; /* scale factor for size */ +float ysize = 1.0; /* scale factor for size */ +float zsize = 1.0; /* scale factor for size */ +float xoffset = 0.0; /* x origin */ +float yoffset = 0.0; /* y origin */ +float aspect_ratio = 0.0; /* don't attempt to force it */ +int aspect_ratio_3D = 0; /* 2 will put x and y on same scale, 3 for z also */ + +/* EAM Augest 2006 - + redefine margin as t_position so that absolute placement is possible */ +/* space between left edge and plot_bounds.xleft in chars (-1: computed) */ +t_position lmargin = DEFAULT_MARGIN_POSITION; +/* space between bottom and plot_bounds.ybot in chars (-1: computed) */ +t_position bmargin = DEFAULT_MARGIN_POSITION; +/* space between right egde and plot_bounds.xright in chars (-1: computed) */ +t_position rmargin = DEFAULT_MARGIN_POSITION; +/* space between top egde and plot_bounds.ytop in chars (-1: computed) */ +t_position tmargin = DEFAULT_MARGIN_POSITION; + +/* File descriptor for output during 'set table' mode */ +FILE *table_outfile = NULL; +TBOOLEAN table_mode = FALSE; + +/* Pointer to the start of the linked list of 'set label' definitions */ +struct text_label *first_label = NULL; + +/* Pointer to first 'set linestyle' definition in linked list */ +struct linestyle_def *first_linestyle = NULL; + +/* Pointer to first 'set style arrow' definition in linked list */ +struct arrowstyle_def *first_arrowstyle = NULL; + +/* set arrow */ +struct arrow_def *first_arrow = NULL; + +#ifdef EAM_OBJECTS +/* Pointer to first object instance in linked list */ +struct object *first_object = NULL; +#endif + +/* 'set title' status */ +text_label title = EMPTY_LABELSTRUCT; + +/* 'set timelabel' status */ +text_label timelabel = EMPTY_LABELSTRUCT; +int timelabel_rotate = FALSE; +int timelabel_bottom = TRUE; + +/* flag for polar mode */ +TBOOLEAN polar = FALSE; + +/* zero threshold, may _not_ be 0! */ +double zero = ZERO; + +/* Status of 'set pointsize' command */ +double pointsize = 1.0; + +/* set border */ +int draw_border = 31; +int border_layer = 1; +# define DEFAULT_BORDER_LP { 0, -2, 0, 1.0, 1.0, 0 } +struct lp_style_type border_lp = DEFAULT_BORDER_LP; +const struct lp_style_type default_border_lp = DEFAULT_BORDER_LP; + +/* set clip */ +TBOOLEAN clip_lines1 = TRUE; +TBOOLEAN clip_lines2 = FALSE; +/* FIXME HBB 20000521: clip_points is only used by 2D plots. This may + * well constitute a yet unknown bug... */ +TBOOLEAN clip_points = FALSE; + +/* set samples */ +int samples_1 = SAMPLES; +int samples_2 = SAMPLES; + +/* set angles */ +double ang2rad = 1.0; /* 1 or pi/180, tracking angles_format */ + +enum PLOT_STYLE data_style = POINTSTYLE; +enum PLOT_STYLE func_style = LINES; + +TBOOLEAN parametric = FALSE; + +/* If last plot was a 3d one. */ +TBOOLEAN is_3d_plot = FALSE; + +#ifdef WITH_IMAGE +/* If last plot was one using color bus, e.g., image, map, pm3d. */ +TBOOLEAN is_cb_plot = FALSE; +#endif + +fill_style_type default_fillstyle = { FS_EMPTY, 100, 0, LT_UNDEFINED } ; + +#ifdef EAM_OBJECTS +/* Default rectangle style - background fill, black border */ +struct object default_rectangle = DEFAULT_RECTANGLE_STYLE; +#endif + +/* filledcurves style options */ +filledcurves_opts filledcurves_opts_data = EMPTY_FILLEDCURVES_OPTS; +filledcurves_opts filledcurves_opts_func = EMPTY_FILLEDCURVES_OPTS; + +/* Prefer line styles over plain line types */ +TBOOLEAN prefer_line_styles = FALSE; + +#ifdef EAM_HISTOGRAMS +histogram_style histogram_opts = DEFAULT_HISTOGRAM_STYLE; +#endif + +/*****************************************************************/ +/* Routines that deal with global objects defined in this module */ +/*****************************************************************/ + +/* Clipping to the bounding box: */ + +/* Test a single point to be within the BoundingBox. + * Sets the returned integers 4 l.s.b. as follows: + * bit 0 if to the left of xleft. + * bit 1 if to the right of xright. + * bit 2 if below of ybot. + * bit 3 if above of ytop. + * 0 is returned if inside. + */ +int +clip_point(unsigned int x, unsigned int y) +{ + int ret_val = 0; + + if (!clip_area) + return 0; + if ((int)x < clip_area->xleft) + ret_val |= 0x01; + if ((int)x > clip_area->xright) + ret_val |= 0x02; + if ((int)y < clip_area->ybot) + ret_val |= 0x04; + if ((int)y > clip_area->ytop) + ret_val |= 0x08; + + return ret_val; +} + +/* Clip the given line to drawing coords defined by BoundingBox. + * This routine uses the cohen & sutherland bit mapping for fast clipping - + * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65. + */ +void +draw_clip_line(int x1, int y1, int x2, int y2) +{ + struct termentry *t = term; + +#if defined(ATARI) || defined(MTOS) + /* HBB 20000522: why would this test be particular to ATARIs? And + * what was the bug this is supposed to fix? */ + if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0) + return; /* temp bug fix */ +#endif + + /* HBB 20000522: I've made this routine use the clippling in + * clip_line(), in a movement to reduce code duplication. There + * was one very small difference between these two routines. See + * clip_line() for a comment about it, at the relevant place. */ + if (!clip_line(&x1, &y1, &x2, &y2)) + /* clip_line() returns zero --> segment completely outside + * bounding box */ + return; + + /* HBB 20000617: there was a design error, here. By nature, this + * is a 2D routine. It should never have to check for hidden3d + * related variables, or call the hidden3d routine + * draw_line_hidden, like this. I've thrown this out. */ + + /* FIXME HBB 20000522: I strongly doubt this can work as + * advertised. It's supposed to allow for continuous contour + * curves, but as soon as the contour curve moves outside the + * boundary, you get overpainting instead, as the contour curve + * walks along the border. Or worse artefacts. */ +#if 0 /* UNUSED */ + if (!suppressMove) +#endif + (*t->move) (x1, y1); + (*t->vector) (x2, y2); +} + +void +draw_clip_arrow( int sx, int sy, int ex, int ey, int head) +{ + struct termentry *t = term; + + /* Don't draw head if the arrow itself is clipped */ + if (clip_point(sx,sy)) + head &= ~BACKHEAD; + if (clip_point(ex,ey)) + head &= ~END_HEAD; + clip_line(&sx, &sy, &ex, &ey); + + /* Call terminal routine to draw the clipped arrow */ + (*t->arrow)((unsigned int)sx, (unsigned int)sy, + (unsigned int)ex, (unsigned int)ey, head); +} + + +/* And text clipping routine. */ +void +clip_put_text(unsigned int x, unsigned y, char *str) +{ + struct termentry *t = term; + + if (clip_point(x, y)) + return; + + (*t->put_text) (x, y, str); +} + + +/* Clip the given line to drawing coords defined by BoundingBox. + * This routine uses the cohen & sutherland bit mapping for fast clipping - + * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65. + */ +/* FIXME HBB 20000521: the parameters of this routine should become + * unsigned ints. */ +int +clip_line(int *x1, int *y1, int *x2, int *y2) +{ + int x, y, dx, dy, x_intr[4], y_intr[4], count, pos1, pos2; + int x_max, x_min, y_max, y_min; + pos1 = clip_point(*x1, *y1); + pos2 = clip_point(*x2, *y2); + if (!pos1 && !pos2) + return 1; /* segment is totally in */ + if (pos1 & pos2) + return 0; /* segment is totally out. */ + /* Here part of the segment MAY be inside. test the intersection + * of this segment with the 4 boundaries for hopefully 2 intersections + * in. If none are found segment is totaly out. + * Under rare circumstances there may be up to 4 intersections (e.g. + * when the line passes directly through at least one corner). In + * this case it is sufficient to take any 2 intersections (e.g. the + * first two found). + */ + count = 0; + dx = *x2 - *x1; + dy = *y2 - *y1; + /* Find intersections with the x parallel bbox lines: */ + if (dy != 0) { + x = (clip_area->ybot - *y2) * dx / dy + *x2; /* Test for clip_area->ybot boundary. */ + if (x >= clip_area->xleft && x <= clip_area->xright) { + x_intr[count] = x; + y_intr[count++] = clip_area->ybot; + } + x = (clip_area->ytop - *y2) * dx / dy + *x2; /* Test for clip_area->ytop boundary. */ + if (x >= clip_area->xleft && x <= clip_area->xright) { + x_intr[count] = x; + y_intr[count++] = clip_area->ytop; + } + } + /* Find intersections with the y parallel bbox lines: */ + if (dx != 0) { + y = (clip_area->xleft - *x2) * dy / dx + *y2; /* Test for clip_area->xleft boundary. */ + if (y >= clip_area->ybot && y <= clip_area->ytop) { + x_intr[count] = clip_area->xleft; + y_intr[count++] = y; + } + y = (clip_area->xright - *x2) * dy / dx + *y2; /* Test for clip_area->xright boundary. */ + if (y >= clip_area->ybot && y <= clip_area->ytop) { + x_intr[count] = clip_area->xright; + y_intr[count++] = y; + } + } + if (count < 2) + return 0; + + if (*x1 < *x2) { + x_min = *x1; + x_max = *x2; + } else { + x_min = *x2; + x_max = *x1; + } + if (*y1 < *y2) { + y_min = *y1; + y_max = *y2; + } else { + y_min = *y2; + y_max = *y1; + } + + if (pos1 && pos2) { /* Both were out - update both */ + *x1 = x_intr[0]; + *y1 = y_intr[0]; + *x2 = x_intr[1]; + *y2 = y_intr[1]; + } else if (pos1) { /* Only x1/y1 was out - update only it */ + /* This is about the only real difference between this and + * draw_clip_line(): it compares for '>0', here */ + if (dx * (*x2 - x_intr[0]) + dy * (*y2 - y_intr[0]) >= 0) { + *x1 = x_intr[0]; + *y1 = y_intr[0]; + } else { + *x1 = x_intr[1]; + *y1 = y_intr[1]; + } + } else { /* Only x2/y2 was out - update only it */ + /* Same difference here, again */ + if (dx * (x_intr[0] - *x1) + dy * (y_intr[0] - *y1) >= 0) { + *x2 = x_intr[0]; + *y2 = y_intr[0]; + } else { + *x2 = x_intr[1]; + *y2 = y_intr[1]; + } + } + + if (*x1 < x_min || *x1 > x_max || *x2 < x_min || *x2 > x_max || *y1 < y_min || *y1 > y_max || *y2 < y_min || *y2 > y_max) + return 0; + + return 1; +} + + +/* Two routines to emulate move/vector sequence using line drawing routine. */ +static unsigned int move_pos_x, move_pos_y; + +void +clip_move(unsigned int x, unsigned int y) +{ + move_pos_x = x; + move_pos_y = y; +} + +void +clip_vector(unsigned int x, unsigned int y) +{ + draw_clip_line(move_pos_x, move_pos_y, x, y); + move_pos_x = x; + move_pos_y = y; +} + +/* Common routines for setting text or line color from t_colorspec */ + +void +apply_pm3dcolor(struct t_colorspec *tc, const struct termentry *t) +{ + + /* Replace colorspec with that of the requested line style */ + struct lp_style_type style; + if (tc->type == TC_LINESTYLE) { + lp_use_properties(&style, tc->lt, 0); + (*t->linetype)(style.l_type); + tc = &style.pm3d_color; + } + + if (tc->type == TC_DEFAULT) { + (*t->linetype)(LT_BLACK); + return; + } + if (tc->type == TC_LT) { + if (t->set_color) + t->set_color(tc); + else + (*t->linetype)(tc->lt); + return; + } + if (tc->type == TC_RGB && t->set_color) { + t->set_color(tc); + return; + } + if (!is_plot_with_palette() || !t->set_color) { + (*t->linetype)(LT_BLACK); + return; + } + switch (tc->type) { + case TC_Z: set_color(cb2gray(z2cb(tc->value))); break; + case TC_CB: set_color(cb2gray(tc->value)); break; + case TC_FRAC: set_color(sm_palette.positive == SMPAL_POSITIVE ? + tc->value : 1-tc->value); + break; + } + if (tc->type == TC_LT) { + (*t->linetype)(tc->lt); + return; + } +} + +void +reset_textcolor(const struct t_colorspec *tc, const struct termentry *t) +{ + if (tc->type != TC_DEFAULT) + (*t->linetype)(LT_BLACK); +} + + +void +default_arrow_style(struct arrow_style_type *arrow) +{ + static const struct lp_style_type tmp_lp_style = DEFAULT_LP_STYLE_TYPE; + + arrow->layer = 0; + arrow->lp_properties = tmp_lp_style; + arrow->head = 1; + arrow->head_length = 0.0; + arrow->head_lengthunit = first_axes; + arrow->head_angle = 15.0; + arrow->head_backangle = 90.0; + arrow->head_filled = 0; +} + +#ifdef EAM_DATASTRINGS +void +free_labels(struct text_label *label) +{ +struct text_label *temp; +char *master_font = label->font; + + /* Labels generated by 'plot with labels' all use the same font */ + if (master_font) + free(master_font); + + while (label) { + if (label->text) + free(label->text); + if (label->font && label->font != master_font) + free(label->font); + temp=label->next; + free(label); + label = temp; + } + +} +#endif + +void +get_offsets( + struct text_label *this_label, + struct termentry *t, + int *htic, int *vtic) +{ + if (this_label->lp_properties.pointflag) { + *htic = (pointsize * t->h_tic * 0.5); + *vtic = (pointsize * t->v_tic * 0.5); + } else { + *htic = 0; + *vtic = 0; + } + if (is_3d_plot) { + int htic2, vtic2; + map3d_position_r(&(this_label->offset), &htic2, &vtic2, "get_offsets"); + *htic += htic2; + *vtic += vtic2; + } else { + double htic2, vtic2; + map_position_r(&(this_label->offset), &htic2, &vtic2, "get_offsets"); + *htic += (int)htic2; + *vtic += (int)vtic2; + } +} + + +/* + * Write one label, with all the trimmings. + * This routine is used for both 2D and 3D plots. + */ +void +write_label(unsigned int x, unsigned int y, struct text_label *this_label) +{ + int htic, vtic; + int justify = JUST_TOP; /* This was the 2D default; 3D had CENTRE */ + + apply_pm3dcolor(&(this_label->textcolor),term); + ignore_enhanced(this_label->noenhanced); + + get_offsets(this_label, term, &htic, &vtic); + if (this_label->rotate && (*term->text_angle) (this_label->rotate)) { + write_multiline(x + htic, y + vtic, this_label->text, + this_label->pos, justify, this_label->rotate, + this_label->font); + (*term->text_angle) (0); + } else { + write_multiline(x + htic, y + vtic, this_label->text, + this_label->pos, justify, 0, this_label->font); + } + /* write_multiline() clips text to on_page; do the same for any point */ + if (this_label->lp_properties.pointflag && on_page(x,y)) { + term_apply_lp_properties(&this_label->lp_properties); + (*term->point) (x, y, this_label->lp_properties.p_type); + /* the default label color is that of border */ + term_apply_lp_properties(&border_lp); + } + + ignore_enhanced(FALSE); +}