File: axis.h

package info (click to toggle)
gnuplot 4.2.2-1.2
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 12,072 kB
  • ctags: 7,756
  • sloc: ansic: 77,004; lisp: 5,013; cpp: 3,357; sh: 1,195; makefile: 871; objc: 647; asm: 539; csh: 297; awk: 235; pascal: 194; perl: 52
file content (651 lines) | stat: -rw-r--r-- 24,010 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
/*
 * $Id: axis.h,v 1.46 2005/09/18 06:20:58 sfeam Exp $
 *
 */

/*[
 * 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.
]*/

#ifndef GNUPLOT_AXIS_H
#define GNUPLOT_AXIS_H

#include "gp_types.h"		/* for TBOOLEAN */

#include "gadgets.h"
#include "parse.h"		/* for const_express() */
#include "tables.h"		/* for the axis name parse table */
#include "term_api.h"		/* for lp_style_type */
#include "util.h"		/* for int_error() */

/* typedefs / #defines */

/* give some names to some array elements used in command.c and grap*.c
 * maybe one day the relevant items in setshow will also be stored
 * in arrays.
 *
 * Always keep the following conditions alive:
 * SECOND_X_AXIS = FIRST_X_AXIS + SECOND_AXES
 * FIRST_X_AXIS & SECOND_AXES == 0
 */
typedef enum AXIS_INDEX {
#define FIRST_AXES 0
    FIRST_Z_AXIS,
    FIRST_Y_AXIS,
    FIRST_X_AXIS,
    T_AXIS,			/* fill gap */
#define SECOND_AXES 4
    SECOND_Z_AXIS,		/* not used, yet */
    SECOND_Y_AXIS,
    SECOND_X_AXIS,
    R_AXIS,			/* never used ? */
    U_AXIS,			/* ditto */
    V_AXIS			/* ditto */
    ,COLOR_AXIS
} AXIS_INDEX;

# define AXIS_ARRAY_SIZE 11

/* What kind of ticmarking is wanted? */
typedef enum en_ticseries_type {
    TIC_COMPUTED=1, 		/* default; gnuplot figures them */
    TIC_SERIES,			/* user-defined series */
    TIC_USER,			/* user-defined points */
    TIC_MONTH,   		/* print out month names ((mo-1)%12)+1 */
    TIC_DAY      		/* print out day of week */
} t_ticseries_type;

/* Defines one ticmark for TIC_USER style.
 * If label==NULL, the value is printed with the usual format string.
 * else, it is used as the format string (note that it may be a constant
 * string, like "high" or "low").
 */
typedef struct ticmark {
    double position;		/* where on axis is this */
    char *label;		/* optional (format) string label */
    int level;			/* 0=major tic, 1=minor tic */
    struct ticmark *next;	/* linked list */
} ticmark;

/* Tic-mark labelling definition; see set xtics */
typedef struct ticdef {
    t_ticseries_type type;
    char *font;
    struct t_colorspec textcolor;
    struct {
	   struct ticmark *user;	/* for TIC_USER */
	   struct {			/* for TIC_SERIES */
		  double start, incr;
		  double end;		/* ymax, if VERYLARGE */
	   } series;
	   TBOOLEAN mix;		/* TRUE to use both the above */
    } def;
    struct position offset;
} t_ticdef;

/* we want two auto modes for minitics - default where minitics are
 * auto for log/time and off for linear, and auto where auto for all
 * graphs I've done them in this order so that logscale-mode can
 * simply test bit 0 to see if it must do the minitics automatically.
 * similarly, conventional plot can test bit 1 to see if minitics are
 * required */
enum en_minitics_status {
    MINI_OFF,
    MINI_DEFAULT,
    MINI_USER,
    MINI_AUTO
};

/* Function pointer type for callback functions doing operations for a
 * single ticmark */
typedef void (*tic_callback) __PROTO((AXIS_INDEX, double, char *, struct lp_style_type ));

/* Values to put in the axis_tics[] variables that decides where the
 * ticmarks should be drawn: not at all, on one or both plot borders,
 * or the zeroaxes. These look like a series of values, but TICS_MASK
 * shows that they're actually bit masks --> don't turn into an enum
 * */
#define NO_TICS        0
#define TICS_ON_BORDER 1
#define TICS_ON_AXIS   2
#define TICS_MASK      3
#define TICS_MIRROR    4


#if 0 /* HBB 20010806 --- move GRID flags into axis struct */
/* Need to allow user to choose grid at first and/or second axes tics.
 * Also want to let user choose circles at x or y tics for polar grid.
 * Also want to allow user rectangular grid for polar plot or polar
 * grid for parametric plot. So just go for full configurability.
 * These are bitmasks
 */
#define GRID_OFF    0
#define GRID_X      (1<<0)
#define GRID_Y      (1<<1)
#define GRID_Z      (1<<2)
#define GRID_X2     (1<<3)
#define GRID_Y2     (1<<4)
#define GRID_MX     (1<<5)
#define GRID_MY     (1<<6)
#define GRID_MZ     (1<<7)
#define GRID_MX2    (1<<8)
#define GRID_MY2    (1<<9)
#define GRID_CB     (1<<10)
#define GRID_MCB    (1<<11)
#endif /* 0 */

/* HBB 20010610: new type for storing autoscale activity. Effectively
 * two booleans (bits) in a single variable, so I'm using an enum with
 * all 4 possible bit masks given readable names. */
typedef enum e_autoscale {
    AUTOSCALE_NONE = 0,
    AUTOSCALE_MIN = 1<<0,
    AUTOSCALE_MAX = 1<<1,
    AUTOSCALE_BOTH = (1<<0 | 1 << 1),
    AUTOSCALE_FIXMIN = 1<<2,
    AUTOSCALE_FIXMAX = 1<<3
} t_autoscale;


/* FIXME 20000725: collect some of those various TBOOLEAN fields into
 * a larger int (or -- shudder -- a bitfield?) */
typedef struct axis {
/* range of this axis */
    t_autoscale autoscale;	/* Which end(s) are autoscaled? */
    t_autoscale set_autoscale;	/* what does 'set' think autoscale to be? */
    int range_flags;		/* flag bits about autoscale/writeback: */
    /* write auto-ed ranges back to variables for autoscale */
#define RANGE_WRITEBACK 1
    /* allow auto and reversed ranges */
#define RANGE_REVERSE   2
    TBOOLEAN range_is_reverted;	/* range [high:low] silently reverted? */
    double min;			/* 'transient' axis extremal values */
    double max;
    double set_min;		/* set/show 'permanent' values */
    double set_max;
    double writeback_min;	/* ULIG's writeback implementation */
    double writeback_max;

/* output-related quantities */
    int term_lower;		/* low and high end of the axis on output, */
    int term_upper;		/* ... (in terminal coordinates)*/
    double term_scale;		/* scale factor: plot --> term coords */
    unsigned int term_zero;	/* position of zero axis */

/* log axis control */
    TBOOLEAN log;		/* log axis stuff: flag "islog?" */
    double base;		/* logarithm base value */
    double log_base;		/* ln(base), for easier computations */

/* time/date axis control */
    TBOOLEAN is_timedata;	/* is this a time/date axis? */
    TBOOLEAN format_is_numeric;	/* format string looks like numeric??? */
    char timefmt[MAX_ID_LEN+1];	/* format string for input */
    char formatstring[MAX_ID_LEN+1];
				/* the format string for output */

/* ticmark control variables */
    int ticmode;		/* tics on border/axis? mirrored? */
    struct ticdef ticdef;	/* tic series definition */
    int tic_rotate;		/* ticmarks rotated by this angle */
    TBOOLEAN gridmajor;		/* Grid lines wanted on major tics? */
    TBOOLEAN gridminor;		/* Grid lines for minor tics? */
    int minitics;		/* minor tic mode (none/auto/user)? */
    double mtic_freq;		/* minitic stepsize */
    double ticscale;		/* scale factor for tic marks (was (0..1])*/
    double miniticscale;	/* and for minitics */
    TBOOLEAN tic_in;		/* tics to be drawn inward?  */

/* other miscellaneous fields */
    text_label label;		/* label string and position offsets */
    lp_style_type zeroaxis;	/* drawing style for zeroaxis, if any */
} AXIS;

#define DEFAULT_AXIS_TICDEF {TIC_COMPUTED, NULL, {TC_DEFAULT, 0, 0}, {NULL, {0,0}, FALSE},  { character, character, character, 0., 0., 0. } }
# define DEFAULT_AXIS_ZEROAXIS {0, -3, 0, 1.0, 1.0, 0}

#define DEFAULT_AXIS_STRUCT {						    \
	AUTOSCALE_BOTH, AUTOSCALE_BOTH, /* auto, set_auto */		    \
	0, FALSE,		/* range_flags, rev_range */		    \
	-10.0, 10.0,		/* 3 pairs of min/max */		    \
	-10.0, 10.0,							    \
	-10.0, 10.0,							    \
	0, 0, 0, 0,		/* terminal dependents */		    \
	FALSE, 0.0, 0.0,	/* log, base, log(base) */		    \
	0, 1,			/* is_timedata, format_numeric */	    \
	DEF_FORMAT, TIMEFMT,	/* output format, timefmt */		    \
	NO_TICS,		/* tic output positions (border, mirror) */ \
	DEFAULT_AXIS_TICDEF,	/* tic series definition */		    \
	0, FALSE, FALSE, 	/* tic_rotate, grid{major,minor} */	    \
	MINI_DEFAULT, 10,	/* minitics, mtic_freq */		    \
        1.0, 0.5, TRUE,		/* ticscale, miniticscale, tic_in */	    \
	EMPTY_LABELSTRUCT,	/* axis label */			    \
	DEFAULT_AXIS_ZEROAXIS	/* zeroaxis line style */		    \
}

/* Table of default behaviours --- a subset of the struct above. Only
 * those fields are present that differ from axis to axis. */
typedef struct axis_defaults {
    double min;			/* default axis endpoints */
    double max;
    char name[4];		/* axis name, like in "x2" or "t" */
    int ticmode;		/* tics on border/axis? mirrored? */
} AXIS_DEFAULTS;



/* global variables in axis.c */

extern AXIS axis_array[AXIS_ARRAY_SIZE];
extern const AXIS_DEFAULTS axis_defaults[AXIS_ARRAY_SIZE];

/* A parsing table for mapping axis names into axis indices. For use
 * by the set/show machinery, mainly */
extern const struct gen_table axisname_tbl[AXIS_ARRAY_SIZE+1];


extern const struct ticdef default_axis_ticdef;

/* default format for tic mark labels */
#define DEF_FORMAT "% g"

/* default parse timedata string */
#define TIMEFMT "%d/%m/%y,%H:%M"

/* axis labels */
extern const text_label default_axis_label;

/* zeroaxis linetype (flag type==-3 if none wanted) */
extern const lp_style_type default_axis_zeroaxis;

/* default grid linetype, to be used by 'unset grid' and 'reset' */
extern const struct lp_style_type default_grid_lp;

/* grid layer: -1 default, 0 back, 1 front */
extern int grid_layer;

/* global variables for communication with the tic callback functions */
/* FIXME HBB 20010806: had better be collected into a struct that's
 * passed to the callback */
extern int tic_start, tic_direction, tic_mirror;
/* These are for passing on to write_multiline(): */
extern int tic_text, rotate_tics, tic_hjust, tic_vjust;
/* The remaining ones are for grid drawing; controlled by 'set grid': */
/* extern int grid_selection; --- comm'ed out, HBB 20010806 */
extern struct lp_style_type grid_lp; /* linestyle for major grid lines */
extern struct lp_style_type mgrid_lp; /* linestyle for minor grid lines */
extern double polar_grid_angle; /* angle step in polar grid in radians */

/* Length of the longest tics label, set by widest_tic_callback(): */
extern int widest_tic_strlen;

/* axes being used by the current plot */
extern AXIS_INDEX x_axis, y_axis, z_axis;
/* macros to reduce code clutter caused by the array notation, mainly
 * in graphics.c and fit.c */
#define X_AXIS axis_array[x_axis]
#define Y_AXIS axis_array[y_axis]
#define Z_AXIS axis_array[z_axis]
#define CB_AXIS axis_array[COLOR_AXIS]

/* -------- macros using these variables: */

/* Macros to map from user to terminal coordinates and back */
#define AXIS_MAP(axis, variable)		\
  (int) ((axis_array[axis].term_lower)		\
	 + ((variable) - axis_array[axis].min)	\
	 * axis_array[axis].term_scale + 0.5)
#define AXIS_MAPBACK(axis, pos)						   \
  (((double)(pos)-axis_array[axis].term_lower)/axis_array[axis].term_scale \
   + axis_array[axis].min)

/* these are the old names for these: */
#define map_x(x) AXIS_MAP(x_axis, x)
#define map_y(y) AXIS_MAP(y_axis, y)

#define AXIS_SETSCALE(axis, out_low, out_high)			\
    axis_array[axis].term_scale = ((out_high) - (out_low))	\
        / (axis_array[axis].max - axis_array[axis].min)

/* write current min/max_array contents into the set/show status
 * variables */
#define AXIS_WRITEBACK(axis)			\
do {						\
    AXIS *this = axis_array + axis;		\
						\
    if (this->range_flags & RANGE_WRITEBACK) {	\
	if (this->autoscale & AUTOSCALE_MIN)	\
	    this->set_min = this->min;		\
	if (this->autoscale & AUTOSCALE_MAX)	\
	    this->set_max = this->max;		\
    }						\
} while(0)

/* HBB 20000430: New macros, logarithmize a value into a stored
 * coordinate*/
#define AXIS_DO_LOG(axis,value) (log(value) / axis_array[axis].log_base)
#define AXIS_UNDO_LOG(axis,value) exp((value) * axis_array[axis].log_base)

/* HBB 20000430: same, but these test if the axis is log, first: */
#define AXIS_LOG_VALUE(axis,value)				\
    (axis_array[axis].log ? AXIS_DO_LOG(axis,value) : (value))
#define AXIS_DE_LOG_VALUE(axis,coordinate)				  \
    (axis_array[axis].log ? AXIS_UNDO_LOG(axis,coordinate): (coordinate))


/* copy scalar data to arrays. The difference between 3D and 2D
 * versions is: dont know we have to support ranges [10:-10] - lets
 * reverse it for now, then fix it at the end.  */
/* FIXME HBB 20000426: unknown if this distinction makes any sense... */
#define AXIS_INIT3D(axis, islog_override, infinite)			\
do {									\
    AXIS *this = axis_array + axis;					\
									\
    this->autoscale = this->set_autoscale;				\
    if ((this->autoscale & AUTOSCALE_BOTH) == AUTOSCALE_NONE		\
	&& this->set_max < this->set_min) {				\
	this->min = this->set_max;					\
	this->max = this->set_min;					\
        /* we will fix later */						\
    } else {								\
	this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN))	\
	    ? VERYLARGE : this->set_min;				\
	this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX))	\
	    ? -VERYLARGE : this->set_max;				\
    }									\
    if (islog_override) {						\
	this->log = 0;							\
	this->base = 1;							\
	this->log_base = 0;						\
    } else {								\
	this->log_base = this->log ? log(this->base) : 0;		\
    }									\
} while(0)

#define AXIS_INIT2D(axis, infinite)					\
do {									\
    AXIS *this = axis_array + axis;					\
									\
    this->autoscale = this->set_autoscale;				\
    this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN))	\
	? VERYLARGE : this->set_min;					\
    this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX))	\
	? -VERYLARGE : this->set_max;					\
    this->log_base = this->log ? log(this->base) : 0;			\
} while(0)

/* handle reversed ranges */
#define CHECK_REVERSE(axis) do {					\
    AXIS *this = axis_array + axis;					\
									\
    if (((this->autoscale & AUTOSCALE_BOTH) == AUTOSCALE_NONE)		\
	&& (this->max < this->min)) {					\
	double temp = this->min;					\
									\
	this->min = this->max;						\
	this->max = temp;						\
	this->range_is_reverted = 1;					\
    } else								\
	this->range_is_reverted = (this->range_flags & RANGE_REVERSE);	\
} while(0)

/* HBB NEW 20050316: macros to always access the actual minimum, even
 * if 'set view map' or something else flipped things around behind
 * our back */
#define AXIS_ACTUAL_MIN(axis)				\
    (axis_array[axis].range_flags & RANGE_REVERSE	\
     ? axis_array[axis].max : axis_array[axis].min)

#define AXIS_ACTUAL_MAX(axis)				\
    (axis_array[axis].range_flags & RANGE_REVERSE	\
     ? axis_array[axis].min : axis_array[axis].max)

/* HBB 20000725: new macro, built upon ULIG's SAVE_WRITEBACK(axis),
 * but easier to use. Code like this occured twice, in plot2d and
 * plot3d: */
#define SAVE_WRITEBACK_ALL_AXES					\
do {								\
    AXIS_INDEX axis;						\
								\
    for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)		\
	if(axis_array[axis].range_flags & RANGE_WRITEBACK) {	\
	    set_writeback_min(axis);				\
	    set_writeback_max(axis);				\
	}							\
} while(0)

/* get optional [min:max] */
#define PARSE_RANGE(axis)						   \
do {									   \
    if (equals(c_token, "[")) {						   \
	c_token++;							   \
	axis_array[axis].autoscale =					   \
	    load_range(axis, &axis_array[axis].min, &axis_array[axis].max, \
		       axis_array[axis].autoscale);			   \
	if (!equals(c_token, "]"))					   \
	    int_error(c_token, "']' expected");				   \
	c_token++;							   \
    }									   \
} while (0)

/* HBB 20000430: new macro, like PARSE_RANGE, but for named ranges as
 * in 'plot [phi=3.5:7] sin(phi)' */
#define PARSE_NAMED_RANGE(axis, dummy_token)				     \
do {									     \
    if (equals(c_token, "[")) {						     \
	c_token++;							     \
	if (isletter(c_token)) {					     \
	    if (equals(c_token + 1, "=")) {				     \
		dummy_token = c_token;					     \
		c_token += 2;						     \
	    }								     \
		/* oops; probably an expression with a variable: act	     \
		 * as if no variable name had been seen, by		     \
		 * fallthrough */					     \
	}								     \
	axis_array[axis].autoscale = load_range(axis, &axis_array[axis].min, \
				      &axis_array[axis].max,		     \
				      axis_array[axis].autoscale);	     \
	if (!equals(c_token, "]"))					     \
	    int_error(c_token, "']' expected");				     \
	c_token++;							     \
    }				/* first '[' */				     \
} while (0)

/* parse a position of the form
 *    [coords] x, [coords] y {,[coords] z}
 * where coords is one of first,second.graph,screen,character
 * if first or second, we need to take axis_is_timedata into account
 */
#define GET_NUMBER_OR_TIME(store,axes,axis)				\
do {									\
    if (((axes) >= 0) && (axis_array[(axes)+(axis)].is_timedata)	\
	&& isstringvalue(c_token)) {					\
	struct tm tm;							\
	char *ss = try_to_get_string();					\
	if (gstrptime(ss,axis_array[axis].timefmt,&tm))			\
	    (store) = (double) gtimegm(&tm);				\
	free(ss);							\
    } else {								\
	struct value value;						\
	(store) = real(const_express(&value));				\
    }									\
} while(0)

/* This is one is very similar to GET_NUMBER_OR_TIME, but has slightly
 * different usage: it writes out '0' in case of inparsable time data,
 * and it's used when the target axis is fixed without a 'first' or
 * 'second' keyword in front of it. */
#define GET_NUM_OR_TIME(store,axis)			\
do {							\
    (store) = 0;					\
    GET_NUMBER_OR_TIME(store, FIRST_AXES, axis);	\
} while (0);

/* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
 * Do OUT_ACTION or UNDEF_ACTION as appropriate
 * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
 * VALUE must not be same as STORE
 * Note: see the particular implementation for COLOR AXIS below.
 */

#define STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS,	  \
				       OUT_ACTION, UNDEF_ACTION)	  \
do {									  \
    /* HBB 20000726: new check, to avoid crashes with axis index -1 */	  \
    if (AXIS==-1)							  \
	break;								  \
    /* HBB 20040304: new check to avoid storing infinities and NaNs */	  \
    if (! (VALUE > -VERYLARGE && VALUE < VERYLARGE)) {			  \
	TYPE = UNDEFINED;						  \
	UNDEF_ACTION;							  \
	break;								  \
    }									  \
    if (axis_array[AXIS].log) {						  \
	if (VALUE<0.0) {						  \
	    TYPE = UNDEFINED;						  \
	    UNDEF_ACTION;						  \
	    break;							  \
	} else if (VALUE == 0.0) {					  \
	    STORE = -VERYLARGE;						  \
	    TYPE = OUTRANGE;						  \
	    OUT_ACTION;							  \
	    break;							  \
	} else {							  \
	    STORE = AXIS_DO_LOG(AXIS,VALUE);				  \
	}								  \
    } else								  \
	STORE = VALUE;							  \
    if (TYPE != INRANGE)						  \
	break;  /* don't set y range if x is outrange, for example */	  \
    if ((int)AXIS < 0)							  \
	break;	/* HBB 20000507: don't check range if not a coordinate */ \
    if ( VALUE<axis_array[AXIS].min ) {					  \
	if (axis_array[AXIS].autoscale & AUTOSCALE_MIN)			  \
	    axis_array[AXIS].min = VALUE;				  \
	else {								  \
	    TYPE = OUTRANGE;						  \
	    OUT_ACTION;							  \
	    break;							  \
	}								  \
    }									  \
    if ( VALUE>axis_array[AXIS].max ) {					  \
	if (axis_array[AXIS].autoscale & AUTOSCALE_MAX)			  \
	    axis_array[AXIS].max = VALUE;				  \
	else {								  \
	    TYPE = OUTRANGE;						  \
	    OUT_ACTION;							  \
	}								  \
    }									  \
} while(0)

/* Implementation of the above for the color axis. It should not change
 * the type of the point (out-of-range color is plotted with the color
 * of the min or max color value).
 */
#define COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS,	  \
				       OUT_ACTION, UNDEF_ACTION)	  \
{									  \
    int c_type_tmp = TYPE;						  \
    STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, c_type_tmp, AXIS,	  \
				       OUT_ACTION, UNDEF_ACTION);	  \
}

/* Empty macro arguments triggered NeXT cpp bug       */
/* #define NOOP (0) caused many warnings from gcc 3.2 */
/* Now trying ((void)0) */
#define NOOP ((void)0)

/* HBB 20000506: new macro, initializes one variable to the same
 * value, for all axes. */
#define INIT_AXIS_ARRAY(field, value)		\
do {						\
    int tmp;					\
    for (tmp=0; tmp<AXIS_ARRAY_SIZE; tmp++)	\
	axis_array[tmp].field=(value);		\
} while(0)

/* HBB 20000506: new macro to automatically build intializer lists
 * for arrays of AXIS_ARRAY_SIZE equal elements */
#define AXIS_ARRAY_INITIALIZER(value) {			\
    value, value, value, value, value,			\
	value, value, value, value, value, value }

/* used by set.c */
#define SET_DEFFORMAT(axis, flag_array)				\
	if (flag_array[axis]) {					\
	    (void) strcpy(axis_array[axis].formatstring,DEF_FORMAT);	\
	    axis_array[axis].format_is_numeric = 1;		\
	}


/* 'roundoff' check tolerance: less than one hundredth of a tic mark */
#define SIGNIF (0.01)
/* (DFK) Watch for cancellation error near zero on axes labels */
/* FIXME HBB 20000521: these seem not to be used much, anywhere... */
#define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
#define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))



/* ------------ functions exported by axis.c */
t_autoscale load_range __PROTO((AXIS_INDEX, double *, double *, t_autoscale));
void axis_unlog_interval __PROTO((AXIS_INDEX, double *, double *, TBOOLEAN));
void axis_revert_and_unlog_range __PROTO((AXIS_INDEX));
double axis_log_value_checked __PROTO((AXIS_INDEX, double, const char *));
void axis_checked_extend_empty_range __PROTO((AXIS_INDEX, const char *mesg));
char * copy_or_invent_formatstring __PROTO((AXIS_INDEX));
double quantize_normal_tics __PROTO((double, int));
void setup_tics __PROTO((AXIS_INDEX, int));
void gen_tics __PROTO((AXIS_INDEX, /* int, */ tic_callback));
void axis_output_tics __PROTO((AXIS_INDEX, int *, AXIS_INDEX, tic_callback));
void axis_set_graphical_range __PROTO((AXIS_INDEX, unsigned int lower, unsigned int upper));
void axis_draw_2d_zeroaxis __PROTO((AXIS_INDEX, AXIS_INDEX));
TBOOLEAN some_grid_selected __PROTO((void));
void add_tic_user __PROTO((AXIS_INDEX, char *, double, int));

double get_writeback_min __PROTO((AXIS_INDEX));
double get_writeback_max __PROTO((AXIS_INDEX));
void set_writeback_min __PROTO((AXIS_INDEX));
void set_writeback_max __PROTO((AXIS_INDEX));

/* set widest_tic_label: length of the longest tics label */
void widest_tic_callback __PROTO((AXIS_INDEX, double place, char *text, struct lp_style_type grid));

void get_position __PROTO((struct position *pos));
void get_position_default __PROTO((struct position *pos, enum position_type default_type));

/* ------------ autoscaling of the color axis */
#define NEED_PALETTE(plot) \
   (PM3DSURFACE == (plot)->plot_style \
    || PM3D_IMPLICIT == pm3d.implicit \
    || 1 == (plot)->lp_properties.use_palette)
int set_cbminmax __PROTO((void));

#endif /* GNUPLOT_AXIS_H */