ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/QuickHull/io.c
Revision: 1138
Committed: Tue May 29 22:51:00 2007 UTC (17 years, 11 months ago) by chuckv
Content type: text/plain
File size: 133322 byte(s)
Log Message:
Addded QuickHull to cvs.

File Contents

# User Rev Content
1 chuckv 1138 /*<html><pre> -<a href="qh-io.htm"
2     >-------------------------------</a><a name="TOP">-</a>
3    
4     io.c
5     Input/Output routines of qhull application
6    
7     see qh-io.htm and io.h
8    
9     see user.c for qh_errprint and qh_printfacetlist
10    
11     unix.c calls qh_readpoints and qh_produce_output
12    
13     unix.c and user.c are the only callers of io.c functions
14     This allows the user to avoid loading io.o from qhull.a
15    
16     copyright (c) 1993-2003 The Geometry Center
17     */
18    
19     #include "QuickHull/qhull_a.h"
20    
21     /*========= -functions in alphabetical order after qh_produce_output() =====*/
22    
23     /*-<a href="qh-io.htm#TOC"
24     >-------------------------------</a><a name="produce_output">-</a>
25    
26     qh_produce_output()
27     prints out the result of qhull in desired format
28     if qh.GETarea
29     computes and prints area and volume
30     qh.PRINTout[] is an array of output formats
31    
32     notes:
33     prints output in qh.PRINTout order
34     */
35     void qh_produce_output(void) {
36     int i, tempsize= qh_setsize ((setT*)qhmem.tempstack), d_1;
37    
38     if (qh VORONOI) {
39     qh_clearcenters (qh_ASvoronoi);
40     qh_vertexneighbors();
41     }
42     if (qh TRIangulate) {
43     qh_triangulate();
44     if (qh VERIFYoutput && !qh CHECKfrequently)
45     qh_checkpolygon (qh facet_list);
46     }
47     qh_findgood_all (qh facet_list);
48     if (qh GETarea)
49     qh_getarea(qh facet_list);
50     if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2)
51     qh_markkeep (qh facet_list);
52     if (qh PRINTsummary)
53     qh_printsummary(qh ferr);
54     else if (qh PRINTout[0] == qh_PRINTnone)
55     qh_printsummary(qh fout);
56     for (i= 0; i < qh_PRINTEND; i++)
57     qh_printfacets (qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL);
58     qh_allstatistics();
59     if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN))
60     qh_printstats (qh ferr, qhstat precision, NULL);
61     if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0))
62     qh_printstats (qh ferr, qhstat vridges, NULL);
63     if (qh PRINTstatistics) {
64     qh_collectstatistics();
65     qh_printstatistics(qh ferr, "");
66     qh_memstatistics (qh ferr);
67     d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;
68     fprintf(qh ferr, "\
69     size in bytes: merge %d ridge %d vertex %d facet %d\n\
70     normal %d ridge vertices %d facet vertices or neighbors %d\n",
71     sizeof(mergeT), sizeof(ridgeT),
72     sizeof(vertexT), sizeof(facetT),
73     qh normal_size, d_1, d_1 + SETelemsize);
74     }
75     if (qh_setsize ((setT*)qhmem.tempstack) != tempsize) {
76     fprintf (qh ferr, "qhull internal error (qh_produce_output): temporary sets not empty (%d)\n",
77     qh_setsize ((setT*)qhmem.tempstack));
78     qh_errexit (qh_ERRqhull, NULL, NULL);
79     }
80     } /* produce_output */
81    
82    
83     /*-<a href="qh-io.htm#TOC"
84     >-------------------------------</a><a name="dfacet">-</a>
85    
86     dfacet( id )
87     print facet by id, for debugging
88    
89     */
90     void dfacet (unsigned id) {
91     facetT *facet;
92    
93     FORALLfacets {
94     if (facet->id == id) {
95     qh_printfacet (qh fout, facet);
96     break;
97     }
98     }
99     } /* dfacet */
100    
101    
102     /*-<a href="qh-io.htm#TOC"
103     >-------------------------------</a><a name="dvertex">-</a>
104    
105     dvertex( id )
106     print vertex by id, for debugging
107     */
108     void dvertex (unsigned id) {
109     vertexT *vertex;
110    
111     FORALLvertices {
112     if (vertex->id == id) {
113     qh_printvertex (qh fout, vertex);
114     break;
115     }
116     }
117     } /* dvertex */
118    
119    
120     /*-<a href="qh-io.htm#TOC"
121     >-------------------------------</a><a name="compare_vertexpoint">-</a>
122    
123     qh_compare_vertexpoint( p1, p2 )
124     used by qsort() to order vertices by point id
125     */
126     int qh_compare_vertexpoint(const void *p1, const void *p2) {
127     vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
128    
129     return ((qh_pointid(a->point) > qh_pointid(b->point)?1:-1));
130     } /* compare_vertexpoint */
131    
132     /*-<a href="qh-io.htm#TOC"
133     >-------------------------------</a><a name="compare_facetarea">-</a>
134    
135     qh_compare_facetarea( p1, p2 )
136     used by qsort() to order facets by area
137     */
138     int qh_compare_facetarea(const void *p1, const void *p2) {
139     facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
140    
141     if (!a->isarea)
142     return -1;
143     if (!b->isarea)
144     return 1;
145     if (a->f.area > b->f.area)
146     return 1;
147     else if (a->f.area == b->f.area)
148     return 0;
149     return -1;
150     } /* compare_facetarea */
151    
152     /*-<a href="qh-io.htm#TOC"
153     >-------------------------------</a><a name="compare_facetmerge">-</a>
154    
155     qh_compare_facetmerge( p1, p2 )
156     used by qsort() to order facets by number of merges
157     */
158     int qh_compare_facetmerge(const void *p1, const void *p2) {
159     facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
160    
161     return (a->nummerge - b->nummerge);
162     } /* compare_facetvisit */
163    
164     /*-<a href="qh-io.htm#TOC"
165     >-------------------------------</a><a name="compare_facetvisit">-</a>
166    
167     qh_compare_facetvisit( p1, p2 )
168     used by qsort() to order facets by visit id or id
169     */
170     int qh_compare_facetvisit(const void *p1, const void *p2) {
171     facetT *a= *((facetT **)p1), *b= *((facetT **)p2);
172     int i,j;
173    
174     if (!(i= a->visitid))
175     i= - a->id; /* do not convert to int */
176     if (!(j= b->visitid))
177     j= - b->id;
178     return (i - j);
179     } /* compare_facetvisit */
180    
181     /*-<a href="qh-io.htm#TOC"
182     >-------------------------------</a><a name="countfacets">-</a>
183    
184     qh_countfacets( facetlist, facets, printall,
185     numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars )
186     count good facets for printing and set visitid
187     if allfacets, ignores qh_skipfacet()
188    
189     notes:
190     qh_printsummary and qh_countfacets must match counts
191    
192     returns:
193     numfacets, numsimplicial, total neighbors, numridges, coplanars
194     each facet with ->visitid indicating 1-relative position
195     ->visitid==0 indicates not good
196    
197     notes
198     numfacets >= numsimplicial
199     if qh.NEWfacets,
200     does not count visible facets (matches qh_printafacet)
201    
202     design:
203     for all facets on facetlist and in facets set
204     unless facet is skipped or visible (i.e., will be deleted)
205     mark facet->visitid
206     update counts
207     */
208     void qh_countfacets (facetT *facetlist, setT *facets, boolT printall,
209     int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) {
210     facetT *facet, **facetp;
211     int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0;
212    
213     FORALLfacet_(facetlist) {
214     if ((facet->visible && qh NEWfacets)
215     || (!printall && qh_skipfacet(facet)))
216     facet->visitid= 0;
217     else {
218     facet->visitid= ++numfacets;
219     totneighbors += qh_setsize (facet->neighbors);
220     if (facet->simplicial) {
221     numsimplicial++;
222     if (facet->keepcentrum && facet->tricoplanar)
223     numtricoplanars++;
224     }else
225     numridges += qh_setsize (facet->ridges);
226     if (facet->coplanarset)
227     numcoplanars += qh_setsize (facet->coplanarset);
228     }
229     }
230     FOREACHfacet_(facets) {
231     if ((facet->visible && qh NEWfacets)
232     || (!printall && qh_skipfacet(facet)))
233     facet->visitid= 0;
234     else {
235     facet->visitid= ++numfacets;
236     totneighbors += qh_setsize (facet->neighbors);
237     if (facet->simplicial){
238     numsimplicial++;
239     if (facet->keepcentrum && facet->tricoplanar)
240     numtricoplanars++;
241     }else
242     numridges += qh_setsize (facet->ridges);
243     if (facet->coplanarset)
244     numcoplanars += qh_setsize (facet->coplanarset);
245     }
246     }
247     qh visit_id += numfacets+1;
248     *numfacetsp= numfacets;
249     *numsimplicialp= numsimplicial;
250     *totneighborsp= totneighbors;
251     *numridgesp= numridges;
252     *numcoplanarsp= numcoplanars;
253     *numtricoplanarsp= numtricoplanars;
254     } /* countfacets */
255    
256     /*-<a href="qh-io.htm#TOC"
257     >-------------------------------</a><a name="detvnorm">-</a>
258    
259     qh_detvnorm( vertex, vertexA, centers, offset )
260     compute separating plane of the Voronoi diagram for a pair of input sites
261     centers= set of facets (i.e., Voronoi vertices)
262     facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded)
263    
264     assumes:
265     qh_ASvoronoi and qh_vertexneighbors() already set
266    
267     returns:
268     norm
269     a pointer into qh.gm_matrix to qh.hull_dim-1 reals
270     copy the data before reusing qh.gm_matrix
271     offset
272     if 'QVn'
273     sign adjusted so that qh.GOODvertexp is inside
274     else
275     sign adjusted so that vertex is inside
276    
277     qh.gm_matrix= simplex of points from centers relative to first center
278    
279     notes:
280     in io.c so that code for 'v Tv' can be removed by removing io.c
281     returns pointer into qh.gm_matrix to avoid tracking of temporary memory
282    
283     design:
284     determine midpoint of input sites
285     build points as the set of Voronoi vertices
286     select a simplex from points (if necessary)
287     incl. midpoint if the Voronoi region is unbounded
288     relocate the first vertex of the simplex to the origin
289     compute the normalized hyperplane through the simplex
290     orient the hyperplane toward 'QVn' or 'vertex'
291     if 'Tv' or 'Ts'
292     if bounded
293     test that hyperplane is the perpendicular bisector of the input sites
294     test that Voronoi vertices not in the simplex are still on the hyperplane
295     free up temporary memory
296     */
297     pointT *qh_detvnorm (vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) {
298     facetT *facet, **facetp;
299     int i, k, pointid, pointidA, point_i, point_n;
300     setT *simplex= NULL;
301     pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint;
302     coordT *coord, *gmcoord, *normalp;
303     setT *points= qh_settemp (qh TEMPsize);
304     boolT nearzero= False;
305     boolT unbounded= False;
306     int numcenters= 0;
307     int dim= qh hull_dim - 1;
308     realT dist, offset, angle, zero= 0.0;
309    
310     midpoint= qh gm_matrix + qh hull_dim * qh hull_dim; /* last row */
311     for (k= 0; k < dim; k++)
312     midpoint[k]= (vertex->point[k] + vertexA->point[k])/2;
313     FOREACHfacet_(centers) {
314     numcenters++;
315     if (!facet->visitid)
316     unbounded= True;
317     else {
318     if (!facet->center)
319     facet->center= qh_facetcenter (facet->vertices);
320     qh_setappend (&points, facet->center);
321     }
322     }
323     if (numcenters > dim) {
324     simplex= qh_settemp (qh TEMPsize);
325     qh_setappend (&simplex, vertex->point);
326     if (unbounded)
327     qh_setappend (&simplex, midpoint);
328     qh_maxsimplex (dim, points, NULL, 0, &simplex);
329     qh_setdelnth (simplex, 0);
330     }else if (numcenters == dim) {
331     if (unbounded)
332     qh_setappend (&points, midpoint);
333     simplex= points;
334     }else {
335     fprintf(qh ferr, "qh_detvnorm: too few points (%d) to compute separating plane\n", numcenters);
336     qh_errexit (qh_ERRqhull, NULL, NULL);
337     }
338     i= 0;
339     gmcoord= qh gm_matrix;
340     point0= SETfirstt_(simplex, pointT);
341     FOREACHpoint_(simplex) {
342     if (qh IStracing >= 4)
343     qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint",
344     &point, 1, dim);
345     if (point != point0) {
346     qh gm_row[i++]= gmcoord;
347     coord= point0;
348     for (k= dim; k--; )
349     *(gmcoord++)= *point++ - *coord++;
350     }
351     }
352     qh gm_row[i]= gmcoord; /* does not overlap midpoint, may be used later for qh_areasimplex */
353     normal= gmcoord;
354     qh_sethyperplane_gauss (dim, qh gm_row, point0, True,
355     normal, &offset, &nearzero);
356     if (qh GOODvertexp == vertexA->point)
357     inpoint= vertexA->point;
358     else
359     inpoint= vertex->point;
360     zinc_(Zdistio);
361     dist= qh_distnorm (dim, inpoint, normal, &offset);
362     if (dist > 0) {
363     offset= -offset;
364     normalp= normal;
365     for (k= dim; k--; ) {
366     *normalp= -(*normalp);
367     normalp++;
368     }
369     }
370     if (qh VERIFYoutput || qh PRINTstatistics) {
371     pointid= qh_pointid (vertex->point);
372     pointidA= qh_pointid (vertexA->point);
373     if (!unbounded) {
374     zinc_(Zdiststat);
375     dist= qh_distnorm (dim, midpoint, normal, &offset);
376     if (dist < 0)
377     dist= -dist;
378     zzinc_(Zridgemid);
379     wwmax_(Wridgemidmax, dist);
380     wwadd_(Wridgemid, dist);
381     trace4((qh ferr, "qh_detvnorm: points %d %d midpoint dist %2.2g\n", pointid, pointidA, dist));
382     for (k= 0; k < dim; k++)
383     midpoint[k]= vertexA->point[k] - vertex->point[k]; /* overwrites midpoint! */
384     qh_normalize (midpoint, dim, False);
385     angle= qh_distnorm (dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */
386     if (angle < 0.0)
387     angle= angle + 1.0;
388     else
389     angle= angle - 1.0;
390     if (angle < 0.0)
391     angle -= angle;
392     trace4((qh ferr, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n", pointid, pointidA, angle, nearzero));
393     if (nearzero) {
394     zzinc_(Zridge0);
395     wwmax_(Wridge0max, angle);
396     wwadd_(Wridge0, angle);
397     }else {
398     zzinc_(Zridgeok)
399     wwmax_(Wridgeokmax, angle);
400     wwadd_(Wridgeok, angle);
401     }
402     }
403     if (simplex != points) {
404     FOREACHpoint_i_(points) {
405     if (!qh_setin (simplex, point)) {
406     facet= SETelemt_(centers, point_i, facetT);
407     zinc_(Zdiststat);
408     dist= qh_distnorm (dim, point, normal, &offset);
409     if (dist < 0)
410     dist= -dist;
411     zzinc_(Zridge);
412     wwmax_(Wridgemax, dist);
413     wwadd_(Wridge, dist);
414     trace4((qh ferr, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n", pointid, pointidA, facet->visitid, dist));
415     }
416     }
417     }
418     }
419     *offsetp= offset;
420     if (simplex != points)
421     qh_settempfree (&simplex);
422     qh_settempfree (&points);
423     return normal;
424     } /* detvnorm */
425    
426     /*-<a href="qh-io.htm#TOC"
427     >-------------------------------</a><a name="detvridge">-</a>
428    
429     qh_detvridge( vertexA )
430     determine Voronoi ridge from 'seen' neighbors of vertexA
431     incl. one vertex-at-infinite if an !neighbor->visitid
432    
433     returns:
434     temporary set of centers (facets, i.e., Voronoi vertices)
435     sorted by center id
436     */
437     setT *qh_detvridge (vertexT *vertex) {
438     setT *centers= qh_settemp (qh TEMPsize);
439     setT *tricenters= qh_settemp (qh TEMPsize);
440     facetT *neighbor, **neighborp;
441     boolT firstinf= True;
442    
443     FOREACHneighbor_(vertex) {
444     if (neighbor->seen) {
445     if (neighbor->visitid) {
446     if (!neighbor->tricoplanar || qh_setunique (&tricenters, neighbor->center))
447     qh_setappend (&centers, neighbor);
448     }else if (firstinf) {
449     firstinf= False;
450     qh_setappend (&centers, neighbor);
451     }
452     }
453     }
454     qsort (SETaddr_(centers, facetT), qh_setsize (centers),
455     sizeof (facetT *), qh_compare_facetvisit);
456     qh_settempfree (&tricenters);
457     return centers;
458     } /* detvridge */
459    
460     /*-<a href="qh-io.htm#TOC"
461     >-------------------------------</a><a name="detvridge3">-</a>
462    
463     qh_detvridge3( atvertex, vertex )
464     determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex
465     incl. one vertex-at-infinite for !neighbor->visitid
466     assumes all facet->seen2= True
467    
468     returns:
469     temporary set of centers (facets, i.e., Voronoi vertices)
470     listed in adjacency order (not oriented)
471     all facet->seen2= True
472    
473     design:
474     mark all neighbors of atvertex
475     for each adjacent neighbor of both atvertex and vertex
476     if neighbor selected
477     add neighbor to set of Voronoi vertices
478     */
479     setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) {
480     setT *centers= qh_settemp (qh TEMPsize);
481     setT *tricenters= qh_settemp (qh TEMPsize);
482     facetT *neighbor, **neighborp, *facet= NULL;
483     boolT firstinf= True;
484    
485     FOREACHneighbor_(atvertex)
486     neighbor->seen2= False;
487     FOREACHneighbor_(vertex) {
488     if (!neighbor->seen2) {
489     facet= neighbor;
490     break;
491     }
492     }
493     while (facet) {
494     facet->seen2= True;
495     if (neighbor->seen) {
496     if (facet->visitid) {
497     if (!facet->tricoplanar || qh_setunique (&tricenters, facet->center))
498     qh_setappend (&centers, facet);
499     }else if (firstinf) {
500     firstinf= False;
501     qh_setappend (&centers, facet);
502     }
503     }
504     FOREACHneighbor_(facet) {
505     if (!neighbor->seen2) {
506     if (qh_setin (vertex->neighbors, neighbor))
507     break;
508     else
509     neighbor->seen2= True;
510     }
511     }
512     facet= neighbor;
513     }
514     if (qh CHECKfrequently) {
515     FOREACHneighbor_(vertex) {
516     if (!neighbor->seen2) {
517     fprintf (stderr, "qh_detvridge3: neigbors of vertex p%d are not connected at facet %d\n",
518     qh_pointid (vertex->point), neighbor->id);
519     qh_errexit (qh_ERRqhull, neighbor, NULL);
520     }
521     }
522     }
523     FOREACHneighbor_(atvertex)
524     neighbor->seen2= True;
525     qh_settempfree (&tricenters);
526     return centers;
527     } /* detvridge3 */
528    
529     /*-<a href="qh-io.htm#TOC"
530     >-------------------------------</a><a name="eachvoronoi">-</a>
531    
532     qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder )
533     if visitall,
534     visit all Voronoi ridges for vertex (i.e., an input site)
535     else
536     visit all unvisited Voronoi ridges for vertex
537     all vertex->seen= False if unvisited
538     assumes
539     all facet->seen= False
540     all facet->seen2= True (for qh_detvridge3)
541     all facet->visitid == 0 if vertex_at_infinity
542     == index of Voronoi vertex
543     >= qh.num_facets if ignored
544     innerouter:
545     qh_RIDGEall-- both inner (bounded) and outer (unbounded) ridges
546     qh_RIDGEinner- only inner
547     qh_RIDGEouter- only outer
548    
549     if inorder
550     orders vertices for 3-d Voronoi diagrams
551    
552     returns:
553     number of visited ridges (does not include previously visited ridges)
554    
555     if printvridge,
556     calls printvridge( fp, vertex, vertexA, centers)
557     fp== any pointer (assumes FILE*)
558     vertex,vertexA= pair of input sites that define a Voronoi ridge
559     centers= set of facets (i.e., Voronoi vertices)
560     ->visitid == index or 0 if vertex_at_infinity
561     ordered for 3-d Voronoi diagram
562     notes:
563     uses qh.vertex_visit
564    
565     see:
566     qh_eachvoronoi_all()
567    
568     design:
569     mark selected neighbors of atvertex
570     for each selected neighbor (either Voronoi vertex or vertex-at-infinity)
571     for each unvisited vertex
572     if atvertex and vertex share more than d-1 neighbors
573     bump totalcount
574     if printvridge defined
575     build the set of shared neighbors (i.e., Voronoi vertices)
576     call printvridge
577     */
578     int qh_eachvoronoi (FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) {
579     boolT unbounded;
580     int count;
581     facetT *neighbor, **neighborp, *neighborA, **neighborAp;
582     setT *centers;
583     setT *tricenters= qh_settemp (qh TEMPsize);
584    
585     vertexT *vertex, **vertexp;
586     boolT firstinf;
587     unsigned int numfacets= (unsigned int)qh num_facets;
588     int totridges= 0;
589    
590     qh vertex_visit++;
591     atvertex->seen= True;
592     if (visitall) {
593     FORALLvertices
594     vertex->seen= False;
595     }
596     FOREACHneighbor_(atvertex) {
597     if (neighbor->visitid < numfacets)
598     neighbor->seen= True;
599     }
600     FOREACHneighbor_(atvertex) {
601     if (neighbor->seen) {
602     FOREACHvertex_(neighbor->vertices) {
603     if (vertex->visitid != qh vertex_visit && !vertex->seen) {
604     vertex->visitid= qh vertex_visit;
605     count= 0;
606     firstinf= True;
607     qh_settruncate (tricenters, 0);
608     FOREACHneighborA_(vertex) {
609     if (neighborA->seen) {
610     if (neighborA->visitid) {
611     if (!neighborA->tricoplanar || qh_setunique (&tricenters, neighborA->center))
612     count++;
613     }else if (firstinf) {
614     count++;
615     firstinf= False;
616     }
617     }
618     }
619     if (count >= qh hull_dim - 1) { /* e.g., 3 for 3-d Voronoi */
620     if (firstinf) {
621     if (innerouter == qh_RIDGEouter)
622     continue;
623     unbounded= False;
624     }else {
625     if (innerouter == qh_RIDGEinner)
626     continue;
627     unbounded= True;
628     }
629     totridges++;
630     trace4((qh ferr, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n", count, qh_pointid (atvertex->point), qh_pointid (vertex->point)));
631     if (printvridge) {
632     if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */
633     centers= qh_detvridge3 (atvertex, vertex);
634     else
635     centers= qh_detvridge (vertex);
636     (*printvridge) (fp, atvertex, vertex, centers, unbounded);
637     qh_settempfree (&centers);
638     }
639     }
640     }
641     }
642     }
643     }
644     FOREACHneighbor_(atvertex)
645     neighbor->seen= False;
646     qh_settempfree (&tricenters);
647     return totridges;
648     } /* eachvoronoi */
649    
650    
651     /*-<a href="qh-poly.htm#TOC"
652     >-------------------------------</a><a name="eachvoronoi_all">-</a>
653    
654     qh_eachvoronoi_all( fp, printvridge, isupper, innerouter, inorder )
655     visit all Voronoi ridges
656    
657     innerouter:
658     see qh_eachvoronoi()
659    
660     if inorder
661     orders vertices for 3-d Voronoi diagrams
662    
663     returns
664     total number of ridges
665    
666     if isupper == facet->upperdelaunay (i.e., a Vornoi vertex)
667     facet->visitid= Voronoi vertex index (same as 'o' format)
668     else
669     facet->visitid= 0
670    
671     if printvridge,
672     calls printvridge( fp, vertex, vertexA, centers)
673     [see qh_eachvoronoi]
674    
675     notes:
676     Not used for qhull.exe
677     same effect as qh_printvdiagram but ridges not sorted by point id
678     */
679     int qh_eachvoronoi_all (FILE *fp, printvridgeT printvridge, boolT isupper, qh_RIDGE innerouter, boolT inorder) {
680     facetT *facet;
681     vertexT *vertex;
682     int numcenters= 1; /* vertex 0 is vertex-at-infinity */
683     int totridges= 0;
684    
685     qh_clearcenters (qh_ASvoronoi);
686     qh_vertexneighbors();
687     maximize_(qh visit_id, (unsigned) qh num_facets);
688     FORALLfacets {
689     facet->visitid= 0;
690     facet->seen= False;
691     facet->seen2= True;
692     }
693     FORALLfacets {
694     if (facet->upperdelaunay == isupper)
695     facet->visitid= numcenters++;
696     }
697     FORALLvertices
698     vertex->seen= False;
699     FORALLvertices {
700     if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
701     continue;
702     totridges += qh_eachvoronoi (fp, printvridge, vertex,
703     !qh_ALL, innerouter, inorder);
704     }
705     return totridges;
706     } /* eachvoronoi_all */
707    
708     /*-<a href="qh-io.htm#TOC"
709     >-------------------------------</a><a name="facet2point">-</a>
710    
711     qh_facet2point( facet, point0, point1, mindist )
712     return two projected temporary vertices for a 2-d facet
713     may be non-simplicial
714    
715     returns:
716     point0 and point1 oriented and projected to the facet
717     returns mindist (maximum distance below plane)
718     */
719     void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) {
720     vertexT *vertex0, *vertex1;
721     realT dist;
722    
723     if (facet->toporient ^ qh_ORIENTclock) {
724     vertex0= SETfirstt_(facet->vertices, vertexT);
725     vertex1= SETsecondt_(facet->vertices, vertexT);
726     }else {
727     vertex1= SETfirstt_(facet->vertices, vertexT);
728     vertex0= SETsecondt_(facet->vertices, vertexT);
729     }
730     zadd_(Zdistio, 2);
731     qh_distplane(vertex0->point, facet, &dist);
732     *mindist= dist;
733     *point0= qh_projectpoint(vertex0->point, facet, dist);
734     qh_distplane(vertex1->point, facet, &dist);
735     minimize_(*mindist, dist);
736     *point1= qh_projectpoint(vertex1->point, facet, dist);
737     } /* facet2point */
738    
739    
740     /*-<a href="qh-io.htm#TOC"
741     >-------------------------------</a><a name="facetvertices">-</a>
742    
743     qh_facetvertices( facetlist, facets, allfacets )
744     returns temporary set of vertices in a set and/or list of facets
745     if allfacets, ignores qh_skipfacet()
746    
747     returns:
748     vertices with qh.vertex_visit
749    
750     notes:
751     optimized for allfacets of facet_list
752    
753     design:
754     if allfacets of facet_list
755     create vertex set from vertex_list
756     else
757     for each selected facet in facets or facetlist
758     append unvisited vertices to vertex set
759     */
760     setT *qh_facetvertices (facetT *facetlist, setT *facets, boolT allfacets) {
761     setT *vertices;
762     facetT *facet, **facetp;
763     vertexT *vertex, **vertexp;
764    
765     qh vertex_visit++;
766     if (facetlist == qh facet_list && allfacets && !facets) {
767     vertices= qh_settemp (qh num_vertices);
768     FORALLvertices {
769     vertex->visitid= qh vertex_visit;
770     qh_setappend (&vertices, vertex);
771     }
772     }else {
773     vertices= qh_settemp (qh TEMPsize);
774     FORALLfacet_(facetlist) {
775     if (!allfacets && qh_skipfacet (facet))
776     continue;
777     FOREACHvertex_(facet->vertices) {
778     if (vertex->visitid != qh vertex_visit) {
779     vertex->visitid= qh vertex_visit;
780     qh_setappend (&vertices, vertex);
781     }
782     }
783     }
784     }
785     FOREACHfacet_(facets) {
786     if (!allfacets && qh_skipfacet (facet))
787     continue;
788     FOREACHvertex_(facet->vertices) {
789     if (vertex->visitid != qh vertex_visit) {
790     vertex->visitid= qh vertex_visit;
791     qh_setappend (&vertices, vertex);
792     }
793     }
794     }
795     return vertices;
796     } /* facetvertices */
797    
798     /*-<a href="qh-geom.htm#TOC"
799     >-------------------------------</a><a name="geomplanes">-</a>
800    
801     qh_geomplanes( facet, outerplane, innerplane )
802     return outer and inner planes for Geomview
803     qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax)
804    
805     notes:
806     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
807     */
808     void qh_geomplanes (facetT *facet, realT *outerplane, realT *innerplane) {
809     realT radius;
810    
811     if (qh MERGING || qh JOGGLEmax < REALmax/2) {
812     qh_outerinner (facet, outerplane, innerplane);
813     radius= qh PRINTradius;
814     if (qh JOGGLEmax < REALmax/2)
815     radius -= qh JOGGLEmax * sqrt (qh hull_dim); /* already accounted for in qh_outerinner() */
816     *outerplane += radius;
817     *innerplane -= radius;
818     if (qh PRINTcoplanar || qh PRINTspheres) {
819     *outerplane += qh MAXabs_coord * qh_GEOMepsilon;
820     *innerplane -= qh MAXabs_coord * qh_GEOMepsilon;
821     }
822     }else
823     *innerplane= *outerplane= 0;
824     } /* geomplanes */
825    
826    
827     /*-<a href="qh-io.htm#TOC"
828     >-------------------------------</a><a name="markkeep">-</a>
829    
830     qh_markkeep( facetlist )
831     mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea
832     ignores visible facets (not part of convex hull)
833    
834     returns:
835     may clear facet->good
836     recomputes qh.num_good
837    
838     design:
839     get set of good facets
840     if qh.KEEParea
841     sort facets by area
842     clear facet->good for all but n largest facets
843     if qh.KEEPmerge
844     sort facets by merge count
845     clear facet->good for all but n most merged facets
846     if qh.KEEPminarea
847     clear facet->good if area too small
848     update qh.num_good
849     */
850     void qh_markkeep (facetT *facetlist) {
851     facetT *facet, **facetp;
852     setT *facets= qh_settemp (qh num_facets);
853     int size, count;
854    
855     trace2((qh ferr, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n", qh KEEParea, qh KEEPmerge, qh KEEPminArea));
856     FORALLfacet_(facetlist) {
857     if (!facet->visible && facet->good)
858     qh_setappend (&facets, facet);
859     }
860     size= qh_setsize (facets);
861     if (qh KEEParea) {
862     qsort (SETaddr_(facets, facetT), size,
863     sizeof (facetT *), qh_compare_facetarea);
864     if ((count= size - qh KEEParea) > 0) {
865     FOREACHfacet_(facets) {
866     facet->good= False;
867     if (--count == 0)
868     break;
869     }
870     }
871     }
872     if (qh KEEPmerge) {
873     qsort (SETaddr_(facets, facetT), size,
874     sizeof (facetT *), qh_compare_facetmerge);
875     if ((count= size - qh KEEPmerge) > 0) {
876     FOREACHfacet_(facets) {
877     facet->good= False;
878     if (--count == 0)
879     break;
880     }
881     }
882     }
883     if (qh KEEPminArea < REALmax/2) {
884     FOREACHfacet_(facets) {
885     if (!facet->isarea || facet->f.area < qh KEEPminArea)
886     facet->good= False;
887     }
888     }
889     qh_settempfree (&facets);
890     count= 0;
891     FORALLfacet_(facetlist) {
892     if (facet->good)
893     count++;
894     }
895     qh num_good= count;
896     } /* markkeep */
897    
898    
899     /*-<a href="qh-io.htm#TOC"
900     >-------------------------------</a><a name="markvoronoi">-</a>
901    
902     qh_markvoronoi( facetlist, facets, printall, islower, numcenters )
903     mark voronoi vertices for printing by site pairs
904    
905     returns:
906     temporary set of vertices indexed by pointid
907     islower set if printing lower hull (i.e., at least one facet is lower hull)
908     numcenters= total number of Voronoi vertices
909     bumps qh.printoutnum for vertex-at-infinity
910     clears all facet->seen and sets facet->seen2
911    
912     if selected
913     facet->visitid= Voronoi vertex id
914     else if upper hull (or 'Qu' and lower hull)
915     facet->visitid= 0
916     else
917     facet->visitid >= qh num_facets
918    
919     notes:
920     ignores qh.ATinfinity, if defined
921     */
922     setT *qh_markvoronoi (facetT *facetlist, setT *facets, boolT printall, boolT *islowerp, int *numcentersp) {
923     int numcenters=0;
924     facetT *facet, **facetp;
925     setT *vertices;
926     boolT islower= False;
927    
928     qh printoutnum++;
929     qh_clearcenters (qh_ASvoronoi); /* in case, qh_printvdiagram2 called by user */
930     qh_vertexneighbors();
931     vertices= qh_pointvertex();
932     if (qh ATinfinity)
933     SETelem_(vertices, qh num_points-1)= NULL;
934     qh visit_id++;
935     maximize_(qh visit_id, (unsigned) qh num_facets);
936     FORALLfacet_(facetlist) {
937     if (printall || !qh_skipfacet (facet)) {
938     if (!facet->upperdelaunay) {
939     islower= True;
940     break;
941     }
942     }
943     }
944     FOREACHfacet_(facets) {
945     if (printall || !qh_skipfacet (facet)) {
946     if (!facet->upperdelaunay) {
947     islower= True;
948     break;
949     }
950     }
951     }
952     FORALLfacets {
953     if (facet->normal && (facet->upperdelaunay == islower))
954     facet->visitid= 0; /* facetlist or facets may overwrite */
955     else
956     facet->visitid= qh visit_id;
957     facet->seen= False;
958     facet->seen2= True;
959     }
960     numcenters++; /* qh_INFINITE */
961     FORALLfacet_(facetlist) {
962     if (printall || !qh_skipfacet (facet))
963     facet->visitid= numcenters++;
964     }
965     FOREACHfacet_(facets) {
966     if (printall || !qh_skipfacet (facet))
967     facet->visitid= numcenters++;
968     }
969     *islowerp= islower;
970     *numcentersp= numcenters;
971     trace2((qh ferr, "qh_markvoronoi: islower %d numcenters %d\n", islower, numcenters));
972     return vertices;
973     } /* markvoronoi */
974    
975     /*-<a href="qh-io.htm#TOC"
976     >-------------------------------</a><a name="order_vertexneighbors">-</a>
977    
978     qh_order_vertexneighbors( vertex )
979     order facet neighbors of a 2-d or 3-d vertex by adjacency
980    
981     notes:
982     does not orient the neighbors
983    
984     design:
985     initialize a new neighbor set with the first facet in vertex->neighbors
986     while vertex->neighbors non-empty
987     select next neighbor in the previous facet's neighbor set
988     set vertex->neighbors to the new neighbor set
989     */
990     void qh_order_vertexneighbors(vertexT *vertex) {
991     setT *newset;
992     facetT *facet, *neighbor, **neighborp;
993    
994     trace4((qh ferr, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id));
995     newset= qh_settemp (qh_setsize (vertex->neighbors));
996     facet= (facetT*)qh_setdellast (vertex->neighbors);
997     qh_setappend (&newset, facet);
998     while (qh_setsize (vertex->neighbors)) {
999     FOREACHneighbor_(vertex) {
1000     if (qh_setin (facet->neighbors, neighbor)) {
1001     qh_setdel(vertex->neighbors, neighbor);
1002     qh_setappend (&newset, neighbor);
1003     facet= neighbor;
1004     break;
1005     }
1006     }
1007     if (!neighbor) {
1008     fprintf (qh ferr, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n",
1009     vertex->id, facet->id);
1010     qh_errexit (qh_ERRqhull, facet, NULL);
1011     }
1012     }
1013     qh_setfree (&vertex->neighbors);
1014     qh_settemppop ();
1015     vertex->neighbors= newset;
1016     } /* order_vertexneighbors */
1017    
1018     /*-<a href="qh-io.htm#TOC"
1019     >-------------------------------</a><a name="printafacet">-</a>
1020    
1021     qh_printafacet( fp, format, facet, printall )
1022     print facet to fp in given output format (see qh.PRINTout)
1023    
1024     returns:
1025     nop if !printall and qh_skipfacet()
1026     nop if visible facet and NEWfacets and format != PRINTfacets
1027     must match qh_countfacets
1028    
1029     notes
1030     preserves qh.visit_id
1031     facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge
1032    
1033     see
1034     qh_printbegin() and qh_printend()
1035    
1036     design:
1037     test for printing facet
1038     call appropriate routine for format
1039     or output results directly
1040     */
1041     void qh_printafacet(FILE *fp, int format, facetT *facet, boolT printall) {
1042     realT color[4], offset, dist, outerplane, innerplane;
1043     boolT zerodiv;
1044     coordT *point, *normp, *coordp, **pointp, *feasiblep;
1045     int k;
1046     vertexT *vertex, **vertexp;
1047     facetT *neighbor, **neighborp;
1048    
1049     if (!printall && qh_skipfacet (facet))
1050     return;
1051     if (facet->visible && qh NEWfacets && format != qh_PRINTfacets)
1052     return;
1053     qh printoutnum++;
1054     switch (format) {
1055     case qh_PRINTarea:
1056     if (facet->isarea) {
1057     fprintf (fp, qh_REAL_1, facet->f.area);
1058     fprintf (fp, "\n");
1059     }else
1060     fprintf (fp, "0\n");
1061     break;
1062     case qh_PRINTcoplanars:
1063     fprintf (fp, "%d", qh_setsize (facet->coplanarset));
1064     FOREACHpoint_(facet->coplanarset)
1065     fprintf (fp, " %d", qh_pointid (point));
1066     fprintf (fp, "\n");
1067     break;
1068     case qh_PRINTcentrums:
1069     qh_printcenter (fp, format, NULL, facet);
1070     break;
1071     case qh_PRINTfacets:
1072     qh_printfacet (fp, facet);
1073     break;
1074     case qh_PRINTfacets_xridge:
1075     qh_printfacetheader (fp, facet);
1076     break;
1077     case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */
1078     if (!facet->normal)
1079     break;
1080     for (k= qh hull_dim; k--; ) {
1081     color[k]= (facet->normal[k]+1.0)/2.0;
1082     maximize_(color[k], -1.0);
1083     minimize_(color[k], +1.0);
1084     }
1085     qh_projectdim3 (color, color);
1086     if (qh PRINTdim != qh hull_dim)
1087     qh_normalize2 (color, 3, True, NULL, NULL);
1088     if (qh hull_dim <= 2)
1089     qh_printfacet2geom (fp, facet, color);
1090     else if (qh hull_dim == 3) {
1091     if (facet->simplicial)
1092     qh_printfacet3geom_simplicial (fp, facet, color);
1093     else
1094     qh_printfacet3geom_nonsimplicial (fp, facet, color);
1095     }else {
1096     if (facet->simplicial)
1097     qh_printfacet4geom_simplicial (fp, facet, color);
1098     else
1099     qh_printfacet4geom_nonsimplicial (fp, facet, color);
1100     }
1101     break;
1102     case qh_PRINTids:
1103     fprintf (fp, "%d\n", facet->id);
1104     break;
1105     case qh_PRINTincidences:
1106     case qh_PRINToff:
1107     case qh_PRINTtriangles:
1108     if (qh hull_dim == 3 && format != qh_PRINTtriangles)
1109     qh_printfacet3vertex (fp, facet, format);
1110     else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff)
1111     qh_printfacetNvertex_simplicial (fp, facet, format);
1112     else
1113     qh_printfacetNvertex_nonsimplicial (fp, facet, qh printoutvar++, format);
1114     break;
1115     case qh_PRINTinner:
1116     qh_outerinner (facet, NULL, &innerplane);
1117     offset= facet->offset - innerplane;
1118     goto LABELprintnorm;
1119     break; /* prevent warning */
1120     case qh_PRINTmerges:
1121     fprintf (fp, "%d\n", facet->nummerge);
1122     break;
1123     case qh_PRINTnormals:
1124     offset= facet->offset;
1125     goto LABELprintnorm;
1126     break; /* prevent warning */
1127     case qh_PRINTouter:
1128     qh_outerinner (facet, &outerplane, NULL);
1129     offset= facet->offset - outerplane;
1130     LABELprintnorm:
1131     if (!facet->normal) {
1132     fprintf (fp, "no normal for facet f%d\n", facet->id);
1133     break;
1134     }
1135     if (qh CDDoutput) {
1136     fprintf (fp, qh_REAL_1, -offset);
1137     for (k=0; k < qh hull_dim; k++)
1138     fprintf (fp, qh_REAL_1, -facet->normal[k]);
1139     }else {
1140     for (k=0; k < qh hull_dim; k++)
1141     fprintf (fp, qh_REAL_1, facet->normal[k]);
1142     fprintf (fp, qh_REAL_1, offset);
1143     }
1144     fprintf (fp, "\n");
1145     break;
1146     case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */
1147     case qh_PRINTmaple:
1148     if (qh hull_dim == 2)
1149     qh_printfacet2math (fp, facet, format, qh printoutvar++);
1150     else
1151     qh_printfacet3math (fp, facet, format, qh printoutvar++);
1152     break;
1153     case qh_PRINTneighbors:
1154     fprintf (fp, "%d", qh_setsize (facet->neighbors));
1155     FOREACHneighbor_(facet)
1156     fprintf (fp, " %d",
1157     neighbor->visitid ? neighbor->visitid - 1: - neighbor->id);
1158     fprintf (fp, "\n");
1159     break;
1160     case qh_PRINTpointintersect:
1161     if (!qh feasible_point) {
1162     fprintf (fp, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n");
1163     qh_errexit( qh_ERRinput, NULL, NULL);
1164     }
1165     if (facet->offset > 0)
1166     goto LABELprintinfinite;
1167     point= coordp= (coordT*)qh_memalloc (qh normal_size);
1168     normp= facet->normal;
1169     feasiblep= qh feasible_point;
1170     if (facet->offset < -qh MINdenom) {
1171     for (k= qh hull_dim; k--; )
1172     *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++);
1173     }else {
1174     for (k= qh hull_dim; k--; ) {
1175     *(coordp++)= qh_divzero (*(normp++), facet->offset, qh MINdenom_1,
1176     &zerodiv) + *(feasiblep++);
1177     if (zerodiv) {
1178     qh_memfree (point, qh normal_size);
1179     goto LABELprintinfinite;
1180     }
1181     }
1182     }
1183     qh_printpoint (fp, NULL, point);
1184     qh_memfree (point, qh normal_size);
1185     break;
1186     LABELprintinfinite:
1187     for (k= qh hull_dim; k--; )
1188     fprintf (fp, qh_REAL_1, qh_INFINITE);
1189     fprintf (fp, "\n");
1190     break;
1191     case qh_PRINTpointnearest:
1192     FOREACHpoint_(facet->coplanarset) {
1193     int id, id2;
1194     vertex= qh_nearvertex (facet, point, &dist);
1195     id= qh_pointid (vertex->point);
1196     id2= qh_pointid (point);
1197     fprintf (fp, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist);
1198     }
1199     break;
1200     case qh_PRINTpoints: /* VORONOI only by qh_printbegin */
1201     if (qh CDDoutput)
1202     fprintf (fp, "1 ");
1203     qh_printcenter (fp, format, NULL, facet);
1204     break;
1205     case qh_PRINTvertices:
1206     fprintf (fp, "%d", qh_setsize (facet->vertices));
1207     FOREACHvertex_(facet->vertices)
1208     fprintf (fp, " %d", qh_pointid (vertex->point));
1209     fprintf (fp, "\n");
1210     break;
1211     }
1212     } /* printafacet */
1213    
1214     /*-<a href="qh-io.htm#TOC"
1215     >-------------------------------</a><a name="printbegin">-</a>
1216    
1217     qh_printbegin( )
1218     prints header for all output formats
1219    
1220     returns:
1221     checks for valid format
1222    
1223     notes:
1224     uses qh.visit_id for 3/4off
1225     changes qh.interior_point if printing centrums
1226     qh_countfacets clears facet->visitid for non-good facets
1227    
1228     see
1229     qh_printend() and qh_printafacet()
1230    
1231     design:
1232     count facets and related statistics
1233     print header for format
1234     */
1235     void qh_printbegin (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
1236     int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
1237     int i, num;
1238     facetT *facet, **facetp;
1239     vertexT *vertex, **vertexp;
1240     setT *vertices;
1241     pointT *point, **pointp, *pointtemp;
1242    
1243     qh printoutnum= 0;
1244     qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
1245     &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
1246     switch (format) {
1247     case qh_PRINTnone:
1248     break;
1249     case qh_PRINTarea:
1250     fprintf (fp, "%d\n", numfacets);
1251     break;
1252     case qh_PRINTcoplanars:
1253     fprintf (fp, "%d\n", numfacets);
1254     break;
1255     case qh_PRINTcentrums:
1256     if (qh CENTERtype == qh_ASnone)
1257     qh_clearcenters (qh_AScentrum);
1258     fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
1259     break;
1260     case qh_PRINTfacets:
1261     case qh_PRINTfacets_xridge:
1262     if (facetlist)
1263     qh_printvertexlist (fp, "Vertices and facets:\n", facetlist, facets, printall);
1264     break;
1265     case qh_PRINTgeom:
1266     if (qh hull_dim > 4) /* qh_initqhull_globals also checks */
1267     goto LABELnoformat;
1268     if (qh VORONOI && qh hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */
1269     goto LABELnoformat;
1270     if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections))
1271     fprintf (qh ferr, "qhull warning: output for ridges and intersections not implemented in 2-d\n");
1272     if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter ||
1273     (qh PRINTdim == 4 && qh PRINTcentrums)))
1274     fprintf (qh ferr, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n");
1275     if (qh PRINTdim == 4 && (qh PRINTspheres))
1276     fprintf (qh ferr, "qhull warning: output for vertices not implemented in 4-d\n");
1277     if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes)
1278     fprintf (qh ferr, "qhull warning: 'Gnh' generates no output in 4-d\n");
1279     if (qh PRINTdim == 2) {
1280     fprintf(fp, "{appearance {linewidth 3} LIST # %s | %s\n",
1281     qh rbox_command, qh qhull_command);
1282     }else if (qh PRINTdim == 3) {
1283     fprintf(fp, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n",
1284     qh rbox_command, qh qhull_command);
1285     }else if (qh PRINTdim == 4) {
1286     qh visit_id++;
1287     num= 0;
1288     FORALLfacet_(facetlist) /* get number of ridges to be printed */
1289     qh_printend4geom (NULL, facet, &num, printall);
1290     FOREACHfacet_(facets)
1291     qh_printend4geom (NULL, facet, &num, printall);
1292     qh ridgeoutnum= num;
1293     qh printoutvar= 0; /* counts number of ridges in output */
1294     fprintf (fp, "LIST # %s | %s\n", qh rbox_command, qh qhull_command);
1295     }
1296     if (qh PRINTdots) {
1297     qh printoutnum++;
1298     num= qh num_points + qh_setsize (qh other_points);
1299     if (qh DELAUNAY && qh ATinfinity)
1300     num--;
1301     if (qh PRINTdim == 4)
1302     fprintf (fp, "4VECT %d %d 1\n", num, num);
1303     else
1304     fprintf (fp, "VECT %d %d 1\n", num, num);
1305     for (i= num; i--; ) {
1306     if (i % 20 == 0)
1307     fprintf (fp, "\n");
1308     fprintf (fp, "1 ");
1309     }
1310     fprintf (fp, "# 1 point per line\n1 ");
1311     for (i= num-1; i--; ) {
1312     if (i % 20 == 0)
1313     fprintf (fp, "\n");
1314     fprintf (fp, "0 ");
1315     }
1316     fprintf (fp, "# 1 color for all\n");
1317     FORALLpoints {
1318     if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) {
1319     if (qh PRINTdim == 4)
1320     qh_printpoint (fp, NULL, point);
1321     else
1322     qh_printpoint3 (fp, point);
1323     }
1324     }
1325     FOREACHpoint_(qh other_points) {
1326     if (qh PRINTdim == 4)
1327     qh_printpoint (fp, NULL, point);
1328     else
1329     qh_printpoint3 (fp, point);
1330     }
1331     fprintf (fp, "0 1 1 1 # color of points\n");
1332     }
1333     if (qh PRINTdim == 4 && !qh PRINTnoplanes)
1334     /* 4dview loads up multiple 4OFF objects slowly */
1335     fprintf(fp, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum);
1336     qh PRINTcradius= 2 * qh DISTround; /* include test DISTround */
1337     if (qh PREmerge) {
1338     maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround);
1339     }else if (qh POSTmerge)
1340     maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround);
1341     qh PRINTradius= qh PRINTcradius;
1342     if (qh PRINTspheres + qh PRINTcoplanar)
1343     maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius);
1344     if (qh premerge_cos < REALmax/2) {
1345     maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord);
1346     }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) {
1347     maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord);
1348     }
1349     maximize_(qh PRINTradius, qh MINvisible);
1350     if (qh JOGGLEmax < REALmax/2)
1351     qh PRINTradius += qh JOGGLEmax * sqrt (qh hull_dim);
1352     if (qh PRINTdim != 4 &&
1353     (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
1354     vertices= qh_facetvertices (facetlist, facets, printall);
1355     if (qh PRINTspheres && qh PRINTdim <= 3)
1356     qh_printspheres (fp, vertices, qh PRINTradius);
1357     if (qh PRINTcoplanar || qh PRINTcentrums) {
1358     qh firstcentrum= True;
1359     if (qh PRINTcoplanar&& !qh PRINTspheres) {
1360     FOREACHvertex_(vertices)
1361     qh_printpointvect2 (fp, vertex->point, NULL,
1362     qh interior_point, qh PRINTradius);
1363     }
1364     FORALLfacet_(facetlist) {
1365     if (!printall && qh_skipfacet(facet))
1366     continue;
1367     if (!facet->normal)
1368     continue;
1369     if (qh PRINTcentrums && qh PRINTdim <= 3)
1370     qh_printcentrum (fp, facet, qh PRINTcradius);
1371     if (!qh PRINTcoplanar)
1372     continue;
1373     FOREACHpoint_(facet->coplanarset)
1374     qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1375     FOREACHpoint_(facet->outsideset)
1376     qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1377     }
1378     FOREACHfacet_(facets) {
1379     if (!printall && qh_skipfacet(facet))
1380     continue;
1381     if (!facet->normal)
1382     continue;
1383     if (qh PRINTcentrums && qh PRINTdim <= 3)
1384     qh_printcentrum (fp, facet, qh PRINTcradius);
1385     if (!qh PRINTcoplanar)
1386     continue;
1387     FOREACHpoint_(facet->coplanarset)
1388     qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1389     FOREACHpoint_(facet->outsideset)
1390     qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius);
1391     }
1392     }
1393     qh_settempfree (&vertices);
1394     }
1395     qh visit_id++; /* for printing hyperplane intersections */
1396     break;
1397     case qh_PRINTids:
1398     fprintf (fp, "%d\n", numfacets);
1399     break;
1400     case qh_PRINTincidences:
1401     if (qh VORONOI && qh PRINTprecision)
1402     fprintf (qh ferr, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n");
1403     qh printoutvar= qh vertex_id; /* centrum id for non-simplicial facets */
1404     if (qh hull_dim <= 3)
1405     fprintf(fp, "%d\n", numfacets);
1406     else
1407     fprintf(fp, "%d\n", numsimplicial+numridges);
1408     break;
1409     case qh_PRINTinner:
1410     case qh_PRINTnormals:
1411     case qh_PRINTouter:
1412     if (qh CDDoutput)
1413     fprintf (fp, "%s | %s\nbegin\n %d %d real\n", qh rbox_command,
1414     qh qhull_command, numfacets, qh hull_dim+1);
1415     else
1416     fprintf (fp, "%d\n%d\n", qh hull_dim+1, numfacets);
1417     break;
1418     case qh_PRINTmathematica:
1419     case qh_PRINTmaple:
1420     if (qh hull_dim > 3) /* qh_initbuffers also checks */
1421     goto LABELnoformat;
1422     if (qh VORONOI)
1423     fprintf (qh ferr, "qhull warning: output is the Delaunay triangulation\n");
1424     if (format == qh_PRINTmaple) {
1425     if (qh hull_dim == 2)
1426     fprintf(fp, "PLOT(CURVES(\n");
1427     else
1428     fprintf(fp, "PLOT3D(POLYGONS(\n");
1429     }else
1430     fprintf(fp, "{\n");
1431     qh printoutvar= 0; /* counts number of facets for notfirst */
1432     break;
1433     case qh_PRINTmerges:
1434     fprintf (fp, "%d\n", numfacets);
1435     break;
1436     case qh_PRINTpointintersect:
1437     fprintf (fp, "%d\n%d\n", qh hull_dim, numfacets);
1438     break;
1439     case qh_PRINTneighbors:
1440     fprintf (fp, "%d\n", numfacets);
1441     break;
1442     case qh_PRINToff:
1443     case qh_PRINTtriangles:
1444     if (qh VORONOI)
1445     goto LABELnoformat;
1446     num = qh hull_dim;
1447     if (format == qh_PRINToff || qh hull_dim == 2)
1448     fprintf (fp, "%d\n%d %d %d\n", num,
1449     qh num_points+qh_setsize (qh other_points), numfacets, totneighbors/2);
1450     else { /* qh_PRINTtriangles */
1451     qh printoutvar= qh num_points+qh_setsize (qh other_points); /* first centrum */
1452     if (qh DELAUNAY)
1453     num--; /* drop last dimension */
1454     fprintf (fp, "%d\n%d %d %d\n", num, qh printoutvar
1455     + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2);
1456     }
1457     FORALLpoints
1458     qh_printpointid (qh fout, NULL, num, point, -1);
1459     FOREACHpoint_(qh other_points)
1460     qh_printpointid (qh fout, NULL, num, point, -1);
1461     if (format == qh_PRINTtriangles && qh hull_dim > 2) {
1462     FORALLfacets {
1463     if (!facet->simplicial && facet->visitid)
1464     qh_printcenter (qh fout, format, NULL, facet);
1465     }
1466     }
1467     break;
1468     case qh_PRINTpointnearest:
1469     fprintf (fp, "%d\n", numcoplanars);
1470     break;
1471     case qh_PRINTpoints:
1472     if (!qh VORONOI)
1473     goto LABELnoformat;
1474     if (qh CDDoutput)
1475     fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
1476     qh qhull_command, numfacets, qh hull_dim);
1477     else
1478     fprintf (fp, "%d\n%d\n", qh hull_dim-1, numfacets);
1479     break;
1480     case qh_PRINTvertices:
1481     fprintf (fp, "%d\n", numfacets);
1482     break;
1483     case qh_PRINTsummary:
1484     default:
1485     LABELnoformat:
1486     fprintf (qh ferr, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n",
1487     qh hull_dim);
1488     qh_errexit (qh_ERRqhull, NULL, NULL);
1489     }
1490     } /* printbegin */
1491    
1492     /*-<a href="qh-io.htm#TOC"
1493     >-------------------------------</a><a name="printcenter">-</a>
1494    
1495     qh_printcenter( fp, string, facet )
1496     print facet->center as centrum or Voronoi center
1497     string may be NULL. Don't include '%' codes.
1498     nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum
1499     if upper envelope of Delaunay triangulation and point at-infinity
1500     prints qh_INFINITE instead;
1501    
1502     notes:
1503     defines facet->center if needed
1504     if format=PRINTgeom, adds a 0 if would otherwise be 2-d
1505     */
1506     void qh_printcenter (FILE *fp, int format, char *string, facetT *facet) {
1507     int k, num;
1508    
1509     if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum)
1510     return;
1511     if (string)
1512     fprintf (fp, string, facet->id);
1513     if (qh CENTERtype == qh_ASvoronoi) {
1514     num= qh hull_dim-1;
1515     if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) {
1516     if (!facet->center)
1517     facet->center= qh_facetcenter (facet->vertices);
1518     for (k=0; k < num; k++)
1519     fprintf (fp, qh_REAL_1, facet->center[k]);
1520     }else {
1521     for (k=0; k < num; k++)
1522     fprintf (fp, qh_REAL_1, qh_INFINITE);
1523     }
1524     }else /* qh CENTERtype == qh_AScentrum */ {
1525     num= qh hull_dim;
1526     if (format == qh_PRINTtriangles && qh DELAUNAY)
1527     num--;
1528     if (!facet->center)
1529     facet->center= qh_getcentrum (facet);
1530     for (k=0; k < num; k++)
1531     fprintf (fp, qh_REAL_1, facet->center[k]);
1532     }
1533     if (format == qh_PRINTgeom && num == 2)
1534     fprintf (fp, " 0\n");
1535     else
1536     fprintf (fp, "\n");
1537     } /* printcenter */
1538    
1539     /*-<a href="qh-io.htm#TOC"
1540     >-------------------------------</a><a name="printcentrum">-</a>
1541    
1542     qh_printcentrum( fp, facet, radius )
1543     print centrum for a facet in OOGL format
1544     radius defines size of centrum
1545     2-d or 3-d only
1546    
1547     returns:
1548     defines facet->center if needed
1549     */
1550     void qh_printcentrum (FILE *fp, facetT *facet, realT radius) {
1551     pointT *centrum, *projpt;
1552     boolT tempcentrum= False;
1553     realT xaxis[4], yaxis[4], normal[4], dist;
1554     realT green[3]={0, 1, 0};
1555     vertexT *apex;
1556     int k;
1557    
1558     if (qh CENTERtype == qh_AScentrum) {
1559     if (!facet->center)
1560     facet->center= qh_getcentrum (facet);
1561     centrum= facet->center;
1562     }else {
1563     centrum= qh_getcentrum (facet);
1564     tempcentrum= True;
1565     }
1566     fprintf (fp, "{appearance {-normal -edge normscale 0} ");
1567     if (qh firstcentrum) {
1568     qh firstcentrum= False;
1569     fprintf (fp, "{INST geom { define centrum CQUAD # f%d\n\
1570     -0.3 -0.3 0.0001 0 0 1 1\n\
1571     0.3 -0.3 0.0001 0 0 1 1\n\
1572     0.3 0.3 0.0001 0 0 1 1\n\
1573     -0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id);
1574     }else
1575     fprintf (fp, "{INST geom { : centrum } transform { # f%d\n", facet->id);
1576     apex= SETfirstt_(facet->vertices, vertexT);
1577     qh_distplane(apex->point, facet, &dist);
1578     projpt= qh_projectpoint(apex->point, facet, dist);
1579     for (k= qh hull_dim; k--; ) {
1580     xaxis[k]= projpt[k] - centrum[k];
1581     normal[k]= facet->normal[k];
1582     }
1583     if (qh hull_dim == 2) {
1584     xaxis[2]= 0;
1585     normal[2]= 0;
1586     }else if (qh hull_dim == 4) {
1587     qh_projectdim3 (xaxis, xaxis);
1588     qh_projectdim3 (normal, normal);
1589     qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL);
1590     }
1591     qh_crossproduct (3, xaxis, normal, yaxis);
1592     fprintf (fp, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]);
1593     fprintf (fp, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]);
1594     fprintf (fp, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]);
1595     qh_printpoint3 (fp, centrum);
1596     fprintf (fp, "1 }}}\n");
1597     qh_memfree (projpt, qh normal_size);
1598     qh_printpointvect (fp, centrum, facet->normal, NULL, radius, green);
1599     if (tempcentrum)
1600     qh_memfree (centrum, qh normal_size);
1601     } /* printcentrum */
1602    
1603     /*-<a href="qh-io.htm#TOC"
1604     >-------------------------------</a><a name="printend">-</a>
1605    
1606     qh_printend( fp, format )
1607     prints trailer for all output formats
1608    
1609     see:
1610     qh_printbegin() and qh_printafacet()
1611    
1612     */
1613     void qh_printend (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
1614     int num;
1615     facetT *facet, **facetp;
1616    
1617     if (!qh printoutnum)
1618     fprintf (qh ferr, "qhull warning: no facets printed\n");
1619     switch (format) {
1620     case qh_PRINTgeom:
1621     if (qh hull_dim == 4 && qh DROPdim < 0 && !qh PRINTnoplanes) {
1622     qh visit_id++;
1623     num= 0;
1624     FORALLfacet_(facetlist)
1625     qh_printend4geom (fp, facet,&num, printall);
1626     FOREACHfacet_(facets)
1627     qh_printend4geom (fp, facet, &num, printall);
1628     if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) {
1629     fprintf (qh ferr, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num);
1630     qh_errexit (qh_ERRqhull, NULL, NULL);
1631     }
1632     }else
1633     fprintf(fp, "}\n");
1634     break;
1635     case qh_PRINTinner:
1636     case qh_PRINTnormals:
1637     case qh_PRINTouter:
1638     if (qh CDDoutput)
1639     fprintf (fp, "end\n");
1640     break;
1641     case qh_PRINTmaple:
1642     fprintf(fp, "));\n");
1643     break;
1644     case qh_PRINTmathematica:
1645     fprintf(fp, "}\n");
1646     break;
1647     case qh_PRINTpoints:
1648     if (qh CDDoutput)
1649     fprintf (fp, "end\n");
1650     break;
1651     }
1652     } /* printend */
1653    
1654     /*-<a href="qh-io.htm#TOC"
1655     >-------------------------------</a><a name="printend4geom">-</a>
1656    
1657     qh_printend4geom( fp, facet, numridges, printall )
1658     helper function for qh_printbegin/printend
1659    
1660     returns:
1661     number of printed ridges
1662    
1663     notes:
1664     just counts printed ridges if fp=NULL
1665     uses facet->visitid
1666     must agree with qh_printfacet4geom...
1667    
1668     design:
1669     computes color for facet from its normal
1670     prints each ridge of facet
1671     */
1672     void qh_printend4geom (FILE *fp, facetT *facet, int *nump, boolT printall) {
1673     realT color[3];
1674     int i, num= *nump;
1675     facetT *neighbor, **neighborp;
1676     ridgeT *ridge, **ridgep;
1677    
1678     if (!printall && qh_skipfacet(facet))
1679     return;
1680     if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
1681     return;
1682     if (!facet->normal)
1683     return;
1684     if (fp) {
1685     for (i=0; i < 3; i++) {
1686     color[i]= (facet->normal[i]+1.0)/2.0;
1687     maximize_(color[i], -1.0);
1688     minimize_(color[i], +1.0);
1689     }
1690     }
1691     facet->visitid= qh visit_id;
1692     if (facet->simplicial) {
1693     FOREACHneighbor_(facet) {
1694     if (neighbor->visitid != qh visit_id) {
1695     if (fp)
1696     fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n",
1697     3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
1698     facet->id, neighbor->id);
1699     num++;
1700     }
1701     }
1702     }else {
1703     FOREACHridge_(facet->ridges) {
1704     neighbor= otherfacet_(ridge, facet);
1705     if (neighbor->visitid != qh visit_id) {
1706     if (fp)
1707     fprintf (fp, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n",
1708     3*num, 3*num+1, 3*num+2, color[0], color[1], color[2],
1709     ridge->id, facet->id, neighbor->id);
1710     num++;
1711     }
1712     }
1713     }
1714     *nump= num;
1715     } /* printend4geom */
1716    
1717     /*-<a href="qh-io.htm#TOC"
1718     >-------------------------------</a><a name="printextremes">-</a>
1719    
1720     qh_printextremes( fp, facetlist, facets, printall )
1721     print extreme points for convex hulls or halfspace intersections
1722    
1723     notes:
1724     #points, followed by ids, one per line
1725    
1726     sorted by id
1727     same order as qh_printpoints_out if no coplanar/interior points
1728     */
1729     void qh_printextremes (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1730     setT *vertices, *points;
1731     pointT *point;
1732     vertexT *vertex, **vertexp;
1733     int id;
1734     int numpoints=0, point_i, point_n;
1735     int allpoints= qh num_points + qh_setsize (qh other_points);
1736    
1737     points= qh_settemp (allpoints);
1738     qh_setzero (points, 0, allpoints);
1739     vertices= qh_facetvertices (facetlist, facets, printall);
1740     FOREACHvertex_(vertices) {
1741     id= qh_pointid (vertex->point);
1742     if (id >= 0) {
1743     SETelem_(points, id)= vertex->point;
1744     numpoints++;
1745     }
1746     }
1747     qh_settempfree (&vertices);
1748     fprintf (fp, "%d\n", numpoints);
1749     FOREACHpoint_i_(points) {
1750     if (point)
1751     fprintf (fp, "%d\n", point_i);
1752     }
1753     qh_settempfree (&points);
1754     } /* printextremes */
1755    
1756     /*-<a href="qh-io.htm#TOC"
1757     >-------------------------------</a><a name="printextremes_2d">-</a>
1758    
1759     qh_printextremes_2d( fp, facetlist, facets, printall )
1760     prints point ids for facets in qh_ORIENTclock order
1761    
1762     notes:
1763     #points, followed by ids, one per line
1764     if facetlist/facets are disjoint than the output includes skips
1765     errors if facets form a loop
1766     does not print coplanar points
1767     */
1768     void qh_printextremes_2d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1769     int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars;
1770     setT *vertices;
1771     facetT *facet, *startfacet, *nextfacet;
1772     vertexT *vertexA, *vertexB;
1773    
1774     qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
1775     &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */
1776     vertices= qh_facetvertices (facetlist, facets, printall);
1777     fprintf(fp, "%d\n", qh_setsize (vertices));
1778     qh_settempfree (&vertices);
1779     if (!numfacets)
1780     return;
1781     facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT);
1782     qh vertex_visit++;
1783     qh visit_id++;
1784     do {
1785     if (facet->toporient ^ qh_ORIENTclock) {
1786     vertexA= SETfirstt_(facet->vertices, vertexT);
1787     vertexB= SETsecondt_(facet->vertices, vertexT);
1788     nextfacet= SETfirstt_(facet->neighbors, facetT);
1789     }else {
1790     vertexA= SETsecondt_(facet->vertices, vertexT);
1791     vertexB= SETfirstt_(facet->vertices, vertexT);
1792     nextfacet= SETsecondt_(facet->neighbors, facetT);
1793     }
1794     if (facet->visitid == qh visit_id) {
1795     fprintf(qh ferr, "qh_printextremes_2d: loop in facet list. facet %d nextfacet %d\n",
1796     facet->id, nextfacet->id);
1797     qh_errexit2 (qh_ERRqhull, facet, nextfacet);
1798     }
1799     if (facet->visitid) {
1800     if (vertexA->visitid != qh vertex_visit) {
1801     vertexA->visitid= qh vertex_visit;
1802     fprintf(fp, "%d\n", qh_pointid (vertexA->point));
1803     }
1804     if (vertexB->visitid != qh vertex_visit) {
1805     vertexB->visitid= qh vertex_visit;
1806     fprintf(fp, "%d\n", qh_pointid (vertexB->point));
1807     }
1808     }
1809     facet->visitid= qh visit_id;
1810     facet= nextfacet;
1811     }while (facet && facet != startfacet);
1812     } /* printextremes_2d */
1813    
1814     /*-<a href="qh-io.htm#TOC"
1815     >-------------------------------</a><a name="printextremes_d">-</a>
1816    
1817     qh_printextremes_d( fp, facetlist, facets, printall )
1818     print extreme points of input sites for Delaunay triangulations
1819    
1820     notes:
1821     #points, followed by ids, one per line
1822    
1823     unordered
1824     */
1825     void qh_printextremes_d (FILE *fp, facetT *facetlist, setT *facets, int printall) {
1826     setT *vertices;
1827     vertexT *vertex, **vertexp;
1828     boolT upperseen, lowerseen;
1829     facetT *neighbor, **neighborp;
1830     int numpoints=0;
1831    
1832     vertices= qh_facetvertices (facetlist, facets, printall);
1833     qh_vertexneighbors();
1834     FOREACHvertex_(vertices) {
1835     upperseen= lowerseen= False;
1836     FOREACHneighbor_(vertex) {
1837     if (neighbor->upperdelaunay)
1838     upperseen= True;
1839     else
1840     lowerseen= True;
1841     }
1842     if (upperseen && lowerseen) {
1843     vertex->seen= True;
1844     numpoints++;
1845     }else
1846     vertex->seen= False;
1847     }
1848     fprintf (fp, "%d\n", numpoints);
1849     FOREACHvertex_(vertices) {
1850     if (vertex->seen)
1851     fprintf (fp, "%d\n", qh_pointid (vertex->point));
1852     }
1853     qh_settempfree (&vertices);
1854     } /* printextremes_d */
1855    
1856     /*-<a href="qh-io.htm#TOC"
1857     >-------------------------------</a><a name="printfacet">-</a>
1858    
1859     qh_printfacet( fp, facet )
1860     prints all fields of a facet to fp
1861    
1862     notes:
1863     ridges printed in neighbor order
1864     */
1865     void qh_printfacet(FILE *fp, facetT *facet) {
1866    
1867     qh_printfacetheader (fp, facet);
1868     if (facet->ridges)
1869     qh_printfacetridges (fp, facet);
1870     } /* printfacet */
1871    
1872    
1873     /*-<a href="qh-io.htm#TOC"
1874     >-------------------------------</a><a name="printfacet2geom">-</a>
1875    
1876     qh_printfacet2geom( fp, facet, color )
1877     print facet as part of a 2-d VECT for Geomview
1878    
1879     notes:
1880     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
1881     mindist is calculated within io.c. maxoutside is calculated elsewhere
1882     so a DISTround error may have occured.
1883     */
1884     void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) {
1885     pointT *point0, *point1;
1886     realT mindist, innerplane, outerplane;
1887     int k;
1888    
1889     qh_facet2point (facet, &point0, &point1, &mindist);
1890     qh_geomplanes (facet, &outerplane, &innerplane);
1891     if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
1892     qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color);
1893     if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
1894     outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
1895     for(k= 3; k--; )
1896     color[k]= 1.0 - color[k];
1897     qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color);
1898     }
1899     qh_memfree (point1, qh normal_size);
1900     qh_memfree (point0, qh normal_size);
1901     } /* printfacet2geom */
1902    
1903     /*-<a href="qh-io.htm#TOC"
1904     >-------------------------------</a><a name="printfacet2geom_points">-</a>
1905    
1906     qh_printfacet2geom_points( fp, point1, point2, facet, offset, color )
1907     prints a 2-d facet as a VECT with 2 points at some offset.
1908     The points are on the facet's plane.
1909     */
1910     void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2,
1911     facetT *facet, realT offset, realT color[3]) {
1912     pointT *p1= point1, *p2= point2;
1913    
1914     fprintf(fp, "VECT 1 2 1 2 1 # f%d\n", facet->id);
1915     if (offset != 0.0) {
1916     p1= qh_projectpoint (p1, facet, -offset);
1917     p2= qh_projectpoint (p2, facet, -offset);
1918     }
1919     fprintf(fp, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n",
1920     p1[0], p1[1], 0.0, p2[0], p2[1], 0.0);
1921     if (offset != 0.0) {
1922     qh_memfree (p1, qh normal_size);
1923     qh_memfree (p2, qh normal_size);
1924     }
1925     fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
1926     } /* printfacet2geom_points */
1927    
1928    
1929     /*-<a href="qh-io.htm#TOC"
1930     >-------------------------------</a><a name="printfacet2math">-</a>
1931    
1932     qh_printfacet2math( fp, facet, format, notfirst )
1933     print 2-d Maple or Mathematica output for a facet
1934     may be non-simplicial
1935    
1936     notes:
1937     please use %16.8f since Mathematica 2.2 does not handle exponential format
1938     see qh_printfacet3math
1939     */
1940     void qh_printfacet2math(FILE *fp, facetT *facet, int format, int notfirst) {
1941     pointT *point0, *point1;
1942     realT mindist;
1943     char *pointfmt;
1944    
1945     qh_facet2point (facet, &point0, &point1, &mindist);
1946     if (notfirst)
1947     fprintf(fp, ",");
1948     if (format == qh_PRINTmaple)
1949     pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n";
1950     else
1951     pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n";
1952     fprintf(fp, pointfmt, point0[0], point0[1], point1[0], point1[1]);
1953     qh_memfree (point1, qh normal_size);
1954     qh_memfree (point0, qh normal_size);
1955     } /* printfacet2math */
1956    
1957    
1958     /*-<a href="qh-io.htm#TOC"
1959     >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a>
1960    
1961     qh_printfacet3geom_nonsimplicial( fp, facet, color )
1962     print Geomview OFF for a 3-d nonsimplicial facet.
1963     if DOintersections, prints ridges to unvisited neighbors (qh visit_id)
1964    
1965     notes
1966     uses facet->visitid for intersections and ridges
1967     */
1968     void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
1969     ridgeT *ridge, **ridgep;
1970     setT *projectedpoints, *vertices;
1971     vertexT *vertex, **vertexp, *vertexA, *vertexB;
1972     pointT *projpt, *point, **pointp;
1973     facetT *neighbor;
1974     realT dist, outerplane, innerplane;
1975     int cntvertices, k;
1976     realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
1977    
1978     qh_geomplanes (facet, &outerplane, &innerplane);
1979     vertices= qh_facet3vertex (facet); /* oriented */
1980     cntvertices= qh_setsize(vertices);
1981     projectedpoints= qh_settemp(cntvertices);
1982     FOREACHvertex_(vertices) {
1983     zinc_(Zdistio);
1984     qh_distplane(vertex->point, facet, &dist);
1985     projpt= qh_projectpoint(vertex->point, facet, dist);
1986     qh_setappend (&projectedpoints, projpt);
1987     }
1988     if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
1989     qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color);
1990     if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
1991     outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
1992     for (k=3; k--; )
1993     color[k]= 1.0 - color[k];
1994     qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color);
1995     }
1996     FOREACHpoint_(projectedpoints)
1997     qh_memfree (point, qh normal_size);
1998     qh_settempfree(&projectedpoints);
1999     qh_settempfree(&vertices);
2000     if ((qh DOintersections || qh PRINTridges)
2001     && (!facet->visible || !qh NEWfacets)) {
2002     facet->visitid= qh visit_id;
2003     FOREACHridge_(facet->ridges) {
2004     neighbor= otherfacet_(ridge, facet);
2005     if (neighbor->visitid != qh visit_id) {
2006     if (qh DOintersections)
2007     qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black);
2008     if (qh PRINTridges) {
2009     vertexA= SETfirstt_(ridge->vertices, vertexT);
2010     vertexB= SETsecondt_(ridge->vertices, vertexT);
2011     qh_printline3geom (fp, vertexA->point, vertexB->point, green);
2012     }
2013     }
2014     }
2015     }
2016     } /* printfacet3geom_nonsimplicial */
2017    
2018     /*-<a href="qh-io.htm#TOC"
2019     >-------------------------------</a><a name="printfacet3geom_points">-</a>
2020    
2021     qh_printfacet3geom_points( fp, points, facet, offset )
2022     prints a 3-d facet as OFF Geomview object.
2023     offset is relative to the facet's hyperplane
2024     Facet is determined as a list of points
2025     */
2026     void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) {
2027     int k, n= qh_setsize(points), i;
2028     pointT *point, **pointp;
2029     setT *printpoints;
2030    
2031     fprintf(fp, "{ OFF %d 1 1 # f%d\n", n, facet->id);
2032     if (offset != 0.0) {
2033     printpoints= qh_settemp (n);
2034     FOREACHpoint_(points)
2035     qh_setappend (&printpoints, qh_projectpoint(point, facet, -offset));
2036     }else
2037     printpoints= points;
2038     FOREACHpoint_(printpoints) {
2039     for (k=0; k < qh hull_dim; k++) {
2040     if (k == qh DROPdim)
2041     fprintf(fp, "0 ");
2042     else
2043     fprintf(fp, "%8.4g ", point[k]);
2044     }
2045     if (printpoints != points)
2046     qh_memfree (point, qh normal_size);
2047     fprintf (fp, "\n");
2048     }
2049     if (printpoints != points)
2050     qh_settempfree (&printpoints);
2051     fprintf(fp, "%d ", n);
2052     for(i= 0; i < n; i++)
2053     fprintf(fp, "%d ", i);
2054     fprintf(fp, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]);
2055     } /* printfacet3geom_points */
2056    
2057    
2058     /*-<a href="qh-io.htm#TOC"
2059     >-------------------------------</a><a name="printfacet3geom_simplicial">-</a>
2060    
2061     qh_printfacet3geom_simplicial( )
2062     print Geomview OFF for a 3-d simplicial facet.
2063    
2064     notes:
2065     may flip color
2066     uses facet->visitid for intersections and ridges
2067    
2068     assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon
2069     innerplane may be off by qh DISTround. Maxoutside is calculated elsewhere
2070     so a DISTround error may have occured.
2071     */
2072     void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
2073     setT *points, *vertices;
2074     vertexT *vertex, **vertexp, *vertexA, *vertexB;
2075     facetT *neighbor, **neighborp;
2076     realT outerplane, innerplane;
2077     realT black[3]={0, 0, 0}, green[3]={0, 1, 0};
2078     int k;
2079    
2080     qh_geomplanes (facet, &outerplane, &innerplane);
2081     vertices= qh_facet3vertex (facet);
2082     points= qh_settemp (qh TEMPsize);
2083     FOREACHvertex_(vertices)
2084     qh_setappend(&points, vertex->point);
2085     if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner))
2086     qh_printfacet3geom_points(fp, points, facet, outerplane, color);
2087     if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter &&
2088     outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) {
2089     for (k= 3; k--; )
2090     color[k]= 1.0 - color[k];
2091     qh_printfacet3geom_points(fp, points, facet, innerplane, color);
2092     }
2093     qh_settempfree(&points);
2094     qh_settempfree(&vertices);
2095     if ((qh DOintersections || qh PRINTridges)
2096     && (!facet->visible || !qh NEWfacets)) {
2097     facet->visitid= qh visit_id;
2098     FOREACHneighbor_(facet) {
2099     if (neighbor->visitid != qh visit_id) {
2100     vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
2101     SETindex_(facet->neighbors, neighbor), 0);
2102     if (qh DOintersections)
2103     qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black);
2104     if (qh PRINTridges) {
2105     vertexA= SETfirstt_(vertices, vertexT);
2106     vertexB= SETsecondt_(vertices, vertexT);
2107     qh_printline3geom (fp, vertexA->point, vertexB->point, green);
2108     }
2109     qh_setfree(&vertices);
2110     }
2111     }
2112     }
2113     } /* printfacet3geom_simplicial */
2114    
2115     /*-<a href="qh-io.htm#TOC"
2116     >-------------------------------</a><a name="printfacet3math">-</a>
2117    
2118     qh_printfacet3math( fp, facet, notfirst )
2119     print 3-d Maple or Mathematica output for a facet
2120    
2121     notes:
2122     may be non-simplicial
2123     please use %16.8f since Mathematica 2.2 does not handle exponential format
2124     see qh_printfacet2math
2125     */
2126     void qh_printfacet3math (FILE *fp, facetT *facet, int format, int notfirst) {
2127     vertexT *vertex, **vertexp;
2128     setT *points, *vertices;
2129     pointT *point, **pointp;
2130     boolT firstpoint= True;
2131     realT dist;
2132     char *pointfmt, *endfmt;
2133    
2134     if (notfirst)
2135     fprintf(fp, ",\n");
2136     vertices= qh_facet3vertex (facet);
2137     points= qh_settemp (qh_setsize (vertices));
2138     FOREACHvertex_(vertices) {
2139     zinc_(Zdistio);
2140     qh_distplane(vertex->point, facet, &dist);
2141     point= qh_projectpoint(vertex->point, facet, dist);
2142     qh_setappend (&points, point);
2143     }
2144     if (format == qh_PRINTmaple) {
2145     fprintf(fp, "[");
2146     pointfmt= "[%16.8f, %16.8f, %16.8f]";
2147     endfmt= "]";
2148     }else {
2149     fprintf(fp, "Polygon[{");
2150     pointfmt= "{%16.8f, %16.8f, %16.8f}";
2151     endfmt= "}]";
2152     }
2153     FOREACHpoint_(points) {
2154     if (firstpoint)
2155     firstpoint= False;
2156     else
2157     fprintf(fp, ",\n");
2158     fprintf(fp, pointfmt, point[0], point[1], point[2]);
2159     }
2160     FOREACHpoint_(points)
2161     qh_memfree (point, qh normal_size);
2162     qh_settempfree(&points);
2163     qh_settempfree(&vertices);
2164     fprintf(fp, endfmt);
2165     } /* printfacet3math */
2166    
2167    
2168     /*-<a href="qh-io.htm#TOC"
2169     >-------------------------------</a><a name="printfacet3vertex">-</a>
2170    
2171     qh_printfacet3vertex( fp, facet, format )
2172     print vertices in a 3-d facet as point ids
2173    
2174     notes:
2175     prints number of vertices first if format == qh_PRINToff
2176     the facet may be non-simplicial
2177     */
2178     void qh_printfacet3vertex(FILE *fp, facetT *facet, int format) {
2179     vertexT *vertex, **vertexp;
2180     setT *vertices;
2181    
2182     vertices= qh_facet3vertex (facet);
2183     if (format == qh_PRINToff)
2184     fprintf (fp, "%d ", qh_setsize (vertices));
2185     FOREACHvertex_(vertices)
2186     fprintf (fp, "%d ", qh_pointid(vertex->point));
2187     fprintf (fp, "\n");
2188     qh_settempfree(&vertices);
2189     } /* printfacet3vertex */
2190    
2191    
2192     /*-<a href="qh-io.htm#TOC"
2193     >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a>
2194    
2195     qh_printfacet4geom_nonsimplicial( )
2196     print Geomview 4OFF file for a 4d nonsimplicial facet
2197     prints all ridges to unvisited neighbors (qh.visit_id)
2198     if qh.DROPdim
2199     prints in OFF format
2200    
2201     notes:
2202     must agree with printend4geom()
2203     */
2204     void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) {
2205     facetT *neighbor;
2206     ridgeT *ridge, **ridgep;
2207     vertexT *vertex, **vertexp;
2208     pointT *point;
2209     int k;
2210     realT dist;
2211    
2212     facet->visitid= qh visit_id;
2213     if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
2214     return;
2215     FOREACHridge_(facet->ridges) {
2216     neighbor= otherfacet_(ridge, facet);
2217     if (neighbor->visitid == qh visit_id)
2218     continue;
2219     if (qh PRINTtransparent && !neighbor->good)
2220     continue;
2221     if (qh DOintersections)
2222     qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color);
2223     else {
2224     if (qh DROPdim >= 0)
2225     fprintf(fp, "OFF 3 1 1 # f%d\n", facet->id);
2226     else {
2227     qh printoutvar++;
2228     fprintf (fp, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id);
2229     }
2230     FOREACHvertex_(ridge->vertices) {
2231     zinc_(Zdistio);
2232     qh_distplane(vertex->point,facet, &dist);
2233     point=qh_projectpoint(vertex->point,facet, dist);
2234     for(k= 0; k < qh hull_dim; k++) {
2235     if (k != qh DROPdim)
2236     fprintf(fp, "%8.4g ", point[k]);
2237     }
2238     fprintf (fp, "\n");
2239     qh_memfree (point, qh normal_size);
2240     }
2241     if (qh DROPdim >= 0)
2242     fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
2243     }
2244     }
2245     } /* printfacet4geom_nonsimplicial */
2246    
2247    
2248     /*-<a href="qh-io.htm#TOC"
2249     >-------------------------------</a><a name="printfacet4geom_simplicial">-</a>
2250    
2251     qh_printfacet4geom_simplicial( fp, facet, color )
2252     print Geomview 4OFF file for a 4d simplicial facet
2253     prints triangles for unvisited neighbors (qh.visit_id)
2254    
2255     notes:
2256     must agree with printend4geom()
2257     */
2258     void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) {
2259     setT *vertices;
2260     facetT *neighbor, **neighborp;
2261     vertexT *vertex, **vertexp;
2262     int k;
2263    
2264     facet->visitid= qh visit_id;
2265     if (qh PRINTnoplanes || (facet->visible && qh NEWfacets))
2266     return;
2267     FOREACHneighbor_(facet) {
2268     if (neighbor->visitid == qh visit_id)
2269     continue;
2270     if (qh PRINTtransparent && !neighbor->good)
2271     continue;
2272     vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
2273     SETindex_(facet->neighbors, neighbor), 0);
2274     if (qh DOintersections)
2275     qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color);
2276     else {
2277     if (qh DROPdim >= 0)
2278     fprintf(fp, "OFF 3 1 1 # ridge between f%d f%d\n",
2279     facet->id, neighbor->id);
2280     else {
2281     qh printoutvar++;
2282     fprintf (fp, "# ridge between f%d f%d\n", facet->id, neighbor->id);
2283     }
2284     FOREACHvertex_(vertices) {
2285     for(k= 0; k < qh hull_dim; k++) {
2286     if (k != qh DROPdim)
2287     fprintf(fp, "%8.4g ", vertex->point[k]);
2288     }
2289     fprintf (fp, "\n");
2290     }
2291     if (qh DROPdim >= 0)
2292     fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]);
2293     }
2294     qh_setfree(&vertices);
2295     }
2296     } /* printfacet4geom_simplicial */
2297    
2298    
2299     /*-<a href="qh-io.htm#TOC"
2300     >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a>
2301    
2302     qh_printfacetNvertex_nonsimplicial( fp, facet, id, format )
2303     print vertices for an N-d non-simplicial facet
2304     triangulates each ridge to the id
2305     */
2306     void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, int format) {
2307     vertexT *vertex, **vertexp;
2308     ridgeT *ridge, **ridgep;
2309    
2310     if (facet->visible && qh NEWfacets)
2311     return;
2312     FOREACHridge_(facet->ridges) {
2313     if (format == qh_PRINTtriangles)
2314     fprintf(fp, "%d ", qh hull_dim);
2315     fprintf(fp, "%d ", id);
2316     if ((ridge->top == facet) ^ qh_ORIENTclock) {
2317     FOREACHvertex_(ridge->vertices)
2318     fprintf(fp, "%d ", qh_pointid(vertex->point));
2319     }else {
2320     FOREACHvertexreverse12_(ridge->vertices)
2321     fprintf(fp, "%d ", qh_pointid(vertex->point));
2322     }
2323     fprintf(fp, "\n");
2324     }
2325     } /* printfacetNvertex_nonsimplicial */
2326    
2327    
2328     /*-<a href="qh-io.htm#TOC"
2329     >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a>
2330    
2331     qh_printfacetNvertex_simplicial( fp, facet, format )
2332     print vertices for an N-d simplicial facet
2333     prints vertices for non-simplicial facets
2334     2-d facets (orientation preserved by qh_mergefacet2d)
2335     PRINToff ('o') for 4-d and higher
2336     */
2337     void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, int format) {
2338     vertexT *vertex, **vertexp;
2339    
2340     if (format == qh_PRINToff || format == qh_PRINTtriangles)
2341     fprintf (fp, "%d ", qh_setsize (facet->vertices));
2342     if ((facet->toporient ^ qh_ORIENTclock)
2343     || (qh hull_dim > 2 && !facet->simplicial)) {
2344     FOREACHvertex_(facet->vertices)
2345     fprintf(fp, "%d ", qh_pointid(vertex->point));
2346     }else {
2347     FOREACHvertexreverse12_(facet->vertices)
2348     fprintf(fp, "%d ", qh_pointid(vertex->point));
2349     }
2350     fprintf(fp, "\n");
2351     } /* printfacetNvertex_simplicial */
2352    
2353    
2354     /*-<a href="qh-io.htm#TOC"
2355     >-------------------------------</a><a name="printfacetheader">-</a>
2356    
2357     qh_printfacetheader( fp, facet )
2358     prints header fields of a facet to fp
2359    
2360     notes:
2361     for 'f' output and debugging
2362     */
2363     void qh_printfacetheader(FILE *fp, facetT *facet) {
2364     pointT *point, **pointp, *furthest;
2365     facetT *neighbor, **neighborp;
2366     realT dist;
2367    
2368     if (facet == qh_MERGEridge) {
2369     fprintf (fp, " MERGEridge\n");
2370     return;
2371     }else if (facet == qh_DUPLICATEridge) {
2372     fprintf (fp, " DUPLICATEridge\n");
2373     return;
2374     }else if (!facet) {
2375     fprintf (fp, " NULLfacet\n");
2376     return;
2377     }
2378     qh old_randomdist= qh RANDOMdist;
2379     qh RANDOMdist= False;
2380     fprintf(fp, "- f%d\n", facet->id);
2381     fprintf(fp, " - flags:");
2382     if (facet->toporient)
2383     fprintf(fp, " top");
2384     else
2385     fprintf(fp, " bottom");
2386     if (facet->simplicial)
2387     fprintf(fp, " simplicial");
2388     if (facet->tricoplanar)
2389     fprintf(fp, " tricoplanar");
2390     if (facet->upperdelaunay)
2391     fprintf(fp, " upperDelaunay");
2392     if (facet->visible)
2393     fprintf(fp, " visible");
2394     if (facet->newfacet)
2395     fprintf(fp, " new");
2396     if (facet->tested)
2397     fprintf(fp, " tested");
2398     if (!facet->good)
2399     fprintf(fp, " notG");
2400     if (facet->seen)
2401     fprintf(fp, " seen");
2402     if (facet->coplanar)
2403     fprintf(fp, " coplanar");
2404     if (facet->mergehorizon)
2405     fprintf(fp, " mergehorizon");
2406     if (facet->keepcentrum)
2407     fprintf(fp, " keepcentrum");
2408     if (facet->dupridge)
2409     fprintf(fp, " dupridge");
2410     if (facet->mergeridge && !facet->mergeridge2)
2411     fprintf(fp, " mergeridge1");
2412     if (facet->mergeridge2)
2413     fprintf(fp, " mergeridge2");
2414     if (facet->newmerge)
2415     fprintf(fp, " newmerge");
2416     if (facet->flipped)
2417     fprintf(fp, " flipped");
2418     if (facet->notfurthest)
2419     fprintf(fp, " notfurthest");
2420     if (facet->degenerate)
2421     fprintf(fp, " degenerate");
2422     if (facet->redundant)
2423     fprintf(fp, " redundant");
2424     fprintf(fp, "\n");
2425     if (facet->isarea)
2426     fprintf(fp, " - area: %2.2g\n", facet->f.area);
2427     else if (qh NEWfacets && facet->visible && facet->f.replace)
2428     fprintf(fp, " - replacement: f%d\n", facet->f.replace->id);
2429     else if (facet->newfacet) {
2430     if (facet->f.samecycle && facet->f.samecycle != facet)
2431     fprintf(fp, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id);
2432     }else if (facet->tricoplanar /* !isarea */) {
2433     if (facet->f.triowner)
2434     fprintf(fp, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id);
2435     }else if (facet->f.newcycle)
2436     fprintf(fp, " - was horizon to f%d\n", facet->f.newcycle->id);
2437     if (facet->nummerge)
2438     fprintf(fp, " - merges: %d\n", facet->nummerge);
2439     qh_printpointid(fp, " - normal: ", qh hull_dim, facet->normal, -1);
2440     fprintf(fp, " - offset: %10.7g\n", facet->offset);
2441     if (qh CENTERtype == qh_ASvoronoi || facet->center)
2442     qh_printcenter (fp, qh_PRINTfacets, " - center: ", facet);
2443     #if qh_MAXoutside
2444     if (facet->maxoutside > qh DISTround)
2445     fprintf(fp, " - maxoutside: %10.7g\n", facet->maxoutside);
2446     #endif
2447     if (!SETempty_(facet->outsideset)) {
2448     furthest= (pointT*)qh_setlast(facet->outsideset);
2449     if (qh_setsize (facet->outsideset) < 6) {
2450     fprintf(fp, " - outside set (furthest p%d):\n", qh_pointid(furthest));
2451     FOREACHpoint_(facet->outsideset)
2452     qh_printpoint(fp, " ", point);
2453     }else if (qh_setsize (facet->outsideset) < 21) {
2454     qh_printpoints(fp, " - outside set:", facet->outsideset);
2455     }else {
2456     fprintf(fp, " - outside set: %d points.", qh_setsize(facet->outsideset));
2457     qh_printpoint(fp, " Furthest", furthest);
2458     }
2459     #if !qh_COMPUTEfurthest
2460     fprintf(fp, " - furthest distance= %2.2g\n", facet->furthestdist);
2461     #endif
2462     }
2463     if (!SETempty_(facet->coplanarset)) {
2464     furthest= (pointT*)qh_setlast(facet->coplanarset);
2465     if (qh_setsize (facet->coplanarset) < 6) {
2466     fprintf(fp, " - coplanar set (furthest p%d):\n", qh_pointid(furthest));
2467     FOREACHpoint_(facet->coplanarset)
2468     qh_printpoint(fp, " ", point);
2469     }else if (qh_setsize (facet->coplanarset) < 21) {
2470     qh_printpoints(fp, " - coplanar set:", facet->coplanarset);
2471     }else {
2472     fprintf(fp, " - coplanar set: %d points.", qh_setsize(facet->coplanarset));
2473     qh_printpoint(fp, " Furthest", furthest);
2474     }
2475     zinc_(Zdistio);
2476     qh_distplane (furthest, facet, &dist);
2477     fprintf(fp, " furthest distance= %2.2g\n", dist);
2478     }
2479     qh_printvertices (fp, " - vertices:", facet->vertices);
2480     fprintf(fp, " - neighboring facets: ");
2481     FOREACHneighbor_(facet) {
2482     if (neighbor == qh_MERGEridge)
2483     fprintf(fp, " MERGE");
2484     else if (neighbor == qh_DUPLICATEridge)
2485     fprintf(fp, " DUP");
2486     else
2487     fprintf(fp, " f%d", neighbor->id);
2488     }
2489     fprintf(fp, "\n");
2490     qh RANDOMdist= qh old_randomdist;
2491     } /* printfacetheader */
2492    
2493    
2494     /*-<a href="qh-io.htm#TOC"
2495     >-------------------------------</a><a name="printfacetridges">-</a>
2496    
2497     qh_printfacetridges( fp, facet )
2498     prints ridges of a facet to fp
2499    
2500     notes:
2501     ridges printed in neighbor order
2502     assumes the ridges exist
2503     for 'f' output
2504     */
2505     void qh_printfacetridges(FILE *fp, facetT *facet) {
2506     facetT *neighbor, **neighborp;
2507     ridgeT *ridge, **ridgep;
2508     int numridges= 0;
2509    
2510    
2511     if (facet->visible && qh NEWfacets) {
2512     fprintf(fp, " - ridges (ids may be garbage):");
2513     FOREACHridge_(facet->ridges)
2514     fprintf(fp, " r%d", ridge->id);
2515     fprintf(fp, "\n");
2516     }else {
2517     fprintf(fp, " - ridges:\n");
2518     FOREACHridge_(facet->ridges)
2519     ridge->seen= False;
2520     if (qh hull_dim == 3) {
2521     ridge= SETfirstt_(facet->ridges, ridgeT);
2522     while (ridge && !ridge->seen) {
2523     ridge->seen= True;
2524     qh_printridge(fp, ridge);
2525     numridges++;
2526     ridge= qh_nextridge3d (ridge, facet, NULL);
2527     }
2528     }else {
2529     FOREACHneighbor_(facet) {
2530     FOREACHridge_(facet->ridges) {
2531     if (otherfacet_(ridge,facet) == neighbor) {
2532     ridge->seen= True;
2533     qh_printridge(fp, ridge);
2534     numridges++;
2535     }
2536     }
2537     }
2538     }
2539     if (numridges != qh_setsize (facet->ridges)) {
2540     fprintf (fp, " - all ridges:");
2541     FOREACHridge_(facet->ridges)
2542     fprintf (fp, " r%d", ridge->id);
2543     fprintf (fp, "\n");
2544     }
2545     FOREACHridge_(facet->ridges) {
2546     if (!ridge->seen)
2547     qh_printridge(fp, ridge);
2548     }
2549     }
2550     } /* printfacetridges */
2551    
2552     /*-<a href="qh-io.htm#TOC"
2553     >-------------------------------</a><a name="printfacets">-</a>
2554    
2555     qh_printfacets( fp, format, facetlist, facets, printall )
2556     prints facetlist and/or facet set in output format
2557    
2558     notes:
2559     also used for specialized formats ('FO' and summary)
2560     turns off 'Rn' option since want actual numbers
2561     */
2562     void qh_printfacets(FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
2563     int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars;
2564     facetT *facet, **facetp;
2565     setT *vertices;
2566     coordT *center;
2567     realT outerplane, innerplane;
2568    
2569     qh old_randomdist= qh RANDOMdist;
2570     qh RANDOMdist= False;
2571     if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff))
2572     fprintf (qh ferr, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n");
2573     if (format == qh_PRINTnone)
2574     ; /* print nothing */
2575     else if (format == qh_PRINTaverage) {
2576     vertices= qh_facetvertices (facetlist, facets, printall);
2577     center= qh_getcenter (vertices);
2578     fprintf (fp, "%d 1\n", qh hull_dim);
2579     qh_printpointid (fp, NULL, qh hull_dim, center, -1);
2580     qh_memfree (center, qh normal_size);
2581     qh_settempfree (&vertices);
2582     }else if (format == qh_PRINTextremes) {
2583     if (qh DELAUNAY)
2584     qh_printextremes_d (fp, facetlist, facets, printall);
2585     else if (qh hull_dim == 2)
2586     qh_printextremes_2d (fp, facetlist, facets, printall);
2587     else
2588     qh_printextremes (fp, facetlist, facets, printall);
2589     }else if (format == qh_PRINToptions)
2590     fprintf(fp, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options);
2591     else if (format == qh_PRINTpoints && !qh VORONOI)
2592     qh_printpoints_out (fp, facetlist, facets, printall);
2593     else if (format == qh_PRINTqhull)
2594     fprintf (fp, "%s | %s\n", qh rbox_command, qh qhull_command);
2595     else if (format == qh_PRINTsize) {
2596     fprintf (fp, "0\n2 ");
2597     fprintf (fp, qh_REAL_1, qh totarea);
2598     fprintf (fp, qh_REAL_1, qh totvol);
2599     fprintf (fp, "\n");
2600     }else if (format == qh_PRINTsummary) {
2601     qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
2602     &totneighbors, &numridges, &numcoplanars, &numtricoplanars);
2603     vertices= qh_facetvertices (facetlist, facets, printall);
2604     fprintf (fp, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim,
2605     qh num_points + qh_setsize (qh other_points),
2606     qh num_vertices, qh num_facets - qh num_visible,
2607     qh_setsize (vertices), numfacets, numcoplanars,
2608     numfacets - numsimplicial, zzval_(Zdelvertextot),
2609     numtricoplanars);
2610     qh_settempfree (&vertices);
2611     qh_outerinner (NULL, &outerplane, &innerplane);
2612     fprintf (fp, qh_REAL_2n, outerplane, innerplane);
2613     }else if (format == qh_PRINTvneighbors)
2614     qh_printvneighbors (fp, facetlist, facets, printall);
2615     else if (qh VORONOI && format == qh_PRINToff)
2616     qh_printvoronoi (fp, format, facetlist, facets, printall);
2617     else if (qh VORONOI && format == qh_PRINTgeom) {
2618     qh_printbegin (fp, format, facetlist, facets, printall);
2619     qh_printvoronoi (fp, format, facetlist, facets, printall);
2620     qh_printend (fp, format, facetlist, facets, printall);
2621     }else if (qh VORONOI
2622     && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter))
2623     qh_printvdiagram (fp, format, facetlist, facets, printall);
2624     else {
2625     qh_printbegin (fp, format, facetlist, facets, printall);
2626     FORALLfacet_(facetlist)
2627     qh_printafacet (fp, format, facet, printall);
2628     FOREACHfacet_(facets)
2629     qh_printafacet (fp, format, facet, printall);
2630     qh_printend (fp, format, facetlist, facets, printall);
2631     }
2632     qh RANDOMdist= qh old_randomdist;
2633     } /* printfacets */
2634    
2635    
2636     /*-<a href="qh-io.htm#TOC"
2637     >-------------------------------</a><a name="printhelp_degenerate">-</a>
2638    
2639     qh_printhelp_degenerate( fp )
2640     prints descriptive message for precision error
2641    
2642     notes:
2643     no message if qh_QUICKhelp
2644     */
2645     void qh_printhelp_degenerate(FILE *fp) {
2646    
2647     if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2)
2648     fprintf(fp, "\n\
2649     A Qhull error has occurred. Qhull should have corrected the above\n\
2650     precision error. Please send the input and all of the output to\n\
2651     qhull_bug@qhull.org\n");
2652     else if (!qh_QUICKhelp) {
2653     fprintf(fp, "\n\
2654     Precision problems were detected during construction of the convex hull.\n\
2655     This occurs because convex hull algorithms assume that calculations are\n\
2656     exact, but floating-point arithmetic has roundoff errors.\n\
2657     \n\
2658     To correct for precision problems, do not use 'Q0'. By default, Qhull\n\
2659     selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\
2660     Qhull joggles the input to prevent precision problems. See \"Imprecision\n\
2661     in Qhull\" (qh-impre.htm).\n\
2662     \n\
2663     If you use 'Q0', the output may include\n\
2664     coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\
2665     Qhull may produce a ridge with four neighbors or two facets with the same \n\
2666     vertices. Qhull reports these events when they occur. It stops when a\n\
2667     concave ridge, flipped facet, or duplicate facet occurs.\n");
2668     #if REALfloat
2669     fprintf (fp, "\
2670     \n\
2671     Qhull is currently using single precision arithmetic. The following\n\
2672     will probably remove the precision problems:\n\
2673     - recompile qhull for double precision (#define REALfloat 0 in user.h).\n");
2674     #endif
2675     if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4)
2676     fprintf( fp, "\
2677     \n\
2678     When computing the Delaunay triangulation of coordinates > 1.0,\n\
2679     - please use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n");
2680     if (qh DELAUNAY && !qh ATinfinity)
2681     fprintf( fp, "\
2682     When computing the Delaunay triangulation:\n\
2683     - please use 'Qz' to add a point at-infinity. This reduces precision problems.\n");
2684    
2685     fprintf(fp, "\
2686     \n\
2687     If you need triangular output:\n\
2688     - please use option 'Qt' to triangulate the output\n\
2689     - please use option 'QJ' to joggle the input points and remove precision errors\n\
2690     - please use option 'Ft'. It triangulates non-simplicial facets with added points.\n\
2691     \n\
2692     If you must use 'Q0',\n\
2693     try one or more of the following options. They can not guarantee an output.\n\
2694     - please use 'QbB' to scale the input to a cube.\n\
2695     - please use 'Po' to produce output and prevent partitioning for flipped facets\n\
2696     - please use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\
2697     - please use 'En' to specify a maximum roundoff error less than %2.2g.\n\
2698     - options 'Qf', 'Qbb', and 'QR0' may also help\n",
2699     qh DISTround);
2700     fprintf(fp, "\
2701     \n\
2702     To guarantee simplicial output:\n\
2703     - please use option 'Qt' to triangulate the output\n\
2704     - please use option 'QJ' to joggle the input points and remove precision errors\n\
2705     - please use option 'Ft' to triangulate the output by adding points\n\
2706     - please use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\
2707     ");
2708     }
2709     } /* printhelp_degenerate */
2710    
2711    
2712     /*-<a href="qh-io.htm#TOC"
2713     >-------------------------------</a><a name="printhelp_singular">-</a>
2714    
2715     qh_printhelp_singular( fp )
2716     prints descriptive message for singular input
2717     */
2718     void qh_printhelp_singular(FILE *fp) {
2719     facetT *facet;
2720     vertexT *vertex, **vertexp;
2721     realT min, max, *coord, dist;
2722     int i,k;
2723    
2724     fprintf(fp, "\n\
2725     The input to qhull appears to be less than %d dimensional, or a\n\
2726     computation has overflowed.\n\n\
2727     Qhull could not construct a clearly convex simplex from points:\n",
2728     qh hull_dim);
2729     qh_printvertexlist (fp, "", qh facet_list, NULL, qh_ALL);
2730     if (!qh_QUICKhelp)
2731     fprintf(fp, "\n\
2732     The center point is coplanar with a facet, or a vertex is coplanar\n\
2733     with a neighboring facet. The maximum round off error for\n\
2734     computing distances is %2.2g. The center point, facets and distances\n\
2735     to the center point are as follows:\n\n", qh DISTround);
2736     qh_printpointid (fp, "center point", qh hull_dim, qh interior_point, -1);
2737     fprintf (fp, "\n");
2738     FORALLfacets {
2739     fprintf (fp, "facet");
2740     FOREACHvertex_(facet->vertices)
2741     fprintf (fp, " p%d", qh_pointid(vertex->point));
2742     zinc_(Zdistio);
2743     qh_distplane(qh interior_point, facet, &dist);
2744     fprintf (fp, " distance= %4.2g\n", dist);
2745     }
2746     if (!qh_QUICKhelp) {
2747     if (qh HALFspace)
2748     fprintf (fp, "\n\
2749     These points are the dual of the given halfspaces. They indicate that\n\
2750     the intersection is degenerate.\n");
2751     fprintf (fp,"\n\
2752     These points either have a maximum or minimum x-coordinate, or\n\
2753     they maximize the determinant for k coordinates. Trial points\n\
2754     are first selected from points that maximize a coordinate.\n");
2755     if (qh hull_dim >= qh_INITIALmax)
2756     fprintf (fp, "\n\
2757     Because of the high dimension, the min x-coordinate and max-coordinate\n\
2758     points are used if the determinant is non-zero. Option 'Qs' will\n\
2759     do a better, though much slower, job. Instead of 'Qs', you can change\n\
2760     the points by randomly rotating the input with 'QR0'.\n");
2761     }
2762     fprintf (fp, "\nThe min and max coordinates for each dimension are:\n");
2763     for (k=0; k < qh hull_dim; k++) {
2764     min= REALmax;
2765     max= -REALmin;
2766     for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) {
2767     maximize_(max, *coord);
2768     minimize_(min, *coord);
2769     }
2770     fprintf (fp, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min);
2771     }
2772     if (!qh_QUICKhelp) {
2773     fprintf (fp, "\n\
2774     If the input should be full dimensional, you have several options that\n\
2775     may determine an initial simplex:\n\
2776     - use 'QJ' to joggle the input and make it full dimensional\n\
2777     - use 'QbB' to scale the points to the unit cube\n\
2778     - use 'QR0' to randomly rotate the input for different maximum points\n\
2779     - use 'Qs' to search all points for the initial simplex\n\
2780     - use 'En' to specify a maximum roundoff error less than %2.2g.\n\
2781     - trace execution with 'T3' to see the determinant for each point.\n",
2782     qh DISTround);
2783     #if REALfloat
2784     fprintf (fp, "\
2785     - recompile qhull for double precision (#define REALfloat 0 in qhull.h).\n");
2786     #endif
2787     fprintf (fp, "\n\
2788     If the input is lower dimensional:\n\
2789     - use 'QJ' to joggle the input and make it full dimensional\n\
2790     - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\
2791     pick the coordinate with the least range. The hull will have the\n\
2792     correct topology.\n\
2793     - determine the flat containing the points, rotate the points\n\
2794     into a coordinate plane, and delete the other coordinates.\n\
2795     - add one or more points to make the input full dimensional.\n\
2796     ");
2797     if (qh DELAUNAY && !qh ATinfinity)
2798     fprintf (fp, "\n\n\
2799     This is a Delaunay triangulation and the input is co-circular or co-spherical:\n\
2800     - use 'Qz' to add a point \"at infinity\" (i.e., above the paraboloid)\n\
2801     - or use 'QJ' to joggle the input and avoid co-circular data\n");
2802     }
2803     } /* printhelp_singular */
2804    
2805     /*-<a href="qh-io.htm#TOC"
2806     >-------------------------------</a><a name="printhyperplaneintersection">-</a>
2807    
2808     qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color )
2809     print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d
2810     */
2811     void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2,
2812     setT *vertices, realT color[3]) {
2813     realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4];
2814     vertexT *vertex, **vertexp;
2815     int i, k;
2816     boolT nearzero1, nearzero2;
2817    
2818     costheta= qh_getangle(facet1->normal, facet2->normal);
2819     denominator= 1 - costheta * costheta;
2820     i= qh_setsize(vertices);
2821     if (qh hull_dim == 3)
2822     fprintf(fp, "VECT 1 %d 1 %d 1 ", i, i);
2823     else if (qh hull_dim == 4 && qh DROPdim >= 0)
2824     fprintf(fp, "OFF 3 1 1 ");
2825     else
2826     qh printoutvar++;
2827     fprintf (fp, "# intersect f%d f%d\n", facet1->id, facet2->id);
2828     mindenom= 1 / (10.0 * qh MAXabs_coord);
2829     FOREACHvertex_(vertices) {
2830     zadd_(Zdistio, 2);
2831     qh_distplane(vertex->point, facet1, &dist1);
2832     qh_distplane(vertex->point, facet2, &dist2);
2833     s= qh_divzero (-dist1 + costheta * dist2, denominator,mindenom,&nearzero1);
2834     t= qh_divzero (-dist2 + costheta * dist1, denominator,mindenom,&nearzero2);
2835     if (nearzero1 || nearzero2)
2836     s= t= 0.0;
2837     for(k= qh hull_dim; k--; )
2838     p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t;
2839     if (qh PRINTdim <= 3) {
2840     qh_projectdim3 (p, p);
2841     fprintf(fp, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]);
2842     }else
2843     fprintf(fp, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]);
2844     if (nearzero1+nearzero2)
2845     fprintf (fp, "p%d (coplanar facets)\n", qh_pointid (vertex->point));
2846     else
2847     fprintf (fp, "projected p%d\n", qh_pointid (vertex->point));
2848     }
2849     if (qh hull_dim == 3)
2850     fprintf(fp, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
2851     else if (qh hull_dim == 4 && qh DROPdim >= 0)
2852     fprintf(fp, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]);
2853     } /* printhyperplaneintersection */
2854    
2855     /*-<a href="qh-io.htm#TOC"
2856     >-------------------------------</a><a name="printline3geom">-</a>
2857    
2858     qh_printline3geom( fp, pointA, pointB, color )
2859     prints a line as a VECT
2860     prints 0's for qh.DROPdim
2861    
2862     notes:
2863     if pointA == pointB,
2864     it's a 1 point VECT
2865     */
2866     void qh_printline3geom (FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) {
2867     int k;
2868     realT pA[4], pB[4];
2869    
2870     qh_projectdim3(pointA, pA);
2871     qh_projectdim3(pointB, pB);
2872     if ((fabs(pA[0] - pB[0]) > 1e-3) ||
2873     (fabs(pA[1] - pB[1]) > 1e-3) ||
2874     (fabs(pA[2] - pB[2]) > 1e-3)) {
2875     fprintf (fp, "VECT 1 2 1 2 1\n");
2876     for (k= 0; k < 3; k++)
2877     fprintf (fp, "%8.4g ", pB[k]);
2878     fprintf (fp, " # p%d\n", qh_pointid (pointB));
2879     }else
2880     fprintf (fp, "VECT 1 1 1 1 1\n");
2881     for (k=0; k < 3; k++)
2882     fprintf (fp, "%8.4g ", pA[k]);
2883     fprintf (fp, " # p%d\n", qh_pointid (pointA));
2884     fprintf (fp, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]);
2885     }
2886    
2887     /*-<a href="qh-io.htm#TOC"
2888     >-------------------------------</a><a name="printneighborhood">-</a>
2889    
2890     qh_printneighborhood( fp, format, facetA, facetB, printall )
2891     print neighborhood of one or two facets
2892    
2893     notes:
2894     calls qh_findgood_all()
2895     bumps qh.visit_id
2896     */
2897     void qh_printneighborhood (FILE *fp, int format, facetT *facetA, facetT *facetB, boolT printall) {
2898     facetT *neighbor, **neighborp, *facet;
2899     setT *facets;
2900    
2901     if (format == qh_PRINTnone)
2902     return;
2903     qh_findgood_all (qh facet_list);
2904     if (facetA == facetB)
2905     facetB= NULL;
2906     facets= qh_settemp (2*(qh_setsize (facetA->neighbors)+1));
2907     qh visit_id++;
2908     for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) {
2909     if (facet->visitid != qh visit_id) {
2910     facet->visitid= qh visit_id;
2911     qh_setappend (&facets, facet);
2912     }
2913     FOREACHneighbor_(facet) {
2914     if (neighbor->visitid == qh visit_id)
2915     continue;
2916     neighbor->visitid= qh visit_id;
2917     if (printall || !qh_skipfacet (neighbor))
2918     qh_setappend (&facets, neighbor);
2919     }
2920     }
2921     qh_printfacets (fp, format, NULL, facets, printall);
2922     qh_settempfree (&facets);
2923     } /* printneighborhood */
2924    
2925     /*-<a href="qh-io.htm#TOC"
2926     >-------------------------------</a><a name="printpoint">-</a>
2927    
2928     qh_printpoint( fp, string, point )
2929     qh_printpointid( fp, string, dim, point, id )
2930     prints the coordinates of a point
2931    
2932     returns:
2933     if string is defined
2934     prints 'string p%d' (skips p%d if id=-1)
2935    
2936     notes:
2937     nop if point is NULL
2938     prints id unless it is undefined (-1)
2939     */
2940     void qh_printpoint(FILE *fp, char *string, pointT *point) {
2941     int id= qh_pointid( point);
2942    
2943     qh_printpointid( fp, string, qh hull_dim, point, id);
2944     } /* printpoint */
2945    
2946     void qh_printpointid(FILE *fp, char *string, int dim, pointT *point, int id) {
2947     int k;
2948     realT r; /*bug fix*/
2949    
2950     if (!point)
2951     return;
2952     if (string) {
2953     fputs (string, fp);
2954     if (id != -1)
2955     fprintf(fp, " p%d: ", id);
2956     }
2957     for(k= dim; k--; ) {
2958     r= *point++;
2959     if (string)
2960     fprintf(fp, " %8.4g", r);
2961     else
2962     fprintf(fp, qh_REAL_1, r);
2963     }
2964     fprintf(fp, "\n");
2965     } /* printpointid */
2966    
2967     /*-<a href="qh-io.htm#TOC"
2968     >-------------------------------</a><a name="printpoint3">-</a>
2969    
2970     qh_printpoint3( fp, point )
2971     prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates
2972     */
2973     void qh_printpoint3 (FILE *fp, pointT *point) {
2974     int k;
2975     realT p[4];
2976    
2977     qh_projectdim3 (point, p);
2978     for (k=0; k < 3; k++)
2979     fprintf (fp, "%8.4g ", p[k]);
2980     fprintf (fp, " # p%d\n", qh_pointid (point));
2981     } /* printpoint3 */
2982    
2983     /*----------------------------------------
2984     -printpoints- print pointids for a set of points starting at index
2985     see geom.c
2986     */
2987    
2988     /*-<a href="qh-io.htm#TOC"
2989     >-------------------------------</a><a name="printpoints_out">-</a>
2990    
2991     qh_printpoints_out( fp, facetlist, facets, printall )
2992     prints vertices, coplanar/inside points, for facets by their point coordinates
2993     allows qh.CDDoutput
2994    
2995     notes:
2996     same format as qhull input
2997     if no coplanar/interior points,
2998     same order as qh_printextremes
2999     */
3000     void qh_printpoints_out (FILE *fp, facetT *facetlist, setT *facets, int printall) {
3001     int allpoints= qh num_points + qh_setsize (qh other_points);
3002     int numpoints=0, point_i, point_n;
3003     setT *vertices, *points;
3004     facetT *facet, **facetp;
3005     pointT *point, **pointp;
3006     vertexT *vertex, **vertexp;
3007     int id;
3008    
3009     points= qh_settemp (allpoints);
3010     qh_setzero (points, 0, allpoints);
3011     vertices= qh_facetvertices (facetlist, facets, printall);
3012     FOREACHvertex_(vertices) {
3013     id= qh_pointid (vertex->point);
3014     if (id >= 0)
3015     SETelem_(points, id)= vertex->point;
3016     }
3017     if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) {
3018     FORALLfacet_(facetlist) {
3019     if (!printall && qh_skipfacet(facet))
3020     continue;
3021     FOREACHpoint_(facet->coplanarset) {
3022     id= qh_pointid (point);
3023     if (id >= 0)
3024     SETelem_(points, id)= point;
3025     }
3026     }
3027     FOREACHfacet_(facets) {
3028     if (!printall && qh_skipfacet(facet))
3029     continue;
3030     FOREACHpoint_(facet->coplanarset) {
3031     id= qh_pointid (point);
3032     if (id >= 0)
3033     SETelem_(points, id)= point;
3034     }
3035     }
3036     }
3037     qh_settempfree (&vertices);
3038     FOREACHpoint_i_(points) {
3039     if (point)
3040     numpoints++;
3041     }
3042     if (qh CDDoutput)
3043     fprintf (fp, "%s | %s\nbegin\n%d %d real\n", qh rbox_command,
3044     qh qhull_command, numpoints, qh hull_dim + 1);
3045     else
3046     fprintf (fp, "%d\n%d\n", qh hull_dim, numpoints);
3047     FOREACHpoint_i_(points) {
3048     if (point) {
3049     if (qh CDDoutput)
3050     fprintf (fp, "1 ");
3051     qh_printpoint (fp, NULL, point);
3052     }
3053     }
3054     if (qh CDDoutput)
3055     fprintf (fp, "end\n");
3056     qh_settempfree (&points);
3057     } /* printpoints_out */
3058    
3059    
3060     /*-<a href="qh-io.htm#TOC"
3061     >-------------------------------</a><a name="printpointvect">-</a>
3062    
3063     qh_printpointvect( fp, point, normal, center, radius, color )
3064     prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point
3065     */
3066     void qh_printpointvect (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) {
3067     realT diff[4], pointA[4];
3068     int k;
3069    
3070     for (k= qh hull_dim; k--; ) {
3071     if (center)
3072     diff[k]= point[k]-center[k];
3073     else if (normal)
3074     diff[k]= normal[k];
3075     else
3076     diff[k]= 0;
3077     }
3078     if (center)
3079     qh_normalize2 (diff, qh hull_dim, True, NULL, NULL);
3080     for (k= qh hull_dim; k--; )
3081     pointA[k]= point[k]+diff[k] * radius;
3082     qh_printline3geom (fp, point, pointA, color);
3083     } /* printpointvect */
3084    
3085     /*-<a href="qh-io.htm#TOC"
3086     >-------------------------------</a><a name="printpointvect2">-</a>
3087    
3088     qh_printpointvect2( fp, point, normal, center, radius )
3089     prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point
3090     */
3091     void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) {
3092     realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0};
3093    
3094     qh_printpointvect (fp, point, normal, center, radius, red);
3095     qh_printpointvect (fp, point, normal, center, -radius, yellow);
3096     } /* printpointvect2 */
3097    
3098     /*-<a href="qh-io.htm#TOC"
3099     >-------------------------------</a><a name="printridge">-</a>
3100    
3101     qh_printridge( fp, ridge )
3102     prints the information in a ridge
3103    
3104     notes:
3105     for qh_printfacetridges()
3106     */
3107     void qh_printridge(FILE *fp, ridgeT *ridge) {
3108    
3109     fprintf(fp, " - r%d", ridge->id);
3110     if (ridge->tested)
3111     fprintf (fp, " tested");
3112     if (ridge->nonconvex)
3113     fprintf (fp, " nonconvex");
3114     fprintf (fp, "\n");
3115     qh_printvertices (fp, " vertices:", ridge->vertices);
3116     if (ridge->top && ridge->bottom)
3117     fprintf(fp, " between f%d and f%d\n",
3118     ridge->top->id, ridge->bottom->id);
3119     } /* printridge */
3120    
3121     /*-<a href="qh-io.htm#TOC"
3122     >-------------------------------</a><a name="printspheres">-</a>
3123    
3124     qh_printspheres( fp, vertices, radius )
3125     prints 3-d vertices as OFF spheres
3126    
3127     notes:
3128     inflated octahedron from Stuart Levy earth/mksphere2
3129     */
3130     void qh_printspheres(FILE *fp, setT *vertices, realT radius) {
3131     vertexT *vertex, **vertexp;
3132    
3133     qh printoutnum++;
3134     fprintf (fp, "{appearance {-edge -normal normscale 0} {\n\
3135     INST geom {define vsphere OFF\n\
3136     18 32 48\n\
3137     \n\
3138     0 0 1\n\
3139     1 0 0\n\
3140     0 1 0\n\
3141     -1 0 0\n\
3142     0 -1 0\n\
3143     0 0 -1\n\
3144     0.707107 0 0.707107\n\
3145     0 -0.707107 0.707107\n\
3146     0.707107 -0.707107 0\n\
3147     -0.707107 0 0.707107\n\
3148     -0.707107 -0.707107 0\n\
3149     0 0.707107 0.707107\n\
3150     -0.707107 0.707107 0\n\
3151     0.707107 0.707107 0\n\
3152     0.707107 0 -0.707107\n\
3153     0 0.707107 -0.707107\n\
3154     -0.707107 0 -0.707107\n\
3155     0 -0.707107 -0.707107\n\
3156     \n\
3157     3 0 6 11\n\
3158     3 0 7 6 \n\
3159     3 0 9 7 \n\
3160     3 0 11 9\n\
3161     3 1 6 8 \n\
3162     3 1 8 14\n\
3163     3 1 13 6\n\
3164     3 1 14 13\n\
3165     3 2 11 13\n\
3166     3 2 12 11\n\
3167     3 2 13 15\n\
3168     3 2 15 12\n\
3169     3 3 9 12\n\
3170     3 3 10 9\n\
3171     3 3 12 16\n\
3172     3 3 16 10\n\
3173     3 4 7 10\n\
3174     3 4 8 7\n\
3175     3 4 10 17\n\
3176     3 4 17 8\n\
3177     3 5 14 17\n\
3178     3 5 15 14\n\
3179     3 5 16 15\n\
3180     3 5 17 16\n\
3181     3 6 13 11\n\
3182     3 7 8 6\n\
3183     3 9 10 7\n\
3184     3 11 12 9\n\
3185     3 14 8 17\n\
3186     3 15 13 14\n\
3187     3 16 12 15\n\
3188     3 17 10 16\n} transforms { TLIST\n");
3189     FOREACHvertex_(vertices) {
3190     fprintf(fp, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n",
3191     radius, vertex->id, radius, radius);
3192     qh_printpoint3 (fp, vertex->point);
3193     fprintf (fp, "1\n");
3194     }
3195     fprintf (fp, "}}}\n");
3196     } /* printspheres */
3197    
3198    
3199     /*----------------------------------------------
3200     -printsummary-
3201     see qhull.c
3202     */
3203    
3204     /*-<a href="qh-io.htm#TOC"
3205     >-------------------------------</a><a name="printvdiagram">-</a>
3206    
3207     qh_printvdiagram( fp, format, facetlist, facets, printall )
3208     print voronoi diagram
3209     # of pairs of input sites
3210     #indices site1 site2 vertex1 ...
3211    
3212     sites indexed by input point id
3213     point 0 is the first input point
3214     vertices indexed by 'o' and 'p' order
3215     vertex 0 is the 'vertex-at-infinity'
3216     vertex 1 is the first Voronoi vertex
3217    
3218     see:
3219     qh_printvoronoi()
3220     qh_eachvoronoi_all()
3221    
3222     notes:
3223     if all facets are upperdelaunay,
3224     prints upper hull (furthest-site Voronoi diagram)
3225     */
3226     void qh_printvdiagram (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
3227     setT *vertices;
3228     int totcount, numcenters;
3229     boolT islower;
3230     qh_RIDGE innerouter= qh_RIDGEall;
3231     printvridgeT printvridge= NULL;
3232    
3233     if (format == qh_PRINTvertices) {
3234     innerouter= qh_RIDGEall;
3235     printvridge= qh_printvridge;
3236     }else if (format == qh_PRINTinner) {
3237     innerouter= qh_RIDGEinner;
3238     printvridge= qh_printvnorm;
3239     }else if (format == qh_PRINTouter) {
3240     innerouter= qh_RIDGEouter;
3241     printvridge= qh_printvnorm;
3242     }else {
3243     fprintf(qh ferr, "qh_printvdiagram: unknown print format %d.\n", format);
3244     qh_errexit (qh_ERRinput, NULL, NULL);
3245     }
3246     vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
3247     totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False);
3248     fprintf (fp, "%d\n", totcount);
3249     totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/);
3250     qh_settempfree (&vertices);
3251     #if 0
3252     /* for testing qh_eachvoronoi_all */
3253     fprintf (fp, "\n");
3254     totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/);
3255     fprintf (fp, "%d\n", totcount);
3256     #endif
3257     } /* printvdiagram */
3258    
3259     /*-<a href="qh-io.htm#TOC"
3260     >-------------------------------</a><a name="printvdiagram2">-</a>
3261    
3262     qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder )
3263     visit all pairs of input sites (vertices) for selected Voronoi vertices
3264     vertices may include NULLs
3265    
3266     innerouter:
3267     qh_RIDGEall print inner ridges (bounded) and outer ridges (unbounded)
3268     qh_RIDGEinner print only inner ridges
3269     qh_RIDGEouter print only outer ridges
3270    
3271     inorder:
3272     print 3-d Voronoi vertices in order
3273    
3274     assumes:
3275     qh_markvoronoi marked facet->visitid for Voronoi vertices
3276     all facet->seen= False
3277     all facet->seen2= True
3278    
3279     returns:
3280     total number of Voronoi ridges
3281     if printvridge,
3282     calls printvridge( fp, vertex, vertexA, centers) for each ridge
3283     [see qh_eachvoronoi()]
3284    
3285     see:
3286     qh_eachvoronoi_all()
3287     */
3288     int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) {
3289     int totcount= 0;
3290     int vertex_i, vertex_n;
3291     vertexT *vertex;
3292    
3293     FORALLvertices
3294     vertex->seen= False;
3295     FOREACHvertex_i_(vertices) {
3296     if (vertex) {
3297     if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex)
3298     continue;
3299     totcount += qh_eachvoronoi (fp, printvridge, vertex, !qh_ALL, innerouter, inorder);
3300     }
3301     }
3302     return totcount;
3303     } /* printvdiagram2 */
3304    
3305     /*-<a href="qh-io.htm#TOC"
3306     >-------------------------------</a><a name="printvertex">-</a>
3307    
3308     qh_printvertex( fp, vertex )
3309     prints the information in a vertex
3310     */
3311     void qh_printvertex(FILE *fp, vertexT *vertex) {
3312     pointT *point;
3313     int k, count= 0;
3314     facetT *neighbor, **neighborp;
3315     realT r; /*bug fix*/
3316    
3317     if (!vertex) {
3318     fprintf (fp, " NULLvertex\n");
3319     return;
3320     }
3321     fprintf(fp, "- p%d (v%d):", qh_pointid(vertex->point), vertex->id);
3322     point= vertex->point;
3323     if (point) {
3324     for(k= qh hull_dim; k--; ) {
3325     r= *point++;
3326     fprintf(fp, " %5.2g", r);
3327     }
3328     }
3329     if (vertex->deleted)
3330     fprintf(fp, " deleted");
3331     if (vertex->delridge)
3332     fprintf (fp, " ridgedeleted");
3333     fprintf(fp, "\n");
3334     if (vertex->neighbors) {
3335     fprintf(fp, " neighbors:");
3336     FOREACHneighbor_(vertex) {
3337     if (++count % 100 == 0)
3338     fprintf (fp, "\n ");
3339     fprintf(fp, " f%d", neighbor->id);
3340     }
3341     fprintf(fp, "\n");
3342     }
3343     } /* printvertex */
3344    
3345    
3346     /*-<a href="qh-io.htm#TOC"
3347     >-------------------------------</a><a name="printvertexlist">-</a>
3348    
3349     qh_printvertexlist( fp, string, facetlist, facets, printall )
3350     prints vertices used by a facetlist or facet set
3351     tests qh_skipfacet() if !printall
3352     */
3353     void qh_printvertexlist (FILE *fp, char* string, facetT *facetlist,
3354     setT *facets, boolT printall) {
3355     vertexT *vertex, **vertexp;
3356     setT *vertices;
3357    
3358     vertices= qh_facetvertices (facetlist, facets, printall);
3359     fputs (string, fp);
3360     FOREACHvertex_(vertices)
3361     qh_printvertex(fp, vertex);
3362     qh_settempfree (&vertices);
3363     } /* printvertexlist */
3364    
3365    
3366     /*-<a href="qh-io.htm#TOC"
3367     >-------------------------------</a><a name="printvertices">-</a>
3368    
3369     qh_printvertices( fp, string, vertices )
3370     prints vertices in a set
3371     */
3372     void qh_printvertices(FILE *fp, char* string, setT *vertices) {
3373     vertexT *vertex, **vertexp;
3374    
3375     fputs (string, fp);
3376     FOREACHvertex_(vertices)
3377     fprintf (fp, " p%d (v%d)", qh_pointid(vertex->point), vertex->id);
3378     fprintf(fp, "\n");
3379     } /* printvertices */
3380    
3381     /*-<a href="qh-io.htm#TOC"
3382     >-------------------------------</a><a name="printvneighbors">-</a>
3383    
3384     qh_printvneighbors( fp, facetlist, facets, printall )
3385     print vertex neighbors of vertices in facetlist and facets ('FN')
3386    
3387     notes:
3388     qh_countfacets clears facet->visitid for non-printed facets
3389    
3390     design:
3391     collect facet count and related statistics
3392     if necessary, build neighbor sets for each vertex
3393     collect vertices in facetlist and facets
3394     build a point array for point->vertex and point->coplanar facet
3395     for each point
3396     list vertex neighbors or coplanar facet
3397     */
3398     void qh_printvneighbors (FILE *fp, facetT* facetlist, setT *facets, boolT printall) {
3399     int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars;
3400     setT *vertices, *vertex_points, *coplanar_points;
3401     int numpoints= qh num_points + qh_setsize (qh other_points);
3402     vertexT *vertex, **vertexp;
3403     int vertex_i, vertex_n;
3404     facetT *facet, **facetp, *neighbor, **neighborp;
3405     pointT *point, **pointp;
3406    
3407     qh_countfacets (facetlist, facets, printall, &numfacets, &numsimplicial,
3408     &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* sets facet->visitid */
3409     fprintf (fp, "%d\n", numpoints);
3410     qh_vertexneighbors();
3411     vertices= qh_facetvertices (facetlist, facets, printall);
3412     vertex_points= qh_settemp (numpoints);
3413     coplanar_points= qh_settemp (numpoints);
3414     qh_setzero (vertex_points, 0, numpoints);
3415     qh_setzero (coplanar_points, 0, numpoints);
3416     FOREACHvertex_(vertices)
3417     qh_point_add (vertex_points, vertex->point, vertex);
3418     FORALLfacet_(facetlist) {
3419     FOREACHpoint_(facet->coplanarset)
3420     qh_point_add (coplanar_points, point, facet);
3421     }
3422     FOREACHfacet_(facets) {
3423     FOREACHpoint_(facet->coplanarset)
3424     qh_point_add (coplanar_points, point, facet);
3425     }
3426     FOREACHvertex_i_(vertex_points) {
3427     if (vertex) {
3428     numneighbors= qh_setsize (vertex->neighbors);
3429     fprintf (fp, "%d", numneighbors);
3430     if (qh hull_dim == 3)
3431     qh_order_vertexneighbors (vertex);
3432     else if (qh hull_dim >= 4)
3433     qsort (SETaddr_(vertex->neighbors, facetT), numneighbors,
3434     sizeof (facetT *), qh_compare_facetvisit);
3435     FOREACHneighbor_(vertex)
3436     fprintf (fp, " %d",
3437     neighbor->visitid ? neighbor->visitid - 1 : - neighbor->id);
3438     fprintf (fp, "\n");
3439     }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT)))
3440     fprintf (fp, "1 %d\n",
3441     facet->visitid ? facet->visitid - 1 : - facet->id);
3442     else
3443     fprintf (fp, "0\n");
3444     }
3445     qh_settempfree (&coplanar_points);
3446     qh_settempfree (&vertex_points);
3447     qh_settempfree (&vertices);
3448     } /* printvneighbors */
3449    
3450     /*-<a href="qh-io.htm#TOC"
3451     >-------------------------------</a><a name="printvoronoi">-</a>
3452    
3453     qh_printvoronoi( fp, format, facetlist, facets, printall )
3454     print voronoi diagram in 'o' or 'G' format
3455     for 'o' format
3456     prints voronoi centers for each facet and for infinity
3457     for each vertex, lists ids of printed facets or infinity
3458     assumes facetlist and facets are disjoint
3459     for 'G' format
3460     prints an OFF object
3461     adds a 0 coordinate to center
3462     prints infinity but does not list in vertices
3463    
3464     see:
3465     qh_printvdiagram()
3466    
3467     notes:
3468     if 'o',
3469     prints a line for each point except "at-infinity"
3470     if all facets are upperdelaunay,
3471     reverses lower and upper hull
3472     */
3473     void qh_printvoronoi (FILE *fp, int format, facetT *facetlist, setT *facets, boolT printall) {
3474     int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n;
3475     facetT *facet, **facetp, *neighbor, **neighborp;
3476     setT *vertices;
3477     vertexT *vertex;
3478     boolT islower;
3479     unsigned int numfacets= (unsigned int) qh num_facets;
3480    
3481     vertices= qh_markvoronoi (facetlist, facets, printall, &islower, &numcenters);
3482     FOREACHvertex_i_(vertices) {
3483     if (vertex) {
3484     numvertices++;
3485     numneighbors = numinf = 0;
3486     FOREACHneighbor_(vertex) {
3487     if (neighbor->visitid == 0)
3488     numinf= 1;
3489     else if (neighbor->visitid < numfacets)
3490     numneighbors++;
3491     }
3492     if (numinf && !numneighbors) {
3493     SETelem_(vertices, vertex_i)= NULL;
3494     numvertices--;
3495     }
3496     }
3497     }
3498     if (format == qh_PRINTgeom)
3499     fprintf (fp, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n",
3500     numcenters, numvertices);
3501     else
3502     fprintf (fp, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices));
3503     if (format == qh_PRINTgeom) {
3504     for (k= qh hull_dim-1; k--; )
3505     fprintf (fp, qh_REAL_1, 0.0);
3506     fprintf (fp, " 0 # infinity not used\n");
3507     }else {
3508     for (k= qh hull_dim-1; k--; )
3509     fprintf (fp, qh_REAL_1, qh_INFINITE);
3510     fprintf (fp, "\n");
3511     }
3512     FORALLfacet_(facetlist) {
3513     if (facet->visitid && facet->visitid < numfacets) {
3514     if (format == qh_PRINTgeom)
3515     fprintf (fp, "# %d f%d\n", vid++, facet->id);
3516     qh_printcenter (fp, format, NULL, facet);
3517     }
3518     }
3519     FOREACHfacet_(facets) {
3520     if (facet->visitid && facet->visitid < numfacets) {
3521     if (format == qh_PRINTgeom)
3522     fprintf (fp, "# %d f%d\n", vid++, facet->id);
3523     qh_printcenter (fp, format, NULL, facet);
3524     }
3525     }
3526     FOREACHvertex_i_(vertices) {
3527     numneighbors= 0;
3528     numinf=0;
3529     if (vertex) {
3530     if (qh hull_dim == 3)
3531     qh_order_vertexneighbors(vertex);
3532     else if (qh hull_dim >= 4)
3533     qsort (SETaddr_(vertex->neighbors, vertexT),
3534     qh_setsize (vertex->neighbors),
3535     sizeof (facetT *), qh_compare_facetvisit);
3536     FOREACHneighbor_(vertex) {
3537     if (neighbor->visitid == 0)
3538     numinf= 1;
3539     else if (neighbor->visitid < numfacets)
3540     numneighbors++;
3541     }
3542     }
3543     if (format == qh_PRINTgeom) {
3544     if (vertex) {
3545     fprintf (fp, "%d", numneighbors);
3546     if (vertex) {
3547     FOREACHneighbor_(vertex) {
3548     if (neighbor->visitid && neighbor->visitid < numfacets)
3549     fprintf (fp, " %d", neighbor->visitid);
3550     }
3551     }
3552     fprintf (fp, " # p%d (v%d)\n", vertex_i, vertex->id);
3553     }else
3554     fprintf (fp, " # p%d is coplanar or isolated\n", vertex_i);
3555     }else {
3556     if (numinf)
3557     numneighbors++;
3558     fprintf (fp, "%d", numneighbors);
3559     if (vertex) {
3560     FOREACHneighbor_(vertex) {
3561     if (neighbor->visitid == 0) {
3562     if (numinf) {
3563     numinf= 0;
3564     fprintf (fp, " %d", neighbor->visitid);
3565     }
3566     }else if (neighbor->visitid < numfacets)
3567     fprintf (fp, " %d", neighbor->visitid);
3568     }
3569     }
3570     fprintf (fp, "\n");
3571     }
3572     }
3573     if (format == qh_PRINTgeom)
3574     fprintf (fp, "}\n");
3575     qh_settempfree (&vertices);
3576     } /* printvoronoi */
3577    
3578     /*-<a href="qh-io.htm#TOC"
3579     >-------------------------------</a><a name="printvnorm">-</a>
3580    
3581     qh_printvnorm( fp, vertex, vertexA, centers, unbounded )
3582     print one separating plane of the Voronoi diagram for a pair of input sites
3583     unbounded==True if centers includes vertex-at-infinity
3584    
3585     assumes:
3586     qh_ASvoronoi and qh_vertexneighbors() already set
3587    
3588     see:
3589     qh_printvdiagram()
3590     qh_eachvoronoi()
3591     */
3592     void qh_printvnorm (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
3593     pointT *normal;
3594     realT offset;
3595     int k;
3596    
3597     normal= qh_detvnorm (vertex, vertexA, centers, &offset);
3598     fprintf (fp, "%d %d %d ",
3599     2+qh hull_dim, qh_pointid (vertex->point), qh_pointid (vertexA->point));
3600     for (k= 0; k< qh hull_dim-1; k++)
3601     fprintf (fp, qh_REAL_1, normal[k]);
3602     fprintf (fp, qh_REAL_1, offset);
3603     fprintf (fp, "\n");
3604     } /* printvnorm */
3605    
3606     /*-<a href="qh-io.htm#TOC"
3607     >-------------------------------</a><a name="printvridge">-</a>
3608    
3609     qh_printvridge( fp, vertex, vertexA, centers, unbounded )
3610     print one ridge of the Voronoi diagram for a pair of input sites
3611     unbounded==True if centers includes vertex-at-infinity
3612    
3613     see:
3614     qh_printvdiagram()
3615    
3616     notes:
3617     the user may use a different function
3618     */
3619     void qh_printvridge (FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) {
3620     facetT *facet, **facetp;
3621    
3622     fprintf (fp, "%d %d %d", qh_setsize (centers)+2,
3623     qh_pointid (vertex->point), qh_pointid (vertexA->point));
3624     FOREACHfacet_(centers)
3625     fprintf (fp, " %d", facet->visitid);
3626     fprintf (fp, "\n");
3627     } /* printvridge */
3628    
3629     /*-<a href="qh-io.htm#TOC"
3630     >-------------------------------</a><a name="projectdim3">-</a>
3631    
3632     qh_projectdim3( source, destination )
3633     project 2-d 3-d or 4-d point to a 3-d point
3634     uses qh.DROPdim and qh.hull_dim
3635     source and destination may be the same
3636    
3637     notes:
3638     allocate 4 elements to destination just in case
3639     */
3640     void qh_projectdim3 (pointT *source, pointT *destination) {
3641     int i,k;
3642    
3643     for (k= 0, i=0; k < qh hull_dim; k++) {
3644     if (qh hull_dim == 4) {
3645     if (k != qh DROPdim)
3646     destination[i++]= source[k];
3647     }else if (k == qh DROPdim)
3648     destination[i++]= 0;
3649     else
3650     destination[i++]= source[k];
3651     }
3652     while (i < 3)
3653     destination[i++]= 0.0;
3654     } /* projectdim3 */
3655    
3656     /*-<a href="qh-io.htm#TOC"
3657     >-------------------------------</a><a name="readfeasible">-</a>
3658    
3659     qh_readfeasible( dim, remainder )
3660     read feasible point from remainder string and qh.fin
3661    
3662     returns:
3663     number of lines read from qh.fin
3664     sets qh.FEASIBLEpoint with malloc'd coordinates
3665    
3666     notes:
3667     checks for qh.HALFspace
3668     assumes dim > 1
3669    
3670     see:
3671     qh_setfeasible
3672     */
3673     int qh_readfeasible (int dim, char *remainder) {
3674     boolT isfirst= True;
3675     int linecount= 0, tokcount= 0;
3676     char *s, *t, firstline[qh_MAXfirst+1];
3677     coordT *coords, value;
3678    
3679     if (!qh HALFspace) {
3680     fprintf (qh ferr, "qhull input error: feasible point (dim 1 coords) is only valid for halfspace intersection\n");
3681     qh_errexit (qh_ERRinput, NULL, NULL);
3682     }
3683     if (qh feasible_string)
3684     fprintf (qh ferr, "qhull input warning: feasible point (dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n");
3685     if (!(qh feasible_point= (coordT*)malloc (dim* sizeof(coordT)))) {
3686     fprintf(qh ferr, "qhull error: insufficient memory for feasible point\n");
3687     qh_errexit(qh_ERRmem, NULL, NULL);
3688     }
3689     coords= qh feasible_point;
3690     while ((s= (isfirst ? remainder : fgets(firstline, qh_MAXfirst, qh fin)))) {
3691     if (isfirst)
3692     isfirst= False;
3693     else
3694     linecount++;
3695     while (*s) {
3696     while (isspace(*s))
3697     s++;
3698     value= qh_strtod (s, &t);
3699     if (s == t)
3700     break;
3701     s= t;
3702     *(coords++)= value;
3703     if (++tokcount == dim) {
3704     while (isspace (*s))
3705     s++;
3706     qh_strtod (s, &t);
3707     if (s != t) {
3708     fprintf (qh ferr, "qhull input error: coordinates for feasible point do not finish out the line: %s\n",
3709     s);
3710     qh_errexit (qh_ERRinput, NULL, NULL);
3711     }
3712     return linecount;
3713     }
3714     }
3715     }
3716     fprintf (qh ferr, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n",
3717     tokcount, dim);
3718     qh_errexit (qh_ERRinput, NULL, NULL);
3719     return 0;
3720     } /* readfeasible */
3721    
3722     /*-<a href="qh-io.htm#TOC"
3723     >-------------------------------</a><a name="readpoints">-</a>
3724    
3725     qh_readpoints( numpoints, dimension, ismalloc )
3726     read points from qh.fin into qh.first_point, qh.num_points
3727     qh.fin is lines of coordinates, one per vertex, first line number of points
3728     if 'rbox D4',
3729     gives message
3730     if qh.ATinfinity,
3731     adds point-at-infinity for Delaunay triangulations
3732    
3733     returns:
3734     number of points, array of point coordinates, dimension, ismalloc True
3735     if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid
3736     and clears qh.PROJECTdelaunay
3737     if qh.HALFspace, reads optional feasible point, reads halfspaces,
3738     converts to dual.
3739    
3740     for feasible point in "cdd format" in 3-d:
3741     3 1
3742     coordinates
3743     comments
3744     begin
3745     n 4 real/integer
3746     ...
3747     end
3748    
3749     notes:
3750     dimension will change in qh_initqhull_globals if qh.PROJECTinput
3751     uses malloc() since qh_mem not initialized
3752     FIXUP: this routine needs rewriting
3753     */
3754     coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) {
3755     coordT *points, *coords, *infinity= NULL;
3756     realT paraboloid, maxboloid= -REALmax, value;
3757     realT *coordp= NULL, *offsetp= NULL, *normalp= NULL;
3758     char *s, *t, firstline[qh_MAXfirst+1];
3759     int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi;
3760     int firsttext=0, firstshort=0, firstlong=0, firstpoint=0;
3761     int tokcount= 0, linecount=0, maxcount, coordcount=0;
3762     boolT islong, isfirst= True, wasbegin= False;
3763     boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput;
3764    
3765     if (qh CDDinput) {
3766     while ((s= fgets(firstline, qh_MAXfirst, qh fin))) {
3767     linecount++;
3768     if (qh HALFspace && linecount == 1 && isdigit(*s)) {
3769     dimfeasible= qh_strtol (s, &s);
3770     while (isspace(*s))
3771     s++;
3772     if (qh_strtol (s, &s) == 1)
3773     linecount += qh_readfeasible (dimfeasible, s);
3774     else
3775     dimfeasible= 0;
3776     }else if (!memcmp (firstline, "begin", 5) || !memcmp (firstline, "BEGIN", 5))
3777     break;
3778     else if (!*qh rbox_command)
3779     strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3780     }
3781     if (!s) {
3782     fprintf (qh ferr, "qhull input error: missing \"begin\" for cdd-formated input\n");
3783     qh_errexit (qh_ERRinput, NULL, NULL);
3784     }
3785     }
3786     while(!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) {
3787     linecount++;
3788     if (!memcmp (s, "begin", 5) || !memcmp (s, "BEGIN", 5))
3789     wasbegin= True;
3790     while (*s) {
3791     while (isspace(*s))
3792     s++;
3793     if (!*s)
3794     break;
3795     if (!isdigit(*s)) {
3796     if (!*qh rbox_command) {
3797     strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3798     firsttext= linecount;
3799     }
3800     break;
3801     }
3802     if (!diminput)
3803     diminput= qh_strtol (s, &s);
3804     else {
3805     numinput= qh_strtol (s, &s);
3806     if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) {
3807     linecount += qh_readfeasible (diminput, s); /* checks if ok */
3808     dimfeasible= diminput;
3809     diminput= numinput= 0;
3810     }else
3811     break;
3812     }
3813     }
3814     }
3815     if (!s) {
3816     fprintf(qh ferr, "qhull input error: short input file. Did not find dimension and number of points\n");
3817     qh_errexit(qh_ERRinput, NULL, NULL);
3818     }
3819     if (diminput > numinput) {
3820     tempi= diminput; /* exchange dim and n, e.g., for cdd input format */
3821     diminput= numinput;
3822     numinput= tempi;
3823     }
3824     if (diminput < 2) {
3825     fprintf(qh ferr,"qhull input error: dimension %d (first number) should be at least 2\n",
3826     diminput);
3827     qh_errexit(qh_ERRinput, NULL, NULL);
3828     }
3829     if (isdelaunay) {
3830     qh PROJECTdelaunay= False;
3831     if (qh CDDinput)
3832     *dimension= diminput;
3833     else
3834     *dimension= diminput+1;
3835     *numpoints= numinput;
3836     if (qh ATinfinity)
3837     (*numpoints)++;
3838     }else if (qh HALFspace) {
3839     *dimension= diminput - 1;
3840     *numpoints= numinput;
3841     if (diminput < 3) {
3842     fprintf(qh ferr,"qhull input error: dimension %d (first number, includes offset) should be at least 3 for halfspaces\n",
3843     diminput);
3844     qh_errexit(qh_ERRinput, NULL, NULL);
3845     }
3846     if (dimfeasible) {
3847     if (dimfeasible != *dimension) {
3848     fprintf(qh ferr,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n",
3849     dimfeasible, diminput);
3850     qh_errexit(qh_ERRinput, NULL, NULL);
3851     }
3852     }else
3853     qh_setfeasible (*dimension);
3854     }else {
3855     if (qh CDDinput)
3856     *dimension= diminput-1;
3857     else
3858     *dimension= diminput;
3859     *numpoints= numinput;
3860     }
3861     qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */
3862     if (qh HALFspace) {
3863     qh half_space= coordp= (coordT*) malloc (qh normal_size + sizeof(coordT));
3864     if (qh CDDinput) {
3865     offsetp= qh half_space;
3866     normalp= offsetp + 1;
3867     }else {
3868     normalp= qh half_space;
3869     offsetp= normalp + *dimension;
3870     }
3871     }
3872     qh maxline= diminput * (qh_REALdigits + 5);
3873     maximize_(qh maxline, 500);
3874     qh line= (char*)malloc ((qh maxline+1) * sizeof (char));
3875     *ismalloc= True; /* use malloc since memory not setup */
3876     coords= points= qh temp_malloc=
3877     (coordT*)malloc((*numpoints)*(*dimension)*sizeof(coordT));
3878     if (!coords || !qh line || (qh HALFspace && !qh half_space)) {
3879     fprintf(qh ferr, "qhull error: insufficient memory to read %d points\n",
3880     numinput);
3881     qh_errexit(qh_ERRmem, NULL, NULL);
3882     }
3883     if (isdelaunay && qh ATinfinity) {
3884     infinity= points + numinput * (*dimension);
3885     for (k= (*dimension) - 1; k--; )
3886     infinity[k]= 0.0;
3887     }
3888     maxcount= numinput * diminput;
3889     paraboloid= 0.0;
3890     while ((s= (isfirst ? s : fgets(qh line, qh maxline, qh fin)))) {
3891     if (!isfirst) {
3892     linecount++;
3893     if (*s == 'e' || *s == 'E') {
3894     if (!memcmp (s, "end", 3) || !memcmp (s, "END", 3)) {
3895     if (qh CDDinput )
3896     break;
3897     else if (wasbegin)
3898     fprintf (qh ferr, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n");
3899     }
3900     }
3901     }
3902     islong= False;
3903     while (*s) {
3904     while (isspace(*s))
3905     s++;
3906     value= qh_strtod (s, &t);
3907     if (s == t) {
3908     if (!*qh rbox_command)
3909     strncat(qh rbox_command, s, sizeof (qh rbox_command)-1);
3910     if (*s && !firsttext)
3911     firsttext= linecount;
3912     if (!islong && !firstshort && coordcount)
3913     firstshort= linecount;
3914     break;
3915     }
3916     if (!firstpoint)
3917     firstpoint= linecount;
3918     s= t;
3919     if (++tokcount > maxcount)
3920     continue;
3921     if (qh HALFspace) {
3922     if (qh CDDinput)
3923     *(coordp++)= -value; /* both coefficients and offset */
3924     else
3925     *(coordp++)= value;
3926     }else {
3927     *(coords++)= value;
3928     if (qh CDDinput && !coordcount) {
3929     if (value != 1.0) {
3930     fprintf (qh ferr, "qhull input error: for cdd format, point at line %d does not start with '1'\n",
3931     linecount);
3932     qh_errexit (qh_ERRinput, NULL, NULL);
3933     }
3934     coords--;
3935     }else if (isdelaunay) {
3936     paraboloid += value * value;
3937     if (qh ATinfinity) {
3938     if (qh CDDinput)
3939     infinity[coordcount-1] += value;
3940     else
3941     infinity[coordcount] += value;
3942     }
3943     }
3944     }
3945     if (++coordcount == diminput) {
3946     coordcount= 0;
3947     if (isdelaunay) {
3948     *(coords++)= paraboloid;
3949     maximize_(maxboloid, paraboloid);
3950     paraboloid= 0.0;
3951     }else if (qh HALFspace) {
3952     if (!qh_sethalfspace (*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) {
3953     fprintf (qh ferr, "The halfspace was on line %d\n", linecount);
3954     if (wasbegin)
3955     fprintf (qh ferr, "The input appears to be in cdd format. If so, you should use option 'Fd'\n");
3956     qh_errexit (qh_ERRinput, NULL, NULL);
3957     }
3958     coordp= qh half_space;
3959     }
3960     while (isspace(*s))
3961     s++;
3962     if (*s) {
3963     islong= True;
3964     if (!firstlong)
3965     firstlong= linecount;
3966     }
3967     }
3968     }
3969     if (!islong && !firstshort && coordcount)
3970     firstshort= linecount;
3971     if (!isfirst && s - qh line >= qh maxline) {
3972     fprintf(qh ferr, "qhull input error: line %d contained more than %d characters\n",
3973     linecount, (int) (s - qh line));
3974     qh_errexit(qh_ERRinput, NULL, NULL);
3975     }
3976     isfirst= False;
3977     }
3978     if (tokcount != maxcount) {
3979     newnum= fmin_(numinput, tokcount/diminput);
3980     fprintf(qh ferr,"\
3981     qhull warning: instead of %d %d-dimensional points, input contains\n\
3982     %d points and %d extra coordinates. Line %d is the first\npoint",
3983     numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint);
3984     if (firsttext)
3985     fprintf(qh ferr, ", line %d is the first comment", firsttext);
3986     if (firstshort)
3987     fprintf(qh ferr, ", line %d is the first short\nline", firstshort);
3988     if (firstlong)
3989     fprintf(qh ferr, ", line %d is the first long line", firstlong);
3990     fprintf(qh ferr, ". Continue with %d points.\n", newnum);
3991     numinput= newnum;
3992     if (isdelaunay && qh ATinfinity) {
3993     for (k= tokcount % diminput; k--; )
3994     infinity[k] -= *(--coords);
3995     *numpoints= newnum+1;
3996     }else {
3997     coords -= tokcount % diminput;
3998     *numpoints= newnum;
3999     }
4000     }
4001     if (isdelaunay && qh ATinfinity) {
4002     for (k= (*dimension) -1; k--; )
4003     infinity[k] /= numinput;
4004     if (coords == infinity)
4005     coords += (*dimension) -1;
4006     else {
4007     for (k= 0; k < (*dimension) -1; k++)
4008     *(coords++)= infinity[k];
4009     }
4010     *(coords++)= maxboloid * 1.1;
4011     }
4012     if (qh rbox_command[0]) {
4013     qh rbox_command[strlen(qh rbox_command)-1]= '\0';
4014     if (!strcmp (qh rbox_command, "./rbox D4"))
4015     fprintf (qh ferr, "\n\
4016     This is the qhull test case. If any errors or core dumps occur,\n\
4017     recompile qhull with 'make new'. If errors still occur, there is\n\
4018     an incompatibility. You should try a different compiler. You can also\n\
4019     change the choices in user.h. If you discover the source of the problem,\n\
4020     please send mail to qhull_bug@qhull.org.\n\
4021     \n\
4022     Type 'qhull' for a short list of options.\n");
4023     }
4024     free (qh line);
4025     qh line= NULL;
4026     if (qh half_space) {
4027     free (qh half_space);
4028     qh half_space= NULL;
4029     }
4030     qh temp_malloc= NULL;
4031     trace1((qh ferr,"qh_readpoints: read in %d %d-dimensional points\n", numinput, diminput));
4032     return(points);
4033     } /* readpoints */
4034    
4035    
4036     /*-<a href="qh-io.htm#TOC"
4037     >-------------------------------</a><a name="setfeasible">-</a>
4038    
4039     qh_setfeasible( dim )
4040     set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format
4041    
4042     notes:
4043     "n,n,n" already checked by qh_initflags()
4044     see qh_readfeasible()
4045     */
4046     void qh_setfeasible (int dim) {
4047     int tokcount= 0;
4048     char *s;
4049     coordT *coords, value;
4050    
4051     if (!(s= qh feasible_string)) {
4052     fprintf(qh ferr, "\
4053     qhull input error: halfspace intersection needs a feasible point.\n\
4054     Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n");
4055     qh_errexit (qh_ERRinput, NULL, NULL);
4056     }
4057     if (!(qh feasible_point= (pointT*)malloc (dim* sizeof(coordT)))) {
4058     fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n");
4059     qh_errexit(qh_ERRmem, NULL, NULL);
4060     }
4061     coords= qh feasible_point;
4062     while (*s) {
4063     value= qh_strtod (s, &s);
4064     if (++tokcount > dim) {
4065     fprintf (qh ferr, "qhull input warning: more coordinates for 'H%s' than dimension %d\n",
4066     qh feasible_string, dim);
4067     break;
4068     }
4069     *(coords++)= value;
4070     if (*s)
4071     s++;
4072     }
4073     while (++tokcount <= dim)
4074     *(coords++)= 0.0;
4075     } /* setfeasible */
4076    
4077     /*-<a href="qh-io.htm#TOC"
4078     >-------------------------------</a><a name="skipfacet">-</a>
4079    
4080     qh_skipfacet( facet )
4081     returns 'True' if this facet is not to be printed
4082    
4083     notes:
4084     based on the user provided slice thresholds and 'good' specifications
4085     */
4086     boolT qh_skipfacet(facetT *facet) {
4087     facetT *neighbor, **neighborp;
4088    
4089     if (qh PRINTneighbors) {
4090     if (facet->good)
4091     return !qh PRINTgood;
4092     FOREACHneighbor_(facet) {
4093     if (neighbor->good)
4094     return False;
4095     }
4096     return True;
4097     }else if (qh PRINTgood)
4098     return !facet->good;
4099     else if (!facet->normal)
4100     return True;
4101     return (!qh_inthresholds (facet->normal, NULL));
4102     } /* skipfacet */
4103