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

Annotation of OpenXM_contrib/gnuplot/graph3d.c, Revision 1.1.1.1

1.1       maekawa     1: #ifndef lint
                      2: static char *RCSid = "$Id: graph3d.c,v 1.106 1998/06/18 14:55:07 ddenholm Exp $";
                      3: #endif
                      4:
                      5: /* GNUPLOT - graph3d.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:
                     38: /*
                     39:  * AUTHORS
                     40:  *
                     41:  *   Original Software:
                     42:  *       Gershon Elber and many others.
                     43:  *
                     44:  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
                     45:  * Added user-specified bases for log scaling.
                     46:  *
                     47:  * 3.6 - split graph3d.c into graph3d.c (graph),
                     48:  *                            util3d.c (intersections, etc)
                     49:  *                            hidden3d.c (hidden-line removal code)
                     50:  *
                     51:  */
                     52:
                     53: #include "plot.h"
                     54: #include "setshow.h"
                     55:
                     56: static int p_height;
                     57: static int p_width;            /* pointsize * t->h_tic */
                     58: static int key_entry_height;   /* bigger of t->v_size, pointsize*t->v_tick */
                     59:
                     60: int suppressMove = 0;          /* to prevent moveto while drawing contours */
                     61:
                     62: /*
                     63:  * hidden_line_type_above, hidden_line_type_below - controls type of lines
                     64:  *   for above and below parts of the surface.
                     65:  * hidden_no_update - if TRUE lines will be hidden line removed but they
                     66:  *   are not assumed to be part of the surface (i.e. grid) and therefore
                     67:  *   do not influence the hidings.
                     68:  * hidden_active - TRUE if hidden lines are to be removed.
                     69:  */
                     70: int hidden_active = FALSE;
                     71: int hidden_no_update;          /* HBB 980324: made this visible despite LITE */
                     72:
                     73: /* LITE defines a restricted memory version for MS-DOS, which doesn't
                     74:  * use the routines in hidden3d.c
                     75:  */
                     76:
                     77: #ifndef LITE
                     78: int hidden_line_type_above, hidden_line_type_below;
                     79: #endif /* LITE */
                     80:
                     81:
                     82: static double LogScale __PROTO((double coord, TBOOLEAN is_log,
                     83:                                double log_base_log, char *what, char *axis));
                     84: static void plot3d_impulses __PROTO((struct surface_points * plot));
                     85: static void plot3d_lines __PROTO((struct surface_points * plot));
                     86: static void plot3d_points __PROTO((struct surface_points * plot));
                     87: static void plot3d_dots __PROTO((struct surface_points * plot));
                     88: static void cntr3d_impulses __PROTO((struct gnuplot_contours * cntr,
                     89:                                     struct surface_points * plot));
                     90: static void cntr3d_lines __PROTO((struct gnuplot_contours * cntr));
                     91: static void cntr3d_points __PROTO((struct gnuplot_contours * cntr,
                     92:                                   struct surface_points * plot));
                     93: static void cntr3d_dots __PROTO((struct gnuplot_contours * cntr));
                     94: static void check_corner_height __PROTO((struct coordinate GPHUGE * point,
                     95:                                         double height[2][2], double depth[2][2]));
                     96: static void draw_bottom_grid __PROTO((struct surface_points * plot,
                     97:                                      int plot_count));
                     98: static void xtick_callback __PROTO((int axis, double place, char *text,
                     99:                                    struct lp_style_type grid));
                    100: static void ytick_callback __PROTO((int axis, double place, char *text,
                    101:                                    struct lp_style_type grid));
                    102: static void ztick_callback __PROTO((int axis, double place, char *text,
                    103:                                    struct lp_style_type grid));
                    104: static void setlinestyle __PROTO((struct lp_style_type style));
                    105:
                    106: static void boundary3d __PROTO((int scaling, struct surface_points * plots,
                    107:                                int count));
                    108: #if 0                          /* not used */
                    109: static double dbl_raise __PROTO((double x, int y));
                    110: #endif
                    111: static void map_position __PROTO((struct position * pos, unsigned int *x,
                    112:                                  unsigned int *y, char *what));
                    113:
                    114: /* put entries in the key */
                    115: static void key_sample_line __PROTO((int xl, int yl));
                    116: static void key_sample_point __PROTO((int xl, int yl, int pointtype));
                    117: static void key_text __PROTO((int xl, int yl, char *text));
                    118:
                    119:
                    120: #if defined(sun386) || defined(AMIGA_SC_6_1)
                    121: static double CheckLog __PROTO((TBOOLEAN is_log, double base_log, double x));
                    122: #endif
                    123:
                    124: /*
                    125:  * The Amiga SAS/C 6.2 compiler moans about macro envocations causing
                    126:  * multiple calls to functions. I converted these macros to inline
                    127:  * functions coping with the problem without loosing speed.
                    128:  * (MGR, 1993)
                    129:  */
                    130: #ifdef AMIGA_SC_6_1
                    131: GP_INLINE static TBOOLEAN i_inrange(int z, int min, int max)
                    132: {
                    133:     return ((min < max) ? ((z >= min) && (z <= max)) : ((z >= max) && (z <= min)));
                    134: }
                    135:
                    136: GP_INLINE static double f_max(double a, double b)
                    137: {
                    138:     return (max(a, b));
                    139: }
                    140:
                    141: GP_INLINE static double f_min(double a, double b)
                    142: {
                    143:     return (min(a, b));
                    144: }
                    145:
                    146: #else
                    147: # define f_max(a,b) GPMAX((a),(b))
                    148: # define f_min(a,b) GPMIN((a),(b))
                    149: # define i_inrange(z,a,b) inrange((z),(a),(b))
                    150: #endif
                    151:
                    152: #define apx_eq(x,y) (fabs(x-y) < 0.001)
                    153: #define ABS(x) ((x) >= 0 ? (x) : -(x))
                    154: #define SQR(x) ((x) * (x))
                    155:
                    156: /* Define the boundary of the plot
                    157:  * These are computed at each call to do_plot, and are constant over
                    158:  * the period of one do_plot. They actually only change when the term
                    159:  * type changes and when the 'set size' factors change.
                    160:  */
                    161:
                    162: /* in order to allow graphic.c to use clip_draw_line, we must
                    163:  * share xleft, xright, ybot, ytop with graphics.c
                    164:  */
                    165: extern int xleft, xright, ybot, ytop;
                    166:
                    167: int xmiddle, ymiddle, xscaler, yscaler;
                    168: static int ptitl_cnt;
                    169: static int max_ptitl_len;
                    170: static int titlelin;
                    171: static int key_sample_width, key_rows, key_cols, key_col_wth, yl_ref;
                    172: static int ktitle_lines = 0;
                    173:
                    174:
                    175: /* Boundary and scale factors, in user coordinates */
                    176: /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
                    177:  * file and are not the same as variables of the same names in other files
                    178:  */
                    179: /*static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d; */
                    180: /* sizes are now set in min_array[], max_array[] from plot.c */
                    181: extern double min_array[], max_array[];
                    182: extern int auto_array[], log_array[];
                    183: extern double base_array[], log_base_array[];
                    184:
                    185: /* for convenience while converting to use these arrays */
                    186: #define x_min3d min_array[FIRST_X_AXIS]
                    187: #define x_max3d max_array[FIRST_X_AXIS]
                    188: #define y_min3d min_array[FIRST_Y_AXIS]
                    189: #define y_max3d max_array[FIRST_Y_AXIS]
                    190: #define z_min3d min_array[FIRST_Z_AXIS]
                    191: #define z_max3d max_array[FIRST_Z_AXIS]
                    192:
                    193: /* There are several z's to take into account - I hope I get these
                    194:  * right !
                    195:  *
                    196:  * ceiling_z is the highest z in use
                    197:  * floor_z   is the lowest z in use
                    198:  * base_z is the z of the base
                    199:  * min3d_z is the lowest z of the graph area
                    200:  * max3d_z is the highest z of the graph area
                    201:  *
                    202:  * ceiling_z is either max3d_z or base_z, and similarly for floor_z
                    203:  * There should be no part of graph drawn outside
                    204:  * min3d_z:max3d_z  - apart from arrows, perhaps
                    205:  */
                    206:
                    207: double ceiling_z, floor_z, base_z;
                    208:
                    209: /* and some bodges while making the change */
                    210: #define min3d_z min_array[FIRST_Z_AXIS]
                    211: #define max3d_z max_array[FIRST_Z_AXIS]
                    212:
                    213:
                    214: double xscale3d, yscale3d, zscale3d;
                    215:
                    216:
                    217: typedef double transform_matrix[4][4];
                    218: transform_matrix trans_mat;
                    219:
                    220: static double xaxis_y, yaxis_x, zaxis_x, zaxis_y;
                    221:
                    222: /* the co-ordinates of the back corner */
                    223: static double back_x, back_y;
                    224:
                    225: /* the penalty for convenience of using tic_gen to make callbacks
                    226:  * to tick routines is that we cant pass parameters very easily.
                    227:  * We communicate with the tick_callbacks using static variables
                    228:  */
                    229:
                    230: /* unit vector (terminal coords) */
                    231: static double tic_unitx, tic_unity;
                    232:
                    233: /* (DFK) Watch for cancellation error near zero on axes labels */
                    234: #define SIGNIF (0.01)          /* less than one hundredth of a tic mark */
                    235: #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
                    236: #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
                    237:
                    238: /* And the functions to map from user to terminal coordinates */
                    239: #define map_x(x) (int)(x+0.5)  /* maps floating point x to screen */
                    240: #define map_y(y) (int)(y+0.5)  /* same for y */
                    241:
                    242: /* And the functions to map from user 3D space into normalized -1..1 */
                    243: #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
                    244: #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
                    245: #define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
                    246:
                    247:
                    248:
                    249: /* Initialize the line style using the current device and set hidden styles
                    250:  * to it as well if hidden line removal is enabled */
                    251: static void setlinestyle(style)
                    252: struct lp_style_type style;
                    253: {
                    254:     term_apply_lp_properties(&style);
                    255:
                    256: #ifndef LITE
                    257:     if (hidden3d) {
                    258:        hidden_line_type_above = style.l_type;
                    259:        hidden_line_type_below = style.l_type;
                    260:     }
                    261: #endif /* LITE */
                    262: }
                    263:
                    264: /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog
                    265:  * macro, so I write it as a function on that machine.
                    266:  *
                    267:  * Amiga SAS/C 6.2 thinks it will do too much work calling functions in
                    268:  * macro arguments twice, thus I inline theese functions. (MGR, 1993)
                    269:  */
                    270: #if defined(sun386) || defined(AMIGA_SC_6_1)
                    271: GP_INLINE static double CheckLog(is_log, base_log, x)
                    272: TBOOLEAN is_log;
                    273: double base_log;
                    274: double x;
                    275: {
                    276:     if (is_log)
                    277:        return (pow(base_log, x));
                    278:     else
                    279:        return (x);
                    280: }
                    281: #else
                    282: /* (DFK) Use 10^x if logscale is in effect, else x */
                    283: # define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
                    284: #endif /* sun386 || SAS/C */
                    285:
                    286: static double LogScale(coord, is_log, log_base_log, what, axis)
                    287: double coord;                  /* the value */
                    288: TBOOLEAN is_log;               /* is this axis in logscale? */
                    289: double log_base_log;           /* if so, the log of its base */
                    290: char *what;                    /* what is the coord for? */
                    291: char *axis;                    /* which axis is this for ("x" or "y")? */
                    292: {
                    293:     if (is_log) {
                    294:        if (coord <= 0.0) {
                    295:            char errbuf[100];   /* place to write error message */
                    296:            (void) sprintf(errbuf, "%s has %s coord of %g; must be above 0 for log scale!",
                    297:                           what, axis, coord);
                    298:            graph_error(errbuf);
                    299:        } else
                    300:            return (log(coord) / log_base_log);
                    301:     }
                    302:     return (coord);
                    303: }
                    304:
                    305: /* And the functions to map from user 3D space to terminal coordinates */
                    306: void map3d_xy(x, y, z, xt, yt)
                    307: double x, y, z;
                    308: unsigned int *xt, *yt;
                    309: {
                    310:     int i, j;
                    311:     double v[4], res[4], /* Homogeneous coords. vectors. */
                    312:        w = trans_mat[3][3];
                    313:
                    314:     v[0] = map_x3d(x);         /* Normalize object space to -1..1 */
                    315:     v[1] = map_y3d(y);
                    316:     v[2] = map_z3d(z);
                    317:     v[3] = 1.0;
                    318:
                    319:     for (i = 0; i < 2; i++) {  /* Dont use the third axes (z). */
                    320:        res[i] = trans_mat[3][i];       /* Initiate it with the weight factor */
                    321:        for (j = 0; j < 3; j++)
                    322:            res[i] += v[j] * trans_mat[j][i];
                    323:     }
                    324:
                    325:     for (i = 0; i < 3; i++)
                    326:        w += v[i] * trans_mat[i][3];
                    327:     if (w == 0)
                    328:        w = 1e-5;
                    329:
                    330:     *xt = (unsigned int) ((res[0] * xscaler / w) + xmiddle);
                    331:     *yt = (unsigned int) ((res[1] * yscaler / w) + ymiddle);
                    332: }
                    333:
                    334:
                    335:
                    336: /* And the functions to map from user 3D space to terminal z coordinate */
                    337: int map3d_z(x, y, z)
                    338: double x, y, z;
                    339: {
                    340:     int i, zt;
                    341:     double v[4], res, /* Homogeneous coords. vectors. */
                    342:        w = trans_mat[3][3];
                    343:
                    344:     v[0] = map_x3d(x);         /* Normalize object space to -1..1 */
                    345:     v[1] = map_y3d(y);
                    346:     v[2] = map_z3d(z);
                    347:     v[3] = 1.0;
                    348:
                    349:     res = trans_mat[3][2];     /* Initiate it with the weight factor. */
                    350:     for (i = 0; i < 3; i++)
                    351:        res += v[i] * trans_mat[i][2];
                    352:     if (w == 0)
                    353:        w = 1e-5;
                    354:     for (i = 0; i < 3; i++)
                    355:        w += v[i] * trans_mat[i][3];
                    356:     zt = ((int) (res * 16384 / w));
                    357:     return zt;
                    358: }
                    359:
                    360: /* borders of plotting area */
                    361: /* computed once on every call to do_plot */
                    362: static void boundary3d(scaling, plots, count)
                    363: TBOOLEAN scaling;              /* TRUE if terminal is doing the scaling */
                    364: struct surface_points *plots;
                    365: int count;
                    366: {
                    367:     register struct termentry *t = term;
                    368:     int ytlen, i;
                    369:
                    370:     titlelin = 0;
                    371:
                    372:     p_height = pointsize * t->v_tic;
                    373:     p_width = pointsize * t->h_tic;
                    374:     if (key_swidth >= 0)
                    375:        key_sample_width = key_swidth * (t->h_char) + pointsize * (t->h_tic);
                    376:     else
                    377:        key_sample_width = 0;
                    378:     key_entry_height = pointsize * (t->v_tic) * 1.25 * key_vert_factor;
                    379:     if (key_entry_height < (t->v_char)) {
                    380:        /* is this reasonable ? */
                    381:        key_entry_height = (t->v_char) * key_vert_factor;
                    382:     }
                    383:
                    384:     /* count max_len key and number keys (plot-titles and contour labels) with len > 0 */
                    385:     max_ptitl_len = find_maxl_keys3d(plots, count, &ptitl_cnt);
                    386:     if ((ytlen = label_width(key_title, &ktitle_lines)) > max_ptitl_len)
                    387:        max_ptitl_len = ytlen;
                    388:     key_col_wth = (max_ptitl_len + 4) * (t->h_char) + key_sample_width;
                    389:
                    390:     /* luecken@udel.edu modifications
                    391:        sizes the plot to take up more of available resolution */
                    392:     if (lmargin >= 0)
                    393:        xleft = (t->h_char) * lmargin;
                    394:     else
                    395:        xleft = (t->h_char) * 2 + (t->h_tic);
                    396:     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char) * 2 - (t->h_tic);
                    397:     key_rows = ptitl_cnt;
                    398:     key_cols = 1;
                    399:     if (key == -1 && key_vpos == TUNDER) {
                    400:        /* calculate max no cols, limited by label-length */
                    401:        key_cols = (int) (xright - xleft) / ((max_ptitl_len + 4) * (t->h_char) + key_sample_width);
                    402:        key_rows = (int) (ptitl_cnt / key_cols) + ((ptitl_cnt % key_cols) > 0);
                    403:        /* now calculate actual no cols depending on no rows */
                    404:        key_cols = (int) (ptitl_cnt / key_rows) + ((ptitl_cnt % key_rows) > 0);
                    405:        key_col_wth = (int) (xright - xleft) / key_cols;
                    406:        /* key_rows += ktitle_lines; - messes up key - div */
                    407:     }
                    408:     /* this should also consider the view and number of lines in
                    409:      * xformat || yformat || xlabel || ylabel */
                    410:
                    411:     /* an absolute 1, with no terminal-dependent scaling ? */
                    412:     ybot = (t->v_char) * 2.5 + 1;
                    413:     if (key_rows && key_vpos == TUNDER)
                    414:        ybot += key_rows * key_entry_height + ktitle_lines * t->v_char;
                    415:
                    416:     if (strlen(title.text)) {
                    417:        titlelin++;
                    418:        for (i = 0; i < strlen(title.text); i++) {
                    419:            if (title.text[i] == '\\')
                    420:                titlelin++;
                    421:        }
                    422:     }
                    423:     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char) * (titlelin + 1.5) - 1;
                    424:     if (key == -1 && key_vpos != TUNDER) {
                    425:        /* calculate max no rows, limited be ytop-ybot */
                    426:        i = (int) (ytop - ybot) / (t->v_char) - 1 - ktitle_lines;
                    427:        if (ptitl_cnt > i) {
                    428:            key_cols = (int) (ptitl_cnt / i) + ((ptitl_cnt % i) > 0);
                    429:            /* now calculate actual no rows depending on no cols */
                    430:            key_rows = (int) (ptitl_cnt / key_cols) + ((ptitl_cnt % key_cols) > 0);
                    431:        }
                    432:        key_rows += ktitle_lines;
                    433:     }
                    434:     if (key_hpos == TOUT) {
                    435:        xright -= key_col_wth * (key_cols - 1) + key_col_wth - 2 * (t->h_char);
                    436:     }
                    437:     xleft += t->xmax * xoffset;
                    438:     xright += t->xmax * xoffset;
                    439:     ytop += t->ymax * yoffset;
                    440:     ybot += t->ymax * yoffset;
                    441:     xmiddle = (xright + xleft) / 2;
                    442:     ymiddle = (ytop + ybot) / 2;
                    443:     /* HBB 980308: sigh... another 16bit glitch: on term's with more than
                    444:      * 8000 pixels in either direction, these calculations produce garbage
                    445:      * results if done in (16bit) ints */
                    446:     xscaler = (xright - xleft) * 4 / 7;                /* HBB: Magic number alert! */
                    447:     yscaler = ((ytop - ybot) * 4L) / 7L;
                    448:
                    449: }
                    450:
                    451: #if 0
                    452: /* not used ; anyway, should be done using bitshifts and squares,
                    453:  * rather than iteratively
                    454:  */
                    455: static double dbl_raise(x, y)
                    456: double x;
                    457: int y;
                    458: {
                    459:     register int i = ABS(y);
                    460:     double val = 1.0;
                    461:     while (--i >= 0)
                    462:        val *= x;
                    463:     if (y < 0)
                    464:        return (1.0 / val);
                    465:     return (val);
                    466: }
                    467: #endif
                    468:
                    469: /* we precalculate features of the key, to save lots of nested
                    470:  * ifs in code - x,y = user supplied or computed position of key
                    471:  * taken to be inner edge of a line sample
                    472:  */
                    473: static int key_sample_left;    /* offset from x for left of line sample */
                    474: static int key_sample_right;   /* offset from x for right of line sample */
                    475: static int key_point_offset;   /* offset from x for point sample */
                    476: static int key_text_left;      /* offset from x for left-justified text */
                    477: static int key_text_right;     /* offset from x for right-justified text */
                    478: static int key_size_left;      /* distance from x to left edge of box */
                    479: static int key_size_right;     /* distance from x to right edge of box */
                    480:
                    481: void do_3dplot(plots, pcount)
                    482: struct surface_points *plots;
                    483: int pcount;                    /* count of plots in linked list */
                    484: {
                    485:     struct termentry *t = term;
                    486:     int surface;
                    487:     struct surface_points *this_plot = NULL;
                    488:     unsigned int xl, yl;
                    489:     int linetypeOffset = 0;
                    490:     double ztemp, temp;
                    491:     struct text_label *this_label;
                    492:     struct arrow_def *this_arrow;
                    493:     TBOOLEAN scaling;
                    494:     transform_matrix mat;
                    495:     int key_count;
                    496:     char ss[MAX_LINE_LEN+1], *s, *e;
                    497:
                    498:     /* Initiate transformation matrix using the global view variables. */
                    499:     mat_rot_z(surface_rot_z, trans_mat);
                    500:     mat_rot_x(surface_rot_x, mat);
                    501:     mat_mult(trans_mat, trans_mat, mat);
                    502:     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
                    503:     mat_mult(trans_mat, trans_mat, mat);
                    504:
                    505:     /* modify min_z/max_z so it will zscale properly. */
                    506:     ztemp = (z_max3d - z_min3d) / (2.0 * surface_zscale);
                    507:     temp = (z_max3d + z_min3d) / 2.0;
                    508:     z_min3d = temp - ztemp;
                    509:     z_max3d = temp + ztemp;
                    510:
                    511:
                    512:     /* The extrema need to be set even when a surface is not being
                    513:      * drawn.   Without this, gnuplot used to assume that the X and
                    514:      * Y axis started at zero.   -RKC
                    515:      */
                    516:
                    517:     if (polar)
                    518:        graph_error("Cannot splot in polar coordinate system.");
                    519:
                    520:     /* done in plot3d.c
                    521:      *    if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
                    522:      *      x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
                    523:      *      y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
                    524:      *      graph_error("all points undefined!");
                    525:      */
                    526:
                    527:     /* If we are to draw the bottom grid make sure zmin is updated properly. */
                    528:     if (xtics || ytics || work_grid.l_type) {
                    529:        base_z = z_min3d - (z_max3d - z_min3d) * ticslevel;
                    530:        if (ticslevel >= 0)
                    531:            floor_z = base_z;
                    532:        else
                    533:            floor_z = z_min3d;
                    534:
                    535:        if (ticslevel < -1)
                    536:            ceiling_z = base_z;
                    537:        else
                    538:            ceiling_z = z_max3d;
                    539:     } else {
                    540:        floor_z = base_z = z_min3d;
                    541:        ceiling_z = z_max3d;
                    542:     }
                    543:
                    544:     /*  see comment accompanying similar tests of x_min/x_max and y_min/y_max
                    545:      *  in graphics.c:do_plot(), for history/rationale of these tests */
                    546:     if (x_min3d == x_max3d)
                    547:        graph_error("x_min3d should not equal x_max3d!");
                    548:     if (y_min3d == y_max3d)
                    549:        graph_error("y_min3d should not equal y_max3d!");
                    550:     if (z_min3d == z_max3d)
                    551:        graph_error("z_min3d should not equal z_max3d!");
                    552:
                    553: #ifndef LITE
                    554:     if (hidden3d) {
                    555:        struct surface_points *plot;
                    556:        int p = 0;
                    557:        /* Verify data is hidden line removable - grid based. */
                    558:        for (plot = plots; ++p <= pcount; plot = plot->next_sp) {
                    559:            if (plot->plot_type == DATA3D && !plot->has_grid_topology) {
                    560:                fprintf(stderr, "Notice: Cannot remove hidden lines from non grid data\n");
                    561:                return;
                    562:            }
                    563:        }
                    564:     }
                    565: #endif /* not LITE */
                    566:
                    567:     term_start_plot();
                    568:
                    569:     screen_ok = FALSE;
                    570:     scaling = (*t->scale) (xsize, ysize);
                    571:
                    572:     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
                    573:     boundary3d(scaling, plots, pcount);
                    574:
                    575:     /* SCALE FACTORS */
                    576:     zscale3d = 2.0 / (ceiling_z - floor_z);
                    577:     yscale3d = 2.0 / (y_max3d - y_min3d);
                    578:     xscale3d = 2.0 / (x_max3d - x_min3d);
                    579:
                    580:     term_apply_lp_properties(&border_lp);      /* border linetype */
                    581:
                    582:     /* PLACE TITLE */
                    583:     if (*title.text != 0) {
                    584:        safe_strncpy(ss, title.text, sizeof(ss));
                    585:        write_multiline((unsigned int) ((xleft + xright) / 2 + title.xoffset * t->h_char),
                    586:                        (unsigned int) (ytop + (titlelin + title.yoffset) * (t->h_char)),
                    587:                        ss, CENTRE, JUST_TOP, 0, title.font);
                    588:     }
                    589:     /* PLACE TIMEDATE */
                    590:     if (*timelabel.text) {
                    591:        char str[MAX_LINE_LEN+1];
                    592:        time_t now;
                    593:        unsigned int x = t->v_char + timelabel.xoffset * t->h_char;
                    594:        unsigned int y = timelabel_bottom ?
                    595:        yoffset * ymax + (timelabel.yoffset + 1) * t->v_char :
                    596:        ytop + (timelabel.yoffset - 1) * t->v_char;
                    597:
                    598:        time(&now);
                    599:        strftime(str, MAX_LINE_LEN, timelabel.text, localtime(&now));
                    600:
                    601:        if (timelabel_rotate && (*t->text_angle) (1)) {
                    602:            if (timelabel_bottom)
                    603:                write_multiline(x, y, str, LEFT, JUST_TOP, 1, timelabel.font);
                    604:            else
                    605:                write_multiline(x, y, str, RIGHT, JUST_TOP, 1, timelabel.font);
                    606:
                    607:            (*t->text_angle) (0);
                    608:        } else {
                    609:            if (timelabel_bottom)
                    610:                write_multiline(x, y, str, LEFT, JUST_BOT, 0, timelabel.font);
                    611:            else
                    612:                write_multiline(x, y, str, LEFT, JUST_TOP, 0, timelabel.font);
                    613:        }
                    614:     }
                    615:     /* PLACE LABELS */
                    616:     for (this_label = first_label; this_label != NULL;
                    617:         this_label = this_label->next) {
                    618:        unsigned int x, y;
                    619:
                    620:
                    621:        map_position(&this_label->place, &x, &y, "label");
                    622:        safe_strncpy(ss, this_label->text, sizeof(ss));
                    623:        if (this_label->rotate && (*t->text_angle) (1)) {
                    624:            write_multiline(x, y, this_label->text, this_label->pos, CENTRE, 1, this_label->font);
                    625:            (*t->text_angle) (0);
                    626:        } else {
                    627:            write_multiline(x, y, this_label->text, this_label->pos, CENTRE, 0, this_label->font);
                    628:        }
                    629:     }
                    630:
                    631:     /* PLACE ARROWS */
                    632:     for (this_arrow = first_arrow; this_arrow != NULL;
                    633:         this_arrow = this_arrow->next) {
                    634:        unsigned int sx, sy, ex, ey;
                    635:
                    636:        map_position(&this_arrow->start, &sx, &sy, "arrow");
                    637:        map_position(&this_arrow->end, &ex, &ey, "arrow");
                    638:        term_apply_lp_properties(&(this_arrow->lp_properties));
                    639:        (*t->arrow) (sx, sy, ex, ey, this_arrow->head);
                    640:     }
                    641:
                    642: #ifndef LITE
                    643:     if (hidden3d && draw_surface) {
                    644:        init_hidden_line_removal();
                    645:        reset_hidden_line_removal();
                    646:        hidden_active = TRUE;
                    647:     }
                    648: #endif /* not LITE */
                    649:
                    650:     /* WORK OUT KEY SETTINGS AND DO KEY TITLE / BOX */
                    651:
                    652:     if (key_reverse) {
                    653:        key_sample_left = -key_sample_width;
                    654:        key_sample_right = 0;
                    655:        key_text_left = t->h_char;
                    656:        key_text_right = (t->h_char) * (max_ptitl_len + 1);
                    657:        key_size_right = (t->h_char) * (max_ptitl_len + 2 + key_width_fix);
                    658:        key_size_left = (t->h_char) + key_sample_width;
                    659:     } else {
                    660:        key_sample_left = 0;
                    661:        key_sample_right = key_sample_width;
                    662:        key_text_left = -(int) ((t->h_char) * (max_ptitl_len + 1));
                    663:        key_text_right = -(int) (t->h_char);
                    664:        key_size_left = (t->h_char) * (max_ptitl_len + 2 + key_width_fix);
                    665:        key_size_right = (t->h_char) + key_sample_width;
                    666:     }
                    667:     key_point_offset = (key_sample_left + key_sample_right) / 2;
                    668:
                    669:     if (key == -1) {
                    670:        if (key_vpos == TUNDER) {
                    671: #if 0
                    672:            yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines + 2) * t->v_char;
                    673:            xl = max_ptitl_len * 1000 / (key_sample_width / (t->h_char) + max_ptitl_len + 2);
                    674:            xl *= (xright - xleft) / key_cols;
                    675:            xl /= 1000;
                    676:            xl += xleft;
                    677: #else
                    678:            /* maximise no cols, limited by label-length */
                    679:            key_cols = (int) (xright - xleft) / key_col_wth;
                    680:            key_rows = (int) (ptitl_cnt + key_cols - 1) / key_cols;
                    681:            /* now calculate actual no cols depending on no rows */
                    682:            key_cols = (int) (ptitl_cnt + key_rows - 1) / key_rows;
                    683:            key_col_wth = (int) (xright - xleft) / key_cols;
                    684:            /* we divide into columns, then centre in column by considering
                    685:             * ratio of key_left_size to key_right_size
                    686:             * key_size_left/(key_size_left+key_size_right) * (xright-xleft)/key_cols
                    687:             * do one integer division to maximise accuracy (hope we dont
                    688:             * overflow !)
                    689:             */
                    690:            xl = xleft + ((xright - xleft) * key_size_left) / (key_cols * (key_size_left + key_size_right));
                    691:            yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines + 2) * t->v_char;
                    692: #endif
                    693:        } else {
                    694:            if (key_vpos == TTOP) {
                    695:                yl = ytop - (t->v_tic) - t->v_char;
                    696:            } else {
                    697:                yl = ybot + (t->v_tic) + key_entry_height * key_rows + ktitle_lines * t->v_char;
                    698:            }
                    699:            if (key_hpos == TOUT) {
                    700:                /* keys outside plot border (right) */
                    701:                xl = xright + (t->h_tic) + key_size_left;
                    702:            } else if (key_hpos == TLEFT) {
                    703:                xl = xleft + (t->h_tic) + key_size_left;
                    704:            } else {
                    705:                xl = xright - key_size_right - key_col_wth * (key_cols - 1);
                    706:            }
                    707:        }
                    708:        yl_ref = yl - ktitle_lines * (t->v_char);
                    709:     }
                    710:     if (key == 1) {
                    711:        map_position(&key_user_pos, &xl, &yl, "key");
                    712:     }
                    713:     if (key && key_box.l_type > -3) {
                    714:        int yt = yl;
                    715:        int yb = yl - key_entry_height * (key_rows - ktitle_lines) - ktitle_lines * t->v_char;
                    716:        int key_xr = xl + key_col_wth * (key_cols - 1) + key_size_right;
                    717:        /* key_rows seems to contain title at this point ??? */
                    718:        term_apply_lp_properties(&key_box);
                    719:        (*t->move) (xl - key_size_left, yb);
                    720:        (*t->vector) (xl - key_size_left, yt);
                    721:        (*t->vector) (key_xr, yt);
                    722:        (*t->vector) (key_xr, yb);
                    723:        (*t->vector) (xl - key_size_left, yb);
                    724:
                    725:        /* draw a horizontal line between key title and first entry  JFi */
                    726:        (*t->move) (xl - key_size_left, yt - (ktitle_lines) * t->v_char);
                    727:        (*t->vector) (xl + key_size_right, yt - (ktitle_lines) * t->v_char);
                    728:     }
                    729:     /* DRAW SURFACES AND CONTOURS */
                    730:
                    731: #ifndef LITE
                    732:     if (hidden3d && draw_surface)
                    733:        plot3d_hidden(plots, pcount);
                    734: #endif /* not LITE */
                    735:
                    736:     /* KEY TITLE */
                    737:     if (key != 0 && strlen(key_title)) {
                    738:        sprintf(ss, "%s\n", key_title);
                    739:        s = ss;
                    740:        yl -= t->v_char / 2;
                    741:        while ((e = (char *) strchr(s, '\n')) != NULL) {
                    742:            *e = '\0';
                    743:            if (key_just == JLEFT) {
                    744:                (*t->justify_text) (LEFT);
                    745:                (*t->put_text) (xl + key_text_left, yl, s);
                    746:            } else {
                    747:                if ((*t->justify_text) (RIGHT)) {
                    748:                    (*t->put_text) (xl + key_text_right,
                    749:                                    yl, s);
                    750:                } else {
                    751:                    int x = xl + key_text_right - (t->h_char) * strlen(s);
                    752:                    if (inrange(x, xleft, xright))
                    753:                        (*t->put_text) (x, yl, s);
                    754:                }
                    755:            }
                    756:            s = ++e;
                    757:            yl -= t->v_char;
                    758:        }
                    759:        yl += t->v_char / 2;
                    760:     }
                    761:     key_count = 0;
                    762:     yl_ref = yl -= key_entry_height / 2;       /* centralise the keys */
                    763:
                    764: #define NEXT_KEY_LINE() \
                    765:  if ( ++key_count >= key_rows ) { \
                    766:    yl = yl_ref; xl += key_col_wth; key_count = 0; \
                    767:  } else \
                    768:    yl -= key_entry_height
                    769:
                    770:     this_plot = plots;
                    771:     for (surface = 0;
                    772:         surface < pcount;
                    773:         this_plot = this_plot->next_sp, surface++) {
                    774:
                    775: #ifndef LITE
                    776:        if (hidden3d)
                    777:            hidden_no_update = FALSE;
                    778: #endif /* not LITE */
                    779:
                    780:        if (draw_surface) {
                    781:            int lkey = (key != 0 && this_plot->title && this_plot->title[0]);
                    782:            term_apply_lp_properties(&(this_plot->lp_properties));
                    783:
                    784: #ifndef LITE
                    785:            if (hidden3d) {
                    786:                hidden_line_type_above = this_plot->lp_properties.l_type;
                    787:                hidden_line_type_below = this_plot->lp_properties.l_type + 1;
                    788:            }
                    789: #endif /* not LITE */
                    790:
                    791:            if (lkey) {
                    792:                key_text(xl, yl, this_plot->title);
                    793:            }
                    794:            switch (this_plot->plot_style) {
                    795:            case BOXES: /* can't do boxes in 3d yet so use impulses */
                    796:            case IMPULSES:{
                    797:                    if (lkey) {
                    798:                        key_sample_line(xl, yl);
                    799:                    }
                    800:                    if (!(hidden3d && draw_surface))
                    801:                        plot3d_impulses(this_plot);
                    802:                    break;
                    803:                }
                    804:            case STEPS: /* HBB: I think these should be here */
                    805:            case FSTEPS:
                    806:            case HISTEPS:
                    807:            case LINES:{
                    808:                    if (lkey) {
                    809:                        key_sample_line(xl, yl);
                    810:                    }
                    811:                    if (!(hidden3d && draw_surface))
                    812:                        plot3d_lines(this_plot);
                    813:                    break;
                    814:                }
                    815:            case YERRORBARS:    /* ignored; treat like points */
                    816:            case XERRORBARS:    /* ignored; treat like points */
                    817:            case XYERRORBARS:   /* ignored; treat like points */
                    818:            case BOXXYERROR:    /* HBB: ignore these as well */
                    819:            case BOXERROR:
                    820:            case CANDLESTICKS:  /* HBB: dito */
                    821:            case FINANCEBARS:
                    822:            case VECTOR:
                    823:            case POINTSTYLE:
                    824:                if (lkey && !clip_point(xl + key_point_offset, yl)) {
                    825:                    key_sample_point(xl, yl, this_plot->lp_properties.p_type);
                    826:                }
                    827:                if (!(hidden3d && draw_surface))
                    828:                    plot3d_points(this_plot);
                    829:                break;
                    830:
                    831:            case LINESPOINTS:
                    832:                /* put lines */
                    833:                if (lkey)
                    834:                    key_sample_line(xl, yl);
                    835:
                    836:                if (!(hidden3d && draw_surface))
                    837:                    plot3d_lines(this_plot);
                    838:
                    839:                /* put points */
                    840:                if (lkey && !clip_point(xl + key_point_offset, yl))
                    841:                    key_sample_point(xl, yl, this_plot->lp_properties.p_type);
                    842:
                    843:                if (!(hidden3d && draw_surface))
                    844:                    plot3d_points(this_plot);
                    845:
                    846:                break;
                    847:
                    848:            case DOTS:
                    849:                if (lkey) {
                    850:                    if (key == 1) {
                    851:                        if (!clip_point(xl + key_point_offset, yl))
                    852:                            (*t->point) (xl + key_point_offset, yl, -1);
                    853:                    } else {
                    854:                        (*t->point) (xl + key_point_offset, yl, -1);
                    855:                        /* (*t->point)(xl+2*(t->h_char),yl, -1); */
                    856:                    }
                    857:                }
                    858:                if (!(hidden3d && draw_surface))
                    859:                    plot3d_dots(this_plot);
                    860:
                    861:                break;
                    862:
                    863:
                    864:            }                   /* switch(plot-style) */
                    865:
                    866:            /* move key on a line */
                    867:            if (lkey) {
                    868:                NEXT_KEY_LINE();
                    869:            }
                    870:        }                       /* draw_surface */
                    871:
                    872: #ifndef LITE
                    873:        if (hidden3d) {
                    874:            hidden_no_update = TRUE;
                    875:            hidden_line_type_above = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
                    876:            hidden_line_type_below = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
                    877:        }
                    878: #endif /* not LITE */
                    879:
                    880:        if (draw_contour && this_plot->contours != NULL) {
                    881:            struct gnuplot_contours *cntrs = this_plot->contours;
                    882:
                    883:            term_apply_lp_properties(&(this_plot->lp_properties));
                    884:            (*t->linetype) (this_plot->lp_properties.l_type + (hidden3d ? 2 : 1));
                    885:
                    886:            if (key != 0 && this_plot->title && this_plot->title[0]
                    887:                && !draw_surface && !label_contours) {
                    888:                /* unlabelled contours but no surface : put key entry in now */
                    889:                key_text(xl, yl, this_plot->title);
                    890:
                    891:                switch (this_plot->plot_style) {
                    892:                case IMPULSES:
                    893:                case LINES:
                    894:                case BOXES:     /* HBB: I think these should be here... */
                    895:                case STEPS:
                    896:                case FSTEPS:
                    897:                case HISTEPS:
                    898:                    key_sample_line(xl, yl);
                    899:                    break;
                    900:                case YERRORBARS:        /* ignored; treat like points */
                    901:                case XERRORBARS:        /* ignored; treat like points */
                    902:                case XYERRORBARS:       /* ignored; treat like points */
                    903:                case BOXERROR:  /* HBB: ignore these as well */
                    904:                case BOXXYERROR:
                    905:                case CANDLESTICKS:      /* HBB: dito */
                    906:                case FINANCEBARS:
                    907:                case VECTOR:
                    908:                case POINTSTYLE:
                    909:                    key_sample_point(xl, yl, this_plot->lp_properties.p_type);
                    910:                    break;
                    911:                case LINESPOINTS:
                    912:                    key_sample_line(xl, yl);
                    913:                    break;
                    914:                case DOTS:
                    915:                    key_sample_point(xl, yl, -1);
                    916:                    break;
                    917:                }
                    918:                NEXT_KEY_LINE();
                    919:            }
                    920:            linetypeOffset = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
                    921:            while (cntrs) {
                    922:                if (label_contours && cntrs->isNewLevel) {
                    923:                    (*t->linetype) (linetypeOffset++);
                    924:                    if (key) {
                    925:
                    926: #ifndef LITE
                    927:                        if (hidden3d)
                    928:                            hidden_line_type_below = hidden_line_type_above = linetypeOffset - 1;
                    929: #endif /* not LITE */
                    930:
                    931:                        key_text(xl, yl, cntrs->label);
                    932:
                    933:                        switch (this_plot->plot_style) {
                    934:                        case IMPULSES:
                    935:                        case LINES:
                    936:                        case LINESPOINTS:
                    937:                        case BOXES:     /* HBB: these should be treated as well... */
                    938:                        case STEPS:
                    939:                        case FSTEPS:
                    940:                        case HISTEPS:
                    941:                            key_sample_line(xl, yl);
                    942:                            break;
                    943:                        case YERRORBARS:        /* ignored; treat like points */
                    944:                        case XERRORBARS:        /* ignored; treat like points */
                    945:                        case XYERRORBARS:       /* ignored; treat like points */
                    946:                        case BOXERROR:          /* HBB: treat these likewise */
                    947:                        case BOXXYERROR:
                    948:                        case CANDLESTICKS:      /* HBB: dito */
                    949:                        case FINANCEBARS:
                    950:                        case VECTOR:
                    951:                        case POINTSTYLE:
                    952:                            key_sample_point(xl, yl, this_plot->lp_properties.p_type);
                    953:                            break;
                    954:                        case DOTS:
                    955:                            key_sample_point(xl, yl, -1);
                    956:                            break;
                    957:                        }       /* switch */
                    958:
                    959:                        NEXT_KEY_LINE();
                    960:
                    961:                    }           /* key */
                    962:                }               /* label_contours */
                    963:                /* now draw the contour */
                    964:                switch (this_plot->plot_style) {
                    965:                case IMPULSES:
                    966:                case BOXES:     /* HBB: this should also be treated somehow */
                    967:                    cntr3d_impulses(cntrs, this_plot);
                    968:                    break;
                    969:                case LINES:
                    970:                case STEPS:     /* HBB: these should also be handled, I think */
                    971:                case FSTEPS:
                    972:                case HISTEPS:
                    973:                    cntr3d_lines(cntrs);
                    974:                    break;
                    975:                case YERRORBARS:        /* ignored; treat like points */
                    976:                case XERRORBARS:        /* ignored; treat like points */
                    977:                case XYERRORBARS:       /* ignored; treat like points */
                    978:                case BOXERROR:  /* HBB: ignore these too... */
                    979:                case BOXXYERROR:
                    980:                case CANDLESTICKS:      /* HBB: dito */
                    981:                case FINANCEBARS:
                    982:                case VECTOR:
                    983:                case POINTSTYLE:
                    984:                    cntr3d_points(cntrs, this_plot);
                    985:                    break;
                    986:                case LINESPOINTS:
                    987:                    cntr3d_lines(cntrs);
                    988:                    cntr3d_points(cntrs, this_plot);
                    989:                    break;
                    990:                case DOTS:
                    991:                    cntr3d_dots(cntrs);
                    992:                    break;
                    993:                }               /*switch */
                    994:
                    995:                cntrs = cntrs->next;
                    996:            }                   /* loop over contours */
                    997:        }                       /* draw contours */
                    998:     }                          /* loop over surfaces */
                    999:
                   1000:     draw_bottom_grid(plots, pcount);
                   1001:
                   1002:     term_end_plot();
                   1003:
                   1004: #ifndef LITE
                   1005:     if (hidden3d && draw_surface) {
                   1006:        term_hidden_line_removal();
                   1007:        hidden_active = FALSE;
                   1008:     }
                   1009: #endif /* not LITE */
                   1010:
                   1011: }
                   1012:
                   1013: /* plot3d_impulses:
                   1014:  * Plot the surfaces in IMPULSES style
                   1015:  */
                   1016: static void plot3d_impulses(plot)
                   1017: struct surface_points *plot;
                   1018: {
                   1019:     int i;                     /* point index */
                   1020:     unsigned int x, y, x0, y0; /* point in terminal coordinates */
                   1021:     struct iso_curve *icrvs = plot->iso_crvs;
                   1022:
                   1023:     while (icrvs) {
                   1024:        struct coordinate GPHUGE *points = icrvs->points;
                   1025:
                   1026:        for (i = 0; i < icrvs->p_count; i++) {
                   1027:            switch (points[i].type) {
                   1028:            case INRANGE:
                   1029:                {
                   1030:                    map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
                   1031:
                   1032:                    if (inrange(0.0, min3d_z, max3d_z)) {
                   1033:                        map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
                   1034:                    } else if (inrange(min3d_z, 0.0, points[i].z)) {
                   1035:                        map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
                   1036:                    } else {
                   1037:                        map3d_xy(points[i].x, points[i].y, max3d_z, &x0, &y0);
                   1038:                    }
                   1039:
                   1040:                    clip_move(x0, y0);
                   1041:                    clip_vector(x, y);
                   1042:
                   1043:                    break;
                   1044:                }
                   1045:            case OUTRANGE:
                   1046:                {
                   1047:                    if (!inrange(points[i].x, x_min3d, x_max3d) ||
                   1048:                        !inrange(points[i].y, y_min3d, y_max3d))
                   1049:                        break;
                   1050:
                   1051:                    if (inrange(0.0, min3d_z, max3d_z)) {
                   1052:                        /* zero point is INRANGE */
                   1053:                        map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
                   1054:
                   1055:                        /* must cross z = min3d_z or max3d_z limits */
                   1056:                        if (inrange(min3d_z, 0.0, points[i].z) &&
                   1057:                            min3d_z != 0.0 && min3d_z != points[i].z) {
                   1058:                            map3d_xy(points[i].x, points[i].y, min3d_z, &x, &y);
                   1059:                        } else {
                   1060:                            map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
                   1061:                        }
                   1062:                    } else {
                   1063:                        /* zero point is also OUTRANGE */
                   1064:                        if (inrange(min3d_z, 0.0, points[i].z) &&
                   1065:                            inrange(max3d_z, 0.0, points[i].z)) {
                   1066:                            /* crosses z = min3d_z or max3d_z limits */
                   1067:                            map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
                   1068:                            map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
                   1069:                        } else {
                   1070:                            /* doesn't cross z = min3d_z or max3d_z limits */
                   1071:                            break;
                   1072:                        }
                   1073:                    }
                   1074:
                   1075:                    clip_move(x0, y0);
                   1076:                    clip_vector(x, y);
                   1077:
                   1078:                    break;
                   1079:                }
                   1080:            default:            /* just a safety */
                   1081:            case UNDEFINED:{
                   1082:                    break;
                   1083:                }
                   1084:            }
                   1085:        }
                   1086:
                   1087:        icrvs = icrvs->next;
                   1088:     }
                   1089: }
                   1090:
                   1091: /* plot3d_lines:
                   1092:  * Plot the surfaces in LINES style
                   1093:  */
                   1094: /* We want to always draw the lines in the same direction, otherwise when
                   1095:    we draw an adjacent box we might get the line drawn a little differently
                   1096:    and we get splotches.  */
                   1097:
                   1098: static void plot3d_lines(plot)
                   1099: struct surface_points *plot;
                   1100: {
                   1101:     int i;
                   1102:     unsigned int x, y, x0, y0; /* point in terminal coordinates */
                   1103:     double clip_x, clip_y, clip_z;
                   1104:     struct iso_curve *icrvs = plot->iso_crvs;
                   1105:     struct coordinate GPHUGE *points;
                   1106:     enum coord_type prev = UNDEFINED;
                   1107:     double lx[2], ly[2], lz[2];        /* two edge points */
                   1108:
                   1109: #ifndef LITE
                   1110: /* These are handled elsewhere.  */
                   1111:     if (plot->has_grid_topology && hidden3d)
                   1112:        return;
                   1113: #endif /* not LITE */
                   1114:
                   1115:     while (icrvs) {
                   1116:        prev = UNDEFINED;       /* type of previous plot */
                   1117:
                   1118:        for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
                   1119:            switch (points[i].type) {
                   1120:            case INRANGE:{
                   1121:                    map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
                   1122:
                   1123:                    if (prev == INRANGE) {
                   1124:                        clip_vector(x, y);
                   1125:                    } else {
                   1126:                        if (prev == OUTRANGE) {
                   1127:                            /* from outrange to inrange */
                   1128:                            if (!clip_lines1) {
                   1129:                                clip_move(x, y);
                   1130:                            } else {
                   1131:                                /*
                   1132:                                 * Calculate intersection point and draw
                   1133:                                 * vector from there
                   1134:                                 */
                   1135:                                edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
                   1136:
                   1137:                                map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
                   1138:
                   1139:                                clip_move(x0, y0);
                   1140:                                clip_vector(x, y);
                   1141:                            }
                   1142:                        } else {
                   1143:                            clip_move(x, y);
                   1144:                        }
                   1145:                    }
                   1146:
                   1147:                    break;
                   1148:                }
                   1149:            case OUTRANGE:{
                   1150:                    if (prev == INRANGE) {
                   1151:                        /* from inrange to outrange */
                   1152:                        if (clip_lines1) {
                   1153:                            /*
                   1154:                             * Calculate intersection point and draw
                   1155:                             * vector to it
                   1156:                             */
                   1157:
                   1158:                            edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
                   1159:
                   1160:                            map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
                   1161:
                   1162:                            clip_vector(x0, y0);
                   1163:                        }
                   1164:                    } else if (prev == OUTRANGE) {
                   1165:                        /* from outrange to outrange */
                   1166:                        if (clip_lines2) {
                   1167:                            /*
                   1168:                             * Calculate the two 3D intersection points
                   1169:                             * if present
                   1170:                             */
                   1171:                            if (two_edge3d_intersect(points, i, lx, ly, lz)) {
                   1172:
                   1173:                                map3d_xy(lx[0], ly[0], lz[0], &x, &y);
                   1174:
                   1175:                                map3d_xy(lx[1], ly[1], lz[1], &x0, &y0);
                   1176:
                   1177:                                clip_move(x, y);
                   1178:                                clip_vector(x0, y0);
                   1179:                            }
                   1180:                        }
                   1181:                    }
                   1182:                    break;
                   1183:                }
                   1184:            case UNDEFINED:{
                   1185:                    break;
                   1186:            default:
                   1187:                    graph_error("Unknown point type in plot3d_lines");
                   1188:                }
                   1189:            }
                   1190:
                   1191:            prev = points[i].type;
                   1192:        }
                   1193:
                   1194:        icrvs = icrvs->next;
                   1195:     }
                   1196: }
                   1197:
                   1198: /* plot3d_points:
                   1199:  * Plot the surfaces in POINTSTYLE style
                   1200:  */
                   1201: static void plot3d_points(plot)
                   1202: struct surface_points *plot;
                   1203: {
                   1204:     int i;
                   1205:     unsigned int x, y;
                   1206:     struct termentry *t = term;
                   1207:     struct iso_curve *icrvs = plot->iso_crvs;
                   1208:
                   1209:     while (icrvs) {
                   1210:        struct coordinate GPHUGE *points = icrvs->points;
                   1211:
                   1212:        for (i = 0; i < icrvs->p_count; i++) {
                   1213:            if (points[i].type == INRANGE) {
                   1214:                map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
                   1215:
                   1216:                if (!clip_point(x, y))
                   1217:                    (*t->point) (x, y, plot->lp_properties.p_type);
                   1218:            }
                   1219:        }
                   1220:
                   1221:        icrvs = icrvs->next;
                   1222:     }
                   1223: }
                   1224:
                   1225: /* plot3d_dots:
                   1226:  * Plot the surfaces in DOTS style
                   1227:  */
                   1228: static void plot3d_dots(plot)
                   1229: struct surface_points *plot;
                   1230: {
                   1231:     int i;
                   1232:     struct termentry *t = term;
                   1233:     struct iso_curve *icrvs = plot->iso_crvs;
                   1234:
                   1235:     while (icrvs) {
                   1236:        struct coordinate GPHUGE *points = icrvs->points;
                   1237:
                   1238:        for (i = 0; i < icrvs->p_count; i++) {
                   1239:            if (points[i].type == INRANGE) {
                   1240:                unsigned int x, y;
                   1241:                map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
                   1242:
                   1243:                if (!clip_point(x, y))
                   1244:                    (*t->point) (x, y, -1);
                   1245:            }
                   1246:        }
                   1247:
                   1248:        icrvs = icrvs->next;
                   1249:     }
                   1250: }
                   1251:
                   1252: /* cntr3d_impulses:
                   1253:  * Plot a surface contour in IMPULSES style
                   1254:  */
                   1255: static void cntr3d_impulses(cntr, plot)
                   1256: struct gnuplot_contours *cntr;
                   1257: struct surface_points *plot;
                   1258: {
                   1259:     int i;                     /* point index */
                   1260:     unsigned int x, y, x0, y0; /* point in terminal coordinates */
                   1261:
                   1262:     if (draw_contour & CONTOUR_SRF) {
                   1263:        for (i = 0; i < cntr->num_pts; i++) {
                   1264:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
                   1265:                     &x, &y);
                   1266:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
                   1267:                     &x0, &y0);
                   1268:
                   1269:            clip_move(x0, y0);
                   1270:            clip_vector(x, y);
                   1271:        }
                   1272:     } else {
                   1273:        /* Must be on base grid, so do points. */
                   1274:        cntr3d_points(cntr, plot);
                   1275:     }
                   1276: }
                   1277:
                   1278: /* cntr3d_lines:
                   1279:  * Plot a surface contour in LINES style
                   1280:  */
                   1281: static void cntr3d_lines(cntr)
                   1282: struct gnuplot_contours *cntr;
                   1283: {
                   1284:     int i;                     /* point index */
                   1285:     unsigned int x, y;         /* point in terminal coordinates */
                   1286:
                   1287:     if (draw_contour & CONTOUR_SRF) {
                   1288:        for (i = 0; i < cntr->num_pts; i++) {
                   1289:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
                   1290:                     &x, &y);
                   1291:
                   1292:            if (i > 0) {
                   1293:                clip_vector(x, y);
                   1294:                if (i == 1)
                   1295:                    suppressMove = TRUE;
                   1296:            } else {
                   1297:                clip_move(x, y);
                   1298:            }
                   1299:        }
                   1300:     }
                   1301:     /* beginning a new contour level, so moveto() required */
                   1302:     suppressMove = FALSE;
                   1303:
                   1304:     if (draw_contour & CONTOUR_BASE) {
                   1305:        for (i = 0; i < cntr->num_pts; i++) {
                   1306:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
                   1307:                     &x, &y);
                   1308:
                   1309:            if (i > 0) {
                   1310:                clip_vector(x, y);
                   1311:                if (i == 1)
                   1312:                    suppressMove = TRUE;
                   1313:            } else {
                   1314:                clip_move(x, y);
                   1315:            }
                   1316:        }
                   1317:     }
                   1318:     /* beginning a new contour level, so moveto() required */
                   1319:     suppressMove = FALSE;
                   1320: }
                   1321:
                   1322: /* cntr3d_points:
                   1323:  * Plot a surface contour in POINTSTYLE style
                   1324:  */
                   1325: static void cntr3d_points(cntr, plot)
                   1326: struct gnuplot_contours *cntr;
                   1327: struct surface_points *plot;
                   1328: {
                   1329:     int i;
                   1330:     unsigned int x, y;
                   1331:     struct termentry *t = term;
                   1332:
                   1333:     if (draw_contour & CONTOUR_SRF) {
                   1334:        for (i = 0; i < cntr->num_pts; i++) {
                   1335:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z, &x, &y);
                   1336:
                   1337:            if (!clip_point(x, y))
                   1338:                (*t->point) (x, y, plot->lp_properties.p_type);
                   1339:        }
                   1340:     }
                   1341:     if (draw_contour & CONTOUR_BASE) {
                   1342:        for (i = 0; i < cntr->num_pts; i++) {
                   1343:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
                   1344:                     &x, &y);
                   1345:
                   1346:            if (!clip_point(x, y))
                   1347:                (*t->point) (x, y, plot->lp_properties.p_type);
                   1348:        }
                   1349:     }
                   1350: }
                   1351:
                   1352: /* cntr3d_dots:
                   1353:  * Plot a surface contour in DOTS style
                   1354:  */
                   1355: static void cntr3d_dots(cntr)
                   1356: struct gnuplot_contours *cntr;
                   1357: {
                   1358:     int i;
                   1359:     unsigned int x, y;
                   1360:     struct termentry *t = term;
                   1361:
                   1362:     if (draw_contour & CONTOUR_SRF) {
                   1363:        for (i = 0; i < cntr->num_pts; i++) {
                   1364:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z, &x, &y);
                   1365:
                   1366:            if (!clip_point(x, y))
                   1367:                (*t->point) (x, y, -1);
                   1368:        }
                   1369:     }
                   1370:     if (draw_contour & CONTOUR_BASE) {
                   1371:        for (i = 0; i < cntr->num_pts; i++) {
                   1372:            map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
                   1373:                     &x, &y);
                   1374:
                   1375:            if (!clip_point(x, y))
                   1376:                (*t->point) (x, y, -1);
                   1377:        }
                   1378:     }
                   1379: }
                   1380:
                   1381:
                   1382:
                   1383: /* map xmin | xmax to 0 | 1 and same for y
                   1384:  * 0.1 avoids any rounding errors
                   1385:  */
                   1386: #define MAP_HEIGHT_X(x) ( (int) (((x)-x_min3d)/(x_max3d-x_min3d)+0.1) )
                   1387: #define MAP_HEIGHT_Y(y) ( (int) (((y)-y_min3d)/(y_max3d-y_min3d)+0.1) )
                   1388:
                   1389: /* if point is at corner, update height[][] and depth[][]
                   1390:  * we are still assuming that extremes of surfaces are at corners,
                   1391:  * but we are not assuming order of corners
                   1392:  */
                   1393: static void check_corner_height(p, height, depth)
                   1394: struct coordinate GPHUGE *p;
                   1395: double height[2][2];
                   1396: double depth[2][2];
                   1397: {
                   1398:     if (p->type != INRANGE)
                   1399:        return;
                   1400:     if ((fabs(p->x - x_min3d) < zero || fabs(p->x - x_max3d) < zero) &&
                   1401:        (fabs(p->y - y_min3d) < zero || fabs(p->y - y_max3d) < zero)) {
                   1402:        unsigned int x = MAP_HEIGHT_X(p->x);
                   1403:        unsigned int y = MAP_HEIGHT_Y(p->y);
                   1404:        if (height[x][y] < p->z)
                   1405:            height[x][y] = p->z;
                   1406:        if (depth[x][y] > p->z)
                   1407:            depth[x][y] = p->z;
                   1408:     }
                   1409: }
                   1410:
                   1411:
                   1412: /* Draw the bottom grid that hold the tic marks for 3d surface. */
                   1413: static void draw_bottom_grid(plot, plot_num)
                   1414: struct surface_points *plot;
                   1415: int plot_num;
                   1416: {
                   1417:     unsigned int x, y;         /* point in terminal coordinates */
                   1418:     struct termentry *t = term;
                   1419:     char ss[MAX_LINE_LEN+1];
                   1420:
                   1421:     /* work out where the axes and tics are drawn */
                   1422:
                   1423:     {
                   1424:        int quadrant = surface_rot_z / 90;
                   1425:        if ((quadrant + 1) & 2) {
                   1426:            zaxis_x = x_max3d;
                   1427:            xaxis_y = y_max3d;
                   1428:        } else {
                   1429:            zaxis_x = x_min3d;
                   1430:            xaxis_y = y_min3d;
                   1431:        }
                   1432:
                   1433:        if (quadrant & 2) {
                   1434:            zaxis_y = y_max3d;
                   1435:            yaxis_x = x_min3d;
                   1436:        } else {
                   1437:            zaxis_y = y_min3d;
                   1438:            yaxis_x = x_max3d;
                   1439:        }
                   1440:
                   1441:        if (surface_rot_x > 90) {
                   1442:            /* labels on the back axes */
                   1443:            back_x = yaxis_x = x_min3d + x_max3d - yaxis_x;
                   1444:            back_y = xaxis_y = y_min3d + y_max3d - xaxis_y;
                   1445:        } else {
                   1446:            back_x = x_min3d + x_max3d - yaxis_x;
                   1447:            back_y = y_min3d + y_max3d - xaxis_y;
                   1448:        }
                   1449:     }
                   1450:
                   1451:     if (draw_border) {
                   1452:        unsigned int bl_x, bl_y;        /* bottom left */
                   1453:        unsigned int bb_x, bb_y;        /* bottom back */
                   1454:        unsigned int br_x, br_y;        /* bottom right */
                   1455:        unsigned int bf_x, bf_y;        /* bottom front */
                   1456:
                   1457: #ifndef LITE
                   1458:        int save_update = hidden_no_update;
                   1459:        hidden_no_update = TRUE;
                   1460: #endif /* LITE */
                   1461:
                   1462:        /* Here is the one and only call to this function. */
                   1463:        setlinestyle(border_lp);
                   1464:
                   1465:        map3d_xy(zaxis_x, zaxis_y, base_z, &bl_x, &bl_y);
                   1466:        map3d_xy(back_x, back_y, base_z, &bb_x, &bb_y);
                   1467:        map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, base_z, &br_x, &br_y);
                   1468:        map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, base_z, &bf_x, &bf_y);
                   1469:
                   1470:        /* border around base */
                   1471:        {
                   1472:            int save = hidden_active;
                   1473:            hidden_active = FALSE;      /* this is in front */
                   1474:            if (draw_border & 4)
                   1475:                draw_clip_line(br_x, br_y, bf_x, bf_y);
                   1476:            if (draw_border & 1)
                   1477:                draw_clip_line(bl_x, bl_y, bf_x, bf_y);
                   1478:            hidden_active = save;
                   1479:        }
                   1480:        if (draw_border & 2)
                   1481:            draw_clip_line(bl_x, bl_y, bb_x, bb_y);
                   1482:        if (draw_border & 8)
                   1483:            draw_clip_line(br_x, br_y, bb_x, bb_y);
                   1484:
                   1485:        if (draw_surface || (draw_contour & CONTOUR_SRF)) {
                   1486:            int save = hidden_active;
                   1487:            /* map the 8 corners to screen */
                   1488:            unsigned int fl_x, fl_y;    /* floor left */
                   1489:            unsigned int fb_x, fb_y;    /* floor back */
                   1490:            unsigned int fr_x, fr_y;    /* floor right */
                   1491:            unsigned int ff_x, ff_y;    /* floor front */
                   1492:
                   1493:            unsigned int tl_x, tl_y;    /* top left */
                   1494:            unsigned int tb_x, tb_y;    /* top back */
                   1495:            unsigned int tr_x, tr_y;    /* top right */
                   1496:            unsigned int tf_x, tf_y;    /* top front */
                   1497:
                   1498:            map3d_xy(zaxis_x, zaxis_y, floor_z, &fl_x, &fl_y);
                   1499:            map3d_xy(back_x, back_y, floor_z, &fb_x, &fb_y);
                   1500:            map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, floor_z, &fr_x, &fr_y);
                   1501:            map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, floor_z, &ff_x, &ff_y);
                   1502:
                   1503:            map3d_xy(zaxis_x, zaxis_y, ceiling_z, &tl_x, &tl_y);
                   1504:            map3d_xy(back_x, back_y, ceiling_z, &tb_x, &tb_y);
                   1505:            map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, ceiling_z, &tr_x, &tr_y);
                   1506:            map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, ceiling_z, &tf_x, &tf_y);
                   1507:
                   1508:            /* vertical lines, to surface or to very top */
                   1509:            if ((draw_border & 0xf0) == 0xf0) {
                   1510:                /* all four verticals drawn - save some time */
                   1511:                draw_clip_line(fl_x, fl_y, tl_x, tl_y);
                   1512:                draw_clip_line(fb_x, fb_y, tb_x, tb_y);
                   1513:                draw_clip_line(fr_x, fr_y, tr_x, tr_y);
                   1514:                hidden_active = FALSE;  /* this is in front */
                   1515:                draw_clip_line(ff_x, ff_y, tf_x, tf_y);
                   1516:                hidden_active = save;
                   1517:            } else {
                   1518:                /* search surfaces for heights at corners */
                   1519:                double height[2][2];
                   1520:                double depth[2][2];
                   1521:                unsigned int zaxis_i = MAP_HEIGHT_X(zaxis_x);
                   1522:                unsigned int zaxis_j = MAP_HEIGHT_Y(zaxis_y);
                   1523:                unsigned int back_i = MAP_HEIGHT_X(back_x);
                   1524:        /* HBB: why isn't back_j unsigned ??? */
                   1525:                int back_j = MAP_HEIGHT_Y(back_y);
                   1526:
                   1527:                height[0][0] = height[0][1] = height[1][0] = height[1][1] = base_z;
                   1528:                depth[0][0] = depth[0][1] = depth[1][0] = depth[1][1] = base_z;
                   1529:
                   1530:                for (; --plot_num >= 0; plot = plot->next_sp) {
                   1531:                    struct iso_curve *curve = plot->iso_crvs;
                   1532:                    int count = curve->p_count;
                   1533:                    int iso;
                   1534:                    if (plot->plot_type == DATA3D) {
                   1535:                        if (!plot->has_grid_topology)
                   1536:                            continue;
                   1537:                        iso = plot->num_iso_read;
                   1538:                    } else
                   1539:                        iso = iso_samples_2;
                   1540:
                   1541:                    check_corner_height(curve->points, height, depth);
                   1542:                    check_corner_height(curve->points + count - 1, height, depth);
                   1543:                    while (--iso)
                   1544:                        curve = curve->next;
                   1545:                    check_corner_height(curve->points, height, depth);
                   1546:                    check_corner_height(curve->points + count - 1, height, depth);
                   1547:                }
                   1548:
                   1549: #define VERTICAL(mask,x,y,i,j,bx,by,tx,ty) \
                   1550:  if (draw_border&mask) \
                   1551:   draw_clip_line(bx,by,tx,ty);\
                   1552: else if (height[i][j] != depth[i][j]) \
                   1553: { unsigned int a0,b0, a1, b1; \
                   1554:   map3d_xy(x,y,depth[i][j],&a0,&b0); \
                   1555:   map3d_xy(x,y,height[i][j],&a1,&b1); \
                   1556:   draw_clip_line(a0,b0,a1,b1); \
                   1557: }
                   1558:
                   1559:                VERTICAL(16,zaxis_x,zaxis_y,zaxis_i,zaxis_j,fl_x,fl_y,tl_x,tl_y);
                   1560:                VERTICAL(32,back_x,back_y,back_i,back_j,fb_x,fb_y,tb_x,tb_y);
                   1561:                VERTICAL(64,x_min3d+x_max3d-zaxis_x,y_min3d+y_max3d-zaxis_y,1-zaxis_i,1-zaxis_j,fr_x,fr_y,tr_x,tr_y);
                   1562:                hidden_active = FALSE;
                   1563:                VERTICAL(128,x_min3d+x_max3d-back_x,y_min3d+y_max3d-back_y,1-back_i,1-back_j,ff_x,ff_y,tf_x,tf_y);
                   1564:                    hidden_active = save;
                   1565:            }
                   1566:
                   1567:            /* now border lines on top */
                   1568:            if (draw_border & 256)
                   1569:                draw_clip_line(tl_x, tl_y, tb_x, tb_y);
                   1570:            if (draw_border & 512)
                   1571:                draw_clip_line(tr_x, tr_y, tb_x, tb_y);
                   1572:            /* these lines are in front of surface (?) */
                   1573:            hidden_active = FALSE;
                   1574:            if (draw_border & 1024)
                   1575:                draw_clip_line(tl_x, tl_y, tf_x, tf_y);
                   1576:            if (draw_border & 2048)
                   1577:                draw_clip_line(tr_x, tr_y, tf_x, tf_y);
                   1578:            hidden_active = save;
                   1579:        }
                   1580:
                   1581: #ifndef LITE
                   1582:        hidden_no_update = save_update;
                   1583: #endif /* LITE */
                   1584:
                   1585:     }
                   1586:     if (xtics || *xlabel.text) {
                   1587:        unsigned int x0, y0, x1, y1;
                   1588:        double mid_x = (x_max3d + x_min3d) / 2;
                   1589:        double len;
                   1590:        map3d_xy(mid_x, xaxis_y, base_z, &x0, &y0);
                   1591:        map3d_xy(mid_x, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
                   1592:        {                       /* take care over unsigned quantities */
                   1593:            int dx = x1 - x0;
                   1594:            int dy = y1 - y0;
                   1595:            /* HBB 980309: 16bit strikes back: */
                   1596:            len = sqrt(((double) dx) * dx + ((double) dy) * dy);
                   1597:            if (len != 0) {
                   1598:                tic_unitx = dx / len;
                   1599:                tic_unity = dy / len;
                   1600:            } else {
                   1601:                tic_unitx = tic_unity = 0;
                   1602:            }
                   1603:        }
                   1604:
                   1605:        if (xtics) {
                   1606:            gen_tics(FIRST_X_AXIS, &xticdef,
                   1607:                     work_grid.l_type & (GRID_X | GRID_MX),
                   1608:                     mxtics, mxtfreq, xtick_callback);
                   1609:        }
                   1610:        if (*xlabel.text) {
                   1611:            /* label at xaxis_y + 1/4 of (xaxis_y-other_y) */
                   1612:            double step = (2 * xaxis_y - y_max3d - y_min3d) / 4;
                   1613:            map3d_xy(mid_x, xaxis_y + step, base_z, &x1, &y1);
                   1614:            x1 += xlabel.xoffset * t->h_char;
                   1615:            y1 += xlabel.yoffset * t->v_char;
                   1616:            if (!tic_in) {
                   1617:                x1 -= tic_unitx * ticscale * (t->h_tic);
                   1618:                y1 -= tic_unity * ticscale * (t->v_tic);
                   1619:            }
                   1620:            /* write_multiline mods it */
                   1621:            safe_strncpy(ss, xlabel.text, sizeof(ss));
                   1622:            write_multiline(x1, y1, ss, CENTRE, JUST_TOP, 0, xlabel.font);
                   1623:        }
                   1624:     }
                   1625:     if (ytics || *ylabel.text) {
                   1626:        unsigned int x0, y0, x1, y1;
                   1627:        double mid_y = (y_max3d + y_min3d) / 2;
                   1628:        double len;
                   1629:        map3d_xy(yaxis_x, mid_y, base_z, &x0, &y0);
                   1630:        map3d_xy(x_min3d + x_max3d - yaxis_x, mid_y, base_z, &x1, &y1);
                   1631:        {                       /* take care over unsigned quantities */
                   1632:            int dx = x1 - x0;
                   1633:            int dy = y1 - y0;
                   1634:            /* HBB 980309: 16 Bits strike again: */
                   1635:            len = sqrt(((double) dx) * dx + ((double) dy) * dy);
                   1636:            if (len != 0) {
                   1637:                tic_unitx = dx / len;
                   1638:                tic_unity = dy / len;
                   1639:            } else {
                   1640:                tic_unitx = tic_unity = 0;
                   1641:            }
                   1642:        }
                   1643:        if (ytics) {
                   1644:            gen_tics(FIRST_Y_AXIS, &yticdef,
                   1645:                     work_grid.l_type & (GRID_Y | GRID_MY),
                   1646:                     mytics, mytfreq, ytick_callback);
                   1647:        }
                   1648:        if (*ylabel.text) {
                   1649:            double step = (x_max3d + x_min3d - 2 * yaxis_x) / 4;
                   1650:            map3d_xy(yaxis_x - step, mid_y, base_z, &x1, &y1);
                   1651:            x1 += ylabel.xoffset * t->h_char;
                   1652:            y1 += ylabel.yoffset * t->v_char;
                   1653:            if (!tic_in) {
                   1654:                x1 -= tic_unitx * ticscale * (t->h_tic);
                   1655:                y1 -= tic_unity * ticscale * (t->v_tic);
                   1656:            }
                   1657:            /* write_multiline mods it */
                   1658:            safe_strncpy(ss, ylabel.text, sizeof(ss));
                   1659:            write_multiline(x1, y1, ss, CENTRE, JUST_TOP, 0, ylabel.font);
                   1660:        }
                   1661:     }
                   1662:     /* do z tics */
                   1663:
                   1664:     if (ztics && (draw_surface || (draw_contour & CONTOUR_SRF))) {
                   1665:        gen_tics(FIRST_Z_AXIS, &zticdef, work_grid.l_type & (GRID_Z | GRID_MZ),
                   1666:                 mztics, mztfreq, ztick_callback);
                   1667:     }
                   1668:     if ((xzeroaxis.l_type >= -2) && !is_log_y && inrange(0, y_min3d, y_max3d)) {
                   1669:        unsigned int x, y, x1, y1;
                   1670:        term_apply_lp_properties(&xzeroaxis);
                   1671:        map3d_xy(0.0, y_min3d, base_z, &x, &y);         /* line through x=0 */
                   1672:        map3d_xy(0.0, y_max3d, base_z, &x1, &y1);
                   1673:        draw_clip_line(x, y, x1, y1);
                   1674:     }
                   1675:     if ((yzeroaxis.l_type >= -2) && !is_log_x && inrange(0, x_min3d, x_max3d)) {
                   1676:        unsigned int x, y, x1, y1;
                   1677:        term_apply_lp_properties(&yzeroaxis);
                   1678:        map3d_xy(x_min3d, 0.0, base_z, &x, &y);         /* line through y=0 */
                   1679:        map3d_xy(x_max3d, 0.0, base_z, &x1, &y1);
                   1680:        draw_clip_line(x, y, x1, y1);
                   1681:     }
                   1682:     /* PLACE ZLABEL - along the middle grid Z axis - eh ? */
                   1683:     if (*zlabel.text && (draw_surface || (draw_contour & CONTOUR_SRF))) {
                   1684:        map3d_xy(zaxis_x, zaxis_y, z_max3d + (z_max3d - base_z) / 4, &x, &y);
                   1685:
                   1686:        x += zlabel.xoffset * t->h_char;
                   1687:        y += zlabel.yoffset * t->v_char;
                   1688:
                   1689:        safe_strncpy(ss, zlabel.text, sizeof(ss));
                   1690:        write_multiline(x, y, ss, CENTRE, CENTRE, 0, zlabel.font);
                   1691:
                   1692:     }
                   1693: }
                   1694:
                   1695:
                   1696: static void xtick_callback(axis, place, text, grid)
                   1697: int axis;
                   1698: double place;
                   1699: char *text;
                   1700: struct lp_style_type grid;     /* linetype or -2 for none */
                   1701: {
                   1702:     unsigned int x, y, x1, y1;
                   1703:     double scale = (text ? ticscale : miniticscale);
                   1704:     int dirn = tic_in ? 1 : -1;
                   1705:     register struct termentry *t = term;
                   1706:
                   1707:     map3d_xy(place, xaxis_y, base_z, &x, &y);
                   1708:     if (grid.l_type > -2) {
                   1709:        term_apply_lp_properties(&grid);
                   1710:        /* to save mapping twice, map non-axis y */
                   1711:        map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
                   1712:        draw_clip_line(x, y, x1, y1);
                   1713:        term_apply_lp_properties(&border_lp);
                   1714:     }
                   1715:     if (xtics & TICS_ON_AXIS) {
                   1716:        map3d_xy(place, (y_min3d + y_max3d) / 2, base_z, &x, &y);
                   1717:     }
                   1718:     x1 = x + tic_unitx * scale * (t->h_tic) * dirn;
                   1719:     y1 = y + tic_unity * scale * (t->v_tic) * dirn;
                   1720:     draw_clip_line(x, y, x1, y1);
                   1721:     if (text) {
                   1722:        int just;
                   1723:        if (tic_unitx < -0.9)
                   1724:            just = LEFT;
                   1725:        else if (tic_unitx < 0.9)
                   1726:            just = CENTRE;
                   1727:        else
                   1728:            just = RIGHT;
                   1729: #if 1
                   1730: /* HBB 970729: let's see if the 'tic labels collide with axes' problem
                   1731:  * may be fixed this way: */
                   1732:        x1 = x - tic_unitx * (t->h_char) * 1;
                   1733:        y1 = y - tic_unity * (t->v_char) * 1;
                   1734: #else
                   1735:        x1 = x - tic_unitx * (t->h_tic) * 2;
                   1736:        y1 = y - tic_unity * (t->v_tic) * 2;
                   1737: #endif
                   1738:        if (!tic_in) {
                   1739:            x1 -= tic_unitx * (t->h_tic) * ticscale;
                   1740:            y1 -= tic_unity * (t->v_tic) * ticscale;
                   1741:        }
                   1742:        clip_put_text_just(x1, y1, text, just);
                   1743:     }
                   1744:     if (xtics & TICS_MIRROR) {
                   1745:        map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x, &y);
                   1746:        x1 = x - tic_unitx * scale * (t->h_tic) * dirn;
                   1747:        y1 = y - tic_unity * scale * (t->v_tic) * dirn;
                   1748:        draw_clip_line(x, y, x1, y1);
                   1749:     }
                   1750: }
                   1751:
                   1752: static void ytick_callback(axis, place, text, grid)
                   1753: int axis;
                   1754: double place;
                   1755: char *text;
                   1756: struct lp_style_type grid;
                   1757: {
                   1758:     unsigned int x, y, x1, y1;
                   1759:     double scale = (text ? ticscale : miniticscale);
                   1760:     int dirn = tic_in ? 1 : -1;
                   1761:     register struct termentry *t = term;
                   1762:
                   1763:     map3d_xy(yaxis_x, place, base_z, &x, &y);
                   1764:     if (grid.l_type > -2) {
                   1765:        term_apply_lp_properties(&grid);
                   1766:        map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x1, &y1);
                   1767:        draw_clip_line(x, y, x1, y1);
                   1768:        term_apply_lp_properties(&border_lp);
                   1769:     }
                   1770:     if (ytics & TICS_ON_AXIS) {
                   1771:        map3d_xy((x_min3d + x_max3d) / 2, place, base_z, &x, &y);
                   1772:     }
                   1773:     x1 = x + tic_unitx * scale * dirn * (t->h_tic);
                   1774:     y1 = y + tic_unity * scale * dirn * (t->v_tic);
                   1775:     draw_clip_line(x, y, x1, y1);
                   1776:     if (text) {
                   1777:        int just;
                   1778:        if (tic_unitx < -0.9)
                   1779:            just = LEFT;
                   1780:        else if (tic_unitx < 0.9)
                   1781:            just = CENTRE;
                   1782:        else
                   1783:            just = RIGHT;
                   1784: #if 1
                   1785:        /* HBB 970729: same as above in xtics_callback */
                   1786:        x1 = x - tic_unitx * (t->h_char) * 1;
                   1787:        y1 = y - tic_unity * (t->v_char) * 1;
                   1788: #else
                   1789:        x1 = x - tic_unitx * (t->h_tic) * 2;
                   1790:        y1 = y - tic_unity * (t->v_tic) * 2;
                   1791: #endif
                   1792:        if (!tic_in) {
                   1793:            x1 -= tic_unitx * (t->h_tic) * ticscale;
                   1794:            y1 -= tic_unity * (t->v_tic) * ticscale;
                   1795:        }
                   1796:        clip_put_text_just(x1, y1, text, just);
                   1797:     }
                   1798:     if (ytics & TICS_MIRROR) {
                   1799:        map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x, &y);
                   1800:        x1 = x - tic_unitx * scale * (t->h_tic) * dirn;
                   1801:        y1 = y - tic_unity * scale * (t->v_tic) * dirn;
                   1802:        draw_clip_line(x, y, x1, y1);
                   1803:     }
                   1804: }
                   1805:
                   1806: static void ztick_callback(axis, place, text, grid)
                   1807: int axis;
                   1808: double place;
                   1809: char *text;
                   1810: struct lp_style_type grid;
                   1811: {
                   1812: /* HBB: inserted some ()'s to shut up gcc -Wall, here and below */
                   1813:     int len = (text ? ticscale : miniticscale) * (tic_in ? 1 : -1) * (term->h_tic);
                   1814:     unsigned int x, y;
                   1815:
                   1816:     if (grid.l_type > -2) {
                   1817:        unsigned int x1, y1, x2, y2, x3, y3;
                   1818:        double other_x = x_min3d + x_max3d - zaxis_x;
                   1819:        double other_y = y_min3d + y_max3d - zaxis_y;
                   1820:        term_apply_lp_properties(&grid);
                   1821:        map3d_xy(zaxis_x, zaxis_y, place, &x1, &y1);
                   1822:        map3d_xy(back_x, back_y, place, &x2, &y2);
                   1823:        map3d_xy(other_x, other_y, place, &x3, &y3);
                   1824:        draw_clip_line(x1, y1, x2, y2);
                   1825:        draw_clip_line(x2, y2, x3, y3);
                   1826:        term_apply_lp_properties(&border_lp);
                   1827:     }
                   1828:     map3d_xy(zaxis_x, zaxis_y, place, &x, &y);
                   1829:     draw_clip_line(x, y, x + len, y);
                   1830:     if (text) {
                   1831:        int x1 = x - (term->h_tic) * 2;
                   1832:        if (!tic_in)
                   1833:            x1 -= (term->h_tic) * ticscale;
                   1834:        clip_put_text_just(x1, y, text, RIGHT);
                   1835:     }
                   1836:     if (ztics & TICS_MIRROR) {
                   1837:        double other_x = x_min3d + x_max3d - zaxis_x;
                   1838:        double other_y = y_min3d + y_max3d - zaxis_y;
                   1839:        map3d_xy(other_x, other_y, place, &x, &y);
                   1840:        draw_clip_line(x, y, x - len, y);
                   1841:     }
                   1842: }
                   1843:
                   1844:
                   1845: static void map_position(pos, x, y, what)
                   1846: struct position *pos;
                   1847: unsigned int *x, *y;
                   1848: char *what;
                   1849: {
                   1850:     double xpos = pos->x;
                   1851:     double ypos = pos->y;
                   1852:     double zpos = pos->z;
                   1853:     int screens = 0;           /* need either 0 or 3 screen co-ordinates */
                   1854:
                   1855:     switch (pos->scalex) {
                   1856:     case first_axes:
                   1857:     case second_axes:
                   1858:        xpos = LogScale(xpos, is_log_x, log_base_log_x, what, "x");
                   1859:        break;
                   1860:     case graph:
                   1861:        xpos = min_array[FIRST_X_AXIS] +
                   1862:                xpos * (max_array[FIRST_X_AXIS] - min_array[FIRST_X_AXIS]);
                   1863:        break;
                   1864:     case screen:
                   1865:        ++screens;
                   1866:     }
                   1867:
                   1868:     switch (pos->scaley) {
                   1869:     case first_axes:
                   1870:     case second_axes:
                   1871:        ypos = LogScale(ypos, is_log_y, log_base_log_y, what, "y");
                   1872:        break;
                   1873:     case graph:
                   1874:        ypos = min_array[FIRST_Y_AXIS] +
                   1875:                ypos * (max_array[FIRST_Y_AXIS] - min_array[FIRST_Y_AXIS]);
                   1876:        break;
                   1877:     case screen:
                   1878:        ++screens;
                   1879:     }
                   1880:
                   1881:     switch (pos->scalez) {
                   1882:     case first_axes:
                   1883:     case second_axes:
                   1884:        zpos = LogScale(zpos, is_log_z, log_base_log_z, what, "z");
                   1885:        break;
                   1886:     case graph:
                   1887:        zpos = min_array[FIRST_Z_AXIS] +
                   1888:                zpos * (max_array[FIRST_Z_AXIS] - min_array[FIRST_Z_AXIS]);
                   1889:        break;
                   1890:     case screen:
                   1891:        ++screens;
                   1892:     }
                   1893:
                   1894:     if (screens == 0) {
                   1895:        map3d_xy(xpos, ypos, zpos, x, y);
                   1896:        return;
                   1897:     }
                   1898:     if (screens != 3) {
                   1899:        graph_error("Cannot mix screen co-ordinates with other types");
                   1900:     } {
                   1901:        register struct termentry *t = term;
                   1902:        *x = pos->x * (t->xmax) + 0.5;
                   1903:        *y = pos->y * (t->ymax) + 0.5;
                   1904:     }
                   1905:
                   1906:     return;
                   1907: }
                   1908:
                   1909:
                   1910: /*
                   1911:  * these code blocks were moved to functions, to make the code simpler
                   1912:  */
                   1913:
                   1914: static void key_text(xl, yl, text)
                   1915: int xl, yl;
                   1916: char *text;
                   1917: {
                   1918:     if (key_just == JLEFT && key == -1) {
                   1919:        (*term->justify_text) (LEFT);
                   1920:        (*term->put_text) (xl + key_text_left, yl, text);
                   1921:     } else {
                   1922:        if ((*term->justify_text) (RIGHT)) {
                   1923:            if (key == 1)
                   1924:                clip_put_text(xl + key_text_right, yl, text);
                   1925:            else
                   1926:                (*term->put_text) (xl + key_text_right, yl, text);
                   1927:        } else {
                   1928:            int x = xl + key_text_right - (term->h_char) * strlen(text);
                   1929:            if (key == 1) {
                   1930:                if (i_inrange(x, xleft, xright))
                   1931:                    clip_put_text(x, yl, text);
                   1932:            } else {
                   1933:                (*term->put_text) (x, yl, text);
                   1934:            }
                   1935:        }
                   1936:     }
                   1937: }
                   1938:
                   1939: static void key_sample_line(xl, yl)
                   1940: int xl, yl;
                   1941: {
                   1942:     if (key == -1) {
                   1943:        (*term->move) (xl + key_sample_left, yl);
                   1944:        (*term->vector) (xl + key_sample_right, yl);
                   1945:     } else {
                   1946:        /* HBB 981118: avoid crash if hidden3d sees a manually placed key:
                   1947:         * simply turn off hidden-lining while we're drawing the key line: */
                   1948:        int save_hidden_active = hidden_active;
                   1949:        hidden_active = FALSE;
                   1950:
                   1951:        clip_move(xl + key_sample_left, yl);
                   1952:        clip_vector(xl + key_sample_right, yl);
                   1953:        hidden_active = save_hidden_active;
                   1954:     }
                   1955: }
                   1956:
                   1957: static void key_sample_point(xl, yl, pointtype)
                   1958: int xl, yl;
                   1959: int pointtype;
                   1960: {
                   1961:     if (!clip_point(xl + key_point_offset, yl)) {
                   1962:        (*term->point) (xl + key_point_offset, yl, pointtype);
                   1963:     } else {
                   1964:        (*term->point) (xl + key_point_offset, yl, pointtype);
                   1965:     }
                   1966: }

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