Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / axis.h
1 /*
2  * $Id: axis.h,v 1.46.2.3 2008/10/30 22:26:23 sfeam Exp $
3  *
4  */
5
6 /*[
7  * Copyright 2000, 2004   Thomas Williams, Colin Kelley
8  *
9  * Permission to use, copy, and distribute this software and its
10  * documentation for any purpose with or without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and
12  * that both that copyright notice and this permission notice appear
13  * in supporting documentation.
14  *
15  * Permission to modify the software is granted, but not the right to
16  * distribute the complete modified source code.  Modifications are to
17  * be distributed as patches to the released version.  Permission to
18  * distribute binaries produced by compiling modified sources is granted,
19  * provided you
20  *   1. distribute the corresponding source modifications from the
21  *    released version in the form of a patch file along with the binaries,
22  *   2. add special version identification to distinguish your version
23  *    in addition to the base release version number,
24  *   3. provide your name and address as the primary contact for the
25  *    support of your modified version, and
26  *   4. retain our contact information in regard to use of the base
27  *    software.
28  * Permission to distribute the released version of the source code along
29  * with corresponding source modifications in the form of a patch file is
30  * granted with same provisions 2 through 4 for binary distributions.
31  *
32  * This software is provided "as is" without express or implied warranty
33  * to the extent permitted by applicable law.
34 ]*/
35
36 #ifndef GNUPLOT_AXIS_H
37 #define GNUPLOT_AXIS_H
38
39 #include "gp_types.h"           /* for TBOOLEAN */
40
41 #include "gadgets.h"
42 #include "parse.h"              /* for const_express() */
43 #include "tables.h"             /* for the axis name parse table */
44 #include "term_api.h"           /* for lp_style_type */
45 #include "util.h"               /* for int_error() */
46
47 /* typedefs / #defines */
48
49 /* give some names to some array elements used in command.c and grap*.c
50  * maybe one day the relevant items in setshow will also be stored
51  * in arrays.
52  *
53  * Always keep the following conditions alive:
54  * SECOND_X_AXIS = FIRST_X_AXIS + SECOND_AXES
55  * FIRST_X_AXIS & SECOND_AXES == 0
56  */
57 typedef enum AXIS_INDEX {
58 #define FIRST_AXES 0
59     FIRST_Z_AXIS,
60     FIRST_Y_AXIS,
61     FIRST_X_AXIS,
62     T_AXIS,                     /* fill gap */
63 #define SECOND_AXES 4
64     SECOND_Z_AXIS,              /* not used, yet */
65     SECOND_Y_AXIS,
66     SECOND_X_AXIS,
67     R_AXIS,                     /* never used ? */
68     U_AXIS,                     /* ditto */
69     V_AXIS                      /* ditto */
70     ,COLOR_AXIS
71 } AXIS_INDEX;
72
73 # define AXIS_ARRAY_SIZE 11
74
75 /* What kind of ticmarking is wanted? */
76 typedef enum en_ticseries_type {
77     TIC_COMPUTED=1,             /* default; gnuplot figures them */
78     TIC_SERIES,                 /* user-defined series */
79     TIC_USER,                   /* user-defined points */
80     TIC_MONTH,                  /* print out month names ((mo-1)%12)+1 */
81     TIC_DAY                     /* print out day of week */
82 } t_ticseries_type;
83
84 /* Defines one ticmark for TIC_USER style.
85  * If label==NULL, the value is printed with the usual format string.
86  * else, it is used as the format string (note that it may be a constant
87  * string, like "high" or "low").
88  */
89 typedef struct ticmark {
90     double position;            /* where on axis is this */
91     char *label;                /* optional (format) string label */
92     int level;                  /* 0=major tic, 1=minor tic */
93     struct ticmark *next;       /* linked list */
94 } ticmark;
95
96 /* Tic-mark labelling definition; see set xtics */
97 typedef struct ticdef {
98     t_ticseries_type type;
99     char *font;
100     struct t_colorspec textcolor;
101     struct {
102            struct ticmark *user;        /* for TIC_USER */
103            struct {                     /* for TIC_SERIES */
104                   double start, incr;
105                   double end;           /* ymax, if VERYLARGE */
106            } series;
107            TBOOLEAN mix;                /* TRUE to use both the above */
108     } def;
109     struct position offset;
110     TBOOLEAN rangelimited;              /* Limit tics to data range */
111 } t_ticdef;
112
113 /* we want two auto modes for minitics - default where minitics are
114  * auto for log/time and off for linear, and auto where auto for all
115  * graphs I've done them in this order so that logscale-mode can
116  * simply test bit 0 to see if it must do the minitics automatically.
117  * similarly, conventional plot can test bit 1 to see if minitics are
118  * required */
119 enum en_minitics_status {
120     MINI_OFF,
121     MINI_DEFAULT,
122     MINI_USER,
123     MINI_AUTO
124 };
125
126 /* Function pointer type for callback functions doing operations for a
127  * single ticmark */
128 typedef void (*tic_callback) __PROTO((AXIS_INDEX, double, char *, struct lp_style_type ));
129
130 /* Values to put in the axis_tics[] variables that decides where the
131  * ticmarks should be drawn: not at all, on one or both plot borders,
132  * or the zeroaxes. These look like a series of values, but TICS_MASK
133  * shows that they're actually bit masks --> don't turn into an enum
134  * */
135 #define NO_TICS        0
136 #define TICS_ON_BORDER 1
137 #define TICS_ON_AXIS   2
138 #define TICS_MASK      3
139 #define TICS_MIRROR    4
140
141
142 #if 0 /* HBB 20010806 --- move GRID flags into axis struct */
143 /* Need to allow user to choose grid at first and/or second axes tics.
144  * Also want to let user choose circles at x or y tics for polar grid.
145  * Also want to allow user rectangular grid for polar plot or polar
146  * grid for parametric plot. So just go for full configurability.
147  * These are bitmasks
148  */
149 #define GRID_OFF    0
150 #define GRID_X      (1<<0)
151 #define GRID_Y      (1<<1)
152 #define GRID_Z      (1<<2)
153 #define GRID_X2     (1<<3)
154 #define GRID_Y2     (1<<4)
155 #define GRID_MX     (1<<5)
156 #define GRID_MY     (1<<6)
157 #define GRID_MZ     (1<<7)
158 #define GRID_MX2    (1<<8)
159 #define GRID_MY2    (1<<9)
160 #define GRID_CB     (1<<10)
161 #define GRID_MCB    (1<<11)
162 #endif /* 0 */
163
164 /* HBB 20010610: new type for storing autoscale activity. Effectively
165  * two booleans (bits) in a single variable, so I'm using an enum with
166  * all 4 possible bit masks given readable names. */
167 typedef enum e_autoscale {
168     AUTOSCALE_NONE = 0,
169     AUTOSCALE_MIN = 1<<0,
170     AUTOSCALE_MAX = 1<<1,
171     AUTOSCALE_BOTH = (1<<0 | 1 << 1),
172     AUTOSCALE_FIXMIN = 1<<2,
173     AUTOSCALE_FIXMAX = 1<<3
174 } t_autoscale;
175
176
177 /* FIXME 20000725: collect some of those various TBOOLEAN fields into
178  * a larger int (or -- shudder -- a bitfield?) */
179 typedef struct axis {
180 /* range of this axis */
181     t_autoscale autoscale;      /* Which end(s) are autoscaled? */
182     t_autoscale set_autoscale;  /* what does 'set' think autoscale to be? */
183     int range_flags;            /* flag bits about autoscale/writeback: */
184     /* write auto-ed ranges back to variables for autoscale */
185 #define RANGE_WRITEBACK 1
186     /* allow auto and reversed ranges */
187 #define RANGE_REVERSE   2
188     TBOOLEAN range_is_reverted; /* range [high:low] silently reverted? */
189     double min;                 /* 'transient' axis extremal values */
190     double max;
191     double set_min;             /* set/show 'permanent' values */
192     double set_max;
193     double writeback_min;       /* ULIG's writeback implementation */
194     double writeback_max;
195     double data_min;            /* Not necessarily the same as axis min */
196     double data_max;
197
198 /* output-related quantities */
199     int term_lower;             /* low and high end of the axis on output, */
200     int term_upper;             /* ... (in terminal coordinates)*/
201     double term_scale;          /* scale factor: plot --> term coords */
202     unsigned int term_zero;     /* position of zero axis */
203
204 /* log axis control */
205     TBOOLEAN log;               /* log axis stuff: flag "islog?" */
206     double base;                /* logarithm base value */
207     double log_base;            /* ln(base), for easier computations */
208
209 /* time/date axis control */
210     TBOOLEAN is_timedata;       /* is this a time/date axis? */
211     TBOOLEAN format_is_numeric; /* format string looks like numeric??? */
212     char timefmt[MAX_ID_LEN+1]; /* format string for input */
213     char formatstring[MAX_ID_LEN+1];
214                                 /* the format string for output */
215
216 /* ticmark control variables */
217     int ticmode;                /* tics on border/axis? mirrored? */
218     struct ticdef ticdef;       /* tic series definition */
219     int tic_rotate;             /* ticmarks rotated by this angle */
220     TBOOLEAN gridmajor;         /* Grid lines wanted on major tics? */
221     TBOOLEAN gridminor;         /* Grid lines for minor tics? */
222     int minitics;               /* minor tic mode (none/auto/user)? */
223     double mtic_freq;           /* minitic stepsize */
224     double ticscale;            /* scale factor for tic marks (was (0..1])*/
225     double miniticscale;        /* and for minitics */
226     TBOOLEAN tic_in;            /* tics to be drawn inward?  */
227
228 /* other miscellaneous fields */
229     text_label label;           /* label string and position offsets */
230     lp_style_type zeroaxis;     /* drawing style for zeroaxis, if any */
231 } AXIS;
232
233 #define DEFAULT_AXIS_TICDEF {TIC_COMPUTED, NULL, {TC_DEFAULT, 0, 0}, {NULL, {0,0}, FALSE},  { character, character, character, 0., 0., 0. }, FALSE }
234 # define DEFAULT_AXIS_ZEROAXIS {0, -3, 0, 1.0, 1.0, 0}
235
236 #define DEFAULT_AXIS_STRUCT {                                               \
237         AUTOSCALE_BOTH, AUTOSCALE_BOTH, /* auto, set_auto */                \
238         0, FALSE,               /* range_flags, rev_range */                \
239         -10.0, 10.0,            /* 3 pairs of min/max for axis itself */    \
240         -10.0, 10.0,                                                        \
241         -10.0, 10.0,                                                        \
242           0.0,  0.0,            /* and another min/max for the data */      \
243         0, 0, 0, 0,             /* terminal dependents */                   \
244         FALSE, 0.0, 0.0,        /* log, base, log(base) */                  \
245         0, 1,                   /* is_timedata, format_numeric */           \
246         DEF_FORMAT, TIMEFMT,    /* output format, timefmt */                \
247         NO_TICS,                /* tic output positions (border, mirror) */ \
248         DEFAULT_AXIS_TICDEF,    /* tic series definition */                 \
249         0, FALSE, FALSE,        /* tic_rotate, grid{major,minor} */         \
250         MINI_DEFAULT, 10,       /* minitics, mtic_freq */                   \
251         1.0, 0.5, TRUE,         /* ticscale, miniticscale, tic_in */        \
252         EMPTY_LABELSTRUCT,      /* axis label */                            \
253         DEFAULT_AXIS_ZEROAXIS   /* zeroaxis line style */                   \
254 }
255
256 /* Table of default behaviours --- a subset of the struct above. Only
257  * those fields are present that differ from axis to axis. */
258 typedef struct axis_defaults {
259     double min;                 /* default axis endpoints */
260     double max;
261     char name[4];               /* axis name, like in "x2" or "t" */
262     int ticmode;                /* tics on border/axis? mirrored? */
263 } AXIS_DEFAULTS;
264
265
266
267 /* global variables in axis.c */
268
269 extern AXIS axis_array[AXIS_ARRAY_SIZE];
270 extern const AXIS_DEFAULTS axis_defaults[AXIS_ARRAY_SIZE];
271
272 /* A parsing table for mapping axis names into axis indices. For use
273  * by the set/show machinery, mainly */
274 extern const struct gen_table axisname_tbl[AXIS_ARRAY_SIZE+1];
275
276
277 extern const struct ticdef default_axis_ticdef;
278
279 /* default format for tic mark labels */
280 #define DEF_FORMAT "% g"
281
282 /* default parse timedata string */
283 #define TIMEFMT "%d/%m/%y,%H:%M"
284
285 /* axis labels */
286 extern const text_label default_axis_label;
287
288 /* zeroaxis linetype (flag type==-3 if none wanted) */
289 extern const lp_style_type default_axis_zeroaxis;
290
291 /* default grid linetype, to be used by 'unset grid' and 'reset' */
292 extern const struct lp_style_type default_grid_lp;
293
294 /* grid layer: -1 default, 0 back, 1 front */
295 extern int grid_layer;
296
297 /* global variables for communication with the tic callback functions */
298 /* FIXME HBB 20010806: had better be collected into a struct that's
299  * passed to the callback */
300 extern int tic_start, tic_direction, tic_mirror;
301 /* These are for passing on to write_multiline(): */
302 extern int tic_text, rotate_tics, tic_hjust, tic_vjust;
303 /* The remaining ones are for grid drawing; controlled by 'set grid': */
304 /* extern int grid_selection; --- comm'ed out, HBB 20010806 */
305 extern struct lp_style_type grid_lp; /* linestyle for major grid lines */
306 extern struct lp_style_type mgrid_lp; /* linestyle for minor grid lines */
307 extern double polar_grid_angle; /* angle step in polar grid in radians */
308
309 /* Length of the longest tics label, set by widest_tic_callback(): */
310 extern int widest_tic_strlen;
311
312 /* axes being used by the current plot */
313 extern AXIS_INDEX x_axis, y_axis, z_axis;
314 /* macros to reduce code clutter caused by the array notation, mainly
315  * in graphics.c and fit.c */
316 #define X_AXIS axis_array[x_axis]
317 #define Y_AXIS axis_array[y_axis]
318 #define Z_AXIS axis_array[z_axis]
319 #define CB_AXIS axis_array[COLOR_AXIS]
320
321 /* -------- macros using these variables: */
322
323 /* Macros to map from user to terminal coordinates and back */
324 #define AXIS_MAP(axis, variable)                \
325   (int) ((axis_array[axis].term_lower)          \
326          + ((variable) - axis_array[axis].min)  \
327          * axis_array[axis].term_scale + 0.5)
328 #define AXIS_MAPBACK(axis, pos)                                            \
329   (((double)(pos)-axis_array[axis].term_lower)/axis_array[axis].term_scale \
330    + axis_array[axis].min)
331
332 /* these are the old names for these: */
333 #define map_x(x) AXIS_MAP(x_axis, x)
334 #define map_y(y) AXIS_MAP(y_axis, y)
335
336 #define AXIS_SETSCALE(axis, out_low, out_high)                  \
337     axis_array[axis].term_scale = ((out_high) - (out_low))      \
338         / (axis_array[axis].max - axis_array[axis].min)
339
340 /* write current min/max_array contents into the set/show status
341  * variables */
342 #define AXIS_WRITEBACK(axis)                    \
343 do {                                            \
344     AXIS *this = axis_array + axis;             \
345                                                 \
346     if (this->range_flags & RANGE_WRITEBACK) {  \
347         if (this->autoscale & AUTOSCALE_MIN)    \
348             this->set_min = this->min;          \
349         if (this->autoscale & AUTOSCALE_MAX)    \
350             this->set_max = this->max;          \
351     }                                           \
352 } while(0)
353
354 /* HBB 20000430: New macros, logarithmize a value into a stored
355  * coordinate*/
356 #define AXIS_DO_LOG(axis,value) (log(value) / axis_array[axis].log_base)
357 #define AXIS_UNDO_LOG(axis,value) exp((value) * axis_array[axis].log_base)
358
359 /* HBB 20000430: same, but these test if the axis is log, first: */
360 #define AXIS_LOG_VALUE(axis,value)                              \
361     (axis_array[axis].log ? AXIS_DO_LOG(axis,value) : (value))
362 #define AXIS_DE_LOG_VALUE(axis,coordinate)                                \
363     (axis_array[axis].log ? AXIS_UNDO_LOG(axis,coordinate): (coordinate))
364
365
366 /* copy scalar data to arrays. The difference between 3D and 2D
367  * versions is: dont know we have to support ranges [10:-10] - lets
368  * reverse it for now, then fix it at the end.  */
369 /* FIXME HBB 20000426: unknown if this distinction makes any sense... */
370 #define AXIS_INIT3D(axis, islog_override, infinite)                     \
371 do {                                                                    \
372     AXIS *this = axis_array + axis;                                     \
373                                                                         \
374     this->autoscale = this->set_autoscale;                              \
375     if ((this->autoscale & AUTOSCALE_BOTH) == AUTOSCALE_NONE            \
376         && this->set_max < this->set_min) {                             \
377         this->min = this->set_max;                                      \
378         this->max = this->set_min;                                      \
379         /* we will fix later */                                         \
380     } else {                                                            \
381         this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN)) \
382             ? VERYLARGE : this->set_min;                                \
383         this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX)) \
384             ? -VERYLARGE : this->set_max;                               \
385     }                                                                   \
386     if (islog_override) {                                               \
387         this->log = 0;                                                  \
388         this->base = 1;                                                 \
389         this->log_base = 0;                                             \
390     } else {                                                            \
391         this->log_base = this->log ? log(this->base) : 0;               \
392     }                                                                   \
393     this->data_min = VERYLARGE;                                         \
394     this->data_max = -VERYLARGE;                                        \
395 } while(0)
396
397 #define AXIS_INIT2D(axis, infinite)                                     \
398 do {                                                                    \
399     AXIS *this = axis_array + axis;                                     \
400                                                                         \
401     this->autoscale = this->set_autoscale;                              \
402     this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN))     \
403         ? VERYLARGE : this->set_min;                                    \
404     this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX))     \
405         ? -VERYLARGE : this->set_max;                                   \
406     this->log_base = this->log ? log(this->base) : 0;                   \
407     this->data_min = VERYLARGE;                                         \
408     this->data_max = -VERYLARGE;                                        \
409 } while(0)
410
411 /* handle reversed ranges */
412 #define CHECK_REVERSE(axis) do {                                        \
413     AXIS *this = axis_array + axis;                                     \
414                                                                         \
415     if (((this->autoscale & AUTOSCALE_BOTH) == AUTOSCALE_NONE)          \
416         && (this->max < this->min)) {                                   \
417         double temp = this->min;                                        \
418                                                                         \
419         this->min = this->max;                                          \
420         this->max = temp;                                               \
421         this->range_is_reverted = 1;                                    \
422     } else                                                              \
423         this->range_is_reverted = (this->range_flags & RANGE_REVERSE);  \
424 } while(0)
425
426 /* HBB NEW 20050316: macros to always access the actual minimum, even
427  * if 'set view map' or something else flipped things around behind
428  * our back */
429 #define AXIS_ACTUAL_MIN(axis)                           \
430     (axis_array[axis].range_flags & RANGE_REVERSE       \
431      ? axis_array[axis].max : axis_array[axis].min)
432
433 #define AXIS_ACTUAL_MAX(axis)                           \
434     (axis_array[axis].range_flags & RANGE_REVERSE       \
435      ? axis_array[axis].min : axis_array[axis].max)
436
437 /* HBB 20000725: new macro, built upon ULIG's SAVE_WRITEBACK(axis),
438  * but easier to use. Code like this occured twice, in plot2d and
439  * plot3d: */
440 #define SAVE_WRITEBACK_ALL_AXES                                 \
441 do {                                                            \
442     AXIS_INDEX axis;                                            \
443                                                                 \
444     for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)              \
445         if(axis_array[axis].range_flags & RANGE_WRITEBACK) {    \
446             set_writeback_min(axis);                            \
447             set_writeback_max(axis);                            \
448         }                                                       \
449 } while(0)
450
451 /* get optional [min:max] */
452 #define PARSE_RANGE(axis)                                                  \
453 do {                                                                       \
454     if (equals(c_token, "[")) {                                            \
455         c_token++;                                                         \
456         axis_array[axis].autoscale =                                       \
457             load_range(axis, &axis_array[axis].min, &axis_array[axis].max, \
458                        axis_array[axis].autoscale);                        \
459         if (!equals(c_token, "]"))                                         \
460             int_error(c_token, "']' expected");                            \
461         c_token++;                                                         \
462     }                                                                      \
463 } while (0)
464
465 /* HBB 20000430: new macro, like PARSE_RANGE, but for named ranges as
466  * in 'plot [phi=3.5:7] sin(phi)' */
467 #define PARSE_NAMED_RANGE(axis, dummy_token)                                 \
468 do {                                                                         \
469     if (equals(c_token, "[")) {                                              \
470         c_token++;                                                           \
471         if (isletter(c_token)) {                                             \
472             if (equals(c_token + 1, "=")) {                                  \
473                 dummy_token = c_token;                                       \
474                 c_token += 2;                                                \
475             }                                                                \
476                 /* oops; probably an expression with a variable: act         \
477                  * as if no variable name had been seen, by                  \
478                  * fallthrough */                                            \
479         }                                                                    \
480         axis_array[axis].autoscale = load_range(axis, &axis_array[axis].min, \
481                                       &axis_array[axis].max,                 \
482                                       axis_array[axis].autoscale);           \
483         if (!equals(c_token, "]"))                                           \
484             int_error(c_token, "']' expected");                              \
485         c_token++;                                                           \
486     }                           /* first '[' */                              \
487 } while (0)
488
489 /* parse a position of the form
490  *    [coords] x, [coords] y {,[coords] z}
491  * where coords is one of first,second.graph,screen,character
492  * if first or second, we need to take axis_is_timedata into account
493  */
494 #define GET_NUMBER_OR_TIME(store,axes,axis)                             \
495 do {                                                                    \
496     if (((axes) >= 0) && (axis_array[(axes)+(axis)].is_timedata)        \
497         && isstringvalue(c_token)) {                                    \
498         struct tm tm;                                                   \
499         char *ss = try_to_get_string();                                 \
500         if (gstrptime(ss,axis_array[axis].timefmt,&tm))                 \
501             (store) = (double) gtimegm(&tm);                            \
502         free(ss);                                                       \
503     } else {                                                            \
504         struct value value;                                             \
505         (store) = real(const_express(&value));                          \
506     }                                                                   \
507 } while(0)
508
509 /* This is one is very similar to GET_NUMBER_OR_TIME, but has slightly
510  * different usage: it writes out '0' in case of inparsable time data,
511  * and it's used when the target axis is fixed without a 'first' or
512  * 'second' keyword in front of it. */
513 #define GET_NUM_OR_TIME(store,axis)                     \
514 do {                                                    \
515     (store) = 0;                                        \
516     GET_NUMBER_OR_TIME(store, FIRST_AXES, axis);        \
517 } while (0);
518
519 /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
520  * Do OUT_ACTION or UNDEF_ACTION as appropriate
521  * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
522  * VALUE must not be same as STORE
523  * Note: see the particular implementation for COLOR AXIS below.
524  */
525
526 #define STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS,         \
527                                        OUT_ACTION, UNDEF_ACTION)          \
528 do {                                                                      \
529     /* HBB 20000726: new check, to avoid crashes with axis index -1 */    \
530     if (AXIS==-1)                                                         \
531         break;                                                            \
532     /* HBB 20040304: new check to avoid storing infinities and NaNs */    \
533     if (! (VALUE > -VERYLARGE && VALUE < VERYLARGE)) {                    \
534         TYPE = UNDEFINED;                                                 \
535         UNDEF_ACTION;                                                     \
536         break;                                                            \
537     }                                                                     \
538     if (axis_array[AXIS].log) {                                           \
539         if (VALUE<0.0) {                                                  \
540             TYPE = UNDEFINED;                                             \
541             UNDEF_ACTION;                                                 \
542             break;                                                        \
543         } else if (VALUE == 0.0) {                                        \
544             STORE = -VERYLARGE;                                           \
545             TYPE = OUTRANGE;                                              \
546             OUT_ACTION;                                                   \
547             break;                                                        \
548         } else {                                                          \
549             STORE = AXIS_DO_LOG(AXIS,VALUE);                              \
550         }                                                                 \
551     } else                                                                \
552         STORE = VALUE;                                                    \
553     if (TYPE != INRANGE)                                                  \
554         break;  /* don't set y range if x is outrange, for example */     \
555     if ((int)AXIS < 0)                                                    \
556         break;  /* HBB 20000507: don't check range if not a coordinate */ \
557     if ( VALUE<axis_array[AXIS].data_min )                                \
558         axis_array[AXIS].data_min = VALUE;                                \
559     if ( VALUE<axis_array[AXIS].min ) {                                   \
560         if (axis_array[AXIS].autoscale & AUTOSCALE_MIN)                   \
561             axis_array[AXIS].min = VALUE;                                 \
562         else {                                                            \
563             TYPE = OUTRANGE;                                              \
564             OUT_ACTION;                                                   \
565             break;                                                        \
566         }                                                                 \
567     }                                                                     \
568     if ( VALUE>axis_array[AXIS].data_max )                                \
569         axis_array[AXIS].data_max = VALUE;                                \
570     if ( VALUE>axis_array[AXIS].max ) {                                   \
571         if (axis_array[AXIS].autoscale & AUTOSCALE_MAX)                   \
572             axis_array[AXIS].max = VALUE;                                 \
573         else {                                                            \
574             TYPE = OUTRANGE;                                              \
575             OUT_ACTION;                                                   \
576         }                                                                 \
577     }                                                                     \
578 } while(0)
579
580 /* Implementation of the above for the color axis. It should not change
581  * the type of the point (out-of-range color is plotted with the color
582  * of the min or max color value).
583  */
584 #define COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS,   \
585                                        OUT_ACTION, UNDEF_ACTION)          \
586 {                                                                         \
587     int c_type_tmp = TYPE;                                                \
588     STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, c_type_tmp, AXIS,       \
589                                        OUT_ACTION, UNDEF_ACTION);         \
590 }
591
592 /* Empty macro arguments triggered NeXT cpp bug       */
593 /* #define NOOP (0) caused many warnings from gcc 3.2 */
594 /* Now trying ((void)0) */
595 #define NOOP ((void)0)
596
597 /* HBB 20000506: new macro, initializes one variable to the same
598  * value, for all axes. */
599 #define INIT_AXIS_ARRAY(field, value)           \
600 do {                                            \
601     int tmp;                                    \
602     for (tmp=0; tmp<AXIS_ARRAY_SIZE; tmp++)     \
603         axis_array[tmp].field=(value);          \
604 } while(0)
605
606 /* HBB 20000506: new macro to automatically build intializer lists
607  * for arrays of AXIS_ARRAY_SIZE equal elements */
608 #define AXIS_ARRAY_INITIALIZER(value) {                 \
609     value, value, value, value, value,                  \
610         value, value, value, value, value, value }
611
612 /* used by set.c */
613 #define SET_DEFFORMAT(axis, flag_array)                         \
614         if (flag_array[axis]) {                                 \
615             (void) strcpy(axis_array[axis].formatstring,DEF_FORMAT);    \
616             axis_array[axis].format_is_numeric = 1;             \
617         }
618
619
620 /* 'roundoff' check tolerance: less than one hundredth of a tic mark */
621 #define SIGNIF (0.01)
622 /* (DFK) Watch for cancellation error near zero on axes labels */
623 /* FIXME HBB 20000521: these seem not to be used much, anywhere... */
624 #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
625
626
627 /* ------------ functions exported by axis.c */
628 t_autoscale load_range __PROTO((AXIS_INDEX, double *, double *, t_autoscale));
629 void axis_unlog_interval __PROTO((AXIS_INDEX, double *, double *, TBOOLEAN));
630 void axis_revert_and_unlog_range __PROTO((AXIS_INDEX));
631 double axis_log_value_checked __PROTO((AXIS_INDEX, double, const char *));
632 void axis_checked_extend_empty_range __PROTO((AXIS_INDEX, const char *mesg));
633 char * copy_or_invent_formatstring __PROTO((AXIS_INDEX));
634 double quantize_normal_tics __PROTO((double, int));
635 void setup_tics __PROTO((AXIS_INDEX, int));
636 void gen_tics __PROTO((AXIS_INDEX, /* int, */ tic_callback));
637 void axis_output_tics __PROTO((AXIS_INDEX, int *, AXIS_INDEX, tic_callback));
638 void axis_set_graphical_range __PROTO((AXIS_INDEX, unsigned int lower, unsigned int upper));
639 void axis_draw_2d_zeroaxis __PROTO((AXIS_INDEX, AXIS_INDEX));
640 TBOOLEAN some_grid_selected __PROTO((void));
641 void add_tic_user __PROTO((AXIS_INDEX, char *, double, int));
642
643 double get_writeback_min __PROTO((AXIS_INDEX));
644 double get_writeback_max __PROTO((AXIS_INDEX));
645 void set_writeback_min __PROTO((AXIS_INDEX));
646 void set_writeback_max __PROTO((AXIS_INDEX));
647
648 /* set widest_tic_label: length of the longest tics label */
649 void widest_tic_callback __PROTO((AXIS_INDEX, double place, char *text, struct lp_style_type grid));
650
651 void get_position __PROTO((struct position *pos));
652 void get_position_default __PROTO((struct position *pos, enum position_type default_type));
653
654 /* ------------ autoscaling of the color axis */
655 #define NEED_PALETTE(plot) \
656    (PM3DSURFACE == (plot)->plot_style \
657     || PM3D_IMPLICIT == pm3d.implicit \
658     || 1 == (plot)->lp_properties.use_palette)
659 int set_cbminmax __PROTO((void));
660
661 #endif /* GNUPLOT_AXIS_H */