home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / Gnuplot / Source / graph3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-02  |  80.0 KB  |  2,878 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graph3d.c%v 3.38.2.86 1993/03/01 01:50:57 woo Exp woo $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graph3d.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   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 modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *
  20.  * This software is provided "as is" without express or implied warranty.
  21.  *
  22.  *
  23.  * AUTHORS
  24.  *
  25.  *   Original Software:
  26.  *       Gershon Elber and many others.
  27.  *
  28.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  29.  * Added user-specified bases for log scaling.
  30.  *
  31.  * Send your comments or suggestions to 
  32.  *  info-gnuplot@dartmouth.edu.
  33.  * This is a mailing list; to join it send a note to 
  34.  *  info-gnuplot-request@dartmouth.edu.  
  35.  * Send bug reports to
  36.  *  bug-gnuplot@dartmouth.edu.
  37.  */
  38.  
  39. #include <stdio.h>
  40. #include <math.h>
  41. #include <assert.h>
  42. #include <time.h>
  43. #if !defined(sequent) && !defined(apollo)
  44. #include <limits.h>
  45. #endif
  46. #include "plot.h"
  47. #include "setshow.h"
  48.  
  49. #ifdef DJGPP
  50. #define time_t unsigned long
  51. #endif
  52.  
  53. #ifdef apollo
  54. #include <sys/types.h> /* typedef long time_t; */
  55. #endif
  56.  
  57. int suppressMove = 0;  /* for preventing moveto while drawing contours */
  58. #ifndef AMIGA_SC_6_1
  59. extern char *strcpy(),*strncpy(),*strcat(),*ctime(),*tdate;
  60. #else /* AMIGA_SC_6_1 */
  61. extern char *tdate;
  62. #endif /* AMIGA_SC_6_1 */
  63. #ifdef AMIGA_AC_5
  64. extern time_t dated;
  65. #else
  66. extern time_t dated; /* ,time(); */
  67. #include <time.h>
  68. #endif
  69.  
  70. #ifdef __TURBOC__
  71. #include <stdlib.h>        /* for qsort */
  72. #endif
  73.  
  74. /*
  75.  * hidden_line_type_above, hidden_line_type_below - controls type of lines
  76.  *   for above and below parts of the surface.
  77.  * hidden_no_update - if TRUE lines will be hidden line removed but they
  78.  *   are not assumed to be part of the surface (i.e. grid) and therefore
  79.  *   do not influence the hidings.
  80.  * hidden_active - TRUE if hidden lines are to be removed.
  81.  */
  82. static int hidden_active = FALSE;
  83.  
  84. /* LITE defines a restricted memory version for MS-DOS */
  85.  
  86. #ifndef LITE
  87.  
  88. static int hidden_line_type_above, hidden_line_type_below, hidden_no_update;
  89.  
  90. /* We divvy up the figure into the component boxes that make it up, and then
  91.    sort them by the z-value (which is really just an average value).  */
  92. struct pnts{
  93.   int x,y,z;
  94.   int flag;
  95.   long int style_used;    /* acw test */
  96.   int nplot;
  97. };
  98. static int * boxlist;
  99. static struct pnts * nodes;
  100. /* These variables are used to keep track of the range of x values used in the
  101. line drawing routine.  */
  102. static long int xmin_hl,xmax_hl;
  103. /* These arrays are used to keep track of the minimum and maximum y values used
  104.    for each X value.  These are only used for drawing the individual boxes that
  105.    make up the 3d figure.  After each box is drawn, the information is copied
  106.    to the bitmap. */
  107. static short int *ymin_hl, *ymax_hl;
  108. /*
  109.  * These numbers are chosen as dividers into the bitmap.
  110.  */
  111. static short int xfact, yfact;
  112. #define XREDUCE(X) ((X)/xfact)
  113. #define YREDUCE(Y) ((Y)/yfact)
  114. /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
  115. static short int **pnt;
  116. #define IFSET(X,Y) (pnt[X] == 0 ? 0 : (((pnt[X])[(Y)>>4] >> ((Y) & 0xf)) & 0x01))
  117. static plot3d_hidden();
  118.  
  119. #endif /* LITE */
  120.  
  121.  
  122. static plot3d_impulses();
  123. static plot3d_lines();
  124. static plot3d_points();
  125. static plot3d_dots();
  126. static cntr3d_impulses();
  127. static cntr3d_lines();
  128. static cntr3d_points();
  129. static cntr3d_dots();
  130. static update_extrema_pts();
  131. static draw_parametric_grid();
  132. static draw_non_param_grid();
  133. static draw_bottom_grid();
  134. static draw_3dxtics();
  135. static draw_3dytics();
  136. static draw_3dztics();
  137. static draw_series_3dxtics();
  138. static draw_series_3dytics();
  139. static draw_series_3dztics();
  140. static draw_set_3dxtics();
  141. static draw_set_3dytics();
  142. static draw_set_3dztics();
  143. static xtick();
  144. static ytick();
  145. static ztick();
  146. static setlinestyle();
  147. #ifdef __PUREC__
  148. /* a little problem with the 16bit int size of PureC. this completely broke
  149.    the hidded3d feature. doesn't really fix it, but I'm working at it.  (AL) */
  150. static int clip_point(int x, int y);
  151. static void clip_put_text(int x, int y, char *str);
  152. #endif
  153.  
  154. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  155. #define max(a,b) ((a > b) ? a : b)
  156. #endif
  157.  
  158. #ifndef min
  159. #define min(a,b) ((a < b) ? a : b)
  160. #endif
  161.  
  162. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  163.  
  164. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  165. #ifndef abs
  166. #define abs(x) ((x) >= 0 ? (x) : -(x))
  167. #endif
  168. #define sqr(x) ((x) * (x))
  169.  
  170. /* Define the boundary of the plot
  171.  * These are computed at each call to do_plot, and are constant over
  172.  * the period of one do_plot. They actually only change when the term
  173.  * type changes and when the 'set size' factors change. 
  174.  */
  175. static int xleft, xright, ybot, ytop, xmiddle, ymiddle, xscaler, yscaler;
  176.  
  177. /* Boundary and scale factors, in user coordinates */
  178. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  179.  * file and are not the same as variables of the same names in other files
  180.  */
  181. static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;
  182. static double xscale3d, yscale3d, zscale3d;
  183. static double real_z_min3d, real_z_max3d;
  184. static double min_sy_ox,min_sy_oy; /* obj. coords. for xy tics placement. */
  185. static double min_sx_ox,min_sx_oy; /* obj. coords. for z tics placement. */
  186.  
  187. typedef double transform_matrix[4][4];
  188. static transform_matrix trans_mat;
  189.  
  190. /* (DFK) Watch for cancellation error near zero on axes labels */
  191. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  192. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  193. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  194.  
  195. /* And the functions to map from user to terminal coordinates */
  196. #define map_x(x) (int)(x+0.5) /* maps floating point x to screen */ 
  197. #define map_y(y) (int)(y+0.5)    /* same for y */
  198.  
  199. /* And the functions to map from user 3D space into normalized -1..1 */
  200. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  201. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  202. #define map_z3d(z) ((z-z_min3d)*zscale3d-1.0)
  203.  
  204. static mat_unit(mat)
  205. transform_matrix mat;
  206. {
  207.     int i, j;
  208.  
  209.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  210.     if (i == j)
  211.         mat[i][j] = 1.0;
  212.     else
  213.         mat[i][j] = 0.0;
  214. }
  215.  
  216. static mat_trans(tx, ty, tz, mat)
  217. double tx, ty, tz;
  218. transform_matrix mat;
  219. {
  220.      mat_unit(mat);                                 /* Make it unit matrix. */
  221.      mat[3][0] = tx;
  222.      mat[3][1] = ty;
  223.      mat[3][2] = tz;
  224. }
  225.  
  226. static mat_scale(sx, sy, sz, mat)
  227. double sx, sy, sz;
  228. transform_matrix mat;
  229. {
  230.      mat_unit(mat);                                 /* Make it unit matrix. */
  231.      mat[0][0] = sx;
  232.      mat[1][1] = sy;
  233.      mat[2][2] = sz;
  234. }
  235.  
  236. static mat_rot_x(teta, mat)
  237. double teta;
  238. transform_matrix mat;
  239. {
  240.     double cos_teta, sin_teta;
  241.  
  242.     teta *= Pi / 180.0;
  243.     cos_teta = cos(teta);
  244.     sin_teta = sin(teta);
  245.  
  246.     mat_unit(mat);                                  /* Make it unit matrix. */
  247.     mat[1][1] = cos_teta;
  248.     mat[1][2] = -sin_teta;
  249.     mat[2][1] = sin_teta;
  250.     mat[2][2] = cos_teta;
  251. }
  252.  
  253. static mat_rot_y(teta, mat)
  254. double teta;
  255. transform_matrix mat;
  256. {
  257.     double cos_teta, sin_teta;
  258.  
  259.     teta *= Pi / 180.0;
  260.     cos_teta = cos(teta);
  261.     sin_teta = sin(teta);
  262.  
  263.     mat_unit(mat);                                  /* Make it unit matrix. */
  264.     mat[0][0] = cos_teta;
  265.     mat[0][2] = -sin_teta;
  266.     mat[2][0] = sin_teta;
  267.     mat[2][2] = cos_teta;
  268. }
  269.  
  270. static mat_rot_z(teta, mat)
  271. double teta;
  272. transform_matrix mat;
  273. {
  274.     double cos_teta, sin_teta;
  275.  
  276.     teta *= Pi / 180.0;
  277.     cos_teta = cos(teta);
  278.     sin_teta = sin(teta);
  279.  
  280.     mat_unit(mat);                                  /* Make it unit matrix. */
  281.     mat[0][0] = cos_teta;
  282.     mat[0][1] = -sin_teta;
  283.     mat[1][0] = sin_teta;
  284.     mat[1][1] = cos_teta;
  285. }
  286.  
  287. /* Multiply two transform_matrix. Result can be one of two operands. */
  288. void mat_mult(mat_res, mat1, mat2)
  289. transform_matrix mat_res, mat1, mat2;
  290. {
  291.     int i, j, k;
  292.     transform_matrix mat_res_temp;
  293.  
  294.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) {
  295.         mat_res_temp[i][j] = 0;
  296.         for (k = 0; k < 4; k++) mat_res_temp[i][j] += mat1[i][k] * mat2[k][j];
  297.     }
  298.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  299.     mat_res[i][j] = mat_res_temp[i][j];
  300. }
  301.  
  302. /* And the functions to map from user 3D space to terminal coordinates */
  303. static int map3d_xy(x, y, z, xt, yt)
  304. double x, y, z;
  305. int *xt, *yt;
  306. {
  307.     int i,j;
  308.     double v[4], res[4],             /* Homogeneous coords. vectors. */
  309.     w = trans_mat[3][3];
  310.  
  311.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  312.     v[1] = map_y3d(y);
  313.     v[2] = map_z3d(z);
  314.     v[3] = 1.0;
  315.  
  316.     for (i = 0; i < 2; i++) {                 /* Dont use the third axes (z). */
  317.         res[i] = trans_mat[3][i];     /* Initiate it with the weight factor. */
  318.         for (j = 0; j < 3; j++) res[i] += v[j] * trans_mat[j][i];
  319.     }
  320.  
  321.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  322.     if (w == 0) w = 1e-5;
  323.  
  324.     *xt = ((int) (res[0] * xscaler / w)) + xmiddle;
  325.     *yt = ((int) (res[1] * yscaler / w)) + ymiddle;
  326. }
  327.  
  328. /* And the functions to map from user 3D space to terminal z coordinate */
  329. static int map3d_z(x, y, z)
  330. double x, y, z;
  331. {
  332.     int i, zt;
  333.     double v[4], res,                 /* Homogeneous coords. vectors. */
  334.     w = trans_mat[3][3];
  335.  
  336.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  337.     v[1] = map_y3d(y);
  338.     v[2] = map_z3d(z);
  339.     v[3] = 1.0;
  340.  
  341.     res = trans_mat[3][2];               /* Initiate it with the weight factor. */
  342.     for (i = 0; i < 3; i++) res += v[i] * trans_mat[i][2];
  343.     if(w==0) w= 1e-5;
  344.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  345.     zt = ((int) (res * 16384 / w));
  346.     return  zt;
  347. }
  348.  
  349. /* Initialize the line style using the current device and set hidden styles  */
  350. /* to it as well if hidden line removal is enabled.                 */
  351. static setlinestyle(style)
  352. int style;
  353. {
  354.     register struct termentry *t = &term_tbl[term];
  355.  
  356.     (*t->linetype)(style);
  357.  
  358. #ifndef LITE
  359.     if (hidden3d) {
  360.     hidden_line_type_above = style;
  361.     hidden_line_type_below = style;
  362.     }
  363. #endif  /* LITE */
  364. }
  365.  
  366. #ifndef LITE
  367. /* Initialize the necessary steps for hidden line removal. */
  368. static void init_hidden_line_removal()
  369. {
  370.   int i;
  371.   /*  We want to keep the bitmap size less than 2048x2048, so we choose
  372.    *  integer dividers for the x and y coordinates to keep the x and y
  373.    *  ranges less than 2048.  In practice, the x and y sizes for the bitmap
  374.    *  will be somewhere between 1024 and 2048, except in cases where the
  375.    *  coordinates ranges for the device are already less than 1024.
  376.    *  We do this mainly to control the size of the bitmap, but it also
  377.    *  speeds up the computation.  We maintain separate dividers for
  378.    *  x and y.
  379.    */
  380.   xfact = (xright-xleft)/1024;
  381.   yfact = (ytop-ybot)/1024;
  382.   if(xfact == 0) xfact=1;
  383.   if(yfact == 0) yfact=1;
  384.   if(pnt == 0){
  385.     i = sizeof(short int*)*(XREDUCE(xright) - XREDUCE(xleft) + 1);
  386.     pnt = (short int **) alloc((unsigned long)i, "hidden");
  387.     bzero(pnt,i);
  388.   };
  389.   ymin_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  390.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  391.   ymax_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  392.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  393. }
  394.  
  395. /* Reset the hidden line data to a fresh start.                     */
  396. static void reset_hidden_line_removal()
  397. {
  398.     int i;
  399.     if(pnt){
  400.       for(i=0;i<=XREDUCE(xright)-XREDUCE(xleft);i++) {
  401.     if(pnt[i])
  402.       { free(pnt[i]); pnt[i] = 0;};
  403.       };
  404.     };
  405. }
  406.  
  407. /* Terminates the hidden line removal process. Free any memory allocated by  */
  408. /* init_hidden_line_removal above.                         */
  409. static void term_hidden_line_removal()
  410. {
  411.      if(pnt){
  412.        int j;
  413.        for(j=0;j<=XREDUCE(xright)-XREDUCE(xleft);j++) {
  414.      if(pnt[j])
  415.        { free(pnt[j]); pnt[j] = 0;};
  416.        };
  417.        free(pnt);
  418.        pnt = 0;
  419.      };
  420.    free(ymin_hl);
  421.    free(ymax_hl);
  422. }
  423. #endif /* not LITE */
  424.  
  425. /* Test a single point to be within the xleft,xright,ybot,ytop bbox.
  426.  * Sets the returned integers 4 l.s.b. as follows:
  427.  * bit 0 if to the left of xleft.
  428.  * bit 1 if to the right of xright.
  429.  * bit 2 if above of ytop.
  430.  * bit 3 if below of ybot.
  431.  * 0 is returned if inside.
  432.  */
  433. static int clip_point(x, y)
  434. int x, y;
  435. {
  436.     int ret_val = 0;
  437.  
  438.     if (x < xleft) ret_val |= 0x01;
  439.     if (x > xright) ret_val |= 0x02;
  440.     if (y < ybot) ret_val |= 0x04;
  441.     if (y > ytop) ret_val |= 0x08;
  442.  
  443.     return ret_val;
  444. }
  445.  
  446.  
  447. /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
  448.  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
  449.  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  450.  */
  451. static void draw_clip_line(x1, y1, x2, y2)
  452. int x1, y1, x2, y2;
  453. {
  454.     int x, y, dx, dy, x_intr[2], y_intr[2], count, pos1, pos2;
  455.     register struct termentry *t = &term_tbl[term];
  456.  
  457.     pos1 = clip_point(x1, y1);
  458.     pos2 = clip_point(x2, y2);
  459.     if (pos1 || pos2) {
  460.     if (pos1 & pos2) return;          /* segment is totally out. */
  461.  
  462.     /* Here part of the segment MAY be inside. test the intersection
  463.      * of this segment with the 4 boundaries for hopefully 2 intersections
  464.      * in. If non found segment is totaly out.
  465.      */
  466.     count = 0;
  467.     dx = x2 - x1;
  468.     dy = y2 - y1;
  469.  
  470.     /* Find intersections with the x parallel bbox lines: */
  471.     if (dy != 0) {
  472.         x = (ybot - y2) * dx / dy + x2;        /* Test for ybot boundary. */
  473.         if (x >= xleft && x <= xright) {
  474.         x_intr[count] = x;
  475.         y_intr[count++] = ybot;
  476.         }
  477.         x = (ytop - y2) * dx / dy + x2;        /* Test for ytop boundary. */
  478.         if (x >= xleft && x <= xright) {
  479.         x_intr[count] = x;
  480.         y_intr[count++] = ytop;
  481.         }
  482.     }
  483.  
  484.     /* Find intersections with the y parallel bbox lines: */
  485.     if (dx != 0) {
  486.         y = (xleft - x2) * dy / dx + y2;      /* Test for xleft boundary. */
  487.         if (y >= ybot && y <= ytop) {
  488.         x_intr[count] = xleft;
  489.         y_intr[count++] = y;
  490.         }
  491.         y = (xright - x2) * dy / dx + y2;    /* Test for xright boundary. */
  492.         if (y >= ybot && y <= ytop) {
  493.         x_intr[count] = xright;
  494.         y_intr[count++] = y;
  495.         }
  496.     }
  497.  
  498.     if (count == 2) {
  499.         int x_max, x_min, y_max, y_min;
  500.  
  501.         x_min = min(x1, x2);
  502.         x_max = max(x1, x2);
  503.         y_min = min(y1, y2);
  504.         y_max = max(y1, y2);
  505.  
  506.         if (pos1 && pos2) {               /* Both were out - update both */
  507.         x1 = x_intr[0];
  508.         y1 = y_intr[0];
  509.         x2 = x_intr[1];
  510.         y2 = y_intr[1];
  511.         }
  512.         else if (pos1) {           /* Only x1/y1 was out - update only it */
  513.         if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
  514.             x1 = x_intr[0];
  515.             y1 = y_intr[0];
  516.         }
  517.         else {
  518.             x1 = x_intr[1];
  519.             y1 = y_intr[1];
  520.         }
  521.         }
  522.         else {                      /* Only x2/y2 was out - update only it */
  523.         if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - x1) > 0) {
  524.             x2 = x_intr[0];
  525.             y2 = y_intr[0];
  526.         }
  527.         else {
  528.             x2 = x_intr[1];
  529.             y2 = y_intr[1];
  530.         }
  531.         }
  532.  
  533.         if (x1 < x_min || x1 > x_max ||
  534.         x2 < x_min || x2 > x_max ||
  535.         y1 < y_min || y1 > y_max ||
  536.         y2 < y_min || y2 > y_max) return;
  537.     }
  538.     else
  539.         return;
  540.     }
  541.  
  542. #ifndef LITE
  543.     if(hidden3d && draw_surface)
  544.       {
  545.     char flag;
  546.     register int xv, yv, errx, erry, err;
  547.     register int xvr, yvr;
  548.     int xve, yve;
  549.     register int dy, nstep, dyr;
  550.     int i;
  551.     if (x1 > x2){
  552.       xvr = x2;
  553.       yvr = y2;
  554.       xve = x1;
  555.       yve = y1;
  556.     } else {
  557.       xvr = x1;
  558.       yvr = y1;
  559.       xve = x2;
  560.       yve = y2;
  561.     };
  562.     errx = XREDUCE(xve) - XREDUCE(xvr);
  563.     erry = YREDUCE(yve) - YREDUCE(yvr);
  564.     dy = (erry > 0 ? 1 : -1);
  565.     dyr = dy*yfact;
  566.     switch (dy){
  567.     case 1:
  568.       nstep = errx + erry;
  569.       errx = -errx;
  570.       break;
  571.     case -1:
  572.       nstep = errx - erry;
  573.       errx = -errx;
  574.       erry = -erry;
  575.       break;
  576.     };
  577.     err = errx + erry;
  578.     errx <<= 1;
  579.     erry <<= 1;
  580.     xv = XREDUCE(xvr) - XREDUCE(xleft);
  581.     yv = YREDUCE(yvr) - YREDUCE(ybot);
  582.     (*t->move)(xvr,yvr);
  583.     if( !IFSET(xv,yv) ) flag = 0;
  584.     else flag = 1;
  585.     if(!hidden_no_update){ /* Check first point */
  586.       if (xv < xmin_hl) xmin_hl = xv;
  587.       if (xv > xmax_hl) xmax_hl = xv;
  588.       if (yv > ymax_hl[xv]) ymax_hl[xv] = yv;
  589.       if (yv < ymin_hl[xv]) ymin_hl[xv] = yv;
  590.     };
  591.     for (i=0;i<nstep;i++){
  592.       if (err < 0){
  593.         xv ++;
  594.         xvr += xfact;
  595.         err += erry;
  596.       } else {
  597.         yv += dy;
  598.         yvr += dyr;
  599.         err += errx;
  600.       };
  601.       if( !IFSET(xv,yv)){
  602.         if(flag != 0) {(*t->move)(xvr,yvr); flag = 0;};
  603.       } else {
  604.         if(flag == 0) {(*t->vector)(xvr,yvr); flag = 1;};
  605.       };
  606.       if(!hidden_no_update){
  607.         if (xv < xmin_hl) xmin_hl = xv;
  608.         if (xv > xmax_hl) xmax_hl = xv;
  609.         if (yv > ymax_hl[xv]) ymax_hl[xv] = yv;
  610.         if (yv < ymin_hl[xv]) ymin_hl[xv] = yv;
  611.       };
  612.     };
  613.     if (flag == 0) (*t->vector)(xve, yve);
  614.     return;
  615.       };
  616. #endif /* not LITE */
  617.     if(!suppressMove) (*t->move)(x1,y1);
  618.     (*t->vector)(x2,y2);
  619. }
  620.  
  621. /* Two routine to emulate move/vector sequence using line drawing routine. */
  622. static int move_pos_x, move_pos_y;
  623.  
  624. static void clip_move(x,y)
  625. int x,y;
  626. {
  627.     move_pos_x = x;
  628.     move_pos_y = y;
  629. }
  630.  
  631. static void clip_vector(x,y)
  632. int x,y;
  633. {
  634.     draw_clip_line(move_pos_x,move_pos_y, x, y);
  635.     move_pos_x = x;
  636.     move_pos_y = y;
  637. }
  638.  
  639. /* And text clipping routine. */
  640. static void clip_put_text(x, y, str)
  641. int x,y;
  642. char *str;
  643. {
  644.     register struct termentry *t = &term_tbl[term];
  645.  
  646.     if (clip_point(x, y)) return;
  647.  
  648.     (*t->put_text)(x,y,str);
  649. }
  650.  
  651. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  652.  * macro, so I write it as a function on that machine.
  653.  */
  654. #ifndef sun386
  655. /* (DFK) Use 10^x if logscale is in effect, else x */
  656. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  657. #else
  658. static double
  659. CheckLog(is_log, base_log, x)
  660.      TBOOLEAN is_log;
  661.      double base_log;
  662.      double x;
  663. {
  664.   if (is_log)
  665.     return(pow(base_log, x));
  666.   else
  667.     return(x);
  668. }
  669. #endif /* sun386 */
  670.  
  671. static double
  672. LogScale(coord, is_log, log_base_log, what, axis)
  673.     double coord;            /* the value */
  674.     TBOOLEAN is_log;            /* is this axis in logscale? */
  675.     double log_base_log;        /* if so, the log of its base */
  676.     char *what;            /* what is the coord for? */
  677.     char *axis;            /* which axis is this for ("x" or "y")? */
  678. {
  679.     if (is_log) {
  680.        if (coord <= 0.0) {
  681.           char errbuf[100];        /* place to write error message */
  682.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  683.                 what, axis, coord);
  684.           (*term_tbl[term].text)();
  685.           (void) fflush(outfile);
  686.           int_error(errbuf, NO_CARET);
  687.        } else
  688.         return(log(coord)/log_base_log);
  689.     }
  690.     return(coord);
  691. }
  692.  
  693. /* borders of plotting area */
  694. /* computed once on every call to do_plot */
  695. static boundary3d(scaling)
  696.     TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  697. {
  698.     register struct termentry *t = &term_tbl[term];
  699.     /* luecken@udel.edu modifications
  700.        sizes the plot to take up more of available resolution */
  701.     xleft = (t->h_char)*2 + (t->h_tic);
  702.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  703.     ybot = (t->v_char)*5/2 + 1;
  704.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*5/2 - 1;
  705.     xmiddle = (xright + xleft) / 2;
  706.     ymiddle = (ytop + ybot) / 2;
  707.     xscaler = (xright - xleft) * 3 / 5;
  708.     yscaler = (ytop - ybot) * 3 / 5;
  709. }
  710.  
  711. static double dbl_raise(x,y)
  712. double x;
  713. int y;
  714. {
  715. register int i;
  716. double val;
  717.  
  718.     val = 1.0;
  719.     for (i=0; i < abs(y); i++)
  720.         val *= x;
  721.     if (y < 0 ) return (1.0/val);
  722.     return(val);
  723. }
  724.  
  725.  
  726. static double make_3dtics(tmin,tmax,axis,logscale, base_log)
  727. double tmin,tmax;
  728. int axis;
  729. TBOOLEAN logscale;
  730. double base_log;
  731. {
  732. int len,x1,y1,x2,y2;
  733. register double xr,xnorm,tics,tic,l10;
  734.  
  735.     xr = fabs(tmin-tmax);
  736.  
  737.     /* Compute length of axis in screen space coords. */
  738.     switch (axis) {
  739.         case 'x':
  740.             map3d_xy(tmin,0.0,0.0,&x1,&y1);
  741.             map3d_xy(tmax,0.0,0.0,&x2,&y2);
  742.             break;
  743.         case 'y':
  744.             map3d_xy(0.0,tmin,0.0,&x1,&y1);
  745.             map3d_xy(0.0,tmax,0.0,&x2,&y2);
  746.             break;
  747.         case 'z':
  748.             map3d_xy(0.0,0.0,tmin,&x1,&y1);
  749.             map3d_xy(0.0,0.0,tmax,&x2,&y2);
  750.             break;
  751.     }
  752.  
  753.     if (((long) (x1-x2))*(x1-x2) + ((long) (y1-y2))*(y1-y2) <
  754.         sqr(3L * term_tbl[term].h_char))
  755.         return -1.0;                              /* No tics! */
  756.  
  757.     l10 = log10(xr);
  758.     if (logscale) {
  759.         tic = dbl_raise(base_log,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  760.         if (tic < 1.0)
  761.             tic = 1.0;
  762.     } else {
  763.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  764.         if (xnorm <= 5)
  765.             tics = 0.5;
  766.         else tics = 1.0;
  767.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  768.     }
  769.     return(tic);
  770. }
  771.  
  772. do_3dplot(plots, pcount, min_x, max_x, min_y, max_y, min_z, max_z)
  773. struct surface_points *plots;
  774. int pcount;            /* count of plots in linked list */
  775. double min_x, max_x;
  776. double min_y, max_y;
  777. double min_z, max_z;
  778. {
  779. register struct termentry *t = &term_tbl[term];
  780. register int surface, xaxis_y, yaxis_x;
  781. register struct surface_points *this_plot;
  782. int xl, yl, linetypeOffset = 0;
  783.             /* only a Pyramid would have this many registers! */
  784. double xtemp, ytemp, ztemp, temp;
  785. struct text_label *this_label;
  786. struct arrow_def *this_arrow;
  787. TBOOLEAN scaling;
  788. transform_matrix mat;
  789.  
  790. /* Initiate transformation matrix using the global view variables. */
  791.     mat_rot_z(surface_rot_z, trans_mat);
  792.     mat_rot_x(surface_rot_x, mat);
  793.     mat_mult(trans_mat, trans_mat, mat);
  794.     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
  795.     mat_mult(trans_mat, trans_mat, mat);
  796.  
  797. /* modify min_z/max_z so it will zscale properly. */
  798.     ztemp = (max_z - min_z) / (2.0 * surface_zscale);
  799.     temp = (max_z + min_z) / 2.0;
  800.     min_z = temp - ztemp;
  801.     max_z = temp + ztemp;
  802.  
  803. /* store these in variables global to this file */
  804. /* otherwise, we have to pass them around a lot */
  805.     x_min3d = min_x;
  806.     x_max3d = max_x;
  807.     y_min3d = min_y;
  808.     y_max3d = max_y;
  809.     z_min3d = min_z;
  810.     z_max3d = max_z;
  811.  
  812.     /* The extrema need to be set even when a surface is not being
  813.      * drawn.   Without this, gnuplot used to assume that the X and
  814.      * Y axis started at zero.   -RKC
  815.      */
  816.  
  817.     /* find (bottom) left corner of grid */
  818.     min_sx_ox = min_x;
  819.     min_sx_oy = min_y;
  820.     /* find bottom (right) corner of grid */
  821.     min_sy_ox = max_x;
  822.     min_sy_oy = min_y;
  823.  
  824.  
  825.     if (polar)
  826.     int_error("Cannot splot in polar coordinate system.", NO_CARET);
  827.  
  828.     if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
  829.     x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
  830.     y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
  831.         int_error("all points undefined!", NO_CARET);
  832.  
  833.     /* If we are to draw the bottom grid make sure zmin is updated properly. */
  834.     if (xtics || ytics || grid)
  835.     z_min3d -= (max_z - min_z) * ticslevel;
  836.  
  837. /*  This used be x_max3d == x_min3d, but that caused an infinite loop once. */
  838.     if (fabs(x_max3d - x_min3d) < zero)
  839.     int_error("x_min3d should not equal x_max3d!",NO_CARET);
  840.     if (fabs(y_max3d - y_min3d) < zero)
  841.     int_error("y_min3d should not equal y_max3d!",NO_CARET);
  842.     if (fabs(z_max3d - z_min3d) < zero)
  843.     int_error("z_min3d should not equal z_max3d!",NO_CARET);
  844.  
  845. #ifndef LITE
  846.     if (hidden3d) {
  847.     struct surface_points *plot;
  848.   
  849.         /* Verify data is hidden line removable - grid based. */
  850.           for (plot = plots; plot != NULL; plot = plot->next_sp) {
  851.          if (plot->plot_type == DATA3D && !plot->has_grid_topology){
  852.           fprintf(stderr,"Notice: Cannot remove hidden lines from non grid data\n");
  853.               return(0);
  854.             }
  855.     
  856.         }
  857.     }
  858. #endif /* not LITE */
  859.  
  860. /* INITIALIZE TERMINAL */
  861.     if (!term_init) {
  862.     (*t->init)();
  863.     term_init = TRUE;
  864.     }
  865.     screen_ok = FALSE;
  866.     scaling = (*t->scale)(xsize, ysize);
  867.     (*t->graphics)();
  868.  
  869.     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  870.     boundary3d(scaling);
  871.  
  872. /* SCALE FACTORS */
  873.     zscale3d = 2.0/(z_max3d - z_min3d);
  874.     yscale3d = 2.0/(y_max3d - y_min3d);
  875.     xscale3d = 2.0/(x_max3d - x_min3d);
  876.  
  877.     (*t->linetype)(-2); /* border linetype */
  878.  
  879. /* PLACE TITLE */
  880.     if (*title != 0) {
  881.         int x, y;
  882.  
  883.         x = title_xoffset * t->h_char;
  884.         y = title_yoffset * t->v_char;
  885.  
  886.         if ((*t->justify_text)(CENTRE)) 
  887.             (*t->put_text)(x+(xleft+xright)/2, 
  888.                        y+ytop+(t->v_char), title);
  889.         else
  890.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  891.                        y+ytop+(t->v_char), title);
  892.     }
  893.  
  894. /* PLACE TIMEDATE */
  895.     if (timedate) {
  896.         int x, y;
  897.  
  898.         x = time_xoffset * t->h_char;
  899.         y = time_yoffset * t->v_char;
  900.         dated = time( (time_t *) 0);
  901.         tdate = ctime( &dated);
  902.         tdate[24]='\0';
  903.         if ((*t->text_angle)(1)) {
  904.             if ((*t->justify_text)(CENTRE)) {
  905.                 (*t->put_text)(x+(t->v_char),
  906.                          y+ybot+4*(t->v_char), tdate);
  907.             }
  908.             else {
  909.                 (*t->put_text)(x+(t->v_char),
  910.                          y+ybot+4*(t->v_char)-(t->h_char)*strlen(ylabel)/2, 
  911.                          tdate);
  912.             }
  913.         }
  914.         else {
  915.             (void)(*t->justify_text)(LEFT);
  916.             (*t->put_text)(x,
  917.                          y+ybot-3*(t->v_char), tdate);
  918.         }
  919.         (void)(*t->text_angle)(0);
  920.     }
  921.  
  922. /* PLACE LABELS */
  923.     for (this_label = first_label; this_label!=NULL;
  924.             this_label=this_label->next ) {
  925.         int x,y;
  926.  
  927.         xtemp = LogScale(this_label->x, is_log_x, log_base_log_x, "label", "x");
  928.         ytemp = LogScale(this_label->y, is_log_y, log_base_log_y, "label", "y");
  929.         ztemp = LogScale(this_label->z, is_log_z, log_base_log_z, "label", "z");
  930.             map3d_xy(xtemp,ytemp,ztemp, &x, &y);
  931.  
  932.         if ((*t->justify_text)(this_label->pos)) {
  933.             (*t->put_text)(x,y,this_label->text);
  934.         }
  935.         else {
  936.             switch(this_label->pos) {
  937.                 case  LEFT:
  938.                     (*t->put_text)(x,y,this_label->text);
  939.                     break;
  940.                 case CENTRE:
  941.                     (*t->put_text)(x -
  942.                         (t->h_char)*strlen(this_label->text)/2,
  943.                         y, this_label->text);
  944.                     break;
  945.                 case RIGHT:
  946.                     (*t->put_text)(x -
  947.                         (t->h_char)*strlen(this_label->text),
  948.                         y, this_label->text);
  949.                     break;
  950.             }
  951.          }
  952.      }
  953.  
  954. /* PLACE ARROWS */
  955.     (*t->linetype)(0);    /* arrow line type */
  956.     for (this_arrow = first_arrow; this_arrow!=NULL;
  957.         this_arrow = this_arrow->next ) {
  958.     int sx,sy,ex,ey;
  959.  
  960.     xtemp = LogScale(this_arrow->sx, is_log_x, log_base_log_x, "arrow", "x");
  961.     ytemp = LogScale(this_arrow->sy, is_log_y, log_base_log_y, "arrow", "y");
  962.     ztemp = LogScale(this_arrow->sz, is_log_z, log_base_log_z, "arrow", "z");
  963.     map3d_xy(xtemp,ytemp,ztemp, &sx, &sy);
  964.  
  965.     xtemp = LogScale(this_arrow->ex, is_log_x, log_base_log_x, "arrow", "x");
  966.     ytemp = LogScale(this_arrow->ey, is_log_y, log_base_log_y, "arrow", "y");
  967.     ztemp = LogScale(this_arrow->ez, is_log_z, log_base_log_z, "arrow", "z");
  968.     map3d_xy(xtemp,ytemp,ztemp, &ex, &ey);
  969.  
  970.     (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  971.     }
  972.  
  973. #ifndef LITE
  974.     if (hidden3d && draw_surface) {
  975.     init_hidden_line_removal();
  976.     reset_hidden_line_removal();
  977.     hidden_active = TRUE;
  978.     }
  979. #endif /* not LITE */
  980.  
  981. /* DRAW SURFACES AND CONTOURS */
  982.     real_z_min3d = min_z;
  983.     real_z_max3d = max_z;
  984.     if (key == -1) {
  985.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  986.         yl = ytop - (t->v_tic) - (t->v_char);
  987.     }
  988.     if (key == 1) {
  989.         xtemp = LogScale(key_x, is_log_x, log_base_log_x, "key", "x");
  990.         ytemp = LogScale(key_y, is_log_y, log_base_log_y, "key", "y");
  991.         ztemp = LogScale(key_z, is_log_z, log_base_log_z, "key", "z");
  992.         map3d_xy(xtemp,ytemp,ztemp, &xl, &yl);
  993.     }
  994.  
  995. #ifndef LITE
  996.     if (hidden3d && draw_surface) plot3d_hidden(plots,pcount);
  997. #endif /* not LITE */
  998.     this_plot = plots;
  999.     for (surface = 0;
  1000.          surface < pcount;
  1001.          this_plot = this_plot->next_sp, surface++) {
  1002. #ifndef LITE
  1003.         if ( hidden3d )
  1004.             hidden_no_update = FALSE;
  1005. #endif /* not LITE */
  1006.  
  1007.         if (draw_surface) {
  1008.             (*t->linetype)(this_plot->line_type);
  1009. #ifndef LITE
  1010.             if (hidden3d) {
  1011.             hidden_line_type_above = this_plot->line_type;
  1012.             hidden_line_type_below = this_plot->line_type + 1;
  1013.             }
  1014. #endif /* not LITE */            
  1015.             if (key != 0 && this_plot->title) {
  1016.             if ((*t->justify_text)(RIGHT)) {
  1017.                 clip_put_text(xl,
  1018.                       yl,this_plot->title);
  1019.             }
  1020.             else {
  1021.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1022.                     xleft, xright))
  1023.                 clip_put_text(xl-(t->h_char)*strlen(this_plot->title),
  1024.                           yl,this_plot->title);
  1025.             }
  1026.             }
  1027.             
  1028.             switch(this_plot->plot_style) {
  1029.                 case BOXES: /* can't do boxes in 3d yet so use impulses */
  1030.                 case IMPULSES: {
  1031.                 if (key != 0 && this_plot->title) {
  1032.                 clip_move(xl+(t->h_char),yl);
  1033.                 clip_vector(xl+4*(t->h_char),yl);
  1034.                 }
  1035.                 if (!(hidden3d && draw_surface))
  1036.                   plot3d_impulses(this_plot);
  1037.                 break;
  1038.             }
  1039.             case LINES: {
  1040.                 if (key != 0 && this_plot->title) {
  1041.                 clip_move(xl+(int)(t->h_char),yl);
  1042.                 clip_vector(xl+(int)(4*(t->h_char)),yl);
  1043.                 }
  1044.                 if (!(hidden3d && draw_surface))
  1045.                   plot3d_lines(this_plot);
  1046.                 break;
  1047.             }
  1048.             case ERRORBARS:    /* ignored; treat like points */
  1049.             case POINTSTYLE: {
  1050.                 if (key != 0 && this_plot->title 
  1051.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1052.                 (*t->point)(xl+2*(t->h_char),yl,
  1053.                         this_plot->point_type);
  1054.                 }
  1055.                 if (!(hidden3d && draw_surface))
  1056.                   plot3d_points(this_plot);
  1057.                 break;
  1058.             }
  1059.             case LINESPOINTS: {
  1060.                 /* put lines */
  1061.                 if (key != 0 && this_plot->title) {
  1062.                 clip_move(xl+(t->h_char),yl);
  1063.                 clip_vector(xl+4*(t->h_char),yl);
  1064.                 }
  1065.                  if (!(hidden3d && draw_surface))
  1066.                    plot3d_lines(this_plot);
  1067.             
  1068.                 /* put points */
  1069.                 if (key != 0 && this_plot->title 
  1070.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1071.                 (*t->point)(xl+2*(t->h_char),yl,
  1072.                         this_plot->point_type);
  1073.                 }
  1074.                 if (!(hidden3d && draw_surface))
  1075.                   plot3d_points(this_plot);
  1076.                 break;
  1077.             }
  1078.             case DOTS: {
  1079.                 if (key != 0 && this_plot->title
  1080.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1081.                 (*t->point)(xl+2*(t->h_char),yl, -1);
  1082.                 }
  1083.                 if (!(hidden3d && draw_surface))
  1084.                   plot3d_dots(this_plot);
  1085.                 break;
  1086.             }
  1087.             }
  1088.             if (key != 0 && this_plot->title)
  1089.                 yl = yl - (t->v_char);
  1090.         }
  1091.  
  1092. #ifndef LITE
  1093.         if ( hidden3d ) {
  1094.             hidden_no_update = TRUE;
  1095.             hidden_line_type_above = this_plot->line_type + (hidden3d ? 2 : 1);
  1096.             hidden_line_type_below = this_plot->line_type + (hidden3d ? 2 : 1);
  1097.         }
  1098. #endif /* not LITE */
  1099.  
  1100.         if (draw_contour && this_plot->contours != NULL) {
  1101.             struct gnuplot_contours *cntrs = this_plot->contours;
  1102.  
  1103.             (*t->linetype)(this_plot->line_type + (hidden3d ? 2 : 1));
  1104.  
  1105.             if (key != 0 && this_plot->title) {
  1106.                 if ((*t->justify_text)(RIGHT)) {
  1107.                     clip_put_text(xl,
  1108.                         yl,this_plot->title);
  1109.                 }
  1110.                 else {
  1111.                     if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1112.                              xleft, xright))
  1113.                      clip_put_text(xl-(t->h_char)*strlen(this_plot->title),
  1114.                                  yl,this_plot->title);
  1115.                 }
  1116.                 switch(this_plot->plot_style) {
  1117.                     case IMPULSES:
  1118.                         clip_move(xl+(t->h_char),yl);
  1119.                         clip_vector(xl+4*(t->h_char),yl);
  1120.                         break;
  1121.                     case LINES:
  1122.                         clip_move(xl+(int)(t->h_char),yl);
  1123.                         clip_vector(xl+(int)(4*(t->h_char)),yl);
  1124.                         break;
  1125.                     case ERRORBARS: /* ignored; treat like points */
  1126.                     case POINTSTYLE:
  1127.                         if (!clip_point(xl+2*(t->h_char),yl)) {
  1128.                              (*t->point)(xl+2*(t->h_char),yl,
  1129.                                     this_plot->point_type);
  1130.                         }
  1131.                         break;
  1132.                     case LINESPOINTS:
  1133.                         clip_move(xl+(int)(t->h_char),yl);
  1134.                         clip_vector(xl+(int)(4*(t->h_char)),yl);
  1135.                         break;
  1136.                     case DOTS:
  1137.                         if (!clip_point(xl+2*(t->h_char),yl)) {
  1138.                              (*t->point)(xl+2*(t->h_char),yl, -1);
  1139.                         }
  1140.                         break;
  1141.                 }
  1142.             }
  1143.              linetypeOffset = this_plot->line_type + (hidden3d ? 2 : 1);
  1144.             while (cntrs) {
  1145.                  if(label_contours && cntrs->isNewLevel) {
  1146.                      (*t->linetype)(linetypeOffset++);
  1147. #ifndef LITE
  1148.                      if(hidden3d) hidden_line_type_below = hidden_line_type_above = linetypeOffset-1;
  1149. #endif /* not LITE */
  1150.                      yl -= (t->v_char);
  1151.                      if ((*t->justify_text)(RIGHT)) {
  1152.                         clip_put_text(xl,
  1153.                             yl,cntrs->label);
  1154.                     }
  1155.                     else {
  1156.                         if (inrange(xl-(t->h_char)*strlen(cntrs->label),
  1157.                                  xleft, xright))
  1158.                          clip_put_text(xl-(t->h_char)*strlen(cntrs->label),
  1159.                                      yl,cntrs->label);
  1160.                     }
  1161.                     switch(this_plot->plot_style) {
  1162.                         case IMPULSES:
  1163.                             clip_move(xl+(t->h_char),yl);
  1164.                             clip_vector(xl+4*(t->h_char),yl);
  1165.                             break;
  1166.                         case LINES:
  1167.                             clip_move(xl+(int)(t->h_char),yl);
  1168.                             clip_vector(xl+(int)(4*(t->h_char)),yl);
  1169.                             break;
  1170.                         case ERRORBARS: /* ignored; treat like points */
  1171.                         case POINTSTYLE:
  1172.                             if (!clip_point(xl+2*(t->h_char),yl)) {
  1173.                                  (*t->point)(xl+2*(t->h_char),yl,
  1174.                                         this_plot->point_type);
  1175.                             }
  1176.                             break;
  1177.                         case LINESPOINTS:
  1178.                             clip_move(xl+(int)(t->h_char),yl);
  1179.                             clip_vector(xl+(int)(4*(t->h_char)),yl);
  1180.                             break;
  1181.                         case DOTS:
  1182.                             if (!clip_point(xl+2*(t->h_char),yl)) {
  1183.                                  (*t->point)(xl+2*(t->h_char),yl, -1);
  1184.                             }
  1185.                             break;
  1186.                     }
  1187.                  }
  1188.                 switch(this_plot->plot_style) {
  1189.                     case IMPULSES:
  1190.                            cntr3d_impulses(cntrs, this_plot);
  1191.                         break;
  1192.                     case LINES:
  1193.                         cntr3d_lines(cntrs);
  1194.                         break;
  1195.                     case ERRORBARS: /* ignored; treat like points */
  1196.                     case POINTSTYLE:
  1197.                         cntr3d_points(cntrs, this_plot);
  1198.                         break;
  1199.                     case LINESPOINTS:
  1200.                         cntr3d_lines(cntrs);
  1201.                         cntr3d_points(cntrs, this_plot);
  1202.                         break;
  1203.                     case DOTS:
  1204.                         cntr3d_dots(cntrs);
  1205.                         break;
  1206.                 }
  1207.                 cntrs = cntrs->next;
  1208.             }
  1209.             if (key != 0 && this_plot->title)
  1210.               yl = yl - (t->v_char);
  1211.         }
  1212.  
  1213.         if (surface == 0)
  1214.             draw_bottom_grid(this_plot,real_z_min3d,real_z_max3d);
  1215.     }
  1216.     (*t->text)();
  1217.     (void) fflush(outfile);
  1218.  
  1219. #ifndef LITE
  1220.     if (hidden3d) {
  1221.         term_hidden_line_removal();
  1222.         hidden_active = FALSE;
  1223.     }
  1224. #endif /* not LITE */
  1225. }
  1226.  
  1227. /* plot3d_impulses:
  1228.  * Plot the surfaces in IMPULSES style
  1229.  */
  1230. static plot3d_impulses(plot)
  1231.     struct surface_points *plot;
  1232. {
  1233.     int i;                /* point index */
  1234.     int x,y,x0,y0;            /* point in terminal coordinates */
  1235.     struct termentry *t = &term_tbl[term];
  1236.     struct iso_curve *icrvs = plot->iso_crvs;
  1237.  
  1238.     while ( icrvs ) {
  1239.     struct coordinate GPHUGE *points = icrvs->points;
  1240.  
  1241.     for (i = 0; i < icrvs->p_count; i++) {
  1242.         if (real_z_max3d<points[i].z)
  1243.         real_z_max3d=points[i].z;
  1244.         if (real_z_min3d>points[i].z)
  1245.         real_z_min3d=points[i].z;
  1246.  
  1247.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1248.         map3d_xy(points[i].x, points[i].y, z_min3d, &x0, &y0);
  1249.  
  1250.         clip_move(x0,y0);
  1251.         clip_vector(x,y);
  1252.     }
  1253.  
  1254.     icrvs = icrvs->next;
  1255.     }
  1256. }
  1257.  
  1258. /* plot3d_lines:
  1259.  * Plot the surfaces in LINES style
  1260.  */
  1261. /* We want to always draw the lines in the same direction, otherwise when
  1262.    we draw an adjacent box we might get the line drawn a little differently
  1263.    and we get splotches.  */
  1264.  
  1265. #ifndef LITE
  1266.  
  1267. static int zsort( r1, r2)
  1268. int * r1;
  1269. int * r2;
  1270. {
  1271.   int z1, z2;
  1272.   z1 = nodes[*r1].z;
  1273.   z2 = nodes[*r2].z;
  1274.   if (z1 < z2) return 1;
  1275.   if (z1 == z2) return 0;
  1276.   return -1;
  1277. }
  1278. #define TESTBOX(X,Y)                    \
  1279.   if(X<xmin_box) xmin_box = X;                \
  1280.   if(X>xmax_box) xmax_box = X;                \
  1281.   if(Y<ymin_box) ymin_box = Y;                \
  1282.   if(Y>ymax_box) ymax_box = Y;
  1283. /* Usefull macro to help us figure out which side of the surface we are on */
  1284. #define XPRD(I,J,K)                     \
  1285.   ((nodes[I].x-nodes[J].x)*(nodes[J].y-nodes[K].y) -    \
  1286.   (nodes[I].y-nodes[J].y)*(nodes[J].x-nodes[K].x))
  1287. #define MAYBE_LINEPOINT(J)                        \
  1288.     if((nodes[J].flag & 0x20) != 0) {                \
  1289.       x = nodes[J].x;                        \
  1290.       y = nodes[J].y;                        \
  1291.       nodes[J].flag -= 0x20;                    \
  1292.       if (!clip_point(x,y) &&                     \
  1293.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot))) \
  1294.     (*t->point)(x,y, plot_info[nplot].point_type);        \
  1295.     };
  1296.  
  1297. struct surface_plots{
  1298.   int above_color;
  1299.   int below_color;
  1300.   int row_offset;
  1301.   int point_type;
  1302. };
  1303. /* All of the plots coming into this routine are assumed to have grid
  1304.    topology.  */
  1305.  
  1306. static plot3d_hidden(plots, pcount)
  1307.      struct surface_points *plots;
  1308.      int pcount;
  1309. {
  1310.   struct surface_points *this_plot;
  1311.   long int i, j;
  1312.   int nplot;
  1313.   long int x,y,z ,nseg, ncrv, ncrv1;        /* point in terminal coordinates */
  1314. #ifdef AMIGA_SC_6_1
  1315.   unsigned short int * cpnt;
  1316. #else /* !AMIGA_SC_6_1 */
  1317.   short int * cpnt;
  1318. #endif /* !AMIGA_SC_6_1 */
  1319.   short int  mask1, mask2;
  1320.   long int indx1, indx2, k, m;
  1321.   short int xmin_box, xmax_box, ymin_box, ymax_box;
  1322.   struct surface_plots * plot_info;
  1323.   int row_offset, nnode;
  1324.   short int y_malloc, y_malloc_offset;  /* Amount of space we need for one vertical
  1325.                      row of bitmap, and byte offset of first
  1326.                      used element */
  1327.   struct termentry *t = &term_tbl[term];
  1328.   struct iso_curve *icrvs;
  1329.   int current_style = 0x7fff;  /* Current line style */
  1330.   int surface;
  1331.   nnode = 0;
  1332.   nseg = 0;
  1333.   nplot = 0;
  1334.   this_plot = plots;
  1335.  
  1336.   for (surface = 0;
  1337.        surface < pcount;
  1338.        this_plot = this_plot->next_sp, surface++) {
  1339.     nplot++;
  1340.     icrvs = plots->iso_crvs;
  1341.     icrvs = plots->iso_crvs;
  1342.     if(this_plot->plot_type == FUNC3D) {
  1343.         for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1344.  /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  1345.     };
  1346.     if(this_plot->plot_type == DATA3D)
  1347.        ncrv = this_plot->num_iso_read;
  1348.     nnode += ncrv * (this_plot->iso_crvs->p_count);
  1349. /*    for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1350.     nnode += ncrv * (this_plot->iso_crvs->p_count); */
  1351.     switch(this_plot->plot_style) {
  1352.     case ERRORBARS:
  1353.     case DOTS:
  1354.     case POINTSTYLE:
  1355.     case LINESPOINTS:
  1356.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  1357.       break;
  1358.     case LINES:
  1359.       nseg += (ncrv-1) * (this_plot->iso_crvs->p_count-1);
  1360.       break;
  1361.     case IMPULSES:
  1362.       /* There will be two nodes for each segment */
  1363.       nnode += ncrv * (this_plot->iso_crvs->p_count);
  1364.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  1365.       break;
  1366.     }
  1367.   };
  1368.   boxlist = (int *) alloc((unsigned long)sizeof(int)*nseg, "hidden");
  1369.   nodes = (struct pnts *) alloc((unsigned long)sizeof(struct pnts)*nnode, "hidden");
  1370.   plot_info = (struct surface_plots *) alloc((unsigned long)sizeof(struct surface_plots)*nplot,"hidden");
  1371.   nnode = 0;
  1372.   nseg = 0;
  1373.   nplot = 0;
  1374.   this_plot = plots;
  1375.   hidden_no_update = FALSE;
  1376.  
  1377.   if ( hidden3d && draw_surface)
  1378.     for (surface = 0;
  1379.      surface < pcount;
  1380.      this_plot = this_plot->next_sp, surface++) {
  1381.       (*t->linetype)(this_plot->line_type);
  1382.       hidden_line_type_above = this_plot->line_type;
  1383.         hidden_line_type_below = this_plot->line_type + 1;
  1384.     if(this_plot->plot_type == FUNC3D) {
  1385.       for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1386. /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  1387.     };
  1388.     if(this_plot->plot_type == DATA3D)
  1389.       ncrv = this_plot->num_iso_read;
  1390.       icrvs = this_plot->iso_crvs;
  1391.       ncrv1 = ncrv;
  1392.       ncrv = 0;
  1393.       while ( icrvs) {
  1394.     struct coordinate GPHUGE *points = icrvs->points;
  1395.     for (i = 0; i < icrvs->p_count; i++) {
  1396.       map3d_xy(points[i].x, points[i].y, points[i].z,&nodes[nnode].x,&nodes[nnode].y);
  1397.       nodes[nnode].z = map3d_z(points[i].x, points[i].y, points[i].z);
  1398.       nodes[nnode].flag = (i==0 ? 1 : 0) + (ncrv == 0 ? 2 : 0) +
  1399.         (i == icrvs->p_count-1 ? 4 : 0) + (ncrv == ncrv1-1 ? 8 : 0);
  1400.       nodes[nnode].nplot = nplot;
  1401.       nodes[nnode].style_used = -1000; /* indicates no style */
  1402.       switch(this_plot->plot_style) {
  1403.       case LINESPOINTS:
  1404.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  1405.           nodes[nnode].flag |= 0x30;
  1406.         else
  1407.           nodes[nnode].flag |= 0x20;
  1408.         boxlist[nseg++] = nnode++;
  1409.         break;
  1410.       case LINES:
  1411.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  1412.           {
  1413.         nodes[nnode].flag |= 0x10;
  1414.         boxlist[nseg++] = nnode++;
  1415.           }
  1416.         else
  1417.           nnode++;
  1418.         break;
  1419.       case ERRORBARS:
  1420.       case POINTSTYLE:
  1421.       case DOTS:
  1422.         nodes[nnode].flag |= 0x40;
  1423.         boxlist[nseg++] = nnode++;
  1424.         break;
  1425.       case IMPULSES:
  1426.         nodes[nnode].flag |= 0x80;
  1427.         boxlist[nseg++] = nnode++;
  1428.         map3d_xy(points[i].x, points[i].y, z_min3d, &nodes[nnode].x,&nodes[nnode].y);
  1429.         nodes[nnode].z = map3d_z(points[i].x, points[i].y, z_min3d);
  1430.         nnode++;
  1431.         break;
  1432.         break;
  1433.       }
  1434.     }
  1435.     icrvs = icrvs->next;
  1436.     ncrv++;
  1437.     if(ncrv == ncrv1) break;
  1438.       }
  1439.       /* Next we go through all of the boxes, and substitute the average z value
  1440.      for the box for the z value of the corner node */
  1441.       plot_info[nplot].above_color = this_plot->line_type;
  1442.       plot_info[nplot].below_color = this_plot->line_type+1;
  1443.       plot_info[nplot].point_type =
  1444.     ((this_plot->plot_style == DOTS) ? -1 : this_plot->point_type);
  1445.       plot_info[nplot++].row_offset = this_plot->iso_crvs->p_count;
  1446.     }
  1447.       for(i=0; i<nseg; i++){
  1448.     j = boxlist[i];
  1449.     if ((nodes[j].flag & 0x80) != 0) {
  1450.       nodes[j].z = (nodes[j].z < nodes[j+1].z ? nodes[j].z : nodes[j+1].z);
  1451.       continue;
  1452.     };
  1453.     if ((nodes[j].flag & 0x10) == 0) continue;
  1454.     row_offset = plot_info[nodes[j].nplot].row_offset;
  1455.     z = nodes[j].z;
  1456.     if (z < nodes[j+1].z) z = nodes[j+1].z;
  1457.     if (z < nodes[j+row_offset].z) z = nodes[j+row_offset].z;
  1458.     if (z < nodes[j+row_offset+1].z) z = nodes[j+row_offset+1].z;
  1459.       };
  1460.   qsort (boxlist, nseg, sizeof(int), zsort);
  1461.   y_malloc = (2+ (YREDUCE(ytop)>>4) - (YREDUCE(ybot)>>4))*sizeof(short int);
  1462.   for(i=0;i<=(XREDUCE(xright)-XREDUCE(xleft));i++) {
  1463.     ymin_hl[i] = 0x7fff; 
  1464.     ymax_hl[i] = 0;
  1465.   };
  1466.   for(i=0;i<nseg;i++) {
  1467.     j = boxlist[i];
  1468.     nplot = nodes[j].nplot;
  1469.     row_offset = plot_info[nplot].row_offset;
  1470.     if((nodes[j].flag & 0x40) != 0) {
  1471.       x = nodes[j].x;
  1472.       y = nodes[j].y;
  1473.       if (!clip_point(x,y) &&
  1474.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot)))
  1475.     (*t->point)(x,y, plot_info[nplot].point_type);
  1476.     };
  1477.     if((nodes[j].flag & 0x80) != 0) { /* impulses */
  1478.       clip_move(nodes[j].x,nodes[j].y);
  1479.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  1480.     };
  1481.     if((nodes[j].flag & 0x10) != 0) {
  1482. /* It is possible, and often profitable, to take a quick look and see
  1483.    if the current box is entirely obscured.  If this is the case we will
  1484.    not even bother testing this box any further.  */
  1485.       xmin_box = 0x7fff; 
  1486.       xmax_box = 0;
  1487.       ymin_box = 0x7fff; 
  1488.       ymax_box = 0;
  1489.       TESTBOX(nodes[j].x-xleft,nodes[j].y-ybot);
  1490.       TESTBOX(nodes[j+1].x-xleft,nodes[j+1].y-ybot);
  1491.       TESTBOX(nodes[j+row_offset].x-xleft,nodes[j+row_offset].y-ybot);
  1492.       TESTBOX(nodes[j+row_offset+1].x-xleft,nodes[j+row_offset+1].y-ybot);
  1493.       z=0;
  1494.       if(xmin_box < 0) xmin_box = 0;
  1495.       if(ymin_box < 0) ymin_box = 0;
  1496.       if(xmax_box > xright-xleft) xmax_box = xright-xleft;
  1497.       if(ymax_box > ytop-ybot) ymax_box = ytop-ybot;
  1498.       /* Now check bitmap.  These coordinates have not been reduced */
  1499.       if(xmin_box <= xmax_box && ymin_box <= ymax_box){
  1500.     ymin_box = YREDUCE(ymin_box);
  1501.     ymax_box = YREDUCE(ymax_box);
  1502.     xmin_box = XREDUCE(xmin_box);
  1503.     xmax_box = XREDUCE(xmax_box);
  1504.     indx1 = ymin_box >> 4;
  1505.     indx2 = ymax_box >> 4;
  1506.     mask1 = 0xffff << (ymin_box & 0x0f);
  1507.     mask2 = 0xffff >> (0x0f-(ymax_box & 0x0f));
  1508.     for(m=xmin_box;m<=xmax_box;m++) {
  1509.       if(pnt[m] == 0) {z++; break;};
  1510.       cpnt = pnt[m] + indx1;
  1511.       if(indx1 == indx2){
  1512.         if((*cpnt & mask1 & mask2) != (mask1 & mask2)) {z++; break;}
  1513.       } else {
  1514.         if((*cpnt++ & mask1) != mask1) {z++; break;}
  1515.         k = indx1+1;
  1516.         while (k != indx2) {
  1517.           if((unsigned short)*cpnt++ != 0xffff) {z++; break;}
  1518.           k++;
  1519.         };
  1520.         if((*cpnt++ & mask2) != mask2) {z++; break;}
  1521.       };
  1522.     };
  1523.       };
  1524.       /* z is 0 if all of the pixels used by the current box are already covered.
  1525.      No point in proceeding, so we just skip all further processing of this
  1526.      box. */
  1527.       if(!z) continue;
  1528.       /* Now we need to figure out whether we are looking at the top or the
  1529.      bottom of the square.  A simple cross product will tell us this.
  1530.      If the square is really distorted then this will not be accurate,
  1531.      but in such cases we would actually be seeing both sides at the same
  1532.      time.  We choose the vertex with the largest z component to
  1533.      take the cross product at.  */
  1534.       {
  1535.     int z1, z2 ,z3, z4;
  1536.     z1 = XPRD(j+row_offset,j,j+1);
  1537.     z2 = XPRD(j,j+1,j+1+row_offset);
  1538.     z3 = XPRD(j+1,j+row_offset+1,j+row_offset);
  1539.     z4 = XPRD(j+row_offset+1,j+row_offset,j);
  1540.     z=0;
  1541.     z += (z1 > 0 ? 1 : -1);
  1542.     z += (z2 > 0 ? 1 : -1);
  1543.     z += (z3 > 0 ? 1 : -1);
  1544.     z += (z4 > 0 ? 1 : -1);
  1545.     /* See if the box is uniformly one side or another. */
  1546.     if(z != 4 && z != -4) {
  1547. /* It isn't.  Now find the corner of the box with the largest z value that
  1548.    has already been plotted, and use the same style used for that node.  */
  1549.       k = -1000;
  1550.       x = -32768;
  1551.       if (nodes[j].z > x && nodes[j].style_used !=-1000) {
  1552.         k = nodes[j].style_used;
  1553.         x = nodes[j].z;
  1554.       };
  1555.       if (nodes[j+1].z > x && nodes[j+1].style_used !=-1000) {
  1556.         k = nodes[j+1].style_used;
  1557.         x = nodes[j+1].z;
  1558.       };
  1559.       if (nodes[j+row_offset+1].z > x && nodes[j+row_offset+1].style_used !=-1000) {
  1560.         k = nodes[j+row_offset+1].style_used;
  1561.         x = nodes[j+row_offset+1].z;
  1562.       };
  1563.       if (nodes[j+row_offset].z > x && nodes[j+row_offset].style_used !=-1000) {
  1564.         k = nodes[j+row_offset].style_used;
  1565.         x = nodes[j+row_offset].z;
  1566.       };
  1567.       if( k != -1000){
  1568.         z = 0; /* To defeat the logic to come.  */
  1569.         current_style = k;
  1570.         (*t->linetype)(current_style);
  1571.       };
  1572.     };
  1573.     /* If k == -1000 then no corner found.  I guess it does not matter.  */
  1574.       };
  1575.       if(z > 0 && current_style != plot_info[nplot].above_color) {
  1576.     current_style = plot_info[nplot].above_color;
  1577.     (*t->linetype)(current_style);
  1578.       };
  1579.       if(z < 0 && current_style != plot_info[nplot].below_color) {
  1580.     current_style = plot_info[nplot].below_color;
  1581.     (*t->linetype)(current_style);
  1582.       };
  1583.       xmin_hl = (sizeof(xleft) == 4 ? 0x7fffffff : 0x7fff ); 
  1584.       xmax_hl = 0;
  1585.       clip_move(nodes[j].x,nodes[j].y);
  1586.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  1587.       clip_vector(nodes[j+row_offset+1].x,nodes[j+row_offset+1].y);
  1588.       clip_vector(nodes[j+row_offset].x,nodes[j+row_offset].y);
  1589.       clip_vector(nodes[j].x,nodes[j].y);
  1590.       nodes[j].style_used = current_style;
  1591.       nodes[j+1].style_used = current_style;
  1592.       nodes[j+row_offset+1].style_used = current_style;
  1593.       nodes[j+row_offset].style_used = current_style;
  1594.       MAYBE_LINEPOINT(j);
  1595.       MAYBE_LINEPOINT(j+1);
  1596.       MAYBE_LINEPOINT(j+row_offset+1);
  1597.       MAYBE_LINEPOINT(j+row_offset);
  1598.       if( xmin_hl < 0 || xmax_hl > XREDUCE(xright)-XREDUCE(xleft))
  1599.     int_error("Logic error #3 in hidden line",NO_CARET);
  1600.       /* now mark the area as being filled in the bitmap.  These coordinates
  1601.          have already been reduced. */
  1602.       if (xmin_hl < xmax_hl)
  1603.     for(j=xmin_hl;j<=xmax_hl;j++) {
  1604.       if (ymin_hl[j] == 0x7fff) 
  1605.         int_error("Logic error #2 in hidden line",NO_CARET);
  1606.       if(pnt[j] == 0) {
  1607.         pnt[j] = (short int *) alloc((unsigned long)y_malloc,"hidden");
  1608.         bzero(pnt[j],y_malloc);
  1609.       };
  1610.       if(ymin_hl[j] < 0 || ymax_hl[j] > YREDUCE(ytop)-YREDUCE(ybot))
  1611.         int_error("Logic error #1 in hidden line",NO_CARET);
  1612. /* this shift is wordsize dependent */
  1613.       indx1 = ymin_hl[j] >> 4;
  1614.       indx2 = ymax_hl[j] >> 4;
  1615.       mask1 = 0xffff << (ymin_hl[j] & 0xf);
  1616.       mask2 = 0xffff >> (0xf-(ymax_hl[j] & 0xf));
  1617.       cpnt = pnt[j] + indx1;
  1618.       if(indx1 == indx2){
  1619.         *cpnt |= (mask1 & mask2);
  1620.       } else {
  1621.         *cpnt++ |= mask1;
  1622.         k = indx1+1;
  1623.         while (k != indx2) {
  1624.           *cpnt++ = 0xffff; 
  1625.           k++;
  1626.         };
  1627.         *cpnt |= mask2;
  1628.       };
  1629.       ymin_hl[j]=0x7fff; 
  1630.       ymax_hl[j]=0;
  1631.     };
  1632.     };
  1633.   };
  1634.   free(nodes);
  1635.   free(boxlist);
  1636.   free(plot_info);
  1637. }
  1638.  
  1639. #endif /* not LITE */
  1640.  
  1641. static plot3d_lines(plot)
  1642.     struct surface_points *plot;
  1643. {
  1644.     int i, iso_count, num_iso_lines;
  1645.     int x,y;                /* point in terminal coordinates */
  1646.     struct termentry *t = &term_tbl[term];
  1647.     struct iso_curve *icrvs = plot->iso_crvs,
  1648.        *first_row_icrv, *last_row_icrv, *first_col_icrv, *icrv;
  1649.     struct coordinate GPHUGE *points;
  1650.  
  1651. #ifndef LITE
  1652. /* These are handled elsewhere.  */
  1653.     if (plot->has_grid_topology && hidden3d)
  1654.     return(0);
  1655. #endif /* not LITE */
  1656.  
  1657.     while (icrvs) {
  1658.  
  1659.     for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
  1660.         if (real_z_max3d<points[i].z)
  1661.         real_z_max3d=points[i].z;
  1662.         if (real_z_min3d>points[i].z)
  1663.         real_z_min3d=points[i].z;
  1664.  
  1665.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1666.  
  1667.         if (i > 0)
  1668.         clip_vector(x,y);
  1669.         else
  1670.         clip_move(x,y);
  1671.     }
  1672.  
  1673.     icrvs = icrvs->next;
  1674.     }
  1675. }
  1676.  
  1677. /* plot3d_points:
  1678.  * Plot the surfaces in POINTSTYLE style
  1679.  */
  1680. static plot3d_points(plot)
  1681.     struct surface_points *plot;
  1682. {
  1683.     int i,x,y;
  1684.     struct termentry *t = &term_tbl[term];
  1685.     struct iso_curve *icrvs = plot->iso_crvs;
  1686.  
  1687.     while ( icrvs ) {
  1688.     struct coordinate GPHUGE *points = icrvs->points;
  1689.  
  1690.     for (i = 0; i < icrvs->p_count; i++) {
  1691.         if (real_z_max3d<points[i].z)
  1692.         real_z_max3d=points[i].z;
  1693.         if (real_z_min3d>points[i].z)
  1694.         real_z_min3d=points[i].z;
  1695.  
  1696.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1697.  
  1698.         if (!clip_point(x,y))
  1699.         (*t->point)(x,y, plot->point_type);
  1700.     }
  1701.  
  1702.     icrvs = icrvs->next;
  1703.     }
  1704. }
  1705.  
  1706. /* plot3d_dots:
  1707.  * Plot the surfaces in DOTS style
  1708.  */
  1709. static plot3d_dots(plot)
  1710.     struct surface_points *plot;
  1711. {
  1712.     int i,x,y;
  1713.     struct termentry *t = &term_tbl[term];
  1714.     struct iso_curve *icrvs = plot->iso_crvs;
  1715.  
  1716.     while ( icrvs ) {
  1717.     struct coordinate GPHUGE *points = icrvs->points;
  1718.  
  1719.         for (i = 0; i < icrvs->p_count; i++) {
  1720.         if (real_z_max3d<points[i].z)
  1721.         real_z_max3d=points[i].z;
  1722.         if (real_z_min3d>points[i].z)
  1723.             real_z_min3d=points[i].z;
  1724.  
  1725.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1726.  
  1727.             if (!clip_point(x,y))
  1728.         (*t->point)(x,y, -1);
  1729.         }
  1730.  
  1731.     icrvs = icrvs->next;
  1732.     }
  1733. }
  1734.  
  1735. /* cntr3d_impulses:
  1736.  * Plot a surface contour in IMPULSES style
  1737.  */
  1738. static cntr3d_impulses(cntr, plot)
  1739.     struct gnuplot_contours *cntr;
  1740.     struct surface_points *plot;
  1741. {
  1742.     int i,j,k;                /* point index */
  1743.     int x,y,x0,y0;            /* point in terminal coordinates */
  1744.     struct termentry *t = &term_tbl[term];
  1745.  
  1746.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1747.     for (i = 0; i < cntr->num_pts; i++) {
  1748.         if (real_z_max3d<cntr->coords[i].z)
  1749.         real_z_max3d=cntr->coords[i].z;
  1750.         if (real_z_min3d>cntr->coords[i].z)
  1751.         real_z_min3d=cntr->coords[i].z;
  1752.  
  1753.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1754.              &x, &y);
  1755.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1756.              &x0, &y0);
  1757.  
  1758.         clip_move(x0,y0);
  1759.         clip_vector(x,y);
  1760.     }
  1761.     }
  1762.     else
  1763.     cntr3d_points(cntr, plot);   /* Must be on base grid, so do points. */
  1764. }
  1765.  
  1766. /* cntr3d_lines:
  1767.  * Plot a surface contour in LINES style
  1768.  */
  1769. static cntr3d_lines(cntr)
  1770.     struct gnuplot_contours *cntr;
  1771. {
  1772.     int i,j,k;                /* point index */
  1773.     int x,y;                /* point in terminal coordinates */
  1774.     struct termentry *t = &term_tbl[term];
  1775.  
  1776.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1777.     for (i = 0; i < cntr->num_pts; i++) {
  1778.         if (real_z_max3d<cntr->coords[i].z)
  1779.         real_z_max3d=cntr->coords[i].z;
  1780.         if (real_z_min3d>cntr->coords[i].z)
  1781.         real_z_min3d=cntr->coords[i].z;
  1782.  
  1783.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1784.                  &x, &y);
  1785.  
  1786.              if (i > 0) {
  1787.                  clip_vector(x,y);
  1788.                  if(i == 1) suppressMove = TRUE;
  1789.              } else {
  1790.                  clip_move(x,y);
  1791.              }
  1792.         }
  1793.     }
  1794.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1795.  
  1796.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1797.     for (i = 0; i < cntr->num_pts; i++) {
  1798.         if (real_z_max3d<cntr->coords[i].z)
  1799.         real_z_max3d=cntr->coords[i].z;
  1800.         if (real_z_min3d>cntr->coords[i].z)
  1801.         real_z_min3d=cntr->coords[i].z;
  1802.  
  1803.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1804.                  &x, &y);
  1805.  
  1806.              if (i > 0) {
  1807.                  clip_vector(x,y);
  1808.                  if(i == 1) suppressMove = TRUE;
  1809.              } else {
  1810.                  clip_move(x,y);
  1811.              }
  1812.          }
  1813.      }
  1814.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1815. }
  1816.  
  1817. /* cntr3d_points:
  1818.  * Plot a surface contour in POINTSTYLE style
  1819.  */
  1820. static cntr3d_points(cntr, plot)
  1821.     struct gnuplot_contours *cntr;
  1822.     struct surface_points *plot;
  1823. {
  1824.     int i,j,k;
  1825.     int x,y;
  1826.     struct termentry *t = &term_tbl[term];
  1827.  
  1828.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1829.     for (i = 0; i < cntr->num_pts; i++) {
  1830.         if (real_z_max3d<cntr->coords[i].z)
  1831.         real_z_max3d=cntr->coords[i].z;
  1832.         if (real_z_min3d>cntr->coords[i].z)
  1833.         real_z_min3d=cntr->coords[i].z;
  1834.  
  1835.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1836.                  &x, &y);
  1837.  
  1838.         if (!clip_point(x,y))
  1839.         (*t->point)(x,y, plot->point_type);
  1840.         }
  1841.     }
  1842.  
  1843.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1844.     for (i = 0; i < cntr->num_pts; i++) {
  1845.         if (real_z_max3d<cntr->coords[i].z)
  1846.         real_z_max3d=cntr->coords[i].z;
  1847.         if (real_z_min3d>cntr->coords[i].z)
  1848.         real_z_min3d=cntr->coords[i].z;
  1849.  
  1850.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1851.                  &x, &y);
  1852.  
  1853.         if (!clip_point(x,y))
  1854.         (*t->point)(x,y, plot->point_type);
  1855.         }
  1856.     }
  1857. }
  1858.  
  1859. /* cntr3d_dots:
  1860.  * Plot a surface contour in DOTS style
  1861.  */
  1862. static cntr3d_dots(cntr)
  1863.     struct gnuplot_contours *cntr;
  1864. {
  1865.     int i,j,k;
  1866.     int x,y;
  1867.     struct termentry *t = &term_tbl[term];
  1868.  
  1869.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1870.     for (i = 0; i < cntr->num_pts; i++) {
  1871.         if (real_z_max3d<cntr->coords[i].z)
  1872.         real_z_max3d=cntr->coords[i].z;
  1873.         if (real_z_min3d>cntr->coords[i].z)
  1874.         real_z_min3d=cntr->coords[i].z;
  1875.  
  1876.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1877.                  &x, &y);
  1878.  
  1879.         if (!clip_point(x,y))
  1880.         (*t->point)(x,y, -1);
  1881.         }
  1882.     }
  1883.  
  1884.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1885.     for (i = 0; i < cntr->num_pts; i++) {
  1886.         if (real_z_max3d<cntr->coords[i].z)
  1887.         real_z_max3d=cntr->coords[i].z;
  1888.         if (real_z_min3d>cntr->coords[i].z)
  1889.         real_z_min3d=cntr->coords[i].z;
  1890.  
  1891.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1892.                  &x, &y);
  1893.  
  1894.         if (!clip_point(x,y))
  1895.         (*t->point)(x,y, -1);
  1896.         }
  1897.     }
  1898. }
  1899.  
  1900. static update_extrema_pts(ix, iy, min_sx_x, min_sx_y, min_sy_x, min_sy_y,
  1901.               x, y)
  1902.     int ix, iy, *min_sx_x, *min_sx_y, *min_sy_x, *min_sy_y;
  1903.     double x, y;
  1904. {
  1905.  
  1906.     if (*min_sx_x > ix + 2 ||         /* find (bottom) left corner of grid */
  1907.     (abs(*min_sx_x - ix) <= 2 && *min_sx_y > iy)) {
  1908.     *min_sx_x = ix;
  1909.     *min_sx_y = iy;
  1910.     min_sx_ox = x;
  1911.     min_sx_oy = y;
  1912.     }
  1913.     if (*min_sy_y > iy + 2 ||         /* find bottom (right) corner of grid */
  1914.     (abs(*min_sy_y - iy) <= 2 && *min_sy_x < ix)) {
  1915.     *min_sy_x = ix;
  1916.     *min_sy_y = iy;
  1917.     min_sy_ox = x;
  1918.     min_sy_oy = y;
  1919.     }
  1920. }
  1921.  
  1922. /* Draw the bottom grid for the parametric case. */
  1923. static draw_parametric_grid(plot)
  1924.     struct surface_points *plot;
  1925. {
  1926.     int i,ix,iy,            /* point in terminal coordinates */
  1927.     min_sx_x = 10000,min_sx_y = 10000,min_sy_x = 10000,min_sy_y = 10000,
  1928.         grid_iso_1 = plot->plot_type == DATA3D && plot->has_grid_topology ?
  1929.                     plot->iso_crvs->p_count : iso_samples_1,
  1930.         grid_iso_2 = plot->plot_type == DATA3D && plot->has_grid_topology ?
  1931.                     plot->num_iso_read : iso_samples_2;
  1932.     double x,y,dx,dy;
  1933.     struct termentry *t = &term_tbl[term];
  1934.  
  1935.     if (grid && plot->has_grid_topology) {
  1936.  
  1937.     /* fix grid lines to tic marks, D. Taber, 02-01-93 */
  1938.     if(xtics && xticdef.type == TIC_SERIES) {
  1939.         dx = xticdef.def.series.incr;
  1940.         x = xticdef.def.series.start;
  1941.         grid_iso_1 = 1 + (xticdef.def.series.end - x) / dx;
  1942.     } else {
  1943.         x = x_min3d;
  1944.     dx = (x_max3d-x_min3d) / (grid_iso_1-1);
  1945.     }
  1946.  
  1947.     if(ytics && yticdef.type == TIC_SERIES) {
  1948.         dy = yticdef.def.series.incr;
  1949.         y = yticdef.def.series.start;
  1950.         grid_iso_2 = 1 + (yticdef.def.series.end - y) / dy;
  1951.     } else {
  1952.         y = y_min3d;
  1953.     dy = (y_max3d-y_min3d) / (grid_iso_2-1);
  1954.     }
  1955.  
  1956.     for (i = 0; i < grid_iso_2; i++) {
  1957.             if (i == 0 || i == grid_iso_2-1)            
  1958.             setlinestyle(-2);
  1959.         else
  1960.             setlinestyle(-1);
  1961.         map3d_xy(x_min3d, y, z_min3d, &ix, &iy);
  1962.         clip_move(ix,iy);
  1963.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1964.                    &min_sy_x,&min_sy_y,x_min3d,y);
  1965.  
  1966.         map3d_xy(x_max3d, y, z_min3d, &ix, &iy);
  1967.         clip_vector(ix,iy);
  1968.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1969.                    &min_sy_x,&min_sy_y,x_max3d,y);
  1970.  
  1971.         y += dy;
  1972.     }
  1973.  
  1974.     for (i = 0; i < grid_iso_1; i++) {
  1975.             if (i == 0 || i == grid_iso_1-1)
  1976.             setlinestyle(-2);
  1977.         else
  1978.             setlinestyle(-1);
  1979.         map3d_xy(x, y_min3d, z_min3d, &ix, &iy);
  1980.         clip_move(ix,iy);
  1981.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1982.                    &min_sy_x,&min_sy_y,x,y_min3d);
  1983.  
  1984.         map3d_xy(x, y_max3d, z_min3d, &ix, &iy);
  1985.         clip_vector(ix,iy);
  1986.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1987.                    &min_sy_x,&min_sy_y,x,y_max3d);
  1988.  
  1989.         x += dx;
  1990.     }
  1991.     }
  1992.     else {
  1993.     setlinestyle(-2);
  1994.  
  1995.     map3d_xy(x_min3d, y_min3d, z_min3d, &ix, &iy);
  1996.     clip_move(ix,iy);
  1997.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  1998.                &min_sy_x,&min_sy_y,x_min3d,y_min3d);
  1999.  
  2000.     map3d_xy(x_max3d, y_min3d, z_min3d, &ix, &iy);
  2001.     clip_vector(ix,iy);
  2002.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2003.                &min_sy_x,&min_sy_y,x_max3d,y_min3d);
  2004.  
  2005.     map3d_xy(x_max3d, y_max3d, z_min3d, &ix, &iy);
  2006.     clip_vector(ix,iy);
  2007.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2008.                &min_sy_x,&min_sy_y,x_max3d,y_max3d);
  2009.  
  2010.     map3d_xy(x_min3d, y_max3d, z_min3d, &ix, &iy);
  2011.     clip_vector(ix,iy);
  2012.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2013.                &min_sy_x,&min_sy_y,x_min3d,y_max3d);
  2014.  
  2015.  
  2016.     map3d_xy(x_min3d, y_min3d, z_min3d, &ix, &iy);
  2017.     clip_vector(ix,iy);
  2018.     }
  2019. }
  2020.  
  2021. /* Draw the bottom grid for non parametric case. */
  2022. static draw_non_param_grid(plot)
  2023.     struct surface_points *plot;
  2024. {
  2025.     int i,is_boundary=TRUE,crv_count=0,
  2026.     x,y,                /* point in terminal coordinates */
  2027.     min_sx_x = 10000,min_sx_y = 10000,min_sy_x = 10000,min_sy_y = 10000,
  2028.         grid_iso = plot->plot_type == DATA3D && plot->has_grid_topology ?
  2029.                     plot->num_iso_read : iso_samples_2;
  2030.     struct termentry *t = &term_tbl[term];
  2031.     struct iso_curve *icrvs = plot->iso_crvs;
  2032.  
  2033.     while ( icrvs ) {
  2034.     struct coordinate GPHUGE *points = icrvs->points;
  2035.     int saved_hidden_active = hidden_active;
  2036.     int z1 = map3d_z(points[0].x, points[0].y, 0.0),
  2037.            z2 = map3d_z(points[icrvs->p_count-1].x,
  2038.                             points[icrvs->p_count-1].y, 0.0);
  2039.  
  2040.     for (i = 0; i < icrvs->p_count; i += icrvs->p_count-1) {
  2041.         map3d_xy(points[i].x, points[i].y, z_min3d, &x, &y);
  2042.         if (is_boundary) {
  2043.         setlinestyle(-2);
  2044.         }
  2045.         else {
  2046.             setlinestyle(-1);
  2047.         }
  2048.  
  2049.         if (i > 0) {
  2050.             clip_vector(x,y);
  2051.         }
  2052.         else {
  2053.             clip_move(x,y);
  2054.         }
  2055.  
  2056.         if (draw_surface &&
  2057.             is_boundary &&
  2058.             (i == 0 || i == icrvs->p_count-1)) {
  2059.             int x1,y1;            /* point in terminal coordinates */
  2060.  
  2061.         /* Draw a vertical line to surface corner from grid corner. */
  2062.             map3d_xy(points[i].x, points[i].y, points[i].z, &x1, &y1);
  2063. #ifndef LITE
  2064.             if (hidden3d) {
  2065.             if ((i == 0 && z1 > z2) ||
  2066.                 (i == icrvs->p_count-1 && z2 > z1)) {
  2067.                 hidden_active = FALSE; /* This one is always visible. */
  2068.             }                
  2069.             }
  2070. #endif /* not LITE */
  2071.             clip_vector(x1,y1);
  2072.             clip_move(x,y);
  2073.         hidden_active = saved_hidden_active;
  2074.         update_extrema_pts(x,y,&min_sx_x,&min_sx_y, &min_sy_x,&min_sy_y,
  2075.                    points[i].x,points[i].y);
  2076.         }
  2077.     }
  2078.  
  2079.     if (grid) {
  2080.         crv_count++;
  2081.         icrvs = icrvs->next;
  2082.         is_boundary = crv_count == grid_iso - 1 ||
  2083.               crv_count == grid_iso ||
  2084.               (icrvs && icrvs->next == NULL);
  2085.     }
  2086.     else {
  2087.         switch (crv_count++) {
  2088.         case 0:
  2089.             for (i = 0; i < grid_iso - 1; i++)
  2090.             icrvs = icrvs->next;
  2091.             break;
  2092.         case 1:
  2093.             icrvs = icrvs->next;
  2094.             break;
  2095.         case 2:
  2096.             while (icrvs->next)
  2097.             icrvs = icrvs->next;
  2098.             break;
  2099.         case 3:
  2100.             icrvs = NULL;
  2101.             break;
  2102.         }
  2103.         }
  2104.     }
  2105.     if(hidden3d){
  2106.       struct iso_curve *lcrvs = plot->iso_crvs;
  2107.       struct coordinate GPHUGE *points, GPHUGE *lpoints;
  2108.       icrvs = lcrvs;
  2109.       while(lcrvs->next) lcrvs = lcrvs->next;
  2110.       points = icrvs->points;
  2111.       lpoints = lcrvs->points;
  2112.       is_boundary = TRUE;
  2113.       for (i = 0; i < icrvs->p_count; i += (grid ? 1 : icrvs->p_count - 1)) {
  2114.     if ((i == 0) || (i == icrvs->p_count - 1)) {
  2115.       setlinestyle(-2);
  2116.     }
  2117.     else {
  2118.       setlinestyle(-1);
  2119.     }
  2120.     map3d_xy(points[i].x, points[i].y, z_min3d, &x, &y);
  2121.     clip_move(x, y);
  2122.     map3d_xy(lpoints[i].x, lpoints[i].y, z_min3d, &x, &y);
  2123.     clip_vector(x, y);
  2124.       };
  2125.     };
  2126. }
  2127.  
  2128. /* Draw the bottom grid that hold the tic marks for 3d surface. */
  2129. static draw_bottom_grid(plot, min_z, max_z)
  2130.     struct surface_points *plot;
  2131.     double min_z, max_z;
  2132. {
  2133.     int i,j,k;                /* point index */
  2134.     int x,y,min_x = 10000,min_y = 10000;/* point in terminal coordinates */
  2135.     double xtic,ytic,ztic;
  2136.     struct termentry *t = &term_tbl[term];
  2137.  
  2138.     xtic = make_3dtics(x_min3d,x_max3d,'x',is_log_x,base_log_x);
  2139.     ytic = make_3dtics(y_min3d,y_max3d,'y',is_log_y,base_log_y);
  2140.     ztic = make_3dtics(min_z,max_z,'z',is_log_z,base_log_z);
  2141.  
  2142.     if (draw_border)
  2143.     if (parametric || !plot->has_grid_topology)
  2144.         draw_parametric_grid(plot);
  2145.     else
  2146.         draw_non_param_grid(plot);
  2147.  
  2148.     setlinestyle(-2); /* border linetype */
  2149.  
  2150. /* label x axis tics */
  2151.     if (xtics && xtic > 0.0) {
  2152.         switch (xticdef.type) {
  2153.             case TIC_COMPUTED:
  2154.          if (x_min3d < x_max3d)
  2155.             draw_3dxtics(xtic * floor(x_min3d/xtic),
  2156.                      xtic,
  2157.                      xtic * ceil(x_max3d/xtic),
  2158.                      min_sy_oy);
  2159.                 else
  2160.             draw_3dxtics(xtic * floor(x_max3d/xtic),
  2161.                      xtic,
  2162.                      xtic * ceil(x_min3d/xtic),
  2163.                      min_sy_oy);
  2164.             break;
  2165.         case TIC_MONTH:
  2166.         draw_month_3dxtics(min_sy_oy);
  2167.         break;
  2168.         case TIC_DAY:
  2169.         draw_day_3dxtics(min_sy_oy);
  2170.         break;
  2171.         case TIC_SERIES:
  2172.         draw_series_3dxtics(xticdef.def.series.start, 
  2173.                     xticdef.def.series.incr, 
  2174.                     xticdef.def.series.end,
  2175.                     min_sy_oy);
  2176.         break;
  2177.         case TIC_USER:
  2178.         draw_set_3dxtics(xticdef.def.user,
  2179.                  min_sy_oy);
  2180.         break;
  2181.             default:
  2182.             (*t->text)();
  2183.             (void) fflush(outfile);
  2184.             int_error("unknown tic type in xticdef in do_3dplot", NO_CARET);
  2185.             break;        /* NOTREACHED */
  2186.         }
  2187.     }
  2188. /* label y axis tics */
  2189.     if (ytics && ytic > 0.0) {
  2190.         switch (yticdef.type) {
  2191.             case TIC_COMPUTED:
  2192.          if (y_min3d < y_max3d)
  2193.             draw_3dytics(ytic * floor(y_min3d/ytic),
  2194.                      ytic,
  2195.                      ytic * ceil(y_max3d/ytic),
  2196.                      min_sy_ox);
  2197.                 else
  2198.             draw_3dytics(ytic * floor(y_max3d/ytic),
  2199.                      ytic,
  2200.                      ytic * ceil(y_min3d/ytic),
  2201.                      min_sy_ox);
  2202.             break;
  2203.         case TIC_MONTH:
  2204.         draw_month_3dytics(min_sy_ox);
  2205.         break;
  2206.         case TIC_DAY:
  2207.         draw_day_3dytics(min_sy_ox);
  2208.         break;
  2209.         case TIC_SERIES:
  2210.         draw_series_3dytics(yticdef.def.series.start, 
  2211.                     yticdef.def.series.incr, 
  2212.                     yticdef.def.series.end,
  2213.                     min_sy_ox);
  2214.         break;
  2215.         case TIC_USER:
  2216.         draw_set_3dytics(yticdef.def.user,
  2217.                  min_sy_ox);
  2218.         break;
  2219.             default:
  2220.             (*t->text)();
  2221.             (void) fflush(outfile);
  2222.             int_error("unknown tic type in yticdef in do_3dplot", NO_CARET);
  2223.             break;        /* NOTREACHED */
  2224.         }
  2225.     }
  2226. /* label z axis tics */
  2227.     if (ztics && ztic > 0.0 && (draw_surface ||
  2228.                 draw_contour == CONTOUR_SRF ||
  2229.                 draw_contour == CONTOUR_BOTH)) {
  2230.         switch (zticdef.type) {
  2231.             case TIC_COMPUTED:
  2232.          if (min_z < max_z)
  2233.             draw_3dztics(ztic * floor(min_z/ztic),
  2234.                      ztic,
  2235.                      ztic * ceil(max_z/ztic),
  2236.                  min_sx_ox,
  2237.                      min_sx_oy,
  2238.                      min_z,
  2239.                  max_z);
  2240.                 else
  2241.             draw_3dztics(ztic * floor(max_z/ztic),
  2242.                      ztic,
  2243.                      ztic * ceil(min_z/ztic),
  2244.                      min_sx_ox,
  2245.                  min_sx_oy,
  2246.                      max_z,
  2247.                  min_z);
  2248.             break;
  2249.         case TIC_MONTH:
  2250.         draw_month_3dztics(min_sx_ox,min_sx_oy,min_z,max_z);
  2251.         break;
  2252.         case TIC_DAY:
  2253.         draw_day_3dztics(min_sx_ox,min_sx_oy,min_z,max_z);
  2254.         break;
  2255.         case TIC_SERIES:
  2256.         draw_series_3dztics(zticdef.def.series.start, 
  2257.                     zticdef.def.series.incr, 
  2258.                     zticdef.def.series.end,
  2259.                     min_sx_ox,
  2260.                     min_sx_oy,
  2261.                     min_z,
  2262.                     max_z);
  2263.  
  2264.         break;
  2265.         case TIC_USER:
  2266.         draw_set_3dztics(zticdef.def.user,
  2267.                  min_sx_ox,
  2268.                      min_sx_oy,
  2269.                      min_z,
  2270.                  max_z);
  2271.         break;
  2272.             default:
  2273.             (*t->text)();
  2274.             (void) fflush(outfile);
  2275.             int_error("unknown tic type in zticdef in do_3dplot", NO_CARET);
  2276.             break;        /* NOTREACHED */
  2277.         }
  2278.     }
  2279.  
  2280. /* PLACE XLABEL - along the middle grid X axis */
  2281.     if (strlen(xlabel) > 0) {
  2282.        int x1,y1;
  2283.        double step = apx_eq( min_sy_oy, y_min3d ) ?    (y_max3d-y_min3d)/4
  2284.                               : (y_min3d-y_max3d)/4;
  2285.            map3d_xy((x_min3d+x_max3d)/2,min_sy_oy-step, z_min3d,&x1,&y1);
  2286.        x1 += xlabel_xoffset * t->h_char;
  2287.        y1 += xlabel_yoffset * t->v_char;
  2288.        if ((*t->justify_text)(CENTRE))
  2289.         clip_put_text(x1,y1,xlabel);
  2290.        else
  2291.         clip_put_text(x1 - strlen(xlabel)*(t->h_char)/2,y1,xlabel);
  2292.     }
  2293.  
  2294. /* PLACE YLABEL - along the middle grid Y axis */
  2295.     if (strlen(ylabel) > 0) {
  2296.        int x1,y1;
  2297.        double step = apx_eq( min_sy_ox, x_min3d ) ?    (x_max3d-x_min3d)/4
  2298.                               : (x_min3d-x_max3d)/4;
  2299.            map3d_xy(min_sy_ox-step,(y_min3d+y_max3d)/2,z_min3d,&x1,&y1);
  2300.        x1 += ylabel_xoffset * t->h_char;
  2301.        y1 += ylabel_yoffset * t->v_char;
  2302.        if ((*t->justify_text)(CENTRE))
  2303.         clip_put_text(x1,y1,ylabel);
  2304.        else
  2305.         clip_put_text(x1 - strlen(ylabel)*(t->h_char)/2,y1,ylabel);
  2306.     }
  2307.  
  2308. /* PLACE ZLABEL - along the middle grid Z axis */
  2309.     if (strlen(zlabel) > 0 &&
  2310.         (draw_surface ||
  2311.      draw_contour == CONTOUR_SRF ||
  2312.      draw_contour == CONTOUR_BOTH)) {
  2313.            map3d_xy(min_sx_ox,min_sx_oy,max_z + (max_z-min_z)/4, &x, &y);
  2314.  
  2315.        x += zlabel_xoffset * t->h_char;
  2316.        y += zlabel_yoffset * t->v_char;
  2317.        if ((*t->justify_text)(CENTRE))
  2318.         clip_put_text(x,y,zlabel);
  2319.        else
  2320.         clip_put_text(x - strlen(zlabel)*(t->h_char)/2,y,zlabel);
  2321.     }
  2322. }
  2323.  
  2324. /* DRAW_3DXTICS: draw a regular tic series, x axis */
  2325. static draw_3dxtics(start, incr, end, ypos)
  2326.     double start, incr, end, ypos; /* tic series definition */
  2327.         /* assume start < end, incr > 0 */
  2328. {
  2329.     double ticplace;
  2330.     int ltic;        /* for mini log tics */
  2331.     double lticplace;    /* for mini log tics */
  2332.  
  2333.     end = end + SIGNIF*incr; 
  2334.  
  2335.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2336.         if (ticplace < x_min3d || ticplace > x_max3d) continue;
  2337.         xtick(ticplace, xformat, incr, 1.0, ypos);
  2338.         if (is_log_x && incr == 1.0) {
  2339.             /* add mini-ticks to log scale ticmarks */
  2340.             for (ltic = 2; ltic < (int)base_log_x; ltic++) {
  2341.                 lticplace = ticplace+log((double)ltic)/log_base_log_x;
  2342.                 xtick(lticplace, "\0", incr, 0.5, ypos);
  2343.             }
  2344.         }
  2345.     }
  2346. }
  2347.  
  2348. /* DRAW_3DYTICS: draw a regular tic series, y axis */
  2349. static draw_3dytics(start, incr, end, xpos)
  2350.     double start, incr, end, xpos; /* tic series definition */
  2351.         /* assume start < end, incr > 0 */
  2352. {
  2353.     double ticplace;
  2354.     int ltic;        /* for mini log tics */
  2355.     double lticplace;    /* for mini log tics */
  2356.  
  2357.     end = end + SIGNIF*incr; 
  2358.  
  2359.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2360.         if (ticplace < y_min3d || ticplace > y_max3d) continue;
  2361.         ytick(ticplace, yformat, incr, 1.0, xpos);
  2362.         if (is_log_y && incr == 1.0) {
  2363.             /* add mini-ticks to log scale ticmarks */
  2364.             for (ltic = 2; ltic < (int)base_log_y; ltic++) {
  2365.                 lticplace = ticplace+log((double)ltic)/log_base_log_y;
  2366.                 ytick(lticplace, "\0", incr, 0.5, xpos);
  2367.             }
  2368.         }
  2369.     }
  2370. }
  2371.  
  2372. /* DRAW_3DZTICS: draw a regular tic series, z axis */
  2373. static draw_3dztics(start, incr, end, xpos, ypos, z_min, z_max)
  2374.     double start, incr, end, xpos, ypos, z_min, z_max;
  2375.         /* assume start < end, incr > 0 */
  2376. {
  2377.     int x, y;
  2378.     double ticplace;
  2379.     int ltic;        /* for mini log tics */
  2380.     double lticplace;    /* for mini log tics */
  2381.     register struct termentry *t = &term_tbl[term];
  2382.  
  2383.     end = end + SIGNIF*incr; 
  2384.  
  2385.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2386.         if (ticplace < z_min || ticplace > z_max) continue;
  2387.  
  2388.         ztick(ticplace, zformat, incr, 1.0, xpos, ypos);
  2389.         if (is_log_z && incr == 1.0) {
  2390.             /* add mini-ticks to log scale ticmarks */
  2391.             for (ltic = 2; ltic < (int)base_log_z; ltic++) {
  2392.                 lticplace = ticplace+log((double)ltic)/log_base_log_z;
  2393.                 ztick(lticplace, "\0", incr, 0.5, xpos, ypos);
  2394.             }
  2395.         }
  2396.     }
  2397.  
  2398.     /* Make sure the vertical line is fully drawn. */
  2399.     setlinestyle(-2);    /* axis line type */
  2400.  
  2401.     map3d_xy(xpos, ypos, z_min3d, &x, &y);
  2402.     clip_move(x,y);
  2403.     map3d_xy(xpos, ypos, min(end,z_max)+(is_log_z ? incr : 0.0), &x, &y);
  2404.     clip_vector(x,y);
  2405.  
  2406.     setlinestyle(-1); /* border linetype */
  2407. }
  2408.  
  2409. /* DRAW_SERIES_3DXTICS: draw a user tic series, x axis */
  2410. static draw_series_3dxtics(start, incr, end, ypos)
  2411.         double start, incr, end, ypos; /* tic series definition */
  2412.         /* assume start < end, incr > 0 */
  2413. {
  2414.     double ticplace, place;
  2415.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2416.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  2417.  
  2418.     if (end == VERYLARGE)
  2419.         end = max(CheckLog(is_log_x, base_log_x, x_min3d),
  2420.               CheckLog(is_log_x, base_log_x, x_max3d));
  2421.     else
  2422.       /* limit to right side of plot */
  2423.       end = min(end, max(CheckLog(is_log_x, base_log_x, x_min3d),
  2424.                  CheckLog(is_log_x, base_log_x, x_max3d)));
  2425.  
  2426.     /* to allow for rounding errors */
  2427.     ticmin = min(x_min3d,x_max3d) - SIGNIF*incr;
  2428.     ticmax = max(x_min3d,x_max3d) + SIGNIF*incr;
  2429.     end = end + SIGNIF*incr; 
  2430.  
  2431.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2432.         place = (is_log_x ? log(ticplace)/log_base_log_x : ticplace);
  2433.         if ( inrange(place,ticmin,ticmax) )
  2434.          xtick(place, xformat, spacing, 1.0, ypos);
  2435.     }
  2436. }
  2437.  
  2438. /* DRAW_SERIES_3DYTICS: draw a user tic series, y axis */
  2439. static draw_series_3dytics(start, incr, end, xpos)
  2440.         double start, incr, end, xpos; /* tic series definition */
  2441.         /* assume start < end, incr > 0 */
  2442. {
  2443.     double ticplace, place;
  2444.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2445.     double spacing = is_log_y ? log(incr)/log_base_log_y : incr;
  2446.  
  2447.     if (end == VERYLARGE)
  2448.         end = max(CheckLog(is_log_y, base_log_y, y_min3d),
  2449.               CheckLog(is_log_y, base_log_y, y_max3d));
  2450.     else
  2451.       /* limit to right side of plot */
  2452.       end = min(end, max(CheckLog(is_log_y, base_log_y, y_min3d),
  2453.                  CheckLog(is_log_y, base_log_y, y_max3d)));
  2454.  
  2455.     /* to allow for rounding errors */
  2456.     ticmin = min(y_min3d,y_max3d) - SIGNIF*incr;
  2457.     ticmax = max(y_min3d,y_max3d) + SIGNIF*incr;
  2458.     end = end + SIGNIF*incr; 
  2459.  
  2460.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2461.         place = (is_log_y ? log(ticplace)/log_base_log_y : ticplace);
  2462.         if ( inrange(place,ticmin,ticmax) )
  2463.          ytick(place, xformat, spacing, 1.0, xpos);
  2464.     }
  2465. }
  2466.  
  2467. /* DRAW_SERIES_3DZTICS: draw a user tic series, z axis */
  2468. static draw_series_3dztics(start, incr, end, xpos, ypos, z_min, z_max)
  2469.         double start, incr, end; /* tic series definition */
  2470.         double xpos, ypos, z_min, z_max;
  2471.         /* assume start < end, incr > 0 */
  2472. {
  2473.     int x, y;
  2474.     double ticplace, place;
  2475.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2476.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  2477.     register struct termentry *t = &term_tbl[term];
  2478.  
  2479.     if (end == VERYLARGE)
  2480.         end = max(CheckLog(is_log_z, base_log_z, z_min),
  2481.               CheckLog(is_log_z, base_log_z, z_max));
  2482.     else
  2483.       /* limit to right side of plot */
  2484.       end = min(end, max(CheckLog(is_log_z, base_log_z, z_min),
  2485.                  CheckLog(is_log_z, base_log_z, z_max)));
  2486.  
  2487.     /* to allow for rounding errors */
  2488.     ticmin = min(z_min,z_max) - SIGNIF*incr;
  2489.     ticmax = max(z_min,z_max) + SIGNIF*incr;
  2490.     end = end + SIGNIF*incr; 
  2491.  
  2492.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2493.         place = (is_log_z ? log(ticplace)/log_base_log_z : ticplace);
  2494.         if ( inrange(place,ticmin,ticmax) )
  2495.          ztick(place, zformat, spacing, 1.0, xpos, ypos);
  2496.     }
  2497.  
  2498.     /* Make sure the vertical line is fully drawn. */
  2499.     setlinestyle(-2);    /* axis line type */
  2500.  
  2501.     map3d_xy(xpos, ypos, z_min3d, &x, &y);
  2502.     clip_move(x,y);
  2503.     map3d_xy(xpos, ypos, min(end,z_max)+(is_log_z ? incr : 0.0), &x, &y);
  2504.     clip_vector(x,y);
  2505.  
  2506.     setlinestyle(-1); /* border linetype */
  2507. }
  2508. extern char *month[];
  2509. extern char *day[];
  2510. draw_month_3dxtics(ypos)
  2511. double ypos;
  2512. {
  2513.     long l_ticplace,l_incr,l_end,m_calc;
  2514.  
  2515.     l_ticplace = (long)x_min3d;
  2516.     if((double)l_ticplace<x_min3d)l_ticplace++;
  2517.     l_end=(long)x_max3d;
  2518.     l_incr=(l_end-l_ticplace)/12;
  2519.     if(l_incr<1)l_incr=1;
  2520.     while(l_ticplace<=l_end)
  2521.     {    m_calc=(l_ticplace-1)%12;
  2522.     if(m_calc<0)m_calc += 12;
  2523.     xtick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,ypos);
  2524.     l_ticplace += l_incr;
  2525.     }
  2526. }
  2527. draw_month_3dytics(xpos)
  2528. double xpos;
  2529. {
  2530.     long l_ticplace,l_incr,l_end,m_calc;
  2531.  
  2532.     l_ticplace = (long)y_min3d;
  2533.     if((double)l_ticplace<y_min3d)l_ticplace++;
  2534.     l_end=(long)y_max3d;
  2535.     l_incr=(l_end-l_ticplace)/12;
  2536.     if(l_incr<1)l_incr=1;
  2537.     while(l_ticplace<=l_end)
  2538.     {    m_calc=(l_ticplace-1)%12;
  2539.     if(m_calc<0)m_calc += 12;
  2540.     ytick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,xpos);
  2541.     l_ticplace += l_incr;
  2542.     }
  2543. }
  2544. draw_month_3dztics(xpos,ypos,z_min3d,z_max3d)
  2545. double xpos,ypos,z_min3d,z_max3d;
  2546. {
  2547.     long l_ticplace,l_incr,l_end,m_calc;
  2548.  
  2549.     l_ticplace = (long)z_min3d;
  2550.     if((double)l_ticplace<z_min3d)l_ticplace++;
  2551.     l_end=(long)z_max3d;
  2552.     l_incr=(l_end-l_ticplace)/12;
  2553.     if(l_incr<1)l_incr=1;
  2554.     while(l_ticplace<=l_end)
  2555.     {    m_calc=(l_ticplace-1)%12;
  2556.     if(m_calc<0)m_calc += 12;
  2557.     ztick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,xpos,ypos);
  2558.     l_ticplace += l_incr;
  2559.     }
  2560. }
  2561. draw_day_3dxtics(ypos)
  2562. double ypos;
  2563. {
  2564.     long l_ticplace,l_incr,l_end,m_calc;
  2565.  
  2566.     l_ticplace = (long)x_min3d;
  2567.     if((double)l_ticplace<x_min3d)l_ticplace++;
  2568.     l_end=(long)x_max3d;
  2569.     l_incr=(l_end-l_ticplace)/14;
  2570.     if(l_incr<1)l_incr=1;
  2571.     while(l_ticplace<=l_end)
  2572.     {    m_calc=l_ticplace%7;
  2573.     if(m_calc<0)m_calc += 7;
  2574.     xtick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,ypos);
  2575.     l_ticplace += l_incr;
  2576.     }
  2577. }
  2578. draw_day_3dytics(xpos)
  2579. double xpos;
  2580. {
  2581.     long l_ticplace,l_incr,l_end,m_calc;
  2582.  
  2583.     l_ticplace = (long)y_min3d;
  2584.     if((double)l_ticplace<y_min3d)l_ticplace++;
  2585.     l_end=(long)y_max3d;
  2586.     l_incr=(l_end-l_ticplace)/14;
  2587.     if(l_incr<1)l_incr=1;
  2588.     while(l_ticplace<=l_end)
  2589.     {    m_calc=l_ticplace%7;
  2590.     if(m_calc<0)m_calc += 7;
  2591.     ytick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,xpos);
  2592.     l_ticplace += l_incr;
  2593.     }
  2594. }
  2595. draw_day_3dztics(xpos,ypos,z_min3d,z_max3d)
  2596. double xpos,ypos,z_min3d,z_max3d;
  2597. {
  2598.     long l_ticplace,l_incr,l_end,m_calc;
  2599.  
  2600.     l_ticplace = (long)z_min3d;
  2601.     if((double)l_ticplace<z_min3d)l_ticplace++;
  2602.     l_end=(long)z_max3d;
  2603.     l_incr=(l_end-l_ticplace)/14;
  2604.     if(l_incr<1)l_incr=1;
  2605.     while(l_ticplace<=l_end)
  2606.     {    m_calc=l_ticplace%7;
  2607.     if(m_calc<0)m_calc += 7;
  2608.     ztick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,xpos,ypos);
  2609.     l_ticplace += l_incr;
  2610.     }
  2611. }
  2612. /* DRAW_SET_3DXTICS: draw a user tic set, x axis */
  2613. static draw_set_3dxtics(list, ypos)
  2614.     struct ticmark *list;    /* list of tic marks */
  2615.     double ypos;
  2616. {
  2617.     double ticplace;
  2618.     double incr = (x_max3d - x_min3d) / 10;
  2619.     /* global x_min3d, x_max3d, xscale, y_min3d, y_max3d, yscale */
  2620.  
  2621.     while (list != NULL) {
  2622.        ticplace = (is_log_x ? log(list->position)/log_base_log_x
  2623.                 : list->position);
  2624.        if ( inrange(ticplace, x_min3d, x_max3d)         /* in range */
  2625.           || NearlyEqual(ticplace, x_min3d, incr)    /* == x_min */
  2626.           || NearlyEqual(ticplace, x_max3d, incr))    /* == x_max */
  2627.         xtick(ticplace, list->label, incr, 1.0, ypos);
  2628.  
  2629.        list = list->next;
  2630.     }
  2631. }
  2632.  
  2633. /* DRAW_SET_3DYTICS: draw a user tic set, y axis */
  2634. static draw_set_3dytics(list, xpos)
  2635.     struct ticmark *list;    /* list of tic marks */
  2636.     double xpos;
  2637. {
  2638.     double ticplace;
  2639.     double incr = (y_max3d - y_min3d) / 10;
  2640.     /* global x_min3d, x_max3d, xscale, y_min3d, y_max3d, yscale */
  2641.  
  2642.     while (list != NULL) {
  2643.        ticplace = (is_log_y ? log(list->position)/log_base_log_y
  2644.                 : list->position);
  2645.        if ( inrange(ticplace, y_min3d, y_max3d)           /* in range */
  2646.           || NearlyEqual(ticplace, y_min3d, incr)    /* == y_min3d */
  2647.           || NearlyEqual(ticplace, y_max3d, incr))    /* == y_max3d */
  2648.         ytick(ticplace, list->label, incr, 1.0, xpos);
  2649.  
  2650.        list = list->next;
  2651.     }
  2652. }
  2653.  
  2654. /* DRAW_SET_3DZTICS: draw a user tic set, z axis */
  2655. static draw_set_3dztics(list, xpos, ypos, z_min, z_max)
  2656.     struct ticmark *list;    /* list of tic marks */
  2657.     double xpos, ypos, z_min, z_max;
  2658. {
  2659.     int x, y;
  2660.     double ticplace;
  2661.     double incr = (z_max - z_min) / 10;
  2662.     register struct termentry *t = &term_tbl[term];
  2663.  
  2664.     while (list != NULL) {
  2665.        ticplace = (is_log_z ? log(list->position)/log_base_log_z
  2666.                 : list->position);
  2667.        if ( inrange(ticplace, z_min, z_max)         /* in range */
  2668.           || NearlyEqual(ticplace, z_min, incr)        /* == z_min */
  2669.           || NearlyEqual(ticplace, z_max, incr))    /* == z_max */
  2670.         ztick(ticplace, list->label, incr, 1.0, xpos, ypos);
  2671.  
  2672.        list = list->next;
  2673.     }
  2674.  
  2675.     /* Make sure the vertical line is fully drawn. */
  2676.     setlinestyle(-2);    /* axis line type */
  2677.  
  2678.     map3d_xy(xpos, ypos, z_min, &x, &y);
  2679.     clip_move(x,y);
  2680.     map3d_xy(xpos, ypos, z_max+(is_log_z ? incr : 0.0), &x, &y);
  2681.     clip_vector(x,y);
  2682.  
  2683.     setlinestyle(-1); /* border linetype */
  2684. }
  2685.  
  2686. /* draw and label a x-axis ticmark */
  2687. static xtick(place, text, spacing, ticscale, ypos)
  2688.         double place;                   /* where on axis to put it */
  2689.         char *text;                     /* optional text label */
  2690.         double spacing;         /* something to use with checkzero */
  2691.         double ticscale;         /* scale factor for tic mark (0..1] */
  2692.     double ypos;
  2693. {
  2694.     register struct termentry *t = &term_tbl[term];
  2695.     char ticlabel[101];
  2696.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2697.     int ticsize = (int)((t->h_tic) * ticscale);
  2698.     double v[2], len;
  2699.  
  2700.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2701.  
  2702.     if (place > x_max3d || place < x_min3d) return(0);
  2703.  
  2704.     map3d_xy(place, ypos, z_min3d, &x0, &y0);
  2705.     /* need to figure out which is in. pick the middle point along the */
  2706.     /* axis as in.                               */
  2707.     map3d_xy(place, (y_max3d + y_min3d) / 2, z_min3d, &x1, &y1);
  2708.  
  2709.     /* compute a vector of length 1 into the grid: */
  2710.     v[0] = x1 - x0;
  2711.     v[1] = y1 - y0;
  2712.     len = sqrt(v[0] * v[0] + v[1] * v[1]);
  2713.     if (len == 0.0) return;
  2714.     v[0] /= len;
  2715.     v[1] /= len;
  2716.  
  2717.     if (tic_in) {
  2718.     x1 = x0;
  2719.     y1 = y0;
  2720.     x2 = x1 + ((int) (v[0] * ticsize));
  2721.     y2 = y1 + ((int) (v[1] * ticsize));
  2722.         x3 = x0 - ((int) (v[0] * ticsize * 3)); /* compute text position */
  2723.         y3 = y0 - ((int) (v[1] * ticsize * 3));
  2724.     } else {
  2725.     x1 = x0;
  2726.     y1 = y0;
  2727.     x2 = x0 - ((int) (v[0] * ticsize));
  2728.     y2 = y0 - ((int) (v[1] * ticsize));
  2729.         x3 = x0 - ((int) (v[0] * ticsize * 4)); /* compute text position */
  2730.         y3 = y0 - ((int) (v[1] * ticsize * 4));
  2731.     }
  2732.     clip_move(x1,y1);
  2733.     clip_vector(x2,y2);
  2734.  
  2735.     /* label the ticmark */
  2736.     if (text == NULL)
  2737.      text = xformat;
  2738.  
  2739.     (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, place));
  2740.     if (apx_eq(v[0], 0.0)) {
  2741.         if ((*t->justify_text)(CENTRE)) {
  2742.             clip_put_text(x3,y3,ticlabel);
  2743.         } else {
  2744.             clip_put_text(x3-(t->h_char)*strlen(ticlabel)/2,y3,ticlabel);
  2745.         }
  2746.     }
  2747.     else if (v[0] > 0) {
  2748.         if ((*t->justify_text)(RIGHT)) {
  2749.             clip_put_text(x3,y3,ticlabel);
  2750.         } else {
  2751.             clip_put_text(x3-(t->h_char)*strlen(ticlabel),y3,ticlabel);
  2752.         }
  2753.     } else {
  2754.         (*t->justify_text)(LEFT);
  2755.     clip_put_text(x3,y3,ticlabel);
  2756.     }
  2757. }
  2758.  
  2759. /* draw and label a y-axis ticmark */
  2760. static ytick(place, text, spacing, ticscale, xpos)
  2761.         double place;                   /* where on axis to put it */
  2762.         char *text;                     /* optional text label */
  2763.         double spacing;         /* something to use with checkzero */
  2764.         double ticscale;         /* scale factor for tic mark (0..1] */
  2765.     double xpos;
  2766. {
  2767.     register struct termentry *t = &term_tbl[term];
  2768.     char ticlabel[101];
  2769.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2770.     int ticsize = (int)((t->h_tic) * ticscale);
  2771.     double v[2], len;
  2772.  
  2773.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2774.  
  2775.     if (place > y_max3d || place < y_min3d) return(0);
  2776.  
  2777.     map3d_xy(xpos, place, z_min3d, &x0, &y0);
  2778.     /* need to figure out which is in. pick the middle point along the */
  2779.     /* axis as in.                               */
  2780.     map3d_xy((x_max3d + x_min3d) / 2, place, z_min3d, &x1, &y1);
  2781.  
  2782.     /* compute a vector of length 1 into the grid: */
  2783.     v[0] = x1 - x0;
  2784.     v[1] = y1 - y0;
  2785.     len = sqrt(v[0] * v[0] + v[1] * v[1]);
  2786.     if (len == 0.0) return;
  2787.     v[0] /= len;
  2788.     v[1] /= len;
  2789.  
  2790.     if (tic_in) {
  2791.     x1 = x0;
  2792.     y1 = y0;
  2793.     x2 = x1 + ((int) (v[0] * ticsize));
  2794.     y2 = y1 + ((int) (v[1] * ticsize));
  2795.         x3 = x0 - ((int) (v[0] * ticsize * 3)); /* compute text position */
  2796.         y3 = y0 - ((int) (v[1] * ticsize * 3));
  2797.     } else {
  2798.     x1 = x0;
  2799.     y1 = y0;
  2800.     x2 = x0 - ((int) (v[0] * ticsize));
  2801.     y2 = y0 - ((int) (v[1] * ticsize));
  2802.         x3 = x0 - ((int) (v[0] * ticsize * 4)); /* compute text position */
  2803.         y3 = y0 - ((int) (v[1] * ticsize * 4));
  2804.     }
  2805.     clip_move(x1,y1);
  2806.     clip_vector(x2,y2);
  2807.  
  2808.     /* label the ticmark */
  2809.     if (text == NULL)
  2810.      text = yformat;
  2811.  
  2812.     (void) sprintf(ticlabel, text, CheckLog(is_log_y, base_log_y, place));
  2813.     if (apx_eq(v[0], 0.0)) {
  2814.         if ((*t->justify_text)(CENTRE)) {
  2815.             clip_put_text(x3,y3,ticlabel);
  2816.         } else {
  2817.             clip_put_text(x3-(t->h_char)*strlen(ticlabel)/2,y3,ticlabel);
  2818.         }
  2819.     }
  2820.     else if (v[0] > 0) {
  2821.         if ((*t->justify_text)(RIGHT)) {
  2822.             clip_put_text(x3,y3,ticlabel);
  2823.         } else {
  2824.             clip_put_text(x3-(t->h_char)*strlen(ticlabel),y3,ticlabel);
  2825.         }
  2826.     } else {
  2827.         (*t->justify_text)(LEFT);
  2828.     clip_put_text(x3,y3,ticlabel);
  2829.     }
  2830. }
  2831.  
  2832. /* draw and label a z-axis ticmark */
  2833. static ztick(place, text, spacing, ticscale, xpos, ypos)
  2834.         double place;                   /* where on axis to put it */
  2835.         char *text;                     /* optional text label */
  2836.         double spacing;         /* something to use with checkzero */
  2837.         double ticscale;         /* scale factor for tic mark (0..1] */
  2838.     double xpos, ypos;
  2839. {
  2840.     register struct termentry *t = &term_tbl[term];
  2841.     char ticlabel[101];
  2842.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2843.     int ticsize = (int)((t->h_tic) * ticscale);
  2844.  
  2845.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2846.  
  2847.     map3d_xy(xpos, ypos, place, &x0, &y0);
  2848.  
  2849.     if (tic_in) {
  2850.     x1 = x0;
  2851.     y1 = y0;
  2852.     x2 = x0 + ticsize;
  2853.     y2 = y0;
  2854.         x3 = x0 - ticsize;
  2855.         y3 = y0;
  2856.     } else {
  2857.     x1 = x0;
  2858.     y1 = y0;
  2859.     x2 = x0 - ticsize;
  2860.     y2 = y0;
  2861.         x3 = x0 - ticsize * 2; /* compute text position */
  2862.         y3 = y0;
  2863.     }
  2864.     clip_move(x1,y1);
  2865.     clip_vector(x2,y2);
  2866.  
  2867.     /* label the ticmark */
  2868.     if (text == NULL)
  2869.      text = zformat;
  2870.  
  2871.     (void) sprintf(ticlabel, text, CheckLog(is_log_z, base_log_z, place));
  2872.     if ((*t->justify_text)(RIGHT)) {
  2873.         clip_put_text(x3,y3,ticlabel);
  2874.     } else {
  2875.         clip_put_text(x3-(t->h_char)*(strlen(ticlabel)+1),y3,ticlabel);
  2876.     }
  2877. }
  2878.