X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Faxis.h;fp=src%2Faxis.h;h=f591f00feffc4e117591e62bb5d880c91a740e03;hb=39ec1247a71f61152a4a7f502a30f06a3896c5da;hp=0000000000000000000000000000000000000000;hpb=06be459be4f5f6a7c6ff878e84f355fb2575caa8;p=gnuplot diff --git a/src/axis.h b/src/axis.h new file mode 100644 index 0000000..f591f00 --- /dev/null +++ b/src/axis.h @@ -0,0 +1,661 @@ +/* + * $Id: axis.h,v 1.46.2.3 2008/10/30 22:26:23 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; + 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 (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; + double data_min; /* Not necessarily the same as axis min */ + double data_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. }, FALSE } +# 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 for axis itself */ \ + -10.0, 10.0, \ + -10.0, 10.0, \ + 0.0, 0.0, /* and another min/max for the data */ \ + 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; \ + } \ + 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) + +/* 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 ( VALUEaxis_array[AXIS].data_max ) \ + axis_array[AXIS].data_max = VALUE; \ + 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; tmpplot_style \ + || PM3D_IMPLICIT == pm3d.implicit \ + || 1 == (plot)->lp_properties.use_palette) +int set_cbminmax __PROTO((void)); + +#endif /* GNUPLOT_AXIS_H */