2 static char *RCSid() { return RCSid("gadgets.c,v 1.1.3.1 2000/05/03 21:47:15 hbb Exp"); }
5 /* GNUPLOT - gadgets.c */
8 * Copyright 2000, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
39 #include "graph3d.h" /* for map3d_position_r() */
41 #include "plot3d.h" /* For is_plot_with_palette() */
45 /* This file contains mainly a collection of global variables that
46 * used to be in 'set.c', where they didn't really belong. They
47 * describe the status of several parts of the gnuplot plotting engine
48 * that are used by both 2D and 3D plots, and thus belong neither to
49 * graphics.c nor graph3d.c, alone. This is not a very clean solution,
50 * but better than mixing internal status and the user interface as we
51 * used to have it, in set.c and setshow.h */
53 legend_key keyT = DEFAULT_KEY_PROPS;
55 /* Description of the color box associated with CB_AXIS */
56 color_box_struct color_box; /* initialized in init_color() */
57 color_box_struct default_color_box = {SMCOLOR_BOX_DEFAULT, 'v', 1, LT_BLACK, LAYER_FRONT,
58 {screen, screen, screen, 0.90, 0.2, 0.0},
59 {screen, screen, screen, 0.05, 0.6, 0.0}};
61 /* The graph box, in terminal coordinates, as calculated by boundary()
63 BoundingBox plot_bounds;
65 /* The bounding box for the entire drawable area of current terminal */
68 /* The bounding box against which clipping is to be done */
69 BoundingBox *clip_area = &plot_bounds;
71 /* 'set size', 'set origin' setttings */
72 float xsize = 1.0; /* scale factor for size */
73 float ysize = 1.0; /* scale factor for size */
74 float zsize = 1.0; /* scale factor for size */
75 float xoffset = 0.0; /* x origin */
76 float yoffset = 0.0; /* y origin */
77 float aspect_ratio = 0.0; /* don't attempt to force it */
78 int aspect_ratio_3D = 0; /* 2 will put x and y on same scale, 3 for z also */
81 redefine margin as t_position so that absolute placement is possible */
82 /* space between left edge and plot_bounds.xleft in chars (-1: computed) */
83 t_position lmargin = DEFAULT_MARGIN_POSITION;
84 /* space between bottom and plot_bounds.ybot in chars (-1: computed) */
85 t_position bmargin = DEFAULT_MARGIN_POSITION;
86 /* space between right egde and plot_bounds.xright in chars (-1: computed) */
87 t_position rmargin = DEFAULT_MARGIN_POSITION;
88 /* space between top egde and plot_bounds.ytop in chars (-1: computed) */
89 t_position tmargin = DEFAULT_MARGIN_POSITION;
91 /* File descriptor for output during 'set table' mode */
92 FILE *table_outfile = NULL;
93 TBOOLEAN table_mode = FALSE;
95 /* Pointer to the start of the linked list of 'set label' definitions */
96 struct text_label *first_label = NULL;
98 /* Pointer to first 'set linestyle' definition in linked list */
99 struct linestyle_def *first_linestyle = NULL;
101 /* Pointer to first 'set style arrow' definition in linked list */
102 struct arrowstyle_def *first_arrowstyle = NULL;
105 struct arrow_def *first_arrow = NULL;
108 /* Pointer to first object instance in linked list */
109 struct object *first_object = NULL;
112 /* 'set title' status */
113 text_label title = EMPTY_LABELSTRUCT;
115 /* 'set timelabel' status */
116 text_label timelabel = EMPTY_LABELSTRUCT;
117 int timelabel_rotate = FALSE;
118 int timelabel_bottom = TRUE;
120 /* flag for polar mode */
121 TBOOLEAN polar = FALSE;
123 /* zero threshold, may _not_ be 0! */
126 /* Status of 'set pointsize' command */
127 double pointsize = 1.0;
130 int draw_border = 31;
131 int border_layer = 1;
132 # define DEFAULT_BORDER_LP { 0, -2, 0, 1.0, 1.0, 0 }
133 struct lp_style_type border_lp = DEFAULT_BORDER_LP;
134 const struct lp_style_type default_border_lp = DEFAULT_BORDER_LP;
137 TBOOLEAN clip_lines1 = TRUE;
138 TBOOLEAN clip_lines2 = FALSE;
139 /* FIXME HBB 20000521: clip_points is only used by 2D plots. This may
140 * well constitute a yet unknown bug... */
141 TBOOLEAN clip_points = FALSE;
144 int samples_1 = SAMPLES;
145 int samples_2 = SAMPLES;
148 double ang2rad = 1.0; /* 1 or pi/180, tracking angles_format */
150 enum PLOT_STYLE data_style = POINTSTYLE;
151 enum PLOT_STYLE func_style = LINES;
153 TBOOLEAN parametric = FALSE;
155 /* If last plot was a 3d one. */
156 TBOOLEAN is_3d_plot = FALSE;
159 /* If last plot was one using color bus, e.g., image, map, pm3d. */
160 TBOOLEAN is_cb_plot = FALSE;
163 fill_style_type default_fillstyle = { FS_EMPTY, 100, 0, LT_UNDEFINED } ;
166 /* Default rectangle style - background fill, black border */
167 struct object default_rectangle = DEFAULT_RECTANGLE_STYLE;
170 /* filledcurves style options */
171 filledcurves_opts filledcurves_opts_data = EMPTY_FILLEDCURVES_OPTS;
172 filledcurves_opts filledcurves_opts_func = EMPTY_FILLEDCURVES_OPTS;
174 /* Prefer line styles over plain line types */
175 TBOOLEAN prefer_line_styles = FALSE;
177 #ifdef EAM_HISTOGRAMS
178 histogram_style histogram_opts = DEFAULT_HISTOGRAM_STYLE;
181 /*****************************************************************/
182 /* Routines that deal with global objects defined in this module */
183 /*****************************************************************/
185 /* Clipping to the bounding box: */
187 /* Test a single point to be within the BoundingBox.
188 * Sets the returned integers 4 l.s.b. as follows:
189 * bit 0 if to the left of xleft.
190 * bit 1 if to the right of xright.
191 * bit 2 if below of ybot.
192 * bit 3 if above of ytop.
193 * 0 is returned if inside.
196 clip_point(unsigned int x, unsigned int y)
202 if ((int)x < clip_area->xleft)
204 if ((int)x > clip_area->xright)
206 if ((int)y < clip_area->ybot)
208 if ((int)y > clip_area->ytop)
214 /* Clip the given line to drawing coords defined by BoundingBox.
215 * This routine uses the cohen & sutherland bit mapping for fast clipping -
216 * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
219 draw_clip_line(int x1, int y1, int x2, int y2)
221 struct termentry *t = term;
223 #if defined(ATARI) || defined(MTOS)
224 /* HBB 20000522: why would this test be particular to ATARIs? And
225 * what was the bug this is supposed to fix? */
226 if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0)
227 return; /* temp bug fix */
230 /* HBB 20000522: I've made this routine use the clippling in
231 * clip_line(), in a movement to reduce code duplication. There
232 * was one very small difference between these two routines. See
233 * clip_line() for a comment about it, at the relevant place. */
234 if (!clip_line(&x1, &y1, &x2, &y2))
235 /* clip_line() returns zero --> segment completely outside
239 /* HBB 20000617: there was a design error, here. By nature, this
240 * is a 2D routine. It should never have to check for hidden3d
241 * related variables, or call the hidden3d routine
242 * draw_line_hidden, like this. I've thrown this out. */
244 /* FIXME HBB 20000522: I strongly doubt this can work as
245 * advertised. It's supposed to allow for continuous contour
246 * curves, but as soon as the contour curve moves outside the
247 * boundary, you get overpainting instead, as the contour curve
248 * walks along the border. Or worse artefacts. */
253 (*t->vector) (x2, y2);
257 draw_clip_arrow( int sx, int sy, int ex, int ey, int head)
259 struct termentry *t = term;
261 /* Don't draw head if the arrow itself is clipped */
262 if (clip_point(sx,sy))
264 if (clip_point(ex,ey))
266 clip_line(&sx, &sy, &ex, &ey);
268 /* Call terminal routine to draw the clipped arrow */
269 (*t->arrow)((unsigned int)sx, (unsigned int)sy,
270 (unsigned int)ex, (unsigned int)ey, head);
274 /* And text clipping routine. */
276 clip_put_text(unsigned int x, unsigned y, char *str)
278 struct termentry *t = term;
280 if (clip_point(x, y))
283 (*t->put_text) (x, y, str);
287 /* Clip the given line to drawing coords defined by BoundingBox.
288 * This routine uses the cohen & sutherland bit mapping for fast clipping -
289 * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
291 /* FIXME HBB 20000521: the parameters of this routine should become
294 clip_line(int *x1, int *y1, int *x2, int *y2)
296 int x, y, dx, dy, x_intr[4], y_intr[4], count, pos1, pos2;
297 int x_max, x_min, y_max, y_min;
298 pos1 = clip_point(*x1, *y1);
299 pos2 = clip_point(*x2, *y2);
301 return 1; /* segment is totally in */
303 return 0; /* segment is totally out. */
304 /* Here part of the segment MAY be inside. test the intersection
305 * of this segment with the 4 boundaries for hopefully 2 intersections
306 * in. If none are found segment is totaly out.
307 * Under rare circumstances there may be up to 4 intersections (e.g.
308 * when the line passes directly through at least one corner). In
309 * this case it is sufficient to take any 2 intersections (e.g. the
315 /* Find intersections with the x parallel bbox lines: */
317 x = (clip_area->ybot - *y2) * dx / dy + *x2; /* Test for clip_area->ybot boundary. */
318 if (x >= clip_area->xleft && x <= clip_area->xright) {
320 y_intr[count++] = clip_area->ybot;
322 x = (clip_area->ytop - *y2) * dx / dy + *x2; /* Test for clip_area->ytop boundary. */
323 if (x >= clip_area->xleft && x <= clip_area->xright) {
325 y_intr[count++] = clip_area->ytop;
328 /* Find intersections with the y parallel bbox lines: */
330 y = (clip_area->xleft - *x2) * dy / dx + *y2; /* Test for clip_area->xleft boundary. */
331 if (y >= clip_area->ybot && y <= clip_area->ytop) {
332 x_intr[count] = clip_area->xleft;
335 y = (clip_area->xright - *x2) * dy / dx + *y2; /* Test for clip_area->xright boundary. */
336 if (y >= clip_area->ybot && y <= clip_area->ytop) {
337 x_intr[count] = clip_area->xright;
359 if (pos1 && pos2) { /* Both were out - update both */
364 } else if (pos1) { /* Only x1/y1 was out - update only it */
365 /* This is about the only real difference between this and
366 * draw_clip_line(): it compares for '>0', here */
367 if (dx * (*x2 - x_intr[0]) + dy * (*y2 - y_intr[0]) >= 0) {
374 } else { /* Only x2/y2 was out - update only it */
375 /* Same difference here, again */
376 if (dx * (x_intr[0] - *x1) + dy * (y_intr[0] - *y1) >= 0) {
385 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)
392 /* Two routines to emulate move/vector sequence using line drawing routine. */
393 static unsigned int move_pos_x, move_pos_y;
396 clip_move(unsigned int x, unsigned int y)
403 clip_vector(unsigned int x, unsigned int y)
405 draw_clip_line(move_pos_x, move_pos_y, x, y);
410 /* Common routines for setting text or line color from t_colorspec */
413 apply_pm3dcolor(struct t_colorspec *tc, const struct termentry *t)
416 /* Replace colorspec with that of the requested line style */
417 struct lp_style_type style;
418 if (tc->type == TC_LINESTYLE) {
419 lp_use_properties(&style, tc->lt, 0);
420 (*t->linetype)(style.l_type);
421 tc = &style.pm3d_color;
424 if (tc->type == TC_DEFAULT) {
425 (*t->linetype)(LT_BLACK);
428 if (tc->type == TC_LT) {
432 (*t->linetype)(tc->lt);
435 if (tc->type == TC_RGB && t->set_color) {
439 if (!is_plot_with_palette() || !t->set_color) {
440 (*t->linetype)(LT_BLACK);
444 case TC_Z: set_color(cb2gray(z2cb(tc->value))); break;
445 case TC_CB: set_color(cb2gray(tc->value)); break;
446 case TC_FRAC: set_color(sm_palette.positive == SMPAL_POSITIVE ?
447 tc->value : 1-tc->value);
450 if (tc->type == TC_LT) {
451 (*t->linetype)(tc->lt);
457 reset_textcolor(const struct t_colorspec *tc, const struct termentry *t)
459 if (tc->type != TC_DEFAULT)
460 (*t->linetype)(LT_BLACK);
465 default_arrow_style(struct arrow_style_type *arrow)
467 static const struct lp_style_type tmp_lp_style = DEFAULT_LP_STYLE_TYPE;
470 arrow->lp_properties = tmp_lp_style;
472 arrow->head_length = 0.0;
473 arrow->head_lengthunit = first_axes;
474 arrow->head_angle = 15.0;
475 arrow->head_backangle = 90.0;
476 arrow->head_filled = 0;
479 #ifdef EAM_DATASTRINGS
481 free_labels(struct text_label *label)
483 struct text_label *temp;
484 char *master_font = label->font;
486 /* Labels generated by 'plot with labels' all use the same font */
493 if (label->font && label->font != master_font)
505 struct text_label *this_label,
507 int *htic, int *vtic)
509 if (this_label->lp_properties.pointflag) {
510 *htic = (pointsize * t->h_tic * 0.5);
511 *vtic = (pointsize * t->v_tic * 0.5);
518 map3d_position_r(&(this_label->offset), &htic2, &vtic2, "get_offsets");
523 map_position_r(&(this_label->offset), &htic2, &vtic2, "get_offsets");
531 * Write one label, with all the trimmings.
532 * This routine is used for both 2D and 3D plots.
535 write_label(unsigned int x, unsigned int y, struct text_label *this_label)
538 int justify = JUST_TOP; /* This was the 2D default; 3D had CENTRE */
540 apply_pm3dcolor(&(this_label->textcolor),term);
541 ignore_enhanced(this_label->noenhanced);
543 get_offsets(this_label, term, &htic, &vtic);
544 if (this_label->rotate && (*term->text_angle) (this_label->rotate)) {
545 write_multiline(x + htic, y + vtic, this_label->text,
546 this_label->pos, justify, this_label->rotate,
548 (*term->text_angle) (0);
550 write_multiline(x + htic, y + vtic, this_label->text,
551 this_label->pos, justify, 0, this_label->font);
553 /* write_multiline() clips text to on_page; do the same for any point */
554 if (this_label->lp_properties.pointflag && on_page(x,y)) {
555 term_apply_lp_properties(&this_label->lp_properties);
556 (*term->point) (x, y, this_label->lp_properties.p_type);
557 /* the default label color is that of border */
558 term_apply_lp_properties(&border_lp);
561 ignore_enhanced(FALSE);