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

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

1.1       maekawa     1: #ifndef lint
1.1.1.2 ! maekawa     2: static char *RCSid = "$Id: plot3d.c,v 1.16 1998/12/10 18:30:52 lhecking Exp $";
1.1       maekawa     3: #endif
                      4:
                      5: /* GNUPLOT - plot3d.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 "binary.h"
                     40:
                     41: #ifndef _Windows
                     42: # include "help.h"
                     43: #endif
                     44:
                     45: #ifndef STDOUT
                     46: #define STDOUT 1
                     47: #endif
                     48:
                     49: /* static prototypes */
                     50:
                     51: static void get_3ddata __PROTO((struct surface_points * this_plot));
                     52: static void print_3dtable __PROTO((int pcount));
                     53: static void eval_3dplots __PROTO((void));
                     54: static void grid_nongrid_data __PROTO((struct surface_points * this_plot));
                     55: static void parametric_3dfixup __PROTO((struct surface_points * start_plot, int *plot_num));
                     56:
                     57: /* the curves/surfaces of the plot */
                     58: struct surface_points *first_3dplot = NULL;
                     59: static struct udft_entry plot_func;
                     60:
                     61:
                     62: extern struct udft_entry *dummy_func;
                     63: extern int datatype[];
                     64: extern char timefmt[];
                     65: extern TBOOLEAN is_3d_plot;
                     66: extern int plot_token;
                     67:
                     68: /* in order to support multiple axes, and to
                     69:  * simplify ranging in parametric plots, we use
                     70:  * arrays to store some things. For 2d plots,
                     71:  * elements are  y1 = 0 x1 = 1 y2 = 2 x2 = 3
                     72:  * for 3d,  z = 0, x = 1, y = 2
                     73:  * these are given symbolic names in plot.h
                     74:  */
                     75:
                     76: extern double min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE];
                     77: extern int auto_array[AXIS_ARRAY_SIZE];
                     78: extern TBOOLEAN log_array[AXIS_ARRAY_SIZE];
                     79: extern double base_array[AXIS_ARRAY_SIZE];
                     80: extern double log_base_array[AXIS_ARRAY_SIZE];
                     81:
                     82: /* some file-wide variables to store which axis we are using */
                     83: static int x_axis, y_axis, z_axis;
                     84:
                     85:
                     86: /* Deleted from setshow.h and renamed */
                     87: extern FILE *gpoutfile;
                     88:
                     89: /* info from datafile module */
                     90: extern int df_datum;
                     91: extern int df_line_number;
                     92: extern int df_no_use_specs;
                     93: extern int df_eof;
                     94: extern int df_timecol[];
                     95: extern TBOOLEAN df_matrix;
                     96:
                     97: #define Inc_c_token if (++c_token >= num_tokens)       \
                     98:                         int_error ("Syntax error", c_token);
                     99:
                    100: /* From plot2d.c */
                    101: extern int reverse_range[];
                    102:
                    103: /*
                    104:  * IMHO, code is getting too cluttered with repeated chunks of
                    105:  * code. Some macros to simplify, I hope.
                    106:  *
                    107:  * do { } while(0) is comp.lang.c recommendation for complex macros
                    108:  * also means that break can be specified as an action, and it will
                    109:  *
                    110:  */
                    111:
                    112: /*  copy scalar data to arrays
                    113:  * optimiser should optimise infinite away
                    114:  * dont know we have to support ranges [10:-10] - lets reverse
                    115:  * it for now, then fix it at the end.
                    116:  */
                    117: #define INIT_ARRAYS(axis, min, max, auto, is_log, base, log_base, infinite) \
                    118: do{if ((auto_array[axis] = auto) == 0 && max<min) {\
                    119:        min_array[axis] = max;\
                    120:    max_array[axis] = min; /* we will fix later */ \
                    121:  } else { \
                    122:        min_array[axis] = (infinite && (auto&1)) ? VERYLARGE : min; \
                    123:        max_array[axis] = (infinite && (auto&2)) ? -VERYLARGE : max; \
                    124:  } \
                    125:  log_array[axis] = is_log; base_array[axis] = base; log_base_array[axis] = log_base;\
                    126: }while(0)
                    127:
                    128: /* handle reversed ranges */
                    129: #define CHECK_REVERSE(axis) \
                    130: do{\
                    131:  if (auto_array[axis] == 0 && max_array[axis] < min_array[axis]) {\
                    132:   double temp = min_array[axis]; min_array[axis] = max_array[axis]; max_array[axis] = temp;\
                    133:   reverse_range[axis] = 1; \
                    134:  } else reverse_range[axis] = (range_flags[axis]&RANGE_REVERSE); \
                    135: }while(0)
                    136:
                    137:
                    138: /* get optional [min:max] */
                    139: #define LOAD_RANGE(axis) \
                    140: do {\
                    141:  if (equals(c_token, "[")) { \
                    142:   c_token++; \
                    143:   auto_array[axis] = load_range(axis,&min_array[axis], &max_array[axis], auto_array[axis]);\
                    144:   if (!equals(c_token, "]"))\
                    145:    int_error("']' expected", c_token);\
                    146:   c_token++;\
                    147:  }\
                    148: } while (0)
                    149:
                    150:
                    151: /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
                    152:  * Do OUT_ACTION or UNDEF_ACTION as appropriate
                    153:  * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
                    154:  * VALUE must not be same as STORE
                    155:  */
                    156:
                    157: #define STORE_WITH_LOG_AND_FIXUP_RANGE(STORE, VALUE, TYPE, AXIS, OUT_ACTION, UNDEF_ACTION)\
                    158: do { if (log_array[AXIS]) { if (VALUE<0.0) {TYPE = UNDEFINED; UNDEF_ACTION; break;} \
                    159:               else if (VALUE == 0.0){STORE = -VERYLARGE; TYPE = OUTRANGE; OUT_ACTION; break;} \
                    160:               else { STORE = log(VALUE)/log_base_array[AXIS]; } \
                    161:      } else STORE = VALUE; \
                    162:      if (TYPE != INRANGE) break;  /* dont set y range if x is outrange, for example */ \
                    163:      if ( VALUE<min_array[AXIS] ) { \
                    164:       if (auto_array[AXIS] & 1) min_array[AXIS] = VALUE; else { TYPE = OUTRANGE; OUT_ACTION; break; }  \
                    165:      } \
                    166:      if ( VALUE>max_array[AXIS] ) { \
                    167:       if (auto_array[AXIS] & 2) max_array[AXIS] = VALUE; else { TYPE = OUTRANGE; OUT_ACTION; }   \
                    168:      } \
                    169: } while(0)
                    170:
                    171: /* use this instead empty macro arguments to work around NeXT cpp bug */
                    172: /* if this fails on any system, we might use ((void)0) */
                    173: #define NOOP                   /* */
                    174:
                    175: /* check range and take logs of min and max if logscale
                    176:  * this also restores min and max for ranges like [10:-10]
                    177:  */
                    178:
                    179: #ifdef HAVE_STRINGIZE
                    180: # define RANGE_MSG(x) #x " range is less than threshold : see `set zero`"
                    181: #else
                    182: # define RANGE_MSG(x) "x range is less than threshold : see `set zero`"
                    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(RANGE_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: /* support for dynamic size of input line */
                    202:
                    203: void plot3drequest()
                    204: /*
                    205:  * in the parametric case we would say splot [u= -Pi:Pi] [v= 0:2*Pi] [-1:1]
                    206:  * [-1:1] [-1:1] sin(v)*cos(u),sin(v)*cos(u),sin(u) in the non-parametric
                    207:  * case we would say only splot [x= -2:2] [y= -5:5] sin(x)*cos(y)
                    208:  *
                    209:  */
                    210: {
                    211:     TBOOLEAN changed;
                    212:     int dummy_token0 = -1, dummy_token1 = -1;
                    213:
                    214:     is_3d_plot = TRUE;
                    215:
                    216:     if (parametric && strcmp(dummy_var[0], "t") == 0) {
                    217:        strcpy(dummy_var[0], "u");
                    218:        strcpy(dummy_var[1], "v");
                    219:     }
                    220:     autoscale_lx = autoscale_x;
                    221:     autoscale_ly = autoscale_y;
                    222:     autoscale_lz = autoscale_z;
                    223:
                    224:     if (!term)                 /* unknown */
                    225:        int_error("use 'set term' to set terminal type first", c_token);
                    226:
                    227:     if (equals(c_token, "[")) {
                    228:        c_token++;
                    229:        if (isletter(c_token)) {
                    230:            if (equals(c_token + 1, "=")) {
                    231:                dummy_token0 = c_token;
                    232:                c_token += 2;
                    233:            } else {
                    234:                /* oops; probably an expression with a variable. */
                    235:                /* Parse it as an xmin expression. */
                    236:                /* used to be: int_error("'=' expected",c_token); */
                    237:            }
                    238:        }
                    239:        changed = parametric ? load_range(U_AXIS, &umin, &umax, autoscale_lu) : load_range(FIRST_X_AXIS, &xmin, &xmax, autoscale_lx);
                    240:        if (!equals(c_token, "]"))
                    241:            int_error("']' expected", c_token);
                    242:        c_token++;
                    243:        /* if (changed) */
                    244:        if (parametric)
                    245:            /* autoscale_lu = FALSE; */
                    246:            autoscale_lu = changed;
                    247:        else
                    248:            /* autoscale_lx = FALSE; */
                    249:            autoscale_lx = changed;
                    250:     }
                    251:     if (equals(c_token, "[")) {
                    252:        c_token++;
                    253:        if (isletter(c_token)) {
                    254:            if (equals(c_token + 1, "=")) {
                    255:                dummy_token1 = c_token;
                    256:                c_token += 2;
                    257:            } else {
                    258:                /* oops; probably an expression with a variable. */
                    259:                /* Parse it as an xmin expression. */
                    260:                /* used to be: int_error("'=' expected",c_token); */
                    261:            }
                    262:        }
                    263:        changed = parametric ? load_range(V_AXIS, &vmin, &vmax, autoscale_lv) : load_range(FIRST_Y_AXIS, &ymin, &ymax, autoscale_ly);
                    264:        if (!equals(c_token, "]"))
                    265:            int_error("']' expected", c_token);
                    266:        c_token++;
                    267:        /* if (changed) */
                    268:        if (parametric)
                    269:            /* autoscale_lv = FALSE; */
                    270:            autoscale_lv = changed;
                    271:        else
                    272:            /* autoscale_ly = FALSE; */
                    273:            autoscale_ly = changed;
                    274:     }
                    275:     if (parametric) {
                    276:        /* set optional x (parametric) or z ranges */
                    277:        if (equals(c_token, "[")) {
                    278:            c_token++;
                    279:            autoscale_lx = load_range(FIRST_X_AXIS, &xmin, &xmax, autoscale_lx);
                    280:            if (!equals(c_token, "]"))
                    281:                int_error("']' expected", c_token);
                    282:            c_token++;
                    283:        }
                    284:        /* set optional y ranges */
                    285:        if (equals(c_token, "[")) {
                    286:            c_token++;
                    287:            autoscale_ly = load_range(FIRST_Y_AXIS, &ymin, &ymax, autoscale_ly);
                    288:            if (!equals(c_token, "]"))
                    289:                int_error("']' expected", c_token);
                    290:            c_token++;
                    291:        }
                    292:     }                          /* parametric */
                    293:     if (equals(c_token, "[")) {        /* set optional z ranges */
                    294:        c_token++;
                    295:        autoscale_lz = load_range(FIRST_Z_AXIS, &zmin, &zmax, autoscale_lz);
                    296:        if (!equals(c_token, "]"))
                    297:            int_error("']' expected", c_token);
                    298:        c_token++;
                    299:     }
                    300:     CHECK_REVERSE(FIRST_X_AXIS);
                    301:     CHECK_REVERSE(FIRST_Y_AXIS);
                    302:     CHECK_REVERSE(FIRST_Z_AXIS);
                    303:
                    304:     /* use the default dummy variable unless changed */
                    305:     if (dummy_token0 >= 0)
                    306:        copy_str(c_dummy_var[0], dummy_token0, MAX_ID_LEN);
                    307:     else
                    308:        (void) strcpy(c_dummy_var[0], dummy_var[0]);
                    309:
                    310:     if (dummy_token1 >= 0)
                    311:        copy_str(c_dummy_var[1], dummy_token1, MAX_ID_LEN);
                    312:     else
                    313:        (void) strcpy(c_dummy_var[1], dummy_var[1]);
                    314:
                    315:     eval_3dplots();
                    316: }
                    317:
                    318:
                    319: static void grid_nongrid_data(this_plot)
                    320: struct surface_points *this_plot;
                    321: {
                    322:     int i, j, k;
                    323:     double x, y, z, w, dx, dy, xmin, xmax, ymin, ymax;
                    324:     struct iso_curve *old_iso_crvs = this_plot->iso_crvs;
                    325:     struct iso_curve *icrv, *oicrv, *oicrvs;
                    326:
                    327:     /* Compute XY bounding box on the original data. */
                    328:     xmin = xmax = old_iso_crvs->points[0].x;
                    329:     ymin = ymax = old_iso_crvs->points[0].y;
                    330:     for (icrv = old_iso_crvs; icrv != NULL; icrv = icrv->next) {
                    331:        struct coordinate GPHUGE *points = icrv->points;
                    332:
                    333:        for (i = 0; i < icrv->p_count; i++, points++) {
                    334:            if (xmin > points->x)
                    335:                xmin = points->x;
                    336:            if (xmax < points->x)
                    337:                xmax = points->x;
                    338:            if (ymin > points->y)
                    339:                ymin = points->y;
                    340:            if (ymax < points->y)
                    341:                ymax = points->y;
                    342:        }
                    343:     }
                    344:
                    345:     dx = (xmax - xmin) / (dgrid3d_col_fineness - 1);
                    346:     dy = (ymax - ymin) / (dgrid3d_row_fineness - 1);
                    347:
                    348:     /* Create the new grid structure, and compute the low pass filtering from
                    349:      * non grid to grid structure.
                    350:      */
                    351:     this_plot->iso_crvs = NULL;
                    352:     this_plot->num_iso_read = dgrid3d_col_fineness;
                    353:     this_plot->has_grid_topology = TRUE;
                    354:     for (i = 0, x = xmin; i < dgrid3d_col_fineness; i++, x += dx) {
                    355:        struct coordinate GPHUGE *points;
                    356:
                    357:        icrv = iso_alloc(dgrid3d_row_fineness + 1);
                    358:        icrv->p_count = dgrid3d_row_fineness;
                    359:        icrv->next = this_plot->iso_crvs;
                    360:        this_plot->iso_crvs = icrv;
                    361:        points = icrv->points;
                    362:
                    363:        for (j = 0, y = ymin; j < dgrid3d_row_fineness; j++, y += dy, points++) {
                    364:            z = w = 0.0;
                    365:
                    366: #ifndef BUGGY_DGRID_RANGING /* HBB 981209 */
                    367:            /* as soon as ->type is changed to UNDEFINED, break out of
                    368:             * two inner loops! */
                    369:            points->type = INRANGE;
                    370: #endif
                    371:            for (oicrv = old_iso_crvs; oicrv != NULL; oicrv = oicrv->next) {
                    372:                struct coordinate GPHUGE *opoints = oicrv->points;
                    373:                for (k = 0; k < oicrv->p_count; k++, opoints++) {
                    374:                    double dist, dist_x = fabs(opoints->x - x), dist_y = fabs(opoints->y - y);
                    375:
                    376:                    switch (dgrid3d_norm_value) {
                    377:                    case 1:
                    378:                        dist = dist_x + dist_y;
                    379:                        break;
                    380:                    case 2:
                    381:                        dist = dist_x * dist_x + dist_y * dist_y;
                    382:                        break;
                    383:                    case 4:
                    384:                        dist = dist_x * dist_x + dist_y * dist_y;
                    385:                        dist *= dist;
                    386:                        break;
                    387:                    case 8:
                    388:                        dist = dist_x * dist_x + dist_y * dist_y;
                    389:                        dist *= dist;
                    390:                        dist *= dist;
                    391:                        break;
                    392:                    case 16:
                    393:                        dist = dist_x * dist_x + dist_y * dist_y;
                    394:                        dist *= dist;
                    395:                        dist *= dist;
                    396:                        dist *= dist;
                    397:                        break;
                    398:                    default:
                    399:                        dist = pow(dist_x, (double) dgrid3d_norm_value) +
                    400:                            pow(dist_y, (double) dgrid3d_norm_value);
                    401:                        break;
                    402:                    }
                    403:
                    404:                    /* The weight of this point is inverse proportional
                    405:                     * to the distance.
                    406:                     */
                    407:                    if (dist == 0.0) {
                    408: #ifndef BUGGY_DGRID_RANGING
                    409:                        /* HBB 981209: revised flagging as undefined */
                    410:                        /* Supporting all those infinities on various
                    411:                         * platforms becomes tiresome, to say the least :-(
                    412:                         * Let's just return the first z where this happens,
                    413:                         * unchanged, and be done with this, period. */
                    414:                        points->type = UNDEFINED;
                    415:                        z = opoints->z;
                    416:                        w = 1.0;
                    417:                        break; /* out of for (k...) loop */
                    418: #else
                    419: #if !defined(AMIGA_SC_6_1) && !defined(__PUREC__)
                    420:                        dist = VERYLARGE;
                    421: #else /* !AMIGA_SC_6_1 && !__PUREC__ */
                    422:                        /* Multiplying VERYLARGE by opoints->z below
                    423:                         * might yield Inf (i.e. a number that can't
                    424:                         * be represented on the machine). This will
                    425:                         * result in points->z being set to NaN. It's
                    426:                         * better to have a pretty large number that is
                    427:                         * also on the safe side... The numbers that are
                    428:                         * read by gnuplot are float values anyway, so
                    429:                         * they can't be bigger than FLT_MAX. So setting
                    430:                         * dist to FLT_MAX^2 will make dist pretty large
                    431:                         * with respect to any value that has been read. */
                    432:                        dist = ((double) FLT_MAX) * ((double) FLT_MAX);
                    433: #endif /* !AMIGA_SC_6_1 && !__PUREC__ */
                    434: #endif /* BUGGY_DGRID_RANGING */
                    435:                    } else
                    436:                        dist = 1.0 / dist;
                    437:
                    438:                    z += opoints->z * dist;
                    439:                    w += dist;
                    440:                }
                    441: #ifndef BUGGY_DGRID_RANGING
                    442:                if (points->type != INRANGE)
                    443:                  break; /* out of the second-inner loop as well ... */
                    444: #endif
                    445:            }
                    446:
                    447: #ifndef BUGGY_DGRID_RANGING
                    448:            /* Now that we've escaped the loops safely, we know that we
                    449:             * do have a good value in z and w, so we can proceed just as
                    450:             * if nothing had happened at all. Nice, isn't it? */
                    451:            points->type = INRANGE;
                    452:
                    453:            STORE_WITH_LOG_AND_FIXUP_RANGE(points->x, x, points->type, x_axis, NOOP, continue);
                    454:            STORE_WITH_LOG_AND_FIXUP_RANGE(points->y, y, points->type, y_axis, NOOP, continue);
                    455:            STORE_WITH_LOG_AND_FIXUP_RANGE(points->z, z / w, points->type, z_axis, NOOP, continue);
                    456: #else
                    457:            /* HBB 981026: original, short version of this code */
                    458:            points->x = x;
                    459:            points->y = y;
                    460:            points->z = z / w;
                    461:            points->type = INRANGE;
                    462: #endif
                    463:        }
                    464:     }
                    465:
                    466:     /* Delete the old non grid data. */
                    467:     for (oicrvs = old_iso_crvs; oicrvs != NULL;) {
                    468:        oicrv = oicrvs;
                    469:        oicrvs = oicrvs->next;
                    470:        iso_free(oicrv);
                    471:     }
                    472: }
                    473:
                    474: static void get_3ddata(this_plot)
                    475: struct surface_points *this_plot;
                    476: /* this_plot->token is end of datafile spec, before title etc
                    477:  * will be moved passed title etc after we return
                    478:  */
                    479: {
                    480:     int xdatum = 0;
                    481:     int ydatum = 0;
                    482:     int i, j;
                    483:     double v[3];
                    484:     int pt_in_iso_crv = 0;
                    485:     struct iso_curve *this_iso;
                    486:
                    487:     if (mapping3d == MAP3D_CARTESIAN) {
                    488:        if (df_no_use_specs == 2)
                    489:            int_error("Need 1 or 3 columns for cartesian data", this_plot->token);
                    490:     } else {
                    491:        if (df_no_use_specs == 1)
                    492:            int_error("Need 2 or 3 columns for polar data", this_plot->token);
                    493:     }
                    494:
                    495:     this_plot->num_iso_read = 0;
                    496:     this_plot->has_grid_topology = TRUE;
                    497:
                    498:     /* we ought to keep old memory - most likely case
                    499:      * is a replot, so it will probably exactly fit into
                    500:      * memory already allocated ?
                    501:      */
                    502:     if (this_plot->iso_crvs != NULL) {
                    503:        struct iso_curve *icrv, *icrvs = this_plot->iso_crvs;
                    504:
                    505:        while (icrvs) {
                    506:            icrv = icrvs;
                    507:            icrvs = icrvs->next;
                    508:            iso_free(icrv);
                    509:        }
                    510:        this_plot->iso_crvs = NULL;
                    511:     }
                    512:     /* data file is already open */
                    513:
                    514:     if (df_matrix)
                    515:        xdatum = df_3dmatrix(this_plot);
                    516:     else {
                    517:        /*{{{  read surface from text file */
                    518:        struct iso_curve *this_iso = iso_alloc(samples);
                    519:        struct coordinate GPHUGE *cp;
                    520:        double x, y, z;
                    521:
                    522:        while ((j = df_readline(v, 3)) != DF_EOF) {
                    523:            if (j == DF_SECOND_BLANK)
                    524:                break;          /* two blank lines */
                    525:            if (j == DF_FIRST_BLANK) {
                    526:                /* one blank line */
                    527:                if (pt_in_iso_crv == 0) {
                    528:                    if (xdatum == 0)
                    529:                        continue;
                    530:                    pt_in_iso_crv = xdatum;
                    531:                }
                    532:                if (xdatum > 0) {
                    533:                    this_iso->p_count = xdatum;
                    534:                    this_iso->next = this_plot->iso_crvs;
                    535:                    this_plot->iso_crvs = this_iso;
                    536:                    this_plot->num_iso_read++;
                    537:
                    538:                    if (xdatum != pt_in_iso_crv)
                    539:                        this_plot->has_grid_topology = FALSE;
                    540:
                    541:                    this_iso = iso_alloc(pt_in_iso_crv);
                    542:                    xdatum = 0;
                    543:                    ydatum++;
                    544:                }
                    545:                continue;
                    546:            }
                    547:            /* its a data point or undefined */
                    548:
                    549:            if (xdatum >= this_iso->p_max) {
                    550:                /*
                    551:                 * overflow about to occur. Extend size of points[] array. We
                    552:                 * either double the size, or add 1000 points, whichever is a
                    553:                 * smaller increment. Note i = p_max.
                    554:                 */
                    555:                iso_extend(this_iso,
                    556:                           xdatum + (xdatum < 1000 ? xdatum : 1000));
                    557:            }
                    558:            cp = this_iso->points + xdatum;
                    559:
                    560:            if (j == DF_UNDEFINED) {
                    561:                cp->type = UNDEFINED;
                    562:                continue;
                    563:            }
                    564:            cp->type = INRANGE; /* unless we find out different */
                    565:
                    566:            switch (mapping3d) {
                    567:            case MAP3D_CARTESIAN:
                    568:                switch (j) {
                    569:                case 1:
                    570:                    x = xdatum;
                    571:                    y = ydatum;
                    572:                    z = v[0];
                    573:                    break;
                    574:                case 3:
                    575:                    x = v[0];
                    576:                    y = v[1];
                    577:                    z = v[2];
                    578:                    break;
                    579:                default:
                    580:                    {
                    581:                        char msg[80];
                    582:                        sprintf(msg, "Need 1 or 3 columns - line %d", df_line_number);
                    583:                        int_error(msg, this_plot->token);
                    584:                        return; /* avoid gcc -Wuninitialised for x,y,z */
                    585:                    }
                    586:                }
                    587:                break;
                    588:            case MAP3D_SPHERICAL:
                    589:                if (j < 2)
                    590:                    int_error("Need 2 or 3 columns", this_plot->token);
                    591:                if (j < 3)
                    592:                    v[2] = 1;   /* default radius */
                    593:                if (angles_format == ANGLES_DEGREES) {
                    594:                    v[0] *= DEG2RAD;    /* Convert to radians. */
                    595:                    v[1] *= DEG2RAD;
                    596:                }
                    597:                x = v[2] * cos(v[0]) * cos(v[1]);
                    598:                y = v[2] * sin(v[0]) * cos(v[1]);
                    599:                z = v[2] * sin(v[1]);
                    600:                break;
                    601:            case MAP3D_CYLINDRICAL:
                    602:                if (j < 2)
                    603:                    int_error("Need 2 or 3 columns", this_plot->token);
                    604:                if (j < 3)
                    605:                    v[2] = 1;   /* default radius */
                    606:                if (angles_format == ANGLES_DEGREES) {
                    607:                    v[0] *= DEG2RAD;    /* Convert to radians. */
                    608:                }
                    609:                x = v[2] * cos(v[0]);
                    610:                y = v[2] * sin(v[0]);
                    611:                z = v[1];
                    612:                break;
                    613:            default:
                    614:                int_error("Internal error : Unknown mapping type", NO_CARET);
                    615:                return;
                    616:            }
                    617:
                    618:            /* adjust for logscales. Set min/max and point types.
                    619:             * store in cp
                    620:             */
                    621:            cp->type = INRANGE;
                    622:            /* cannot use continue, as macro is wrapped in a loop.
                    623:             * I regard this as correct goto use
                    624:             */
                    625:            STORE_WITH_LOG_AND_FIXUP_RANGE(cp->x, x, cp->type, x_axis, NOOP, goto come_here_if_undefined);
                    626:            STORE_WITH_LOG_AND_FIXUP_RANGE(cp->y, y, cp->type, y_axis, NOOP, goto come_here_if_undefined);
                    627:            STORE_WITH_LOG_AND_FIXUP_RANGE(cp->z, z, cp->type, z_axis, NOOP, goto come_here_if_undefined);
                    628:
                    629:            /* some may complain, but I regard this as the correct use
                    630:             * of goto
                    631:             */
                    632:          come_here_if_undefined:
                    633:            ++xdatum;
                    634:        }                       /* end of whileloop - end of surface */
                    635:
                    636:        if (xdatum > 0) {
                    637:            this_plot->num_iso_read++;  /* Update last iso. */
                    638:            this_iso->p_count = xdatum;
                    639:
                    640:            this_iso->next = this_plot->iso_crvs;
                    641:            this_plot->iso_crvs = this_iso;
                    642:
                    643:            if (xdatum != pt_in_iso_crv)
                    644:                this_plot->has_grid_topology = FALSE;
                    645:
                    646:        } else {
                    647:            iso_free(this_iso); /* Free last allocation. */
                    648:        }
                    649:
                    650:        if (dgrid3d && this_plot->num_iso_read > 0)
                    651:            grid_nongrid_data(this_plot);
                    652:        /*}}} */
                    653:     }
                    654:
                    655:     if (this_plot->num_iso_read <= 1)
                    656:        this_plot->has_grid_topology = FALSE;
                    657:     if (this_plot->has_grid_topology && !hidden3d) {
                    658:        struct iso_curve *new_icrvs = NULL;
                    659:        int num_new_iso = this_plot->iso_crvs->p_count, len_new_iso = this_plot->num_iso_read;
                    660:
                    661:        /* Now we need to set the other direction (pseudo) isolines. */
                    662:        for (i = 0; i < num_new_iso; i++) {
                    663:            struct iso_curve *new_icrv = iso_alloc(len_new_iso);
                    664:
                    665:            new_icrv->p_count = len_new_iso;
                    666:
                    667:            for (j = 0, this_iso = this_plot->iso_crvs;
                    668:                 this_iso != NULL;
                    669:                 j++, this_iso = this_iso->next) {
                    670:                /* copy whole point struct to get type too.
                    671:                 * wasteful for windows, with padding */
                    672:                /* more efficient would be extra pointer to same struct */
                    673:                new_icrv->points[j] = this_iso->points[i];
                    674:            }
                    675:
                    676:            new_icrv->next = new_icrvs;
                    677:            new_icrvs = new_icrv;
                    678:        }
                    679:
                    680:        /* Append the new iso curves after the read ones. */
                    681:        for (this_iso = this_plot->iso_crvs;
                    682:             this_iso->next != NULL;
                    683:             this_iso = this_iso->next);
                    684:        this_iso->next = new_icrvs;
                    685:     }
                    686: }
                    687:
                    688:
                    689:
                    690: static void print_3dtable(pcount)
                    691: int pcount;
                    692: {
                    693:     register struct surface_points *this_plot;
                    694:     int i, curve, surface;
                    695:     struct iso_curve *icrvs;
                    696:     struct coordinate GPHUGE *points;
                    697:
                    698:     for (surface = 0, this_plot = first_3dplot; surface < pcount;
                    699:         this_plot = this_plot->next_sp, surface++) {
                    700:        fprintf(gpoutfile, "\n#Surface %d of %d surfaces\n", surface, pcount);
                    701:        icrvs = this_plot->iso_crvs;
                    702:        curve = 0;
                    703:
                    704:        if (draw_surface) {
                    705:            /* only the curves in one direction */
                    706:            while (icrvs && curve < this_plot->num_iso_read) {
                    707:                fprintf(gpoutfile, "\n#IsoCurve %d, %d points\n#x y z type\n",
                    708:                        curve, icrvs->p_count);
                    709:                for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
                    710:                    fprintf(gpoutfile, "%g %g %g %c\n",
                    711:                            points[i].x,
                    712:                            points[i].y,
                    713:                            points[i].z,
                    714:                            points[i].type == INRANGE ? 'i'
                    715:                            : points[i].type == OUTRANGE ? 'o'
                    716:                            : 'u');
                    717:                }
                    718:                icrvs = icrvs->next;
                    719:                curve++;
                    720:            }
                    721:            putc('\n', gpoutfile);
                    722:        }
                    723:        if (draw_contour) {
                    724:            int number = 0;
                    725:            struct gnuplot_contours *c = this_plot->contours;
                    726:            while (c) {
                    727:                int count = c->num_pts;
                    728:                struct coordinate GPHUGE *p = c->coords;
                    729:                if (c->isNewLevel)
                    730:                    /* dont display count - contour split across chunks */
                    731:                    /* put # in case user wants to use it for a plot */
                    732:                    /* double blank line to allow plot ... index ... */
                    733:                    fprintf(gpoutfile, "\n# Contour %d, label: %s\n", number++, c->label);
                    734:                for (; --count >= 0; ++p)
                    735:                    fprintf(gpoutfile, "%g %g %g\n", p->x, p->y, p->z);
                    736:                /* blank line between segments of same contour */
                    737:                putc('\n', gpoutfile);
                    738:                c = c->next;
                    739:            }
                    740:        }
                    741:     }
                    742:     fflush(gpoutfile);
                    743: }
                    744:
                    745:
                    746:
                    747: #define SET_DUMMY_RANGE(AXIS) \
                    748: do{\
                    749:  if (parametric || polar) { \
                    750:   t_min = tmin; t_max = tmax;\
                    751:  } else if (log_array[AXIS]) {\
                    752:   if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0)\
                    753:    int_error("x/x2 range must be greater than 0 for log scale!", NO_CARET);\
                    754:   t_min = log(min_array[AXIS])/log_base_array[AXIS]; t_max = log(max_array[AXIS])/log_base_array[AXIS];\
                    755:  } else {\
                    756:   t_min = min_array[AXIS]; t_max = max_array[AXIS];\
                    757:  }\
                    758:  t_step = (t_max - t_min) / (samples - 1); \
                    759: }while(0)
                    760:
                    761:
                    762: /*
                    763:  * This parses the splot command after any range specifications. To support
                    764:  * autoscaling on the x/z axis, we want any data files to define the x/y
                    765:  * range, then to plot any functions using that range. We thus parse the
                    766:  * input twice, once to pick up the data files, and again to pick up the
                    767:  * functions. Definitions are processed twice, but that won't hurt.
                    768:  * div - okay, it doesn't hurt, but every time an option as added for
                    769:  * datafiles, code to parse it has to be added here. Change so that
                    770:  * we store starting-token in the plot structure.
                    771:  */
                    772: static void eval_3dplots()
                    773: {
                    774:     int i, j;
                    775:     struct surface_points **tp_3d_ptr;
                    776:     int start_token, end_token;
                    777:     int begin_token;
                    778:     TBOOLEAN some_data_files = FALSE, some_functions = FALSE;
                    779:     int plot_num, line_num, point_num, crnt_param = 0; /* 0 = z, 1 = y, 2 = x */
                    780:     char *xtitle;
                    781:     char *ytitle;
                    782:
                    783:     /* Reset first_3dplot. This is usually done at the end of this function.
                    784:      * If there is an error within this function, the memory is left allocated,
                    785:      * since we cannot call sp_free if the list is incomplete
                    786:      */
                    787:     first_3dplot = NULL;
                    788:
                    789:     /* put stuff into arrays to simplify access */
                    790:     INIT_ARRAYS(FIRST_X_AXIS, xmin, xmax, autoscale_lx, is_log_x, base_log_x, log_base_log_x, 0);
                    791:     INIT_ARRAYS(FIRST_Y_AXIS, ymin, ymax, autoscale_ly, is_log_y, base_log_y, log_base_log_y, 0);
                    792:     INIT_ARRAYS(FIRST_Z_AXIS, zmin, zmax, autoscale_lz, is_log_z, base_log_z, log_base_log_z, 1);
                    793:
                    794:     x_axis = FIRST_X_AXIS;
                    795:     y_axis = FIRST_Y_AXIS;
                    796:     z_axis = FIRST_Z_AXIS;
                    797:
                    798:     tp_3d_ptr = &(first_3dplot);
                    799:     plot_num = 0;
                    800:     line_num = 0;              /* default line type */
                    801:     point_num = 0;             /* default point type */
                    802:
                    803:     xtitle = NULL;
                    804:     ytitle = NULL;
                    805:
                    806:     begin_token = c_token;
                    807:
                    808: /*** First Pass: Read through data files ***/
                    809:     /*
                    810:      * This pass serves to set the x/yranges and to parse the command, as
                    811:      * well as filling in every thing except the function data. That is done
                    812:      * after the x/yrange is defined.
                    813:      */
                    814:     while (TRUE) {
                    815:        if (END_OF_COMMAND)
                    816:            int_error("function to plt3d expected", c_token);
                    817:
                    818:        start_token = c_token;
                    819:
                    820:        if (is_definition(c_token)) {
                    821:            define();
                    822:        } else {
                    823:            int specs;
                    824:            struct surface_points *this_plot;
                    825:
                    826:            if (isstring(c_token)) {    /* data file to plot */
                    827:
                    828:                /*{{{  data file */
                    829:                if (parametric && crnt_param != 0)
                    830:                    int_error("previous parametric function not fully specified", c_token);
                    831:
                    832:                if (!some_data_files) {
                    833:                    if (autoscale_lx & 1) {
                    834:                        min_array[FIRST_X_AXIS] = VERYLARGE;
                    835:                    }
                    836:                    if (autoscale_lx & 2) {
                    837:                        max_array[FIRST_X_AXIS] = -VERYLARGE;
                    838:                    }
                    839:                    if (autoscale_ly & 1) {
                    840:                        min_array[FIRST_Y_AXIS] = VERYLARGE;
                    841:                    }
                    842:                    if (autoscale_ly & 2) {
                    843:                        max_array[FIRST_Y_AXIS] = -VERYLARGE;
                    844:                    }
                    845:                    some_data_files = TRUE;
                    846:                }
                    847:                if (*tp_3d_ptr)
                    848:                    this_plot = *tp_3d_ptr;
                    849:                else {          /* no memory malloc()'d there yet */
                    850:                    /* Allocate enough isosamples and samples */
                    851:                    this_plot = sp_alloc(0, 0, 0, 0);
                    852:                    *tp_3d_ptr = this_plot;
                    853:                }
                    854:
                    855:                this_plot->plot_type = DATA3D;
                    856:                this_plot->plot_style = data_style;
                    857:
                    858:                specs = df_open(3);
                    859:                /* parses all datafile-specific modifiers */
                    860:                /* we will load the data after parsing title,with,... */
                    861:
                    862:                /* for capture to key */
                    863:                this_plot->token = end_token = c_token - 1;
                    864:
                    865:                /* this_plot->token is temporary, for errors in get_3ddata() */
                    866:
                    867:                if (datatype[FIRST_X_AXIS] == TIME) {
                    868:                    if (specs < 3)
                    869:                        int_error("Need full using spec for x time data",
                    870:                                  c_token);
                    871:                    df_timecol[0] = 1;
                    872:                }
                    873:                if (datatype[FIRST_Y_AXIS] == TIME) {
                    874:                    if (specs < 3)
                    875:                        int_error("Need full using spec for y time data",
                    876:                                  c_token);
                    877:                    df_timecol[1] = 1;
                    878:                }
                    879:                if (datatype[FIRST_Z_AXIS] == TIME) {
                    880:                    if (specs < 3)
                    881:                        df_timecol[0] = 1;
                    882:                    else
                    883:                        df_timecol[2] = 1;
                    884:                }
                    885:                /*}}} */
                    886:
                    887:            } else {            /* function to plot */
                    888:
                    889:                /*{{{  function */
                    890:                ++plot_num;
                    891:                if (parametric) {
                    892:                    /* Rotate between x/y/z axes */
                    893:                    /* +2 same as -1, but beats -ve problem */
                    894:                    crnt_param = (crnt_param + 2) % 3;
                    895:                }
                    896:
                    897:                if (*tp_3d_ptr) {
                    898:                    this_plot = *tp_3d_ptr;
                    899:                    if (!hidden3d)
                    900:                        sp_replace(this_plot, samples_1, iso_samples_1,
                    901:                                   samples_2, iso_samples_2);
                    902:                    else
                    903:                        sp_replace(this_plot, iso_samples_1, 0,
                    904:                                   0, iso_samples_2);
                    905:
                    906:                } else {        /* no memory malloc()'d there yet */
                    907:                    /* Allocate enough isosamples and samples */
                    908:                    if (!hidden3d)
                    909:                        this_plot = sp_alloc(samples_1, iso_samples_1,
                    910:                                             samples_2, iso_samples_2);
                    911:                    else
                    912:                        this_plot = sp_alloc(iso_samples_1, 0,
                    913:                                             0, iso_samples_2);
                    914:                    *tp_3d_ptr = this_plot;
                    915:                }
                    916:
                    917:                this_plot->plot_type = FUNC3D;
                    918:                this_plot->has_grid_topology = TRUE;
                    919:                this_plot->plot_style = func_style;
                    920:                this_plot->num_iso_read = iso_samples_2;
                    921:                dummy_func = &plot_func;
                    922:                plot_func.at = temp_at();
                    923:                dummy_func = NULL;
                    924:                /* ignore it for now */
                    925:                some_functions = TRUE;
                    926:                end_token = c_token - 1;
                    927:                /*}}} */
                    928:
                    929:            }                   /* end of IS THIS A FILE OR A FUNC block */
                    930:
                    931:
                    932:            /*{{{  title */
                    933:            if (this_plot->title) {
                    934:                free(this_plot->title);
                    935:                this_plot->title = NULL;
                    936:            }
                    937:            if (almost_equals(c_token, "t$itle")) {
                    938:                /*                      if (!isstring(++c_token))
                    939:                   int_error("Expected title", c_token);
                    940:                   m_quote_capture(&(this_plot->title), c_token, c_token);
                    941:                 */
                    942:                if (parametric) {
                    943:                    if (crnt_param != 0)
                    944:                        int_error("\"title\" allowed only after parametric function fully specified", c_token);
                    945:                    else {
                    946:                        if (xtitle != NULL)
                    947:                            xtitle[0] = NUL;    /* Remove default title . */
                    948:                        if (ytitle != NULL)
                    949:                            ytitle[0] = NUL;    /* Remove default title . */
                    950:                    }
                    951:                }
                    952:                if (isstring(++c_token))
                    953:                    m_quote_capture(&(this_plot->title), c_token, c_token);
                    954:                else
                    955:                    int_error("expecting \"title\" for plot", c_token);
                    956:                /* end of new method */
                    957:                ++c_token;
                    958:            } else if (almost_equals(c_token, "not$itle")) {
                    959:                if (xtitle != NULL)
                    960:                    xtitle[0] = '\0';
                    961:                if (ytitle != NULL)
                    962:                    ytitle[0] = '\0';
                    963:                /*   this_plot->title = NULL;   */
                    964:                ++c_token;
                    965:            } else {
                    966:                m_capture(&(this_plot->title), start_token, end_token);
                    967:                if (crnt_param == 2)
                    968:                    xtitle = this_plot->title;
                    969:                else if (crnt_param == 1)
                    970:                    ytitle = this_plot->title;
                    971:            }
                    972:            /*}}} */
                    973:
                    974:
                    975:            /*{{{  line types, widths, ... */
                    976:            this_plot->lp_properties.l_type = line_num;
                    977:            this_plot->lp_properties.p_type = point_num;
                    978:
                    979:            if (almost_equals(c_token, "w$ith")) {
                    980:                this_plot->plot_style = get_style();
                    981:            }
                    982:            /* pick up line/point specs
                    983:             * - point spec allowed if style uses points, ie style&2 != 0
                    984:             * - keywords are optional
                    985:             */
                    986:            LP_PARSE(this_plot->lp_properties, 1, this_plot->plot_style & 2,
                    987:                     line_num, point_num);
                    988:
                    989:            /* allow old-style syntax too - ignore case lt 3 4 for example */
                    990:            if (!equals(c_token, ",") && !END_OF_COMMAND) {
                    991:                struct value t;
                    992:                this_plot->lp_properties.l_type =
                    993:                    this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
                    994:
                    995:                if (!equals(c_token, ",") && !END_OF_COMMAND)
                    996:                    this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
                    997:            }
                    998:            if (this_plot->plot_style & 2)      /* lines, linesp, ... */
                    999:                if (crnt_param == 0)
                   1000:                    point_num +=
                   1001:                        1 + (draw_contour != 0)
                   1002:                        + (hidden3d != 0);
                   1003:
                   1004:            if (crnt_param == 0)
                   1005:                line_num += 1 + (draw_contour != 0)
                   1006:                    + (hidden3d != 0);
                   1007:            /*}}} */
                   1008:
                   1009:
                   1010:            /* now get the data... having to think hard here...
                   1011:             * first time through, we fill in this_plot. For second
                   1012:             * surface in file, we have to allocate another surface
                   1013:             * struct. BUT we may allocate this store only to
                   1014:             * find that it is merely some blank lines at end of file
                   1015:             * tp_3d_ptr is still pointing at next field of prev. plot,
                   1016:             * before :    prev_or_first -> this_plot -> possible_preallocated_store
                   1017:             *                tp_3d_ptr--^
                   1018:             * after  :    prev_or_first -> first -> second -> last -> possibly_more_store
                   1019:             *                                        tp_3d_ptr ----^
                   1020:             * if file is empty, tp_3d_ptr is not moved. this_plot continues
                   1021:             * to point at allocated storage, but that will be reused later
                   1022:             */
                   1023:
                   1024:            assert(this_plot == *tp_3d_ptr);
                   1025:
                   1026:            if (this_plot->plot_type == DATA3D) {
                   1027:                /*{{{  read data */
                   1028:                /* remember settings for second surface in file */
                   1029:                struct lp_style_type *these_props = &(this_plot->lp_properties);
                   1030:                enum PLOT_STYLE this_style = this_plot->plot_style;
                   1031:
                   1032:                int this_token = this_plot->token;
                   1033:                while (!df_eof) {
                   1034:                    this_plot = *tp_3d_ptr;
                   1035:                    assert(this_plot != NULL);
                   1036:
                   1037:                    /* dont move tp_3d_ptr until we are sure we
                   1038:                     * have read a surface
                   1039:                     */
                   1040:
                   1041:                    /* used by get_3ddata() */
                   1042:                    this_plot->token = this_token;
                   1043:
                   1044:                    get_3ddata(this_plot);
                   1045:                    /* for second pass */
                   1046:                    this_plot->token = c_token;
                   1047:
                   1048:                    if (this_plot->num_iso_read == 0)
                   1049:                        /* probably df_eof, in which case we
                   1050:                         * will leave loop. if not eof, then
                   1051:                         * how come we got no surface ? - retry
                   1052:                         * in neither case do we update tp_3d_ptr
                   1053:                         */
                   1054:                        continue;
                   1055:
                   1056:                    /* okay, we have read a surface */
                   1057:                    ++plot_num;
                   1058:                    tp_3d_ptr = &(this_plot->next_sp);
                   1059:                    if (df_eof)
                   1060:                        break;
                   1061:
                   1062:                    /* there might be another surface so allocate
                   1063:                     * and prepare another surface structure
                   1064:                     * This does no harm if in fact there are
                   1065:                     * no more surfaces to read
                   1066:                     */
                   1067:
                   1068:                    if ((this_plot = *tp_3d_ptr) != NULL) {
                   1069:                        if (this_plot->title) {
                   1070:                            free(this_plot->title);
                   1071:                            this_plot->title = NULL;
                   1072:                        }
                   1073:                    } else {
                   1074:                        /* Allocate enough isosamples and samples */
                   1075:                        this_plot = *tp_3d_ptr = sp_alloc(0, 0, 0, 0);
                   1076:                    }
                   1077:
                   1078:                    this_plot->plot_type = DATA3D;
                   1079:                    this_plot->plot_style = this_style;
                   1080:                    /* Struct copy */
                   1081:                    this_plot->lp_properties = *these_props;
                   1082:                }
                   1083:                df_close();
                   1084:                /*}}} */
                   1085:
                   1086:            } else {            /* not a data file */
                   1087:                tp_3d_ptr = &(this_plot->next_sp);
                   1088:                this_plot->token = c_token;     /* store for second pass */
                   1089:            }
                   1090:
                   1091:        }               /* !is_definition() : end of scope of this_plot */
                   1092:
                   1093:
                   1094:        if (equals(c_token, ","))
                   1095:            c_token++;
                   1096:        else
                   1097:            break;
                   1098:
                   1099:     }                          /* while(TRUE), ie first pass */
                   1100:
                   1101:
                   1102:     if (parametric && crnt_param != 0)
                   1103:        int_error("parametric function not fully specified", NO_CARET);
                   1104:
                   1105:
                   1106: /*** Second Pass: Evaluate the functions ***/
                   1107:     /*
                   1108:      * Everything is defined now, except the function data. We expect no
                   1109:      * syntax errors, etc, since the above parsed it all. This makes the code
                   1110:      * below simpler. If autoscale_ly, the yrange may still change.
                   1111:      * - eh ?  - z can still change.  x/y/z can change if we are parametric ??
                   1112:      */
                   1113:
                   1114:     if (some_functions) {
                   1115:
                   1116:        /* I've changed the controlled variable in fn plots to u_min etc since
                   1117:         * it's easier for me to think parametric - 'normal' plot is after all
                   1118:         * a special case. I was confused about x_min being both minimum of
                   1119:         * x values found, and starting value for fn plots.
                   1120:         */
                   1121:        register double u_min, u_max, u_step, v_min, v_max, v_step;
                   1122:        double uisodiff, visodiff;
                   1123:        struct surface_points *this_plot;
                   1124:
                   1125:
                   1126:        if (!parametric) {
                   1127:            /*{{{  check ranges */
                   1128:            /* give error if xrange badly set from missing datafile error
                   1129:             * parametric fn can still set ranges
                   1130:             * if there are no fns, we'll report it later as 'nothing to plot'
                   1131:             */
                   1132:
                   1133:            if (min_array[FIRST_X_AXIS] == VERYLARGE ||
                   1134:                max_array[FIRST_X_AXIS] == -VERYLARGE) {
                   1135:                int_error("x range is invalid", c_token);
                   1136:            }
                   1137:            if (min_array[FIRST_Y_AXIS] == VERYLARGE ||
                   1138:                max_array[FIRST_Y_AXIS] == -VERYLARGE) {
                   1139:                int_error("y range is invalid", c_token);
                   1140:            }
                   1141:            /* check that xmin -> xmax is not too small */
                   1142:            fixup_range(FIRST_X_AXIS, "x");
                   1143:            fixup_range(FIRST_Y_AXIS, "y");
                   1144:            /*}}} */
                   1145:        }
                   1146:        if (parametric && !some_data_files) {
                   1147:            /*{{{  set ranges */
                   1148:            /* parametric fn can still change x/y range */
                   1149:            if (autoscale_lx & 1)
                   1150:                min_array[FIRST_X_AXIS] = VERYLARGE;
                   1151:            if (autoscale_lx & 2)
                   1152:                max_array[FIRST_X_AXIS] = -VERYLARGE;
                   1153:            if (autoscale_ly & 1)
                   1154:                min_array[FIRST_Y_AXIS] = VERYLARGE;
                   1155:            if (autoscale_ly & 2)
                   1156:                max_array[FIRST_Y_AXIS] = -VERYLARGE;
                   1157:            /*}}} */
                   1158:        }
                   1159:        if (parametric) {
                   1160:            u_min = umin;
                   1161:            u_max = umax;
                   1162:            v_min = vmin;
                   1163:            v_max = vmax;
                   1164:        } else {
                   1165:            /*{{{  figure ranges, taking logs etc into account */
                   1166:            if (is_log_x) {
                   1167:                if (min_array[FIRST_X_AXIS] <= 0.0 ||
                   1168:                    max_array[FIRST_X_AXIS] <= 0.0)
                   1169:                    int_error("x range must be greater than 0 for log scale!",
                   1170:                              NO_CARET);
                   1171:                u_min = log(min_array[FIRST_X_AXIS]) / log_base_log_x;
                   1172:                u_max = log(max_array[FIRST_X_AXIS]) / log_base_log_x;
                   1173:            } else {
                   1174:                u_min = min_array[FIRST_X_AXIS];
                   1175:                u_max = max_array[FIRST_X_AXIS];
                   1176:            }
                   1177:
                   1178:            if (is_log_y) {
                   1179:                if (min_array[FIRST_Y_AXIS] <= 0.0 ||
                   1180:                    max_array[FIRST_Y_AXIS] <= 0.0) {
                   1181:                    int_error("y range must be greater than 0 for log scale!",
                   1182:                              NO_CARET);
                   1183:                }
                   1184:                v_min = log(min_array[FIRST_Y_AXIS]) / log_base_log_y;
                   1185:                v_max = log(max_array[FIRST_Y_AXIS]) / log_base_log_y;
                   1186:            } else {
                   1187:                v_min = min_array[FIRST_Y_AXIS];
                   1188:                v_max = max_array[FIRST_Y_AXIS];
                   1189:            }
                   1190:            /*}}} */
                   1191:        }
                   1192:
                   1193:
                   1194:        if (samples_1 < 2 || samples_2 < 2 || iso_samples_1 < 2 ||
                   1195:            iso_samples_2 < 2) {
                   1196:            int_error("samples or iso_samples < 2. Must be at least 2.",
                   1197:                      NO_CARET);
                   1198:        }
                   1199:
                   1200:        /* start over */
                   1201:        this_plot = first_3dplot;
                   1202:        c_token = begin_token;
                   1203:
                   1204:        /* why do attributes of this_plot matter ? */
                   1205:
                   1206:        if (this_plot && this_plot->has_grid_topology && hidden3d) {
                   1207:            u_step = (u_max - u_min) / (iso_samples_1 - 1);
                   1208:            v_step = (v_max - v_min) / (iso_samples_2 - 1);
                   1209:        } else {
                   1210:            u_step = (u_max - u_min) / (samples_1 - 1);
                   1211:            v_step = (v_max - v_min) / (samples_2 - 1);
                   1212:        }
                   1213:
                   1214:        uisodiff = (u_max - u_min) / (iso_samples_1 - 1);
                   1215:        visodiff = (v_max - v_min) / (iso_samples_2 - 1);
                   1216:
                   1217:
                   1218:        /* Read through functions */
                   1219:        while (TRUE) {
                   1220:            if (is_definition(c_token)) {
                   1221:                define();
                   1222:            } else {
                   1223:
                   1224:                if (!isstring(c_token)) {       /* func to plot */
                   1225:                    /*{{{  evaluate function */
                   1226:                    struct iso_curve *this_iso = this_plot->iso_crvs;
                   1227:                    struct coordinate GPHUGE *points = this_iso->points;
                   1228:                    int num_sam_to_use, num_iso_to_use;
                   1229:
                   1230:                    if (parametric)
                   1231:                        crnt_param = (crnt_param + 2) % 3;
                   1232:
                   1233:                    dummy_func = &plot_func;
                   1234:                    plot_func.at = temp_at();   /* reparse function */
                   1235:                    dummy_func = NULL;
                   1236:                    num_iso_to_use = iso_samples_2;
                   1237:
                   1238:                    if (!(this_plot->has_grid_topology && hidden3d))
                   1239:                        num_sam_to_use = samples_1;
                   1240:                    else
                   1241:                        num_sam_to_use = iso_samples_1;
                   1242:
                   1243:                    for (j = 0; j < num_iso_to_use; j++) {
                   1244:                        double y = v_min + j * visodiff;
                   1245:                        /* if (is_log_y) PEM fix logscale y axis */
                   1246:                        /* y = pow(log_base_log_y,y); 26-Sep-89 */
                   1247:                        /* parametric => NOT a log quantity (?) */
                   1248:                        (void) Gcomplex(&plot_func.dummy_values[1],
                   1249:                        !parametric && is_log_y ? pow(base_log_y, y) : y,
                   1250:                                        0.0);
                   1251:
                   1252:                        for (i = 0; i < num_sam_to_use; i++) {
                   1253:                            double x = u_min + i * u_step;
                   1254:                            struct value a;
                   1255:                            double temp;
                   1256:
                   1257:                            /* if (is_log_x) PEM fix logscale x axis */
                   1258:                            /* x = pow(base_log_x,x); 26-Sep-89 */
                   1259:                            /* parametric => NOT a log quantity (?) */
                   1260:                            (void) Gcomplex(&plot_func.dummy_values[0],
                   1261:                                            !parametric && is_log_x ? pow(base_log_x, x) : x, 0.0);
                   1262:
                   1263:                            points[i].x = x;
                   1264:                            points[i].y = y;
                   1265:
                   1266:                            evaluate_at(plot_func.at, &a);
                   1267:
                   1268:                            if (undefined || (fabs(imag(&a)) > zero)) {
                   1269:                                points[i].type = UNDEFINED;
                   1270:                                continue;
                   1271:                            }
                   1272:                            temp = real(&a);
                   1273:
                   1274:                            points[i].type = INRANGE;
                   1275:                            STORE_WITH_LOG_AND_FIXUP_RANGE(points[i].z, temp, points[i].type, crnt_param, NOOP, NOOP);
                   1276:
                   1277:                        }
                   1278:                        this_iso->p_count = num_sam_to_use;
                   1279:                        this_iso = this_iso->next;
                   1280:                        points = this_iso ? this_iso->points : NULL;
                   1281:                    }
                   1282:
                   1283:                    if (!(this_plot->has_grid_topology && hidden3d)) {
                   1284:                        num_iso_to_use = iso_samples_1;
                   1285:                        num_sam_to_use = samples_2;
                   1286:                        for (i = 0; i < num_iso_to_use; i++) {
                   1287:                            double x = u_min + i * uisodiff;
                   1288:                            /* if (is_log_x) PEM fix logscale x axis */
                   1289:                            /* x = pow(base_log_x,x); 26-Sep-89 */
                   1290:                            /* if parametric, no logs involved - 3.6 */
                   1291:                            (void) Gcomplex(&plot_func.dummy_values[0],
                   1292:                                            (!parametric && is_log_x) ? pow(base_log_x, x) : x, 0.0);
                   1293:
                   1294:                            for (j = 0; j < num_sam_to_use; j++) {
                   1295:                                double y = v_min + j * v_step;
                   1296:                                struct value a;
                   1297:                                double temp;
                   1298:                                /* if (is_log_y) PEM fix logscale y axis */
                   1299:                                /* y = pow(base_log_y,y); 26-Sep-89 */
                   1300:                                (void) Gcomplex(&plot_func.dummy_values[1],
                   1301:                                                (!parametric && is_log_y) ? pow(base_log_y, y) : y, 0.0);
                   1302:
                   1303:                                points[j].x = x;
                   1304:                                points[j].y = y;
                   1305:
                   1306:                                evaluate_at(plot_func.at, &a);
                   1307:
                   1308:                                if (undefined || (fabs(imag(&a)) > zero)) {
                   1309:                                    points[j].type = UNDEFINED;
                   1310:                                    continue;
                   1311:                                }
                   1312:                                temp = real(&a);
                   1313:
                   1314:                                points[j].type = INRANGE;
                   1315:                                STORE_WITH_LOG_AND_FIXUP_RANGE(points[j].z, temp, points[j].type, crnt_param, NOOP, NOOP);
                   1316:                            }
                   1317:                            this_iso->p_count = num_sam_to_use;
                   1318:                            this_iso = this_iso->next;
                   1319:                            points = this_iso ? this_iso->points : NULL;
                   1320:                        }
                   1321:                    }
                   1322:                    /*}}} */
                   1323:                }               /* end of ITS A FUNCTION TO PLOT */
                   1324:
                   1325:                /* we saved it from first pass */
                   1326:                c_token = this_plot->token;
                   1327:
                   1328:                /* one data file can make several plots */
                   1329:                do
                   1330:                    this_plot = this_plot->next_sp;
                   1331:                while (this_plot && this_plot->token == c_token);
                   1332:
                   1333:            }                   /* !is_definition */
                   1334:
                   1335:            if (equals(c_token, ","))
                   1336:                c_token++;
                   1337:            else
                   1338:                break;
                   1339:
                   1340:        }                       /* while(TRUE) */
                   1341:
                   1342:
                   1343:        if (parametric) {
                   1344:            /* Now actually fix the plot triplets to be single plots. */
                   1345:            parametric_3dfixup(first_3dplot, &plot_num);
                   1346:        }
                   1347:     }                          /* some functions */
                   1348:     /* if first_3dplot is NULL, we have no functions or data at all.
                   1349:        * This can happen, if you type "splot x=5", since x=5 is a
                   1350:        * variable assignment
                   1351:      */
                   1352:     if (plot_num == 0 || first_3dplot == NULL) {
                   1353:        int_error("no functions or data to plot", c_token);
                   1354:     }
                   1355:     if (min_array[FIRST_X_AXIS] == VERYLARGE ||
                   1356:        max_array[FIRST_X_AXIS] == -VERYLARGE ||
                   1357:        min_array[FIRST_Y_AXIS] == VERYLARGE ||
                   1358:        max_array[FIRST_Y_AXIS] == -VERYLARGE ||
                   1359:        min_array[FIRST_Z_AXIS] == VERYLARGE ||
                   1360:        max_array[FIRST_Z_AXIS] == -VERYLARGE)
                   1361:        int_error("All points undefined", NO_CARET);
                   1362:
                   1363:     fixup_range(FIRST_X_AXIS, "x");
                   1364:     fixup_range(FIRST_Y_AXIS, "y");
                   1365:     fixup_range(FIRST_Z_AXIS, "z");
                   1366:
                   1367:     FIXUP_RANGE_FOR_LOG(FIRST_X_AXIS, x);
                   1368:     FIXUP_RANGE_FOR_LOG(FIRST_Y_AXIS, y);
                   1369:     FIXUP_RANGE_FOR_LOG(FIRST_Z_AXIS, z);
                   1370:
                   1371:     /* last parameter should take plot size into effect...
                   1372:      * probably needs to be moved to graph3d.c
                   1373:      * in the meantime, a value of 20 gives same behaviour
                   1374:      * as 3.5 which will do for the moment
                   1375:      */
                   1376:
                   1377:     if (xtics)
                   1378:        setup_tics(FIRST_X_AXIS, &xticdef, xformat, 20);
                   1379:     if (ytics)
                   1380:        setup_tics(FIRST_Y_AXIS, &yticdef, yformat, 20);
                   1381:     if (ztics)
                   1382:        setup_tics(FIRST_Z_AXIS, &zticdef, zformat, 20);
                   1383:
                   1384: #define WRITEBACK(axis,min,max) \
                   1385: if(range_flags[axis]&RANGE_WRITEBACK) \
                   1386:   {if (auto_array[axis]&1) min = min_array[axis]; \
                   1387:    if (auto_array[axis]&2) max = max_array[axis]; \
                   1388:   }
                   1389:
                   1390:     WRITEBACK(FIRST_X_AXIS, xmin, xmax);
                   1391:     WRITEBACK(FIRST_Y_AXIS, ymin, ymax);
                   1392:     WRITEBACK(FIRST_Z_AXIS, zmin, zmax);
                   1393:
                   1394:     if (plot_num == 0 || first_3dplot == NULL) {
                   1395:         int_error("no functions or data to plot", c_token);
                   1396:     }
                   1397:     /* Creates contours if contours are to be plotted as well. */
                   1398:
                   1399:     if (draw_contour) {
                   1400:        struct surface_points *this_plot;
                   1401:        for (this_plot = first_3dplot, i = 0;
                   1402:             i < plot_num;
                   1403:             this_plot = this_plot->next_sp, i++) {
                   1404:
                   1405:            if (this_plot->contours) {
                   1406:                struct gnuplot_contours *cntrs = this_plot->contours;
                   1407:
                   1408:                while (cntrs) {
                   1409:                    struct gnuplot_contours *cntr = cntrs;
                   1410:                    cntrs = cntrs->next;
                   1411:                    free(cntr->coords);
                   1412:                    free(cntr);
                   1413:                }
                   1414:            }
                   1415:            /* Make sure this one can be contoured. */
                   1416:            if (!this_plot->has_grid_topology) {
                   1417:                this_plot->contours = NULL;
                   1418:                fputs("Notice: cannot contour non grid data!\n", stderr);
                   1419:                /* changed from int_error by recommendation of
                   1420:                 * rkc@xn.ll.mit.edu
                   1421:                 */
                   1422:            } else if (this_plot->plot_type == DATA3D) {
                   1423:                this_plot->contours = contour(
                   1424:                                                 this_plot->num_iso_read,
                   1425:                                                 this_plot->iso_crvs,
                   1426:                                             contour_levels, contour_pts,
                   1427:                                             contour_kind, contour_order,
                   1428:                                               levels_kind, levels_list);
                   1429:            } else {
                   1430:                this_plot->contours = contour(iso_samples_2,
                   1431:                                              this_plot->iso_crvs,
                   1432:                                              contour_levels, contour_pts,
                   1433:                                              contour_kind, contour_order,
                   1434:                                              levels_kind, levels_list);
                   1435:            }
                   1436:        }
                   1437:     }                          /* draw_contour */
                   1438:     /* perform the plot */
                   1439:     if (strcmp(term->name, "table") == 0)
                   1440:        print_3dtable(plot_num);
                   1441:     else {
                   1442:        START_LEAK_CHECK();     /* assert no memory leaks here ! */
                   1443:        do_3dplot(first_3dplot, plot_num);
                   1444:        END_LEAK_CHECK();
                   1445:     }
                   1446:
                   1447:     /* if we get here, all went well, so record the line for replot */
                   1448:     if (plot_token != -1) {
                   1449:        /* note that m_capture also frees the old replot_line */
                   1450:        m_capture(&replot_line, plot_token, c_token - 1);
                   1451:        plot_token = -1;
                   1452:     }
                   1453:     sp_free(first_3dplot);
                   1454:     first_3dplot = NULL;
                   1455: }
                   1456:
                   1457:
                   1458:
                   1459:
                   1460:
                   1461: static void parametric_3dfixup(start_plot, plot_num)
                   1462: struct surface_points *start_plot;
                   1463: int *plot_num;
                   1464: /*
                   1465:  * The hardest part of this routine is collapsing the FUNC plot types in the
                   1466:  * list (which are gauranteed to occur in (x,y,z) triplets while preserving
                   1467:  * the non-FUNC type plots intact.  This means we have to work our way
                   1468:  * through various lists.  Examples (hand checked):
                   1469:  * start_plot:F1->F2->F3->NULL ==> F3->NULL
                   1470:  * start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F3->F6->NULL
                   1471:  * start_plot:F1->F2->F3->D1->D2->F4->F5->F6->D3->NULL ==>
                   1472:  * F3->D1->D2->F6->D3->NULL
                   1473:  */
                   1474: {
                   1475: /*
                   1476:  * I initialized *free_list with NULL, because my compiler warns some lines
                   1477:  * later that it might be uninited. The code however seems to not access that
                   1478:  * line in that case, but if I'm right, my change is OK and if not, this is a
                   1479:  * serious bug in the code.
                   1480:  *
                   1481:  * x and y ranges now fixed in eval_3dplots
                   1482:  */
                   1483:     struct surface_points *xp, *new_list, *free_list = NULL;
                   1484:     struct surface_points **last_pointer = &new_list;
                   1485:
                   1486:     int i, tlen, surface;
                   1487:     char *new_title;
                   1488:
                   1489:     /*
                   1490:      * Ok, go through all the plots and move FUNC3D types together.  Note:
                   1491:      * this originally was written to look for a NULL next pointer, but
                   1492:      * gnuplot wants to be sticky in grabbing memory and the right number of
                   1493:      * items in the plot list is controlled by the plot_num variable.
                   1494:      *
                   1495:      * Since gnuplot wants to do this sticky business, a free_list of
                   1496:      * surface_points is kept and then tagged onto the end of the plot list
                   1497:      * as this seems more in the spirit of the original memory behavior than
                   1498:      * simply freeing the memory.  I'm personally not convinced this sort of
                   1499:      * concern is worth it since the time spent computing points seems to
                   1500:      * dominate any garbage collecting that might be saved here...
                   1501:      */
                   1502:     new_list = xp = start_plot;
                   1503:     for (surface = 0; surface < *plot_num; surface++) {
                   1504:        if (xp->plot_type == FUNC3D) {
                   1505:            struct surface_points *yp = xp->next_sp;
                   1506:            struct surface_points *zp = yp->next_sp;
                   1507:
                   1508:            /* Here's a FUNC3D parametric function defined as three parts.
                   1509:             * Go through all the points and assign the x's and y's from xp and
                   1510:             * yp to zp. min/max already done
                   1511:             */
                   1512:            struct iso_curve *xicrvs = xp->iso_crvs;
                   1513:            struct iso_curve *yicrvs = yp->iso_crvs;
                   1514:            struct iso_curve *zicrvs = zp->iso_crvs;
                   1515:
                   1516:            (*plot_num) -= 2;
                   1517:
                   1518:            assert(INRANGE < OUTRANGE && OUTRANGE < UNDEFINED);
                   1519:
                   1520:            while (zicrvs) {
                   1521:                struct coordinate GPHUGE *xpoints = xicrvs->points,
                   1522:                 GPHUGE * ypoints = yicrvs->points, GPHUGE * zpoints = zicrvs->points;
                   1523:                for (i = 0; i < zicrvs->p_count; ++i) {
                   1524:                    zpoints[i].x = xpoints[i].z;
                   1525:                    zpoints[i].y = ypoints[i].z;
                   1526:                    if (zpoints[i].type < xpoints[i].type)
                   1527:                        zpoints[i].type = xpoints[i].type;
                   1528:                    if (zpoints[i].type < ypoints[i].type)
                   1529:                        zpoints[i].type = ypoints[i].type;
                   1530:
                   1531:                }
                   1532:                xicrvs = xicrvs->next;
                   1533:                yicrvs = yicrvs->next;
                   1534:                zicrvs = zicrvs->next;
                   1535:            }
                   1536:
                   1537:            /* Ok, fix up the title to include xp and yp plots. */
                   1538:            if (((xp->title && xp->title[0] != '\0') ||
                   1539:                 (yp->title && yp->title[0] != '\0')) && zp->title) {
                   1540:                tlen = (xp->title ? strlen(xp->title) : 0) +
                   1541:                    (yp->title ? strlen(yp->title) : 0) +
                   1542:                    (zp->title ? strlen(zp->title) : 0) + 5;
                   1543:                new_title = gp_alloc((unsigned long) tlen, "string");
                   1544:                new_title[0] = 0;
                   1545:                if (xp->title && xp->title[0] != '\0') {
                   1546:                    strcat(new_title, xp->title);
                   1547:                    strcat(new_title, ", ");    /* + 2 */
                   1548:                }
                   1549:                if (yp->title && yp->title[0] != '\0') {
                   1550:                    strcat(new_title, yp->title);
                   1551:                    strcat(new_title, ", ");    /* + 2 */
                   1552:                }
                   1553:                strcat(new_title, zp->title);
                   1554:                free(zp->title);
                   1555:                zp->title = new_title;
                   1556:            }
                   1557:            /* add xp and yp to head of free list */
                   1558:            assert(xp->next_sp == yp);
                   1559:            yp->next_sp = free_list;
                   1560:            free_list = xp;
                   1561:
                   1562:            /* add zp to tail of new_list */
                   1563:            *last_pointer = zp;
                   1564:            last_pointer = &(zp->next_sp);
                   1565:            xp = zp->next_sp;
                   1566:        } else {                /* its a data plot */
                   1567:            assert(*last_pointer == xp);        /* think this is true ! */
                   1568:            last_pointer = &(xp->next_sp);
                   1569:            xp = xp->next_sp;
                   1570:        }
                   1571:     }
                   1572:
                   1573:     /* Ok, append free list and write first_plot */
                   1574:     *last_pointer = free_list;
                   1575:     first_3dplot = new_list;
                   1576: }

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