Annotation of OpenXM_contrib/gnuplot/hidden3d.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: hidden3d.c,v 1.33 1998/06/18 14:55:10 ddenholm Exp $";
! 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)
! 202: #define map_z3d(z) ((z-base_z)*zscale3d-1.0)
! 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;
! 211: extern double base_z;
! 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>