1 /*[
2  * Copyright 2000, 2004   Thomas Williams, Colin Kelley
3  *
4  * Permission to use, copy, and distribute this software and its
5  * documentation for any purpose with or without fee is hereby granted,
6  * provided that the above copyright notice appear in all copies and
7  * that both that copyright notice and this permission notice appear
8  * in supporting documentation.
9  *
10  * Permission to modify the software is granted, but not the right to
11  * distribute the complete modified source code.  Modifications are to
12  * be distributed as patches to the released version.  Permission to
13  * distribute binaries produced by compiling modified sources is granted,
14  * provided you
15  *   1. distribute the corresponding source modifications from the
16  *    released version in the form of a patch file along with the binaries,
17  *   2. add special version identification to distinguish your version
18  *    in addition to the base release version number,
19  *   3. provide your name and address as the primary contact for the
20  *    support of your modified version, and
21  *   4. retain our contact information in regard to use of the base
22  *    software.
23  * Permission to distribute the released version of the source code along
24  * with corresponding source modifications in the form of a patch file is
25  * granted with same provisions 2 through 4 for binary distributions.
26  *
27  * This software is provided "as is" without express or implied warranty
28  * to the extent permitted by applicable law.
29 ]*/
30 
31 #ifndef GNUPLOT_AXIS_H
32 #define GNUPLOT_AXIS_H
33 
34 /* Aug 2017 - unconditional support for nonlinear axes */
35 # define nonlinear(axis) ((axis)->linked_to_primary != NULL && (axis)->link_udf->at != NULL)
36 # define invalid_coordinate(x,y) ((unsigned)(x)==intNaN || (unsigned)(y)==intNaN)
37 
38 #include <stddef.h>		/* for offsetof() */
39 #include "gp_types.h"		/* for TBOOLEAN */
40 
41 #include "gadgets.h"
42 #include "parse.h"		/* for const_*() */
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 
58 typedef enum AXIS_INDEX {
59     NO_AXIS = -2,
60     ALL_AXES = -1,
61     FIRST_Z_AXIS = 0,
62 #define FIRST_AXES FIRST_Z_AXIS
63     FIRST_Y_AXIS,
64     FIRST_X_AXIS,
65     COLOR_AXIS,			/* fill gap */
66     SECOND_Z_AXIS,		/* not used, yet */
67 #define SECOND_AXES SECOND_Z_AXIS
68     SAMPLE_AXIS=SECOND_Z_AXIS,
69     SECOND_Y_AXIS,
70     SECOND_X_AXIS,
71     POLAR_AXIS,
72 #define NUMBER_OF_MAIN_VISIBLE_AXES (POLAR_AXIS + 1)
73     T_AXIS,
74     U_AXIS,
75     V_AXIS,		/* Last index into axis_array[] */
76     PARALLEL_AXES,	/* Parallel axis structures are allocated dynamically */
77     THETA_index = 1234,	/* Used to identify THETA_AXIS */
78 
79     AXIS_ARRAY_SIZE = PARALLEL_AXES
80 } AXIS_INDEX;
81 
82 
83 /* sample axis doesn't need mtics, so use the slot to hold sample interval */
84 # define SAMPLE_INTERVAL mtic_freq
85 
86 /* What kind of ticmarking is wanted? */
87 typedef enum en_ticseries_type {
88     TIC_COMPUTED=1, 		/* default; gnuplot figures them */
89     TIC_SERIES,			/* user-defined series */
90     TIC_USER,			/* user-defined points */
91     TIC_MONTH,   		/* print out month names ((mo-1)%12)+1 */
92     TIC_DAY      		/* print out day of week */
93 } t_ticseries_type;
94 
95 /* Defines one ticmark for TIC_USER style.
96  * If label==NULL, the value is printed with the usual format string.
97  * else, it is used as the format string (note that it may be a constant
98  * string, like "high" or "low").
99  */
100 typedef struct ticmark {
101     double position;		/* where on axis is this */
102     char *label;		/* optional (format) string label */
103     int level;			/* 0=major tic, 1=minor tic */
104     struct ticmark *next;	/* linked list */
105 } ticmark;
106 
107 /* Tic-mark labelling definition; see set xtics */
108 typedef struct ticdef {
109     t_ticseries_type type;
110     char *font;
111     struct t_colorspec textcolor;
112     struct {
113 	   struct ticmark *user;	/* for TIC_USER */
114 	   struct {			/* for TIC_SERIES */
115 		  double start, incr;
116 		  double end;		/* ymax, if VERYLARGE */
117 	   } series;
118 	   TBOOLEAN mix;		/* TRUE to use both the above */
119     } def;
120     struct position offset;
121     TBOOLEAN rangelimited;		/* Limit tics to data range */
122     TBOOLEAN enhanced;			/* Use enhanced text mode or labels */
123     TBOOLEAN logscaling;		/* place tics using old logscale algorithm */
124 } t_ticdef;
125 
126 /* we want two auto modes for minitics - default where minitics are
127  * auto for log/time and off for linear, and auto where auto for all
128  * graphs I've done them in this order so that logscale-mode can
129  * simply test bit 0 to see if it must do the minitics automatically.
130  * similarly, conventional plot can test bit 1 to see if minitics are
131  * required */
132 typedef enum en_minitics_status {
133     MINI_OFF,
134     MINI_DEFAULT,
135     MINI_USER,
136     MINI_AUTO
137 } t_minitics_status;
138 
139 /* Values to put in the axis_tics[] variables that decides where the
140  * ticmarks should be drawn: not at all, on one or both plot borders,
141  * or the zeroaxes. These look like a series of values, but TICS_MASK
142  * shows that they're actually bit masks --> don't turn into an enum
143  * */
144 #define NO_TICS        0
145 #define TICS_ON_BORDER 1
146 #define TICS_ON_AXIS   2
147 #define TICS_MASK      3
148 #define TICS_MIRROR    4
149 
150 /* Tic levels 0 and 1 are maintained in the axis structure.
151  * Tic levels 2 - MAX_TICLEVEL have only one property - scale.
152  */
153 #define MAX_TICLEVEL 5
154 extern double ticscale[MAX_TICLEVEL];
155 
156 /* HBB 20010610: new type for storing autoscale activity. Effectively
157  * two booleans (bits) in a single variable, so I'm using an enum with
158  * all 4 possible bit masks given readable names. */
159 typedef enum e_autoscale {
160     AUTOSCALE_NONE = 0,
161     AUTOSCALE_MIN = 1<<0,
162     AUTOSCALE_MAX = 1<<1,
163     AUTOSCALE_BOTH = (1<<0 | 1 << 1),
164     AUTOSCALE_FIXMIN = 1<<2,
165     AUTOSCALE_FIXMAX = 1<<3
166 } t_autoscale;
167 
168 typedef enum e_constraint {
169     CONSTRAINT_NONE  = 0,
170     CONSTRAINT_LOWER = 1<<0,
171     CONSTRAINT_UPPER = 1<<1,
172     CONSTRAINT_BOTH  = (1<<0 | 1<<1)
173 } t_constraint;
174 
175 /* The unit the tics of a given time/date axis are to interpreted in */
176 /* HBB 20040318: start at one, to avoid undershoot */
177 typedef enum e_timelevel {
178     TIMELEVEL_SECONDS = 1, TIMELEVEL_MINUTES, TIMELEVEL_HOURS,
179     TIMELEVEL_DAYS, TIMELEVEL_WEEKS, TIMELEVEL_MONTHS,
180     TIMELEVEL_YEARS
181 } t_timelevel;
182 
183 typedef struct axis {
184 /* range of this axis */
185     t_autoscale autoscale;	/* Which end(s) are autoscaled? */
186     t_autoscale set_autoscale;	/* what does 'set' think autoscale to be? */
187     int range_flags;		/* flag bits about autoscale/writeback: */
188     /* write auto-ed ranges back to variables for autoscale */
189 #define RANGE_WRITEBACK   1
190 #define RANGE_SAMPLED     2
191 #define RANGE_IS_REVERSED 4
192     double min;			/* 'transient' axis extremal values */
193     double max;
194     double set_min;		/* set/show 'permanent' values */
195     double set_max;
196     double writeback_min;	/* ULIG's writeback implementation */
197     double writeback_max;
198     double data_min;		/* Not necessarily the same as axis min */
199     double data_max;
200 
201 /* range constraints */
202     t_constraint min_constraint;
203     t_constraint max_constraint;
204     double min_lb, min_ub;     /* min lower- and upper-bound */
205     double max_lb, max_ub;     /* min lower- and upper-bound */
206 
207 /* output-related quantities */
208     int term_lower;		/* low and high end of the axis on output, */
209     int term_upper;		/* ... (in terminal coordinates)*/
210     double term_scale;		/* scale factor: plot --> term coords */
211     unsigned int term_zero;	/* position of zero axis */
212 
213 /* log axis control */
214     TBOOLEAN log;		/* log axis stuff: flag "islog?" */
215     double base;		/* logarithm base value */
216     double log_base;		/* ln(base), for easier computations */
217 
218 /* linked axis information (used only by x2, y2)
219  * If axes are linked, the primary axis info will be cloned into the
220  * secondary axis only up to this point in the structure.
221  */
222     struct axis *linked_to_primary;	/* Set only in a secondary axis */
223     struct axis *linked_to_secondary;	/* Set only in a primary axis */
224     struct udft_entry *link_udf;
225 
226 /* ticmark control variables */
227     int ticmode;		/* tics on border/axis? mirrored? */
228     struct ticdef ticdef;	/* tic series definition */
229     int tic_rotate;		/* ticmarks rotated by this angle */
230     enum JUSTIFY tic_pos;	/* left/center/right tic label justification */
231     TBOOLEAN gridmajor;		/* Grid lines wanted on major tics? */
232     TBOOLEAN gridminor;		/* Grid lines for minor tics? */
233     t_minitics_status minitics;	/* minor tic mode (none/auto/user)? */
234     double mtic_freq;		/* minitic stepsize */
235     double ticscale;		/* scale factor for tic marks (was (0..1])*/
236     double miniticscale;	/* and for minitics */
237     double ticstep;		/* increment used to generate tic placement */
238     TBOOLEAN tic_in;		/* tics to be drawn inward?  */
239 
240 /* time/date axis control */
241     td_type datatype;		/* {DT_NORMAL|DT_TIMEDATE} controls _input_ */
242     td_type tictype;		/* {DT_NORMAL|DT_TIMEDATE|DT_DMS} controls _output_ */
243     char *formatstring;		/* the format string for output */
244     char *ticfmt;		/* autogenerated alternative to formatstring (needed??) */
245     t_timelevel timelevel;	/* minimum time unit used to quantize ticks */
246 
247 /* other miscellaneous fields */
248     int index;			/* if this is a permanent axis, this indexes axis_array[] */
249 				/* (index >= PARALLEL_AXES) indexes parallel axes */
250 				/* (index < 0) indicates a dynamically allocated structure */
251     text_label label;		/* label string and position offsets */
252     TBOOLEAN manual_justify;	/* override automatic justification */
253     lp_style_type *zeroaxis;	/* usually points to default_axis_zeroaxis */
254     double paxis_x;		/* x coordinate of parallel axis */
255 } AXIS;
256 
257 #define DEFAULT_AXIS_TICDEF {TIC_COMPUTED, NULL, {TC_DEFAULT, 0, 0.0}, {NULL, {0.,0.,0.}, FALSE},  { character, character, character, 0., 0., 0. }, FALSE, TRUE, FALSE }
258 #define DEFAULT_AXIS_ZEROAXIS {0, LT_AXIS, 0, DASHTYPE_AXIS, 0, 0, 1.0, PTSZ_DEFAULT, DEFAULT_P_CHAR, BLACK_COLORSPEC, DEFAULT_DASHPATTERN}
259 
260 #define DEFAULT_AXIS_STRUCT {						    \
261 	AUTOSCALE_BOTH, AUTOSCALE_BOTH, /* auto, set_auto */		    \
262 	0, 			/* range_flags for autoscaling */	    \
263 	-10.0, 10.0,		/* 3 pairs of min/max for axis itself */    \
264 	-10.0, 10.0,							    \
265 	-10.0, 10.0,							    \
266 	  0.0,  0.0,		/* and another min/max for the data */	    \
267 	CONSTRAINT_NONE, CONSTRAINT_NONE,  /* min and max constraints */    \
268 	0., 0., 0., 0.,         /* lower and upper bound for min and max */ \
269 	0, 0,   		/* terminal lower and upper coords */	    \
270 	0.,        		/* terminal scale */			    \
271 	0,        		/* zero axis position */		    \
272 	FALSE, 10.0, 0.0,	/* log, base, log(base) */		    \
273 	NULL, NULL,		/* linked_to_primary, linked_to_secondary */\
274 	NULL,      		/* link function */                         \
275 	NO_TICS,		/* tic output positions (border, mirror) */ \
276 	DEFAULT_AXIS_TICDEF,	/* tic series definition */		    \
277 	0, CENTRE,	 	/* tic_rotate, horizontal justification */  \
278 	FALSE, FALSE,	 	/* grid{major,minor} */			    \
279 	MINI_DEFAULT, 10.,	/* minitics, mtic_freq */		    \
280 	1.0, 0.5, 0.0, TRUE,	/* ticscale, miniticscale, ticstep, tic_in */ \
281 	DT_NORMAL, DT_NORMAL,	/* datatype for input, output */	    \
282 	NULL, NULL,      	/* output format, another output format */  \
283 	0,			/* timelevel */                             \
284 	0,			/* index (e.g.FIRST_Y_AXIS) */		    \
285 	EMPTY_LABELSTRUCT,	/* axis label */			    \
286 	FALSE,			/* override automatic justification */	    \
287 	NULL			/* NULL means &default_axis_zeroaxis */	    \
288 }
289 
290 /* This much of the axis structure is cloned by the "set x2range link" command */
291 #define AXIS_CLONE_SIZE offsetof(AXIS, linked_to_primary)
292 
293 /* Table of default behaviours --- a subset of the struct above. Only
294  * those fields are present that differ from axis to axis. */
295 typedef struct axis_defaults {
296     double min;			/* default axis endpoints */
297     double max;
298     char name[4];		/* axis name, like in "x2" or "t" */
299     int ticmode;		/* tics on border/axis? mirrored? */
300 } AXIS_DEFAULTS;
301 
302 /* global variables in axis.c */
303 
304 extern AXIS axis_array[AXIS_ARRAY_SIZE];
305 extern AXIS *shadow_axis_array;
306 extern const AXIS_DEFAULTS axis_defaults[AXIS_ARRAY_SIZE];
307 extern const AXIS default_axis_state;
308 
309 /* Dynamic allocation of parallel axis structures */
310 extern AXIS *parallel_axis_array;
311 extern int num_parallel_axes;
312 
313 /* A parsing table for mapping axis names into axis indices. For use
314  * by the set/show machinery, mainly */
315 extern const struct gen_table axisname_tbl[];
316 
317 
318 extern const struct ticdef default_axis_ticdef;
319 
320 /* default format for tic mark labels */
321 #define DEF_FORMAT "% h"
322 #define DEF_FORMAT_LATEX "$%h$"
323 
324 /* default parse timedata string */
325 #define TIMEFMT "%d/%m/%y,%H:%M"
326 extern char *timefmt;
327 
328 /* axis labels */
329 extern const text_label default_axis_label;
330 
331 /* zeroaxis linetype (flag type==-3 if none wanted) */
332 extern const lp_style_type default_axis_zeroaxis;
333 
334 /* default grid linetype, to be used by 'unset grid' and 'reset' */
335 extern const struct lp_style_type default_grid_lp;
336 
337 /* grid layer: LAYER_BEHIND LAYER_BACK LAYER_FRONT */
338 extern int grid_layer;
339 
340 /* Whether to draw the axis tic labels and tic marks in front of everything else */
341 extern TBOOLEAN grid_tics_in_front;
342 
343 /* Whether to draw vertical grid lines in 3D */
344 extern TBOOLEAN grid_vertical_lines;
345 
346 /* Whether to draw a grid in spiderplots */
347 extern TBOOLEAN grid_spiderweb;
348 
349 /* Whether or not to draw a separate polar axis in polar mode */
350 extern TBOOLEAN raxis;
351 
352 /* global variables for communication with the tic callback functions */
353 /* FIXME HBB 20010806: had better be collected into a struct that's
354  * passed to the callback */
355 extern int tic_start, tic_direction, tic_mirror;
356 /* These are for passing on to write_multiline(): */
357 extern int tic_text, rotate_tics, tic_hjust, tic_vjust;
358 /* The remaining ones are for grid drawing; controlled by 'set grid': */
359 /* extern int grid_selection; --- comm'ed out, HBB 20010806 */
360 extern struct lp_style_type grid_lp; /* linestyle for major grid lines */
361 extern struct lp_style_type mgrid_lp; /* linestyle for minor grid lines */
362 
363 extern double polar_grid_angle; /* angle step in polar grid in radians */
364 extern double theta_origin;	/* 0 = right side of plot */
365 extern double theta_direction;	/* 1 = counterclockwise -1 = clockwise */
366 
367 /* Length of the longest tics label, set by widest_tic_callback(): */
368 extern int widest_tic_strlen;
369 
370 /* flag to indicate that in-line axis ranges should be ignored */
371 extern TBOOLEAN inside_zoom;
372 
373 /* axes being used by the current plot */
374 extern AXIS_INDEX x_axis, y_axis, z_axis;
375 
376 extern struct axis THETA_AXIS;
377 
378 /* macros to reduce code clutter caused by the array notation, mainly
379  * in graphics.c and fit.c */
380 #define X_AXIS axis_array[x_axis]
381 #define Y_AXIS axis_array[y_axis]
382 #define Z_AXIS axis_array[z_axis]
383 #define R_AXIS axis_array[POLAR_AXIS]
384 #define CB_AXIS axis_array[COLOR_AXIS]
385 
386 /* -------- macros using these variables: */
387 
388 /* Macros to map from user to terminal coordinates and back */
389 #define AXIS_MAP(axis, variable)        axis_map(        &axis_array[axis], variable)
390 #define AXIS_MAP_DOUBLE(axis, variable) axis_map_double( &axis_array[axis], variable)
391 #define AXIS_MAPBACK(axis, pos)         axis_mapback(    &axis_array[axis], pos)
392 
393 /* Same thing except that "axis" is a pointer, not an index */
394 #define axis_map_double(axis, variable)         \
395     ((axis)->term_lower + ((variable) - (axis)->min) * (axis)->term_scale)
396 #define axis_map_toint(x) (int)( (x) + 0.5 )
397 #define axis_map(axis, variable) axis_map_toint( axis_map_double(axis, variable) )
398 
399 #define axis_mapback(axis, pos) \
400     (((double)(pos) - (axis)->term_lower)/(axis)->term_scale + (axis)->min)
401 
402 /* parse a position of the form
403  *    [coords] x, [coords] y {,[coords] z}
404  * where coords is one of first,second.graph,screen,character
405  * if first or second, we need to take axis.datatype into account
406  * FIXME: Cannot handle parallel axes
407  */
408 #define GET_NUMBER_OR_TIME(store,axes,axis)				\
409 do {									\
410     AXIS *this_axis = (axes == NO_AXIS) ? NULL				\
411 			    : &(axis_array[(axes)+(axis)]);		\
412     (store) = get_num_or_time(this_axis);				\
413 } while(0)
414 
415 
416 /*
417  * Gradually replacing extremely complex macro ACTUAL_STORE_AND_UPDATE_RANGE
418  * (called 50+ times) with a subroutine. The original logic was that in-line
419  * code was faster than calls to a subroutine, but on current hardware it is
420  * better to have one cached copy than to have 50 separate uncached copies.
421  *
422  * The difference between STORE_AND_UPDATE_RANGE and store_and_update_range
423  * is that the former takes an axis index and the latter an axis pointer.
424  */
425 #define STORE_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS, NOAUTOSCALE, UNDEF_ACTION)	 \
426  if (AXIS != NO_AXIS) do { \
427     if (store_and_update_range( &(STORE), VALUE, &(TYPE), (&axis_array[AXIS]), NOAUTOSCALE) \
428         == UNDEFINED) { \
429 	UNDEF_ACTION; \
430     } \
431 } while(0)
432 
433 /* Use NOOP for UNDEF_ACTION if no action is wanted */
434 #define NOOP ((void)0)
435 
436 
437 
438 /* HBB 20000506: new macro to automatically build initializer lists
439  * for arrays of AXIS_ARRAY_SIZE=11 equal elements */
440 #define AXIS_ARRAY_INITIALIZER(value) {			\
441     value, value, value, value, value,			\
442 	value, value, value, value, value, value }
443 
444 /* 'roundoff' check tolerance: less than one hundredth of a tic mark */
445 #define SIGNIF (0.01)
446 /* (DFK) Watch for cancellation error near zero on axes labels */
447 /* FIXME HBB 20000521: these seem not to be used much, anywhere... */
448 #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
449 
450 /* Function pointer type for callback functions to generate ticmarks */
451 typedef void (*tic_callback) (struct axis *, double, char *, int,
452 			struct lp_style_type, struct ticmark *);
453 
454 /* ------------ functions exported by axis.c */
455 coord_type store_and_update_range(double *store, double curval, coord_type *type,
456 				struct axis *axis, TBOOLEAN noautoscale);
457 void autoscale_one_point( struct axis *axis, double x );
458 t_autoscale load_range(struct axis *, double *, double *, t_autoscale);
459 void check_log_limits(struct axis *, double, double);
460 void axis_invert_if_requested(struct axis *);
461 void axis_check_range(AXIS_INDEX);
462 void axis_init(AXIS *this_axis, TBOOLEAN infinite);
463 void set_explicit_range(struct axis *axis, double newmin, double newmax);
464 double axis_log_value_checked(AXIS_INDEX, double, const char *);
465 void axis_checked_extend_empty_range(AXIS_INDEX, const char *mesg);
466 void axis_check_empty_nonlinear(struct axis *this_axis);
467 char * copy_or_invent_formatstring(struct axis *);
468 double quantize_normal_tics(double, int);
469 void setup_tics(struct axis *, int);
470 void gen_tics(struct axis *, tic_callback);
471 void axis_output_tics(AXIS_INDEX, int *, AXIS_INDEX, tic_callback);
472 void axis_set_scale_and_range(struct axis *axis, int lower, int upper);
473 void axis_draw_2d_zeroaxis(AXIS_INDEX, AXIS_INDEX);
474 TBOOLEAN some_grid_selected(void);
475 void add_tic_user(struct axis *, char *, double, int);
476 double get_num_or_time(struct axis *);
477 TBOOLEAN bad_axis_range(struct axis *axis);
478 
479 void save_writeback_all_axes(void);
480 int  parse_range(AXIS_INDEX axis);
481 void parse_skip_range(void);
482 void check_axis_reversed(AXIS_INDEX axis);
483 
484 /* set widest_tic_label: length of the longest tics label */
485 void widest_tic_callback(struct axis *, double place, char *text, int ticlevel,
486 			struct lp_style_type grid, struct ticmark *);
487 
488 void get_position(struct position *pos);
489 void get_position_default(struct position *pos, enum position_type default_type, int ndim);
490 
491 void gstrdms(char *label, char *format, double value);
492 
493 void clone_linked_axes(AXIS *axis1, AXIS *axis2);
494 AXIS *get_shadow_axis(AXIS *axis);
495 void extend_primary_ticrange(AXIS *axis);
496 void update_primary_axis_range(struct axis *secondary);
497 void update_secondary_axis_range(struct axis *primary);
498 void reconcile_linked_axes(AXIS *primary, AXIS *secondary);
499 
500 int map_x(double value);
501 int map_y(double value);
502 
503 double map_x_double(double value);
504 double map_y_double(double value);
505 
506 coord_type polar_to_xy( double theta, double r, double *x, double *y, TBOOLEAN update);
507 double polar_radius(double r);
508 
509 void set_cbminmax(void);
510 
511 void save_autoscaled_ranges(AXIS *, AXIS *);
512 void restore_autoscaled_ranges(AXIS *, AXIS *);
513 
514 char * axis_name(AXIS_INDEX);
515 void init_sample_range(AXIS *axis, enum PLOT_TYPE plot_type);
516 void init_parallel_axis(AXIS *, AXIS_INDEX);
517 void extend_parallel_axis(int);
518 
519 /* Evaluate the function linking a secondary axis to its primary axis */
520 double eval_link_function(AXIS *, double);
521 
522 /* For debugging */
523 void dump_axis_range(AXIS *axis);
524 
525 /* macro for tic scale, used in all tic_callback functions */
526 #define tic_scale(ticlevel, axis) \
527     (ticlevel <= 0 ? axis->ticscale : \
528      ticlevel == 1 ? axis->miniticscale : \
529      ticlevel < MAX_TICLEVEL ? ticscale[ticlevel] : \
530      0)
531 
532 /* convenience macro to make sure min < max */
533 #define reorder_if_necessary( min, max ) \
534 do { if (max < min) { double temp = min; min = max; max = temp; } \
535 } while (0)
536 
537 #endif /* GNUPLOT_AXIS_H */
538