[BACK]Return to plot2d.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

Annotation of OpenXM_contrib/gnuplot/plot2d.c, Revision 1.1.1.2

1.1       maekawa     1: #ifndef lint
1.1.1.2 ! maekawa     2: static char *RCSid = "$Id: plot2d.c,v 1.16.2.4 1999/10/11 12:18:56 lhecking Exp $";
1.1       maekawa     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: {
1.1.1.2 ! maekawa   291:     int i /* num. points ! */ , j;
        !           292:     int max_cols, min_cols;    /* allowed range of column numbers */
1.1       maekawa   293:     double v[NCOL];
                    294:     int storetoken = this_plot->token;
                    295:
                    296:     /* eval_plots has already opened file */
                    297:
                    298:     switch (this_plot->plot_style) {   /* set maximum columns to scan */
                    299:     case XYERRORBARS:
                    300:     case BOXXYERROR:
1.1.1.2 ! maekawa   301:        max_cols = 7;
        !           302:        min_cols = 4;
1.1       maekawa   303:        break;
                    304:
                    305:     case FINANCEBARS:
                    306:     case CANDLESTICKS:
1.1.1.2 ! maekawa   307:        min_cols = max_cols = 5;
        !           308:        break;
        !           309:
        !           310:     case BOXERROR:
        !           311:        max_cols = 5;
        !           312:        min_cols = 4;
        !           313:        break;
        !           314:
        !           315:     case VECTOR:
        !           316:        min_cols = max_cols = 4;
1.1       maekawa   317:        break;
                    318:
                    319:     case XERRORBARS:
                    320:     case YERRORBARS:
1.1.1.2 ! maekawa   321:        max_cols = 4;
        !           322:        min_cols = 3;
1.1       maekawa   323:        break;
                    324:
                    325:     case BOXES:
1.1.1.2 ! maekawa   326:        min_cols = 2;
        !           327:        max_cols = 4;
1.1       maekawa   328:
                    329:     default:
1.1.1.2 ! maekawa   330:        min_cols = 1;
        !           331:        max_cols = 2;
1.1       maekawa   332:     }
                    333:
                    334:     if (this_plot->plot_smooth == ACSPLINES)
1.1.1.2 ! maekawa   335:        max_cols = 3;
        !           336:
        !           337:     if (df_no_use_specs > max_cols)
        !           338:        int_error("Too many using specs for this style", NO_CARET);
1.1       maekawa   339:
1.1.1.2 ! maekawa   340:     if (df_no_use_specs >0 && df_no_use_specs < min_cols)
        !           341:        int_error("Not enough columns for this style", NO_CARET);
1.1       maekawa   342:
                    343:     i = 0;
1.1.1.2 ! maekawa   344:     while ((j = df_readline(v, max_cols)) != DF_EOF) {
        !           345:        /* j <= max_cols */
1.1       maekawa   346:
                    347:        if (i >= this_plot->p_max) {
                    348:            /*
                    349:             * overflow about to occur. Extend size of points[] array. We
                    350:             * either double the size, or add 1000 points, whichever is a
                    351:             * smaller increment. Note i = p_max.
                    352:             */
                    353:            cp_extend(this_plot, i + (i < 1000 ? i : 1000));
                    354:        }
                    355:        /* Limitation: No xerrorbars with boxes */
                    356:        switch (j) {
                    357:        default:
                    358:            {
                    359:                char message[80];
                    360:                sprintf(message, "internal error : df_readline returned %d : datafile line %d", j, df_line_number);
                    361:                df_close();
                    362:                int_error(message, c_token);
                    363:            }
                    364:        case DF_UNDEFINED:
                    365:            /* bad result from extended using expression */
                    366:            this_plot->points[i].type = UNDEFINED;
                    367:            i++;
                    368:            continue;
                    369:
                    370:        case DF_FIRST_BLANK:
                    371:            /* break in data, make next point undefined */
                    372:            this_plot->points[i].type = UNDEFINED;
                    373:            i++;
                    374:            continue;
                    375:
                    376:        case DF_SECOND_BLANK:
                    377:            /* second blank line. We dont do anything
                    378:             * (we did everything when we got FIRST one)
                    379:             */
                    380:            continue;
                    381:
                    382:        case 0:         /* not blank line, but df_readline couldn't parse it */
                    383:            {
                    384:                char message[80];
                    385:                sprintf(message, "Bad data on line %d", df_line_number);
                    386:                df_close();
                    387:                int_error(message, this_plot->token);
                    388:            }
                    389:
                    390:        case 1:
                    391:            {                   /* only one number */
                    392:                /* x is index, assign number to y */
                    393:                v[1] = v[0];
                    394:                v[0] = df_datum;
                    395:                /* nobreak */
                    396:            }
                    397:
                    398:        case 2:
                    399:            /* x, y */
                    400:            /* ylow and yhigh are same as y */
                    401:
                    402:            if (this_plot->plot_style == BOXES && boxwidth > 0) {
                    403:                /* calc width now */
                    404:                store2d_point(this_plot, i++, v[0], v[1], v[0] - boxwidth / 2, v[0] + boxwidth / 2, v[1], v[1], 0.0);
                    405:            } else {
                    406:                /* xlow and xhigh are same as x */
                    407:                store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1],
                    408:                              -1.0);    /* auto width if boxes, else ignored */
                    409:            }
                    410:            break;
                    411:
                    412:
                    413:        case 3:
                    414:            /* x, y, ydelta OR x, y, xdelta OR x, y, width */
                    415:            if (this_plot->plot_smooth == ACSPLINES)
                    416:                store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
                    417:            else
                    418:                switch (this_plot->plot_style) {
                    419:                default:
                    420:                    int_warn("This plot style not work with 3 cols. Setting to yerrorbars", storetoken);
                    421:                    this_plot->plot_style = YERRORBARS;
                    422:                    /* fall through */
                    423:
                    424:                case YERRORBARS:
                    425:                case BOXERROR:  /* x, y, dy */
                    426:                    store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1] - v[2], v[1] + v[2],
                    427:                                  -1.0);        /* auto width if boxes, else ignored */
                    428:                    break;
                    429:
                    430:                case XERRORBARS:
                    431:                    store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2], v[0] + v[2], v[1], v[1], 0.0);
                    432:                    break;
                    433:
                    434:                case BOXES:
                    435:                    /* calculate xmin and xmax here, so that logs are taken if
                    436:                     * if necessary
                    437:                     */
                    438:                    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);
                    439:                    break;
                    440:
                    441:                }               /*inner switch */
                    442:
                    443:            break;
                    444:
                    445:
                    446:
                    447:        case 4:
                    448:            /* x, y, ylow, yhigh OR
                    449:             * x, y, xlow, xhigh OR
                    450:             * x, y, xdelta, ydelta OR
                    451:             * x, y, ydelta, width
                    452:             */
                    453:
                    454:            switch (this_plot->plot_style) {
                    455:            default:
                    456:                int_warn("This plot style does not work with 4 cols. Setting to yerrorbars",
                    457:                         storetoken);
                    458:                this_plot->plot_style = YERRORBARS;
                    459:                /* fall through */
                    460:
                    461:            case YERRORBARS:
                    462:                store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], -1.0);
                    463:                break;
                    464:
                    465:            case BOXXYERROR:    /* x, y, dx, dy */
                    466:            case XYERRORBARS:
                    467:                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);
                    468:                break;
                    469:
                    470:
                    471:            case BOXES: /* x, y, xmin, xmax */
                    472:                store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], 0.0);
                    473:                break;
                    474:
                    475:            case XERRORBARS:
                    476:                store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], 0.0);
                    477:                break;
                    478:
                    479:            case BOXERROR:
                    480:                /* x,y, xleft, xright */
                    481:                store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1] - v[2], v[1] + v[2], 0.0);
                    482:                break;
                    483:
                    484:            case VECTOR:
                    485:                /* x,y,dx,dy */
                    486:                store2d_point(this_plot, i++, v[0], v[1], v[0], v[0] + v[2], v[1], v[1] + v[3], -1.0);
                    487:                break;
                    488:            }                   /*inner switch */
                    489:
                    490:            break;
                    491:
                    492:
                    493:        case 5:
                    494:            {                   /* x, y, ylow, yhigh, width  or  x open low high close */
                    495:                switch (this_plot->plot_style) {
                    496:                default:
                    497:                    int_warn("Five col. plot style must be boxerrorbars, financebars or candlesticks. Setting to boxerrorbars", storetoken);
                    498:                    this_plot->plot_style = BOXERROR;
                    499:                    /*fall through */
                    500:
                    501:                case BOXERROR:  /* x, y, ylow, yhigh, width */
                    502:                    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);
                    503:                    break;
                    504:
                    505:                case FINANCEBARS:
                    506:                case CANDLESTICKS:
                    507:                    store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], v[4]);
                    508:                    break;
                    509:                }
                    510:                break;
                    511:            }
                    512:
                    513:        case 7:
                    514:            /* same as six columns. Width ignored */
                    515:            /* eh ? - fall through */
                    516:        case 6:
                    517:            /* x, y, xlow, xhigh, ylow, yhigh */
                    518:            switch (this_plot->plot_style) {
                    519:            default:
                    520:                int_warn("This plot style not work with 6 cols. Setting to xyerrorbars", storetoken);
                    521:                this_plot->plot_style = XYERRORBARS;
                    522:                /*fall through */
                    523:            case XYERRORBARS:
                    524:            case BOXXYERROR:
                    525:                store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[4], v[5], 0.0);
                    526:                break;
                    527:            }
                    528:
                    529:        }                       /*switch */
                    530:
                    531:     }                          /*while */
                    532:
                    533:     this_plot->p_count = i;
                    534:     cp_extend(this_plot, i);   /* shrink to fit */
                    535:
                    536:     df_close();
                    537: }
                    538:
                    539: /* called by get_data for each point */
                    540: static void store2d_point(this_plot, i, x, y, xlow, xhigh, ylow, yhigh, width)
                    541: struct curve_points *this_plot;
                    542: int i;                         /* point number */
                    543: double x, y;
                    544: double ylow, yhigh;
                    545: double xlow, xhigh;
                    546: double width;                  /* -1 means autocalc, 0 means use xmin/xmax */
                    547: {
                    548:     struct coordinate GPHUGE *cp = &(this_plot->points[i]);
                    549:     int dummy_type = INRANGE;  /* sometimes we dont care about outranging */
                    550:
                    551:
                    552:     /* jev -- pass data values thru user-defined function */
                    553:     /* div -- y is dummy variable 2 - copy value there */
                    554:     if (ydata_func.at) {
                    555:        struct value val;
                    556:
                    557:        (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0);
                    558:        ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
                    559:        evaluate_at(ydata_func.at, &val);
                    560:        y = undefined ? 0.0 : real(&val);
                    561:
                    562:        (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0);
                    563:        ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
                    564:        evaluate_at(ydata_func.at, &val);
                    565:        ylow = undefined ? 0 : real(&val);
                    566:
                    567:        (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0);
                    568:        ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
                    569:        evaluate_at(ydata_func.at, &val);
                    570:        yhigh = undefined ? 0 : real(&val);
                    571:     }
                    572:     dummy_type = cp->type = INRANGE;
                    573:
                    574:     if (polar) {
                    575:        double newx, newy;
                    576:        if (!(autoscale_r & 2) && y > rmax) {
                    577:            cp->type = OUTRANGE;
                    578:        }
                    579:        if (!(autoscale_r & 1)) {
                    580:            /* we store internally as if plotting r(t)-rmin */
                    581:            y -= rmin;
                    582:        }
                    583:        newx = y * cos(x * ang2rad);
                    584:        newy = y * sin(x * ang2rad);
                    585: #if 0 /* HBB 981118: added polar errorbars */
                    586:        /* only lines and points supported with polar */
                    587:        y = ylow = yhigh = newy;
                    588:        x = xlow = xhigh = newx;
                    589: #else
                    590:        y = newy;
                    591:        x = newx;
                    592:
                    593:        if (!(autoscale_r & 2) && yhigh > rmax) {
                    594:            cp->type = OUTRANGE;
                    595:        }
                    596:        if (!(autoscale_r & 1)) {
                    597:            /* we store internally as if plotting r(t)-rmin */
                    598:            yhigh -= rmin;
                    599:        }
                    600:        newx = yhigh * cos(xhigh * ang2rad);
                    601:        newy = yhigh * sin(xhigh * ang2rad);
                    602:        yhigh = newy;
                    603:        xhigh = newx;
                    604:
                    605:        if (!(autoscale_r & 2) && ylow > rmax) {
                    606:            cp->type = OUTRANGE;
                    607:        }
                    608:        if (!(autoscale_r & 1)) {
                    609:            /* we store internally as if plotting r(t)-rmin */
                    610:            ylow -= rmin;
                    611:        }
                    612:        newx = ylow * cos(xlow * ang2rad);
                    613:        newy = ylow * sin(xlow * ang2rad);
                    614:        ylow = newy;
                    615:        xlow = newx;
                    616: #endif
                    617:     }
                    618:     /* return immediately if x or y are undefined
                    619:      * we dont care if outrange for high/low.
                    620:      * BUT if high/low undefined (ie log( < 0 ), no number is stored,
                    621:      * but graphics.c doesn't know.
                    622:      * explicitly store -VERYLARGE;
                    623:      */
                    624:     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->x, x, cp->type, this_plot->x_axis, NOOP, return);
                    625:     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xlow, xlow, dummy_type, this_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
                    626:     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xhigh, xhigh, dummy_type, this_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
                    627:     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->y, y, cp->type, this_plot->y_axis, NOOP, return);
                    628:     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->ylow, ylow, dummy_type, this_plot->y_axis, NOOP, cp->ylow = -VERYLARGE);
                    629:     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->yhigh, yhigh, dummy_type, this_plot->y_axis, NOOP, cp->yhigh = -VERYLARGE);
                    630:     cp->z = width;
                    631: }                              /* store2d_point */
                    632:
                    633:
                    634:
                    635: /*
                    636:  * print_points: a debugging routine to print out the points of a curve, and
                    637:  * the curve structure. If curve<0, then we print the list of curves.
                    638:  */
                    639:
                    640: #if 0                          /* not used */
                    641: static char *plot_type_names[4] =
                    642: {
                    643:     "Function", "Data", "3D Function", "3d data"
                    644: };
                    645: static char *plot_style_names[14] =
                    646: {
                    647:     "Lines", "Points", "Impulses", "LinesPoints", "Dots", "XErrorbars",
                    648:  "YErrorbars", "XYErrorbars", "BoxXYError", "Boxes", "Boxerror", "Steps",
                    649:     "FSteps", "Vector"
                    650: };
                    651: static char *plot_smooth_names[5] =
                    652: {
                    653:     "None", "Unique", "CSplines", "ACSplines", "Bezier", "SBezier"
                    654: };
                    655:
                    656: static void print_points(curve)
                    657: int curve;                     /* which curve to print */
                    658: {
                    659:     register struct curve_points *this_plot;
                    660:     int i;
                    661:
                    662:     if (curve < 0) {
                    663:        for (this_plot = first_plot, i = 0;
                    664:             this_plot != NULL;
                    665:             i++, this_plot = this_plot->next_cp) {
                    666:            printf("Curve %d:\n", i);
                    667:            if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4)
                    668:                printf("Plot type %d: %s\n", (int) (this_plot->plot_type),
                    669:                       plot_type_names[(int) (this_plot->plot_type)]);
                    670:            else
                    671:                printf("Plot type %d: BAD\n", (int) (this_plot->plot_type));
                    672:            if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 14)
                    673:                printf("Plot style %d: %s\n", (int) (this_plot->plot_style),
                    674:                       plot_style_names[(int) (this_plot->plot_style)]);
                    675:            else
                    676:                printf("Plot style %d: BAD\n", (int) (this_plot->plot_style));
                    677:            if ((int) this_plot->plot_smooth >= 0 && (int) (this_plot->plot_smooth) < 6)
                    678:                printf("Plot smooth style %d: %s\n", (int) (this_plot->plot_style),
                    679:                       plot_smooth_names[(int) (this_plot->plot_smooth)]);
                    680:            else
                    681:                printf("Plot smooth style %d: BAD\n", (int) (this_plot->plot_smooth));
                    682:            printf("Plot title: '%s'\n", this_plot->title);
                    683:            printf("Line type %d\n", this_plot->line_type);
                    684:            printf("Point type %d\n", this_plot->point_type);
                    685:            printf("max points %d\n", this_plot->p_max);
                    686:            printf("current points %d\n", this_plot->p_count);
                    687:            printf("\n");
                    688:        }
                    689:     } else {
                    690:        for (this_plot = first_plot, i = 0;
                    691:             i < curve && this_plot != NULL;
                    692:             i++, this_plot = this_plot->next_cp);
                    693:        if (this_plot == NULL)
                    694:            printf("Curve %d does not exist; list has %d curves\n", curve, i);
                    695:        else {
                    696:            printf("Curve %d, %d points\n", curve, this_plot->p_count);
                    697:            for (i = 0; i < this_plot->p_count; i++) {
                    698:                printf("%c x=%g y=%g z=%g xlow=%g xhigh=%g ylow=%g yhigh=%g\n",
                    699:                       this_plot->points[i].type == INRANGE ? 'i'
                    700:                       : this_plot->points[i].type == OUTRANGE ? 'o'
                    701:                       : 'u',
                    702:                       this_plot->points[i].x,
                    703:                       this_plot->points[i].y,
                    704:                       this_plot->points[i].z,
                    705:                       this_plot->points[i].xlow,
                    706:                       this_plot->points[i].xhigh,
                    707:                       this_plot->points[i].ylow,
                    708:                       this_plot->points[i].yhigh);
                    709:            }
                    710:            printf("\n");
                    711:        }
                    712:     }
                    713: }
                    714: #endif /* not used */
                    715:
                    716: static void print_table(this_plot, plot_num)
                    717: struct curve_points *this_plot;
                    718: int plot_num;
                    719: {
                    720:     int i, curve;
                    721:
                    722:     for (curve = 0; curve < plot_num;
                    723:         curve++, this_plot = this_plot->next_cp) {
                    724:        fprintf(gpoutfile, "#Curve %d, %d points\n#x y type\n", curve, this_plot->p_count);
                    725:        for (i = 0; i < this_plot->p_count; i++) {
                    726:            fprintf(gpoutfile, "%g %g %c\n",
                    727:                    this_plot->points[i].x,
                    728:                    this_plot->points[i].y,
                    729:                    this_plot->points[i].type == INRANGE ? 'i'
                    730:                    : this_plot->points[i].type == OUTRANGE ? 'o'
                    731:                    : 'u');
                    732:        }
                    733:        fputc('\n', gpoutfile);
                    734:     }
                    735: /* two blank lines between plots in table output */
                    736:     fputc('\n', gpoutfile);
                    737:     fflush(gpoutfile);
                    738: }
                    739:
                    740: /*
                    741:  * This parses the plot command after any range specifications. To support
                    742:  * autoscaling on the x axis, we want any data files to define the x range,
                    743:  * then to plot any functions using that range. We thus parse the input
                    744:  * twice, once to pick up the data files, and again to pick up the functions.
                    745:  * Definitions are processed twice, but that won't hurt.
                    746:  * div - okay, it doesn't hurt, but every time an option as added for
                    747:  * datafiles, code to parse it has to be added here. Change so that
                    748:  * we store starting-token in the plot structure.
                    749:  */
                    750: static void eval_plots()
                    751: {
                    752:     register int i;
                    753:     register struct curve_points *this_plot, **tp_ptr;
                    754:
                    755:     int some_functions = 0;
                    756:     int plot_num, line_num, point_num, xparam = 0;
                    757:     char *xtitle;
                    758:     int begin_token = c_token; /* so we can rewind for second pass */
                    759:
                    760:     int uses_axis[AXIS_ARRAY_SIZE];
                    761:
                    762:     uses_axis[FIRST_X_AXIS] =
                    763:        uses_axis[FIRST_Y_AXIS] =
                    764:        uses_axis[SECOND_X_AXIS] =
                    765:        uses_axis[SECOND_Y_AXIS] = 0;
                    766:
                    767:     /* Reset first_plot. This is usually done at the end of this function.
                    768:        If there is an error within this function, the memory is left allocated,
                    769:        since we cannot call cp_free if the list is incomplete. Making sure that
                    770:        the list structure is always vaild requires some rewriting */
                    771:     first_plot = NULL;
                    772:
                    773:     tp_ptr = &(first_plot);
                    774:     plot_num = 0;
                    775:     line_num = 0;              /* default line type */
                    776:     point_num = 0;             /* default point type */
                    777:
                    778:     xtitle = NULL;
                    779:
                    780:     /*** First Pass: Read through data files ***
                    781:      * This pass serves to set the xrange and to parse the command, as well
                    782:      * as filling in every thing except the function data. That is done after
                    783:      * the xrange is defined.
                    784:      */
                    785:     while (TRUE) {
                    786:        if (END_OF_COMMAND)
                    787:            int_error("function to plot expected", c_token);
                    788:
                    789:        if (is_definition(c_token)) {
                    790:            define();
                    791:        } else {
                    792:            int x_axis = 0, y_axis = 0;
                    793:            int specs;
                    794:
                    795:            /* for datafile plot, record datafile spec for title */
                    796:            int start_token = c_token, end_token;
                    797:
                    798:            plot_num++;
                    799:
                    800:            if (isstring(c_token)) {    /* data file to plot */
                    801:
                    802:                if (parametric && xparam)
                    803:                    int_error("previous parametric function not fully specified", c_token);
                    804:
                    805:                if (*tp_ptr)
                    806:                    this_plot = *tp_ptr;
                    807:                else {          /* no memory malloc()'d there yet */
                    808:                    this_plot = cp_alloc(MIN_CRV_POINTS);
                    809:                    *tp_ptr = this_plot;
                    810:                }
                    811:                this_plot->plot_type = DATA;
                    812:                this_plot->plot_style = data_style;
                    813:                this_plot->plot_smooth = NONE;
                    814:
                    815:                specs = df_open(NCOL);  /* up to NCOL cols */
                    816:                /* this parses data-file-specific modifiers only */
                    817:                /* we'll sort points when we know style, if necessary */
                    818:                if (df_binary)
                    819:                    int_error("2d binary files not yet supported", c_token);
                    820:
                    821:                this_plot->token = end_token = c_token - 1;     /* include modifiers in default title */
                    822:
                    823:            } else {
                    824:
                    825:                /* function to plot */
                    826:
                    827:                some_functions = 1;
                    828:                if (parametric) /* working on x parametric function */
                    829:                    xparam = 1 - xparam;
                    830:                if (*tp_ptr) {
                    831:                    this_plot = *tp_ptr;
                    832:                    cp_extend(this_plot, samples + 1);
                    833:                } else {        /* no memory malloc()'d there yet */
                    834:                    this_plot = cp_alloc(samples + 1);
                    835:                    *tp_ptr = this_plot;
                    836:                }
                    837:                this_plot->plot_type = FUNC;
                    838:                this_plot->plot_style = func_style;
                    839:                dummy_func = &plot_func;
                    840:                plot_func.at = temp_at();
                    841:                dummy_func = NULL;
                    842:                /* ignore it for now */
                    843:                end_token = c_token - 1;
                    844:            }                   /* end of IS THIS A FILE OR A FUNC block */
                    845:
                    846:
                    847:            /*  deal with smooth */
                    848:            if (almost_equals(c_token, "s$mooth")) {
                    849:
                    850:                if (END_OF_COMMAND)
                    851:                    int_error("expecting smooth parameter", c_token);
                    852:                else {
                    853:                    c_token++;
                    854:                    if (almost_equals(c_token, "u$nique"))
                    855:                        this_plot->plot_smooth = UNIQUE;
                    856:                    else if (almost_equals(c_token, "a$csplines"))
                    857:                        this_plot->plot_smooth = ACSPLINES;
                    858:                    else if (almost_equals(c_token, "c$splines"))
                    859:                        this_plot->plot_smooth = CSPLINES;
                    860:                    else if (almost_equals(c_token, "b$ezier"))
                    861:                        this_plot->plot_smooth = BEZIER;
                    862:                    else if (almost_equals(c_token, "s$bezier"))
                    863:                        this_plot->plot_smooth = SBEZIER;
                    864:                    else
                    865:                        int_error("expecting 'unique', 'acsplines', 'csplines', 'bezier' or 'sbezier'", c_token);
                    866:                }
                    867:                this_plot->plot_style = LINES;
                    868:                c_token++;      /* skip format */
                    869:            }
                    870:            /* look for axes/axis */
                    871:
                    872:            if (almost_equals(c_token, "ax$es") || almost_equals(c_token, "ax$is")) {
                    873:                if (parametric && xparam)
                    874:                    int_error("previous parametric function not fully specified", c_token);
                    875:
                    876:                if (equals(++c_token, "x1y1")) {
                    877:                    x_axis = FIRST_X_AXIS;
                    878:                    y_axis = FIRST_Y_AXIS;
                    879:                    ++c_token;
                    880:                } else if (equals(c_token, "x2y2")) {
                    881:                    x_axis = SECOND_X_AXIS;
                    882:                    y_axis = SECOND_Y_AXIS;
                    883:                    ++c_token;
                    884:                } else if (equals(c_token, "x1y2")) {
                    885:                    x_axis = FIRST_X_AXIS;
                    886:                    y_axis = SECOND_Y_AXIS;
                    887:                    ++c_token;
                    888:                } else if (equals(c_token, "x2y1")) {
                    889:                    x_axis = SECOND_X_AXIS;
                    890:                    y_axis = FIRST_Y_AXIS;
                    891:                    ++c_token;
                    892:                } else
                    893:                    int_error("axes must be x1y1, x1y2, x2y1 or x2y2", c_token);
                    894:            } else {
                    895:                x_axis = FIRST_X_AXIS;
                    896:                y_axis = FIRST_Y_AXIS;
                    897:            }
                    898:
                    899:
                    900:            this_plot->x_axis = x_axis;
                    901:            this_plot->y_axis = y_axis;
                    902:
                    903:            /* we can now do some checks that we deferred earlier */
                    904:
                    905:            if (this_plot->plot_type == DATA) {
                    906:                if (!(uses_axis[x_axis] & 1) && autoscale_lx) {
                    907:                    if (auto_array[x_axis] & 1)
                    908:                        min_array[x_axis] = VERYLARGE;
                    909:                    if (auto_array[x_axis] & 2)
                    910:                        max_array[x_axis] = -VERYLARGE;
                    911:                }
                    912:                if (datatype[x_axis] == TIME) {
                    913:                    if (specs < 2)
                    914:                        int_error("Need full using spec for x time data", c_token);
                    915:                    df_timecol[0] = 1;
                    916:                }
                    917:                if (datatype[y_axis] == TIME) {
                    918:                    if (specs < 1)
                    919:                        int_error("Need using spec for y time data", c_token);
                    920:                    df_timecol[y_axis] = 1;     /* need other cols, but I'm lazy */
                    921:                }
                    922:                uses_axis[x_axis] |= 1;         /* separate record of datafile and func */
                    923:                uses_axis[y_axis] |= 1;
                    924:            } else if (!parametric || !xparam) {
                    925:                /* for x part of a parametric function, axes are possibly wrong */
                    926:                uses_axis[x_axis] |= 2;         /* separate record of data and func */
                    927:                uses_axis[y_axis] |= 2;
                    928:            }
                    929:            if (almost_equals(c_token, "t$itle")) {
                    930:                if (parametric) {
                    931:                    if (xparam)
                    932:                        int_error("\"title\" allowed only after parametric function fully specified", c_token);
                    933:                    else if (xtitle != NULL)
                    934:                        xtitle[0] = '\0';       /* Remove default title . */
                    935:                }
                    936:                c_token++;
                    937:                if (isstring(c_token)) {
                    938:                    m_quote_capture(&(this_plot->title), c_token, c_token);
                    939:                } else {
                    940:                    int_error("expecting \"title\" for plot", c_token);
                    941:                }
                    942:                c_token++;
                    943:            } else if (almost_equals(c_token, "not$itle")) {
                    944:                if (xtitle != NULL)
                    945:                    xtitle[0] = '\0';
                    946:                c_token++;
                    947:            } else {
                    948:                m_capture(&(this_plot->title), start_token, end_token);
                    949:                if (xparam)
                    950:                    xtitle = this_plot->title;
                    951:            }
                    952:
                    953:
                    954:            if (almost_equals(c_token, "w$ith")) {
                    955:                if (parametric && xparam)
                    956:                    int_error("\"with\" allowed only after parametric function fully specified", c_token);
                    957:                this_plot->plot_style = get_style();
                    958:            }
                    959:            /* pick up line/point specs
                    960:             * - point spec allowed if style uses points, ie style&2 != 0
                    961:             * - keywords for lt and pt are optional
                    962:             */
                    963:            LP_PARSE(this_plot->lp_properties, 1, this_plot->plot_style & 2,
                    964:                     line_num, point_num);
                    965:
                    966:            /* allow old-style syntax too - ignore case lt 3 4 for example */
                    967:            if (!equals(c_token, ",") && !END_OF_COMMAND) {
                    968:                struct value t;
                    969:                this_plot->lp_properties.l_type =
                    970:                    this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
                    971:
                    972:                if (!equals(c_token, ",") && !END_OF_COMMAND)
                    973:                    this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
                    974:            }
                    975:            if (!xparam) {
                    976:                if (this_plot->plot_style & 2)  /* style includes points */
                    977:                    ++point_num;
                    978:                ++line_num;
                    979:            }
                    980:            if (this_plot->plot_type == DATA) {
                    981:                /* actually get the data now */
                    982:                get_data(this_plot);
                    983:
                    984:                /* sort */
                    985:                switch (this_plot->plot_smooth) {       /* sort and average, if */
                    986:                case UNIQUE:    /* the style requires   */
                    987:                case CSPLINES:
                    988:                case ACSPLINES:
                    989:                case SBEZIER:
                    990:                    sort_points(this_plot);
                    991:                    cp_implode(this_plot);
                    992:                    break;
                    993:                default:
                    994:                    ;           /* keep gcc -Wall happy */
                    995:                }
                    996:                switch (this_plot->plot_smooth) {       /* create new data set     */
                    997:                case SBEZIER:   /* by evaluation of        */
                    998:                case BEZIER:    /* interpolation routines  */
                    999:                case ACSPLINES:
                   1000:                case CSPLINES:
                   1001:                    gen_interp(this_plot);
                   1002:                    break;
                   1003:                default:
                   1004:                    ;           /* keep gcc -Wall happy */
                   1005:                }
                   1006:
                   1007:                /* now that we know the plot style, adjust the x- and yrange */
                   1008:                /* adjust_range(this_plot); no longer needed */
                   1009:            }
                   1010:            this_plot->token = c_token;         /* save end of plot for second pass */
                   1011:            tp_ptr = &(this_plot->next_cp);
                   1012:
                   1013:        }                       /* !is_defn */
                   1014:
                   1015:        if (equals(c_token, ","))
                   1016:            c_token++;
                   1017:        else
                   1018:            break;
                   1019:     }
                   1020:
                   1021:     if (parametric && xparam)
                   1022:        int_error("parametric function not fully specified", NO_CARET);
                   1023:
                   1024:
                   1025: /*** Second Pass: Evaluate the functions ***/
                   1026:     /*
                   1027:      * Everything is defined now, except the function data. We expect no
                   1028:      * syntax errors, etc, since the above parsed it all. This makes the code
                   1029:      * below simpler. If autoscale_ly, the yrange may still change.
                   1030:      * we stored last token of each plot, so we dont need to do everything again
                   1031:      */
                   1032:
                   1033:     /* give error if xrange badly set from missing datafile error
                   1034:      * parametric or polar fns can still affect x ranges
                   1035:      */
                   1036:
                   1037:     if (!parametric && !polar) {
                   1038:        if (min_array[FIRST_X_AXIS] == VERYLARGE ||
                   1039:            max_array[FIRST_X_AXIS] == -VERYLARGE)
                   1040:            int_error("x range is invalid", c_token);
                   1041:        /* check that xmin -> xmax is not too small */
                   1042:        fixup_range(FIRST_X_AXIS, "x");
                   1043:
                   1044:        if (uses_axis[SECOND_X_AXIS] & 1) {
                   1045:            /* some data plots with x2 */
                   1046:            if (min_array[SECOND_X_AXIS] == VERYLARGE ||
                   1047:                max_array[SECOND_X_AXIS] == -VERYLARGE)
                   1048:                int_error("x2 range is invalid", c_token);
                   1049:            /* check that x2min -> x2max is not too small */
                   1050:            fixup_range(SECOND_X_AXIS, "x2");
                   1051:        } else if (auto_array[SECOND_X_AXIS]) {
                   1052:            /* copy x1's range */
                   1053:            if (auto_array[SECOND_X_AXIS] & 1)
                   1054:                min_array[SECOND_X_AXIS] = min_array[FIRST_X_AXIS];
                   1055:            if (auto_array[SECOND_X_AXIS] & 2)
                   1056:                max_array[SECOND_X_AXIS] = max_array[FIRST_X_AXIS];
                   1057:        }
                   1058:     }
                   1059:     if (some_functions) {
                   1060:
                   1061:        /* call the controlled variable t, since x_min can also mean smallest x */
                   1062:        double t_min, t_max, t_step;
                   1063:
                   1064:        if (parametric || polar) {
                   1065:            if (!(uses_axis[FIRST_X_AXIS] & 1)) {
                   1066:                /* these have not yet been set to full width */
                   1067:                if (auto_array[FIRST_X_AXIS] & 1)
                   1068:                    min_array[FIRST_X_AXIS] = VERYLARGE;
                   1069:                if (auto_array[FIRST_X_AXIS] & 2)
                   1070:                    max_array[FIRST_X_AXIS] = -VERYLARGE;
                   1071:            }
                   1072:            if (!(uses_axis[SECOND_X_AXIS] & 1)) {
                   1073:                if (auto_array[SECOND_X_AXIS] & 1)
                   1074:                    min_array[SECOND_X_AXIS] = VERYLARGE;
                   1075:                if (auto_array[SECOND_X_AXIS] & 2)
                   1076:                    max_array[SECOND_X_AXIS] = -VERYLARGE;
                   1077:            }
                   1078:        }
                   1079: #define SET_DUMMY_RANGE(AXIS) \
                   1080: do{ assert(!polar && !parametric); \
                   1081:  if (log_array[AXIS]) {\
                   1082:   if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0)\
                   1083:    int_error("x/x2 range must be greater than 0 for log scale!", NO_CARET);\
                   1084:   t_min = log(min_array[AXIS])/log_base_array[AXIS]; t_max = log(max_array[AXIS])/log_base_array[AXIS];\
                   1085:  } else {\
                   1086:   t_min = min_array[AXIS]; t_max = max_array[AXIS];\
                   1087:  }\
                   1088:  t_step = (t_max - t_min) / (samples - 1); \
                   1089: }while(0)
                   1090:
                   1091:        if (parametric || polar) {
                   1092:            t_min = min_array[T_AXIS];
                   1093:            t_max = max_array[T_AXIS];
                   1094:            t_step = (t_max - t_min) / (samples - 1);
                   1095:        }
                   1096:        /* else we'll do it on each plot */
                   1097:
                   1098:        tp_ptr = &(first_plot);
                   1099:        plot_num = 0;
                   1100:        this_plot = first_plot;
                   1101:        c_token = begin_token;  /* start over */
                   1102:
                   1103:        /* Read through functions */
                   1104:        while (TRUE) {
                   1105:            if (is_definition(c_token)) {
                   1106:                define();
                   1107:            } else {
                   1108:                int x_axis = this_plot->x_axis;
                   1109:                int y_axis = this_plot->y_axis;
                   1110:
                   1111:                plot_num++;
                   1112:                if (!isstring(c_token)) {       /* function to plot */
                   1113:                    if (parametric) {   /* toggle parametric axes */
                   1114:                        xparam = 1 - xparam;
                   1115:                    }
                   1116:                    dummy_func = &plot_func;
                   1117:                    plot_func.at = temp_at();   /* reparse function */
                   1118:
                   1119:                    if (!parametric && !polar) {
                   1120:                        SET_DUMMY_RANGE(x_axis);
                   1121:                    }
                   1122:                    for (i = 0; i < samples; i++) {
                   1123:                        double temp;
                   1124:                        struct value a;
                   1125:                        double t = t_min + i * t_step;
                   1126:                        /* parametric/polar => NOT a log quantity */
                   1127:                        double x = (!parametric && !polar &&
                   1128:                                    log_array[x_axis]) ? pow(base_array[x_axis], t) : t;
                   1129:
                   1130:                        (void) Gcomplex(&plot_func.dummy_values[0], x, 0.0);
                   1131:                        evaluate_at(plot_func.at, &a);
                   1132:
                   1133:                        if (undefined || (fabs(imag(&a)) > zero)) {
                   1134:                            this_plot->points[i].type = UNDEFINED;
                   1135:                            continue;
                   1136:                        }
                   1137:                        temp = real(&a);
                   1138:
                   1139:                        this_plot->points[i].z = -1.0;  /* width of box not specified */
                   1140:                        this_plot->points[i].type = INRANGE;    /* for the moment */
                   1141:
                   1142:                        if (parametric) {
                   1143:                            /* we cannot do range-checking now, since for
                   1144:                             * the x function we did not know which axes
                   1145:                             * we were using
                   1146:                             * DO NOT TAKE LOGS YET - do it in parametric_fixup
                   1147:                             */
                   1148:                            this_plot->points[i].x = t;         /* ignored, actually... */
                   1149:                            this_plot->points[i].y = temp;
                   1150:                        } else if (polar) {
                   1151:                            double y;
                   1152:                            if (!(autoscale_r & 2) && temp > rmax)
                   1153:                                this_plot->points[i].type = OUTRANGE;
                   1154:                            if (!(autoscale_r & 1))
                   1155:                                temp -= rmin;
                   1156:                            y = temp * sin(x * ang2rad);
                   1157:                            x = temp * cos(x * ang2rad);
                   1158:                            temp = y;
                   1159:                            STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].x, x, this_plot->points[i].type,
                   1160:                              x_axis, NOOP, goto come_here_if_undefined);
                   1161:                            STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, y, this_plot->points[i].type,
                   1162:                              y_axis, NOOP, goto come_here_if_undefined);
                   1163:                        } else {        /* neither parametric or polar */
                   1164:                            /* If non-para, it must be INRANGE */
                   1165:                            this_plot->points[i].x = t;         /* logscale ? log(x) : x */
                   1166:
                   1167:                            STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, temp, this_plot->points[i].type,
                   1168:                                                           y_axis + (x_axis - y_axis) * xparam, NOOP, goto come_here_if_undefined);
                   1169:
                   1170:                          come_here_if_undefined:       /* could not use a continue in this case */
                   1171:                            ;   /* ansi requires a statement after a label */
                   1172:                        }
                   1173:
                   1174:                    }           /* loop over samples */
                   1175:                    this_plot->p_count = i;     /* samples */
                   1176:                }
                   1177:                c_token = this_plot->token;     /* skip all modifers func / whole of data plots */
                   1178:
                   1179:                tp_ptr = &(this_plot->next_cp);         /* used below */
                   1180:                this_plot = this_plot->next_cp;
                   1181:            }
                   1182:
                   1183:            if (equals(c_token, ","))
                   1184:                c_token++;
                   1185:            else
                   1186:                break;
                   1187:        }
                   1188:
                   1189:        if (parametric) {
                   1190:            /* Now actually fix the plot pairs to be single plots */
                   1191:            /* also fixes up polar&&parametric fn plots */
                   1192:            parametric_fixup(first_plot, &plot_num);
                   1193:            /* we omitted earlier check for range too small */
                   1194:            fixup_range(FIRST_X_AXIS, "x");
                   1195:            if (uses_axis[SECOND_X_AXIS]) {
                   1196:                fixup_range(SECOND_X_AXIS, "x2");
                   1197:            }
                   1198:        }
                   1199:     }                          /* some_functions */
                   1200:     /* throw out all curve_points at end of list, that we don't need  */
                   1201:     cp_free(*tp_ptr);
                   1202:     *tp_ptr = NULL;
                   1203:
                   1204:
                   1205:     /* if first_plot is NULL, we have no functions or data at all. This can
                   1206:        happen, if you type "plot x=5", since x=5 is a variable assignment */
                   1207:
                   1208:     if (plot_num == 0 || first_plot == NULL) {
                   1209:        int_error("no functions or data to plot", c_token);
                   1210:     }
1.1.1.2 ! maekawa  1211:
        !          1212:
1.1       maekawa  1213:     if (uses_axis[FIRST_X_AXIS]) {
                   1214:        if (max_array[FIRST_X_AXIS] == -VERYLARGE ||
                   1215:            min_array[FIRST_X_AXIS] == VERYLARGE)
                   1216:            int_error("all points undefined!", NO_CARET);
                   1217:        FIXUP_RANGE_FOR_LOG(FIRST_X_AXIS, x);
                   1218:     }
                   1219:     if (uses_axis[SECOND_X_AXIS]) {
                   1220:        if (max_array[SECOND_X_AXIS] == -VERYLARGE ||
                   1221:            min_array[SECOND_X_AXIS] == VERYLARGE)
                   1222:            int_error("all points undefined!", NO_CARET);
                   1223:        FIXUP_RANGE_FOR_LOG(SECOND_X_AXIS, x2);
                   1224:     } else {
                   1225:        assert(uses_axis[FIRST_X_AXIS]);
                   1226:        if (auto_array[SECOND_X_AXIS] & 1)
                   1227:            min_array[SECOND_X_AXIS] = min_array[FIRST_X_AXIS];
                   1228:        if (auto_array[SECOND_X_AXIS] & 2)
                   1229:            max_array[SECOND_X_AXIS] = max_array[FIRST_X_AXIS];
1.1.1.2 ! maekawa  1230:        if (! auto_array[SECOND_X_AXIS])
        !          1231:            FIXUP_RANGE_FOR_LOG(SECOND_X_AXIS, x2);
1.1       maekawa  1232:     }
                   1233:     if (!uses_axis[FIRST_X_AXIS]) {
                   1234:        assert(uses_axis[SECOND_X_AXIS]);
                   1235:        if (auto_array[FIRST_X_AXIS] & 1)
                   1236:            min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS];
                   1237:        if (auto_array[FIRST_X_AXIS] & 2)
                   1238:            max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS];
                   1239:     }
1.1.1.2 ! maekawa  1240:
        !          1241:
1.1       maekawa  1242:     if (uses_axis[FIRST_Y_AXIS]) {
                   1243:        if (max_array[FIRST_Y_AXIS] == -VERYLARGE ||
                   1244:            min_array[FIRST_Y_AXIS] == VERYLARGE)
                   1245:            int_error("all points undefined!", NO_CARET);
                   1246:        fixup_range(FIRST_Y_AXIS, "y");
                   1247:        FIXUP_RANGE_FOR_LOG(FIRST_Y_AXIS, y);
1.1.1.2 ! maekawa  1248:     }
1.1       maekawa  1249:     if (uses_axis[SECOND_Y_AXIS]) {
                   1250:        if (max_array[SECOND_Y_AXIS] == -VERYLARGE ||
                   1251:            min_array[SECOND_Y_AXIS] == VERYLARGE)
                   1252:            int_error("all points undefined!", NO_CARET);
                   1253:        fixup_range(SECOND_Y_AXIS, "y2");
                   1254:        FIXUP_RANGE_FOR_LOG(SECOND_Y_AXIS, y2);
                   1255:     } else {
1.1.1.2 ! maekawa  1256:        /* else we want to copy y2 range */
1.1       maekawa  1257:        assert(uses_axis[FIRST_Y_AXIS]);
                   1258:        if (auto_array[SECOND_Y_AXIS] & 1)
                   1259:            min_array[SECOND_Y_AXIS] = min_array[FIRST_Y_AXIS];
                   1260:        if (auto_array[SECOND_Y_AXIS] & 2)
                   1261:            max_array[SECOND_Y_AXIS] = max_array[FIRST_Y_AXIS];
1.1.1.2 ! maekawa  1262:        /* Log() fixup is only necessary if the range was *not* copied from
        !          1263:         * the (already logarithmized) yrange */
        !          1264:        if (! auto_array[SECOND_Y_AXIS])
        !          1265:            FIXUP_RANGE_FOR_LOG(SECOND_Y_AXIS, y2);
1.1       maekawa  1266:     }
                   1267:     if (!uses_axis[FIRST_Y_AXIS]) {
                   1268:        assert(uses_axis[SECOND_Y_AXIS]);
                   1269:        if (auto_array[FIRST_Y_AXIS] & 1)
                   1270:            min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS];
                   1271:        if (auto_array[FIRST_Y_AXIS] & 2)
                   1272:            max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS];
                   1273:     }
1.1.1.2 ! maekawa  1274:
1.1       maekawa  1275: #define WRITEBACK(axis,min,max) \
                   1276: if(range_flags[axis]&RANGE_WRITEBACK) \
                   1277:   {if (auto_array[axis]&1) min = min_array[axis]; \
                   1278:    if (auto_array[axis]&2) max = max_array[axis]; \
                   1279:   }
                   1280:
                   1281:     WRITEBACK(FIRST_X_AXIS, xmin, xmax)
                   1282:        WRITEBACK(FIRST_Y_AXIS, ymin, ymax)
                   1283:        WRITEBACK(SECOND_X_AXIS, x2min, x2max)
                   1284:        WRITEBACK(SECOND_Y_AXIS, y2min, y2max)
1.1.1.2 ! maekawa  1285:
        !          1286:     if (strcmp(term->name, "table") == 0)
1.1       maekawa  1287:        print_table(first_plot, plot_num);
                   1288:     else {
                   1289:        START_LEAK_CHECK();     /* check for memory leaks in this routine */
                   1290:
                   1291:        /* do_plot now uses max_array[], etc */
                   1292:        do_plot(first_plot, plot_num);
                   1293:
                   1294:        END_LEAK_CHECK();
                   1295:     }
                   1296:
                   1297:     /* if we get here, all went well, so record this line for replot */
                   1298:
                   1299:     if (plot_token != -1) {
                   1300:        /* note that m_capture also frees the old replot_line */
                   1301:        m_capture(&replot_line, plot_token, c_token - 1);
                   1302:        plot_token = -1;
                   1303:     }
                   1304:     cp_free(first_plot);
                   1305:     first_plot = NULL;
                   1306: }                              /* eval_plots */
                   1307:
                   1308:
                   1309:
                   1310:
                   1311: static void parametric_fixup(start_plot, plot_num)
                   1312: struct curve_points *start_plot;
                   1313: int *plot_num;
                   1314: /*
                   1315:  * The hardest part of this routine is collapsing the FUNC plot types in the
                   1316:  * list (which are garanteed to occur in (x,y) pairs while preserving the
                   1317:  * non-FUNC type plots intact.  This means we have to work our way through
                   1318:  * various lists.  Examples (hand checked): start_plot:F1->F2->NULL ==>
                   1319:  * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
                   1320:  * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
                   1321:  *
                   1322:  */
                   1323: {
                   1324:     struct curve_points *xp, *new_list = NULL, *free_list = NULL;
                   1325:     struct curve_points **last_pointer = &new_list;
                   1326:     int i, tlen, curve;
                   1327:     char *new_title;
                   1328:
                   1329:     /*
                   1330:      * Ok, go through all the plots and move FUNC types together.  Note: this
                   1331:      * originally was written to look for a NULL next pointer, but gnuplot
                   1332:      * wants to be sticky in grabbing memory and the right number of items in
                   1333:      * the plot list is controlled by the plot_num variable.
                   1334:      *
                   1335:      * Since gnuplot wants to do this sticky business, a free_list of
                   1336:      * curve_points is kept and then tagged onto the end of the plot list as
                   1337:      * this seems more in the spirit of the original memory behavior than
                   1338:      * simply freeing the memory.  I'm personally not convinced this sort of
                   1339:      * concern is worth it since the time spent computing points seems to
                   1340:      * dominate any garbage collecting that might be saved here...
                   1341:      */
                   1342:     new_list = xp = start_plot;
                   1343:     curve = 0;
                   1344:
                   1345:     while (++curve <= *plot_num) {
                   1346:        if (xp->plot_type == FUNC) {
                   1347:            /* Here's a FUNC parametric function defined as two parts. */
                   1348:            struct curve_points *yp = xp->next_cp;
                   1349:
                   1350:            --(*plot_num);
                   1351:
                   1352:            assert(xp->p_count == yp->p_count);
                   1353:
                   1354:            /* because syntax is   plot x(t), y(t) axes ..., only
                   1355:             * the y function axes are correct
                   1356:             */
                   1357:
                   1358:
                   1359:            /*
                   1360:             * Go through all the points assigning the y's from xp to be the x's
                   1361:             * for yp. In polar mode, we need to check max's and min's as we go.
                   1362:             */
                   1363:
                   1364:            for (i = 0; i < yp->p_count; ++i) {
                   1365:                if (polar) {
                   1366:                    double r = yp->points[i].y;
                   1367:                    double t = xp->points[i].y * ang2rad;
                   1368:                    double x, y;
                   1369:                    if (!(autoscale_r & 2) && r > rmax)
                   1370:                        yp->points[i].type = OUTRANGE;
                   1371:                    if (!(autoscale_r & 1))
                   1372:                        r -= rmin;      /* store internally as if plotting r(t)-rmin */
                   1373:                    x = r * cos(t);
                   1374:                    y = r * sin(t);
                   1375:                    /* we hadn't done logs when we stored earlier */
                   1376:                    STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x, yp->points[i].type,
                   1377:                                                 xp->x_axis, NOOP, NOOP);
                   1378:                    STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y, yp->points[i].type,
                   1379:                                                 xp->y_axis, NOOP, NOOP);
                   1380:                } else {
                   1381:                    double x = xp->points[i].y;
                   1382:                    double y = yp->points[i].y;
                   1383:                    STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x,
                   1384:                             yp->points[i].type, yp->x_axis, NOOP, NOOP);
                   1385:                    STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y,
                   1386:                             yp->points[i].type, yp->y_axis, NOOP, NOOP);
                   1387:                }
                   1388:            }
                   1389:
                   1390:            /* Ok, fix up the title to include both the xp and yp plots. */
                   1391:            if (xp->title && xp->title[0] != '\0' && yp->title) {
                   1392:                tlen = strlen(yp->title) + strlen(xp->title) + 3;
                   1393:                new_title = gp_alloc((unsigned long) tlen, "string");
                   1394:                strcpy(new_title, xp->title);
                   1395:                strcat(new_title, ", ");        /* + 2 */
                   1396:                strcat(new_title, yp->title);   /* + 1 = + 3 */
                   1397:                free(yp->title);
                   1398:                yp->title = new_title;
                   1399:            }
                   1400:            /* move xp to head of free list */
                   1401:            xp->next_cp = free_list;
                   1402:            free_list = xp;
                   1403:
                   1404:            /* append yp to new_list */
                   1405:            *last_pointer = yp;
                   1406:            last_pointer = &(yp->next_cp);
                   1407:            xp = yp->next_cp;
                   1408:
                   1409:        } else {                /* data plot */
                   1410:            assert(*last_pointer == xp);
                   1411:            last_pointer = &(xp->next_cp);
                   1412:            xp = xp->next_cp;
                   1413:        }
                   1414:     }                          /* loop over plots */
                   1415:
                   1416:     first_plot = new_list;
                   1417:
                   1418:     /* Ok, stick the free list at the end of the curve_points plot list. */
                   1419:     *last_pointer = free_list;
                   1420: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>