Icons are changed
[gnuplot] / src / pm3d.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: pm3d.c,v 1.66.2.6 2009/06/19 00:01:00 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - pm3d.c */
6
7 /*[
8  *
9  * Petr Mikulik, since December 1998
10  * Copyright: open source as much as possible
11  *
12  * What is here: global variables and routines for the pm3d splotting mode.
13  * This file is included only if PM3D is defined.
14  *
15 ]*/
16
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 #include "pm3d.h"
21 #include "alloc.h"
22 #include "axis.h"
23 #include "graphics.h"
24 #include "graph3d.h"
25 #include "hidden3d.h"           /* p_vertex & map3d_xyz() */
26 #include "plot2d.h"
27 #include "plot3d.h"
28 #include "setshow.h"            /* for surface_rot_z */
29 #include "term_api.h"           /* for lp_use_properties() */
30 #include "command.h"            /* for c_token */
31
32 #include <stdlib.h> /* qsort() */
33
34
35 /*
36   Global options for pm3d algorithm (to be accessed by set / show).
37 */
38
39 pm3d_struct pm3d = {
40     "s",                        /* where[6] */
41     PM3D_FLUSH_BEGIN,           /* flush */
42     0,                          /* no flushing triangles */
43     PM3D_SCANS_AUTOMATIC,       /* scans direction is determined automatically */
44     PM3D_CLIP_4IN,              /* clipping: all 4 points in ranges */
45     0,                          /* no pm3d hidden3d is drawn */
46 #if PM3D_HAVE_SOLID
47     0,                          /* solid (off by default, that means `transparent') */
48 #endif /* PM3D_HAVE_SOLID */
49     PM3D_EXPLICIT,              /* implicit */
50     PM3D_WHICHCORNER_MEAN,      /* color from which corner(s) */
51     1,                          /* interpolate along scanline */
52     1                           /* interpolate between scanlines */
53 };
54
55 typedef struct {
56     double gray;
57     double z; /* maximal z value after rotation to graph coordinate system */
58     gpdPoint corners[4];
59     gpiPoint icorners[4]; /* also if EXTENDED_COLOR_SPECS is not defined */
60 } quadrangle;
61
62 static int allocated_quadrangles = 0;
63 static int current_quadrangle = 0;
64 static quadrangle* quadrangles = (quadrangle*)0;
65
66 /* Internal prototypes for this module */
67 static TBOOLEAN plot_has_palette;
68 static double geomean4 __PROTO((double, double, double, double));
69 static double median4 __PROTO((double, double, double, double));
70 static void pm3d_plot __PROTO((struct surface_points *, int));
71 static void pm3d_option_at_error __PROTO((void));
72 static void pm3d_rearrange_part __PROTO((struct iso_curve *, const int, struct iso_curve ***, int *));
73 static void filled_color_contour_plot  __PROTO((struct surface_points *, int));
74
75 /*
76  * Utility routines.
77  */
78
79 /* Geometrical mean = pow( prod(x_i > 0) x_i, 1/N )
80  * Sign of the result: result is positive if 3 or 4 x_i are positive,
81  * it is negative if 3 or all 4 x_i are negative. Helps to splot surface
82  * with all color coordinates negative.
83  */
84 static double
85 geomean4 (double x1, double x2, double x3, double x4)
86 {
87 #if 0
88     /* return 0 if any of the number is negative */
89     if (x1 <= 0) x1 = 1;
90     if (x2 > 0) x1 *= x2;
91     if (x3 > 0) x1 *= x3;
92     if (x4 > 0) x1 *= x4;
93     return pow(x1, 0.25);
94 #else
95     /* honor signess, i.e. sign(geomean) = sign(prod(x_i)) */
96     int neg = (x1 < 0) + (x2 < 0) + (x3 < 0) + (x4 < 0);
97     x1 *= x2 * x3 * x4;
98     if (x1 == 0) return 0;
99     /* pow(x, 0.25) is slightly faster than sqrt(sqrt(x)) */
100     x1 = sqrt(sqrt(fabs(x1)));
101 #if 0
102     /* such a warning could be helpful, but under normal usage it is just an overhead */
103     if (neg > 1 && interactive && notwarned) {
104             int notwarned = 1;  ... to be set on every new splot
105             if (notwarned)
106                 int_warn(NO_CARET, "corners2color geomean with negative data points");
107             notwarned = 0;
108     }
109 #endif
110     return (neg <= 2) ? x1 : -x1;
111 #endif
112 }
113
114
115 /* Median: sort values, and then: for N odd, it is the middle value; for N even,
116  * it is mean of the two middle values.
117  */
118 static double
119 median4 (double x1, double x2, double x3, double x4)
120 {
121     double tmp;
122     /* sort them: x1 < x2 and x3 < x4 */
123     if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
124     if (x3 > x4) { tmp = x3; x3 = x4; x4 = tmp; }
125     /* sum middle numbers */
126     tmp = (x1 < x3) ? x3 : x1;
127     tmp += (x2 < x4) ? x2 : x4;
128     return tmp * 0.5;
129 }
130
131
132 /* Minimum of 4 numbers.
133  */
134 static double
135 minimum4 (double x1, double x2, double x3, double x4)
136 {
137     x1 = GPMIN(x1, x2);
138     x3 = GPMIN(x3, x4);
139     return GPMIN(x1, x3);
140 }
141
142
143 /* Maximum of 4 numbers.
144  */
145 static double
146 maximum4 (double x1, double x2, double x3, double x4)
147 {
148     x1 = GPMAX(x1, x2);
149     x3 = GPMAX(x3, x4);
150     return GPMAX(x1, x3);
151 }
152
153
154 /*
155 * Now the routines which are really just those for pm3d.c
156 */
157
158 /*
159  * Rescale z to cb values. Nothing to do if both z and cb are linear or log of the
160  * same base, other it has to un-log z and subsequently log it again.
161  */
162 double
163 z2cb(double z)
164 {
165     if (!Z_AXIS.log && !CB_AXIS.log) /* both are linear */
166         return z;
167     if (Z_AXIS.log && !CB_AXIS.log) /* log z, linear cb */
168         return exp(z * Z_AXIS.log_base); /* unlog(z) */
169     if (!Z_AXIS.log && CB_AXIS.log) /* linear z, log cb */
170         return (log(z) / CB_AXIS.log_base);
171     /* both are log */
172     if (Z_AXIS.base==CB_AXIS.base) /* can we compare double numbers like that? */
173         return z;
174     return z * Z_AXIS.log_base / CB_AXIS.log_base; /* log_cb(unlog_z(z)) */
175 }
176
177
178 /*
179  * Rescale cb (color) value into the interval of grays [0,1], taking care
180  * of palette being positive or negative.
181  * Note that it is OK for logarithmic cb-axis too.
182  */
183 double
184 cb2gray(double cb)
185 {
186     if (cb <= CB_AXIS.min)
187         return (sm_palette.positive == SMPAL_POSITIVE) ? 0 : 1;
188     if (cb >= CB_AXIS.max)
189         return (sm_palette.positive == SMPAL_POSITIVE) ? 1 : 0;
190     cb = (cb - CB_AXIS.min)
191       / (CB_AXIS.max - CB_AXIS.min);
192     return (sm_palette.positive == SMPAL_POSITIVE) ? cb : 1-cb;
193 }
194
195
196 /*
197  * Rearrange...
198  */
199 static void
200 pm3d_rearrange_part(
201     struct iso_curve *src,
202     const int len,
203     struct iso_curve ***dest,
204     int *invert)
205 {
206     struct iso_curve *scanA;
207     struct iso_curve *scanB;
208     struct iso_curve **scan_array;
209     int i, scan;
210     int invert_order = 0;
211
212     /* loop over scans in one surface
213        Scans are linked from this_plot->iso_crvs in the opposite order than
214        they are in the datafile.
215        Therefore it is necessary to make vector scan_array of iso_curves.
216        Scans are sorted in scan_array according to pm3d.direction (this can
217        be PM3D_SCANS_FORWARD or PM3D_SCANS_BACKWARD).
218      */
219     scan_array = *dest = gp_alloc(len * sizeof(scanA), "pm3d scan array");
220
221     if (pm3d.direction == PM3D_SCANS_AUTOMATIC) {
222         int cnt;
223         int len2 = len;
224         TBOOLEAN exit_outer_loop = 0;
225
226         for (scanA = src; scanA && 0 == exit_outer_loop; scanA = scanA->next, len2--) {
227
228             int from, i;
229             vertex vA, vA2;
230
231             if ((cnt = scanA->p_count - 1) <= 0)
232                 continue;
233
234             /* ordering within one scan */
235             for (from=0; from<=cnt; from++) /* find 1st non-undefined point */
236                 if (scanA->points[from].type != UNDEFINED) {
237                     map3d_xyz(scanA->points[from].x, scanA->points[from].y, 0, &vA);
238                     break;
239                 }
240             for (i=cnt; i>from; i--) /* find the last non-undefined point */
241                 if (scanA->points[i].type != UNDEFINED) {
242                     map3d_xyz(scanA->points[i].x, scanA->points[i].y, 0, &vA2);
243                     break;
244                 }
245
246             if (i - from > cnt * 0.1)
247                 /* it is completely arbitrary to request at least
248                  * 10% valid samples in this scan. (joze Jun-05-2002) */
249                 *invert = (vA2.z > vA.z) ? 0 : 1;
250             else
251                 continue; /* all points were undefined, so check next scan */
252
253
254             /* check the z ordering between scans
255              * Find last scan. If this scan has all points undefined,
256              * find last but one scan, an so on. */
257
258             for (; len2 >= 3 && !exit_outer_loop; len2--) {
259                 for (scanB = scanA-> next, i = len2 - 2; i && scanB; i--)
260                     scanB = scanB->next; /* skip over to last scan */
261                 if (scanB && scanB->p_count) {
262                     vertex vB;
263                     for (i = from /* we compare vA.z with vB.z */; i<scanB->p_count; i++) {
264                         /* find 1st non-undefined point */
265                         if (scanB->points[i].type != UNDEFINED) {
266                             map3d_xyz(scanB->points[i].x, scanB->points[i].y, 0, &vB);
267                             invert_order = (vB.z > vA.z) ? 0 : 1;
268                             exit_outer_loop = 1;
269                             break;
270                         }
271                     }
272                 }
273             }
274         }
275     }
276
277 #if 0
278     fprintf(stderr, "(pm3d_rearrange_part) invert       = %d\n", *invert);
279     fprintf(stderr, "(pm3d_rearrange_part) invert_order = %d\n", invert_order);
280 #endif
281
282     for (scanA = src, scan = len - 1, i = 0; scan >= 0; --scan, i++) {
283         if (pm3d.direction == PM3D_SCANS_AUTOMATIC) {
284             switch (invert_order) {
285             case 1:
286                 scan_array[scan] = scanA;
287                 break;
288             case 0:
289             default:
290                 scan_array[i] = scanA;
291                 break;
292             }
293         } else if (pm3d.direction == PM3D_SCANS_FORWARD)
294             scan_array[scan] = scanA;
295         else                    /* PM3D_SCANS_BACKWARD: i counts scans */
296             scan_array[i] = scanA;
297         scanA = scanA->next;
298     }
299 }
300
301
302 /*
303  * Rearrange scan array
304  *
305  * Allocates *first_ptr (and eventually *second_ptr)
306  * which must be freed by the caller
307  */
308 void
309 pm3d_rearrange_scan_array(
310     struct surface_points *this_plot,
311     struct iso_curve ***first_ptr,
312     int *first_n, int *first_invert,
313     struct iso_curve ***second_ptr,
314     int *second_n, int *second_invert)
315 {
316     if (first_ptr) {
317         pm3d_rearrange_part(this_plot->iso_crvs, this_plot->num_iso_read, first_ptr, first_invert);
318         *first_n = this_plot->num_iso_read;
319     }
320     if (second_ptr) {
321         struct iso_curve *icrvs = this_plot->iso_crvs;
322         struct iso_curve *icrvs2;
323         int i;
324         /* advance until second part */
325         for (i = 0; i < this_plot->num_iso_read; i++)
326             icrvs = icrvs->next;
327         /* count the number of scans of second part */
328         for (i = 0, icrvs2 = icrvs; icrvs2; icrvs2 = icrvs2->next)
329             i++;
330         if (i > 0) {
331             *second_n = i;
332             pm3d_rearrange_part(icrvs, i, second_ptr, second_invert);
333         } else {
334             *second_ptr = (struct iso_curve **) 0;
335         }
336     }
337 }
338
339 static int compare_quadrangles(const void* v1, const void* v2)
340 {
341     const quadrangle* q1 = (const quadrangle*)v1;
342     const quadrangle* q2 = (const quadrangle*)v2;
343
344     if (q1->z > q2->z)
345         return 1;
346     else if (q1->z < q2->z)
347         return -1;
348     else
349         return 0;
350 }
351
352 void pm3d_depth_queue_clear(void)
353 {
354     if (pm3d.direction != PM3D_DEPTH)
355         return;
356
357     if (quadrangles)
358         free(quadrangles);
359     quadrangles = (quadrangle*)0;
360     allocated_quadrangles = 0;
361     current_quadrangle = 0;
362 }
363
364 void pm3d_depth_queue_flush(void)
365 {
366     if (pm3d.direction != PM3D_DEPTH)
367         return;
368
369     if (current_quadrangle > 0 && quadrangles) {
370
371         quadrangle* qp;
372         quadrangle* qe;
373         gpdPoint* gpdPtr;
374         gpiPoint* gpiPtr;
375         vertex out;
376         double z = 0; /* assignment keeps the compiler happy */
377         double w = trans_mat[3][3];
378         int i;
379
380         for (qp = quadrangles, qe = quadrangles + current_quadrangle; qp != qe; qp++) {
381
382             gpdPtr = qp->corners;
383             gpiPtr = qp->icorners;
384
385             for (i = 0; i < 4; i++, gpdPtr++, gpiPtr++) {
386
387                 map3d_xyz(gpdPtr->x, gpdPtr->y, gpdPtr->z, &out);
388
389                 if (i == 0 || out.z > z)
390                     z = out.z;
391
392                 gpiPtr->x = (unsigned int) ((out.x * xscaler / w) + xmiddle);
393                 gpiPtr->y = (unsigned int) ((out.y * yscaler / w) + ymiddle);
394             }
395
396             qp->z = z; /* maximal z value of all four corners */
397         }
398
399         qsort(quadrangles, current_quadrangle, sizeof (quadrangle), compare_quadrangles);
400
401         for (qp = quadrangles, qe = quadrangles + current_quadrangle; qp != qe; qp++) {
402
403             set_color(qp->gray);
404             ifilled_quadrangle(qp->icorners);
405         }
406     }
407
408     pm3d_depth_queue_clear();
409 }
410
411 /*
412  * Now the implementation of the pm3d (s)plotting mode
413  *
414  * Note: the input parameter at_which_z is char, but an old HP cc requires
415  * ANSI C K&R routines with int only.
416  */
417 static void
418 pm3d_plot(struct surface_points *this_plot, int at_which_z)
419 {
420     int j, i, i1, ii, ii1, from, curve, scan, up_to, up_to_minus, invert = 0;
421     int go_over_pts, max_pts;
422     int are_ftriangles, ftriangles_low_pt = -999, ftriangles_high_pt = -999;
423     struct iso_curve *scanA, *scanB;
424     struct coordinate GPHUGE *pointsA, *pointsB;
425     struct iso_curve **scan_array;
426     int scan_array_n;
427     double avgC, gray;
428     double cb1, cb2, cb3, cb4;
429     gpdPoint corners[4];
430 #ifdef EXTENDED_COLOR_SPECS
431     gpiPoint icorners[4];
432 #endif
433     gpdPoint **bl_point = NULL; /* used for bilinear interpolation */
434
435     /* just a shortcut */
436     TBOOLEAN color_from_column = this_plot->pm3d_color_from_column;
437
438     if (this_plot == NULL)
439         return;
440
441     if (at_which_z != PM3D_AT_BASE && at_which_z != PM3D_AT_TOP && at_which_z != PM3D_AT_SURFACE)
442         return;
443
444     /* return if the terminal does not support filled polygons */
445     if (!term->filled_polygon)
446         return;
447
448     switch (at_which_z) {
449     case PM3D_AT_BASE:
450         corners[0].z = corners[1].z = corners[2].z = corners[3].z = base_z;
451         break;
452     case PM3D_AT_TOP:
453         corners[0].z = corners[1].z = corners[2].z = corners[3].z = ceiling_z;
454         break;
455         /* the 3rd possibility is surface, PM3D_AT_SURFACE, coded below */
456     }
457
458     scanA = this_plot->iso_crvs;
459     curve = 0;
460
461     pm3d_rearrange_scan_array(this_plot, &scan_array, &scan_array_n, &invert, (struct iso_curve ***) 0, (int *) 0, (int *) 0);
462
463     if (pm3d.direction == PM3D_DEPTH) {
464
465         for (scan = 0; scan < this_plot->num_iso_read - 1; scan++) {
466
467             scanA = scan_array[scan];
468             scanB = scan_array[scan + 1];
469
470             are_ftriangles = pm3d.ftriangles && (scanA->p_count != scanB->p_count);
471             if (!are_ftriangles)
472                 allocated_quadrangles += GPMIN(scanA->p_count, scanB->p_count) - 1;
473             else {
474                 allocated_quadrangles += GPMAX(scanA->p_count, scanB->p_count) - 1;
475             }
476         }
477         allocated_quadrangles *= (pm3d.interp_i > 1) ? pm3d.interp_i : 1;
478         allocated_quadrangles *= (pm3d.interp_j > 1) ? pm3d.interp_j : 1;
479         quadrangles = (quadrangle*)gp_realloc(quadrangles, allocated_quadrangles * sizeof (quadrangle), "pm3d_plot->quadrangles");
480         /* DEBUG: fprintf(stderr, "allocated_quadrangles = %d\n", allocated_quadrangles); */
481     }
482     /* pm3d_rearrange_scan_array(this_plot, (struct iso_curve***)0, (int*)0, &scan_array, &invert); */
483
484 #if 0
485     /* debugging: print scan_array */
486     for (scan = 0; scan < this_plot->num_iso_read; scan++) {
487         printf("**** SCAN=%d  points=%d\n", scan, scan_array[scan]->p_count);
488     }
489 #endif
490
491 #if 0
492     /* debugging: this loop prints properties of all scans */
493     for (scan = 0; scan < this_plot->num_iso_read; scan++) {
494         struct coordinate GPHUGE *points;
495         scanA = scan_array[scan];
496         printf("\n#IsoCurve = scan nb %d, %d points\n#x y z type(in,out,undef)\n", scan, scanA->p_count);
497         for (i = 0, points = scanA->points; i < scanA->p_count; i++) {
498             printf("%g %g %g %c\n",
499                    points[i].x, points[i].y, points[i].z, points[i].type == INRANGE ? 'i' : points[i].type == OUTRANGE ? 'o' : 'u');
500             /* Note: INRANGE, OUTRANGE, UNDEFINED */
501         }
502     }
503     printf("\n");
504 #endif
505
506     /*
507      * if bilinear interpolation is enabled, allocate memory for the
508      * interpolated points here
509      */
510     if (pm3d.interp_i > 1 || pm3d.interp_j > 1) {
511         bl_point = (gpdPoint **)gp_alloc(sizeof(gpdPoint*) * (pm3d.interp_i+1), "bl-interp along scan");
512         for (i1 = 0; i1 <= pm3d.interp_i; i1++)
513             bl_point[i1] = (gpdPoint *)gp_alloc(sizeof(gpdPoint) * (pm3d.interp_j+1), "bl-interp between scan");
514     }
515
516     /*
517      * this loop does the pm3d draw of joining two curves
518      *
519      * How the loop below works:
520      * - scanB = scan last read; scanA = the previous one
521      * - link the scan from A to B, then move B to A, then read B, then draw
522      */
523     for (scan = 0; scan < this_plot->num_iso_read - 1; scan++) {
524         scanA = scan_array[scan];
525         scanB = scan_array[scan + 1];
526 #if 0
527         printf("\n#IsoCurveA = scan nb %d has %d points   ScanB has %d points\n", scan, scanA->p_count, scanB->p_count);
528 #endif
529         pointsA = scanA->points;
530         pointsB = scanB->points;
531         /* if the number of points in both scans is not the same, then the
532          * starting index (offset) of scan B according to the flushing setting
533          * has to be determined
534          */
535         from = 0;               /* default is pm3d.flush==PM3D_FLUSH_BEGIN */
536         if (pm3d.flush == PM3D_FLUSH_END)
537             from = abs(scanA->p_count - scanB->p_count);
538         else if (pm3d.flush == PM3D_FLUSH_CENTER)
539             from = abs(scanA->p_count - scanB->p_count) / 2;
540         /* find the minimal number of points in both scans */
541         up_to = GPMIN(scanA->p_count, scanB->p_count) - 1;
542         up_to_minus = up_to - 1; /* calculate only once */
543         are_ftriangles = pm3d.ftriangles && (scanA->p_count != scanB->p_count);
544         if (!are_ftriangles)
545             go_over_pts = up_to;
546         else {
547             max_pts = GPMAX(scanA->p_count, scanB->p_count);
548             go_over_pts = max_pts - 1;
549             /* the j-subrange of quadrangles; in the remaing of the interval
550              * [0..up_to] the flushing triangles are to be drawn */
551             ftriangles_low_pt = from;
552             ftriangles_high_pt = from + up_to_minus;
553         }
554         /* Go over
555          *   - the minimal number of points from both scans, if only quadrangles.
556          *   - the maximal number of points from both scans if flush triangles
557          *     (the missing points in the scan of lower nb of points will be
558          *     duplicated from the begin/end points).
559          *
560          * Notice: if it would be once necessary to go over points in `backward'
561          * direction, then the loop body below would require to replace the data
562          * point indices `i' by `up_to-i' and `i+1' by `up_to-i-1'.
563          */
564         for (j = 0; j < go_over_pts; j++) {
565             /* Now i be the index of the scan with smaller number of points,
566              * ii of the scan with larger number of points. */
567             if (are_ftriangles && (j < ftriangles_low_pt || j > ftriangles_high_pt)) {
568                 i = (j <= ftriangles_low_pt) ? 0 : ftriangles_high_pt-from+1;
569                 ii = j;
570                 i1 = i;
571                 ii1 = ii + 1;
572             } else {
573                 int jj = are_ftriangles ? j - from : j;
574                 i = jj;
575                 if (PM3D_SCANS_AUTOMATIC == pm3d.direction && invert)
576                     i = up_to_minus - jj;
577                 ii = i + from;
578                 i1 = i + 1;
579                 ii1 = ii + 1;
580             }
581             /* From here, i is index to scan A, ii to scan B */
582             if (scanA->p_count > scanB->p_count) {
583                 int itmp = i;
584                 i = ii;
585                 ii = itmp;
586                 itmp = i1;
587                 i1 = ii1;
588                 ii1 = itmp;
589             }
590 #if 0
591             fprintf(stderr,"j=%i:  i=%i i1=%i  [%i]   ii=%i ii1=%i  [%i]\n",j,i,i1,scanA->p_count,ii,ii1,scanB->p_count);
592 #endif
593             /* choose the clipping method */
594             if (pm3d.clip == PM3D_CLIP_4IN) {
595                 /* (1) all 4 points of the quadrangle must be in x and y range */
596                 if (!(pointsA[i].type == INRANGE && pointsA[i1].type == INRANGE &&
597                       pointsB[ii].type == INRANGE && pointsB[ii1].type == INRANGE))
598                     continue;
599             } else {            /* (pm3d.clip == PM3D_CLIP_1IN) */
600                 /* (2) all 4 points of the quadrangle must be defined */
601                 if (pointsA[i].type == UNDEFINED || pointsA[i1].type == UNDEFINED ||
602                     pointsB[ii].type == UNDEFINED || pointsB[ii1].type == UNDEFINED)
603                     continue;
604                 /* and at least 1 point of the quadrangle must be in x and y range */
605                 if (pointsA[i].type == OUTRANGE && pointsA[i1].type == OUTRANGE &&
606                     pointsB[ii].type == OUTRANGE && pointsB[ii1].type == OUTRANGE)
607                     continue;
608             }
609
610             if ((pm3d.interp_i <= 1 && pm3d.interp_j <= 1) || pm3d.direction == PM3D_DEPTH) {
611 #ifdef EXTENDED_COLOR_SPECS
612               if (!supply_extended_color_specs) {
613 #endif
614                 /* Get the gray as the average of the corner z- or gray-positions
615                    (note: log scale is already included). The average is calculated here
616                    if there is no interpolation (including the "pm3d depthorder" option),
617                    otherwise it is done for each interpolated quadrangle later.
618                    I always wonder what is faster: d*0.25 or d/4? Someone knows? -- 0.25 (joze) */
619                 if (color_from_column) {
620                     /* color is set in plot3d.c:get_3ddata() */
621                     cb1 = pointsA[i].CRD_COLOR;
622                     cb2 = pointsA[i1].CRD_COLOR;
623                     cb3 = pointsB[ii].CRD_COLOR;
624                     cb4 = pointsB[ii1].CRD_COLOR;
625                 } else {
626                     cb1 = z2cb(pointsA[i].z);
627                     cb2 = z2cb(pointsA[i1].z);
628                     cb3 = z2cb(pointsB[ii].z);
629                     cb4 = z2cb(pointsB[ii1].z);
630                 }
631                 switch (pm3d.which_corner_color) {
632                     case PM3D_WHICHCORNER_MEAN: avgC = (cb1 + cb2 + cb3 + cb4) * 0.25; break;
633                     case PM3D_WHICHCORNER_GEOMEAN: avgC = geomean4(cb1, cb2, cb3, cb4); break;
634                     case PM3D_WHICHCORNER_MEDIAN: avgC = median4(cb1, cb2, cb3, cb4); break;
635                     case PM3D_WHICHCORNER_MIN: avgC = minimum4(cb1, cb2, cb3, cb4); break;
636                     case PM3D_WHICHCORNER_MAX: avgC = maximum4(cb1, cb2, cb3, cb4); break;
637                     case PM3D_WHICHCORNER_C1: avgC = cb1; break;
638                     case PM3D_WHICHCORNER_C2: avgC = cb2; break;
639                     case PM3D_WHICHCORNER_C3: avgC = cb3; break;
640                     case PM3D_WHICHCORNER_C4: avgC = cb4; break;
641                     default: int_error(NO_CARET, "cannot be here"); avgC = 0;
642                 }
643                 /* transform z value to gray, i.e. to interval [0,1] */
644                 gray = cb2gray(avgC);
645 #if 0
646                 /* print the quadrangle with the given color */
647                 printf("averageColor %g\tgray=%g\tM %g %g L %g %g L %g %g L %g %g\n",
648                        avgC,
649                        gray,
650                        pointsA[i].x, pointsA[i].y, pointsB[ii].x, pointsB[ii].y,
651                        pointsB[ii1].x, pointsB[ii1].y, pointsA[i1].x, pointsA[i1].y);
652 #endif
653                 /* set the color */
654                 if (pm3d.direction != PM3D_DEPTH)
655                     set_color(gray);
656 #ifdef EXTENDED_COLOR_SPECS
657               }
658 #endif
659             }
660
661             corners[0].x = pointsA[i].x;
662             corners[0].y = pointsA[i].y;
663             corners[1].x = pointsB[ii].x;
664             corners[1].y = pointsB[ii].y;
665             corners[2].x = pointsB[ii1].x;
666             corners[2].y = pointsB[ii1].y;
667             corners[3].x = pointsA[i1].x;
668             corners[3].y = pointsA[i1].y;
669
670             if ( pm3d.interp_i > 1 || pm3d.interp_j > 1 || at_which_z == PM3D_AT_SURFACE) {
671                 /* always supply the z value if
672                  * EXTENDED_COLOR_SPECS is defined
673                  */
674                 corners[0].z = pointsA[i].z;
675                 corners[1].z = pointsB[ii].z;
676                 corners[2].z = pointsB[ii1].z;
677                 corners[3].z = pointsA[i1].z;
678                 if (color_from_column) {
679                     corners[0].c = pointsA[i].CRD_COLOR;
680                     corners[1].c = pointsB[ii].CRD_COLOR;
681                     corners[2].c = pointsB[ii1].CRD_COLOR;
682                     corners[3].c = pointsA[i1].CRD_COLOR;
683                 }
684             }
685 #ifdef EXTENDED_COLOR_SPECS
686             if (supply_extended_color_specs) {
687                 if (color_from_column) {
688                     icorners[0].z = pointsA[i].CRD_COLOR;
689                     icorners[1].z = pointsB[ii].CRD_COLOR;
690                     icorners[2].z = pointsB[ii1].CRD_COLOR;
691                     icorners[3].z = pointsA[i1].CRD_COLOR;
692                 } else {
693                     /* the target wants z and gray value */
694                     icorners[0].z = pointsA[i].z;
695                     icorners[1].z = pointsB[ii].z;
696                     icorners[2].z = pointsB[ii1].z;
697                     icorners[3].z = pointsA[i1].z;
698                 }
699                 for (i = 0; i < 4; i++) {
700                     icorners[i].spec.gray =
701                         cb2gray( color_from_column ? icorners[i].z : z2cb(icorners[i].z) );
702                 }
703             }
704             if (pm3d.direction == PM3D_DEPTH) {
705                 /* copy quadrangle */
706                 quadrangle* qp = quadrangles + current_quadrangle;
707                 memcpy(qp->corners, corners, 4 * sizeof (gpdPoint));
708                 qp->gray = gray;
709                 for (i = 0; i < 4; i++) {
710                     qp->icorners[i].z = icorners[i].z;
711                     qp->icorners[i].spec.gray = icorners[i].spec.gray;
712                 }
713                 current_quadrangle++;
714
715             } else
716                 filled_quadrangle(corners, icorners);
717 #else
718             if (pm3d.interp_i > 1 || pm3d.interp_j > 1) {
719                 /* Interpolation is enabled.
720                  * interp_i is the # of points along scan lines
721                  * interp_j is the # of points between scan lines
722                  * Algorithm is to first sample i points along the scan lines
723                  * defined by corners[3],corners[0] and corners[2],corners[1]. */
724                 int j1;
725                 for (i1 = 0; i1 <= pm3d.interp_i; i1++) {
726                     bl_point[i1][0].x = 
727                         ((corners[3].x - corners[0].x) / pm3d.interp_i) * i1 + corners[0].x;
728                     bl_point[i1][pm3d.interp_j].x = 
729                         ((corners[2].x - corners[1].x) / pm3d.interp_i) * i1 + corners[1].x;
730                     bl_point[i1][0].y =
731                         ((corners[3].y - corners[0].y) / pm3d.interp_i) * i1 + corners[0].y;
732                     bl_point[i1][pm3d.interp_j].y =
733                         ((corners[2].y - corners[1].y) / pm3d.interp_i) * i1 + corners[1].y;
734                     bl_point[i1][0].z =
735                         ((corners[3].z - corners[0].z) / pm3d.interp_i) * i1 + corners[0].z;
736                     bl_point[i1][pm3d.interp_j].z =
737                         ((corners[2].z - corners[1].z) / pm3d.interp_i) * i1 + corners[1].z;
738                     if (color_from_column) {
739                         bl_point[i1][0].c =
740                             ((corners[3].c - corners[0].c) / pm3d.interp_i) * i1 + corners[0].c;
741                         bl_point[i1][pm3d.interp_j].c =
742                             ((corners[2].c - corners[1].c) / pm3d.interp_i) * i1 + corners[1].c;
743                     }
744                     /* Next we sample j points between each of the new points
745                      * created in the previous step (this samples between
746                      * scan lines) in the same manner. */
747                     for (j1 = 1; j1 < pm3d.interp_j; j1++) {
748                         bl_point[i1][j1].x =
749                             ((bl_point[i1][pm3d.interp_j].x - bl_point[i1][0].x) / pm3d.interp_j) *
750                                 j1 + bl_point[i1][0].x;
751                         bl_point[i1][j1].y =
752                             ((bl_point[i1][pm3d.interp_j].y - bl_point[i1][0].y) / pm3d.interp_j) *
753                                 j1 + bl_point[i1][0].y;
754                         bl_point[i1][j1].z =
755                             ((bl_point[i1][pm3d.interp_j].z - bl_point[i1][0].z) / pm3d.interp_j) *
756                                 j1 + bl_point[i1][0].z;
757                         if (color_from_column)
758                             bl_point[i1][j1].c =
759                                 ((bl_point[i1][pm3d.interp_j].c - bl_point[i1][0].c) / pm3d.interp_j) *
760                                     j1 + bl_point[i1][0].c;
761                     }
762                 }
763                 /* Once all points are created, move them into an appropriate
764                  * structure and call set_color on each to retrieve the
765                  * correct color mapping for this new sub-sampled quadrangle. */
766                 for (i1 = 0; i1 < pm3d.interp_i; i1++) {
767                     for (j1 = 0; j1 < pm3d.interp_j; j1++) {
768                         corners[0].x = bl_point[i1][j1].x;
769                         corners[0].y = bl_point[i1][j1].y;
770                         corners[0].z = bl_point[i1][j1].z;
771                         corners[1].x = bl_point[i1+1][j1].x;
772                         corners[1].y = bl_point[i1+1][j1].y;
773                         corners[1].z = bl_point[i1+1][j1].z;
774                         corners[2].x = bl_point[i1+1][j1+1].x;
775                         corners[2].y = bl_point[i1+1][j1+1].y;
776                         corners[2].z = bl_point[i1+1][j1+1].z;
777                         corners[3].x = bl_point[i1][j1+1].x;
778                         corners[3].y = bl_point[i1][j1+1].y;
779                         corners[3].z = bl_point[i1][j1+1].z;
780                         if (color_from_column) {
781                             corners[0].c = bl_point[i1][j1].c;
782                             corners[1].c = bl_point[i1+1][j1].c;
783                             corners[2].c = bl_point[i1+1][j1+1].c;
784                             corners[3].c = bl_point[i1][j1+1].c;
785                         }
786 #if 0
787                         printf("(%g,%g),(%g,%g),(%g,%g),(%g,%g)\n",
788                             corners[0].x, corners[0].y,
789                             corners[1].x, corners[1].y,
790                             corners[2].x, corners[2].y,
791                             corners[3].x, corners[3].y);
792 #endif
793                         /* If the colors are given separately, we already loaded them above */
794                         if (!color_from_column) {
795                             cb1 = z2cb(corners[0].z);
796                             cb2 = z2cb(corners[1].z);
797                             cb3 = z2cb(corners[2].z);
798                             cb4 = z2cb(corners[3].z);
799                         } else {
800                             cb1 = corners[0].c;
801                             cb2 = corners[1].c;
802                             cb3 = corners[2].c;
803                             cb4 = corners[3].c;
804                         }
805                         switch (pm3d.which_corner_color) {
806                             case PM3D_WHICHCORNER_MEAN: avgC = (cb1 + cb2 + cb3 + cb4) * 0.25; break;
807                             case PM3D_WHICHCORNER_GEOMEAN: avgC = geomean4(cb1, cb2, cb3, cb4); break;
808                             case PM3D_WHICHCORNER_MEDIAN: avgC = median4(cb1, cb2, cb3, cb4); break;
809                             case PM3D_WHICHCORNER_MIN: avgC = minimum4(cb1, cb2, cb3, cb4); break;
810                             case PM3D_WHICHCORNER_MAX: avgC = maximum4(cb1, cb2, cb3, cb4); break;
811                             case PM3D_WHICHCORNER_C1: avgC = cb1; break;
812                             case PM3D_WHICHCORNER_C2: avgC = cb2; break;
813                             case PM3D_WHICHCORNER_C3: avgC = cb3; break;
814                             case PM3D_WHICHCORNER_C4: avgC = cb4; break;
815                             default: int_error(NO_CARET, "cannot be here"); avgC = 0;
816                         }
817                         /* transform z value to gray, i.e. to interval [0,1] */
818                         gray = cb2gray(avgC);
819                         if (pm3d.direction != PM3D_DEPTH) {
820                             set_color(gray);
821                             filled_quadrangle(corners);
822                         } else {
823                             /* copy quadrangle */
824                             quadrangle* qp = quadrangles + current_quadrangle;
825                             memcpy(qp->corners, corners, 4 * sizeof (gpdPoint));
826                             qp->gray = gray;
827                             current_quadrangle++;
828                         }
829                     }
830                 }
831             } else { /* thus (pm3d.interp_i == 1 && pm3d.interp_j == 1) */
832                 if (pm3d.direction != PM3D_DEPTH) {
833                     filled_quadrangle(corners);
834                 } else {
835                     /* copy quadrangle */
836                     quadrangle* qp = quadrangles + current_quadrangle;
837                     memcpy(qp->corners, corners, 4 * sizeof (gpdPoint));
838                     qp->gray = gray;
839                     current_quadrangle++;
840                 }
841             } /* interpolate between points */
842 #endif
843         } /* loop quadrangles over points of two subsequent scans */
844     } /* loop over scans */
845
846     if (bl_point) {
847         for (i1 = 0; i1 <= pm3d.interp_i; i1++)
848             free(bl_point[i1]);
849         free(bl_point);
850     }
851     /* free memory allocated by scan_array */
852     free(scan_array);
853 }                               /* end of pm3d splotting mode */
854
855
856 /*
857  *  Now the implementation of the filled color contour plot
858 */
859 static void
860 filled_color_contour_plot(struct surface_points *this_plot, int contours_where)
861 {
862     double gray;
863     struct gnuplot_contours *cntr;
864
865     /* just a shortcut */
866     TBOOLEAN color_from_column = this_plot->pm3d_color_from_column;
867
868     if (this_plot == NULL || this_plot->contours == NULL)
869         return;
870     if (contours_where != CONTOUR_SRF && contours_where != CONTOUR_BASE)
871         return;
872
873     /* return if the terminal does not support filled polygons */
874     if (!term->filled_polygon)
875         return;
876
877     /* TODO: CHECK FOR NUMBER OF POINTS IN CONTOUR: IF TOO SMALL, THEN IGNORE! */
878     cntr = this_plot->contours;
879     while (cntr) {
880         printf("# Contour: points %i, z %g, label: %s\n", cntr->num_pts, cntr->coords[0].z, (cntr->label) ? cntr->label : "<no>");
881         if (cntr->isNewLevel) {
882             printf("\t...it isNewLevel\n");
883             /* contour split across chunks */
884             /* fprintf(gpoutfile, "\n# Contour %d, label: %s\n", number++, c->label); */
885             /* What is the color? */
886             /* get the z-coordinate */
887             /* transform contour z-coordinate value to gray, i.e. to interval [0,1] */
888             if (color_from_column)
889                 gray = cb2gray(cntr->coords[0].CRD_COLOR);
890             else
891                 gray = cb2gray( z2cb(cntr->coords[0].z) );
892             set_color(gray);
893         }
894         /* draw one countour */
895         if (contours_where == CONTOUR_SRF)      /* at CONTOUR_SRF */
896             filled_polygon_3dcoords(cntr->num_pts, cntr->coords);
897         else                    /* at CONTOUR_BASE */
898             filled_polygon_3dcoords_zfixed(cntr->num_pts, cntr->coords, base_z);
899         /* next contour */
900         cntr = cntr->next;
901     }
902 }                               /* end of filled color contour plot splot mode */
903
904
905 /*
906  * unset pm3d for the reset command
907  */
908 void
909 pm3d_reset()
910 {
911     strcpy(pm3d.where, "s");
912     pm3d.flush = PM3D_FLUSH_BEGIN;
913     pm3d.ftriangles = 0;
914     pm3d.direction = PM3D_SCANS_AUTOMATIC;
915     pm3d.clip = PM3D_CLIP_4IN;
916     pm3d.hidden3d_tag = 0;
917 #if PM3D_HAVE_SOLID
918     pm3d.solid = 0;
919 #endif /* PM3D_HAVE_SOLID */
920     pm3d.implicit = PM3D_EXPLICIT;
921     pm3d.which_corner_color = PM3D_WHICHCORNER_MEAN;
922     pm3d.interp_i = 1;
923     pm3d.interp_j = 1;
924 }
925
926
927 /*
928  * Draw (one) PM3D color surface.
929  */
930 void
931 pm3d_draw_one(struct surface_points *plot)
932 {
933     int i = 0;
934     char *where = plot->pm3d_where[0] ? plot->pm3d_where : pm3d.where;
935         /* Draw either at 'where' option of the given surface or at pm3d.where
936          * global option. */
937
938     if (!where[0]) {
939         return;
940     }
941
942     /* for pm3dCompress.awk */
943     if (gppsfile && (pm3d.direction != PM3D_DEPTH))
944         fputs("%pm3d_map_begin\n", gppsfile);
945
946     for (; where[i]; i++) {
947         pm3d_plot(plot, where[i]);
948     }
949
950     if (strchr(where, 'C') != NULL) {
951         /* !!!!! FILLED COLOR CONTOURS, *UNDOCUMENTED*
952            !!!!! LATER CHANGE TO STH LIKE
953            !!!!!   (if_filled_contours_requested)
954            !!!!!      ...
955            Currently filled color contours do not work because gnuplot generates
956            open contour lines, i.e. not closed on the graph boundary.
957          */
958         if (draw_contour & CONTOUR_SRF)
959             filled_color_contour_plot(plot, CONTOUR_SRF);
960         if (draw_contour & CONTOUR_BASE)
961             filled_color_contour_plot(plot, CONTOUR_BASE);
962     }
963
964     /* for pm3dCompress.awk */
965     if (gppsfile && (pm3d.direction != PM3D_DEPTH))
966         fputs("%pm3d_map_end\n", gppsfile);
967 }
968
969
970 /* Display an error message for the routine get_pm3d_at_option() below.
971  */
972
973 static void
974 pm3d_option_at_error()
975 {
976     int_error(c_token, "\
977 parameter to `pm3d at` requires combination of up to 6 characters b,s,t\n\
978 \t(drawing at bottom, surface, top)");
979 }
980
981
982 /* Read the option for 'pm3d at' command.
983  * Used by 'set pm3d at ...' or by 'splot ... with pm3d at ...'.
984  * If no option given, then returns empty string, otherwise copied there.
985  * The string is unchanged on error, and 1 is returned.
986  * On success, 0 is returned.
987  */
988 int
989 get_pm3d_at_option(char *pm3d_where)
990 {
991     char* c;
992
993     if (END_OF_COMMAND || token[c_token].length >= sizeof(pm3d.where)) {
994         pm3d_option_at_error();
995         return 1;
996     }
997     memcpy(pm3d_where, gp_input_line + token[c_token].start_index,
998            token[c_token].length);
999     pm3d_where[ token[c_token].length ] = 0;
1000     /* verify the parameter */
1001     for (c = pm3d_where; *c; c++) {
1002         if (*c != 'C') /* !!!!! CONTOURS, UNDOCUMENTED, THIS LINE IS TEMPORARILY HERE !!!!! */
1003             if (*c != PM3D_AT_BASE && *c != PM3D_AT_TOP && *c != PM3D_AT_SURFACE) {
1004                 pm3d_option_at_error();
1005                 return 1;
1006         }
1007     }
1008     c_token++;
1009     return 0;
1010 }
1011
1012 /* Set flag plot_has_palette to TRUE if there is any element on the graph
1013  * which requires palette of continuous colors.
1014  */
1015 void
1016 set_plot_with_palette(int plot_num, int plot_mode)
1017 {
1018     struct surface_points *this_3dplot = first_3dplot;
1019     struct curve_points *this_2dplot = first_plot;
1020     int surface = 0;
1021     struct text_label *this_label = first_label;
1022
1023     plot_has_palette = TRUE;
1024     /* Is pm3d switched on globally? */
1025     if (pm3d.implicit == PM3D_IMPLICIT)
1026         return;
1027
1028     /* Check 2D plots */
1029     if (plot_mode == MODE_PLOT) {
1030         while (this_2dplot) {
1031 #ifdef WITH_IMAGE
1032             if (this_2dplot->plot_style == IMAGE)
1033                 return;
1034 #endif
1035             if (this_2dplot->lp_properties.use_palette
1036             &&  this_2dplot->lp_properties.pm3d_color.type > TC_RGB)
1037                 return;
1038             if (this_2dplot->labels
1039             &&  this_2dplot->labels->textcolor.type >= TC_CB)
1040                 return;
1041             this_2dplot = this_2dplot->next;
1042         }
1043     }
1044
1045     /* Check 3D plots */
1046     if (plot_mode == MODE_SPLOT) {
1047         /* Any surface 'with pm3d', 'with image' or 'with line|dot palette'? */
1048         while (surface++ < plot_num) {
1049             if (this_3dplot->plot_style == PM3DSURFACE)
1050                 return;
1051 #ifdef WITH_IMAGE
1052             if (this_3dplot->plot_style == IMAGE)
1053                 return;
1054 #endif
1055             if (this_3dplot->lp_properties.use_palette) {
1056                 int type = this_3dplot->lp_properties.pm3d_color.type;
1057                 if (type == TC_LT || type == TC_LINESTYLE || type == TC_RGB)
1058                     /* don't return yet */
1059                     ;
1060                 else
1061                     /* TC_DEFAULT: splot x with line|lp|dot palette */
1062                     return;
1063             }
1064 #ifdef EAM_DATASTRINGS
1065             if (this_3dplot->labels &&
1066                 this_3dplot->labels->textcolor.type >= TC_CB)
1067                 return;
1068 #endif
1069             this_3dplot = this_3dplot->next_sp;
1070         }
1071     }
1072
1073     /* Any label with 'textcolor palette'? */
1074 #define TC_USES_PALETTE(tctype) (tctype==TC_Z) || (tctype==TC_CB) || (tctype==TC_FRAC)
1075     for (; this_label != NULL; this_label = this_label->next) {
1076         if (TC_USES_PALETTE(this_label->textcolor.type))
1077             return;
1078     }
1079     /* Any of title, xlabel, ylabel, zlabel, ... with 'textcolor palette'? */
1080     if (TC_USES_PALETTE(title.textcolor.type)) return;
1081     if (TC_USES_PALETTE(axis_array[FIRST_X_AXIS].label.textcolor.type)) return;
1082     if (TC_USES_PALETTE(axis_array[FIRST_Y_AXIS].label.textcolor.type)) return;
1083     if (TC_USES_PALETTE(axis_array[SECOND_X_AXIS].label.textcolor.type)) return;
1084     if (TC_USES_PALETTE(axis_array[SECOND_Y_AXIS].label.textcolor.type)) return;
1085     if (plot_mode == MODE_SPLOT)
1086         if (TC_USES_PALETTE(axis_array[FIRST_Z_AXIS].label.textcolor.type)) return;
1087     if (TC_USES_PALETTE(axis_array[COLOR_AXIS].label.textcolor.type)) return;
1088 #undef TC_USES_PALETTE
1089
1090     /* Palette with continuous colors is not used. */
1091     plot_has_palette = FALSE; /* otherwise it stays TRUE */
1092 }
1093
1094 TBOOLEAN
1095 is_plot_with_palette()
1096 {
1097     return plot_has_palette;
1098 }
1099
1100 TBOOLEAN
1101 is_plot_with_colorbox()
1102 {
1103     return plot_has_palette && (color_box.where != SMCOLOR_BOX_NO);
1104 }
1105