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