Annotation of OpenXM_contrib/gnuplot/plot2d.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: plot2d.c,v 1.53 1998/06/18 14:55:14 ddenholm Exp $";
! 3: #endif
! 4:
! 5: /* GNUPLOT - plot2d.c */
! 6:
! 7: /*[
! 8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
! 9: *
! 10: * Permission to use, copy, and distribute this software and its
! 11: * documentation for any purpose with or without fee is hereby granted,
! 12: * provided that the above copyright notice appear in all copies and
! 13: * that both that copyright notice and this permission notice appear
! 14: * in supporting documentation.
! 15: *
! 16: * Permission to modify the software is granted, but not the right to
! 17: * distribute the complete modified source code. Modifications are to
! 18: * be distributed as patches to the released version. Permission to
! 19: * distribute binaries produced by compiling modified sources is granted,
! 20: * provided you
! 21: * 1. distribute the corresponding source modifications from the
! 22: * released version in the form of a patch file along with the binaries,
! 23: * 2. add special version identification to distinguish your version
! 24: * in addition to the base release version number,
! 25: * 3. provide your name and address as the primary contact for the
! 26: * support of your modified version, and
! 27: * 4. retain our contact information in regard to use of the base
! 28: * software.
! 29: * Permission to distribute the released version of the source code along
! 30: * with corresponding source modifications in the form of a patch file is
! 31: * granted with same provisions 2 through 4 for binary distributions.
! 32: *
! 33: * This software is provided "as is" without express or implied warranty
! 34: * to the extent permitted by applicable law.
! 35: ]*/
! 36:
! 37: #include "plot.h"
! 38: #include "setshow.h"
! 39: #include "fit.h"
! 40: #include "binary.h"
! 41:
! 42: #ifndef _Windows
! 43: # include "help.h"
! 44: #endif
! 45:
! 46: #ifndef STDOUT
! 47: #define STDOUT 1
! 48: #endif
! 49:
! 50: /* static prototypes */
! 51:
! 52: void plotrequest __PROTO((void));
! 53: void plot3drequest __PROTO((void));
! 54: void define __PROTO((void));
! 55: static void get_data __PROTO((struct curve_points * this_plot));
! 56: static void store2d_point __PROTO((struct curve_points * this_plot, int i, double x, double y, double xlow, double xhigh, double ylow, double yhigh, double width));
! 57: static void print_table __PROTO((struct curve_points * first_plot, int plot_num));
! 58: static void eval_plots __PROTO((void));
! 59: static void parametric_fixup __PROTO((struct curve_points * start_plot, int *plot_num));
! 60:
! 61:
! 62: /* the curves/surfaces of the plot */
! 63: struct curve_points *first_plot = NULL;
! 64: static struct udft_entry plot_func;
! 65: extern struct udft_entry *dummy_func;
! 66:
! 67: /* jev -- for passing data thru user-defined function */
! 68: /* Needed by datafile.c */
! 69: struct udft_entry ydata_func;
! 70:
! 71: extern int datatype[];
! 72: extern char timefmt[];
! 73:
! 74: extern TBOOLEAN is_3d_plot;
! 75: extern int plot_token;
! 76:
! 77: /* in order to support multiple axes, and to
! 78: * simplify ranging in parametric plots, we use
! 79: * arrays to store some things.
! 80: * Elements are z = 0, y1 = 1, x1 = 2, [z2 =4 ], y2 = 5, x2 = 6
! 81: * these are given symbolic names in plot.h
! 82: */
! 83:
! 84: /* Were declared in command.c */
! 85: double min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE];
! 86: int auto_array[AXIS_ARRAY_SIZE];
! 87: TBOOLEAN log_array[AXIS_ARRAY_SIZE];
! 88: double base_array[AXIS_ARRAY_SIZE];
! 89: double log_base_array[AXIS_ARRAY_SIZE];
! 90:
! 91: /* Deleted from setshow.h and renamed */
! 92: extern FILE *gpoutfile;
! 93:
! 94: /* if user specifies [10:-10] we use [-10:10] internally, and swap at end */
! 95: int reverse_range[AXIS_ARRAY_SIZE];
! 96:
! 97: /* info from datafile module */
! 98: extern int df_datum;
! 99: extern int df_line_number;
! 100: extern int df_no_use_specs;
! 101: extern int df_eof;
! 102: extern int df_timecol[];
! 103: extern TBOOLEAN df_binary;
! 104:
! 105: #define Inc_c_token if (++c_token >= num_tokens) \
! 106: int_error ("Syntax error", c_token);
! 107:
! 108:
! 109: /*
! 110: * IMHO, code is getting too cluttered with repeated chunks of
! 111: * code. Some macros to simplify, I hope.
! 112: *
! 113: * do { } while(0) is comp.lang.c recommendation for complex macros
! 114: * also means that break can be specified as an action, and it will
! 115: *
! 116: */
! 117:
! 118: /* copy scalar data to arrays
! 119: * optimiser should optimise infinite away
! 120: * dont know we have to support ranges [10:-10] - lets reverse
! 121: * it for now, then fix it at the end.
! 122: */
! 123: #define INIT_ARRAYS(axis, min, max, auto, is_log, base, log_base, infinite) \
! 124: do{auto_array[axis] = auto; \
! 125: min_array[axis] = (infinite && (auto&1)) ? VERYLARGE : min; \
! 126: max_array[axis] = (infinite && (auto&2)) ? -VERYLARGE : max; \
! 127: log_array[axis] = is_log; base_array[axis] = base; log_base_array[axis] = log_base;\
! 128: }while(0)
! 129: /* handle reversed ranges */
! 130: #define CHECK_REVERSE(axis) \
! 131: do{\
! 132: if (auto_array[axis] == 0 && max_array[axis] < min_array[axis]) {\
! 133: double temp = min_array[axis]; min_array[axis] = max_array[axis]; max_array[axis] = temp;\
! 134: reverse_range[axis] = 1; \
! 135: } else reverse_range[axis] = (range_flags[axis]&RANGE_REVERSE); \
! 136: }while(0)
! 137:
! 138:
! 139: /* get optional [min:max] */
! 140: #define LOAD_RANGE(axis) \
! 141: do {\
! 142: if (equals(c_token, "[")) { \
! 143: c_token++; \
! 144: auto_array[axis] = load_range(axis,&min_array[axis], &max_array[axis], auto_array[axis]);\
! 145: if (!equals(c_token, "]"))\
! 146: int_error("']' expected", c_token);\
! 147: c_token++;\
! 148: }\
! 149: } while (0)
! 150:
! 151:
! 152: /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
! 153: * Do OUT_ACTION or UNDEF_ACTION as appropriate
! 154: * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
! 155: * VALUE must not be same as STORE
! 156: */
! 157:
! 158: #define STORE_WITH_LOG_AND_FIXUP_RANGE(STORE, VALUE, TYPE, AXIS, OUT_ACTION, UNDEF_ACTION)\
! 159: do { if (log_array[AXIS]) { if (VALUE<0.0) {TYPE = UNDEFINED; UNDEF_ACTION; break;} \
! 160: else if (VALUE == 0.0){STORE = -VERYLARGE; TYPE = OUTRANGE; OUT_ACTION; break;} \
! 161: else { STORE = log(VALUE)/log_base_array[AXIS]; } \
! 162: } else STORE = VALUE; \
! 163: if (TYPE != INRANGE) break; /* dont set y range if x is outrange, for example */ \
! 164: if ( VALUE<min_array[AXIS] ) { \
! 165: if (auto_array[AXIS] & 1) min_array[AXIS] = VALUE; else { TYPE = OUTRANGE; OUT_ACTION; break; } \
! 166: } \
! 167: if ( VALUE>max_array[AXIS] ) { \
! 168: if (auto_array[AXIS] & 2) max_array[AXIS] = VALUE; else { TYPE = OUTRANGE; OUT_ACTION; } \
! 169: } \
! 170: } while(0)
! 171:
! 172: /* use this instead empty macro arguments to work around NeXT cpp bug */
! 173: /* if this fails on any system, we might use ((void)0) */
! 174: #define NOOP /* */
! 175:
! 176: /* check range and take logs of min and max if logscale
! 177: * this also restores min and max for ranges like [10:-10]
! 178: */
! 179: #ifdef HAVE_STRINGIZE
! 180: # define LOG_MSG(x) #x " range must be greater than 0 for log scale!"
! 181: #else
! 182: # define LOG_MSG(x) "x range must be greater than 0 for log scale!"
! 183: #endif
! 184:
! 185: #define FIXUP_RANGE_FOR_LOG(AXIS, WHICH) \
! 186: do { if (reverse_range[AXIS]) { \
! 187: double temp = min_array[AXIS]; \
! 188: min_array[AXIS] = max_array[AXIS]; \
! 189: max_array[AXIS] = temp; \
! 190: }\
! 191: if (log_array[AXIS]) { \
! 192: if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0) \
! 193: int_error(LOG_MSG(WHICH), NO_CARET); \
! 194: min_array[AXIS] = log(min_array[AXIS])/log_base_array[AXIS]; \
! 195: max_array[AXIS] = log(max_array[AXIS])/log_base_array[AXIS]; \
! 196: } \
! 197: } while(0)
! 198:
! 199:
! 200:
! 201: void plotrequest()
! 202: /*
! 203: * In the parametric case we can say plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2
! 204: * while in the non-parametric case we would say only plot [b= -2:2] [-1:1]
! 205: * sin(b)
! 206: */
! 207: {
! 208: int dummy_token = -1;
! 209:
! 210: if (!term) /* unknown */
! 211: int_error("use 'set term' to set terminal type first", c_token);
! 212:
! 213: is_3d_plot = FALSE;
! 214:
! 215: if (parametric && strcmp(dummy_var[0], "u") == 0)
! 216: strcpy(dummy_var[0], "t");
! 217:
! 218: /* initialise the arrays from the 'set' scalars */
! 219:
! 220: INIT_ARRAYS(FIRST_X_AXIS, xmin, xmax, autoscale_x, is_log_x, base_log_x, log_base_log_x, 0);
! 221: INIT_ARRAYS(FIRST_Y_AXIS, ymin, ymax, autoscale_y, is_log_y, base_log_y, log_base_log_y, 1);
! 222: INIT_ARRAYS(SECOND_X_AXIS, x2min, x2max, autoscale_x2, is_log_x2, base_log_x2, log_base_log_x2, 0);
! 223: INIT_ARRAYS(SECOND_Y_AXIS, y2min, y2max, autoscale_y2, is_log_y2, base_log_y2, log_base_log_y2, 1);
! 224:
! 225: min_array[T_AXIS] = tmin;
! 226: max_array[T_AXIS] = tmax;
! 227:
! 228: if (equals(c_token, "[")) {
! 229: c_token++;
! 230: if (isletter(c_token)) {
! 231: if (equals(c_token + 1, "=")) {
! 232: dummy_token = c_token;
! 233: c_token += 2;
! 234: } else {
! 235: /* oops; probably an expression with a variable. */
! 236: /* Parse it as an xmin expression. */
! 237: /* used to be: int_error("'=' expected",c_token); */
! 238: }
! 239: } {
! 240: int axis = (parametric || polar) ? T_AXIS : FIRST_X_AXIS;
! 241:
! 242:
! 243: auto_array[axis] = load_range(axis, &min_array[axis], &max_array[axis], auto_array[axis]);
! 244: if (!equals(c_token, "]"))
! 245: int_error("']' expected", c_token);
! 246: c_token++;
! 247: } /* end of scope of 'axis' */
! 248: } /* first '[' */
! 249: if (parametric || polar) /* set optional x ranges */
! 250: LOAD_RANGE(FIRST_X_AXIS);
! 251: else {
! 252: /* order of t doesn't matter, but x does */
! 253: CHECK_REVERSE(FIRST_X_AXIS);
! 254: }
! 255:
! 256: LOAD_RANGE(FIRST_Y_AXIS);
! 257: CHECK_REVERSE(FIRST_Y_AXIS);
! 258: LOAD_RANGE(SECOND_X_AXIS);
! 259: CHECK_REVERSE(SECOND_X_AXIS);
! 260: LOAD_RANGE(SECOND_Y_AXIS);
! 261: CHECK_REVERSE(SECOND_Y_AXIS);
! 262:
! 263: /* use the default dummy variable unless changed */
! 264: if (dummy_token >= 0)
! 265: copy_str(c_dummy_var[0], dummy_token, MAX_ID_LEN);
! 266: else
! 267: (void) strcpy(c_dummy_var[0], dummy_var[0]);
! 268:
! 269: eval_plots();
! 270: }
! 271:
! 272: /* Use up to 7 columns in data file at once -- originally it was 5 */
! 273: #define NCOL 7
! 274:
! 275:
! 276: /* A quick note about boxes style. For boxwidth auto, we cannot
! 277: * calculate widths yet, since it may be sorted, etc. But if
! 278: * width is set, we must do it now, before logs of xmin/xmax
! 279: * are taken.
! 280: * We store -1 in point->z as a marker to mean width needs to be
! 281: * calculated, or 0 to mean that xmin/xmax are set correctly
! 282: */
! 283:
! 284:
! 285: static void get_data(this_plot)
! 286: struct curve_points *this_plot;
! 287: /* this_plot->token is after datafile spec, for error reporting
! 288: * it will later be moved passed title/with/linetype/pointtype
! 289: */
! 290: {
! 291: register int i /* num. points ! */ , j, col;
! 292: double v[NCOL];
! 293: int storetoken = this_plot->token;
! 294:
! 295: /* eval_plots has already opened file */
! 296:
! 297: switch (this_plot->plot_style) { /* set maximum columns to scan */
! 298: case XYERRORBARS:
! 299: case BOXXYERROR:
! 300: col = 7;
! 301: break;
! 302:
! 303: case BOXERROR:
! 304: case FINANCEBARS:
! 305: case CANDLESTICKS:
! 306: col = 5;
! 307: break;
! 308:
! 309: case XERRORBARS:
! 310: case YERRORBARS:
! 311: case VECTOR:
! 312: col = 4;
! 313: break;
! 314:
! 315: case BOXES:
! 316: col = 4;
! 317: break;
! 318:
! 319: default:
! 320: col = 2;
! 321: }
! 322:
! 323: if (this_plot->plot_smooth == ACSPLINES)
! 324: col = 3;
! 325:
! 326: if (df_no_use_specs > col)
! 327: fputs("warning : too many using specs for this style\n", stderr);
! 328:
! 329: i = 0;
! 330: while ((j = df_readline(v, col)) != DF_EOF) {
! 331: /* j <= col */
! 332:
! 333: if (i >= this_plot->p_max) {
! 334: /*
! 335: * overflow about to occur. Extend size of points[] array. We
! 336: * either double the size, or add 1000 points, whichever is a
! 337: * smaller increment. Note i = p_max.
! 338: */
! 339: cp_extend(this_plot, i + (i < 1000 ? i : 1000));
! 340: }
! 341: /* Limitation: No xerrorbars with boxes */
! 342: switch (j) {
! 343: default:
! 344: {
! 345: char message[80];
! 346: sprintf(message, "internal error : df_readline returned %d : datafile line %d", j, df_line_number);
! 347: df_close();
! 348: int_error(message, c_token);
! 349: }
! 350: case DF_UNDEFINED:
! 351: /* bad result from extended using expression */
! 352: this_plot->points[i].type = UNDEFINED;
! 353: i++;
! 354: continue;
! 355:
! 356: case DF_FIRST_BLANK:
! 357: /* break in data, make next point undefined */
! 358: this_plot->points[i].type = UNDEFINED;
! 359: i++;
! 360: continue;
! 361:
! 362: case DF_SECOND_BLANK:
! 363: /* second blank line. We dont do anything
! 364: * (we did everything when we got FIRST one)
! 365: */
! 366: continue;
! 367:
! 368: case 0: /* not blank line, but df_readline couldn't parse it */
! 369: {
! 370: char message[80];
! 371: sprintf(message, "Bad data on line %d", df_line_number);
! 372: df_close();
! 373: int_error(message, this_plot->token);
! 374: }
! 375:
! 376: case 1:
! 377: { /* only one number */
! 378: /* x is index, assign number to y */
! 379: v[1] = v[0];
! 380: v[0] = df_datum;
! 381: /* nobreak */
! 382: }
! 383:
! 384: case 2:
! 385: /* x, y */
! 386: /* ylow and yhigh are same as y */
! 387:
! 388: if (this_plot->plot_style == BOXES && boxwidth > 0) {
! 389: /* calc width now */
! 390: store2d_point(this_plot, i++, v[0], v[1], v[0] - boxwidth / 2, v[0] + boxwidth / 2, v[1], v[1], 0.0);
! 391: } else {
! 392: /* xlow and xhigh are same as x */
! 393: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1],
! 394: -1.0); /* auto width if boxes, else ignored */
! 395: }
! 396: break;
! 397:
! 398:
! 399: case 3:
! 400: /* x, y, ydelta OR x, y, xdelta OR x, y, width */
! 401: if (this_plot->plot_smooth == ACSPLINES)
! 402: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
! 403: else
! 404: switch (this_plot->plot_style) {
! 405: default:
! 406: int_warn("This plot style not work with 3 cols. Setting to yerrorbars", storetoken);
! 407: this_plot->plot_style = YERRORBARS;
! 408: /* fall through */
! 409:
! 410: case YERRORBARS:
! 411: case BOXERROR: /* x, y, dy */
! 412: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1] - v[2], v[1] + v[2],
! 413: -1.0); /* auto width if boxes, else ignored */
! 414: break;
! 415:
! 416: case XERRORBARS:
! 417: store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2], v[0] + v[2], v[1], v[1], 0.0);
! 418: break;
! 419:
! 420: case BOXES:
! 421: /* calculate xmin and xmax here, so that logs are taken if
! 422: * if necessary
! 423: */
! 424: store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2] / 2, v[0] + v[2] / 2, v[1], v[1], 0.0);
! 425: break;
! 426:
! 427: } /*inner switch */
! 428:
! 429: break;
! 430:
! 431:
! 432:
! 433: case 4:
! 434: /* x, y, ylow, yhigh OR
! 435: * x, y, xlow, xhigh OR
! 436: * x, y, xdelta, ydelta OR
! 437: * x, y, ydelta, width
! 438: */
! 439:
! 440: switch (this_plot->plot_style) {
! 441: default:
! 442: int_warn("This plot style does not work with 4 cols. Setting to yerrorbars",
! 443: storetoken);
! 444: this_plot->plot_style = YERRORBARS;
! 445: /* fall through */
! 446:
! 447: case YERRORBARS:
! 448: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], -1.0);
! 449: break;
! 450:
! 451: case BOXXYERROR: /* x, y, dx, dy */
! 452: case XYERRORBARS:
! 453: store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2], v[0] + v[2], v[1] - v[3], v[1] + v[3], 0.0);
! 454: break;
! 455:
! 456:
! 457: case BOXES: /* x, y, xmin, xmax */
! 458: store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], 0.0);
! 459: break;
! 460:
! 461: case XERRORBARS:
! 462: store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], 0.0);
! 463: break;
! 464:
! 465: case BOXERROR:
! 466: /* x,y, xleft, xright */
! 467: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1] - v[2], v[1] + v[2], 0.0);
! 468: break;
! 469:
! 470: case VECTOR:
! 471: /* x,y,dx,dy */
! 472: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0] + v[2], v[1], v[1] + v[3], -1.0);
! 473: break;
! 474: } /*inner switch */
! 475:
! 476: break;
! 477:
! 478:
! 479: case 5:
! 480: { /* x, y, ylow, yhigh, width or x open low high close */
! 481: switch (this_plot->plot_style) {
! 482: default:
! 483: int_warn("Five col. plot style must be boxerrorbars, financebars or candlesticks. Setting to boxerrorbars", storetoken);
! 484: this_plot->plot_style = BOXERROR;
! 485: /*fall through */
! 486:
! 487: case BOXERROR: /* x, y, ylow, yhigh, width */
! 488: store2d_point(this_plot, i++, v[0], v[1], v[0] - v[4] / 2, v[0] + v[4] / 2, v[2], v[3], 0.0);
! 489: break;
! 490:
! 491: case FINANCEBARS:
! 492: case CANDLESTICKS:
! 493: store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], v[4]);
! 494: break;
! 495: }
! 496: break;
! 497: }
! 498:
! 499: case 7:
! 500: /* same as six columns. Width ignored */
! 501: /* eh ? - fall through */
! 502: case 6:
! 503: /* x, y, xlow, xhigh, ylow, yhigh */
! 504: switch (this_plot->plot_style) {
! 505: default:
! 506: int_warn("This plot style not work with 6 cols. Setting to xyerrorbars", storetoken);
! 507: this_plot->plot_style = XYERRORBARS;
! 508: /*fall through */
! 509: case XYERRORBARS:
! 510: case BOXXYERROR:
! 511: store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[4], v[5], 0.0);
! 512: break;
! 513: }
! 514:
! 515: } /*switch */
! 516:
! 517: } /*while */
! 518:
! 519: this_plot->p_count = i;
! 520: cp_extend(this_plot, i); /* shrink to fit */
! 521:
! 522: df_close();
! 523: }
! 524:
! 525: /* called by get_data for each point */
! 526: static void store2d_point(this_plot, i, x, y, xlow, xhigh, ylow, yhigh, width)
! 527: struct curve_points *this_plot;
! 528: int i; /* point number */
! 529: double x, y;
! 530: double ylow, yhigh;
! 531: double xlow, xhigh;
! 532: double width; /* -1 means autocalc, 0 means use xmin/xmax */
! 533: {
! 534: struct coordinate GPHUGE *cp = &(this_plot->points[i]);
! 535: int dummy_type = INRANGE; /* sometimes we dont care about outranging */
! 536:
! 537:
! 538: /* jev -- pass data values thru user-defined function */
! 539: /* div -- y is dummy variable 2 - copy value there */
! 540: if (ydata_func.at) {
! 541: struct value val;
! 542:
! 543: (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0);
! 544: ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
! 545: evaluate_at(ydata_func.at, &val);
! 546: y = undefined ? 0.0 : real(&val);
! 547:
! 548: (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0);
! 549: ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
! 550: evaluate_at(ydata_func.at, &val);
! 551: ylow = undefined ? 0 : real(&val);
! 552:
! 553: (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0);
! 554: ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
! 555: evaluate_at(ydata_func.at, &val);
! 556: yhigh = undefined ? 0 : real(&val);
! 557: }
! 558: dummy_type = cp->type = INRANGE;
! 559:
! 560: if (polar) {
! 561: double newx, newy;
! 562: if (!(autoscale_r & 2) && y > rmax) {
! 563: cp->type = OUTRANGE;
! 564: }
! 565: if (!(autoscale_r & 1)) {
! 566: /* we store internally as if plotting r(t)-rmin */
! 567: y -= rmin;
! 568: }
! 569: newx = y * cos(x * ang2rad);
! 570: newy = y * sin(x * ang2rad);
! 571: #if 0 /* HBB 981118: added polar errorbars */
! 572: /* only lines and points supported with polar */
! 573: y = ylow = yhigh = newy;
! 574: x = xlow = xhigh = newx;
! 575: #else
! 576: y = newy;
! 577: x = newx;
! 578:
! 579: if (!(autoscale_r & 2) && yhigh > rmax) {
! 580: cp->type = OUTRANGE;
! 581: }
! 582: if (!(autoscale_r & 1)) {
! 583: /* we store internally as if plotting r(t)-rmin */
! 584: yhigh -= rmin;
! 585: }
! 586: newx = yhigh * cos(xhigh * ang2rad);
! 587: newy = yhigh * sin(xhigh * ang2rad);
! 588: yhigh = newy;
! 589: xhigh = newx;
! 590:
! 591: if (!(autoscale_r & 2) && ylow > rmax) {
! 592: cp->type = OUTRANGE;
! 593: }
! 594: if (!(autoscale_r & 1)) {
! 595: /* we store internally as if plotting r(t)-rmin */
! 596: ylow -= rmin;
! 597: }
! 598: newx = ylow * cos(xlow * ang2rad);
! 599: newy = ylow * sin(xlow * ang2rad);
! 600: ylow = newy;
! 601: xlow = newx;
! 602: #endif
! 603: }
! 604: /* return immediately if x or y are undefined
! 605: * we dont care if outrange for high/low.
! 606: * BUT if high/low undefined (ie log( < 0 ), no number is stored,
! 607: * but graphics.c doesn't know.
! 608: * explicitly store -VERYLARGE;
! 609: */
! 610: STORE_WITH_LOG_AND_FIXUP_RANGE(cp->x, x, cp->type, this_plot->x_axis, NOOP, return);
! 611: STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xlow, xlow, dummy_type, this_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
! 612: STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xhigh, xhigh, dummy_type, this_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
! 613: STORE_WITH_LOG_AND_FIXUP_RANGE(cp->y, y, cp->type, this_plot->y_axis, NOOP, return);
! 614: STORE_WITH_LOG_AND_FIXUP_RANGE(cp->ylow, ylow, dummy_type, this_plot->y_axis, NOOP, cp->ylow = -VERYLARGE);
! 615: STORE_WITH_LOG_AND_FIXUP_RANGE(cp->yhigh, yhigh, dummy_type, this_plot->y_axis, NOOP, cp->yhigh = -VERYLARGE);
! 616: cp->z = width;
! 617: } /* store2d_point */
! 618:
! 619:
! 620:
! 621: /*
! 622: * print_points: a debugging routine to print out the points of a curve, and
! 623: * the curve structure. If curve<0, then we print the list of curves.
! 624: */
! 625:
! 626: #if 0 /* not used */
! 627: static char *plot_type_names[4] =
! 628: {
! 629: "Function", "Data", "3D Function", "3d data"
! 630: };
! 631: static char *plot_style_names[14] =
! 632: {
! 633: "Lines", "Points", "Impulses", "LinesPoints", "Dots", "XErrorbars",
! 634: "YErrorbars", "XYErrorbars", "BoxXYError", "Boxes", "Boxerror", "Steps",
! 635: "FSteps", "Vector"
! 636: };
! 637: static char *plot_smooth_names[5] =
! 638: {
! 639: "None", "Unique", "CSplines", "ACSplines", "Bezier", "SBezier"
! 640: };
! 641:
! 642: static void print_points(curve)
! 643: int curve; /* which curve to print */
! 644: {
! 645: register struct curve_points *this_plot;
! 646: int i;
! 647:
! 648: if (curve < 0) {
! 649: for (this_plot = first_plot, i = 0;
! 650: this_plot != NULL;
! 651: i++, this_plot = this_plot->next_cp) {
! 652: printf("Curve %d:\n", i);
! 653: if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4)
! 654: printf("Plot type %d: %s\n", (int) (this_plot->plot_type),
! 655: plot_type_names[(int) (this_plot->plot_type)]);
! 656: else
! 657: printf("Plot type %d: BAD\n", (int) (this_plot->plot_type));
! 658: if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 14)
! 659: printf("Plot style %d: %s\n", (int) (this_plot->plot_style),
! 660: plot_style_names[(int) (this_plot->plot_style)]);
! 661: else
! 662: printf("Plot style %d: BAD\n", (int) (this_plot->plot_style));
! 663: if ((int) this_plot->plot_smooth >= 0 && (int) (this_plot->plot_smooth) < 6)
! 664: printf("Plot smooth style %d: %s\n", (int) (this_plot->plot_style),
! 665: plot_smooth_names[(int) (this_plot->plot_smooth)]);
! 666: else
! 667: printf("Plot smooth style %d: BAD\n", (int) (this_plot->plot_smooth));
! 668: printf("Plot title: '%s'\n", this_plot->title);
! 669: printf("Line type %d\n", this_plot->line_type);
! 670: printf("Point type %d\n", this_plot->point_type);
! 671: printf("max points %d\n", this_plot->p_max);
! 672: printf("current points %d\n", this_plot->p_count);
! 673: printf("\n");
! 674: }
! 675: } else {
! 676: for (this_plot = first_plot, i = 0;
! 677: i < curve && this_plot != NULL;
! 678: i++, this_plot = this_plot->next_cp);
! 679: if (this_plot == NULL)
! 680: printf("Curve %d does not exist; list has %d curves\n", curve, i);
! 681: else {
! 682: printf("Curve %d, %d points\n", curve, this_plot->p_count);
! 683: for (i = 0; i < this_plot->p_count; i++) {
! 684: printf("%c x=%g y=%g z=%g xlow=%g xhigh=%g ylow=%g yhigh=%g\n",
! 685: this_plot->points[i].type == INRANGE ? 'i'
! 686: : this_plot->points[i].type == OUTRANGE ? 'o'
! 687: : 'u',
! 688: this_plot->points[i].x,
! 689: this_plot->points[i].y,
! 690: this_plot->points[i].z,
! 691: this_plot->points[i].xlow,
! 692: this_plot->points[i].xhigh,
! 693: this_plot->points[i].ylow,
! 694: this_plot->points[i].yhigh);
! 695: }
! 696: printf("\n");
! 697: }
! 698: }
! 699: }
! 700: #endif /* not used */
! 701:
! 702: static void print_table(this_plot, plot_num)
! 703: struct curve_points *this_plot;
! 704: int plot_num;
! 705: {
! 706: int i, curve;
! 707:
! 708: for (curve = 0; curve < plot_num;
! 709: curve++, this_plot = this_plot->next_cp) {
! 710: fprintf(gpoutfile, "#Curve %d, %d points\n#x y type\n", curve, this_plot->p_count);
! 711: for (i = 0; i < this_plot->p_count; i++) {
! 712: fprintf(gpoutfile, "%g %g %c\n",
! 713: this_plot->points[i].x,
! 714: this_plot->points[i].y,
! 715: this_plot->points[i].type == INRANGE ? 'i'
! 716: : this_plot->points[i].type == OUTRANGE ? 'o'
! 717: : 'u');
! 718: }
! 719: fputc('\n', gpoutfile);
! 720: }
! 721: /* two blank lines between plots in table output */
! 722: fputc('\n', gpoutfile);
! 723: fflush(gpoutfile);
! 724: }
! 725:
! 726: /*
! 727: * This parses the plot command after any range specifications. To support
! 728: * autoscaling on the x axis, we want any data files to define the x range,
! 729: * then to plot any functions using that range. We thus parse the input
! 730: * twice, once to pick up the data files, and again to pick up the functions.
! 731: * Definitions are processed twice, but that won't hurt.
! 732: * div - okay, it doesn't hurt, but every time an option as added for
! 733: * datafiles, code to parse it has to be added here. Change so that
! 734: * we store starting-token in the plot structure.
! 735: */
! 736: static void eval_plots()
! 737: {
! 738: register int i;
! 739: register struct curve_points *this_plot, **tp_ptr;
! 740:
! 741: int some_functions = 0;
! 742: int plot_num, line_num, point_num, xparam = 0;
! 743: char *xtitle;
! 744: int begin_token = c_token; /* so we can rewind for second pass */
! 745:
! 746: int uses_axis[AXIS_ARRAY_SIZE];
! 747:
! 748: uses_axis[FIRST_X_AXIS] =
! 749: uses_axis[FIRST_Y_AXIS] =
! 750: uses_axis[SECOND_X_AXIS] =
! 751: uses_axis[SECOND_Y_AXIS] = 0;
! 752:
! 753: /* Reset first_plot. This is usually done at the end of this function.
! 754: If there is an error within this function, the memory is left allocated,
! 755: since we cannot call cp_free if the list is incomplete. Making sure that
! 756: the list structure is always vaild requires some rewriting */
! 757: first_plot = NULL;
! 758:
! 759: tp_ptr = &(first_plot);
! 760: plot_num = 0;
! 761: line_num = 0; /* default line type */
! 762: point_num = 0; /* default point type */
! 763:
! 764: xtitle = NULL;
! 765:
! 766: /*** First Pass: Read through data files ***
! 767: * This pass serves to set the xrange and to parse the command, as well
! 768: * as filling in every thing except the function data. That is done after
! 769: * the xrange is defined.
! 770: */
! 771: while (TRUE) {
! 772: if (END_OF_COMMAND)
! 773: int_error("function to plot expected", c_token);
! 774:
! 775: if (is_definition(c_token)) {
! 776: define();
! 777: } else {
! 778: int x_axis = 0, y_axis = 0;
! 779: int specs;
! 780:
! 781: /* for datafile plot, record datafile spec for title */
! 782: int start_token = c_token, end_token;
! 783:
! 784: plot_num++;
! 785:
! 786: if (isstring(c_token)) { /* data file to plot */
! 787:
! 788: if (parametric && xparam)
! 789: int_error("previous parametric function not fully specified", c_token);
! 790:
! 791: if (*tp_ptr)
! 792: this_plot = *tp_ptr;
! 793: else { /* no memory malloc()'d there yet */
! 794: this_plot = cp_alloc(MIN_CRV_POINTS);
! 795: *tp_ptr = this_plot;
! 796: }
! 797: this_plot->plot_type = DATA;
! 798: this_plot->plot_style = data_style;
! 799: this_plot->plot_smooth = NONE;
! 800:
! 801: specs = df_open(NCOL); /* up to NCOL cols */
! 802: /* this parses data-file-specific modifiers only */
! 803: /* we'll sort points when we know style, if necessary */
! 804: if (df_binary)
! 805: int_error("2d binary files not yet supported", c_token);
! 806:
! 807: this_plot->token = end_token = c_token - 1; /* include modifiers in default title */
! 808:
! 809: } else {
! 810:
! 811: /* function to plot */
! 812:
! 813: some_functions = 1;
! 814: if (parametric) /* working on x parametric function */
! 815: xparam = 1 - xparam;
! 816: if (*tp_ptr) {
! 817: this_plot = *tp_ptr;
! 818: cp_extend(this_plot, samples + 1);
! 819: } else { /* no memory malloc()'d there yet */
! 820: this_plot = cp_alloc(samples + 1);
! 821: *tp_ptr = this_plot;
! 822: }
! 823: this_plot->plot_type = FUNC;
! 824: this_plot->plot_style = func_style;
! 825: dummy_func = &plot_func;
! 826: plot_func.at = temp_at();
! 827: dummy_func = NULL;
! 828: /* ignore it for now */
! 829: end_token = c_token - 1;
! 830: } /* end of IS THIS A FILE OR A FUNC block */
! 831:
! 832:
! 833: /* deal with smooth */
! 834: if (almost_equals(c_token, "s$mooth")) {
! 835:
! 836: if (END_OF_COMMAND)
! 837: int_error("expecting smooth parameter", c_token);
! 838: else {
! 839: c_token++;
! 840: if (almost_equals(c_token, "u$nique"))
! 841: this_plot->plot_smooth = UNIQUE;
! 842: else if (almost_equals(c_token, "a$csplines"))
! 843: this_plot->plot_smooth = ACSPLINES;
! 844: else if (almost_equals(c_token, "c$splines"))
! 845: this_plot->plot_smooth = CSPLINES;
! 846: else if (almost_equals(c_token, "b$ezier"))
! 847: this_plot->plot_smooth = BEZIER;
! 848: else if (almost_equals(c_token, "s$bezier"))
! 849: this_plot->plot_smooth = SBEZIER;
! 850: else
! 851: int_error("expecting 'unique', 'acsplines', 'csplines', 'bezier' or 'sbezier'", c_token);
! 852: }
! 853: this_plot->plot_style = LINES;
! 854: c_token++; /* skip format */
! 855: }
! 856: /* look for axes/axis */
! 857:
! 858: if (almost_equals(c_token, "ax$es") || almost_equals(c_token, "ax$is")) {
! 859: if (parametric && xparam)
! 860: int_error("previous parametric function not fully specified", c_token);
! 861:
! 862: if (equals(++c_token, "x1y1")) {
! 863: x_axis = FIRST_X_AXIS;
! 864: y_axis = FIRST_Y_AXIS;
! 865: ++c_token;
! 866: } else if (equals(c_token, "x2y2")) {
! 867: x_axis = SECOND_X_AXIS;
! 868: y_axis = SECOND_Y_AXIS;
! 869: ++c_token;
! 870: } else if (equals(c_token, "x1y2")) {
! 871: x_axis = FIRST_X_AXIS;
! 872: y_axis = SECOND_Y_AXIS;
! 873: ++c_token;
! 874: } else if (equals(c_token, "x2y1")) {
! 875: x_axis = SECOND_X_AXIS;
! 876: y_axis = FIRST_Y_AXIS;
! 877: ++c_token;
! 878: } else
! 879: int_error("axes must be x1y1, x1y2, x2y1 or x2y2", c_token);
! 880: } else {
! 881: x_axis = FIRST_X_AXIS;
! 882: y_axis = FIRST_Y_AXIS;
! 883: }
! 884:
! 885:
! 886: this_plot->x_axis = x_axis;
! 887: this_plot->y_axis = y_axis;
! 888:
! 889: /* we can now do some checks that we deferred earlier */
! 890:
! 891: if (this_plot->plot_type == DATA) {
! 892: if (!(uses_axis[x_axis] & 1) && autoscale_lx) {
! 893: if (auto_array[x_axis] & 1)
! 894: min_array[x_axis] = VERYLARGE;
! 895: if (auto_array[x_axis] & 2)
! 896: max_array[x_axis] = -VERYLARGE;
! 897: }
! 898: if (datatype[x_axis] == TIME) {
! 899: if (specs < 2)
! 900: int_error("Need full using spec for x time data", c_token);
! 901: df_timecol[0] = 1;
! 902: }
! 903: if (datatype[y_axis] == TIME) {
! 904: if (specs < 1)
! 905: int_error("Need using spec for y time data", c_token);
! 906: df_timecol[y_axis] = 1; /* need other cols, but I'm lazy */
! 907: }
! 908: uses_axis[x_axis] |= 1; /* separate record of datafile and func */
! 909: uses_axis[y_axis] |= 1;
! 910: } else if (!parametric || !xparam) {
! 911: /* for x part of a parametric function, axes are possibly wrong */
! 912: uses_axis[x_axis] |= 2; /* separate record of data and func */
! 913: uses_axis[y_axis] |= 2;
! 914: }
! 915: if (almost_equals(c_token, "t$itle")) {
! 916: if (parametric) {
! 917: if (xparam)
! 918: int_error("\"title\" allowed only after parametric function fully specified", c_token);
! 919: else if (xtitle != NULL)
! 920: xtitle[0] = '\0'; /* Remove default title . */
! 921: }
! 922: c_token++;
! 923: if (isstring(c_token)) {
! 924: m_quote_capture(&(this_plot->title), c_token, c_token);
! 925: } else {
! 926: int_error("expecting \"title\" for plot", c_token);
! 927: }
! 928: c_token++;
! 929: } else if (almost_equals(c_token, "not$itle")) {
! 930: if (xtitle != NULL)
! 931: xtitle[0] = '\0';
! 932: c_token++;
! 933: } else {
! 934: m_capture(&(this_plot->title), start_token, end_token);
! 935: if (xparam)
! 936: xtitle = this_plot->title;
! 937: }
! 938:
! 939:
! 940: if (almost_equals(c_token, "w$ith")) {
! 941: if (parametric && xparam)
! 942: int_error("\"with\" allowed only after parametric function fully specified", c_token);
! 943: this_plot->plot_style = get_style();
! 944: }
! 945: /* pick up line/point specs
! 946: * - point spec allowed if style uses points, ie style&2 != 0
! 947: * - keywords for lt and pt are optional
! 948: */
! 949: LP_PARSE(this_plot->lp_properties, 1, this_plot->plot_style & 2,
! 950: line_num, point_num);
! 951:
! 952: /* allow old-style syntax too - ignore case lt 3 4 for example */
! 953: if (!equals(c_token, ",") && !END_OF_COMMAND) {
! 954: struct value t;
! 955: this_plot->lp_properties.l_type =
! 956: this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
! 957:
! 958: if (!equals(c_token, ",") && !END_OF_COMMAND)
! 959: this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
! 960: }
! 961: if (!xparam) {
! 962: if (this_plot->plot_style & 2) /* style includes points */
! 963: ++point_num;
! 964: ++line_num;
! 965: }
! 966: if (this_plot->plot_type == DATA) {
! 967: /* actually get the data now */
! 968: get_data(this_plot);
! 969:
! 970: /* sort */
! 971: switch (this_plot->plot_smooth) { /* sort and average, if */
! 972: case UNIQUE: /* the style requires */
! 973: case CSPLINES:
! 974: case ACSPLINES:
! 975: case SBEZIER:
! 976: sort_points(this_plot);
! 977: cp_implode(this_plot);
! 978: break;
! 979: default:
! 980: ; /* keep gcc -Wall happy */
! 981: }
! 982: switch (this_plot->plot_smooth) { /* create new data set */
! 983: case SBEZIER: /* by evaluation of */
! 984: case BEZIER: /* interpolation routines */
! 985: case ACSPLINES:
! 986: case CSPLINES:
! 987: gen_interp(this_plot);
! 988: break;
! 989: default:
! 990: ; /* keep gcc -Wall happy */
! 991: }
! 992:
! 993: /* now that we know the plot style, adjust the x- and yrange */
! 994: /* adjust_range(this_plot); no longer needed */
! 995: }
! 996: this_plot->token = c_token; /* save end of plot for second pass */
! 997: tp_ptr = &(this_plot->next_cp);
! 998:
! 999: } /* !is_defn */
! 1000:
! 1001: if (equals(c_token, ","))
! 1002: c_token++;
! 1003: else
! 1004: break;
! 1005: }
! 1006:
! 1007: if (parametric && xparam)
! 1008: int_error("parametric function not fully specified", NO_CARET);
! 1009:
! 1010:
! 1011: /*** Second Pass: Evaluate the functions ***/
! 1012: /*
! 1013: * Everything is defined now, except the function data. We expect no
! 1014: * syntax errors, etc, since the above parsed it all. This makes the code
! 1015: * below simpler. If autoscale_ly, the yrange may still change.
! 1016: * we stored last token of each plot, so we dont need to do everything again
! 1017: */
! 1018:
! 1019: /* give error if xrange badly set from missing datafile error
! 1020: * parametric or polar fns can still affect x ranges
! 1021: */
! 1022:
! 1023: if (!parametric && !polar) {
! 1024: if (min_array[FIRST_X_AXIS] == VERYLARGE ||
! 1025: max_array[FIRST_X_AXIS] == -VERYLARGE)
! 1026: int_error("x range is invalid", c_token);
! 1027: /* check that xmin -> xmax is not too small */
! 1028: fixup_range(FIRST_X_AXIS, "x");
! 1029:
! 1030: if (uses_axis[SECOND_X_AXIS] & 1) {
! 1031: /* some data plots with x2 */
! 1032: if (min_array[SECOND_X_AXIS] == VERYLARGE ||
! 1033: max_array[SECOND_X_AXIS] == -VERYLARGE)
! 1034: int_error("x2 range is invalid", c_token);
! 1035: /* check that x2min -> x2max is not too small */
! 1036: fixup_range(SECOND_X_AXIS, "x2");
! 1037: } else if (auto_array[SECOND_X_AXIS]) {
! 1038: /* copy x1's range */
! 1039: if (auto_array[SECOND_X_AXIS] & 1)
! 1040: min_array[SECOND_X_AXIS] = min_array[FIRST_X_AXIS];
! 1041: if (auto_array[SECOND_X_AXIS] & 2)
! 1042: max_array[SECOND_X_AXIS] = max_array[FIRST_X_AXIS];
! 1043: }
! 1044: }
! 1045: if (some_functions) {
! 1046:
! 1047: /* call the controlled variable t, since x_min can also mean smallest x */
! 1048: double t_min, t_max, t_step;
! 1049:
! 1050: if (parametric || polar) {
! 1051: if (!(uses_axis[FIRST_X_AXIS] & 1)) {
! 1052: /* these have not yet been set to full width */
! 1053: if (auto_array[FIRST_X_AXIS] & 1)
! 1054: min_array[FIRST_X_AXIS] = VERYLARGE;
! 1055: if (auto_array[FIRST_X_AXIS] & 2)
! 1056: max_array[FIRST_X_AXIS] = -VERYLARGE;
! 1057: }
! 1058: if (!(uses_axis[SECOND_X_AXIS] & 1)) {
! 1059: if (auto_array[SECOND_X_AXIS] & 1)
! 1060: min_array[SECOND_X_AXIS] = VERYLARGE;
! 1061: if (auto_array[SECOND_X_AXIS] & 2)
! 1062: max_array[SECOND_X_AXIS] = -VERYLARGE;
! 1063: }
! 1064: }
! 1065: #define SET_DUMMY_RANGE(AXIS) \
! 1066: do{ assert(!polar && !parametric); \
! 1067: if (log_array[AXIS]) {\
! 1068: if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0)\
! 1069: int_error("x/x2 range must be greater than 0 for log scale!", NO_CARET);\
! 1070: t_min = log(min_array[AXIS])/log_base_array[AXIS]; t_max = log(max_array[AXIS])/log_base_array[AXIS];\
! 1071: } else {\
! 1072: t_min = min_array[AXIS]; t_max = max_array[AXIS];\
! 1073: }\
! 1074: t_step = (t_max - t_min) / (samples - 1); \
! 1075: }while(0)
! 1076:
! 1077: if (parametric || polar) {
! 1078: t_min = min_array[T_AXIS];
! 1079: t_max = max_array[T_AXIS];
! 1080: t_step = (t_max - t_min) / (samples - 1);
! 1081: }
! 1082: /* else we'll do it on each plot */
! 1083:
! 1084: tp_ptr = &(first_plot);
! 1085: plot_num = 0;
! 1086: this_plot = first_plot;
! 1087: c_token = begin_token; /* start over */
! 1088:
! 1089: /* Read through functions */
! 1090: while (TRUE) {
! 1091: if (is_definition(c_token)) {
! 1092: define();
! 1093: } else {
! 1094: int x_axis = this_plot->x_axis;
! 1095: int y_axis = this_plot->y_axis;
! 1096:
! 1097: plot_num++;
! 1098: if (!isstring(c_token)) { /* function to plot */
! 1099: if (parametric) { /* toggle parametric axes */
! 1100: xparam = 1 - xparam;
! 1101: }
! 1102: dummy_func = &plot_func;
! 1103: plot_func.at = temp_at(); /* reparse function */
! 1104:
! 1105: if (!parametric && !polar) {
! 1106: SET_DUMMY_RANGE(x_axis);
! 1107: }
! 1108: for (i = 0; i < samples; i++) {
! 1109: double temp;
! 1110: struct value a;
! 1111: double t = t_min + i * t_step;
! 1112: /* parametric/polar => NOT a log quantity */
! 1113: double x = (!parametric && !polar &&
! 1114: log_array[x_axis]) ? pow(base_array[x_axis], t) : t;
! 1115:
! 1116: (void) Gcomplex(&plot_func.dummy_values[0], x, 0.0);
! 1117: evaluate_at(plot_func.at, &a);
! 1118:
! 1119: if (undefined || (fabs(imag(&a)) > zero)) {
! 1120: this_plot->points[i].type = UNDEFINED;
! 1121: continue;
! 1122: }
! 1123: temp = real(&a);
! 1124:
! 1125: this_plot->points[i].z = -1.0; /* width of box not specified */
! 1126: this_plot->points[i].type = INRANGE; /* for the moment */
! 1127:
! 1128: if (parametric) {
! 1129: /* we cannot do range-checking now, since for
! 1130: * the x function we did not know which axes
! 1131: * we were using
! 1132: * DO NOT TAKE LOGS YET - do it in parametric_fixup
! 1133: */
! 1134: this_plot->points[i].x = t; /* ignored, actually... */
! 1135: this_plot->points[i].y = temp;
! 1136: } else if (polar) {
! 1137: double y;
! 1138: if (!(autoscale_r & 2) && temp > rmax)
! 1139: this_plot->points[i].type = OUTRANGE;
! 1140: if (!(autoscale_r & 1))
! 1141: temp -= rmin;
! 1142: y = temp * sin(x * ang2rad);
! 1143: x = temp * cos(x * ang2rad);
! 1144: temp = y;
! 1145: STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].x, x, this_plot->points[i].type,
! 1146: x_axis, NOOP, goto come_here_if_undefined);
! 1147: STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, y, this_plot->points[i].type,
! 1148: y_axis, NOOP, goto come_here_if_undefined);
! 1149: } else { /* neither parametric or polar */
! 1150: /* If non-para, it must be INRANGE */
! 1151: this_plot->points[i].x = t; /* logscale ? log(x) : x */
! 1152:
! 1153: STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, temp, this_plot->points[i].type,
! 1154: y_axis + (x_axis - y_axis) * xparam, NOOP, goto come_here_if_undefined);
! 1155:
! 1156: come_here_if_undefined: /* could not use a continue in this case */
! 1157: ; /* ansi requires a statement after a label */
! 1158: }
! 1159:
! 1160: } /* loop over samples */
! 1161: this_plot->p_count = i; /* samples */
! 1162: }
! 1163: c_token = this_plot->token; /* skip all modifers func / whole of data plots */
! 1164:
! 1165: tp_ptr = &(this_plot->next_cp); /* used below */
! 1166: this_plot = this_plot->next_cp;
! 1167: }
! 1168:
! 1169: if (equals(c_token, ","))
! 1170: c_token++;
! 1171: else
! 1172: break;
! 1173: }
! 1174:
! 1175: if (parametric) {
! 1176: /* Now actually fix the plot pairs to be single plots */
! 1177: /* also fixes up polar&¶metric fn plots */
! 1178: parametric_fixup(first_plot, &plot_num);
! 1179: /* we omitted earlier check for range too small */
! 1180: fixup_range(FIRST_X_AXIS, "x");
! 1181: if (uses_axis[SECOND_X_AXIS]) {
! 1182: fixup_range(SECOND_X_AXIS, "x2");
! 1183: }
! 1184: }
! 1185: } /* some_functions */
! 1186: /* throw out all curve_points at end of list, that we don't need */
! 1187: cp_free(*tp_ptr);
! 1188: *tp_ptr = NULL;
! 1189:
! 1190:
! 1191: /* if first_plot is NULL, we have no functions or data at all. This can
! 1192: happen, if you type "plot x=5", since x=5 is a variable assignment */
! 1193:
! 1194: if (plot_num == 0 || first_plot == NULL) {
! 1195: int_error("no functions or data to plot", c_token);
! 1196: }
! 1197: if (uses_axis[FIRST_X_AXIS]) {
! 1198: if (max_array[FIRST_X_AXIS] == -VERYLARGE ||
! 1199: min_array[FIRST_X_AXIS] == VERYLARGE)
! 1200: int_error("all points undefined!", NO_CARET);
! 1201: FIXUP_RANGE_FOR_LOG(FIRST_X_AXIS, x);
! 1202: }
! 1203: if (uses_axis[SECOND_X_AXIS]) {
! 1204: if (max_array[SECOND_X_AXIS] == -VERYLARGE ||
! 1205: min_array[SECOND_X_AXIS] == VERYLARGE)
! 1206: int_error("all points undefined!", NO_CARET);
! 1207: FIXUP_RANGE_FOR_LOG(SECOND_X_AXIS, x2);
! 1208: } else {
! 1209: assert(uses_axis[FIRST_X_AXIS]);
! 1210: if (auto_array[SECOND_X_AXIS] & 1)
! 1211: min_array[SECOND_X_AXIS] = min_array[FIRST_X_AXIS];
! 1212: if (auto_array[SECOND_X_AXIS] & 2)
! 1213: max_array[SECOND_X_AXIS] = max_array[FIRST_X_AXIS];
! 1214: }
! 1215:
! 1216: if (!uses_axis[FIRST_X_AXIS]) {
! 1217: assert(uses_axis[SECOND_X_AXIS]);
! 1218: if (auto_array[FIRST_X_AXIS] & 1)
! 1219: min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS];
! 1220: if (auto_array[FIRST_X_AXIS] & 2)
! 1221: max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS];
! 1222: }
! 1223: if (uses_axis[FIRST_Y_AXIS]) {
! 1224: if (max_array[FIRST_Y_AXIS] == -VERYLARGE ||
! 1225: min_array[FIRST_Y_AXIS] == VERYLARGE)
! 1226: int_error("all points undefined!", NO_CARET);
! 1227: fixup_range(FIRST_Y_AXIS, "y");
! 1228: FIXUP_RANGE_FOR_LOG(FIRST_Y_AXIS, y);
! 1229: } /* else we want to copy y2 range, but need to fix it up first */
! 1230: if (uses_axis[SECOND_Y_AXIS]) {
! 1231: if (max_array[SECOND_Y_AXIS] == -VERYLARGE ||
! 1232: min_array[SECOND_Y_AXIS] == VERYLARGE)
! 1233: int_error("all points undefined!", NO_CARET);
! 1234: fixup_range(SECOND_Y_AXIS, "y2");
! 1235: FIXUP_RANGE_FOR_LOG(SECOND_Y_AXIS, y2);
! 1236: } else {
! 1237: assert(uses_axis[FIRST_Y_AXIS]);
! 1238: if (auto_array[SECOND_Y_AXIS] & 1)
! 1239: min_array[SECOND_Y_AXIS] = min_array[FIRST_Y_AXIS];
! 1240: if (auto_array[SECOND_Y_AXIS] & 2)
! 1241: max_array[SECOND_Y_AXIS] = max_array[FIRST_Y_AXIS];
! 1242: }
! 1243:
! 1244: if (!uses_axis[FIRST_Y_AXIS]) {
! 1245: assert(uses_axis[SECOND_Y_AXIS]);
! 1246: if (auto_array[FIRST_Y_AXIS] & 1)
! 1247: min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS];
! 1248: if (auto_array[FIRST_Y_AXIS] & 2)
! 1249: max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS];
! 1250: }
! 1251: #define WRITEBACK(axis,min,max) \
! 1252: if(range_flags[axis]&RANGE_WRITEBACK) \
! 1253: {if (auto_array[axis]&1) min = min_array[axis]; \
! 1254: if (auto_array[axis]&2) max = max_array[axis]; \
! 1255: }
! 1256:
! 1257: WRITEBACK(FIRST_X_AXIS, xmin, xmax)
! 1258: WRITEBACK(FIRST_Y_AXIS, ymin, ymax)
! 1259: WRITEBACK(SECOND_X_AXIS, x2min, x2max)
! 1260: WRITEBACK(SECOND_Y_AXIS, y2min, y2max)
! 1261: if (strcmp(term->name, "table") == 0)
! 1262: print_table(first_plot, plot_num);
! 1263: else {
! 1264: START_LEAK_CHECK(); /* check for memory leaks in this routine */
! 1265:
! 1266: /* do_plot now uses max_array[], etc */
! 1267: do_plot(first_plot, plot_num);
! 1268:
! 1269: END_LEAK_CHECK();
! 1270: }
! 1271:
! 1272: /* if we get here, all went well, so record this line for replot */
! 1273:
! 1274: if (plot_token != -1) {
! 1275: /* note that m_capture also frees the old replot_line */
! 1276: m_capture(&replot_line, plot_token, c_token - 1);
! 1277: plot_token = -1;
! 1278: }
! 1279: cp_free(first_plot);
! 1280: first_plot = NULL;
! 1281: } /* eval_plots */
! 1282:
! 1283:
! 1284:
! 1285:
! 1286: static void parametric_fixup(start_plot, plot_num)
! 1287: struct curve_points *start_plot;
! 1288: int *plot_num;
! 1289: /*
! 1290: * The hardest part of this routine is collapsing the FUNC plot types in the
! 1291: * list (which are garanteed to occur in (x,y) pairs while preserving the
! 1292: * non-FUNC type plots intact. This means we have to work our way through
! 1293: * various lists. Examples (hand checked): start_plot:F1->F2->NULL ==>
! 1294: * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
! 1295: * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
! 1296: *
! 1297: */
! 1298: {
! 1299: struct curve_points *xp, *new_list = NULL, *free_list = NULL;
! 1300: struct curve_points **last_pointer = &new_list;
! 1301: int i, tlen, curve;
! 1302: char *new_title;
! 1303:
! 1304: /*
! 1305: * Ok, go through all the plots and move FUNC types together. Note: this
! 1306: * originally was written to look for a NULL next pointer, but gnuplot
! 1307: * wants to be sticky in grabbing memory and the right number of items in
! 1308: * the plot list is controlled by the plot_num variable.
! 1309: *
! 1310: * Since gnuplot wants to do this sticky business, a free_list of
! 1311: * curve_points is kept and then tagged onto the end of the plot list as
! 1312: * this seems more in the spirit of the original memory behavior than
! 1313: * simply freeing the memory. I'm personally not convinced this sort of
! 1314: * concern is worth it since the time spent computing points seems to
! 1315: * dominate any garbage collecting that might be saved here...
! 1316: */
! 1317: new_list = xp = start_plot;
! 1318: curve = 0;
! 1319:
! 1320: while (++curve <= *plot_num) {
! 1321: if (xp->plot_type == FUNC) {
! 1322: /* Here's a FUNC parametric function defined as two parts. */
! 1323: struct curve_points *yp = xp->next_cp;
! 1324:
! 1325: --(*plot_num);
! 1326:
! 1327: assert(xp->p_count == yp->p_count);
! 1328:
! 1329: /* because syntax is plot x(t), y(t) axes ..., only
! 1330: * the y function axes are correct
! 1331: */
! 1332:
! 1333:
! 1334: /*
! 1335: * Go through all the points assigning the y's from xp to be the x's
! 1336: * for yp. In polar mode, we need to check max's and min's as we go.
! 1337: */
! 1338:
! 1339: for (i = 0; i < yp->p_count; ++i) {
! 1340: if (polar) {
! 1341: double r = yp->points[i].y;
! 1342: double t = xp->points[i].y * ang2rad;
! 1343: double x, y;
! 1344: if (!(autoscale_r & 2) && r > rmax)
! 1345: yp->points[i].type = OUTRANGE;
! 1346: if (!(autoscale_r & 1))
! 1347: r -= rmin; /* store internally as if plotting r(t)-rmin */
! 1348: x = r * cos(t);
! 1349: y = r * sin(t);
! 1350: /* we hadn't done logs when we stored earlier */
! 1351: STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x, yp->points[i].type,
! 1352: xp->x_axis, NOOP, NOOP);
! 1353: STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y, yp->points[i].type,
! 1354: xp->y_axis, NOOP, NOOP);
! 1355: } else {
! 1356: double x = xp->points[i].y;
! 1357: double y = yp->points[i].y;
! 1358: STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x,
! 1359: yp->points[i].type, yp->x_axis, NOOP, NOOP);
! 1360: STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y,
! 1361: yp->points[i].type, yp->y_axis, NOOP, NOOP);
! 1362: }
! 1363: }
! 1364:
! 1365: /* Ok, fix up the title to include both the xp and yp plots. */
! 1366: if (xp->title && xp->title[0] != '\0' && yp->title) {
! 1367: tlen = strlen(yp->title) + strlen(xp->title) + 3;
! 1368: new_title = gp_alloc((unsigned long) tlen, "string");
! 1369: strcpy(new_title, xp->title);
! 1370: strcat(new_title, ", "); /* + 2 */
! 1371: strcat(new_title, yp->title); /* + 1 = + 3 */
! 1372: free(yp->title);
! 1373: yp->title = new_title;
! 1374: }
! 1375: /* move xp to head of free list */
! 1376: xp->next_cp = free_list;
! 1377: free_list = xp;
! 1378:
! 1379: /* append yp to new_list */
! 1380: *last_pointer = yp;
! 1381: last_pointer = &(yp->next_cp);
! 1382: xp = yp->next_cp;
! 1383:
! 1384: } else { /* data plot */
! 1385: assert(*last_pointer == xp);
! 1386: last_pointer = &(xp->next_cp);
! 1387: xp = xp->next_cp;
! 1388: }
! 1389: } /* loop over plots */
! 1390:
! 1391: first_plot = new_list;
! 1392:
! 1393: /* Ok, stick the free list at the end of the curve_points plot list. */
! 1394: *last_pointer = free_list;
! 1395: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>