[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.3

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

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