Annotation of OpenXM_contrib/gnuplot/hidden3d.c, Revision 1.1.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>