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

Annotation of OpenXM_contrib/gnuplot/hidden3d.c, Revision 1.1.1.2

1.1       maekawa     1: #ifndef lint
1.1.1.2 ! maekawa     2: static char *RCSid = "$Id: hidden3d.c,v 1.13.2.1 1999/08/19 14:39:28 lhecking Exp $";
1.1       maekawa     3: #endif
                      4:
                      5: /* GNUPLOT - hidden3d.c */
                      6:
                      7: /*[
                      8:  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
                      9:  *
                     10:  * Permission to use, copy, and distribute this software and its
                     11:  * documentation for any purpose with or without fee is hereby granted,
                     12:  * provided that the above copyright notice appear in all copies and
                     13:  * that both that copyright notice and this permission notice appear
                     14:  * in supporting documentation.
                     15:  *
                     16:  * Permission to modify the software is granted, but not the right to
                     17:  * distribute the complete modified source code.  Modifications are to
                     18:  * be distributed as patches to the released version.  Permission to
                     19:  * distribute binaries produced by compiling modified sources is granted,
                     20:  * provided you
                     21:  *   1. distribute the corresponding source modifications from the
                     22:  *    released version in the form of a patch file along with the binaries,
                     23:  *   2. add special version identification to distinguish your version
                     24:  *    in addition to the base release version number,
                     25:  *   3. provide your name and address as the primary contact for the
                     26:  *    support of your modified version, and
                     27:  *   4. retain our contact information in regard to use of the base
                     28:  *    software.
                     29:  * Permission to distribute the released version of the source code along
                     30:  * with corresponding source modifications in the form of a patch file is
                     31:  * granted with same provisions 2 through 4 for binary distributions.
                     32:  *
                     33:  * This software is provided "as is" without express or implied warranty
                     34:  * to the extent permitted by applicable law.
                     35: ]*/
                     36:
                     37:
                     38: /*
                     39:  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
                     40:  * Added user-specified bases for log scaling.
                     41:  *
                     42:  * 'someone'  contributed a complete rewrite of the hidden line
                     43:  * stuff, for about beta 173 or so, called 'newhide.tgz'
                     44:  *
                     45:  * 1995-1997 Hans-Bernhard Br"oker (Broeker@physik.rwth-aachen.de)
                     46:  *   Speedup, cleanup and several modification to integrate
                     47:  *   'newhide' with 3.6 betas ~188 (start of work) up to 273.
                     48:  *   As of beta 290, this is 'officially' in gnuplot.
                     49:  *
                     50:  */
                     51:
                     52: #include "plot.h"
                     53: #include "setshow.h"
                     54:
                     55: /* TODO (HBB's notes, just in case you're interested):
                     56:  * + fix all the problems I annotated by a 'FIXME' comment
                     57:  * + Find out which value EPSILON should have, and why
                     58:  * + Ask gnuplot-beta for a suitable way of concentrating
                     59:  *   all those 'VERYSMALL', 'EPSILON', and other numbers
                     60:  *   into one, consistent scheme, possibly based on
                     61:  *   <float.h>. E.g., I'd say that for most applications,
                     62:  *   the best 'epsilon' is either DBL_EPS or its square root.
                     63:  * + redo all the profiling, esp. to find out if TEST_GRIDCHECK = 1
                     64:  *   actually gains some speed, and if it is worth the memory
                     65:  *   spent to store the bit masks
                     66:  *   -> seems not improve speed at all, at least for my standard
                     67:  *   test case (mandd.gpl) it even slows it down by ~ 10%
                     68:  * + Evaluate the speed/memory comparison for storing vertex
                     69:  *   indices instead of (double) floating point constants
                     70:  *   to store {x|y}{min|max}
                     71:  * + remove those of my comments that are now pointless
                     72:  * + indent all that code
                     73:  * + try to really understand that 'hl_buffer' stuff...
                     74:  * + get rid of hardcoded things like sizeof(short) == 4,
                     75:  *   those 0x7fff terms and all that.
                     76:  * + restructure the hl_buffer storing method to make it more efficient
                     77:  * + Try to cut the speed decrease of this code rel. to the old hidden
                     78:  *   hidden line removal. (For 'mandd.gpl', it costs an overall
                     79:  *   factor of 9 compared with my older versions of gnuplot!)
                     80:  */
                     81:
                     82: /*************************/
                     83: /* Configuration section */
                     84: /*************************/
                     85:
                     86: /* HBB: if this module is compiled with TEST_GRIDCHECK = 1 defined,
                     87:  * it will store the information about {x|y}{min|max} in an
                     88:  * other (additional!) form: a bit mask, with each bit representing
                     89:  * one horizontal or vertical strip of the screen. The bits
                     90:  * for  strips a polygon spans are set to one. This allows to
                     91:  * test for xy_overlap simply by comparing bit patterns.
                     92:  */
                     93: #ifndef TEST_GRIDCHECK
                     94: #define TEST_GRIDCHECK 0
                     95: #endif
                     96:
                     97: /* HBB 961124; If you don't want the color-distinction between the
                     98:  * 'top' and 'bottom' sides of the surface, like I do, then just compile
                     99:  * with -DBACKSIDE_LINETYPE_OFFSET = 0. */
                    100: #ifndef BACKSIDE_LINETYPE_OFFSET
                    101: #define BACKSIDE_LINETYPE_OFFSET 1
                    102: #endif
                    103:
                    104: /* HBB 961127: defining FOUR_TRIANGLES = 1 will separate each quadrangle
                    105:  * of data points into *four* triangles, by introducing an additional
                    106:  * point at the mean of the four corners. Status: experimental
                    107:  */
                    108: #ifndef FOUR_TRIANGLES
                    109: #define FOUR_TRIANGLES 0
                    110: #endif
                    111:
                    112: /* HBB 970322: I removed the SENTINEL flag and its implementation
                    113:  * completely.  Its speed improvement wasn't that great, and it never
                    114:  * fully worked anyway, so that shouldn't make much of a difference at
                    115:  * all. */
                    116:
                    117: /* HBB 961212: this #define lets you choose if the diagonals that
                    118:  * divide each original quadrangle in two triangles will be drawn
                    119:  * visible or not: do draw them, define it to be 7L, otherwise let be
                    120:  * 3L (for the FOUR_TRIANGLES method, the values are 7L and 1L) */
                    121: /* drd : default to 3, for back-compatibility with 3.5 */
                    122: #ifndef TRIANGLE_LINESDRAWN_PATTERN
                    123: #define TRIANGLE_LINESDRAWN_PATTERN 3L
                    124: #endif
                    125:
                    126: /* HBB 970131: with HANDLE_UNDEFINED_POINTS = 1, let's try to handle
                    127:  * UNDEFINED data points in the input we're given by the rest of
                    128:  * gnuplot. We do that by marking these points by giving them z = -2
                    129:  * (which normally never happens), and then refusing to build any
                    130:  * polygon if one of its vertices has this mark. Thus, there's now a
                    131:  * hole in the generated surface. */
                    132: /* HBB 970322: some of this code is now hardwired (in
                    133:  * PREPARE_POLYGON), so HANDLE_UNDEFINED_POINTS = 0 might have stopped
                    134:  * to be a useful setting. I doubt anyone will miss it, anyway. */
                    135: /* drd : 2 means undefined only. 1 means outrange treated as undefined */
                    136: #ifndef HANDLE_UNDEFINED_POINTS
                    137: #define HANDLE_UNDEFINED_POINTS 1
                    138: #endif
                    139: /* Symbolic value for 'do not handle Undefined Points specially' */
                    140: #define UNHANDLED (UNDEFINED+1)
                    141:
                    142: /* HBB 970322: If both subtriangles of a quad were cancelled, try if
                    143:  * using the other diagonal is better. This only makes a difference if
                    144:  * exactly one vertex of the quad is unusable, and that one is on the
                    145:  * first tried diagonal. In such a case, the border of the hole in the
                    146:  * surface will be less rough than with the previous method. To
                    147:  * disable this, #define SHOW_ALTERNATIVE_DIAGONAL as 0 */
                    148: #ifndef SHOW_ALTERNATIVE_DIAGONAL
                    149: #define SHOW_ALTERNATIVE_DIAGONAL 1
                    150: #endif
                    151:
                    152: /* HBB 9790522: If the two triangles in a quad are both drawn, and
                    153:  * they show different sides to the user (the quad is 'bent over'),
                    154:  * then it often looks more sensible to draw the diagonal visibly to
                    155:  * avoid other parts of the scene being obscured by what the user
                    156:  * can't see. To disable, #define HANDLE_BENTOVER_QUADRANGLES 0 */
                    157: #ifndef HANDLE_BENTOVER_QUADRANGLES
                    158: #define HANDLE_BENTOVER_QUADRANGLES 1
                    159: #endif
                    160:
                    161: /* HBB 970618: The code of split_polygon_by_plane used to make a
                    162:  * separate decision about what should happen to points that are 'in'
                    163:  * the splitting plane (within EPSILON accuracy, i.e.), based on the
                    164:  * orientation of the splitting plane. I had disabled that code for I
                    165:  * assumed it might be the cause of some of the buggyness. I'm not yet
                    166:  * fully convinced on wether that assumption holds or not, so it's now
                    167:  * choosable.  OLD_SPLIT_PLANE == 1 will enable it. Some older comments
                    168:  * from the source:*/
                    169: /* HBB 970325: re-inserted this from older versions. Finally, someone
                    170:  * came up with a test case where it is actually needed :-( */
                    171: /* HBB 970427: seems to have been an incorrect analysis of that error.
                    172:  * the problematic plot works without this as well. */
                    173: #ifndef OLD_SPLIT_INPLANE
                    174: #define OLD_SPLIT_INPLANE 1
                    175: #endif
                    176:
                    177: /* HBB 970618: this way, new edges introduced by splitting a polygon
                    178:  * by the plane of another one will be made visible. Not too useful on
                    179:  * production output, but can help in debugging. */
                    180: #ifndef SHOW_SPLITTING_EDGES
                    181: #define SHOW_SPLITTING_EDGES 0
                    182: #endif
                    183:
                    184: /********************************/
                    185: /* END of configuration section */
                    186: /********************************/
                    187:
                    188:
                    189:
                    190: /* Variables to hold configurable values. This is meant to prepare for
                    191:  * making these settable by the user via 'set hidden [option]...' */
                    192:
                    193: int hiddenBacksideLinetypeOffset = BACKSIDE_LINETYPE_OFFSET;
                    194: long hiddenTriangleLinesdrawnPattern = TRIANGLE_LINESDRAWN_PATTERN;
                    195: int hiddenHandleUndefinedPoints = HANDLE_UNDEFINED_POINTS;
                    196: int hiddenShowAlternativeDiagonal = SHOW_ALTERNATIVE_DIAGONAL;
                    197: int hiddenHandleBentoverQuadrangles = HANDLE_BENTOVER_QUADRANGLES;
                    198:
                    199: /* The functions to map from user 3D space into normalized -1..1 */
                    200: #define map_x3d(x) ((x-min_array[FIRST_X_AXIS])*xscale3d-1.0)
                    201: #define map_y3d(y) ((y-min_array[FIRST_Y_AXIS])*yscale3d-1.0)
1.1.1.2 ! maekawa   202: #define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
1.1       maekawa   203:
                    204: extern int suppressMove;
                    205: extern int xright, xleft, ybot, ytop;
                    206: extern int xmiddle, ymiddle, xscaler, yscaler;
                    207: extern double min_array[], max_array[];
                    208: extern int auto_array[], log_array[];
                    209: extern double base_array[], log_base_array[];
                    210: extern double xscale3d, yscale3d, zscale3d;
1.1.1.2 ! maekawa   211: extern double floor_z;
1.1       maekawa   212:
                    213: extern int hidden_no_update, hidden_active;
                    214: extern int hidden_line_type_above, hidden_line_type_below;
                    215:
                    216: extern double trans_mat[4][4];
                    217:
                    218:
                    219: #ifdef HAVE_STRINGIZE
                    220: /* ANSI preprocessor concatenation */
                    221: # define CONCAT(x,y) x##y
                    222: # define CONCAT3(x,y,z) x##y##z
                    223: #else
                    224: /* K&R preprocessor concatenation */
                    225: # define CONCAT(x,y) x/**/y
                    226: # define CONCAT3(x,y,z) x/**/y/**/z
                    227: #endif
                    228:
                    229: /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
                    230: /* HBB 961111: started parametrisation of type t_pnt, to prepare change from
                    231:  * short to normal ints in **pnt. The other changes aren't always annotated,
                    232:  * so watch out! */
                    233: typedef unsigned short int t_pnt;
                    234: #define PNT_BITS (CHAR_BIT*sizeof(t_pnt))
                    235: /* caution! ANSI-dependant ! ? */
                    236: #define PNT_MAX USHRT_MAX
                    237: typedef t_pnt *tp_pnt;
                    238: static tp_pnt *pnt;
                    239:
                    240: /* Testroutine for the bitmap */
                    241: /* HBB 961110: fixed slight problem indicated by lclint:
                    242:  * calling IS_UNSET with pnt == 0 (possible?) */
                    243: /* HBB 961111: changed for new t_pnt, let compiler take care of optimisation
                    244:  * `%' -> `&' */
                    245: /* HBB 961124: switched semantics: as this was *always* called as !IS_SET(),
                    246:  * it's better to check for *unset* bits right away: */
                    247: #define IS_UNSET(X,Y) ((!pnt || pnt[X] == 0) ? 1 : !(((pnt[X])[(Y)/PNT_BITS] >> ((Y)%PNT_BITS)) & 0x01))
                    248:
                    249: /* Amount of space we need for one vertical row of bitmap,
                    250:    and byte offset of first used element */
                    251: static unsigned long y_malloc;
                    252:
                    253: /* These numbers are chosen as dividers into the bitmap. */
                    254: static int xfact, yfact;
                    255: #define XREDUCE(X) ((X)/xfact)
                    256: #define YREDUCE(Y) ((Y)/yfact)
                    257:
                    258: /* These variables are only used for drawing the individual polygons
                    259:    that make up the 3d figure.  After each polygon is drawn, the
                    260:    information is copied to the bitmap: xmin_hl, ymin_hl are used to
                    261:    keep track of the range of x values.  The arrays ymin_hl[],
                    262:    ymax_hl[] are used to keep track of the minimum and maximum y
                    263:    values used for each X value. */
                    264:
                    265: /* HBB 961124: new macro, to avoid a wordsize-depence */
                    266: #define HL_EXTENT_X_MAX UINT_MAX       /* caution! ANSI-only !? */
                    267: static unsigned int xmin_hl, xmax_hl;
                    268:
                    269: /* HBB: parametrized type of hl_buffer elements, to allow easier
                    270:    changing later on: */
                    271: #define HL_EXTENT_Y_MAX SHRT_MAX       /* caution! ANSI-only !? */
                    272: typedef short int t_hl_extent_y;
                    273: static t_hl_extent_y *ymin_hl, *ymax_hl;
                    274:
                    275:
                    276: /* hl_buffer is a buffer which is needed to draw polygons with very small
                    277:    angles correct:
                    278:
                    279:    One polygon may be split during the sorting algorithmus into
                    280:    several polygons. Before drawing a part of a polygon, I save in
                    281:    this buffer all lines of the polygon, which will not yet be drawn.
                    282:    If then the actual part draws a virtual line (a invisible line,
                    283:    which splits the polygon into 2 parts), it draws the line visible
                    284:    in those points, which are set in the buffer.
                    285:
                    286:    The layout of the buffer:
                    287:    hl_buffer[i] stands for the i'th column of the bitmap.
                    288:    Each column is splitted into pairs of points (a,b).
                    289:    Each pair describes a cross of one line with the column. */
                    290:
                    291: struct Cross {
                    292:     int a, b;
                    293:     struct Cross GPHUGE *next;
                    294: };
                    295:
                    296: static struct Cross GPHUGE *GPHUGE * hl_buffer;
                    297:
                    298: /* HBB 980303: added a global array of Cross structures, to save lots
                    299:  * of gp_alloc() calls (3 millions in a run through all.dem!)  */
                    300:
                    301: #define CROSS_STORE_INCREASE 500       /* number of Cross'es to alloc at a time */
                    302: static struct Cross *Cross_store = 0;
                    303: static int last_Cross_store = 0, free_Cross_store = 0;
                    304:
                    305: struct Vertex {
                    306:     coordval x, y, z;
                    307:     int style;
                    308: };
                    309:
                    310: /* HBB 971114: two new macros, to properly hide the machinery that
                    311:  *implements flagging of vertices as 'undefined' (or 'out of range',
                    312:  *handled equally). Thanks to Lars Hecking for pointing this out */
                    313: #define FLAG_VERTEX_AS_UNDEFINED(v) \
                    314:   do { (v).z = -2.0; } while (0)
                    315: #define VERTEX_IS_UNDEFINED(v) ((v).z == -2.0)
                    316:
                    317: /* These values serve as flags to detect loops of polygons obscuring
                    318:  * each other in in_front() */
                    319: typedef enum {
                    320:     is_untested = 0, is_tested, is_in_loop, is_moved_or_split
                    321: } t_poly_tested;
                    322:
                    323: /* Strings for printing out values of type t_poly_tested: */
                    324: static const char *string_poly_tested[] =
                    325: {
                    326:     "is_untested",
                    327:     "is_tested",
                    328:     "is_in_loop",
                    329:     "is_moved_or_split"
                    330: };
                    331:
                    332: struct Polygon {
                    333:     int n;                     /* amount of vertices */
                    334:     long *vertex;              /* The vertices (indices on vlist) */
                    335:     long line;                 /* i'th bit shows, if the i'th line should be drawn */
                    336:     coordval xmin, xmax, ymin, ymax, zmin, zmax;
                    337:     /* min/max in all three directions */
                    338:     struct lp_style_type *lp;  /* pointer to l/p properties */
                    339:     int style;                 /* The style of the lines */
                    340:     long next;                 /* index of next polygon in z-sorted list */
                    341:     long next_frag;            /* next fragment of same polygon... */
                    342:     int id;                    /* Which polygons belong together? */
                    343:     t_poly_tested tested;      /* To determine a loop during the sorting algorithm */
                    344:     /* HBB 980317: on the 16 bit PC platforms, the struct size must
                    345:      * be a power of two, so it exactly fits into a 64KB segment. First
                    346:      * we'll add the TEST_GRIDCHECK fields, regardless wether that
                    347:      * feature was activated or not. */
                    348: #if TEST_GRIDCHECK || defined(DOS16) || defined(WIN16)
                    349:     unsigned int xextent, yextent;
                    350: #endif
                    351:     /* HBB 980317: the remaining bit of padding. */
                    352: #if defined(DOS16) || defined(WIN16) || defined(WIN32)
                    353:     char dummies[8];
                    354: #endif
                    355: };
                    356:
                    357: typedef enum {                 /* result type for polygon_plane_intersection() */
                    358:     infront, inside, behind, intersects
                    359: } t_poly_plane_intersect;
                    360:
                    361: static struct Vertex GPHUGE *vlist;    /* The vertices */
                    362: static struct Polygon GPHUGE *plist;   /* The polygons */
                    363: static long nvert, npoly;      /* amount of vertices and polygons */
                    364: static long pfree, vert_free;  /* index on the first free entries */
                    365:
                    366: static long pfirst;            /* Index on the first polygon */
                    367:
                    368: /* macros for (somewhat) safer handling of the dynamic array of
                    369:  * polygons, 'plist[]' */
                    370: #define EXTEND_PLIST() \
                    371:     plist = (struct Polygon GPHUGE *) gp_realloc(plist, \
                    372:       (unsigned long)sizeof(struct Polygon)*(npoly += 10L), "hidden plist")
                    373:
                    374: #define CHECK_PLIST() if (pfree >= npoly) EXTEND_PLIST()
                    375: #define CHECK_PLIST_2() if (pfree+1 >= npoly) EXTEND_PLIST()
                    376: #define CHECK_PLIST_EXTRA(extra) if (pfree >= npoly) { EXTEND_PLIST() ; extra; }
                    377:
                    378:
                    379: /* precision of calculations in normalized space: */
                    380: #define EPSILON 1e-5           /* HBB: was 1.0E-5 */
                    381: #define SIGNOF(X)  ( ((X)<-EPSILON) ? -1: ((X)>EPSILON) )
                    382:
                    383: /* Some inexact relations: == , > , >= */
                    384: #define EQ(X,Y)  (fabs( (X) - (Y) ) < EPSILON) /* X == Y */
                    385: #define GR(X,Y)  ((X) >  (Y) + EPSILON)                /* X >  Y */
                    386: #define GE(X,Y)  ((X) >= (Y) - EPSILON)                /* X >= Y */
                    387:
                    388: /* Test, if two vertices are near each other */
                    389: #define V_EQUAL(a,b) ( GE(0.0, fabs((a)->x - (b)->x) + \
                    390:    fabs((a)->y - (b)->y) + fabs((a)->z - (b)->z)) )
                    391:
                    392: #define SETBIT(a,i,set) a= (set) ?  (a) | (1L<<(i)) : (a) & ~(1L<<(i))
                    393: #define GETBIT(a,i) (((a)>>(i))&1L)
                    394:
                    395: #define UINT_BITS (CHAR_BIT*sizeof(unsigned int))
                    396: #define USHRT_BITS (CHAR_BIT*sizeof(unsigned short))
                    397:
                    398:
                    399: static void print_polygon __PROTO((struct Polygon GPHUGE * p, const char *pname));
                    400:
                    401: /* HBB: new routine, to help debug 'Logic errors', mainly */
                    402: static void print_polygon(p, pname)
                    403: struct Polygon GPHUGE *p;
                    404: const char *pname;
                    405: {
                    406:     struct Vertex GPHUGE *v;
                    407:     int i;
                    408:
                    409:     fprintf(stderr, "#%s:(ind %d) n:%d, id:%d, next:%ld, tested:%s\n",
                    410:            pname, (int) (p - plist), p->n, p->id, p->next,
                    411:            string_poly_tested[(int) (p->tested)]);
                    412:     fprintf(stderr, "#zmin:%g, zmax:%g\n", p->zmin, p->zmax);
                    413:     for (i = 0; i < p->n; i++, v++) {
                    414:        v = vlist + p->vertex[i];
                    415:        fprintf(stderr, "%g %g %g \t%ld\n", v->x, v->y, v->z, p->vertex[i]);
                    416:     }
                    417:     /*repeat first vertex, so the line gets closed: */
                    418:     v = vlist + p->vertex[0];
                    419:     fprintf(stderr, "%g %g %g \t%ld\n", v->x, v->y, v->z, p->vertex[0]);
                    420:     /*two blank lines, as a multimesh separator: */
                    421:     fputs("\n\n", stderr);
                    422: }
                    423:
                    424: /* Gets Minimum 'C' value of polygon, C is x, y, or z: */
                    425: #define GET_MIN(p, C, min) do { \
                    426:   int i; \
                    427:   long *v = p->vertex; \
                    428:                        \
                    429:   min = vlist[*v++].C; \
                    430:   for (i = 1; i< p->n; i++, v++) \
                    431:     if (vlist[*v].C < min) \
                    432:       min = vlist[*v].C; \
                    433: } while (0)
                    434:
                    435: /* Gets Maximum 'C' value of polygon, C is x, y, or z: */
                    436: #define GET_MAX(p, C, max) do { \
                    437:   int i; \
                    438:   long *v = p->vertex; \
                    439:                       \
                    440:   max = vlist[*v++].C; \
                    441:   for (i = 1; i< p->n; i++, v++) \
                    442:     if (vlist[*v].C > max) \
                    443:       max = vlist[*v].C; \
                    444: } while (0)
                    445:
                    446: /* Prototypes for internal functions of this module. */
                    447: static void map3d_xyz __PROTO((double x, double y, double z,
                    448:                               struct Vertex GPHUGE * v));
                    449: static int reduce_polygon __PROTO((int *n, long **v, long *line, int nmin));
                    450: static void build_polygon __PROTO((struct Polygon GPHUGE * p, int n,
                    451:                long *v, long line, int style, struct lp_style_type * lp,
                    452:               long next, long next_frag, int id, t_poly_tested tested));
                    453: static GP_INLINE int maybe_build_polygon __PROTO((struct Polygon GPHUGE * p,
                    454:         int n, long *v, long line, int style, struct lp_style_type * lp,
                    455:               long next, long next_frag, int id, t_poly_tested tested));
                    456: static void init_polygons __PROTO((struct surface_points * plots, int pcount));
                    457: static int compare_by_zmax __PROTO((const void *p1, const void *p2));
                    458: static void sort_by_zmax __PROTO((void));
                    459: static int obscured __PROTO((struct Polygon GPHUGE * p));
                    460: static GP_INLINE int xy_overlap __PROTO((struct Polygon GPHUGE * a, struct Polygon GPHUGE * b));
                    461: static void get_plane __PROTO((struct Polygon GPHUGE * p, double *a, double *b,
                    462:                               double *c, double *d));
                    463: static t_poly_plane_intersect polygon_plane_intersection __PROTO((struct Polygon GPHUGE * p, double a, double b, double c, double d));
                    464: static int intersect __PROTO((struct Vertex GPHUGE * v1,
                    465:                              struct Vertex GPHUGE * v2, struct Vertex GPHUGE * v3, struct Vertex GPHUGE * v4));
                    466: static int v_intersect __PROTO((struct Vertex GPHUGE * v1,
                    467:                                struct Vertex GPHUGE * v2, struct Vertex GPHUGE * v3, struct Vertex GPHUGE * v4));
                    468: static int intersect_polygon __PROTO((struct Vertex GPHUGE * v1, struct Vertex GPHUGE * v2, struct Polygon GPHUGE * p));
                    469: static int full_xy_overlap __PROTO((struct Polygon GPHUGE * a, struct Polygon GPHUGE * b));
                    470: static long build_new_vertex __PROTO((long V1, long V2, double w));
                    471: static long split_polygon_by_plane __PROTO((long P, double a, double b,
                    472:                                        double c, double d, TBOOLEAN f));
                    473: static int in_front __PROTO((long Last, long Test));
                    474:
                    475: /* HBB 980303: new, for the new back-buffer for *Cross structures: */
                    476: static GP_INLINE struct Cross *get_Cross_from_store __PROTO((void));
                    477: static GP_INLINE void init_Cross_store __PROTO((void));
                    478:
                    479: static GP_INLINE TBOOLEAN hl_buffer_set __PROTO((int xv, int yv));
                    480: static GP_INLINE void update_hl_buffer_column __PROTO((int xv, int ya, int yv));
                    481: static void draw_clip_line_buffer __PROTO((int x1, int y1, int x2, int y2));
                    482: static void draw_clip_line_update __PROTO((int x1, int y1, int x2, int y2,
                    483:                                           int virtual));
                    484: static GP_INLINE void clip_vector_h __PROTO((int x, int y));
                    485: static GP_INLINE void clip_vector_virtual __PROTO((int x, int y));
                    486: static GP_INLINE void clip_vector_buffer __PROTO((int x, int y));
                    487: static void draw __PROTO((struct Polygon GPHUGE * p));
                    488:
                    489:
                    490: /* Set the options for hidden3d. To be called from set.c, when the
                    491:  * user has begun a command with 'set hidden3d', to parse the rest of
                    492:  * that command */
                    493: void set_hidden3doptions()
                    494: {
                    495:     struct value t;
                    496:
                    497:     c_token++;
                    498:
                    499:     if (END_OF_COMMAND) {
                    500:        return;
                    501:     }
                    502:     if (almost_equals(c_token, "def$aults")) {
                    503:        /* reset all parameters to defaults */
                    504:        hiddenBacksideLinetypeOffset = BACKSIDE_LINETYPE_OFFSET;
                    505:        hiddenTriangleLinesdrawnPattern = TRIANGLE_LINESDRAWN_PATTERN;
                    506:        hiddenHandleUndefinedPoints = HANDLE_UNDEFINED_POINTS;
                    507:        hiddenShowAlternativeDiagonal = SHOW_ALTERNATIVE_DIAGONAL;
                    508:        hiddenHandleBentoverQuadrangles = HANDLE_BENTOVER_QUADRANGLES;
                    509:        c_token++;
                    510:        if (!END_OF_COMMAND)
                    511:            int_error("No further options allowed after 'defaults'", c_token);
                    512:        return;
                    513:     }
                    514:     if (almost_equals(c_token, "off$set")) {
                    515:        c_token++;
                    516:        hiddenBacksideLinetypeOffset = (int) real(const_express(&t));
                    517:     } else if (almost_equals(c_token, "nooff$set")) {
                    518:        c_token++;
                    519:        hiddenBacksideLinetypeOffset = 0;
                    520:     }
                    521:     if (END_OF_COMMAND) {
                    522:        return;
                    523:     }
                    524:     if (almost_equals(c_token, "tri$anglepattern")) {
                    525:        c_token++;
                    526:        hiddenTriangleLinesdrawnPattern = (int) real(const_express(&t));
                    527:     }
                    528:     if (END_OF_COMMAND) {
                    529:        return;
                    530:     }
                    531:     if (almost_equals(c_token, "undef$ined")) {
                    532:        int tmp;
                    533:
                    534:        c_token++;
                    535:        tmp = (int) real(const_express(&t));
                    536:        if (tmp <= 0 || tmp > UNHANDLED)
                    537:            tmp = UNHANDLED;
                    538:        hiddenHandleUndefinedPoints = tmp;
                    539:     } else if (almost_equals(c_token, "nound$efined")) {
                    540:        c_token++;
                    541:        hiddenHandleUndefinedPoints = UNHANDLED;
                    542:     }
                    543:     if (END_OF_COMMAND) {
                    544:        return;
                    545:     }
                    546:     if (almost_equals(c_token, "alt$diagonal")) {
                    547:        c_token++;
                    548:        hiddenShowAlternativeDiagonal = 1;
                    549:     } else if (almost_equals(c_token, "noalt$diagonal")) {
                    550:        c_token++;
                    551:        hiddenShowAlternativeDiagonal = 0;
                    552:     }
                    553:     if (END_OF_COMMAND) {
                    554:        return;
                    555:     }
                    556:     if (almost_equals(c_token, "bent$over")) {
                    557:        c_token++;
                    558:        hiddenHandleBentoverQuadrangles = 1;
                    559:     } else if (almost_equals(c_token, "nobent$over")) {
                    560:        c_token++;
                    561:        hiddenHandleBentoverQuadrangles = 0;
                    562:     }
                    563:     if (!END_OF_COMMAND) {
                    564:        int_error("No such option to hidden3d (or wrong order)", c_token);
                    565:     }
                    566: }
                    567:
                    568: /* HBB 970619: new routine for displaying the option settings */
                    569: void show_hidden3doptions()
                    570: {
                    571:     fprintf(stderr,"\
                    572: \t  Back side of surfaces has linestyle offset of %d\n\
                    573: \t  Bit-Mask of Lines to draw in each triangle is %ld\n\
                    574: \t  %d: ",
                    575:            hiddenBacksideLinetypeOffset, hiddenTriangleLinesdrawnPattern,
                    576:            hiddenHandleUndefinedPoints);
                    577:
                    578:     switch (hiddenHandleUndefinedPoints) {
                    579:     case OUTRANGE:
                    580:        fputs("Outranged and undefined datapoints are omitted from the surface.\n", stderr);
                    581:        break;
                    582:     case UNDEFINED:
                    583:        fputs("Only undefined datapoints are omitted from the surface.\n", stderr);
                    584:        break;
                    585:     case UNHANDLED:
                    586:        fputs("Will not check for undefined datapoints (may cause crashes).\n", stderr);
                    587:        break;
                    588:     default:
                    589:        fputs("This value is illegal!!!\n", stderr);
                    590:        break;
                    591:     }
                    592:     fprintf(stderr,"\
                    593: \t  Will %suse other diagonal if it gives a less jaggy outline\n\
                    594: \t  Will %sdraw diagonal visibly if quadrangle is 'bent over'\n",
                    595:            hiddenShowAlternativeDiagonal ? "" : "not ",
                    596:            hiddenHandleBentoverQuadrangles ? "" : "not ");
                    597: }
                    598:
                    599: /* HBB 971117: new function. */
                    600: /* Implements proper 'save'ing of the new hidden3d options... */
                    601: void save_hidden3doptions(fp)
                    602: FILE *fp;
                    603: {
                    604:     if (!hidden3d) {
                    605:        fputs("set nohidden3d\n", fp);
                    606:        return;
                    607:     }
                    608:     fprintf(fp, "set hidden3d offset %d trianglepattern %ld undefined %d %saltdiagonal %sbentover\n",
                    609:            hiddenBacksideLinetypeOffset,
                    610:            hiddenTriangleLinesdrawnPattern,
                    611:            hiddenHandleUndefinedPoints,
                    612:            hiddenShowAlternativeDiagonal ? "" : "no",
                    613:            hiddenHandleBentoverQuadrangles ? "" : "no");
                    614: }
                    615:
                    616: /* Initialize the necessary steps for hidden line removal and
                    617:    initialize global variables. */
                    618: void init_hidden_line_removal()
                    619: {
                    620:     int i;
                    621:
                    622:     /* Check for some necessary conditions to be set elsewhere: */
                    623:     /* HandleUndefinedPoints mechanism depends on these: */
                    624:     assert(OUTRANGE == 1);
                    625:     assert(UNDEFINED == 2);
                    626:     /* '3' makes the test easier in the critical section */
                    627:     if (hiddenHandleUndefinedPoints < OUTRANGE)
                    628:        hiddenHandleUndefinedPoints = UNHANDLED;
                    629:
                    630:     /*  We want to keep the bitmap size less than 2048x2048, so we choose
                    631:      *  integer dividers for the x and y coordinates to keep the x and y
                    632:      *  ranges less than 2048.  In practice, the x and y sizes for the bitmap
                    633:      *  will be somewhere between 1024 and 2048, except in cases where the
                    634:      *  coordinates ranges for the device are already less than 1024.
                    635:      *  We do this mainly to control the size of the bitmap, but it also
                    636:      *  speeds up the computation.  We maintain separate dividers for
                    637:      *  x and y.
                    638:      */
                    639:     xfact = (xright - xleft) / 1024;
                    640:     yfact = (ytop - ybot) / 1024;
                    641:     if (xfact == 0)
                    642:        xfact = 1;
                    643:     if (yfact == 0)
                    644:        yfact = 1;
                    645:     if (pnt == 0) {
                    646:        i = XREDUCE(xright) - XREDUCE(xleft) + 1;
                    647:        pnt = (tp_pnt *) gp_alloc(
                    648:                     (unsigned long) (i * sizeof(tp_pnt)), "hidden pnt");
                    649:        while (--i >= 0)
                    650:            pnt[i] = (tp_pnt) 0;
                    651:     }
                    652: }
                    653:
                    654: /* Reset the hidden line data to a fresh start.                              */
                    655: void reset_hidden_line_removal()
                    656: {
                    657:     int i;
                    658:     if (pnt) {
                    659:        for (i = 0; i <= XREDUCE(xright) - XREDUCE(xleft); i++) {
                    660:            if (pnt[i]) {
                    661:                free(pnt[i]);
                    662:                pnt[i] = 0;
                    663:            };
                    664:        };
                    665:     };
                    666: }
                    667:
                    668:
                    669: /* Terminates the hidden line removal process.                  */
                    670: /* Free any memory allocated by init_hidden_line_removal above. */
                    671: void term_hidden_line_removal()
                    672: {
                    673:     if (pnt) {
                    674:        int j;
                    675:        for (j = 0; j <= XREDUCE(xright) - XREDUCE(xleft); j++) {
                    676:            if (pnt[j]) {
                    677:                free(pnt[j]);
                    678:                pnt[j] = 0;
                    679:            };
                    680:        };
                    681:        free(pnt);
                    682:        pnt = 0;
                    683:     };
                    684:     if (ymin_hl)
                    685:        free(ymin_hl), ymin_hl = 0;
                    686:     if (ymax_hl)
                    687:        free(ymax_hl), ymax_hl = 0;
                    688: }
                    689:
                    690:
                    691: /* Maps from normalized space to terminal coordinates */
                    692: #define TERMCOORD(v,x,y) x = ((int)((v)->x * xscaler)) + xmiddle, \
                    693:                         y = ((int)((v)->y * yscaler)) + ymiddle;
                    694:
                    695:
                    696: static void map3d_xyz(x, y, z, v)
                    697: double x, y, z;                        /* user coordinates */
                    698: struct Vertex GPHUGE *v;       /* the point in normalized space */
                    699: {
                    700:     int i, j;
                    701:     double V[4], Res[4],       /* Homogeneous coords. vectors. */
                    702:      w = trans_mat[3][3];
                    703:     /* Normalize object space to -1..1 */
                    704:     V[0] = map_x3d(x);
                    705:     V[1] = map_y3d(y);
                    706:     V[2] = map_z3d(z);
                    707:     V[3] = 1.0;
                    708:     Res[0] = 0;                        /*HBB 961110: lclint wanted this... Why? */
                    709:     for (i = 0; i < 3; i++) {
                    710:        Res[i] = trans_mat[3][i];       /* Initiate it with the weight factor. */
                    711:        for (j = 0; j < 3; j++)
                    712:            Res[i] += V[j] * trans_mat[j][i];
                    713:     }
                    714:     for (i = 0; i < 3; i++)
                    715:        w += V[i] * trans_mat[i][3];
                    716:     if (w == 0)
                    717:        w = 1.0e-5;
                    718:     v->x = Res[0] / w;
                    719:     v->y = Res[1] / w;
                    720:     v->z = Res[2] / w;
                    721: }
                    722:
                    723:
                    724: /* remove unnecessary Vertices from a polygon: */
                    725: static int reduce_polygon(n, v, line, nmin)
                    726: int *n;                                /* number of vertices */
                    727: long **v;                      /* the vertices */
                    728: long *line;                    /* information which line should be drawn */
                    729: int nmin;                      /* if the number reduces under nmin, forget polygon */
                    730:      /* Return value 1: the reduced polygon has still more or equal
                    731:         vertices than nmin.
                    732:         Return value 0: the polygon was trivial; memory is given free */
                    733: {
                    734:     int less, i;
                    735:     long *w = *v;
                    736:     for (less = 0, i = 0; i < *n - 1; i++) {
                    737:        if (V_EQUAL(vlist + w[i], vlist + w[i + 1])
                    738:        /* HBB 970321: try to remove an endless loop bug (part1/2) */
                    739:            && ((w[i] == w[i + 1])
                    740:                || !GETBIT(*line, i)
                    741:                || GETBIT(*line, i + 1)
                    742:            || ((i > 0) ? GETBIT(*line, i - 1) : GETBIT(*line, *n - 1))))
                    743:            less++;
                    744:        else if (less) {
                    745:            w[i - less] = w[i];
                    746:            SETBIT(*line, i - less, GETBIT(*line, i));
                    747:        }
                    748:     }
                    749:     if (i - less > 0
                    750:        && V_EQUAL(vlist + w[i], vlist + w[0])
                    751:     /* HBB 970321: try to remove an endless loop bug (part2/2) */
                    752:        && (w[i] == w[0]
                    753:            || !GETBIT(*line, i)
                    754:            || GETBIT(*line, i - 1)
                    755:            || GETBIT(*line, 0)))
                    756:        less++;
                    757:     else if (less) {
                    758:        w[i - less] = w[i];
                    759:        SETBIT(*line, i - less, GETBIT(*line, i));
                    760:     }
                    761:     *n -= less;
                    762:     if (*n < nmin) {
                    763:        free(w);
                    764:        *v = 0;                 /* HBB 980213: signal that v(==w) is free()d */
                    765:        return 0;
                    766:     }
                    767:     if (less) {
                    768:        w = (long *) gp_realloc(w, (unsigned long) sizeof(long) * (*n),
                    769:                                "hidden red_poly");
                    770:        *v = w;
                    771:        for (; less > 0; less--)
                    772:            SETBIT(*line, *n + less - 1, 0);
                    773:     }
                    774:     return 1;
                    775: }
                    776:
                    777: /* Write polygon in plist */
                    778: /*
                    779:  * HBB: changed this to precalculate {x|y}{min|max}
                    780:  */
                    781: static void build_polygon(p, n, v, line, style, lp, next, next_frag, id, tested)
                    782: struct Polygon GPHUGE *p;      /* this should point at a free entry in plist */
                    783: int n;                         /* number of vertices */
                    784: long *v;                       /* array of indices on the vertices (in vlist) */
                    785: long line;                     /* information, which line should be drawn */
                    786: int style;                     /* color of the lines */
                    787: struct lp_style_type *lp;      /* pointer to line/point properties */
                    788: long next;                     /* next polygon in the list */
                    789: long next_frag;                        /* next fragment of same polygon */
                    790: int id;                                /* Which polygons belong together? */
                    791: t_poly_tested tested;          /* Is polygon already on the right place of list? */
                    792: {
                    793:     int i;
                    794:     struct Vertex vert;
                    795:
                    796:     if (p >= plist + npoly)
                    797:        fputs("uh oh !\n", stderr);
                    798:
                    799:     CHECK_POINTER(plist, p);
                    800:
                    801:     p->n = n;
                    802:     p->vertex = v;
                    803:     p->line = line;
                    804:     p->lp = lp;                        /* line and point properties */
                    805:     p->style = style;
                    806:     CHECK_POINTER(vlist, (vlist + v[0]));
                    807:     vert = vlist[v[0]];
                    808:     p->xmin = p->xmax = vert.x;
                    809:     p->ymin = p->ymax = vert.y;
                    810:     p->zmin = p->zmax = vert.z;
                    811:     for (i = 1; i < n; i++) {
                    812:        CHECK_POINTER(vlist, (vlist + v[i]));
                    813:        vert = vlist[v[i]];
                    814:        if (vert.x < p->xmin)
                    815:            p->xmin = vert.x;
                    816:        else if (vert.x > p->xmax)
                    817:            p->xmax = vert.x;
                    818:        if (vert.y < p->ymin)
                    819:            p->ymin = vert.y;
                    820:        else if (vert.y > p->ymax)
                    821:            p->ymax = vert.y;
                    822:        if (vert.z < p->zmin)
                    823:            p->zmin = vert.z;
                    824:        else if (vert.z > p->zmax)
                    825:            p->zmax = vert.z;
                    826:     }
                    827:
                    828: #if TEST_GRIDCHECK
                    829: /* FIXME: this should probably use a table of bit-patterns instead... */
                    830:     p->xextent = (~(~0U << (unsigned int) ((p->xmax + 1.0) / 2.0 * UINT_BITS + 1.0)))
                    831:        & (~0U << (unsigned int) ((p->xmin + 1.0) / 2.0 * UINT_BITS));
                    832:     p->yextent = (~(~0U << (unsigned int) ((p->ymax + 1.0) / 2.0 * UINT_BITS + 1.0)))
                    833:        & (~0U << (unsigned int) ((p->ymin + 1.0) / 2.0 * UINT_BITS));
                    834: #endif
                    835:
                    836:     p->next = next;
                    837:     p->next_frag = next_frag;  /* HBB 961201: link fragments, to speed up draw() q-loop */
                    838:     p->id = id;
                    839:     p->tested = tested;
                    840: }
                    841:
                    842:
                    843: /* get the amount of curves in a plot */
                    844: #define GETNCRV(NCRV) do {\
                    845:    if(this_plot->plot_type == FUNC3D)        \
                    846:      for(icrvs = this_plot->iso_crvs,NCRV = 0; \
                    847:         icrvs;icrvs = icrvs->next,NCRV++);  \
                    848:    else if(this_plot->plot_type == DATA3D) \
                    849:         NCRV = this_plot->num_iso_read;    \
                    850:     else {                                 \
                    851:        graph_error("Plot type is neither function nor data"); \
                    852:        return; /* stops a gcc -Wunitialised warning */        \
                    853:     } \
                    854: } while (0)
                    855:
                    856: /* Do we see the top or bottom of the polygon, or is it 'on edge'? */
                    857: #define GET_SIDE(vlst,csign) do { \
                    858:   double c = vlist[vlst[0]].x * (vlist[vlst[1]].y - vlist[vlst[2]].y) + \
                    859:     vlist[vlst[1]].x * (vlist[vlst[2]].y - vlist[vlst[0]].y) + \
                    860:     vlist[vlst[2]].x * (vlist[vlst[0]].y - vlist[vlst[1]].y); \
                    861:   csign = SIGNOF (c); \
                    862: } while (0)
                    863:
                    864: /* HBB 970131: new function, to allow handling of undefined datapoints
                    865:  * by leaving out the corresponding polygons from the list.
                    866:  * Return Value: 1 if polygon was built, 0 otherwise */
                    867: static GP_INLINE int maybe_build_polygon(p, n, v, line, style, lp,
                    868:                                         next, next_frag, id, tested)
                    869: struct Polygon GPHUGE *p;
                    870: struct lp_style_type *lp;
                    871: int n, style, id;
                    872: t_poly_tested tested;
                    873: long *v, line, next, next_frag;
                    874: {
                    875:     int i;
                    876:
                    877:     assert(v);
                    878:
                    879:     if (hiddenHandleUndefinedPoints != UNHANDLED)
                    880:        for (i = 0; i < n; i++)
                    881:            if (VERTEX_IS_UNDEFINED(vlist[v[i]])) {
                    882:                free(v);        /* HBB 980213: free mem... */
                    883:                v = 0;
                    884:                return 0;       /* *don't* build the polygon! */
                    885:            }
                    886:     build_polygon(p, n, v, line, style, lp, next, next_frag, id, tested);
                    887:     return 1;
                    888: }
                    889:
                    890: /* HBB 970322: new macro, invented because code like this occured several
                    891:  * times inside init_polygons, esp. after I added the option to choose the
                    892:  * other diagonal to divide a quad when necessary */
                    893: /* HBB 980213: Here and below in init_polygons, added code to properly
                    894:  * free any allocated vertex lists ('v' here), or avoid allocating
                    895:  * them in the first place. Thanks to Stefan Schroepfer for reporting
                    896:  * the leak.  */
                    897: #define PREPARE_POLYGON(n,v,i0,i1,i2,line,c,border,i_chk,ncrv_chk,style) do {\
                    898:   (n) = 3; \
                    899:   if (VERTEX_IS_UNDEFINED(vlist[vert_free + (i0)])\
                    900:       || VERTEX_IS_UNDEFINED(vlist[vert_free + (i1)]) \
                    901:       || VERTEX_IS_UNDEFINED(vlist[vert_free + (i2)])) { \
                    902:     /* These values avoid any further action on this polygon */\
                    903:     (v) = 0; /* flag this as undefined */ \
                    904:     (c) = (border) = 0; \
                    905:   } else {\
                    906:   (v) = (long *) gp_alloc ((unsigned long) sizeof (long) * (n), "hidden PREPARE_POLYGON"); \
                    907:   (v)[0] = vert_free + (i0);\
                    908:   (v)[1] = vert_free + (i1);\
                    909:   (v)[2] = vert_free + (i2);\
                    910:   (line) = hiddenTriangleLinesdrawnPattern;\
                    911:     GET_SIDE((v),(c));\
                    912:     /* Is this polygon at the border of the surface? */\
                    913:     (border) = (i == (i_chk) || ncrv == (ncrv_chk));\
                    914:   }\
                    915:   (style) = ((c) >= 0) ? above : below;\
                    916: } while (0)
                    917:
                    918: static void init_polygons(plots, pcount)
                    919: struct surface_points *plots;
                    920: int pcount;
                    921:      /* Initialize vlist, plist */
                    922: {
                    923:     long int i;
                    924:     struct surface_points *this_plot;
                    925:     int surface;
                    926:     long int ncrv, ncrv1;
                    927:     struct iso_curve *icrvs;
                    928:     int row_offset;
                    929:     int id;
                    930:     int n1, n2;                        /* number of vertices of a Polygon */
                    931:     long *v1, *v2;             /* the Vertices */
                    932:     long line1, line2;         /* which  lines should be drawn */
                    933:     int above = -1, below, style1, style2;     /* the line color */
                    934:     struct lp_style_type *lp;  /* pointer to line and point properties */
                    935:     int c1, c2;                        /* do we see the front or the back */
                    936:     TBOOLEAN border1, border2; /* is it at the border of the surface */
                    937:
                    938:     /* allocate memory for polylist and nodelist */
                    939:     nvert = npoly = 0;
                    940:     for (this_plot = plots, surface = 0;
                    941:         surface < pcount;
                    942:         this_plot = this_plot->next_sp, surface++) {
                    943:        GETNCRV(ncrv);
                    944:        switch (this_plot->plot_style) {
                    945:        case LINESPOINTS:
                    946:        case STEPS:             /* handle as LINES */
                    947:        case FSTEPS:
                    948:        case HISTEPS:
                    949:        case LINES:
                    950: #if FOUR_TRIANGLES
                    951:            nvert += ncrv * (2 * this_plot->iso_crvs->p_count - 1);
                    952: #else
                    953:            nvert += ncrv * (this_plot->iso_crvs->p_count);
                    954: #endif
                    955:            npoly += 2 * (ncrv - 1) * (this_plot->iso_crvs->p_count - 1);
                    956:            break;
                    957:        case DOTS:
                    958:        case XERRORBARS:        /* handle as POINTSTYLE */
                    959:        case YERRORBARS:
                    960:        case XYERRORBARS:
                    961:        case BOXXYERROR:
                    962:        case BOXERROR:
                    963:        case CANDLESTICKS:      /* HBB: these as well */
                    964:        case FINANCEBARS:
                    965:        case VECTOR:
                    966:        case POINTSTYLE:
                    967:            nvert += ncrv * (this_plot->iso_crvs->p_count);
                    968:            npoly += (ncrv - 1) * (this_plot->iso_crvs->p_count - 1);
                    969:            break;
                    970:        case BOXES:             /* handle as IMPULSES */
                    971:        case IMPULSES:
                    972:            nvert += 2 * ncrv * (this_plot->iso_crvs->p_count);
                    973:            npoly += (ncrv - 1) * (this_plot->iso_crvs->p_count - 1);
                    974:            break;
                    975:        }
                    976:     }
                    977:     vlist = (struct Vertex GPHUGE *)
                    978:        gp_alloc((unsigned long) sizeof(struct Vertex) * nvert, "hidden vlist");
                    979:     plist = (struct Polygon GPHUGE *)
                    980:        gp_alloc((unsigned long) sizeof(struct Polygon) * npoly, "hidden plist");
                    981:
                    982:     /* initialize vlist: */
                    983:     for (vert_free = 0, this_plot = plots, surface = 0;
                    984:         surface < pcount;
                    985:         this_plot = this_plot->next_sp, surface++) {
                    986:        switch (this_plot->plot_style) {
                    987:        case LINESPOINTS:
                    988:        case BOXERROR:          /* handle as POINTSTYLE */
                    989:        case BOXXYERROR:
                    990:        case XERRORBARS:
                    991:        case YERRORBARS:
                    992:        case XYERRORBARS:
                    993:        case CANDLESTICKS:      /* HBB: these as well */
                    994:        case FINANCEBARS:
                    995:        case VECTOR:
                    996:        case POINTSTYLE:
                    997:            above = this_plot->lp_properties.p_type;
                    998:            break;
                    999:        case STEPS:             /* handle as LINES */
                   1000:        case FSTEPS:
                   1001:        case HISTEPS:
                   1002:        case LINES:
                   1003:        case DOTS:
                   1004:        case BOXES:             /* handle as IMPULSES */
                   1005:        case IMPULSES:
                   1006:            above = -1;
                   1007:            break;
                   1008:        }
                   1009:        GETNCRV(ncrv1);
                   1010:        for (ncrv = 0, icrvs = this_plot->iso_crvs;
                   1011:             ncrv < ncrv1 && icrvs;
                   1012:             ncrv++, icrvs = icrvs->next) {
                   1013:            struct coordinate GPHUGE *points = icrvs->points;
                   1014:
                   1015:            for (i = 0; i < icrvs->p_count; i++) {
                   1016:                /* As long as the point types keep OUTRANGE == 1 and
                   1017:                 * UNDEFINED == 2, we can just compare
                   1018:                 * hiddenHandleUndefinedPoints to the type of the point. To
                   1019:                 * simplify this, let UNHANDLED := UNDEFINED+1 mean 'do not
                   1020:                 * handle undefined or outranged points at all' (dangerous
                   1021:                 * option, that is...) */
                   1022:                if (points[i].type >= hiddenHandleUndefinedPoints) {
                   1023:                    /* mark this vertex as a bad one */
                   1024:                    FLAG_VERTEX_AS_UNDEFINED(vlist[vert_free++]);
                   1025:                    continue;
                   1026:                }
                   1027:                map3d_xyz(points[i].x, points[i].y, points[i].z, vlist + vert_free);
                   1028:                vlist[vert_free++].style = above;
                   1029:                if (this_plot->plot_style == IMPULSES
                   1030:                    || this_plot->plot_style == BOXES) {
                   1031:                    map3d_xyz(points[i].x, points[i].y, min_array[FIRST_Z_AXIS], vlist + vert_free);
                   1032:                    vlist[vert_free++].style = above;
                   1033:                }
                   1034: #if FOUR_TRIANGLES
                   1035:                /* FIXME: handle other styles as well! */
                   1036:                if (this_plot->plot_style == LINES &&
                   1037:                    i < icrvs->p_count - 1)
                   1038:                    vert_free++;        /* keep one entry free for quad-center */
                   1039: #endif
                   1040:            }
                   1041:        }
                   1042:     }
                   1043:
                   1044:     /* initialize plist: */
                   1045:     id = 0;
                   1046:     for (pfree = vert_free = 0, this_plot = plots, surface = 0;
                   1047:         surface < pcount;
                   1048:         this_plot = this_plot->next_sp, surface++) {
                   1049:        row_offset = this_plot->iso_crvs->p_count;
                   1050:        lp = &(this_plot->lp_properties);
                   1051:        above = this_plot->lp_properties.l_type;
                   1052:        below = this_plot->lp_properties.l_type + hiddenBacksideLinetypeOffset;
                   1053:        GETNCRV(ncrv1);
                   1054:        for (ncrv = 0, icrvs = this_plot->iso_crvs;
                   1055:             ncrv < ncrv1 && icrvs;
                   1056:             ncrv++, icrvs = icrvs->next)
                   1057:            for (i = 0; i < icrvs->p_count; i++)
                   1058:                switch (this_plot->plot_style) {
                   1059:                case LINESPOINTS:
                   1060:                case STEPS:     /* handle as LINES */
                   1061:                case FSTEPS:
                   1062:                case HISTEPS:
                   1063:                case LINES:
                   1064:                    if (i < icrvs->p_count - 1 && ncrv < ncrv1 - 1) {
                   1065: #if FOUR_TRIANGLES
                   1066:                        long *v3, *v4;
                   1067:                        int n3, n4;
                   1068:                        long line3, line4;
                   1069:                        int c3, c4, style3, style4;
                   1070:                        TBOOLEAN border3, border4, inc_id = FALSE;
                   1071:
                   1072:                        /* Build medium vertex: */
                   1073:                        vlist[vert_free + 1].x =
                   1074:                            (vlist[vert_free].x + vlist[vert_free + 2 * row_offset - 1].x +
                   1075:                             vlist[vert_free + 2].x + vlist[vert_free + 2 * row_offset + 1].x
                   1076:                            ) / 4;
                   1077:                        vlist[vert_free + 1].y =
                   1078:                            (vlist[vert_free].y + vlist[vert_free + 2 * row_offset - 1].y +
                   1079:                             vlist[vert_free + 2].y + vlist[vert_free + 2 * row_offset + 1].y
                   1080:                            ) / 4;
                   1081:                        vlist[vert_free + 1].z =
                   1082:                            (vlist[vert_free].z + vlist[vert_free + 2 * row_offset - 1].z +
                   1083:                             vlist[vert_free + 2].z + vlist[vert_free + 2 * row_offset + 1].z
                   1084:                            ) / 4;
                   1085:                        vlist[vert_free + 1].style = above;
                   1086:
                   1087:                        PREPARE_POLYGON(n1, v1, 2, 0, 1, line1, c1,
                   1088:                                        border1, 0, -1, style1);
                   1089:                        /* !!FIXME!! special casing (see the older code) still needs to be
                   1090:                         * implemented! */
                   1091:                        if ((c1 || border1)
                   1092:                            && reduce_polygon(&n1, &v1, &line1, 3)) {
                   1093:                            CHECK_PLIST();
                   1094:                            pfree += maybe_build_polygon(plist + pfree, n1, v1, line1,
                   1095:                                              style1, lp, -1L, -1L, id++,
                   1096:                                                         is_untested);
                   1097:                            inc_id = TRUE;
                   1098:                        }
                   1099:                        PREPARE_POLYGON(n2, v2, 0, 2 * row_offset - 1, 1, line2, c2,
                   1100:                                        border2, -1, 0, style2);
                   1101:                        if ((c2 || border2)
                   1102:                            && reduce_polygon(&n2, &v2, &line2, 3)) {
                   1103:                            CHECK_PLIST();
                   1104:                            pfree += maybe_build_polygon(plist + pfree, n2, v2, line2,
                   1105:                                              style2, lp, -1L, -1L, id++,
                   1106:                                                         is_untested);
                   1107:                            inc_id = TRUE;
                   1108:                        }
                   1109:                        PREPARE_POLYGON(n3, v3, 2 * row_offset - 1, 2 * row_offset + 1, 1,
                   1110:                              line3, c3, border3, icrvs->p_count - 2, -1,
                   1111:                                        style3);
                   1112:                        if ((c3 || border3)
                   1113:                            && reduce_polygon(&n3, &v3, &line3, 3)) {
                   1114:                            CHECK_PLIST();
                   1115:                            pfree += maybe_build_polygon(plist + pfree, n3, v3, line3,
                   1116:                                              style3, lp, -1L, -1L, id++,
                   1117:                                                         is_untested);
                   1118:                            inc_id = TRUE;
                   1119:                        }
                   1120:                        PREPARE_POLYGON(n4, v4, 2 * row_offset + 1, 0, 1, line4, c4,
                   1121:                                        border4, -1, ncrv1 - 2, style4);
                   1122:                        if ((c4 || border4)
                   1123:                            && reduce_polygon(&n4, &v4, &line4, 3)) {
                   1124:                            CHECK_PLIST();
                   1125:                            pfree += maybe_build_polygon(plist + pfree, n4, v4, line4,
                   1126:                                              style4, lp, -1L, -1L, id++,
                   1127:                                                         is_untested);
                   1128:                            inc_id = TRUE;
                   1129:                        }
                   1130:                        /*if (inc_id)
                   1131:                           id++; */
                   1132:                        vert_free++;
                   1133:
                   1134: #else /* FOUR_TRIANGLES */
                   1135:
                   1136:                        PREPARE_POLYGON(n1, v1, row_offset, 0, 1, line1, c1,
                   1137:                                        border1, 0, 0, style1);
                   1138:                        PREPARE_POLYGON(n2, v2, 1, row_offset + 1, row_offset, line2,
                   1139:                              c2, border2, icrvs->p_count - 2, ncrv1 - 2,
                   1140:                                        style2);
                   1141:
                   1142:                        /* if this makes at least one of the two triangles
                   1143:                         * visible, use the other diagonal here */
                   1144:                        if (hiddenShowAlternativeDiagonal
                   1145:                            && !(v1)    /* HBB 980213: only try this in the case of */
                   1146:                            &&!(v2)     /* undefined vertices -> *missing* trigs */
                   1147:                            ) {
                   1148:                            if (VERTEX_IS_UNDEFINED(vlist[vert_free + 1])) {
                   1149:                                PREPARE_POLYGON(n1, v1, row_offset + 1, row_offset, 0,
                   1150:                                        line1, c1, border1, 0, ncrv1 - 2,
                   1151:                                                style1);
                   1152:                            } else if (VERTEX_IS_UNDEFINED(vlist[vert_free + row_offset])) {
                   1153:                                PREPARE_POLYGON(n1, v1, 0, 1, row_offset + 1, line1,
                   1154:                                      c1, border1, icrvs->p_count - 2, 0,
                   1155:                                                style1);
                   1156:                            }
                   1157:                        }
                   1158:                        /* HBB 970323: if visible sides of the two triangles
                   1159:                         * differs, make diagonal visible! */
                   1160:                        /* HBB 970428: FIXME: should this be changed to only
                   1161:                         * activate *one* of the triangles' diagonals? If so, how
                   1162:                         * to find out the right one? Maybe the one with its
                   1163:                         * normal closer to the z direction? */
                   1164:                        if (hiddenHandleBentoverQuadrangles
                   1165:                            && (c1 * c2) < 0
                   1166:                            ) {
                   1167:                            SETBIT(line1, n1 - 1, 1);
                   1168:                            SETBIT(line2, n2 - 1, 1);
                   1169:                        }
                   1170:                        if ((c1 || border1)
                   1171:                            && reduce_polygon(&n1, &v1, &line1, 3)) {
                   1172:                            if ((c2 || border2)
                   1173:                                && reduce_polygon(&n2, &v2, &line2, 3)) {
                   1174:                                /* These two will need special handling, to
                   1175:                                 * ensure the links from one to the other
                   1176:                                 * are only set up when *both* polygons are
                   1177:                                 * valid */
                   1178:                                int r1, r2;     /* temp. results */
                   1179:
                   1180:                                CHECK_PLIST_2();
                   1181:                                r1 = maybe_build_polygon(plist + pfree, n1, v1,
                   1182:                                                  line1, style1, lp, -1L,
                   1183:                                                   -1L, id, is_untested);
                   1184:                                r2 = maybe_build_polygon(plist + pfree + r1, n2, v2,
                   1185:                                                  line2, style2, lp, -1L,
                   1186:                                                 -1L, id++, is_untested);
                   1187:                                if (r1 && r2) {
                   1188:                                    plist[pfree].next_frag = pfree + 1;
                   1189:                                    plist[pfree + 1].next_frag = pfree;
                   1190:                                }
                   1191:                                pfree += r1 + r2;
                   1192:                            } else {    /* P1 was ok, but P2 wasn't */
                   1193: /* HBB 980213: P2 is invisible, so free its vertex list: */
                   1194:                                if (v2) {
                   1195:                                    free(v2);
                   1196:                                    v2 = 0;
                   1197:                                }
                   1198: /* HBB 970323: if other polygon wasn't drawn, draw this polygon's
                   1199:  * diagonal visibly (not only if it was 'on edge'). */
                   1200:                                /*if (c2 || border2) */
                   1201:                                SETBIT(line1, n1 - 1, 1);
                   1202:                                CHECK_PLIST();
                   1203:                                pfree += maybe_build_polygon(plist + pfree, n1, v1, line1,
                   1204:                                              style1, lp, -1L, -1L, id++,
                   1205:                                                             is_untested);
                   1206:                            }
                   1207:                        } else {        /* P1 was not ok */
                   1208: /* HBB 980213: P1 is invisible, so free its vertex list: */
                   1209:                            if (v1) {
                   1210:                                free(v1);
                   1211:                                v1 = 0;
                   1212:                            }
                   1213: /* HBB 970323: if other polygon wasn't drawn, draw this polygon's
                   1214:  * diagonal visibly (not only if it was 'on edge'). */
                   1215:                            /*if (c1 || border1) */
                   1216:                            SETBIT(line2, n2 - 1, 1);
                   1217: /* HBB 970522: yet another problem triggered by the handling of
                   1218:  * undefined points: if !(c2||border2), we mustn't try to reduce
                   1219:  * triangle 2. */
                   1220:                            if (0
                   1221:                                || (1
                   1222:                                    && (c2 || border2)
                   1223:                                  && reduce_polygon(&n2, &v2, &line2, 2))
                   1224:                                || (1
                   1225: /* HBB 980213: reduce_... above might have zeroed v... */
                   1226:                                    && (v2)
                   1227:                                    && (c1 || border1))) {
                   1228:                                CHECK_PLIST();
                   1229:                                pfree += maybe_build_polygon(plist + pfree, n2, v2, line2,
                   1230:                                              style2, lp, -1L, -1L, id++,
                   1231:                                                             is_untested);
                   1232:                            } else {
                   1233:                                /* HBB 980213: sigh... both P1 and P2 were invisible, but
                   1234:                                 * at least one of them was a not undefined.. */
                   1235:                                if (v1)
                   1236:                                    free(v1);
                   1237:                                if (v2)
                   1238:                                    free(v2);
                   1239:                            }
                   1240:                        }
                   1241: #endif /* else: FOUR_TRIANGLES */
                   1242:                    }
                   1243:                    vert_free++;
                   1244:                    break;
                   1245:                case DOTS:
                   1246:                    v1 = (long *) gp_alloc((unsigned long) sizeof(long) * 1,
                   1247:                                           "hidden v1 for dots");
                   1248:                    v1[0] = vert_free++;
                   1249:                    CHECK_PLIST();
                   1250:                    pfree += maybe_build_polygon(plist + pfree, 1, v1, 1L, above,
                   1251:                                        lp, -1L, -1L, id++, is_untested);
                   1252:                    break;
                   1253:                case BOXERROR:  /* handle as POINTSTYLE */
                   1254:                case BOXXYERROR:
                   1255:                case XERRORBARS:        /* handle as POINTSTYLE */
                   1256:                case YERRORBARS:
                   1257:                case XYERRORBARS:
                   1258:                case CANDLESTICKS:      /* HBB: these as well */
                   1259:                case FINANCEBARS:
                   1260:                case POINTSTYLE:
                   1261:                case VECTOR:
                   1262:                    v1 = (long *) gp_alloc((unsigned long) sizeof(long) * 1,
                   1263:                                           "hidden v1 for point");
                   1264:                    v1[0] = vert_free++;
                   1265:                    CHECK_PLIST();
                   1266:                    pfree += maybe_build_polygon(plist + pfree, 1, v1, 0L, above,
                   1267:                                        lp, -1L, -1L, id++, is_untested);
                   1268:                    break;
                   1269:                case BOXES:     /* handle as IMPULSES */
                   1270:                case IMPULSES:
                   1271:                    n1 = 2;
                   1272:                    v1 = (long *) gp_alloc((unsigned long) sizeof(long) * n1,
                   1273:                                           "hidden v1 for impulse");
                   1274:                    v1[0] = vert_free++;
                   1275:                    v1[1] = vert_free++;
                   1276:                    line1 = 2L;
                   1277:                    (void) reduce_polygon(&n1, &v1, &line1, 1);
                   1278:                    CHECK_PLIST();
                   1279:                    pfree += maybe_build_polygon(plist + pfree, n1, v1, line1, above,
                   1280:                                        lp, -1L, -1L, id++, is_untested);
                   1281:                    break;
                   1282:                }
                   1283:     }
                   1284: }
                   1285:
                   1286: static int compare_by_zmax(p1, p2)
                   1287: const void *p1, *p2;
                   1288: {
                   1289:     return (SIGNOF(plist[*(const long *) p2].zmax - plist[*(const long *) p1].zmax));
                   1290: }
                   1291:
                   1292: static void sort_by_zmax()
                   1293:      /* and build the list (return_value = start of list) */
                   1294: {
                   1295:     long *sortarray, i;
                   1296:     struct Polygon GPHUGE *this;
                   1297:     sortarray = (long *) gp_alloc((unsigned long) sizeof(long) * pfree, "hidden sortarray");
                   1298:     for (i = 0; i < pfree; i++)
                   1299:        sortarray[i] = i;
                   1300:     qsort(sortarray, (size_t) pfree, sizeof(long), compare_by_zmax);
                   1301:     this = plist + sortarray[0];
                   1302:     for (i = 1; i < pfree; i++) {
                   1303:        this->next = sortarray[i];
                   1304:        this = plist + sortarray[i];
                   1305:     }
                   1306:     this->next = -1L;
                   1307:     pfirst = sortarray[0];
                   1308:     free(sortarray);
                   1309: }
                   1310:
                   1311:
                   1312: /* HBB: try if converting this code to unsigned int (from signed shorts)
                   1313:  *  fixes any of the remaining bugs. In the same motion, remove
                   1314:  *  hardcoded sizeof(short) = 2 (09.10.1996) */
                   1315:
                   1316: #define LASTBITS (USHRT_BITS -1)       /* ????? */
                   1317: static int obscured(p)
                   1318:      /* is p obscured by already drawn polygons? (only a simple minimax-test) */
                   1319: struct Polygon GPHUGE *p;
                   1320: {
                   1321:     int l_xmin, l_xmax, l_ymin, l_ymax;                /* HBB 961110: avoid shadowing external names */
                   1322:     t_pnt mask1, mask2;
                   1323:     long indx1, indx2, k, m;
                   1324:     tp_pnt cpnt;
                   1325:     /* build the minimax-box */
                   1326:     l_xmin = (p->xmin * xscaler) + xmiddle;
                   1327:     l_xmax = (p->xmax * xscaler) + xmiddle;
                   1328:     l_ymin = (p->ymin * yscaler) + ymiddle;
                   1329:     l_ymax = (p->ymax * yscaler) + ymiddle;
                   1330:     if (l_xmin < xleft)
                   1331:        l_xmin = xleft;
                   1332:     if (l_xmax > xright)
                   1333:        l_xmax = xright;
                   1334:     if (l_ymin < ybot)
                   1335:        l_ymin = ybot;
                   1336:     if (l_ymax > ytop)
                   1337:        l_ymax = ytop;
                   1338:     if (l_xmin > l_xmax || l_ymin > l_ymax)
                   1339:        return 1;               /* not viewable */
                   1340:     l_ymin = YREDUCE(l_ymin) - YREDUCE(ybot);
                   1341:     l_ymax = YREDUCE(l_ymax) - YREDUCE(ybot);
                   1342:     l_xmin = XREDUCE(l_xmin) - XREDUCE(xleft);
                   1343:     l_xmax = XREDUCE(l_xmax) - XREDUCE(xleft);
                   1344:     /* Now check bitmap */
                   1345:     indx1 = l_ymin / PNT_BITS;
                   1346:     indx2 = l_ymax / PNT_BITS;
                   1347:     mask1 = PNT_MAX << (((unsigned) l_ymin) % PNT_BITS);
                   1348:     mask2 = PNT_MAX >> ((~((unsigned) l_ymax)) % PNT_BITS);
                   1349:     /* HBB: lclint wanted this: */
                   1350:     assert(pnt != 0);
                   1351:     for (m = l_xmin; m <= l_xmax; m++) {
                   1352:        if (pnt[m] == 0)
                   1353:            return 0;           /* not obscured */
                   1354:        cpnt = pnt[m] + indx1;
                   1355:        if (indx1 == indx2) {
                   1356:            if (~(*cpnt) & mask1 & mask2)
                   1357:                return 0;
                   1358:        } else {
                   1359:            if (~(*cpnt++) & mask1)
                   1360:                return 0;
                   1361:            for (k = indx1 + 1; k < indx2; k++)
                   1362:                if ((*cpnt++) != PNT_MAX)
                   1363:                    return 0;
                   1364:            if (~(*cpnt++) & mask2)
                   1365:                return 0;
                   1366:        }
                   1367:     }
                   1368:     return 1;
                   1369: }
                   1370:
                   1371:
                   1372: void draw_line_hidden(x1, y1, x2, y2)
                   1373: unsigned int x1, y1, x2, y2;
                   1374: {
                   1375:     register struct termentry *t = term;
                   1376:     TBOOLEAN flag;
                   1377:     register int xv, yv, errx, erry, err;
                   1378:     register unsigned int xvr, yvr;
                   1379:     int unsigned xve, yve;
                   1380:     register int dy, nstep = 0, dyr;
                   1381:     int i;
                   1382:
                   1383:     if (x1 > x2) {
                   1384:        xvr = x2;
                   1385:        yvr = y2;
                   1386:        xve = x1;
                   1387:        yve = y1;
                   1388:     } else {
                   1389:        xvr = x1;
                   1390:        yvr = y1;
                   1391:        xve = x2;
                   1392:        yve = y2;
                   1393:     };
                   1394:     errx = XREDUCE(xve) - XREDUCE(xvr);
                   1395:     erry = YREDUCE(yve) - YREDUCE(yvr);
                   1396:     dy = (erry > 0 ? 1 : -1);
                   1397:     dyr = dy * yfact;
                   1398:     switch (dy) {
                   1399:     case 1:
                   1400:        nstep = errx + erry;
                   1401:        errx = -errx;
                   1402:        break;
                   1403:     case -1:
                   1404:        nstep = errx - erry;
                   1405:        errx = -errx;
                   1406:        erry = -erry;
                   1407:        break;
                   1408:     };
                   1409:     err = errx + erry;
                   1410:     errx <<= 1;
                   1411:     erry <<= 1;
                   1412:     xv = XREDUCE(xvr) - XREDUCE(xleft);
                   1413:     yv = YREDUCE(yvr) - YREDUCE(ybot);
                   1414:     (*t->move) (xvr, yvr);
                   1415:     flag = !IS_UNSET(xv, yv);
                   1416:     if (!hidden_no_update) {   /* Check first point */
                   1417:        assert(ymax_hl != 0);
                   1418:        assert(ymin_hl != 0);
                   1419:        if (xv < xmin_hl)
                   1420:            xmin_hl = xv;
                   1421:        if (xv > xmax_hl)
                   1422:            xmax_hl = xv;
                   1423:        if (yv > ymax_hl[xv])
                   1424:            ymax_hl[xv] = yv;
                   1425:        if (yv < ymin_hl[xv])
                   1426:            ymin_hl[xv] = yv;
                   1427:     };
                   1428:     for (i = 0; i < nstep; i++) {
                   1429:        if (err < 0) {
                   1430:            xv++;
                   1431:            xvr += xfact;
                   1432:            err += erry;
                   1433:        } else {
                   1434:            yv += dy;
                   1435:            yvr += dyr;
                   1436:            err += errx;
                   1437:        };
                   1438:        if (IS_UNSET(xv, yv)) {
                   1439:            if (flag) {
                   1440:                (*t->move) (xvr, yvr);
                   1441:                flag = FALSE;
                   1442:            };
                   1443:        } else {
                   1444:            if (!flag) {
                   1445:                (*t->vector) (xvr, yvr);
                   1446:                flag = TRUE;
                   1447:            };
                   1448:        };
                   1449:        if (!hidden_no_update) {
                   1450:            /* HBB 961110: lclint wanted these: */
                   1451:            assert(ymax_hl != 0);
                   1452:            assert(ymin_hl != 0);
                   1453:            if (xv < xmin_hl)
                   1454:                xmin_hl = xv;
                   1455:            if (xv > xmax_hl)
                   1456:                xmax_hl = xv;
                   1457:            if (yv > ymax_hl[xv])
                   1458:                ymax_hl[xv] = yv;
                   1459:            if (yv < ymin_hl[xv])
                   1460:                ymin_hl[xv] = yv;
                   1461:        };
                   1462:     };
                   1463:     if (!flag)
                   1464:        (*t->vector) (xve, yve);
                   1465:     return;
                   1466: }
                   1467:
                   1468:
                   1469: static GP_INLINE int xy_overlap(a, b)
                   1470:      /* Do a and b overlap in x or y (minimax test) */
                   1471: struct Polygon GPHUGE *a, GPHUGE * b;
                   1472: {
                   1473: #if TEST_GRIDCHECK
                   1474:     /* First, check by comparing the extent bit patterns: */
                   1475:     if (!((a->xextent & b->xextent) && (a->yextent & b->yextent)))
                   1476:        return 0;
                   1477: #endif
                   1478:     return ((int) (GE(b->xmax, a->xmin) && GE(a->xmax, b->xmin)
                   1479:                   && GE(b->ymax, a->ymin) && GE(a->ymax, b->ymin)));
                   1480: }
                   1481:
                   1482:
                   1483: static void get_plane(p, a, b, c, d)
                   1484: struct Polygon GPHUGE *p;
                   1485: double *a, *b, *c, *d;
                   1486: {
                   1487:     int i;
                   1488:     struct Vertex GPHUGE *v1, GPHUGE * v2;
                   1489:     double x, y, z, s;
                   1490:     if (p->n == 1) {
                   1491:        *a = 0.0;
                   1492:        *b = 0.0;
                   1493:        *c = 1.0;
                   1494:        *d = -vlist[p->vertex[0]].z;
                   1495:        return;
                   1496:     }
                   1497:     v1 = vlist + p->vertex[p->n - 1];
                   1498:     v2 = vlist + p->vertex[0];
                   1499:     *a = (v1->y - v2->y) * (v1->z + v2->z);
                   1500:     *b = (v1->z - v2->z) * (v1->x + v2->x);
                   1501:     *c = (v1->x - v2->x) * (v1->y + v2->y);
                   1502:     for (i = 0; i < p->n - 1; i++) {
                   1503:        v1 = vlist + p->vertex[i];
                   1504:        v2 = vlist + p->vertex[i + 1];
                   1505:        *a += (v1->y - v2->y) * (v1->z + v2->z);
                   1506:        *b += (v1->z - v2->z) * (v1->x + v2->x);
                   1507:        *c += (v1->x - v2->x) * (v1->y + v2->y);
                   1508:     }
                   1509:     s = sqrt(*a * *a + *b * *b + *c * *c);
                   1510:     if (GE(0.0, s)) {          /* => s==0 => the vertices are in one line */
                   1511:        v1 = vlist + p->vertex[0];
                   1512:        for (i = 1; i < p->n; i++) {
                   1513:            v2 = vlist + p->vertex[i];
                   1514:            if (!V_EQUAL(v1, v2))
                   1515:                break;
                   1516:        }
                   1517:        /* (x,y,z) is l.u. from <v1, v2> */
                   1518:        x = v1->x;
                   1519:        y = v1->y;
                   1520:        z = v1->z;
                   1521:        if (EQ(y, v2->y))
                   1522:            y += 1.0;
                   1523:        else
                   1524:            x += 1.0;
                   1525:        /* build a vector that is orthogonal to the line of the polygon */
                   1526:        *a = v1->y * (v2->z - z) + v2->y * (z - v1->z) + y * (v1->z - v2->z);
                   1527:        *b = v1->z * (v2->x - x) + v2->z * (x - v1->x) + z * (v1->x - v2->x);
                   1528:        *c = v1->x * (v2->y - y) + v2->x * (y - v1->y) + x * (v1->y - v2->y);
                   1529:        s = sqrt(*a * *a + *b * *b + *c * *c);
                   1530:     }
                   1531:     if (*c < 0.0)              /* ensure that normalized c is > 0 */
                   1532:        s *= -1.0;              /* The exact relation, because c can be very small */
                   1533:     *a /= s;
                   1534:     *b /= s;
                   1535:     *c /= s;
                   1536:     *d = -*a * v1->x - *b * v1->y - *c * v1->z;
                   1537:     return;
                   1538: }
                   1539:
                   1540:
                   1541: static t_poly_plane_intersect
                   1542:  polygon_plane_intersection(p, a, b, c, d)
                   1543: struct Polygon GPHUGE *p;
                   1544: double a, b, c, d;
                   1545: {
                   1546:     int i, sign, max_sign, min_sign;
                   1547:     struct Vertex GPHUGE *v;
                   1548:
                   1549:     CHECK_POINTER(plist, p);
                   1550:
                   1551:     v = vlist + p->vertex[0];
                   1552:     max_sign = min_sign = SIGNOF(a * v->x + b * v->y + c * v->z + d);
                   1553:     for (i = 1; i < p->n; i++) {
                   1554:        v = vlist + p->vertex[i];
                   1555:        sign = SIGNOF(a * v->x + b * v->y + c * v->z + d);
                   1556:        if (sign > max_sign)
                   1557:            max_sign = sign;
                   1558:        else if (sign < min_sign)
                   1559:            min_sign = sign;
                   1560:     }
                   1561:
                   1562:     /* Yes, this is a bit tricky, but it's simpler for the computer... */
                   1563:     if (min_sign == -1) {
                   1564:        if (max_sign == 1)
                   1565:            return (intersects);
                   1566:        else
                   1567:            return behind;
                   1568:     } else {
                   1569:        if ((max_sign == 0) && (min_sign == 0))
                   1570:            return (inside);
                   1571:        else
                   1572:            return infront;
                   1573:     }
                   1574: }
                   1575:
                   1576:
                   1577: /* full xy-overlap test (support routines first) */
                   1578:
                   1579: /* What do negative return values mean?
                   1580:    It is allowed, that the 2 polygons touch themselves in one point.
                   1581:    There are 2 possibilities of this case:
                   1582:    (A) A vertex of the one polygon is on an edge of the other
                   1583:    (B) The two polygons have a vertex together.
                   1584:    In case (A) the algorithm finds 2 edges, wich touches an edge of the
                   1585:    other polygon. In case (B) the algorithm finds four pairs of edges.
                   1586:    I handle both cases with negative return values:
                   1587:    Case (A) returns -2, and case (B) returns -1.
                   1588:    So I can say, if the sum of negative return values goes greater than 4
                   1589:    (absolutly), there must be more than one touch point. So the
                   1590:    polygons must overlap. */
                   1591:
                   1592: /* some variables, for keeping track of minima and maxima across
                   1593:  * all these routines */
                   1594:
                   1595: static double m1x, M1x, m1y, M1y, m2x, M2x, m2y, M2y;
                   1596:
                   1597: #define MINIMAX  (GE(M2x,m1x) && GE(M1x,m2x) && GE(M2y,m1y) && GE(M1y,m2y))
                   1598:
                   1599:
                   1600: /* Does the edge [v1,v2] intersect edge [v3, v4] ?
                   1601:  * This is for non-vertical [v1,v2]
                   1602:  */
                   1603: static int intersect(v1, v2, v3, v4)
                   1604: struct Vertex GPHUGE *v1, GPHUGE * v2, GPHUGE * v3, GPHUGE * v4;
                   1605: {
                   1606:     double m1, m2, t1, t2, x, y, minx, maxx;
                   1607:
                   1608:     m1 = (v2->y - v1->y) / (v2->x - v1->x);
                   1609:     t1 = v1->y - m1 * v1->x;
                   1610:
                   1611:     /* if [v3,v4] vertical: */
                   1612:     if (EQ(v3->x, v4->x)) {
                   1613:        y = v3->x * m1 + t1;
                   1614:        if (GR(m2x, m1x) && GR(M1x, m2x)) {
                   1615:            if (GR(y, m2y) && GR(M2y, y))
                   1616:                return 1;
                   1617:            if (EQ(y, m2y) || EQ(y, M2y))
                   1618:                return -2;
                   1619:            return 0;
                   1620:        }
                   1621:        /* m2x == m1x || m2x == M1x */
                   1622:        if (GR(y, m2y) && GR(M2y, y))
                   1623:            return -2;
                   1624:        if (EQ(y, m2y) || EQ(y, M2y))
                   1625:            return -1;
                   1626:        return 0;
                   1627:     }
                   1628:     /* [v3,v4] not vertical */
                   1629:     m2 = (v4->y - v3->y) / (v4->x - v3->x);
                   1630:     t2 = v3->y - m2 * v3->x;
                   1631:     if (!SIGNOF(m1 - m2)) {    /* if edges are parallel: */
                   1632:        x = m1 * v3->x + t1 - v3->y;
                   1633:        if (!EQ(m1 * v3->x + t1 - v3->y, 0.0))
                   1634:            return 0;
                   1635:        if (GR(M2x, m1x) && GR(M1x, m2x))
                   1636:            return 1;
                   1637:        return -1;              /* the edges have a common vertex */
                   1638:     }
                   1639:     x = (t2 - t1) / (m1 - m2);
                   1640:     minx = GPMAX(m1x, m2x);
                   1641:     maxx = GPMIN(M1x, M2x);
                   1642:     if (GR(x, minx) && GR(maxx, x))
                   1643:        return 1;
                   1644:     if (GR(minx, x) || GR(x, maxx))
                   1645:        return 0;
                   1646:     if ((EQ(x, m1x) || EQ(x, M1x)) && (EQ(x, m1x) || EQ(x, M1x)))
                   1647:        return -1;
                   1648:     return -2;
                   1649: }
                   1650:
                   1651: /* Does the edge [v1,v2] intersect edge [v3, v4] ?
                   1652:  * This is for vertical [v1,v2]
                   1653:  */
                   1654: static int v_intersect(v1, v2, v3, v4)
                   1655: struct Vertex GPHUGE *v1, GPHUGE * v2, GPHUGE * v3, GPHUGE * v4;
                   1656: {
                   1657:     double y;
                   1658:
                   1659:     /* HBB 971115: to silence picky compilers, use v2 at least once, in
                   1660:      * a dummy expression (caution, may be ANSI-C specific because of
                   1661:      * the use of 'void'...) */
                   1662:     (void) v2;
                   1663:
                   1664:     /* if [v3,v4] is vertical, too: */
                   1665:     /* already known: rectangles do overlap, because MINIMAX was true */
                   1666:     if (EQ(v3->x, v4->x))
                   1667:        return (GR(M2y, m1y) && GR(M1y, m2y)) ? 1 : -1;
                   1668:
                   1669:     /*  [v3,v4] not vertical */
                   1670:     y = v3->y + (v1->x - v3->x) * (v4->y - v3->y) / (v4->x - v3->x);
                   1671:     if (GR(m1x, m2x) && GR(M2x, m1x)) {
                   1672:        if (GR(y, m1y) && GR(M1y, y))
                   1673:            return 1;
                   1674:        if (EQ(y, m1y) || EQ(y, M1y))
                   1675:            return -2;
                   1676:        return 0;
                   1677:     }
                   1678:     /* m1x == m2x || m1x == M2x */
                   1679:     if (GR(y, m1y) && GR(M1y, y))
                   1680:        return -2;
                   1681:     if (EQ(y, m1y) || EQ(y, M1y))
                   1682:        return -1;
                   1683:     return 0;
                   1684: }
                   1685:
                   1686: #define UPD_MINMAX(v1,v2,npar) do {    \
                   1687:   if (v1->x< v2->x)                 \
                   1688:     CONCAT3(m,npar,x) = v1->x, CONCAT3(M,npar,x) = v2->x;   \
                   1689:   else                              \
                   1690:     CONCAT3(m,npar,x) = v2->x, CONCAT3(M,npar,x) = v1->x;   \
                   1691:   if (v1->y< v2->y)                 \
                   1692:     CONCAT3(m,npar,y) = v1->y, CONCAT3(M,npar,y) = v2->y;   \
                   1693:   else                              \
                   1694:     CONCAT3(m,npar,y) = v2->y, CONCAT3(M,npar,y) = v1->y;   \
                   1695: } while (0)
                   1696:
                   1697: /* does the edge [v1,v2] intersect polygon p? */
                   1698: static int intersect_polygon(v1, v2, p)
                   1699: struct Vertex GPHUGE *v1, GPHUGE * v2;
                   1700: struct Polygon GPHUGE *p;
                   1701: {
                   1702:     struct Vertex GPHUGE *v3, GPHUGE * v4;
                   1703:     int i, s, t = 0;
                   1704:     int (*which_intersect) __PROTO((struct Vertex GPHUGE * v1,
                   1705:                                    struct Vertex GPHUGE * v2,
                   1706:                                    struct Vertex GPHUGE * v3,
                   1707:                                    struct Vertex GPHUGE * v4))
                   1708:     = intersect;
                   1709:
                   1710:     /* Is [v1,v2] vertical? If, use v_intersect() */
                   1711:     if (EQ(v1->x, v2->x))
                   1712:        which_intersect = v_intersect;
                   1713:
                   1714:     UPD_MINMAX(v1,v2,1);
                   1715:
                   1716:     /* test first edge of polygon p */
                   1717:     v3 = vlist + p->vertex[p->n - 1];
                   1718:     v4 = vlist + p->vertex[0];
                   1719:     UPD_MINMAX(v3,v4,2);
                   1720:
                   1721:
                   1722:     if (MINIMAX) {
                   1723:        s = (*which_intersect) (v1, v2, v3, v4);
                   1724:        if (s == 1 || (s < 0 && (t += s) < -4))
                   1725:            return 1;
                   1726:     }
                   1727:     /* and the other edges... */
                   1728:     for (i = 0; i < p->n - 1; i++) {
                   1729:        v3 = vlist + p->vertex[i];
                   1730:        v4 = vlist + p->vertex[i + 1];
                   1731:        UPD_MINMAX(v3,v4,2);
                   1732:        if (!MINIMAX)
                   1733:            continue;
                   1734:        s = (*which_intersect) (v1, v2, v3, v4);
                   1735:        if (s == 1 || (s < 0 && (t += s) < -4))
                   1736:            return 1;
                   1737:     }
                   1738:     return t;
                   1739: }
                   1740:
                   1741: /* OK, now here comes the 'real' polygon intersection routine:
                   1742:  * Do a and b overlap in x or y (full test):
                   1743:  * Do edges intersect, do the polygons touch in two points,
                   1744:  * or is a vertex of one polygon inside the other polygon? */
                   1745:
                   1746: static int full_xy_overlap(a, b)
                   1747: struct Polygon GPHUGE *a, GPHUGE * b;
                   1748: {
                   1749:     struct Vertex GPHUGE *v1, GPHUGE * v2, v;
                   1750:     int i, s, t = 0;
                   1751:
                   1752:     if (a->n < 2 || b->n < 2)
                   1753:        return 0;
                   1754:     v1 = vlist + a->vertex[a->n - 1];
                   1755:     v2 = vlist + a->vertex[0];
                   1756:     s = intersect_polygon(v1, v2, b);
                   1757:     if (s == 1 || (s < 0 && (t += s) < -4))
                   1758:        return 1;
                   1759:     for (i = 0; i < a->n - 1; i++) {
                   1760:        v1 = vlist + a->vertex[i];
                   1761:        v2 = vlist + a->vertex[i + 1];
                   1762:        s = intersect_polygon(v1, v2, b);
                   1763:        if (s == 1 || (s < 0 && (t += s) < -4))
                   1764:            return 1;
                   1765:     }
                   1766:     /* No edges intersect. Is one polygon inside the other? */
                   1767:     /* The  inner polygon has the greater minx */
                   1768:     if (a->xmin < b->xmin) {
                   1769:        struct Polygon GPHUGE *temp = a;
                   1770:        a = b;
                   1771:        b = temp;
                   1772:     }
                   1773:     /* Now, a is the inner polygon */
                   1774:     for (i = 0; i < a->n; i++) {
                   1775:        v1 = vlist + a->vertex[i];
                   1776:        /* HBB: lclint seems to have found a problem here: v wasn't
                   1777:         * fully defined when passed to intersect_polygon() */
                   1778:        v = *v1;
                   1779:        v.x = -1.1;
                   1780:        s = intersect_polygon(v1, &v, b);
                   1781:        if (s == 0)
                   1782:            return 0;           /* a is outside polygon b */
                   1783:        v.x = 1.1;
                   1784:        if (s == 1) {
                   1785:            s = intersect_polygon(v1, &v, b);
                   1786:            if (s == 0)
                   1787:                return 0;
                   1788:            if (s == 1)
                   1789:                return 1;
                   1790:        } else if (intersect_polygon(v1, &v, b) == 0)
                   1791:            return 0;
                   1792:     }
                   1793: #if 1
                   1794:     /* 970614: don't bother, just presume that they do overlap: */
                   1795:     return 1;
                   1796: #else /* !1 */
                   1797:     print_polygon(a, "a");
                   1798:     print_polygon(b, "b");
                   1799:     graph_error("Logic Error in full_xy_overlap");
                   1800:     return -1;                 /* HBB: shut up gcc -Wall */
                   1801: #endif /* !1 */
                   1802: }
                   1803:
                   1804:
                   1805: /* Helper routine for split_polygon_by_plane */
                   1806: static long build_new_vertex(V1, V2, w)
                   1807: long V1, V2;   /* the vertices, between which a new vertex is demanded */
                   1808: double w;      /* information about where between V1 and V2 it should be */
                   1809: {
                   1810:     long V;
                   1811:     struct Vertex GPHUGE *v, GPHUGE * v1, GPHUGE * v2;
                   1812:
                   1813:     if (EQ(w, 0.0))
                   1814:        return V1;
                   1815:     if (EQ(w, 1.0))
                   1816:        return V2;
                   1817:
                   1818:     /* We need a new Vertex */
                   1819:     if (vert_free == nvert)    /* Extend vlist, if necessary */
                   1820:        vlist = (struct Vertex GPHUGE *)
                   1821:            gp_realloc(vlist, (unsigned long) sizeof(struct Vertex) * (nvert += 10L), "hidden vlist");
                   1822:     V = vert_free++;
                   1823:     v = vlist + V;
                   1824:     v1 = vlist + V1;
                   1825:     v2 = vlist + V2;
                   1826:
                   1827:     v->x = (v2->x - v1->x) * w + v1->x;
                   1828:     v->y = (v2->y - v1->y) * w + v1->y;
                   1829:     v->z = (v2->z - v1->z) * w + v1->z;
                   1830:     v->style = -1;
                   1831:
                   1832:     /* 970610: additional checks, to prevent adding unnecessary vertices */
                   1833:     if (V_EQUAL(v, v1)) {
                   1834:        vert_free--;
                   1835:        return V1;
                   1836:     }
                   1837:     if (V_EQUAL(v, v2)) {
                   1838:        vert_free--;
                   1839:        return V2;
                   1840:     }
                   1841:     return V;
                   1842: }
                   1843:
                   1844:
                   1845: /* Splits polygon p by the plane represented by its equation
                   1846:  * coeffecients a to d.
                   1847:  * return-value: part of the polygon, that is in front/back of plane
                   1848:  * (Distinction necessary to ensure the ordering of polygons in
                   1849:  * the plist stays intact)
                   1850:  * Caution: plist and vlist can change their location!!!
                   1851:  * If a point is in plane, it comes to the behind - part
                   1852:  * (HBB: that may well have changed, as I cut at the 'in plane'
                   1853:  * mechanisms heavily)
                   1854:  */
                   1855:
                   1856: static long split_polygon_by_plane(P, a, b, c, d, f)
                   1857: long P;                                /* Polygon as index on plist */
                   1858: double a, b, c, d;
                   1859: TBOOLEAN f;                    /* return value = Front(1) or Back(0) */
                   1860: {
                   1861:     int i, j;
                   1862:     struct Polygon GPHUGE *p = plist + P;
                   1863:     struct Vertex GPHUGE *v;
                   1864:     int snew, stest;
                   1865:     int in_plane;              /* what is about points in plane? */
                   1866:     int cross1, cross2;                /* first vertices, after p crossed the plane */
                   1867:     double a1 = 0.0, b1, a2 = 0.0, b2; /* parameters of the crosses */
                   1868:     long Front;                        /* the new Polygon */
                   1869:     int n1, n2;
                   1870:     long *v1, *v2;
                   1871:     long line1, line2;
                   1872:     long next_frag_temp;
                   1873:
                   1874:
                   1875:     CHECK_POINTER(plist, p);
                   1876:
                   1877:     in_plane = (EQ(c, 0.0) && f) ? 1 : -1;
                   1878:     /* first vertex */
                   1879:     v = vlist + p->vertex[0];
                   1880:
                   1881:     CHECK_POINTER(vlist, v);
                   1882:
                   1883:     b1 = a * v->x + b * v->y + c * v->z + d;
                   1884:     stest = SIGNOF(b1);
                   1885: #if OLD_SPLIT_INPLANE
                   1886:     if (!stest)
                   1887:        stest = in_plane;
                   1888: #endif
                   1889:
                   1890:     /* find first vertex that is on the other side of the plane */
                   1891:     for (cross1 = 1, snew = stest; snew == stest && cross1 < p->n; cross1++) {
                   1892:        a1 = b1;
                   1893:        v = vlist + p->vertex[cross1];
                   1894:        CHECK_POINTER(vlist, v);
                   1895:        b1 = a * v->x + b * v->y + c * v->z + d;
                   1896:        snew = SIGNOF(b1);
                   1897: #if OLD_SPLIT_INPLANE
                   1898:        if (!snew)
                   1899:            snew = in_plane;
                   1900: #endif
                   1901:     }
                   1902:
                   1903:     if (snew == stest) {
                   1904:        /*HBB: this is possibly not an error in split_polygon, it's just
                   1905:         * not possible to split this polygon by this plane. I.e., the
                   1906:         * error is in the caller!  */
                   1907:        fprintf(stderr, "split_poly failed, polygon nr. %ld\n", P);
                   1908:        return (-1);            /* return 'unsplittable' */
                   1909:     }
                   1910:     cross1--;                  /* now, it's the last one on 'this' side */
                   1911:
                   1912:     /* first vertex that is on the first side again */
                   1913:     for (b2 = b1, cross2 = cross1 + 1;
                   1914:         snew != stest && cross2 < p->n; cross2++) {
                   1915:        a2 = b2;
                   1916:        v = vlist + p->vertex[cross2];
                   1917:        CHECK_POINTER(vlist, v);
                   1918:        b2 = a * v->x + b * v->y + c * v->z + d;
                   1919:        snew = SIGNOF(b2);
                   1920: #if OLD_SPLIT_INPLANE
                   1921:        if (!snew)
                   1922:            snew = -in_plane;
                   1923: #endif
                   1924:     }
                   1925:
                   1926:     if (snew != stest) {
                   1927:        /* only p->vertex[0] is on 'this' side */
                   1928:        a2 = b2;
                   1929:        v = vlist + p->vertex[0];
                   1930:        CHECK_POINTER(vlist, v);
                   1931:        b2 = a * v->x + b * v->y + c * v->z + d;
                   1932:     } else
                   1933:        cross2--;               /* now it's the last one on 'the other' side */
                   1934:
                   1935:     /* We need two new polygons instead of the old one: */
                   1936:     n1 = p->n - cross2 + cross1 + 2;
                   1937:     n2 = cross2 - cross1 + 2;
                   1938:     v1 = (long *) gp_alloc((unsigned long) sizeof(long) * n1,
                   1939:                           "hidden v1 for two new poly");
                   1940:     v2 = (long *) gp_alloc((unsigned long) sizeof(long) * n2,
                   1941:                           "hidden v2 for two new poly");
                   1942: #if SHOW_SPLITTING_EDGES
                   1943:     line1 = 1L << (n1 - 1);
                   1944:     line2 = 1L << (n2 - 1);
                   1945: #else
                   1946:     line1 = line2 = 0L;
                   1947: #endif
                   1948:     v1[0] = v2[n2 - 1] =
                   1949:        build_new_vertex(p->vertex[cross2 - 1],
                   1950:                p->vertex[(cross2 < p->n) ? cross2 : 0], a2 / (a2 - b2));
                   1951:     v2[0] = v1[n1 - 1] =
                   1952:        build_new_vertex(p->vertex[cross1 - 1],
                   1953:                         p->vertex[cross1], a1 / (a1 - b1));
                   1954:
                   1955:     /* Copy visibility from split edges to their fragments: */
                   1956:     if (p->line & (1 << (cross1 - 1))) {
                   1957:        line1 |= 1L << (n1 - 2);
                   1958:        line2 |= 1L;
                   1959:     }
                   1960:     if (p->line & (1L << (cross2 - 1))) {
                   1961:        line1 |= 1L;
                   1962:        line2 |= 1L << (n2 - 2);
                   1963:     }
                   1964:     /* Copy the old line patterns and vertex listings into new places */
                   1965:     /* p->vertex[cross2...p->n-1] --> v1[1...] */
                   1966:     for (i = cross2, j = 1; i < p->n;) {
                   1967:        if (p->line & (1L << i))
                   1968:            line1 |= 1L << j;
                   1969:        v1[j++] = p->vertex[i++];
                   1970:     }
                   1971:     /* p->vertex[0...cross1-1] --> v1[...n1-2] */
                   1972:     for (i = 0; i < cross1 - 1;) {
                   1973:        if (p->line & (1L << i))
                   1974:            line1 |= 1L << j;
                   1975:        v1[j++] = p->vertex[i++];
                   1976:     }
                   1977:     v1[j++] = p->vertex[i++];
                   1978:
                   1979:     /* p->vertex[cross1...cross2-1] -> v2[1...n2-2] */
                   1980:     for (j = 1; i < cross2 - 1;) {
                   1981:        if (p->line & (1L << i))
                   1982:            line2 |= 1L << j;
                   1983:        v2[j++] = p->vertex[i++];
                   1984:     }
                   1985:     v2[j++] = p->vertex[i];
                   1986:
                   1987:     /* old vertex list isn't needed any more: */
                   1988:     free(p->vertex);
                   1989:     p->vertex = 0;
                   1990:
                   1991:     if (!reduce_polygon(&n1, &v1, &line1, 1) ||
                   1992:        !reduce_polygon(&n2, &v2, &line2, 1))
                   1993:        graph_error("Logic Error 2 in split_polygon");
                   1994:
                   1995:     /* Build the 2 new polygons : we are reusing one + making one new */
                   1996:     CHECK_PLIST_EXTRA(p = plist + P);
                   1997:     Front = pfree++;
                   1998:
                   1999:     if ((next_frag_temp = p->next_frag) < 0)
                   2000:        next_frag_temp = P;     /* First split of this polygon at all */
                   2001:
                   2002:     /* HBB 961110: lclint said == shouldn't be used on Boolean's */
                   2003:     if ((f && (stest < 0)) || ((!f) && !(stest < 0))) {
                   2004:        build_polygon(plist + P, n1, v1, line1, p->style, p->lp,
                   2005:                      p->next, Front, p->id, p->tested);
                   2006:        build_polygon(plist + Front, n2, v2, line2, p->style, p->lp,
                   2007:                      -1, next_frag_temp, p->id, is_moved_or_split);
                   2008:     } else {
                   2009:        build_polygon(plist + P, n2, v2, line2, p->style, p->lp,
                   2010:                      p->next, Front, p->id, p->tested);
                   2011:        build_polygon(plist + Front, n1, v1, line1, p->style, p->lp,
                   2012:                      -1, next_frag_temp, p->id, is_moved_or_split);
                   2013:     }
                   2014:     return Front;
                   2015: }
                   2016:
                   2017: /* HBB: these pieces of code are found repeatedly in in_front(), so
                   2018:  * I put them into macros
                   2019:  * Note: can't use the 'do {...} while (0)' method for
                   2020:  * these: 'continue' wouldn't work any more.
                   2021:  */
                   2022: #define PUT_P_IN_FRONT_TEST(new_tested) {\
                   2023:   plist[Plast].next = p->next; \
                   2024:   p->next = Test; \
                   2025:   p->tested = new_tested; \
                   2026:   if (Insert >= 0) \
                   2027:     plist[Insert].next = P; \
                   2028:   else \
                   2029:     pfirst = P; \
                   2030:   Insert = P; \
                   2031:   P = Plast; \
                   2032:   p = plist + P; \
                   2033:   continue; \
                   2034: }
                   2035:
                   2036: #define SPLIT_TEST_BY_P {\
                   2037:   long Back = split_polygon_by_plane (Test, pa, pb, pc, pd, 0); \
                   2038:   if (Back >0) { \
                   2039:     p = plist + P; \
                   2040:     test = plist + Test;  /* plist can change */ \
                   2041:     plist[Back].next = p->next; \
                   2042:     p->next = Back; \
                   2043:     P = Back; \
                   2044:     p = plist + P; \
                   2045:     zmin = test->zmin;  /* the new z-value */ \
                   2046:   } else { \
                   2047:     fprintf(stderr, "Failed to split test (%ld) by p (%ld)\n", Test, P); \
                   2048:     graph_error("Error in hidden line removal: couldn't split..."); \
                   2049:   } \
                   2050:   continue; \
                   2051: }
                   2052:
                   2053: #define SPLIT_P_BY_TEST {\
                   2054:   long Front = split_polygon_by_plane (P, ta, tb, tc, td, 1);\
                   2055:   if (Front >0) {\
                   2056:     p = plist + P;\
                   2057:     test = plist + Test;       /* plist can change */\
                   2058:     plist[Front].next = Test;\
                   2059:     if (Insert >= 0)\
                   2060:       plist[Insert].next = Front;\
                   2061:     else\
                   2062:       pfirst = Front;\
                   2063:     Insert = Front;\
                   2064:   } else {\
                   2065:     fprintf(stderr, "Failed to split p (%ld) by test(%ld), relations are %d, %d\n", P, Test, p_rel_tplane, t_rel_pplane);\
                   2066:     print_polygon(test, "test");\
                   2067:     print_polygon(p, "p");\
                   2068:     fputc('\n', stderr);\
                   2069:   }\
                   2070:   continue; /* FIXME: should we continue nevertheless? */\
                   2071: }
                   2072:
                   2073:
                   2074: /* Is Test in front of the other polygons?
                   2075:  * If not, polygons which are in front of test come between
                   2076:  * Last and Test (I.e. to the 'front' of the plist)
                   2077:  */
                   2078: static int in_front(Last, Test)
                   2079: long Last, Test;
                   2080: {
                   2081:     struct Polygon GPHUGE *test = plist + Test, GPHUGE * p;
                   2082:     long Insert, P, Plast;
                   2083:     double zmin,               /* minimum z-value of Test */
                   2084:      ta, tb, tc, td,           /* the plane of Test      */
                   2085:      pa, pb, pc, pd;           /* the plane of a polygon */
                   2086:     t_poly_plane_intersect p_rel_tplane, t_rel_pplane;
                   2087:     int loop = (test->tested == is_in_loop);
                   2088:
                   2089:     CHECK_POINTER(plist, test);
                   2090:
                   2091:     /* Maybe this should only done at the end of this routine... */
                   2092:     /* test->tested = is_tested; */
                   2093:
                   2094:     Insert = Last;
                   2095:
                   2096:     /* minimal z-value of Test */
                   2097:     zmin = test->zmin;
                   2098:
                   2099:     /* The plane of the polygon Test */
                   2100:     get_plane(test, &ta, &tb, &tc, &td);
                   2101:
                   2102:     /* Compare Test with the following polygons, which overlap in z value */
                   2103:     for (Plast = Test, p = test;
                   2104:         ((P = p->next) >= 0) && (((p = plist + P)->zmax > zmin) || (p->tested != 0));
                   2105:         Plast = P) {
                   2106:        CHECK_POINTER(plist, p);
                   2107:
                   2108:        if (!xy_overlap(test, p))
                   2109:            continue;
                   2110:
                   2111:        if (p->zmax <= zmin)
                   2112:            continue;
                   2113:
                   2114:        p_rel_tplane = polygon_plane_intersection(p, ta, tb, tc, td);
                   2115:        if ((p_rel_tplane == behind) || (p_rel_tplane == inside))
                   2116:            continue;
                   2117:
                   2118:        get_plane(p, &pa, &pb, &pc, &pd);
                   2119:        t_rel_pplane = polygon_plane_intersection(test, pa, pb, pc, pd);
                   2120:        if ((t_rel_pplane == infront) || (t_rel_pplane == inside))
                   2121:            continue;
                   2122:
                   2123:        if (!full_xy_overlap(test, p))
                   2124:            continue;
                   2125:
                   2126: #if 1
                   2127:        /* HBB 971115: try new approach developed directly from Foley et
                   2128:         * al.'s original description */
                   2129:        /* OK, at this point, a total of 16 cases is left to be handled,
                   2130:         * as 4 variables are important, each with two possible values:
                   2131:         * t_rel_pplane may be 'behind' or 'intersects', p_rel_tplane may
                   2132:         * be 'infront' or 'intersects', 'test' may be (seem to be) part
                   2133:         * of a loop or not ('loop'), and p may have been considered
                   2134:         * already or not (p->tested =?= is_tested). */
                   2135:        /* See if splitting wherever possible is a good idea: */
                   2136:        if (p_rel_tplane == intersects) {
                   2137:            p->tested = is_moved_or_split;
                   2138:            SPLIT_P_BY_TEST;
                   2139:        } else if (t_rel_pplane == intersects) {
                   2140:            test->tested = is_moved_or_split;
                   2141:            SPLIT_TEST_BY_P;
                   2142:        } else {
                   2143:            if (loop && (p->tested == is_tested)) {
                   2144:                /* Ouch, seems like we're in trouble, really */
                   2145:                fprintf(stderr, "\
                   2146: #Failed: In loop, without intersections.\n\
                   2147: #Relations are %d, %d\n",
                   2148:                        p_rel_tplane, t_rel_pplane);
                   2149:                print_polygon(test, "test");
                   2150:                print_polygon(p, "p");
                   2151:                continue;       /* Keep quiet, maybe no-one will notice (;-) */
                   2152:            } else {
                   2153:                PUT_P_IN_FRONT_TEST(is_in_loop);
                   2154:            }
                   2155:        }
                   2156: #else
                   2157:        /* p obscures test (at least, this *might* be happening */
                   2158:        if (loop) {
                   2159:            /* if P isn't interesting for the loop, put P in front of Test */
                   2160:            if ((p->tested != is_tested)
                   2161:                || (p_rel_tplane == infront)
                   2162:                || (t_rel_pplane == behind))    /* HBB 970325: was infront (!?) */
                   2163:                PUT_P_IN_FRONT_TEST(is_moved_or_split);
                   2164:
                   2165:            /* else, split either test or p */
                   2166:            if (t_rel_pplane == intersects)
                   2167:                SPLIT_TEST_BY_P;
                   2168:            if (p_rel_tplane == intersects)
                   2169:                SPLIT_P_BY_TEST;
                   2170:
                   2171:            /* HBB: if we ever come through here, something went severely wrong */
                   2172:            fprintf(stderr, "Failed: polygon %ld vs. %ld, relations are %d, %d\n", P, Test, p_rel_tplane, t_rel_pplane);
                   2173:            print_polygon(test, "test");
                   2174:            print_polygon(p, "p");
                   2175:            fputc('\n', stderr);
                   2176:            graph_error("Couldn't resolve a polygon overlapping pb. Go tell HBB...");
                   2177:        }
                   2178:        /* No loop: if it makes sense, put P in front of Test */
                   2179:        if ((p->tested != is_tested)
                   2180:            && ((t_rel_pplane == behind)
                   2181:                || (p_rel_tplane == infront)))
                   2182:            PUT_P_IN_FRONT_TEST(is_moved_or_split);
                   2183:
                   2184:        /* If possible, split P */
                   2185:        if ((p->tested != is_tested) || (p_rel_tplane == intersects))
                   2186:            SPLIT_P_BY_TEST;
                   2187:
                   2188:        /* if possible, split Test */
                   2189:        if (t_rel_pplane == intersects)
                   2190:            SPLIT_TEST_BY_P;
                   2191:
                   2192:        /* else, we have a loop: mark P as loop and put it in front of Test */
                   2193:        PUT_P_IN_FRONT_TEST(is_in_loop);        /* -2: p is in a loop */
                   2194: #endif
                   2195:     }
                   2196:     if (Insert == Last)
                   2197:        test->tested = is_tested;
                   2198:     return (int) (Insert == Last);
                   2199: }
                   2200:
                   2201:
                   2202: /* Drawing the polygons */
                   2203:
                   2204: /* HBB 980303: new functions to handle Cross back-buffer (saves
                   2205:  * gp_alloc()'s) */
                   2206:
                   2207: static GP_INLINE void init_Cross_store()
                   2208: {
                   2209:     assert(!Cross_store && !last_Cross_store);
                   2210:     last_Cross_store = CROSS_STORE_INCREASE;
                   2211:     free_Cross_store = 0;
                   2212:     Cross_store = (struct Cross *)
                   2213:        gp_alloc((unsigned long) last_Cross_store * sizeof(struct Cross),
                   2214:                 "hidden cross store");
                   2215: }
                   2216:
                   2217: static GP_INLINE struct Cross *get_Cross_from_store()
                   2218: {
                   2219:     while (last_Cross_store <= free_Cross_store) {
                   2220:        last_Cross_store += CROSS_STORE_INCREASE;
                   2221:        Cross_store = (struct Cross *)
                   2222:            gp_realloc(Cross_store,
                   2223:                 (unsigned long) last_Cross_store * sizeof(struct Cross),
                   2224:                       "hidden cross store");
                   2225:     }
                   2226:     return Cross_store + (free_Cross_store++);
                   2227: }
                   2228:
                   2229: static GP_INLINE TBOOLEAN
                   2230:  hl_buffer_set(xv, yv)
                   2231: int xv, yv;
                   2232: {
                   2233:     struct Cross GPHUGE *c;
                   2234:     /*HBB 961110: lclint wanted this: */
                   2235:     assert(hl_buffer != 0);
                   2236:     for (c = hl_buffer[xv]; c != NULL; c = c->next)
                   2237:        if (c->a <= yv && c->b >= yv) {
                   2238:            return TRUE;
                   2239:        }
                   2240:     return FALSE;
                   2241: }
                   2242:
                   2243: /* HBB 961201: new var's, to speed up free()ing hl_buffer later */
                   2244: static int hl_buff_xmin, hl_buff_xmax;
                   2245:
                   2246: /* HBB 961124: new routine. All this occured twice in
                   2247:  * draw_clip_line_buffer */
                   2248: /* Store a line crossing the x interval around xv between y = ya and
                   2249:  * y = yb in the hl_buffer */
                   2250: static GP_INLINE void update_hl_buffer_column(xv, ya, yb)
                   2251: int xv, ya, yb;
                   2252: {
                   2253:     struct Cross GPHUGE *GPHUGE * cross, GPHUGE * cross2;
                   2254:
                   2255:     /* First, ensure that ya <= yb */
                   2256:     if (ya > yb) {
                   2257:        int y_temp = yb;
                   2258:        yb = ya;
                   2259:        ya = y_temp;
                   2260:     }
                   2261:     /* loop over all previous crossings at this x-value */
                   2262:     for (cross = hl_buffer + xv; 1; cross = &(*cross)->next) {
                   2263:        if (*cross == NULL) {
                   2264:            /* first or new highest crossing at this x-value */
                   2265:
                   2266:            /* HBB 980303: new method to allocate Cross structures */
                   2267:            *cross = get_Cross_from_store();
                   2268:            (*cross)->a = ya;
                   2269:            (*cross)->b = yb;
                   2270:            (*cross)->next = NULL;
                   2271:            /* HBB 961201: keep track of x-range of hl_buffer, to
                   2272:             * speedup free()ing it */
                   2273:            if (xv < hl_buff_xmin)
                   2274:                hl_buff_xmin = xv;
                   2275:            if (xv > hl_buff_xmax)
                   2276:                hl_buff_xmax = xv;
                   2277:            break;
                   2278:        }
                   2279:        if (yb < (*cross)->a - 1) {
                   2280:            /* crossing below 'cross', create new entry before 'cross' */
                   2281:            cross2 = *cross;
                   2282:            /* HBB 980303: new method to allocate Cross structures */
                   2283:            *cross = get_Cross_from_store();
                   2284:            (*cross)->a = ya;
                   2285:            (*cross)->b = yb;
                   2286:            (*cross)->next = cross2;
                   2287:            break;
                   2288:        } else if (ya <= (*cross)->b + 1) {
                   2289:            /* crossing overlaps or covers 'cross' */
                   2290:            if (ya < (*cross)->a)
                   2291:                (*cross)->a = ya;
                   2292:            if (yb > (*cross)->b) {
                   2293:                if ((*cross)->next && (*cross)->next->a <= yb) {
                   2294:                    /* crossing spans all the way up to 'cross->next' so
                   2295:                     * unite them */
                   2296:                    cross2 = (*cross)->next;
                   2297:                    (*cross)->b = cross2->b;
                   2298:                    (*cross)->next = cross2->next;
                   2299:                } else
                   2300:                    (*cross)->b = yb;
                   2301:            }
                   2302:            break;
                   2303:        }
                   2304:     }
                   2305:     return;
                   2306: }
                   2307:
                   2308:
                   2309: static void draw_clip_line_buffer(x1, y1, x2, y2)
                   2310: int x1, y1, x2, y2;
                   2311:      /* Draw a line in the hl_buffer */
                   2312: {
                   2313:     register int xv, yv, errx, erry, err;
                   2314:     register int dy, nstep;
                   2315:     register int ya;
                   2316:     int i;
                   2317:
                   2318:     if (!clip_line(&x1, &y1, &x2, &y2)) {
                   2319:        /*printf("dcl_buffer: clipped away!\n"); */
                   2320:        return;
                   2321:     }
                   2322:     if (x1 > x2) {
                   2323:        errx = XREDUCE(x1) - XREDUCE(x2);
                   2324:        erry = YREDUCE(y1) - YREDUCE(y2);
                   2325:        xv = XREDUCE(x2) - XREDUCE(xleft);
                   2326:        yv = YREDUCE(y2) - YREDUCE(ybot);
                   2327:     } else {
                   2328:        errx = XREDUCE(x2) - XREDUCE(x1);
                   2329:        erry = YREDUCE(y2) - YREDUCE(y1);
                   2330:        xv = XREDUCE(x1) - XREDUCE(xleft);
                   2331:        yv = YREDUCE(y1) - YREDUCE(ybot);
                   2332:     }
                   2333:     if (erry > 0)
                   2334:        dy = 1;
                   2335:     else {
                   2336:        dy = -1;
                   2337:        erry = -erry;
                   2338:     }
                   2339:     nstep = errx + erry;
                   2340:     err = -errx + erry;
                   2341:     errx <<= 1;
                   2342:     erry <<= 1;
                   2343:     ya = yv;
                   2344:
                   2345:     for (i = 0; i < nstep; i++) {
                   2346:        if (err < 0) {
                   2347:            update_hl_buffer_column(xv, ya, yv);
                   2348:            xv++;
                   2349:            ya = yv;
                   2350:            err += erry;
                   2351:        } else {
                   2352:            yv += dy;
                   2353:            err -= errx;
                   2354:        }
                   2355:     }
                   2356:     (void) update_hl_buffer_column(xv, ya, yv);
                   2357:     return;
                   2358: }
                   2359:
                   2360:
                   2361: /* HBB 961124: improve similarity of this routine with
                   2362:  * draw_clip_line_buffer ()
                   2363:  *
                   2364:  * HBB 961124: changed from 'virtual' to 'do_draw', for clarity (this
                   2365:  * also affects the routines calling this one, so beware!
                   2366:  *
                   2367:  * HBB 961124: introduced checking code, to search for the 'holes in
                   2368:  * the surface' bug
                   2369:  *
                   2370:  * Draw a line into the bitmap (**cpnt), and optionally also to the
                   2371:  * terminal
                   2372:  */
                   2373: static void draw_clip_line_update(x1, y1, x2, y2, do_draw)
                   2374: int x1, y1, x2, y2;
                   2375: TBOOLEAN do_draw;
                   2376: {
                   2377:     /* HBB 961110: made 'flag' a boolean variable, which needs some
                   2378:      *  other changes below as well
                   2379:      *
                   2380:      * HBB 970508: renamed 'flag' to 'is_drawn' (reverting its meaning).
                   2381:      * Should be clearer now
                   2382:      */
                   2383:     TBOOLEAN is_drawn;
                   2384:     register struct termentry *t = term;
                   2385:     register int xv, yv, errx, erry, err;
                   2386:     register int xvr, yvr;
                   2387:     int xve, yve;
                   2388:     register int dy, nstep = 0, dyr;
                   2389:     int i;
                   2390:     if (!clip_line(&x1, &y1, &x2, &y2)) {
                   2391:        /*printf("dcl_update: clipped away!\n"); */
                   2392:        return;
                   2393:     }
                   2394:     if (x1 > x2) {
                   2395:        xvr = x2;
                   2396:        yvr = y2;
                   2397:        xve = x1;
                   2398:        yve = y1;
                   2399:     } else {
                   2400:        xvr = x1;
                   2401:        yvr = y1;
                   2402:        xve = x2;
                   2403:        yve = y2;
                   2404:     }
                   2405:     errx = XREDUCE(xve) - XREDUCE(xvr);
                   2406:     erry = YREDUCE(yve) - YREDUCE(yvr);
                   2407:     if (erry > 0)
                   2408:        dy = 1;
                   2409:     else {
                   2410:        dy = -1;
                   2411:        erry = -erry;
                   2412:     }
                   2413:     dyr = dy * yfact;
                   2414:     nstep = errx + erry;
                   2415:     err = -errx + erry;
                   2416:     errx <<= 1;
                   2417:     erry <<= 1;
                   2418:     xv = XREDUCE(xvr) - XREDUCE(xleft);
                   2419:     yv = YREDUCE(yvr) - YREDUCE(ybot);
                   2420:     (*t->move) ((unsigned int) xvr, (unsigned int) yvr);
                   2421:
                   2422:     is_drawn = (IS_UNSET(xv, yv) && (do_draw || hl_buffer_set(xv, yv)));
                   2423:
                   2424:     /* HBB 961110: lclint wanted these: */
                   2425:     assert(ymin_hl != 0);
                   2426:     assert(ymax_hl != 0);
                   2427:     /* Check first point in hl-buffer */
                   2428:     if (xv < xmin_hl)
                   2429:        xmin_hl = xv;
                   2430:     if (xv > xmax_hl)
                   2431:        xmax_hl = xv;
                   2432:     if (yv < ymin_hl[xv])
                   2433:        ymin_hl[xv] = yv;
                   2434:     if (yv > ymax_hl[xv])
                   2435:        ymax_hl[xv] = yv;
                   2436:     for (i = 0; i < nstep; i++) {
                   2437:        /* 970722: new variables */
                   2438:        unsigned int xvr_temp = xvr, yvr_temp = yvr;
                   2439:        if (err < 0) {
                   2440:            xv++;
                   2441:            xvr += xfact;
                   2442:            err += erry;
                   2443:        } else {
                   2444:            yv += dy;
                   2445:            yvr += dyr;
                   2446:            err -= errx;
                   2447:        }
                   2448:        if (IS_UNSET(xv, yv) && (do_draw || hl_buffer_set(xv, yv))) {
                   2449:            if (!is_drawn) {
                   2450:                /* 970722: If this line was meant to be drawn, originally,
                   2451:                 * and it was just the bitmap that stopped it, then draw
                   2452:                 * it a bit longer (i.e.: start one pixel earlier
                   2453:                 */
                   2454:                if (do_draw)
                   2455:                    (*t->move) ((unsigned int) xvr_temp, (unsigned int) yvr_temp);
                   2456:                else
                   2457:                    (*t->move) ((unsigned int) xvr, (unsigned int) yvr);
                   2458:                is_drawn = TRUE;
                   2459:            }
                   2460:        } else {
                   2461:            if (is_drawn) {
                   2462:                /* 970722: If this line is only drawn because hl_buffer_set()
                   2463:                 * was true, then don't extend to the new position (where it
                   2464:                 * isn't true any more). Draw the line one pixel shorter,
                   2465:                 * instead:
                   2466:                 */
                   2467:                if (do_draw)
                   2468:                    (*t->vector) ((unsigned int) xvr, (unsigned int) yvr);
                   2469:                else {
                   2470:                    (*t->vector) ((unsigned int) xvr_temp, (unsigned int) yvr_temp);
                   2471:                    (*t->move) ((unsigned int) xvr, (unsigned int) yvr);
                   2472:                }
                   2473:                is_drawn = FALSE;
                   2474:            }
                   2475:        }
                   2476:        if (xv < xmin_hl)
                   2477:            xmin_hl = xv;
                   2478:        if (xv > xmax_hl)
                   2479:            xmax_hl = xv;
                   2480:        if (yv < ymin_hl[xv])
                   2481:            ymin_hl[xv] = yv;
                   2482:        if (yv > ymax_hl[xv])
                   2483:            ymax_hl[xv] = yv;
                   2484:     }
                   2485:     if (is_drawn)
                   2486:        (*t->vector) ((unsigned int) xvr, (unsigned int) yvr);
                   2487:     return;
                   2488: }
                   2489:
                   2490: #define DRAW_VERTEX(v, x, y) do { \
                   2491:    if ((v)->style >= 0 &&                                            \
                   2492:        !clip_point(x,y)  &&                                        \
                   2493:        IS_UNSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot))) \
                   2494:      (*t->point)(x,y, v->style);                                   \
                   2495:    (v)->style = -1;                                                  \
                   2496: } while (0)
                   2497:
                   2498: /* Two routines to emulate move/vector sequence using line drawing routine. */
                   2499: static unsigned int move_pos_x, move_pos_y;
                   2500:
                   2501: void clip_move(x, y)
                   2502: unsigned int x, y;
                   2503: {
                   2504:     move_pos_x = x;
                   2505:     move_pos_y = y;
                   2506: }
                   2507:
                   2508: void clip_vector(x, y)
                   2509: unsigned int x, y;
                   2510: {
                   2511:     draw_clip_line(move_pos_x, move_pos_y, x, y);
                   2512:     move_pos_x = x;
                   2513:     move_pos_y = y;
                   2514: }
                   2515:
                   2516: static GP_INLINE void clip_vector_h(x, y)
                   2517: int x, y;
                   2518:      /* Draw a line on terminal and update bitmap */
                   2519: {
                   2520:     draw_clip_line_update(move_pos_x, move_pos_y, x, y, TRUE);
                   2521:     move_pos_x = x;
                   2522:     move_pos_y = y;
                   2523: }
                   2524:
                   2525:
                   2526: static GP_INLINE void clip_vector_virtual(x, y)
                   2527: int x, y;
                   2528:      /* update bitmap, do not really draw the line */
                   2529: {
                   2530:     draw_clip_line_update(move_pos_x, move_pos_y, x, y, FALSE);
                   2531:     move_pos_x = x;
                   2532:     move_pos_y = y;
                   2533: }
                   2534:
                   2535: static GP_INLINE void clip_vector_buffer(x, y)
                   2536:      /* draw a line in the hl_buffer */
                   2537: int x, y;
                   2538: {
                   2539:     draw_clip_line_buffer(move_pos_x, move_pos_y, x, y);
                   2540:     move_pos_x = x;
                   2541:     move_pos_y = y;
                   2542: }
                   2543:
                   2544: static void draw(p)
                   2545: struct Polygon GPHUGE *p;
                   2546: {
                   2547:     struct Vertex GPHUGE *v;
                   2548:     struct Polygon GPHUGE *q;
                   2549:     long Q;
                   2550:     int i;
                   2551:     int x, y;                  /* point in terminal coordinates */
                   2552:     register struct termentry *t = term;
                   2553:     t_pnt mask1, mask2;
                   2554:     long int indx1, indx2, k;
                   2555:     tp_pnt cpnt;
                   2556:
                   2557:     xmin_hl = HL_EXTENT_X_MAX; /* HBB 961124: parametrized this value */
                   2558:     xmax_hl = 0;
                   2559:
                   2560:     /* HBB 961201: store initial values for range of hl_buffer: */
                   2561:     hl_buff_xmin = XREDUCE(xright) - XREDUCE(xleft);
                   2562:     hl_buff_xmax = 0;
                   2563:
                   2564:     /* Write the lines of all polygons with the same id as p in the hl_buffer */
                   2565:     /* HBB 961201: use next_frag pointers to loop over fragments: */
                   2566:     for (q = p; (Q = q->next_frag) >= 0 && (q = plist + Q) != p;) {
                   2567:        if (q->id != p->id)
                   2568:            continue;
                   2569:
                   2570:        /* draw the lines of q into hl_buffer: */
                   2571:        v = vlist + q->vertex[0];
                   2572:        TERMCOORD(v, x, y);
                   2573:        clip_move(x, y);
                   2574:        for (i = 1; i < q->n; i++) {
                   2575:            v = vlist + q->vertex[i];
                   2576:            TERMCOORD(v, x, y);
                   2577:            if (q->line & (1L << (i - 1)))
                   2578:                clip_vector_buffer(x, y);
                   2579:            else
                   2580:                clip_move(x, y);
                   2581:        }
                   2582:        if (q->line & (1L << (i - 1))) {
                   2583:            v = vlist + q->vertex[0];
                   2584:            TERMCOORD(v, x, y);
                   2585:            clip_vector_buffer(x, y);
                   2586:        }
                   2587:     }
                   2588:
                   2589:
                   2590:     /* first, set the line and point styles: */
                   2591:     {
                   2592:        struct lp_style_type lp;
                   2593:
                   2594:        lp = *(p->lp);
                   2595:        lp.l_type = p->style;
                   2596:        term_apply_lp_properties(&(lp));
                   2597:     }
                   2598:
                   2599:     /*print_polygon (p, "drawing"); */
                   2600:
                   2601:     /* draw the lines of p */
                   2602:     v = vlist + p->vertex[0];
                   2603:     TERMCOORD(v, x, y);
                   2604:     clip_move(x, y);
                   2605:     DRAW_VERTEX(v, x, y);
                   2606:     for (i = 1; i < p->n; i++) {
                   2607:        v = vlist + p->vertex[i];
                   2608:        TERMCOORD(v, x, y);
                   2609:        if (p->line & (1L << (i - 1)))
                   2610:            clip_vector_h(x, y);
                   2611:        else
                   2612:            clip_vector_virtual(x, y);
                   2613:        DRAW_VERTEX(v, x, y);
                   2614:     }
                   2615:     TERMCOORD(vlist + p->vertex[0], x, y);
                   2616:     if (p->line & (1L << (i - 1)))
                   2617:        clip_vector_h(x, y);
                   2618:     else
                   2619:        clip_vector_virtual(x, y);
                   2620:
                   2621:
                   2622:     /* reset the hl_buffer */
                   2623:     /*HBB 961110: lclint wanted this: */
                   2624:     assert(hl_buffer);
                   2625:     for (i = hl_buff_xmin; i <= hl_buff_xmax; i++) {
                   2626:        /* HBB 980303: one part was removed here. It isn't needed any more,
                   2627:         * with the global store for Cross structs. */
                   2628:        hl_buffer[i] = NULL;
                   2629:     }
                   2630:     /* HBB 980303: instead, set back the free pointer of the Cross store: */
                   2631:     free_Cross_store = 0;
                   2632:
                   2633:     /* now mark the area as being filled in the bitmap. */
                   2634:     /* HBB 971115: Yes, I do know that xmin_hl is unsigned, and the
                   2635:      * first test is thus useless. But I'd like to keep it anyway ;-) */
                   2636:     if (xmin_hl < 0 || xmax_hl > XREDUCE(xright) - XREDUCE(xleft))
                   2637:        graph_error("Logic error #3 in hidden line");
                   2638:     /* HBB 961110: lclint wanted these: */
                   2639:     assert(ymin_hl != 0);
                   2640:     assert(ymax_hl != 0);
                   2641:     assert(pnt != 0);
                   2642:     if (xmin_hl < xmax_hl)
                   2643:        for (i = xmin_hl; i <= xmax_hl; i++) {
                   2644:            if (ymin_hl[i] == HL_EXTENT_Y_MAX)
                   2645:                graph_error("Logic error #2 in hidden line");
                   2646:            if (pnt[i] == 0) {
                   2647:                pnt[i] = (t_pnt *) gp_alloc((unsigned long) y_malloc, "hidden ymalloc");
                   2648:                memset(pnt[i], 0, (size_t) y_malloc);
                   2649:            }
                   2650:            if (ymin_hl[i] < 0 || ymax_hl[i] > YREDUCE(ytop) - YREDUCE(ybot))
                   2651:                graph_error("Logic error #1 in hidden line");
                   2652:            /* HBB 970508: this shift was wordsize dependent
                   2653:             * I think I fixed that
                   2654:             */
                   2655:            indx1 = ymin_hl[i] / PNT_BITS;
                   2656:            indx2 = ymax_hl[i] / PNT_BITS;
                   2657:            mask1 = PNT_MAX << (((unsigned) ymin_hl[i]) % PNT_BITS);
                   2658:            mask2 = PNT_MAX >> ((~((unsigned) ymax_hl[i])) % PNT_BITS);
                   2659:            cpnt = pnt[i] + indx1;
                   2660:            if (indx1 == indx2)
                   2661:                *cpnt |= (mask1 & mask2);
                   2662:            else {
                   2663:                *cpnt++ |= mask1;
                   2664:                for (k = indx1 + 1; k < indx2; k++)
                   2665:                    *cpnt++ = PNT_MAX;
                   2666:                *cpnt |= mask2;
                   2667:            }
                   2668:            ymin_hl[i] = HL_EXTENT_Y_MAX;
                   2669:            ymax_hl[i] = 0;
                   2670:        }
                   2671: }
                   2672:
                   2673:
                   2674: void plot3d_hidden(plots, pcount)
                   2675: struct surface_points *plots;
                   2676: int pcount;
                   2677: {
                   2678:     long Last, This;
                   2679:     long i;
                   2680:
                   2681: #if defined(DOS16) || defined(WIN16)
                   2682:     /* HBB 980309: Ensure that Polygon Structs exactly fit a 64K segment. The
                   2683:      * problem this prevents is that even with 'huge pointers', a single
                   2684:      * struct may not cross a 64K boundary: it will wrap around to the
                   2685:      * beginning of that 64K segment. Someone ought to complain about
                   2686:      * this nuisance, somewhere... :-( */
                   2687:     assert(0 == (0x1 << 16) % (sizeof(struct Polygon)));
                   2688: #endif
                   2689:
                   2690:     /* Initialize global variables */
                   2691:     y_malloc = (2 + (YREDUCE(ytop) >> 4) - (YREDUCE(ybot) >> 4)) * sizeof(t_pnt);
                   2692:     /* ymin_hl, ymax_hl: */
                   2693:     i = sizeof(t_hl_extent_y) * (XREDUCE(xright) - XREDUCE(xleft) + 1);
                   2694:     ymin_hl = (t_hl_extent_y *) gp_alloc((unsigned long) i, "hidden ymin_hl");
                   2695:     ymax_hl = (t_hl_extent_y *) gp_alloc((unsigned long) i, "hidden ymax_hl");
                   2696:     for (i = (XREDUCE(xright) - XREDUCE(xleft)); i >= 0; i--) {
                   2697:        ymin_hl[i] = HL_EXTENT_Y_MAX;
                   2698:        ymax_hl[i] = 0;
                   2699:     }
                   2700:     /* hl_buffer: */
                   2701:     /* HBB 980303 new: initialize the global store for Cross structs: */
                   2702:     init_Cross_store();
                   2703:     i = XREDUCE(xright) - XREDUCE(xleft) + 1;
                   2704:     hl_buffer =
                   2705:        (struct Cross GPHUGE * GPHUGE *) gp_alloc((unsigned long) (i * sizeof(struct Cross GPHUGE *)),
                   2706:                                                  "hidden hl_buffer");
                   2707:     while (--i >= 0)
                   2708:        hl_buffer[i] = (struct Cross *) 0;
                   2709:
                   2710:     init_polygons(plots, pcount);
                   2711:
                   2712:     /* HBB 970326: if no polygons survived the cutting away of undefined
                   2713:      * and/or outranged vertices, bail out with a warning message.
                   2714:      * Without this, sort_by_zmax gets a SegFault */
                   2715:     if (!pfree) {
                   2716:        /* HBB 980701: new code to deallocate all the structures allocated up
                   2717:         * to this point. Should fix the core dump reported by
                   2718:         * Stefan A. Deutscher today  */
                   2719:        if (ymin_hl) {
                   2720:            free(ymin_hl);
                   2721:            ymin_hl = 0;
                   2722:        }
                   2723:        if (ymax_hl) {
                   2724:            free(ymax_hl);
                   2725:            ymax_hl = 0;
                   2726:        }
                   2727:        if (hl_buffer) {
                   2728:            free(hl_buffer);
                   2729:            hl_buffer = 0;
                   2730:        }
                   2731:        if (Cross_store) {
                   2732:            free(Cross_store);
                   2733:            Cross_store = 0;
                   2734:            last_Cross_store = 0;
                   2735:        }
                   2736:        graph_error("*All* polygons undefined or out of range, thus no plot.");
                   2737:     }
                   2738:     sort_by_zmax();
                   2739:
                   2740:     /* sort the polygons and draw them in one loop */
                   2741:     Last = -1L;
                   2742:     This = pfirst;
                   2743:     /* Search first polygon, that can be drawn */
                   2744:     while (Last == -1L && This >= 0L) {
                   2745:        This = pfirst;
                   2746:        if (obscured(plist + This)) {
                   2747:            Last = This;
                   2748:            continue;
                   2749:        }
                   2750:        if (plist[This].tested != is_tested && !in_front(Last, This))
                   2751:            continue;
                   2752:        draw(plist + This);
                   2753:        Last = This;
                   2754:     }
                   2755:     /* Draw the other polygons */
                   2756:     for (This = plist[Last].next; This >= 0L; This = plist[Last].next) {
                   2757:        if (obscured(plist + This)) {
                   2758:            Last = This;
                   2759:            continue;
                   2760:        }
                   2761:        if (plist[This].tested != is_tested && !in_front(Last, This))
                   2762:            continue;
                   2763:        draw(plist + This);
                   2764:        Last = This;
                   2765:     }
                   2766:
                   2767:     /* Free memory */
                   2768:     if (plist) {
                   2769:        for (This = 0L; This < pfree; This++)
                   2770:            free(plist[This].vertex);
                   2771:        free(plist);
                   2772:        plist = 0;
                   2773:     }
                   2774:     if (vlist) {
                   2775:        free(vlist);
                   2776:        vlist = 0;
                   2777:     }
                   2778:     if (ymin_hl) {
                   2779:        free(ymin_hl);
                   2780:        ymin_hl = 0;
                   2781:     }
                   2782:     if (ymax_hl) {
                   2783:        free(ymax_hl);
                   2784:        ymax_hl = 0;
                   2785:     }
                   2786:     if (hl_buffer) {
                   2787:        free(hl_buffer);
                   2788:        hl_buffer = 0;
                   2789:     }
                   2790:     if (Cross_store) {
                   2791:        free(Cross_store);
                   2792:        Cross_store = 0;
                   2793:        last_Cross_store = 0;
                   2794:     }
                   2795: }

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