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

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