/*
* $Id: axis.h,v 1.56 2009/01/31 17:21:32 vanzandt 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_*() */
#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
#define NO_AXIS 99
} 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;
TBOOLEAN rangelimited; /* Limit tics to data range */
} 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 (1log = 0; \
this->base = 1; \
this->log_base = 0; \
} else { \
this->log_base = this->log ? log(this->base) : 0; \
} \
this->data_min = VERYLARGE; \
this->data_max = -VERYLARGE; \
} 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; \
this->data_min = VERYLARGE; \
this->data_max = -VERYLARGE; \
} while(0)
#ifdef VOLATILE_REFRESH
#define AXIS_INIT2D_REFRESH(axis, infinite) \
do { \
AXIS *this = axis_array + axis; \
\
this->autoscale = this->set_autoscale; \
this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN)) \
? VERYLARGE*1e-3 : AXIS_LOG_VALUE(axis, this->set_min); \
this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX)) \
? -VERYLARGE*1e-3 : AXIS_LOG_VALUE(axis, this->set_max); \
this->log_base = this->log ? log(this->base) : 0; \
} while(0)
/* why multiply by 1e-3: if an already VERYLARGE x2 and y2 ranges are
calculated after zoom-out by mouse, then they would become even larger
*/
#define AXIS_UPDATE2D_REFRESH(axis) \
do { \
AXIS *this_axis = axis_array + axis; \
if ((this_axis->set_autoscale & AUTOSCALE_MIN) == 0) \
this_axis->min = AXIS_LOG_VALUE(axis, this_axis->set_min); \
if ((this_axis->set_autoscale & AUTOSCALE_MAX) == 0) \
this_axis->max = AXIS_LOG_VALUE(axis, this_axis->set_max); \
} while (0)
#endif
/* 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 { \
(store) = real_expression(); \
} \
} 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
* NOAUTOSCALE is per-plot property, whereas AUTOSCALE_XXX is per-axis.
* Note: see the particular implementation for COLOR AXIS below.
*/
#define STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS, \
NOAUTOSCALE, OUT_ACTION, UNDEF_ACTION) \
do { \
if (AXIS == NO_AXIS) \
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 (VALUElp_properties.use_palette)
int set_cbminmax __PROTO((void));
#endif /* GNUPLOT_AXIS_H */