Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / hidden3d.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: hidden3d.c,v 1.56.2.3 2008/06/02 19:40:10 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - hidden3d.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 1999, 2004   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  * 1999 Hans-Bernhard Broeker (Broeker@physik.rwth-aachen.de)
40  *
41  * Major rewrite, affecting just about everything
42  *
43  */
44
45 #include "hidden3d.h"
46 #include "color.h"
47 #include "pm3d.h"
48 #include "alloc.h"
49 #include "axis.h"
50 #include "command.h"
51 #include "dynarray.h"
52 #include "graph3d.h"
53 #include "tables.h"
54 #include "term_api.h"
55 #include "util.h"
56 #include "util3d.h"
57
58
59 /*************************/
60 /* Configuration section */
61 /*************************/
62
63 /* If this module is compiled with HIDDEN3D_GRIDBOX = 1 defined, it
64  * will store the information about {x|y}{min|max} in an other
65  * (additional!) form: a bit mask, with each bit representing one
66  * horizontal or vertical strip of the screen. The bits for strips a
67  * polygon spans are set to one. This allows to test for xy overlap
68  * of an edge with a polygon simply by comparing bit patterns.  */
69 #ifndef HIDDEN3D_GRIDBOX
70 #define HIDDEN3D_GRIDBOX 0
71 #endif
72
73 /* HBB 19991204: new code started to finally implement a spatially
74  * ordered data structure to store the polygons in. This is meant to
75  * speed up the HLR process. Before, the hot spot of hidden3d was the
76  * loop in in_front, where by far most of the polygons are rejected by
77  * the first test, already. The idea is to _not_ to loop over all
78  * those polygons far away from the edge under consideration, in the
79  * first place. Instead, store the polygons in an xy grid of lists,
80  * so we can select a sample of these lists to test a given edge
81  * against. */
82 #ifndef HIDDEN3D_QUADTREE
83 #define HIDDEN3D_QUADTREE 0
84 #endif
85 #if HIDDEN3D_QUADTREE && HIDDEN3D_GRIDBOX
86 # warning HIDDEN3D_QUADTREE & HIDDEN3D_GRIDBOX do not work together, sensibly!
87 #endif
88
89 /* If you don't want the color-distinction between the
90  * 'top' and 'bottom' sides of the surface, like I do, then just compile
91  * with -DBACKSIDE_LINETYPE_OFFSET = 0. */
92 #ifndef BACKSIDE_LINETYPE_OFFSET
93 # define BACKSIDE_LINETYPE_OFFSET 1
94 #endif
95
96 /* This #define lets you choose if the diagonals that
97  * divide each original quadrangle in two triangles will be drawn
98  * visible or not: do draw them, define it to be 7L, otherwise let be
99  * 3L */
100 #ifndef TRIANGLE_LINESDRAWN_PATTERN
101 # define TRIANGLE_LINESDRAWN_PATTERN 3L
102 #endif
103
104 /* Handle out-of-range or undefined points. Compares the maximum
105  * marking (0=inrange, 1=outrange, 2=undefined) of the coordinates of
106  * a vertex to the value #defined here. If not less, the vertex is
107  * rejected, and all edges that hit it, as well. NB: if this is set to
108  * anything above 1, gnuplot may crash with a floating point exception
109  * in hidden3d. You get what you asked for ... */
110 #ifndef HANDLE_UNDEFINED_POINTS
111 # define HANDLE_UNDEFINED_POINTS 1
112 #endif
113 /* Symbolic value for 'do not handle Undefined Points specially' */
114 #define UNHANDLED (UNDEFINED+1)
115
116 /* If both subtriangles of a quad were cancelled, try if using the
117  * other diagonal is better. This only makes a difference if exactly
118  * one vertex of the quad is unusable, and that one is on the 'usual'
119  * tried diagonal. In such a case, the border of the hole in the
120  * surface will be less rough than with the previous method, as the
121  * border follows the undefined region as close as it can. */
122 #ifndef SHOW_ALTERNATIVE_DIAGONAL
123 # define SHOW_ALTERNATIVE_DIAGONAL 1
124 #endif
125
126 /* If the two triangles in a quad are both drawn, and they show
127  * different sides to the user (the quad is 'bent over'), then it's
128  * preferrable to force the diagonal being visible to avoid other
129  * parts of the scene being obscured by a line the user can't
130  * see. This avoids unnecessary user surprises. */
131 #ifndef HANDLE_BENTOVER_QUADRANGLES
132 # define HANDLE_BENTOVER_QUADRANGLES 1
133 #endif
134
135 /* The actual configuration is stored in these variables, modifiable
136  * at runtime through 'set hidden3d' options */
137 static int hiddenBacksideLinetypeOffset = BACKSIDE_LINETYPE_OFFSET;
138 static long hiddenTriangleLinesdrawnPattern = TRIANGLE_LINESDRAWN_PATTERN;
139 static int hiddenHandleUndefinedPoints = HANDLE_UNDEFINED_POINTS;
140 static int hiddenShowAlternativeDiagonal = SHOW_ALTERNATIVE_DIAGONAL;
141 static int hiddenHandleBentoverQuadrangles = HANDLE_BENTOVER_QUADRANGLES;
142
143
144 /**************************************************************/
145 /**************************************************************
146  * The 'real' code begins, here.                              *
147  *                                                            *
148  * first: types and global variables                          *
149  **************************************************************/
150 /**************************************************************/
151
152 /* precision of calculations in normalized space. Coordinates closer to
153  * each other than an absolute difference of EPSILON are considered
154  * equal, by some of the routines in this module. */
155 #define EPSILON 1e-5
156
157 /* The code used to die messily if the scale parameters got over-large.
158  * Prevent this from happening due to mousing by locking out the mouse
159  * response. */
160 TBOOLEAN disable_mouse_z = FALSE;
161
162 /* Some inexact operations: == , > , >=, sign() */
163 #define EQ(X,Y)  (fabs( (X) - (Y) ) < EPSILON)  /* X == Y */
164 #define GR(X,Y)  ((X) >  (Y) + EPSILON)         /* X >  Y */
165 #define GE(X,Y)  ((X) >= (Y) - EPSILON)         /* X >= Y */
166 #define SIGN(X)  ( ((X)<-EPSILON) ? -1: ((X)>EPSILON) )
167
168 /* A plane equation, stored as a four-element vector. The equation
169  * itself is: x*p[0]+y*p[1]+z*p[2]+1*p[3]=0 */
170 typedef coordval t_plane[4];
171
172 /* One edge of the mesh. The edges are (currently) organized into a
173  * linked list as a method of traversing them back-to-front. */
174 typedef struct edge {
175     long v1, v2;                /* the vertices at either end */
176     int style;                  /* linetype index */
177     struct lp_style_type *lp;   /* line/point style attributes */
178     long next;                  /* index of next edge in z-sorted list */
179 } edge;
180 typedef edge GPHUGE *p_edge;
181
182
183 /* One polygon (actually: always a triangle) of the surface
184  * mesh(es). */
185 #define POLY_NVERT 3
186 typedef struct polygon {
187     long vertex[POLY_NVERT];    /* The vertices (indices on vlist) */
188     /* min/max in all three directions */
189     coordval xmin, xmax, ymin, ymax, zmin, zmax;
190     t_plane plane;              /* the plane coefficients */
191     TBOOLEAN frontfacing;       /* is polygon facing front- or backwards? */
192 #if ! HIDDEN3D_QUADTREE
193     long next;                  /* index of next polygon in z-sorted list */
194 #endif
195 #if HIDDEN3D_GRIDBOX
196     unsigned long xbits;        /* x coverage mask of bounding box */
197     unsigned long ybits;        /* y coverage mask of bounding box */
198 #endif
199 } polygon;
200 typedef polygon GPHUGE *p_polygon;
201
202 #if HIDDEN3D_GRIDBOX
203 # define UINT_BITS (CHAR_BIT * sizeof(unsigned int))
204 # define COORD_TO_BITMASK(x,shift)                                                      \
205   (~0U << (unsigned int) ((((x) / surface_scale) + 1.0) / 2.0 * UINT_BITS + (shift)))
206 # define CALC_BITRANGE(range_min, range_max)                             \
207   ((~COORD_TO_BITMASK((range_max), 1)) & COORD_TO_BITMASK(range_min, 0))
208 #endif
209
210 /* Enumeration of possible types of line, for use with the
211  * store_edge() function. Influences the position in the grid the
212  * second vertex will be put to, relative to the one that is passed
213  * in, as another argument to that function. edir_none is for
214  * single-pixel 'blind' edges, which exist only to facilitate output
215  * of 'points' style splots.
216  *
217  * Directions are interpreted in a pseudo-geographical coordinate
218  * system of the data grid: within the isoline, we count from left to
219  * right (west to east), and the isolines themselves are counted from
220  * top to bottom, described as north and south. */
221 typedef enum edge_direction {
222     edir_west, edir_north,
223     edir_NW, edir_NE,
224     edir_impulse, edir_point,
225     edir_vector
226 } edge_direction;
227
228 /* direction into which the polygon is facing (the corner with the
229  * right angle, inside the mesh, that is). The reference identifiying
230  * the whole cell is always the lower right, i.e. southeast one. */
231 typedef enum polygon_direction {
232     pdir_NE, pdir_SE, pdir_SW, pdir_NW
233 } polygon_direction;
234
235 /* Three dynamical arrays that describe what we have to plot: */
236 static dynarray vertices, edges, polygons;
237
238 /* convenience #defines to make the generic vector useable as typed arrays */
239 #define vlist ((p_vertex) vertices.v)
240 #define plist ((p_polygon) polygons.v)
241 #define elist ((p_edge) edges.v)
242
243 static long pfirst;             /* first polygon in zsorted chain*/
244 static long efirst;             /* first edges in zsorted chain */
245
246 #if HIDDEN3D_QUADTREE
247 /* HBB 20000716: spatially oriented hierarchical data structure to
248  * store polygons in. For now, it's a simple xy grid of z-sorted
249  * lists. A single polygon can appear in several lists, if it spans
250  * cell borders */
251 typedef struct qtreelist {
252     long p;                     /* the polygon */
253     long next;                  /* next element in this chain */
254 } qtreelist;
255 typedef qtreelist GPHUGE *p_qtreelist;
256
257 /* the number of cells in x and y direction: */
258 # ifndef QUADTREE_GRANULARITY
259 #  define QUADTREE_GRANULARITY 10
260 # endif
261 /* indices of the heads of all the cells' chains: */
262 static long quadtree[QUADTREE_GRANULARITY][QUADTREE_GRANULARITY];
263
264 /* and a routine to calculate the cells' position in that array: */
265 static int
266 coord_to_treecell(coordval x)
267 {
268     int index;
269     index = ((((x) / surface_scale) + 1.0) / 2.0) * QUADTREE_GRANULARITY;
270     if (index >= QUADTREE_GRANULARITY)
271         index = QUADTREE_GRANULARITY - 1;
272     else if (index < 0)
273         index = 0;
274
275     return index;
276 }
277
278 /* the dynarray to actually store all that stuff in: */
279 static dynarray qtree;
280 #define qlist ((p_qtreelist) qtree.v)
281 #endif /* HIDDEN3D_QUADTREE*/
282
283 /* Prototypes for internal functions of this module. */
284 static long int store_vertex __PROTO((struct coordinate GPHUGE *point,
285                                       lp_style_type *lp_style, TBOOLEAN color_from_column));
286 static long int make_edge __PROTO((long int vnum1, long int vnum2,
287                                    struct lp_style_type *lp,
288                                    int style, int next));
289 static long int store_edge __PROTO((long int vnum1, edge_direction direction,
290                                     long int crvlen, struct lp_style_type *lp,
291                                     int style));
292 static GP_INLINE double eval_plane_equation __PROTO((t_plane p, p_vertex v));
293 static long int store_polygon __PROTO((long int vnum1,
294                                        polygon_direction direction,
295                                        long int crvlen));
296 static void color_edges __PROTO((long int new_edge, long int old_edge,
297                                  long int new_poly, long int old_poly,
298                                  int style_above, int style_below));
299 static void build_networks __PROTO((struct surface_points * plots,
300                                     int pcount));
301 int compare_edges_by_zmin __PROTO((SORTFUNC_ARGS p1, SORTFUNC_ARGS p2));
302 int compare_polys_by_zmax __PROTO((SORTFUNC_ARGS p1, SORTFUNC_ARGS p2));
303 static void sort_edges_by_z __PROTO((void));
304 static void sort_polys_by_z __PROTO((void));
305 static TBOOLEAN get_plane __PROTO((p_polygon p, t_plane plane));
306 static long split_line_at_ratio __PROTO((long int vnum1, long int vnum2, double w));
307 static GP_INLINE double area2D __PROTO((p_vertex v1, p_vertex v2,
308                                         p_vertex v3));
309 static void draw_vertex __PROTO((p_vertex v));
310 static GP_INLINE void draw_edge __PROTO((p_edge e, p_vertex v1, p_vertex v2));
311 static GP_INLINE void handle_edge_fragment __PROTO((long int edgenum,
312                                                     long int vnum1,
313                                                     long int vnum2,
314                                                     long int firstpoly));
315 static int in_front __PROTO((long int edgenum,
316                              long int vnum1, long int vnum2,
317                              long int *firstpoly));
318
319
320 /* Set the options for hidden3d. To be called from set.c, when the
321  * user has begun a command with 'set hidden3d', to parse the rest of
322  * that command */
323 void
324 set_hidden3doptions()
325 {
326     struct value t;
327     int tmp;
328
329     while (!END_OF_COMMAND) {
330         switch (lookup_table(&set_hidden3d_tbl[0], c_token)) {
331         case S_HI_DEFAULTS:
332             /* reset all parameters to defaults */
333             reset_hidden3doptions();
334             c_token++;
335             if (!END_OF_COMMAND)
336                 int_error(c_token,
337                           "No further options allowed after 'defaults'");
338             return;
339             break;
340         case S_HI_OFFSET:
341             c_token++;
342             hiddenBacksideLinetypeOffset = (int) real(const_express(&t));
343             c_token--;
344             break;
345         case S_HI_NOOFFSET:
346             hiddenBacksideLinetypeOffset = 0;
347             break;
348         case S_HI_TRIANGLEPATTERN:
349             c_token++;
350             hiddenTriangleLinesdrawnPattern = (int) real(const_express(&t));
351             c_token--;
352             break;
353         case S_HI_UNDEFINED:
354             c_token++;
355             tmp = (int) real(const_express(&t));
356             if (tmp <= 0 || tmp > UNHANDLED)
357                 tmp = UNHANDLED;
358             hiddenHandleUndefinedPoints = tmp;
359             c_token--;
360             break;
361         case S_HI_NOUNDEFINED:
362             hiddenHandleUndefinedPoints = UNHANDLED;
363             break;
364         case S_HI_ALTDIAGONAL:
365             hiddenShowAlternativeDiagonal = 1;
366             break;
367         case S_HI_NOALTDIAGONAL:
368             hiddenShowAlternativeDiagonal = 0;
369             break;
370         case S_HI_BENTOVER:
371             hiddenHandleBentoverQuadrangles = 1;
372             break;
373         case S_HI_NOBENTOVER:
374             hiddenHandleBentoverQuadrangles = 0;
375             break;
376         case S_HI_INVALID:
377             int_error(c_token, "No such option to hidden3d (or wrong order)");
378         default:
379             break;
380         }
381         c_token++;
382     }
383 }
384
385 void
386 show_hidden3doptions()
387 {
388     fprintf(stderr,"\
389 \t  Back side of surfaces has linestyle offset of %d\n\
390 \t  Bit-Mask of Lines to draw in each triangle is %ld\n\
391 \t  %d: ",
392             hiddenBacksideLinetypeOffset, hiddenTriangleLinesdrawnPattern,
393             hiddenHandleUndefinedPoints);
394
395     switch (hiddenHandleUndefinedPoints) {
396     case OUTRANGE:
397         fputs("Outranged and undefined datapoints are omitted from the surface.\n",
398               stderr);
399         break;
400     case UNDEFINED:
401         fputs("Only undefined datapoints are omitted from the surface.\n",
402               stderr);
403         break;
404     case UNHANDLED:
405         fputs("Will not check for undefined datapoints (may cause crashes).\n",
406               stderr);
407         break;
408     default:
409         fputs("Value stored for undefined datapoint handling is illegal!!!\n",
410               stderr);
411         break;
412     }
413
414     fprintf(stderr,"\
415 \t  Will %suse other diagonal if it gives a less jaggy outline\n\
416 \t  Will %sdraw diagonal visibly if quadrangle is 'bent over'\n",
417             hiddenShowAlternativeDiagonal ? "" : "not ",
418             hiddenHandleBentoverQuadrangles ? "" : "not ");
419 }
420
421 /* Implements proper 'save'ing of the new hidden3d options... */
422 void
423 save_hidden3doptions(FILE *fp)
424 {
425     if (!hidden3d) {
426         fputs("unset hidden3d\n", fp);
427         return;
428     }
429     fprintf(fp, "set hidden3d offset %d trianglepattern %ld undefined %d %saltdiagonal %sbentover\n",
430             hiddenBacksideLinetypeOffset,
431             hiddenTriangleLinesdrawnPattern,
432             hiddenHandleUndefinedPoints,
433             hiddenShowAlternativeDiagonal ? "" : "no",
434             hiddenHandleBentoverQuadrangles ? "" : "no");
435 }
436
437 /* Initialize the necessary steps for hidden line removal and
438    initialize global variables. */
439 void
440 init_hidden_line_removal()
441 {
442     /* Check for some necessary conditions to be set elsewhere: */
443     /* HandleUndefinedPoints mechanism depends on these: */
444     assert(OUTRANGE == 1);
445     assert(UNDEFINED == 2);
446
447     /* Re-mapping of this value makes the test easier in the critical
448      * section */
449     if (hiddenHandleUndefinedPoints < OUTRANGE)
450         hiddenHandleUndefinedPoints = UNHANDLED;
451
452     init_dynarray(&vertices, sizeof(vertex), 100, 100);
453     init_dynarray(&edges, sizeof(edge), 100, 100);
454     init_dynarray(&polygons, sizeof(polygon), 100, 100);
455 #if HIDDEN3D_QUADTREE
456     init_dynarray(&qtree, sizeof(qtreelist), 100, 100);
457 #endif
458
459 }
460
461 /* Reset the hidden line data to a fresh start. */
462 void
463 reset_hidden_line_removal()
464 {
465     vertices.end = 0;
466     edges.end = 0;
467     polygons.end = 0;
468 #if HIDDEN3D_QUADTREE
469     qtree.end = 0;
470 #endif
471 }
472
473
474 /* Terminates the hidden line removal process.                  */
475 /* Free any memory allocated by init_hidden_line_removal above. */
476 void
477 term_hidden_line_removal()
478 {
479     free_dynarray(&polygons);
480     free_dynarray(&edges);
481     free_dynarray(&vertices);
482 #if HIDDEN3D_QUADTREE
483     free_dynarray(&qtree);
484 #endif
485 }
486
487
488 #if 0 /* UNUSED ! */
489 /* Do we see the top or bottom of the polygon, or is it 'on edge'? */
490 #define GET_SIDE(vlst,csign)                                            \
491 do {                                                                    \
492     double ctmp =                                                       \
493         vlist[vlst[0]].x * (vlist[vlst[1]].y - vlist[vlst[2]].y) +      \
494         vlist[vlst[1]].x * (vlist[vlst[2]].y - vlist[vlst[0]].y) +      \
495         vlist[vlst[2]].x * (vlist[vlst[0]].y - vlist[vlst[1]].y);       \
496     csign = SIGN (ctmp);                                                \
497 } while (0)
498 #endif /* UNUSED */
499
500 static long int
501 store_vertex (
502     struct coordinate GPHUGE * point,
503     lp_style_type *lp_style,
504     TBOOLEAN color_from_column)
505 {
506     p_vertex thisvert = nextfrom_dynarray(&vertices);
507
508     thisvert->lp_style = lp_style;
509     if ((int) point->type >= hiddenHandleUndefinedPoints) {
510         FLAG_VERTEX_AS_UNDEFINED(*thisvert);
511         return (-1);
512     }
513     map3d_xyz(point->x, point->y, point->z, thisvert);
514     if (color_from_column) {
515         thisvert->real_z = point->CRD_COLOR;
516         thisvert->lp_style->pm3d_color.lt = LT_COLORFROMCOLUMN;
517     } else
518         thisvert->real_z = point->z;
519
520 #ifdef HIDDEN3D_VAR_PTSIZE
521     /* Store pointer back to original point */
522     /* Needed to support variable pointsize */
523     thisvert->original = point;
524 #endif
525         
526     return (thisvert - vlist);
527 }
528
529 /* A part of store_edge that does the actual storing. Used by
530  * in_front(), as well, so I separated it out. */
531 static long int
532 make_edge(
533     long vnum1, long vnum2,
534     struct lp_style_type *lp,
535     int style,
536     int next)
537 {
538     p_edge thisedge = nextfrom_dynarray(&edges);
539     p_vertex v1 = vlist + vnum1;
540     p_vertex v2 = vlist + vnum2;
541
542     /* ensure z ordering inside each edge */
543     if (v1->z >= v2->z) {
544         thisedge->v1 = vnum1;
545         thisedge->v2 = vnum2;
546     } else {
547         thisedge->v1 = vnum2;
548         thisedge->v2 = vnum1;
549     }
550
551     thisedge->style = style;
552     thisedge->lp = lp;
553     thisedge->next = next;
554
555     return thisedge - elist;
556 }
557
558 /* store the edge from vnum1 to vnum2 into the edge list. Ensure that
559  * the vertex with higher z is stored in v1, to ease sorting by zmax */
560 static long int
561 store_edge(
562     long int vnum1,
563     edge_direction direction,
564     long int crvlen,
565     struct lp_style_type *lp,
566     int style)
567 {
568     p_vertex v1 = vlist + vnum1;
569     p_vertex v2 = NULL;         /* just in case: initialize... */
570     long int vnum2;
571     unsigned int drawbits = (0x1 << direction);
572
573     switch (direction) {
574     case edir_vector:
575         v2 = v1 + 1;
576         drawbits = 0;
577         break;
578     case edir_west:
579         v2 = v1 - 1;
580         break;
581     case edir_north:
582         v2 = v1 - crvlen;
583         break;
584     case edir_NW:
585         v2 = v1 - crvlen - 1;
586         break;
587     case edir_NE:
588         v2 = v1 - crvlen;
589         v1 -= 1;
590         drawbits >>= 1;         /* altDiag is handled like normal NW one */
591         break;
592     case edir_impulse:
593         v2 = v1 - 1;
594         drawbits = 0;           /* don't care about the triangle pattern */
595         break;
596     case edir_point:
597         v2 = v1;
598         drawbits = 0;           /* nothing to draw, but disable check */
599         break;
600     }
601
602     vnum2 = v2 - vlist;
603
604     if (VERTEX_IS_UNDEFINED(*v1)
605         || VERTEX_IS_UNDEFINED(*v2)) {
606         return -2;
607     }
608
609     if (drawbits &&             /* no bits set: 'blind' edge --> no test! */
610         ! (hiddenTriangleLinesdrawnPattern & drawbits)
611         )
612         style = -3;
613
614     return make_edge(vnum1, vnum2, lp, style, -1);
615 }
616
617
618 /* Calculate the normal equation coefficients of the plane of polygon
619  * 'p'. Uses is the 'signed projected area' method. Its benefit is
620  * that it doesn't rely on only three of the vertices of 'p', as the
621  * naive cross product method does. */
622 static TBOOLEAN
623 get_plane(p_polygon poly, t_plane plane)
624 {
625     int i;
626     p_vertex v1, v2;
627     double x, y, z, s;
628     TBOOLEAN frontfacing=TRUE;
629
630     /* calculate the signed areas of the polygon projected onto the
631      * planes x=0, y=0 and z=0, respectively. The three areas form
632      * the components of the plane's normal vector: */
633     v1 = vlist + poly->vertex[POLY_NVERT - 1];
634     v2 = vlist + poly->vertex[0];
635     plane[0] = (v1->y - v2->y) * (v1->z + v2->z);
636     plane[1] = (v1->z - v2->z) * (v1->x + v2->x);
637     plane[2] = (v1->x - v2->x) * (v1->y + v2->y);
638     for (i = 1; i < POLY_NVERT; i++) {
639         v1 = v2;
640         v2 = vlist + poly->vertex[i];
641         plane[0] += (v1->y - v2->y) * (v1->z + v2->z);
642         plane[1] += (v1->z - v2->z) * (v1->x + v2->x);
643         plane[2] += (v1->x - v2->x) * (v1->y + v2->y);
644     }
645
646     /* Normalize the resulting normal vector */
647     s = sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
648
649     if (GE(0.0, s)) {
650         /* The normal vanishes, i.e. the polygon is degenerate. We build
651          * another vector that is orthogonal to the line of the polygon */
652         v1 = vlist + poly->vertex[0];
653         for (i = 1; i < POLY_NVERT; i++) {
654             v2 = vlist + poly->vertex[i];
655             if (!V_EQUAL(v1, v2))
656                 break;
657         }
658
659         /* build (x,y,z) that should be linear-independant from <v1, v2> */
660         x = v1->x;
661         y = v1->y;
662         z = v1->z;
663         if (EQ(y, v2->y))
664             y += 1.0;
665         else
666             x += 1.0;
667
668         /* Re-do the signed area computations */
669         plane[0] = v1->y * (v2->z - z) + v2->y * (z - v1->z) + y * (v1->z - v2->z);
670         plane[1] = v1->z * (v2->x - x) + v2->z * (x - v1->x) + z * (v1->x - v2->x);
671         plane[2] = v1->x * (v2->y - y) + v2->x * (y - v1->y) + x * (v1->y - v2->y);
672         s = sqrt(plane[0] * plane[0] + plane[1] * plane[1] + plane[2] * plane[2]);
673     }
674
675     /* ensure that normalized c is > 0 */
676     if (plane[2] < 0.0) {
677         s *= -1.0;
678         frontfacing = FALSE;
679     }
680
681     plane[0] /= s;
682     plane[1] /= s;
683     plane[2] /= s;
684
685     /* Now we have the normalized normal vector, insert one of the
686      * vertices into the equation to get 'd'. For an even better result,
687      * an average over all the vertices might be used */
688     plane[3] = -plane[0] * v1->x - plane[1] * v1->y - plane[2] * v1->z;
689
690     return frontfacing;
691 }
692
693
694 /* Evaluate the plane equation represented a four-vector for the given
695  * vector. For points in the plane, this should result in values ==0.
696  * < 0 is 'away' from the polygon, > 0 is infront of it */
697 static GP_INLINE double
698 eval_plane_equation(t_plane p, p_vertex v)
699 {
700     return (p[0]*v->x + p[1]*v->y + p[2]*v->z + p[3]);
701 }
702
703
704 /* Build the data structure for this polygon. The return value is the
705  * index of the newly generated polygon. This is memorized for access
706  * to polygons in the previous isoline, from the next-following
707  * one. */
708 static long int
709 store_polygon(long vnum1, polygon_direction direction, long crvlen)
710 {
711     long int v[POLY_NVERT];
712     p_vertex v1, v2, v3;
713     p_polygon p;
714
715     switch (direction) {
716     case pdir_NE:
717         v[0] = vnum1;
718         v[2] = vnum1 - crvlen;
719         v[1] = v[2] - 1;
720         break;
721     case pdir_SW:
722         /* triangle points southwest, here */
723         v[0] = vnum1;
724         v[1] = vnum1 - 1;
725         v[2] = v[1] - crvlen;
726         break;
727     case pdir_SE:
728         /* alt-diagonal, case 1: southeast triangle: */
729         v[0] = vnum1;
730         v[2] = vnum1 - crvlen;
731         v[1] = vnum1 - 1;
732         break;
733     case pdir_NW:
734         v[2] = vnum1 - crvlen;
735         v[0] = vnum1 - 1;
736         v[1] = v[0] - crvlen;
737         break;
738     }
739
740     v1 = vlist + v[0];
741     v2 = vlist + v[1];
742     v3 = vlist + v[2];
743
744     if (VERTEX_IS_UNDEFINED(*v1)
745         || VERTEX_IS_UNDEFINED(*v2)
746         || VERTEX_IS_UNDEFINED(*v3)
747         )
748         return (-2);
749
750     /* Check if polygon is degenerate */
751     if (V_EQUAL(v1,v2) || V_EQUAL(v2,v3) || V_EQUAL(v3,v1))
752         return (-2);
753
754     /* All else OK, fill in the polygon: */
755
756     p = nextfrom_dynarray(&polygons);
757
758     memcpy (p->vertex, v, sizeof(v));
759 #if ! HIDDEN3D_QUADTREE
760     p->next = -1;
761 #endif
762
763     /* Some helper macros for repeated code blocks: */
764
765     /* Gets Minimum 'var' value of polygon 'poly' into variable
766      * 'min. C is one of x, y, or z: */
767 #define GET_MIN(poly, var, min)                 \
768     do {                                        \
769         int i;                                  \
770         long *v = poly->vertex;                 \
771                                                 \
772         min = vlist[*v++].var;                  \
773         for (i = 1; i< POLY_NVERT; i++, v++)    \
774             if (vlist[*v].var < min)            \
775                 min = vlist[*v].var;            \
776         if (min < -surface_scale) disable_mouse_z = TRUE;       \
777     } while (0)
778
779     /* Gets Maximum 'var' value of polygon 'poly', as with GET_MIN */
780 #define GET_MAX(poly, var, max)                 \
781     do {                                        \
782         int i;                                  \
783         long *v = poly->vertex;                 \
784                                                 \
785         max = vlist[*v++].var;                  \
786         for (i = 1; i< POLY_NVERT; i++, v++)    \
787             if (vlist[*v].var > max)            \
788                 max = vlist[*v].var;            \
789         if (max > surface_scale) disable_mouse_z = TRUE;        \
790     } while (0)
791
792     GET_MIN(p, x, p->xmin);
793     GET_MIN(p, y, p->ymin);
794     GET_MIN(p, z, p->zmin);
795     GET_MAX(p, x, p->xmax);
796     GET_MAX(p, y, p->ymax);
797     GET_MAX(p, z, p->zmax);
798 #undef GET_MIN
799 #undef GET_MAX
800
801 #if HIDDEN3D_GRIDBOX
802     p->xbits = CALC_BITRANGE(p->xmin, p->xmax);
803     p->ybits = CALC_BITRANGE(p->ymin, p->ymax);
804 #endif
805
806     p->frontfacing = get_plane(p, p->plane);
807
808     return (p - plist);
809 }
810
811 /* color edges, based on the orientation of polygon(s). One of the two
812  * edges passed in is a new one, meaning there is no other polygon
813  * sharing it, yet. The other, 'old' edge is common to the new polygon
814  * and another one, which was created earlier on. If these two polygon
815  * differ in their orientation (one front-, the other backsided to the
816  * viewer), this routine has to resolve that conflict.  Edge colours
817  * are changed only if the edge wasn't invisible, before */
818 static void
819 color_edges(
820     long int new_edge,          /* index of 'new', conflictless edge */
821     long int old_edge,          /* index of 'old' edge, may conflict */
822     long int new_poly,          /* index of current polygon */
823     long int old_poly,          /* index of poly sharing old_edge */
824     int above,                  /* style number for front of polygons */
825     int below)                  /* style number for backside of polys */
826 {
827     int casenumber;
828
829     if (new_poly > -2) {
830         /* new polygon was built successfully */
831         if (old_poly <= -2)
832             /* old polygon doesn't exist. Use new_polygon for both: */
833             old_poly = new_poly;
834
835         casenumber =
836             (plist[new_poly].frontfacing ? 1 : 0)
837             + 2 * (plist[old_poly].frontfacing ? 1 : 0);
838         switch (casenumber) {
839         case 0:
840             /* both backfacing */
841             if (elist[new_edge].style >= -2)
842                 elist[new_edge].style   = below;
843             if (elist[old_edge].style >= -2)
844                 elist[old_edge].style = below;
845             break;
846         case 2:
847             if (elist[new_edge].style >= -2)
848                 elist[new_edge].style = below;
849             /* FALLTHROUGH */
850         case 1:
851             /* new front-, old one backfacing, or */
852             /* new back-, old one frontfacing */
853             if (((new_edge == old_edge)
854                  && hiddenHandleBentoverQuadrangles) /* a diagonal edge! */
855                 || (elist[old_edge].style >= -2)) {
856                 /* conflict has occured: two polygons meet here, with opposige
857                  * sides being shown. What's to do?
858                  * 1) find a vertex of one polygon outside this common
859                  * edge
860                  * 2) check wether it's in front of or behind the
861                  * other polygon's plane
862                  * 3) if in front, color the edge accoring to the
863                  * vertex' polygon, otherwise, color like the other
864                  * polygon */
865                 long int vnum1 = elist[old_edge].v1;
866                 long int vnum2 = elist[old_edge].v2;
867                 p_polygon p = plist + new_poly;
868                 long int pvert = -1;
869                 double point_to_plane;
870
871                 if (p->vertex[0] == vnum1) {
872                     if (p->vertex[1] == vnum2) {
873                         pvert = p->vertex[2];
874                     } else if (p->vertex[2] == vnum2) {
875                         pvert = p->vertex[1];
876                     }
877                 } else if (p->vertex[1] == vnum1) {
878                     if (p->vertex[0] == vnum2) {
879                         pvert = p->vertex[2];
880                     } else if (p->vertex[2] == vnum2) {
881                         pvert = p->vertex[0];
882                     }
883                 } else if (p->vertex[2] == vnum1) {
884                     if (p->vertex[0] == vnum2) {
885                         pvert = p->vertex[1];
886                     } else if (p->vertex[1] == vnum2) {
887                         pvert = p->vertex[0];
888                     }
889                 }
890                 assert (pvert >= 0);
891
892                 point_to_plane =
893                     eval_plane_equation(plist[old_poly].plane, vlist + pvert);
894
895                 if (point_to_plane > 0) {
896                     /* point in new_poly is in front of old_poly plane */
897                     elist[old_edge].style = p->frontfacing ? above : below;
898                 }       else {
899                     elist[old_edge].style =
900                         plist[old_poly].frontfacing ? above : below;
901                 }
902             }
903             break;
904         case 3:
905             /* both frontfacing: nothing to do */
906             break;
907         } /* switch */
908     } else {
909         /* Ooops? build_networks() must have guessed incorrectly that
910          * this polygon should exist. */
911         return;
912     }
913 }
914
915
916 /* This somewhat monstrous routine fills the vlist, elist and plist
917  * dynamic arrays with values from all those plots. It strives to
918  * respect all the topological linkage between vertices, edges and
919  * polygons. E.g., it has to find the correct color for each edge,
920  * based on the orientation of the two polygons sharing it, WRT both
921  * the observer and each other. */
922 /* NEW FEATURE HBB 20000715: allow non-grid datasets too, by storing
923  * only vertices and 'direct' edges, but no polygons or 'cross' edges
924  * */
925 static void
926 build_networks(struct surface_points *plots, int pcount)
927 {
928     long int i;
929     struct surface_points *this_plot;
930     int surface;                /* count the surfaces (i.e. sub-plots) */
931     long int crv, ncrvs;        /* count isolines */
932     long int nverts;            /* count vertices */
933     long int max_crvlen;        /* maximal length of isoline in any plot */
934     long int nv, ne, np;        /* local poly/edge/vertex counts */
935     long int *north_polygons;   /* stores polygons of isoline above */
936     long int *these_polygons;   /* same, being built for use by next turn */
937     long int *north_edges;      /* stores edges of polyline above */
938     long int *these_edges;      /* same, being built for use by next turn */
939     struct iso_curve *icrvs;
940     int above = -3, below;      /* line type for edges of front/back side*/
941     struct lp_style_type *lp;   /* pointer to line and point properties */
942
943     /* Count out the initial sizes needed for the polygon and vertex
944      * lists. */
945     nv = ne = np = 0;
946     max_crvlen = -1;
947
948     for (this_plot = plots, surface = 0;
949         surface < pcount;
950         this_plot = this_plot->next_sp, surface++) {
951         long int crvlen;
952         
953         /* Quietly skip empty plots */
954         if (this_plot->plot_type == NODATA)
955             continue;
956
957         crvlen = this_plot->iso_crvs->p_count;
958
959         /* Allow individual plots to opt out of hidden3d calculations */
960         if (this_plot->opt_out_of_hidden3d)
961             continue;
962
963         /* register maximal isocurve length. Only necessary for
964          * grid-topology plots that will create polygons, so I can do
965          * it here, already. */
966         if (crvlen > max_crvlen)
967             max_crvlen = crvlen;
968
969         /* count 'curves' (i.e. isolines) and vertices in this plot */
970         nverts = 0;
971         if(this_plot->plot_type == FUNC3D) {
972             ncrvs = 0;
973             for(icrvs = this_plot->iso_crvs;
974                 icrvs; icrvs = icrvs->next) {
975                 ncrvs++;
976             }
977             nverts += ncrvs * crvlen;
978         } else if(this_plot->plot_type == DATA3D) {
979             ncrvs = this_plot->num_iso_read;
980             if (this_plot->has_grid_topology)
981                 nverts += ncrvs * crvlen;
982             else if (this_plot->plot_style == VECTOR)
983                 nverts += this_plot->iso_crvs->p_count;
984             else {
985                 /* have to check each isoline separately: */
986                 for (icrvs = this_plot->iso_crvs; icrvs; icrvs = icrvs->next)
987                     nverts += icrvs->p_count;
988             }
989         } else {
990             graph_error("Plot type is neither function nor data");
991             return;
992         }
993
994         /* To avoid possibly suprising error messages, several 2d-only
995          * plot styles are mapped to others, that are genuinely
996          * available in 3d. */
997         switch (this_plot->plot_style) {
998         case LINESPOINTS:
999         case STEPS:
1000         case FSTEPS:
1001         case HISTEPS:
1002         case LINES:
1003             nv += nverts;
1004             ne += nverts - ncrvs;
1005             if (this_plot->has_grid_topology) {
1006                 ne += 2 * nverts - ncrvs - 2 * crvlen + 1;
1007                 np += 2 * (ncrvs - 1) * (crvlen - 1);
1008             }
1009             break;
1010         case BOXES:
1011         case FILLEDCURVES:
1012         case IMPULSES:
1013         case VECTOR:
1014             nv += 2 * nverts;
1015             ne += nverts;
1016             break;
1017         case POINTSTYLE:
1018         default:
1019             /* treat all remaining ones like 'points' */
1020             nv += nverts;
1021             ne += nverts; /* a 'phantom edge' per isolated point */
1022             break;
1023         } /* switch */
1024     } /* for (plots) */
1025
1026     /* Check for no data at all */
1027     if (max_crvlen <= 0)
1028         return;
1029
1030     /* allocate all the lists to the size we need: */
1031     resize_dynarray(&vertices, nv);
1032     resize_dynarray(&edges, ne);
1033     resize_dynarray(&polygons, np);
1034
1035     /* allocate the storage for polygons and edges of the isoline just
1036      * above the current one, to allow easy access to them from the
1037      * current isoline */
1038     north_polygons = gp_alloc(2 * max_crvlen * sizeof (long int),
1039                               "hidden north_polys");
1040     these_polygons = gp_alloc(2 * max_crvlen * sizeof (long int),
1041                               "hidden these_polys");
1042     north_edges = gp_alloc(3 * max_crvlen * sizeof (long int),
1043                            "hidden north_edges");
1044     these_edges = gp_alloc(3 * max_crvlen * sizeof (long int),
1045                            "hidden these_edges");
1046
1047     /* initialize the lists, all in one large loop. This is different
1048      * from the previous approach, which went over the vertices,
1049      * first, and only then, in new loop, built polygons */
1050     for (this_plot = plots, surface = 0;
1051          surface < pcount;
1052          this_plot = this_plot->next_sp, surface++) {
1053         lp_style_type *lp_style = NULL;
1054         TBOOLEAN color_from_column = this_plot->pm3d_color_from_column;
1055         long int crvlen;
1056
1057         /* Quietly skip empty plots */
1058         if (this_plot->plot_type == NODATA)
1059             continue;
1060
1061         crvlen = this_plot->iso_crvs->p_count;
1062
1063         /* Allow individual plots to opt out of hidden3d calculations */
1064         if (this_plot->opt_out_of_hidden3d)
1065             continue;
1066
1067         lp = &(this_plot->lp_properties);
1068         above = this_plot->lp_properties.l_type;
1069         below = this_plot->lp_properties.l_type + hiddenBacksideLinetypeOffset;
1070
1071         /* calculate the point symbol type: */
1072         /* Assumest hat upstream functions have made sure this is
1073          * initialized sensibly --- thou hast been warned */
1074         lp_style = &(this_plot->lp_properties);
1075
1076         /* HBB 20000715: new initialization code block for non-grid
1077          * structured datasets. Sufficiently different from the rest
1078          * to warrant separate code, I think. */
1079         if (! this_plot->has_grid_topology) {
1080             for (crv = 0, icrvs = this_plot->iso_crvs;
1081                  icrvs;
1082                  crv++, icrvs = icrvs->next) {
1083                 struct coordinate GPHUGE *points = icrvs->points;
1084                 long int previousvertex = -1;
1085
1086 #ifdef EAM_DATASTRINGS
1087                 /* To handle labels we must look inside a separate list */
1088                 /* rather than just walking through the points arrays.  */
1089                 if (this_plot->plot_style == LABELPOINTS) {
1090                     struct text_label *label;
1091                     long int thisvertex;
1092                     struct coordinate labelpoint = {0};
1093
1094                     lp->pointflag = 1; /* Labels can use the code for hidden points */
1095                     for (label = this_plot->labels->next; label != NULL; label = label->next) {
1096                         labelpoint.x = label->place.x;
1097                         labelpoint.y = label->place.y;
1098                         labelpoint.z = label->place.z;
1099                         thisvertex = store_vertex(&labelpoint, 
1100                                 &(this_plot->lp_properties), color_from_column);
1101                         if (thisvertex < 0)
1102                             continue;
1103                         (vlist+thisvertex)->label = label;
1104                         store_edge(thisvertex, edir_point, crvlen, lp, above);
1105                     }
1106                 } else
1107 #endif
1108
1109                 for (i = 0; i < icrvs->p_count; i++) {
1110                     long int thisvertex, basevertex;
1111
1112                     thisvertex = store_vertex(points + i, lp_style,
1113                                               color_from_column);
1114
1115                     if (this_plot->plot_style == VECTOR) {
1116                         store_vertex(icrvs->next->points+i, 0, 0);
1117                     }
1118
1119                     if (thisvertex < 0) {
1120                         previousvertex = thisvertex;
1121                         continue;
1122                     }
1123
1124                     switch (this_plot->plot_style) {
1125                     case LINESPOINTS:
1126                     case STEPS:
1127                     case FSTEPS:
1128                     case HISTEPS:
1129                     case LINES:
1130                         if (previousvertex >= 0)
1131                             store_edge(thisvertex, edir_west, 0, lp, above);
1132                         break;
1133                     case VECTOR:
1134                         store_edge(thisvertex, edir_vector, 0, lp, above);
1135                         break;
1136                     case BOXES:
1137                     case FILLEDCURVES:
1138                     case IMPULSES:
1139                         /* set second vertex to the low end of zrange */
1140                         {
1141                             coordval remember_z = points[i].z;
1142
1143                             points[i].z = axis_array[FIRST_Z_AXIS].min;
1144                             basevertex = store_vertex(points + i, lp_style,
1145                                                       color_from_column);
1146                             points[i].z = remember_z;
1147                         }
1148                         if (basevertex > 0)
1149                             store_edge(basevertex, edir_impulse, 0, lp, above);
1150                         break;
1151
1152                     case POINTSTYLE:
1153                     default:    /* treat all the others like 'points' */
1154                         store_edge(thisvertex, edir_point, crvlen, lp, above);
1155                         break;
1156                     } /* switch(plot_style) */
1157
1158                     previousvertex = thisvertex;
1159                 } /* for(vertex) */
1160             } /* for(crv) */
1161
1162             continue;           /* done with this plot! */
1163         }
1164
1165         /* initialize stored indices of north-of-this-isoline polygons and
1166          * edges properly */
1167         for (i=0; i < this_plot->iso_crvs->p_count; i++) {
1168             north_polygons[2 * i]
1169                 = north_polygons[2 * i + 1]
1170                 = north_edges[3 * i]
1171                 = north_edges[3 * i + 1]
1172                 = north_edges[3 * i + 2]
1173                 = -3;
1174         }
1175
1176         for (crv = 0, icrvs = this_plot->iso_crvs;
1177              icrvs;
1178              crv++, icrvs = icrvs->next) {
1179             struct coordinate GPHUGE *points = icrvs->points;
1180
1181             for (i = 0; i < icrvs->p_count; i++) {
1182                 long int thisvertex, basevertex;
1183                 long int e1, e2, e3;
1184                 long int pnum;
1185
1186                 thisvertex = store_vertex(points + i, lp_style,
1187                                           color_from_column);
1188
1189                 /* Preset the pointers to the polygons and edges
1190                  * belonging to this isoline */
1191                 these_polygons[2 * i] = these_polygons[2 * i + 1]
1192                     = these_edges[3 * i] = these_edges[3 * i + 1]
1193                     = these_edges[3 * i + 2]
1194                     = -3;
1195
1196                 switch (this_plot->plot_style) {
1197                 case LINESPOINTS:
1198                 case STEPS:
1199                 case FSTEPS:
1200                 case HISTEPS:
1201                 case LINES:
1202                     if (i > 0) {
1203                         /* not first point, so we might want to set up
1204                          * the edge(s) to the left of this vertex */
1205                         if (thisvertex < 0) {
1206                             if ((crv > 0)
1207                                 && (hiddenShowAlternativeDiagonal)
1208                                 ) {
1209                                 /* this vertex is invalid, but the
1210                                  * other three might still form a
1211                                  * valid triangle, facing northwest to
1212                                  * do that, we'll need the 'wrong'
1213                                  * diagonal, which goes from SW to NE:
1214                                  * */
1215                                 these_edges[i*3+2] = e3
1216                                     = store_edge(vertices.end - 1, edir_NE, crvlen,
1217                                                  lp, above);
1218                                 if (e3 > -2) {
1219                                     /* don't store this polygon for
1220                                      * later: it doesn't share edges
1221                                      * with any others to the south or
1222                                      * east, so there's need to */
1223                                     pnum
1224                                         = store_polygon(vertices.end - 1, pdir_NW, crvlen);
1225                                     /* The other two edges of this
1226                                      * polygon need to be checked
1227                                      * against the neighboring
1228                                      * polygons' orientations, before
1229                                      * being coloured */
1230                                     color_edges(e3, these_edges[3*(i-1) +1],
1231                                                 pnum, these_polygons[2*(i-1) + 1],
1232                                                 above, below);
1233                                     color_edges(e3, north_edges[3*i],
1234                                                 pnum, north_polygons[2*i], above, below);
1235                                 }
1236                             }
1237                             break; /* nothing else to do for invalid vertex */
1238                         }
1239
1240                         /* Coming here means that the current vertex
1241                          * is valid: check the other three of this
1242                          * cell, by trying to set up the edges from
1243                          * this one to there */
1244                         these_edges[i*3] = e1
1245                             = store_edge(thisvertex, edir_west, crvlen, lp, above);
1246
1247                         if (crv > 0) { /* vertices to the north exist */
1248                             these_edges[i*3 + 1] = e2
1249                                 = store_edge(thisvertex, edir_north, crvlen, lp, above);
1250                             these_edges[i*3 + 2] = e3
1251                                 = store_edge(thisvertex, edir_NW, crvlen, lp, above);
1252                             if (e3 > -2) {
1253                                 /* diagonal edge of this cell is OK,
1254                                  * so try to build both the polygons:
1255                                  * */
1256                                 if (e1 > -2) {
1257                                     /* one pair of edges is valid: put
1258                                      * first polygon, which points
1259                                      * towards the southwest */
1260                                     these_polygons[2*i] = pnum
1261                                         = store_polygon(thisvertex, pdir_SW, crvlen);
1262                                     color_edges(e1, these_edges[3*(i-1)+1],
1263                                                 pnum, these_polygons[2*(i-1)+ 1], above, below );
1264                                 }
1265                                 if (e2 > -2) {
1266                                     /* other pair of two is fine, put
1267                                      * the northeast polygon: */
1268                                     these_polygons[2*i + 1] = pnum
1269                                         = store_polygon(thisvertex, pdir_NE, crvlen);
1270                                     color_edges(e2, north_edges[3*i],
1271                                                 pnum, north_polygons[2*i], above, below);
1272                                 }
1273                                 /* In case these two new polygons
1274                                  * differ in orientation, find good
1275                                  * coloring of the diagonal */
1276                                 color_edges(e3, e3, these_polygons[2*i],
1277                                             these_polygons[2*i+1], above, below);
1278                             } /* if e3 valid */
1279                             else if ((e1 > -2) && (e2 > -2)
1280                                      && hiddenShowAlternativeDiagonal) {
1281                                 /* looks like all but the north-west
1282                                  * vertex are usable, so we set up the
1283                                  * southeast-pointing triangle, using
1284                                  * the 'wrong' diagonal: */
1285                                 these_edges[3*i + 2] = e3
1286                                     = store_edge(thisvertex, edir_NE, crvlen, lp, above);
1287                                 if (e3 > -2) {
1288                                     /* fill this polygon into *both*
1289                                      * polygon places for this
1290                                      * quadrangle, as this triangle
1291                                      * coincides with both edges that
1292                                      * will be used by later polygons
1293                                      * */
1294                                     these_polygons[2*i] = these_polygons[2*i+1] = pnum
1295                                         = store_polygon(thisvertex, pdir_SE, crvlen);
1296                                     /* This case is somewhat special:
1297                                      * all edges are new, so there is
1298                                      * no other polygon orientation to
1299                                      * consider */
1300                                     if (!plist[pnum].frontfacing)
1301                                         elist[e1].style = elist[e2].style = elist[e3].style
1302                                             = below;
1303                                 }
1304                             }
1305                         }
1306                     } else if ((crv > 0)
1307                                && (thisvertex >= 0)) {
1308                         /* We're at the west border of the grid, but
1309                          * not on the north one: put vertical end-wall
1310                          * edge:*/
1311                         these_edges[3*i + 1] =
1312                             store_edge(thisvertex, edir_north, crvlen, lp, above);
1313                     }
1314                     break;
1315
1316                 case BOXES:
1317                 case FILLEDCURVES:
1318                 case IMPULSES:
1319                     if (thisvertex < 0)
1320                         break;
1321
1322                     /* set second vertex to the low end of zrange */
1323                     {
1324                         coordval remember_z = points[i].z;
1325
1326                         points[i].z = axis_array[FIRST_Z_AXIS].min;
1327                         basevertex = store_vertex(points + i, lp_style,
1328                                                   color_from_column);
1329                         points[i].z = remember_z;
1330                     }
1331                     if (basevertex > 0)
1332                         store_edge(basevertex, edir_impulse, 0, lp, above);
1333                     break;
1334
1335                 case POINTSTYLE:
1336                 default:        /* treat all the others like 'points' */
1337                     if (thisvertex < 0) /* Ignore invalid vertex */
1338                         break;
1339                     store_edge(thisvertex, edir_point, crvlen, lp, above);
1340                     break;
1341                 } /* switch */
1342             } /* for(i) */
1343
1344             /* Swap the 'north' lists of polygons and edges with
1345              * 'these' ones, which have been filled in the pass
1346              * through this isocurve */
1347             {
1348                 long int *temp = north_polygons;
1349                 north_polygons = these_polygons;
1350                 these_polygons = temp;
1351
1352                 temp = north_edges;
1353                 north_edges = these_edges;
1354                 these_edges = temp;
1355             }
1356         } /* for(isocrv) */
1357     } /* for(plot) */
1358
1359     free (these_polygons);
1360     free (north_polygons);
1361     free (these_edges);
1362     free (north_edges);
1363 }
1364
1365 /* Sort the elist in order of growing zmax. Uses qsort on an array of
1366  * plist indices, and then fills in the 'next' fields in struct
1367  * polygon to store the resulting order inside the plist */
1368 /* HBB 20010720: removed 'static' to avoid HP-sUX gcc bug */
1369 int
1370 compare_edges_by_zmin(SORTFUNC_ARGS p1, SORTFUNC_ARGS p2)
1371 {
1372     return SIGN(vlist[elist[*(const long *) p1].v2].z
1373                 - vlist[elist[*(const long *) p2].v2].z);
1374 }
1375
1376 static void
1377 sort_edges_by_z()
1378 {
1379     long *sortarray, i;
1380     p_edge this;
1381
1382     if (!edges.end)
1383         return;
1384
1385     sortarray = gp_alloc((unsigned long) sizeof(long) * edges.end,
1386                          "hidden sort edges");
1387     /* initialize sortarray with an identity mapping */
1388     for (i = 0; i < edges.end; i++)
1389         sortarray[i] = i;
1390     /* sort it */
1391     qsort(sortarray, (size_t) edges.end, sizeof(long), compare_edges_by_zmin);
1392
1393     /* traverse plist in the order given by sortarray, and set the
1394      * 'next' pointers */
1395     this = elist + sortarray[0];
1396     for (i = 1; i < edges.end; i++) {
1397         this->next = sortarray[i];
1398         this = elist + sortarray[i];
1399     }
1400     this->next = -1L;
1401
1402     /* 'efirst' is the index of the leading element of plist */
1403     efirst = sortarray[0];
1404
1405     free(sortarray);
1406 }
1407
1408 /* HBB 20010720: removed 'static' to avoid HP-sUX gcc bug */
1409 int
1410 compare_polys_by_zmax(SORTFUNC_ARGS p1, SORTFUNC_ARGS p2)
1411 {
1412     return (SIGN(plist[*(const long *) p1].zmax
1413                  - plist[*(const long *) p2].zmax));
1414 }
1415
1416 static void
1417 sort_polys_by_z()
1418 {
1419     long *sortarray, i;
1420     p_polygon this;
1421
1422     if (!polygons.end)
1423         return;
1424
1425     sortarray = gp_alloc((unsigned long) sizeof(long) * polygons.end,
1426                          "hidden sortarray");
1427
1428     /* initialize sortarray with an identity mapping */
1429     for (i = 0; i < polygons.end; i++)
1430         sortarray[i] = i;
1431
1432     /* sort it */
1433     qsort(sortarray, (size_t) polygons.end, sizeof(long),
1434           compare_polys_by_zmax);
1435
1436     /* traverse plist in the order given by sortarray, and set the
1437      * 'next' pointers */
1438 #if HIDDEN3D_QUADTREE
1439     /* HBB 20000716: Loop backwards, to ease construction of
1440      * linked lists from the head: */
1441     {
1442         int grid_x, grid_y;
1443         int grid_x_low, grid_x_high, grid_y_low, grid_y_high;
1444
1445         for (grid_x = 0; grid_x < QUADTREE_GRANULARITY; grid_x++)
1446             for (grid_y = 0; grid_y < QUADTREE_GRANULARITY; grid_y++)
1447                 quadtree[grid_x][grid_y] = -1;
1448
1449         for (i=polygons.end - 1; i >= 0; i--) {
1450             this = plist + sortarray[i];
1451
1452             grid_x_low = coord_to_treecell(this->xmin);
1453             grid_x_high = coord_to_treecell(this->xmax);
1454             grid_y_low = coord_to_treecell(this->ymin);
1455             grid_y_high = coord_to_treecell(this->ymax);
1456
1457             for (grid_x = grid_x_low; grid_x <= grid_x_high; grid_x++) {
1458                 for (grid_y = grid_y_low; grid_y <= grid_y_high; grid_y++) {
1459                     p_qtreelist newhead = nextfrom_dynarray(&qtree);
1460
1461                     newhead->next = quadtree[grid_x][grid_y];
1462                     newhead->p = sortarray[i];
1463
1464                     quadtree[grid_x][grid_y] = newhead - qlist;
1465                 }
1466             }
1467         }
1468     }
1469
1470 #else /* HIDDEN3D_QUADTREE */
1471     this = plist + sortarray[0];
1472     for (i = 1; i < polygons.end; i++) {
1473         this->next = sortarray[i];
1474         this = plist + sortarray[i];
1475     }
1476     this->next = -1L;
1477     /* 'pfirst' is the index of the leading element of plist */
1478 #endif /* HIDDEN3D_QUADTREE */
1479     pfirst = sortarray[0];
1480
1481     free(sortarray);
1482 }
1483
1484
1485 #define LASTBITS (USHRT_BITS -1)        /* ????? */
1486
1487 /************************************************/
1488 /*******            Drawing the polygons ********/
1489 /************************************************/
1490
1491 /* draw a single vertex as a point symbol, if requested by the chosen
1492  * plot style (linespoints, points, or dots...) */
1493 static void
1494 draw_vertex(p_vertex v)
1495 {
1496     unsigned int x, y;
1497
1498     TERMCOORD(v, x, y);
1499     if (v->lp_style && v->lp_style->p_type >= 0 && !clip_point(x,y)) {
1500         int colortype = v->lp_style->pm3d_color.type;
1501
1502 #ifdef EAM_DATASTRINGS
1503         if (v->label)  {
1504             write_label(x,y, v->label);
1505             v->lp_style = NULL;
1506             return;
1507         }
1508 #endif
1509
1510         /* EAM DEBUG - Check for extra point properties */
1511         if (colortype == TC_LT)
1512             /* Should have been set already! */
1513             ;
1514         else if (colortype == TC_RGB && v->lp_style->pm3d_color.lt == LT_COLORFROMCOLUMN)
1515             set_rgbcolor(v->real_z);
1516         else if (colortype == TC_RGB)
1517             set_rgbcolor(v->lp_style->pm3d_color.lt);
1518         else if (colortype == TC_Z)
1519             set_color( cb2gray(z2cb(v->real_z)) );
1520
1521 #ifdef HIDDEN3D_VAR_PTSIZE
1522         if (v->lp_style->p_size == PTSZ_VARIABLE)
1523             (term->pointsize)(pointsize * v->original->CRD_PTSIZE);
1524 #endif
1525
1526         (term->point)(x,y, v->lp_style->p_type);
1527
1528         /* vertex has been drawn --> flag it as done */
1529         v->lp_style = NULL;
1530     }
1531 }
1532
1533
1534 /* The function that actually does the drawing of the visible portions
1535  * of lines */
1536 /* HBB 20001108: changed to take the pointers to the end vertices as
1537  * additional arguments. */
1538 static void
1539 draw_edge(p_edge e, p_vertex v1, p_vertex v2)
1540 {
1541     assert (e >= elist && e < elist + edges.end);
1542
1543     draw3d_line_unconditional(v1, v2, e->lp, e->style);
1544     if (e->lp->pointflag) {
1545         draw_vertex(v1);
1546         draw_vertex(v2);
1547     }
1548 }
1549
1550
1551 /*************************************************************/
1552 /*************************************************************/
1553 /*******   The depth sort algorithm (in_front) and its  ******/
1554 /*******   whole lot of helper functions                ******/
1555 /*************************************************************/
1556 /*************************************************************/
1557
1558 /* Split a given line segment into two at an inner point. The inner
1559  * point is specified as a fraction of the line-length (0 is V1, 1 is
1560  * V2) */
1561 /* HBB 20001108: changed to now take two vertex pointers as its
1562  * arguments, rather than an edge pointer. */
1563 /* HBB 20001204: changed interface again. Now use vertex indices,
1564  * rather than pointers, to avoid problems with dangling pointers
1565  * after nextfrom_dynarray() call. */
1566 static long
1567 split_line_at_ratio(
1568     long vnum1, long vnum2,     /* vertex indices of line to split */
1569     double w)                   /* where to split it */
1570 {
1571     p_vertex v;
1572
1573     if (EQ(w, 0.0))
1574         return vnum1;
1575     if (EQ(w, 1.0))
1576         return vnum2;
1577
1578     /* Create a new vertex */
1579     v = nextfrom_dynarray(&vertices);
1580
1581     v->x = (vlist[vnum2].x - vlist[vnum1].x) * w + vlist[vnum1].x;
1582     v->y = (vlist[vnum2].y - vlist[vnum1].y) * w + vlist[vnum1].y;
1583     v->z = (vlist[vnum2].z - vlist[vnum1].z) * w + vlist[vnum1].z;
1584     v->real_z = (vlist[vnum2].real_z - vlist[vnum1].real_z) * w
1585         + vlist[vnum1].real_z;
1586
1587     /* no point symbol for vertices generated by splitting an edge */
1588     v->lp_style = NULL;
1589
1590     /* additional checks to prevent adding unnecessary vertices */
1591     if (V_EQUAL(v, vlist + vnum1)) {
1592         droplast_dynarray(&vertices);
1593         return vnum1;
1594     }
1595     if (V_EQUAL(v, vlist + vnum2)) {
1596         droplast_dynarray(&vertices);
1597         return vnum2;
1598     }
1599
1600     return (v - vlist);
1601 }
1602
1603
1604 /* Compute the 'signed area' of 3 points in their 2d projection
1605  * to the x-y plane. Essentially the z component of the crossproduct.
1606  * Should come out positive if v1, v2, v3 are ordered counter-clockwise */
1607
1608 static GP_INLINE double
1609 area2D(p_vertex v1, p_vertex v2, p_vertex v3)
1610 {
1611     double
1612         dx12 = v2->x - v1->x,   /* x/y components of (v2-v1) and (v3-v1) */
1613         dx13 = v3->x - v1->x,
1614         dy12 = v2->y - v1->y,
1615         dy13 = v3->y - v1->y;
1616     return (dx12 * dy13 - dy12 * dx13);
1617 }
1618
1619 /* Utility routine: takes an edge and makes a new one, which is a fragment
1620  * of the old one. The fragment inherits the line style and stuff of the
1621  * given edge; only the two new vertices are different. The new edge
1622  * is then passed to in_front, for recursive handling */
1623 /* HBB 20001108: Changed from edge pointer to edge index. Don't
1624  * allocate a fresh anymore, as this is no longer needed after the
1625  * change to in_front().  What remains of this function may no longer
1626  * be worth having. I.e. it can be replaced by a direct recursion call
1627  * of in_front(), sometime soon. */
1628 static GP_INLINE void
1629 handle_edge_fragment(long edgenum, long vnum1, long vnum2, long firstpoly)
1630 {
1631 #if !HIDDEN3D_QUADTREE
1632     /* Avoid checking against the same polygon again. */
1633     firstpoly = plist[firstpoly].next;
1634 #endif
1635     in_front(edgenum, vnum1, vnum2, &firstpoly);
1636 }
1637
1638 /*********************************************************************/
1639 /* The actual heart of all this: determines if edge at index 'edgenum'
1640  * of the elist is in_front of all the polygons, or not. If necessary,
1641  * it will recursively call itself to isolate more than one visible
1642  * fragment of the input edge. Wherever possible, recursion is
1643  * avoided, by in-place modification of the edge.
1644  *
1645  * The visible fragments are then drawn by a call to 'draw_edge' from
1646  * inside this routine. */
1647 /*********************************************************************/
1648 /* HBB 20001108: changed to now take the vertex numbers as additional
1649  * arguments. The idea is to not overwrite the endpoint stored with
1650  * the edge, so Test 2 will catch on even after the subject edge has
1651  * been split up before one of its two polygons is tested against
1652  * it. FIXME: allocates new vertices when splitting, but never frees
1653  * them, currently. */
1654
1655 static int
1656 in_front(
1657     long edgenum,               /* number of the edge in elist */
1658     long vnum1, long vnum2,     /* numbers of its endpoints */
1659     long *firstpoly)            /* first plist index to consider */
1660 {
1661     p_polygon p;                /* pointer to current testing polygon */
1662     long int polynum;           /* ... and its index in the plist */
1663     p_vertex v1, v2;            /* pointers to vertices of input edge */
1664
1665     coordval xmin, xmax;        /* all of these are for the edge */
1666     coordval ymin, ymax;
1667     coordval zmin, zmax;
1668 #if HIDDEN3D_GRIDBOX
1669     unsigned int xextent;       /* extent bitmask in x direction */
1670     unsigned int yextent;       /* same, in y direction */
1671
1672 # define SET_XEXTENT \
1673   xextent = CALC_BITRANGE(xmin, xmax);
1674 # define SET_YEXTENT \
1675   yextent = CALC_BITRANGE(ymin, ymax);
1676 #else
1677 # define SET_XEXTENT /* nothing */
1678 # define SET_YEXTENT /* nothing */
1679 #endif
1680 #if HIDDEN3D_QUADTREE
1681     int grid_x, grid_y;
1682     int grid_x_low, grid_x_high;
1683     int grid_y_low, grid_y_high;
1684     long listhead;
1685 #endif
1686
1687     /* zmin of the edge, as it started out. This is needed separately to
1688      * allow modifying '*firstpoly', without moving it too far to the
1689      * front. */
1690     coordval first_zmin;
1691
1692     /* macro for eliminating tail-recursion inside in_front: when the
1693      * current edge is modified, recompute all function-wide status
1694      * variables. Note that it guarantees that v1 is always closer to
1695      * the viewer than v2 (in z direction) */
1696     /* HBB 20001108: slightly changed so it can be called with vnum1
1697      * and vnum2 as its arguments, too */
1698 #define setup_edge(vert1, vert2)                \
1699     do {                                        \
1700         if (vlist[vert1].z > vlist[vert2].z) {  \
1701             v1 = vlist + (vert1);               \
1702             v2 = vlist + (vert2);               \
1703         } else {                                \
1704             v1 = vlist + (vert2);               \
1705             v2 = vlist + (vert1);               \
1706         }                                       \
1707         vnum1 = v1 - vlist;                     \
1708         vnum2 = v2 - vlist;                     \
1709         zmax = v1->z;   zmin = v2->z;           \
1710                                                 \
1711         if (v1->x > v2->x) {                    \
1712             xmin = v2->x;       xmax = v1->x;   \
1713         } else {                                \
1714             xmin = v1->x;       xmax = v2->x;   \
1715         }                                       \
1716         SET_XEXTENT;                            \
1717                                                 \
1718         if (v1->y > v2->y) {                    \
1719             ymin = v2->y;       ymax = v1->y;   \
1720         } else {                                \
1721             ymin = v1->y;       ymax = v2->y;   \
1722         }                                       \
1723         SET_YEXTENT;                            \
1724     } while (0) /* end macro setup_edge */
1725
1726     /* use the macro for initial setup, too: */
1727     setup_edge(vnum1, vnum2);
1728
1729     first_zmin = zmin;
1730
1731 #if HIDDEN3D_QUADTREE
1732     grid_x_low = coord_to_treecell(xmin);
1733     grid_x_high = coord_to_treecell(xmax);
1734     grid_y_low = coord_to_treecell(ymin);
1735     grid_y_high = coord_to_treecell(ymax);
1736
1737     for (grid_x = grid_x_low; grid_x <= grid_x_high; grid_x ++)
1738         for (grid_y = grid_y_low; grid_y <= grid_y_high; grid_y ++)
1739             for (listhead = quadtree[grid_x][grid_y];
1740                  listhead >= 0;
1741                  listhead = qlist[listhead].next)
1742 #else /* HIDDEN3D_QUADTREE */
1743     /* loop over all the polygons in the sorted list, starting at the
1744      * currently first (i.e. furthest, from the viewer) polgon. */
1745     for (polynum = *firstpoly; polynum >=0; polynum = p->next)
1746 #endif /* HIDDEN3D_QUADTREE */
1747         {
1748             /* shortcut variables for the three vertices of 'p':*/
1749             p_vertex w1, w2, w3;
1750             /* signed areas of each of e's vertices wrt. the edges of
1751              * p. I store them explicitly, because they are used more
1752              * than once, eventually */
1753             double e_side[2][POLY_NVERT];
1754             /* signed areas of each of p's vertices wrt. to edge e. Stored
1755              * for re-use in intersection calculations, as well */
1756             double p_side[POLY_NVERT];
1757             /* values got from throwing the edge vertices into the plane
1758              * equation of the polygon. Used for testing if the vertices are
1759              * in front of or behind the plane, and also to determine the
1760              * point where the edge goes through the polygon, by
1761              * interpolation. */
1762             double v1_rel_pplane, v2_rel_pplane;
1763             /* Orientation of polygon wrt. to the eye: front or back side
1764              * visible? */
1765             coordval polyfacing;
1766             int whichside;
1767             /* stores classification of cases as 4 2-bit patterns, mainly */
1768             unsigned int classification[POLY_NVERT + 1];
1769
1770 #if HIDDEN3D_QUADTREE
1771             polynum = qlist[listhead].p;
1772 #endif
1773             p = plist + polynum;
1774
1775             /* OK, off we go with the real work. This algo is mainly
1776              * following the one of 'HLines.java', as described in the
1777              * book 'Computer Graphics for Java Programmers', by Dutch
1778              * professor Leen Ammeraal, published by J.Wiley & Sons,
1779              * ISBN 0 471 98142 7. It happens to the only(!) actual
1780              * code or algorithm example I got out of a question to
1781              * the Newsgroup comp.graphics.algorithms, asking for a
1782              * hidden *line* removal algorithm. */
1783
1784             /* Test 1 (2D): minimax tests. Do x/y ranges of polygon
1785              * and edge have any overlap? */
1786             if (0
1787 #if HIDDEN3D_GRIDBOX
1788                 /* First, check by comparing the extent bit patterns: */
1789                 || (!(xextent & p->xbits))
1790                 || (!(yextent & p->ybits))
1791 #endif
1792                 || (p->xmax < xmin)
1793                 || (p->xmin > xmax)
1794                 || (p->ymax < ymin)
1795                 || (p->ymin > ymax)
1796                 )
1797                 continue;
1798
1799             /* Tests 2 and 3 switched... */
1800
1801             /* Test 3 (3D): Is edge completely in front of polygon? */
1802             if (p->zmax < zmin) {
1803                 /* Polygon completely behind this edge. Move start of
1804                  * relevant plist to this point, to speed up next
1805                  * run. This makes use of the fact that elist is also
1806                  * kept in upwardly sorted order of zmin, i.e. the
1807                  * condition found here will also hold for all coming
1808                  * edges in the list */
1809                 if (p->zmax < first_zmin)
1810                     *firstpoly = polynum;
1811                 continue;       /* this polygon is done with */
1812             }
1813
1814             /* Test 2 (0D): does edge belong to this very polygon? */
1815             /* 20001108: to make this rejector more effective, do keep
1816              * the original edge vertices unchanged */
1817             if (1
1818                 && (0
1819                     || (p->vertex[0] == elist[edgenum].v1)
1820                     || (p->vertex[1] == elist[edgenum].v1)
1821                     || (p->vertex[2] == elist[edgenum].v1)
1822                     )
1823                 && (0
1824                     || (p->vertex[0] == elist[edgenum].v2)
1825                     || (p->vertex[1] == elist[edgenum].v2)
1826                     || (p->vertex[2] == elist[edgenum].v2)
1827                     )
1828                 )
1829                 continue;
1830
1831             w1 = vlist + p->vertex[0];
1832             w2 = vlist + p->vertex[1];
1833             w3 = vlist + p->vertex[2];
1834
1835
1836             /* Test 4 (2D): Is edge fully on the 'wrong side' of one of the
1837              * polygon edges?
1838              *
1839              * Done by comparing signed areas (cross-product z components of
1840              * both edge endpoints) to that of the polygon itself (as given by
1841              * the plane normal z component). If both v1 and v2 are found on
1842              * the 'outside' side of a polygon edge (interpreting it as
1843              * infinite line), the polygon can't obscure this edge. All the
1844              * signed areas are remembered, for later tests. */
1845             polyfacing = p->plane[2];
1846             whichside = SIGN(polyfacing);
1847             if (!whichside)
1848                 /* We're looking at the border of this polygon. It
1849                  * looks like an infitisemally thin line, i.e. it'll
1850                  * be practically invisible*/
1851                 /* FIXME: should such a polygon have been stored in the plist,
1852                  * in the first place??? */
1853                 continue;
1854
1855             /* p->plane[2] is now forced >=0, so it doesn't tell anything
1856              * about which side the polygon is facing */
1857             whichside = (p->frontfacing) ? -1 : 1;
1858
1859 #if 0
1860             /* Just make sure I got this the right way round: */
1861             if (p->frontfacing)
1862                 assert (GE(area2D(w1, w2, w3),0));
1863             else
1864                 assert (GE(0,area2D(w1, w2, w3)));
1865 #endif
1866
1867             /* classify both endpoints of the test edge, by their
1868              * position relative to some plane that defines the volume
1869              * shadowed by a triangle. Used both by macro 'checkside',
1870              * and for individual checking, below --> put this into a
1871              * macro */
1872 #define classify(par1, par2, classnum)                                  \
1873             do {                                                        \
1874                 if (GR(par1, 0)) {                                      \
1875                     /* v1 strictly outside --> v2 in-plane is enough,   \
1876                        already : */                                     \
1877                     classification[classnum]                            \
1878                         = (1 << 0) | ((GE(par2, 0)) << 1);              \
1879                 } else if (GR(par2, 0)) {                               \
1880                     /* v2 strictly outside --> v1 in-plane is enough,   \
1881                        already : */                                     \
1882                     classification[classnum]                            \
1883                         = ((GE(par1, 0)) << 0) | (1 << 1);              \
1884                 } else {                                                \
1885                     /* as neither one of them is strictly outside,      \
1886                      * there's no need for any edge-splitting, at all.  \
1887                      * */                                               \
1888                     classification[classnum] = 0;                       \
1889                 }                                                       \
1890             } while (0)
1891
1892             /* code block used thrice, so put into a macro. The
1893              * 'area2D' calls return <0, ==0 or >0 if the three
1894              * vertices passed to it are in clockwise order, colinear,
1895              * or in conter-clockwise order, respectively. So the sign
1896              * of this can be used to determine if a point is inside
1897              * or outside the shadow volume. */
1898 #define checkside(a,b,s)                                        \
1899             e_side[0][s] = whichside * area2D((a), (b), v1);    \
1900             e_side[1][s] = whichside * area2D((a), (b), v2);    \
1901             classify(e_side[0][s], e_side[1][s], s);            \
1902             if (classification[s] == 3)                         \
1903                 continue;
1904
1905             checkside(w1, w2, 0);
1906             checkside(w2, w3, 1);
1907             checkside(w3, w1, 2);
1908 #undef checkside                /* get rid of that macro, again */
1909
1910
1911             /* Test 5 (2D): Does the whole polygon lie on one and the same
1912              * side of the tested edge? Again, area2D is used to determine on
1913              * which side of a given edge a vertex lies. */
1914             /* HBB 20000621: this test only makes sense if this is a
1915              * 'real' edge, not just a single point */
1916             /* HBB 20051206: but p_side[] may still have to be computed, to be used
1917              * by Test 9 */
1918             p_side[0] = area2D(v1, v2, w1);
1919             p_side[1] = area2D(v1, v2, w2);
1920             p_side[2] = area2D(v1, v2, w3);
1921             if (v1 != v2) {
1922                 /* HBB 20001104: made this more restrictive: only
1923                  * reject p if areas are greater than 0, i.e. don't
1924                  * allow EQ(..,0). Otherwise, edges coincident with a
1925                  * polygon edge in 2D will not be hidden by it. */
1926                 /* FIXME HBB 20001108: some more code will be needed
1927                  * here or further down below. It will currently fail
1928                  * if two edges fall exactly on top of each other
1929                  * (like the crossover line in the Klein-bottle demo):
1930                  * both edges will be hidden by the other's polygon,
1931                  * essentially */
1932 #if 0
1933                 if (0
1934                     || (GR(p_side[0], 0)
1935                         && GR(p_side[1], 0)
1936                         && GR(p_side[2], 0)
1937                         )
1938                     || (GR(0 , p_side[0])
1939                         && GR(0 , p_side[1])
1940                         && GR(0 , p_side[2])
1941                         )
1942                     )
1943                     continue;
1944 #else
1945                 /* HBB 20020406: try to repair this */
1946                 if (0
1947                     || (GE(p_side[0], 0)
1948                         && GE(p_side[1], 0)
1949                         && GE(p_side[2], 0)
1950                         )
1951                     || (GE(0 , p_side[0])
1952                         && GE(0 , p_side[1])
1953                         && GE(0 , p_side[2])
1954                         )
1955                     )
1956                     continue;
1957 #endif
1958             }
1959
1960             /* Test 6 (3D): does the whole edge lie on the viewer's
1961              * side of the polygon's plane? */
1962             v1_rel_pplane = eval_plane_equation(p->plane, v1);
1963             v2_rel_pplane = eval_plane_equation(p->plane, v2);
1964
1965             /* Condense into classification bit pattern for v1 and v2
1966              * wrt.  this plane, and store into entry 'POLY_NVERT' of
1967              * the classification array, following the three edges of
1968              * the polygon. */
1969             classify(v1_rel_pplane, v2_rel_pplane, POLY_NVERT);
1970
1971             if (classification[POLY_NVERT] == 3)
1972                 continue;                                                                       /* edge completely in front of polygon */
1973
1974             /* Test 7 (2D): is edge completely inside the triangle?
1975              * The stored results from Test 4 make this rather easy to
1976              * check: if a point is oriented equally wrt. all three
1977              * edges, and also to the triangle itself, the point is
1978              * inside the 2D triangle: */
1979
1980             /* search for any one bits (--> they mean 'outside') */
1981             if (! (classification[0]
1982                    | classification[1]
1983                    | classification[2])) {
1984
1985                 /* Edge is completely inside the polygon's 2D
1986                  * projection. Unlike Ammeraal, I have to check for
1987                  * edges penetrating polygons, as well. */
1988
1989                 /* Check if edge really doesn't intersect the triangle
1990                  * (this happens in roughly one third of the
1991                  * cases). If both vertices have been classified as
1992                  * 'behind', the result is true even in the case of
1993                  * possibly intersecting polygons */
1994                 /* HBB 20020408: softened this check to allow edges
1995                  * not to be hidden by polygons they're fully inside.
1996                  * I.e. only declare the edge invisible if at least
1997                  * one of its endpoints is truly behind, not inside
1998                  * the polygon's plane. ---> FIXME 20001108 above */
1999                 if (!classification[POLY_NVERT]
2000                     && (GR(0, v1_rel_pplane) || GR(0, v2_rel_pplane)))
2001                     return 0;
2002             }
2003
2004
2005             /* Test 8 (3D): If no edge intersects any polygon, the edge must
2006              * lie infront of the poly if the 'inside' vertex in front of it.
2007              * This test doesn't work if lines might intersect polygons, so I
2008              * took it out of my version of Ammeraal's algorithm. */
2009
2010
2011             /* Test 9 (3D): The final 'catch-all' handler. We now know
2012              * that the edges passes through the walls of the
2013              * semifinite polygonal cylinder of invisible space
2014              * stamped out by the polygon, somewhere, so we have to
2015              * compute the intersection points with the 2D projection
2016              * of the polygon and check whether they are infront of or
2017              * behind the polygon, to isolate the visible fragments of
2018              * the line. Method is to calc. the [0..1] parameter that
2019              * describes the way from V1 to V2, for all intersections
2020              * of the edge with any of the planes that define the
2021              * 'shadow volume' of this polygon, and deciding what to
2022              * do, with all this.
2023              *
2024              * The remaining work can be classified by the values of
2025              * the variables calculated in previous tests:
2026              * v{1/2}_rel_pplane, e_side[2][POLY_NVERT],
2027              * p_side[POLY_NVERT]. Setting aside cases where one of
2028              * them is zero, this leaves a total of 2^11 = 2048
2029              * separate cases, in principal. Several of those have
2030              * been sorted out, already, by the previous tests. That
2031              * leaves us with 3*27 cases, essentially. The '3' cases
2032              * differ by which of the three vertices of the polygon is
2033              * alone on its side of the test edge.  That already fixes
2034              * which two edges might intersect the test edge.  The 27
2035              * cases differ by which of the edge points lies on which
2036              * of the three planes in space (two sides, and the
2037              * polygon plane) that remain interesting for the tests.
2038              * That would normally make 2^2 = 4 cases per plane. But
2039              * the 'both outside' cases for all three planes have
2040              * already been taken care of, earlier, leaving 3 of those
2041              * cases to be handled. This is the same for all three
2042              * relevant planes, so we get 3^3 = 27 cases. */
2043
2044             {
2045                 /* the interception point parameters: */
2046                 double front_hit, this_hit, hit_in_poly;
2047                 long newvert[2];
2048                 int side1, side2;
2049                 double hit1, hit2;
2050                 unsigned int full_class;
2051
2052                 /* find out which of the three edges would be intersected: */
2053                 if ((p_side[0] > 0) == (p_side[1] > 0)) {
2054                     /* first two vertices on the same side, the third
2055                      * is on the 'other' side of the test edge */
2056                     side1 = 1;
2057                     side2 = 2;
2058                 } else if ((p_side[0] > 0) == (p_side[2] > 0)) {
2059                     /* vertex '1' on the other side */
2060                     side1 = 0;
2061                     side2 = 1;
2062                 } else {
2063                     /* we now know that it must be the first vertex
2064                      * that is on the 'other' side, as not all three
2065                      * can be on different sides. */
2066                     side1 = 0;
2067                     side2 = 2;
2068                 }
2069
2070                 /* Carry out the classification into those 27 cases,
2071                  * based upon classification bits precomputed above,
2072                  * and calculate the intersection parameters, as
2073                  * appropriate. Start by regarding the polygon's
2074                  * plane: '1' means point is in front of plane.
2075                  *
2076                  * First, some utility macros: */
2077 #define cleanup_hit(hit)                        \
2078                 do {                            \
2079                     if (EQ(hit,0))              \
2080                         hit=0;                  \
2081                     else if (EQ(hit,1))         \
2082                         hit=1;                  \
2083                 } while (0)
2084
2085 #define hit_in_edge(hit) ((hit >= 0) && (hit <= 1))
2086
2087                 /* find the intersection point through the front
2088                  * plane, if any: */
2089                 front_hit = 1e10;
2090                 if (classification[3]) {
2091                     if (SIGN(v1_rel_pplane - v2_rel_pplane)) {
2092                         front_hit = v1_rel_pplane / (v1_rel_pplane - v2_rel_pplane);
2093                         cleanup_hit(front_hit);
2094                     }
2095                     if (!hit_in_edge(front_hit)) {
2096                         front_hit = 1e10;
2097                         classification[3] = 0;  /* not really intersecting */
2098                     }
2099                 }
2100
2101
2102                 /* Find intersection points with the two relevant side
2103                  * planes of the shadow volume. A macro contains the
2104                  * code, to be used for both side1 and side2, to
2105                  * reduce code overhead: */
2106 #define check_out_hit(hit, side)                                        \
2107                 do {                                                    \
2108                     hit = 1e10; /* default is 'way off' */              \
2109                     if (classification[side]) {                         \
2110                         /* Not both inside, i.e. there has to be an     \
2111                          * intersection point: */                       \
2112                         hit_in_poly = - whichside * p_side[side]        \
2113                             / (e_side[0][side] - e_side[1][side]);      \
2114                         cleanup_hit(hit_in_poly);                       \
2115                         if (hit_in_edge(hit_in_poly))   {               \
2116                             this_hit = e_side[0][side]                  \
2117                                 / (e_side[0][side] - e_side[1][side]);  \
2118                             cleanup_hit(this_hit);                      \
2119                             if (hit_in_edge(this_hit)) {                \
2120                                 hit = this_hit;                         \
2121                             }                                           \
2122                         }                                               \
2123                     }                                                   \
2124                     if (hit == 1e10)                                    \
2125                         /* doesn't really intersect */                  \
2126                         classification[side] = 0;                       \
2127                 } while (0)
2128
2129                 check_out_hit(hit1, side1);
2130                 check_out_hit(hit2, side2);
2131 #undef check_out_hit
2132
2133                 /* OK, now we know the position of all the hits that
2134                  * might be needed, given by their positions between
2135                  * the test edge's vertices. */
2136
2137                 /* Macro: combine all the classifications into a
2138                  * single classification bitpattern, for easier
2139                  * listing of cases */
2140 #define makeclass(s2, s1, p) (16 * s2 + 4 * s1 + p)
2141
2142                 full_class = makeclass(classification[side2],
2143                                        classification[side1],
2144                                        classification[3]);
2145
2146                 if (!full_class)
2147                     /* all suspected intersections cleared, already! */
2148                     continue;
2149
2150                 /* First sort out all cases where one endpoint is
2151                  * attributed to more than one intersecting
2152                  * plane. Only one of those can be 'the real'
2153                  * intersection of the edge with the surface of the
2154                  * shadow volume surface. The others are intersections
2155                  * with the planes defining the volumes, but outside
2156                  * the actual faces.
2157                  *
2158                  * This cuts down the 27 to 13 cases (000, 001, 002,
2159                  * 012, and their permutations). Start with v1: */
2160                 switch (full_class & makeclass(1, 1, 1)) {
2161                 case makeclass(0,1,1):
2162                     /* v1 is out 'side1' and infront of 'p' */
2163                     if (front_hit < hit1)
2164                         classification[3] = 0;
2165                     else
2166                         classification[side1] = 0;
2167                     break;
2168
2169                 case makeclass(1,0,1):
2170                     /* v1 is out 'side2' and infront of 'p' */
2171                     if (front_hit < hit2)
2172                         classification[3] = 0;
2173                     else
2174                         classification[side2] = 0;
2175                     break;
2176
2177                     /* The following two cases never trigger, even in
2178                      * a full run through all.dem. Neither do the
2179                      * corresponding 2 cases for the vertex2
2180                      * classification. I think this is so because the
2181                      * determination of 'side1' and 'side2' already
2182                      * took care of this: if the edge vertex is out
2183                      * two sides, those two will _not_ be chosen as
2184                      * 'side1' and 'side2', because one of them is
2185                      * completely on one side of the edge.  */
2186                 case makeclass(1,1,0):
2187                     /* v1 out both sides, but behind the front */
2188                     if (hit1 < hit2)
2189                         /* hit2 is closer to the hidden vertex v2, so
2190                          * it's the relevant intersection: */
2191                         classification[side1] = 0;
2192                     else
2193                         classification[side2] = 0;
2194                     break;
2195
2196                 case makeclass(1,1,1):
2197                     /* v1 out both sides, and in front of p (--> v2 is
2198                      * hidden) */
2199                     if (front_hit < hit1) {
2200                         classification[3] = 0;
2201                         if (hit1 < hit2)
2202                             classification[side1] = 0;
2203                         else
2204                             classification[side2] = 0;
2205                     } else {
2206                         classification[side1] = 0;
2207                         if (front_hit < hit2)
2208                             classification[3] = 0;
2209                         else
2210                             classification[side2] = 0;
2211                     }
2212                     break;
2213
2214                 default:
2215                     ; /* do nothing */
2216                 } /* switch(v1 classes) */
2217
2218
2219                 /* And the same, for v2 */
2220                 switch (full_class & makeclass(2, 2, 2)) {
2221                 case makeclass(0,2,2):
2222                     /* v2 is out 'side1' and infront of 'p' */
2223                     if (front_hit > hit1)
2224                         classification[3] = 0;
2225                     else
2226                         classification[side1] = 0;
2227                     break;
2228
2229                 case makeclass(2,0,2):
2230                     /* v2 out side 'side2' and infront of 'p' */
2231                     if (front_hit > hit2)
2232                         classification[3] = 0;
2233                     else
2234                         classification[side2] = 0;
2235                     break;
2236
2237                     /* See note in v1 handling about these two cases
2238                      * being impossible... */
2239                 case makeclass(2,2,0):
2240                     /* v2 out both sides, but behind the front */
2241                     if (hit1 > hit2)
2242                         /* hit2 is closer to the hidden vertex v2, so
2243                          * it's the relevant intersection: */
2244                         classification[side1] = 0;
2245                     else
2246                         classification[side2] = 0;
2247                     break;
2248
2249                 case makeclass(2,2,2):
2250                     /* v2 out both sides, and in front of p (--> v1 is
2251                      * hidden) */
2252                     if (front_hit > hit1) {
2253                         classification[3] = 0;
2254                         if (hit1 > hit2)
2255                             classification[side1] = 0;
2256                         else
2257                             classification[side2] = 0;
2258                     } else {
2259                         classification[side1] = 0;
2260                         if (front_hit > hit2)
2261                             classification[3] = 0;
2262                         else
2263                             classification[side2] = 0;
2264                     }
2265                     break;
2266
2267                 default:
2268                     ; /* do nothing */
2269                 } /* switch(v2 classes) */
2270
2271
2272                 /* recalculate full_class after all these possible changes: */
2273                 full_class = makeclass(classification[side2],
2274                                        classification[side1],
2275                                        classification[3]);
2276
2277                 /* This monster switch catches all the 13 remaining cases
2278                  * individually. */
2279                 switch (full_class) {
2280                 default:
2281                     printf("in_front: (T9) class %d is illegal. Should never happen.\n",
2282                            full_class);
2283                     break;
2284                 case makeclass(0,0,0):
2285                     /* can happen, by resetting of classification bits
2286                      * inside this test */
2287                     break;
2288
2289 /*--------- The simplest cases first: only one intersection point -----*/
2290                     /* Code is the same for all six cases, or nearly so: */
2291 #define handle_singleplane_hit(vert, hitpar)                                \
2292                     newvert[0] = split_line_at_ratio(vnum1, vnum2, hitpar); \
2293                     setup_edge(vert, newvert[0]);                           \
2294                     break;
2295
2296                 case makeclass(0,0,1): /* v1 is in front of poly: */
2297                     handle_singleplane_hit(vnum1, front_hit);
2298                 case makeclass(0,0,2): /* v2 is in front of poly: */
2299                     handle_singleplane_hit(vnum2, front_hit);
2300                 case makeclass(0,1,0): /* v1 is out side1: */
2301                     handle_singleplane_hit(vnum1,hit1);
2302                 case makeclass(0,2,0): /* v2 is out side1: */
2303                     handle_singleplane_hit(vnum2,hit1);
2304                 case makeclass(1,0,0): /* v1 is out side2 */
2305                     handle_singleplane_hit(vnum1,hit2);
2306                 case makeclass(2,0,0): /* v2 is out side2 */
2307                     handle_singleplane_hit(vnum2,hit2);
2308
2309 /*----------- cases with 2 certain intersections: --------------*/
2310                 case makeclass(1,2,0):
2311                 case makeclass(2,1,0):
2312                     /* Both behind the front, v1 out one side, v2 out
2313                      * the other.  These two cases can be handled by
2314                      * common code: */
2315                     newvert[0] = split_line_at_ratio(vnum1, vnum2, hit1);
2316                     newvert[1] = split_line_at_ratio(vnum1, vnum2, hit2);
2317                     if (hit1 < hit2) {
2318                         /* the fragments are v1--hit1 and hit2--v2 */
2319                         handle_edge_fragment(edgenum, newvert[1], vnum2, polynum);
2320                         setup_edge(vnum1, newvert[0]);
2321                     } else {
2322                         /* the fragments are v2--hit1 and hit2--v1 */
2323                         handle_edge_fragment(edgenum, vnum1, newvert[1], polynum);
2324                         setup_edge(newvert[0], vnum2);
2325                     }
2326                     break;
2327
2328 /*----------- cases with either 2 or no intersections: --------------*/
2329
2330                     /* Mainly identical code block to be used 4 times
2331                      * --> macro */
2332                     /* HBB 20001108: up until today, this part of the
2333                      * was severely buggy. But I do think I've got it
2334                      * fixed up, this time */
2335 #define handle_outside_behind_vs_infront(hitvar1, hitvar2)                         \
2336                     /* vnum1 out plane of 'hitvar1' and in back, vnum2             \
2337                      * in front */                                                 \
2338                     if ((hitvar1) < (hitvar2)) {                                   \
2339                         newvert[0] = split_line_at_ratio(vnum1, vnum2, (hitvar1)); \
2340                         newvert[1] = split_line_at_ratio(vnum1, vnum2, (hitvar2)); \
2341                         handle_edge_fragment(edgenum, newvert[1], vnum2, polynum); \
2342                         setup_edge(vnum1, newvert[0]);                             \
2343                     }                                                              \
2344                     /* otherwise, the edge missed the shadow volume                \
2345                      * --> nothing to do */                                        \
2346                     break;
2347
2348                 case makeclass(0,1,2): /* v1 out side1 and in back, v2 in front */
2349                     handle_outside_behind_vs_infront(hit1, front_hit);
2350
2351                 case makeclass(0,2,1): /* v2 out side1 and in back, v1 in front */
2352                     handle_outside_behind_vs_infront(front_hit, hit1);
2353
2354                 case makeclass(1,0,2): /* v1 out side2 and in back, v2 in front */
2355                     handle_outside_behind_vs_infront(hit2, front_hit);
2356
2357                 case makeclass(2,0,1): /* v2 out side2 and in back, v1 in front */
2358                     handle_outside_behind_vs_infront(front_hit, hit2);
2359
2360 #undef handle_outside_behind_vs_infront
2361
2362                 } /* end of switch through the cases */
2363
2364             } /* end of part 'T9' */
2365         } /* for (polygons in list) */
2366
2367     /* Came here, so there's something left of this edge, which needs
2368      * to be drawn.  But the vertices are different, now, so copy our
2369      * new vertices back into 'e' */
2370
2371     draw_edge(elist + edgenum, vlist + vnum1, vlist + vnum2);
2372
2373     return 1;
2374 }
2375
2376
2377 /* HBB 20000617: reimplemented this routine from scratch */
2378 /* Externally callable function to draw a line, but hide it behind the
2379  * visible surface. */
2380 /* NB: The p_vertex arguments are not allowed to be pointers into the
2381  * hidden3d 'vlist' structure. If they are, they may become invalid
2382  * before they're used, because of the nextfrom_dynarray() call. */
2383 void
2384 draw_line_hidden(
2385     p_vertex v1, p_vertex v2,   /* pointers to the end vertices */
2386     struct lp_style_type *lp)   /* line and point style to draw in */
2387 {
2388     long int vstore1, vstore2;
2389     long int edgenum;
2390     long int temp_pfirst;
2391
2392     /* If no polygons have been stored, nothing can be hidden, and we
2393      * can't use in_front() because the datastructures are partly
2394      * invalid. So just draw the line and be done with it */
2395     if (!polygons.end) {
2396         draw3d_line_unconditional(v1, v2, lp, lp->l_type);
2397         return;
2398     }
2399
2400     /* Copy two vertices into hidden3d arrays: */
2401     nextfrom_dynarray(&vertices);
2402     vstore1 = vertices.end - 1;
2403     vlist[vstore1] = *v1;
2404     if (v2) {
2405         vlist[vstore1].lp_style = NULL;
2406         nextfrom_dynarray(&vertices);
2407         vstore2 = vertices.end - 1;
2408         vlist[vstore2] = *v2;
2409         vlist[vstore2].lp_style = NULL;
2410     } else {
2411         /* v2 == NULL --> this is a point symbol to be drawn. Make two
2412          * vertex pointers the same, and set up the 'style' field */
2413         vstore2 = vstore1;
2414         vlist[vstore2].lp_style = lp;
2415     }
2416
2417     /* store the edge into the hidden3d datastructures */
2418     edgenum = make_edge(vstore1, vstore2, lp, lp->l_type, -1);
2419
2420     /* remove hidden portions of the line, and draw what remains */
2421     temp_pfirst = pfirst;
2422     in_front(edgenum, elist[edgenum].v1, elist[edgenum].v2, &temp_pfirst);
2423
2424     /* release allocated storage slots: */
2425     droplast_dynarray(&edges);
2426     droplast_dynarray(&vertices);
2427     if (v2)
2428         droplast_dynarray(&vertices);
2429 }
2430
2431 /***********************************************************************
2432  * and, finally, the 'mother function' that uses all these lots of tools
2433  ***********************************************************************/
2434 void
2435 plot3d_hidden(struct surface_points *plots, int pcount)
2436 {
2437     /* make vertices, edges and polygons out of all the plots */
2438     build_networks(plots, pcount);
2439
2440     if (! edges.end) {
2441         /* No drawable edges found. Free all storage and bail out. */
2442         term_hidden_line_removal();
2443         graph_error("*All* edges undefined or out of range, thus no plot.");
2444     }
2445
2446     if (! polygons.end) {
2447         /* No polygons anything could be hidden behind... */
2448
2449         sort_edges_by_z();
2450         while (efirst >= 0) {
2451             draw_edge(elist+efirst, vlist + elist[efirst].v1, vlist + elist[efirst].v2);
2452             efirst = elist[efirst].next;
2453         }
2454     } else {
2455         long int temporary_pfirst;
2456
2457         /* Presort edges in z order */
2458         sort_edges_by_z();
2459         /* Presort polygons in z order */
2460         sort_polys_by_z();
2461
2462         temporary_pfirst = pfirst;
2463
2464         while (efirst >=0) {
2465             if (elist[efirst].style >= -2) /* skip invisible edges */
2466                 in_front(efirst, elist[efirst].v1, elist[efirst].v2,
2467                          &temporary_pfirst);
2468             efirst = elist[efirst].next;
2469         }
2470     }
2471
2472     /* Free memory */
2473     /* FIXME: anything to free? */
2474 }
2475
2476 void
2477 reset_hidden3doptions()
2478 {
2479     hiddenBacksideLinetypeOffset = BACKSIDE_LINETYPE_OFFSET;
2480     hiddenTriangleLinesdrawnPattern = TRIANGLE_LINESDRAWN_PATTERN;
2481     hiddenHandleUndefinedPoints = HANDLE_UNDEFINED_POINTS;
2482     hiddenShowAlternativeDiagonal = SHOW_ALTERNATIVE_DIAGONAL;
2483     hiddenHandleBentoverQuadrangles = HANDLE_BENTOVER_QUADRANGLES;
2484 }
2485
2486 /* Emacs editing help for HBB:
2487  * Local Variables: ***
2488  * c-basic-offset: 4 ***
2489  * End: ***
2490  */