[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.1     ! maekawa     1: #ifndef lint
        !             2: static char *RCSid = "$Id: plot3d.c,v 1.36 1998/06/18 14:55:14 ddenholm Exp $";
        !             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>