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