ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/QuickHull/qhull.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: 50295 byte(s)
Log Message:
Addded QuickHull to cvs.

File Contents

# User Rev Content
1 chuckv 1138 /*<html><pre> -<a href="qh-qhull.htm"
2     >-------------------------------</a><a name="TOP">-</a>
3    
4     qhull.c
5     Quickhull algorithm for convex hulls
6    
7     qhull() and top-level routines
8    
9     see qh-qhull.htm, qhull.h, unix.c
10    
11     see qhull_a.h for internal functions
12    
13     copyright (c) 1993-2003 The Geometry Center
14     */
15    
16     #include "QuickHull/qhull_a.h"
17    
18     /*============= functions in alphabetic order after qhull() =======*/
19    
20     /*-<a href="qh-qhull.htm#TOC"
21     >-------------------------------</a><a name="qhull">-</a>
22    
23     qh_qhull()
24     compute DIM3 convex hull of qh.num_points starting at qh.first_point
25     qh contains all global options and variables
26    
27     returns:
28     returns polyhedron
29     qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices,
30    
31     returns global variables
32     qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex
33    
34     returns precision constants
35     qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge
36    
37     notes:
38     unless needed for output
39     qh.max_vertex and qh.min_vertex are max/min due to merges
40    
41     see:
42     to add individual points to either qh.num_points
43     please use qh_addpoint()
44    
45     if qh.GETarea
46     qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea()
47    
48     design:
49     record starting time
50     initialize hull and partition points
51     build convex hull
52     unless early termination
53     update facet->maxoutside for vertices, coplanar, and near-inside points
54     error if temporary sets exist
55     record end time
56     */
57    
58     void qh_qhull (void) {
59     int numoutside;
60    
61     qh hulltime= qh_CPUclock;
62     if (qh RERUN || qh JOGGLEmax < REALmax/2)
63     qh_build_withrestart();
64     else {
65     qh_initbuild();
66     qh_buildhull();
67     }
68     if (!qh STOPpoint && !qh STOPcone) {
69     if (qh ZEROall_ok && !qh TESTvneighbors && qh MERGEexact)
70     qh_checkzero( qh_ALL);
71     if (qh ZEROall_ok && !qh TESTvneighbors && !qh WAScoplanar) {
72     trace2((qh ferr, "qh_qhull: all facets are clearly convex and no coplanar points. Post-merging and check of maxout not needed.\n"));
73     qh DOcheckmax= False;
74     }else {
75     if (qh MERGEexact || (qh hull_dim > qh_DIMreduceBuild && qh PREmerge))
76     qh_postmerge ("First post-merge", qh premerge_centrum, qh premerge_cos,
77     (qh POSTmerge ? False : qh TESTvneighbors));
78     else if (!qh POSTmerge && qh TESTvneighbors)
79     qh_postmerge ("For testing vertex neighbors", qh premerge_centrum,
80     qh premerge_cos, True);
81     if (qh POSTmerge)
82     qh_postmerge ("For post-merging", qh postmerge_centrum,
83     qh postmerge_cos, qh TESTvneighbors);
84     if (qh visible_list == qh facet_list) { /* i.e., merging done */
85     qh findbestnew= True;
86     qh_partitionvisible (/*visible_list, newfacet_list*/ !qh_ALL, &numoutside);
87     qh findbestnew= False;
88     qh_deletevisible (/*qh visible_list*/);
89     qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
90     }
91     }
92     if (qh DOcheckmax){
93     if (qh REPORTfreq) {
94     qh_buildtracing (NULL, NULL);
95     fprintf (qh ferr, "\nTesting all coplanar points.\n");
96     }
97     qh_check_maxout();
98     }
99     if (qh KEEPnearinside && !qh maxoutdone)
100     qh_nearcoplanar();
101     }
102     if (qh_setsize ((setT*)qhmem.tempstack) != 0) {
103     fprintf (qh ferr, "qhull internal error (qh_qhull): temporary sets not empty (%d)\n",
104     qh_setsize ((setT*)qhmem.tempstack));
105     qh_errexit (qh_ERRqhull, NULL, NULL);
106     }
107     qh hulltime= qh_CPUclock - qh hulltime;
108     qh QHULLfinished= True;
109     trace1((qh ferr, "qh_qhull: algorithm completed\n"));
110     } /* qhull */
111    
112     /*-<a href="qh-qhull.htm#TOC"
113     >-------------------------------</a><a name="addpoint">-</a>
114    
115     qh_addpoint( furthest, facet, checkdist )
116     add point (usually furthest point) above facet to hull
117     if checkdist,
118     check that point is above facet.
119     if point is not outside of the hull, uses qh_partitioncoplanar()
120     assumes that facet is defined by qh_findbestfacet()
121     else if facet specified,
122     assumes that point is above facet (major damage if below)
123     for Delaunay triangulations,
124     Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
125     Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
126    
127     returns:
128     returns False if user requested an early termination
129     qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
130     updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
131     clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
132     if unknown point, adds a pointer to qh.other_points
133     do not deallocate the point's coordinates
134    
135     notes:
136     assumes point is near its best facet and not at a local minimum of a lens
137     distributions. Use qh_findbestfacet to avoid this case.
138     uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
139    
140     see also:
141     qh_triangulate() -- triangulate non-simplicial facets
142    
143     design:
144     check point in qh.first_point/.num_points
145     if checkdist
146     if point not above facet
147     partition coplanar point
148     exit
149     exit if pre STOPpoint requested
150     find horizon and visible facets for point
151     make new facets for point to horizon
152     make hyperplanes for point
153     compute balance statistics
154     match neighboring new facets
155     update vertex neighbors and delete interior vertices
156     exit if STOPcone requested
157     merge non-convex new facets
158     if merge found, many merges, or 'Qf'
159     please use qh_findbestnew() instead of qh_findbest()
160     partition outside points from visible facets
161     delete visible facets
162     check polyhedron if requested
163     exit if post STOPpoint requested
164     reset working lists of facets and vertices
165     */
166     boolT qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist) {
167     int goodvisible, goodhorizon;
168     vertexT *vertex;
169     facetT *newfacet;
170     realT dist, newbalance, pbalance;
171     boolT isoutside= False;
172     int numpart, numpoints, numnew, firstnew;
173    
174     qh maxoutdone= False;
175     if (qh_pointid (furthest) == -1)
176     qh_setappend (&qh other_points, furthest);
177     if (!facet) {
178     fprintf (qh ferr, "qh_addpoint: NULL facet. Need to call qh_findbestfacet first\n");
179     qh_errexit (qh_ERRqhull, NULL, NULL);
180     }
181     if (checkdist) {
182     facet= qh_findbest (furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
183     &dist, &isoutside, &numpart);
184     zzadd_(Zpartition, numpart);
185     if (!isoutside) {
186     zinc_(Znotmax); /* last point of outsideset is no longer furthest. */
187     facet->notfurthest= True;
188     qh_partitioncoplanar (furthest, facet, &dist);
189     return True;
190     }
191     }
192     qh_buildtracing (furthest, facet);
193     if (qh STOPpoint < 0 && qh furthest_id == -qh STOPpoint-1) {
194     facet->notfurthest= True;
195     return False;
196     }
197     qh_findhorizon (furthest, facet, &goodvisible, &goodhorizon);
198     if (qh ONLYgood && !(goodvisible+goodhorizon) && !qh GOODclosest) {
199     zinc_(Znotgood);
200     facet->notfurthest= True;
201     /* last point of outsideset is no longer furthest. This is ok
202     since all points of the outside are likely to be bad */
203     qh_resetlists (False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
204     return True;
205     }
206     zzinc_(Zprocessed);
207     firstnew= qh facet_id;
208     vertex= qh_makenewfacets (furthest /*visible_list, attaches if !ONLYgood */);
209     qh_makenewplanes (/* newfacet_list */);
210     numnew= qh facet_id - firstnew;
211     newbalance= numnew - (realT) (qh num_facets-qh num_visible)
212     * qh hull_dim/qh num_vertices;
213     wadd_(Wnewbalance, newbalance);
214     wadd_(Wnewbalance2, newbalance * newbalance);
215     if (qh ONLYgood
216     && !qh_findgood (qh newfacet_list, goodhorizon) && !qh GOODclosest) {
217     FORALLnew_facets
218     qh_delfacet (newfacet);
219     qh_delvertex (vertex);
220     qh_resetlists (True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
221     zinc_(Znotgoodnew);
222     facet->notfurthest= True;
223     return True;
224     }
225     if (qh ONLYgood)
226     qh_attachnewfacets(/*visible_list*/);
227     qh_matchnewfacets();
228     qh_updatevertices();
229     if (qh STOPcone && qh furthest_id == qh STOPcone-1) {
230     facet->notfurthest= True;
231     return False; /* visible_list etc. still defined */
232     }
233     qh findbestnew= False;
234     if (qh PREmerge || qh MERGEexact) {
235     qh_premerge (vertex, qh premerge_centrum, qh premerge_cos);
236     if (qh_USEfindbestnew)
237     qh findbestnew= True;
238     else {
239     FORALLnew_facets {
240     if (!newfacet->simplicial) {
241     qh findbestnew= True; /* use qh_findbestnew instead of qh_findbest*/
242     break;
243     }
244     }
245     }
246     }else if (qh BESToutside)
247     qh findbestnew= True;
248     qh_partitionvisible (/*visible_list, newfacet_list*/ !qh_ALL, &numpoints);
249     qh findbestnew= False;
250     qh findbest_notsharp= False;
251     zinc_(Zpbalance);
252     pbalance= numpoints - (realT) qh hull_dim /* assumes all points extreme */
253     * (qh num_points - qh num_vertices)/qh num_vertices;
254     wadd_(Wpbalance, pbalance);
255     wadd_(Wpbalance2, pbalance * pbalance);
256     qh_deletevisible (/*qh visible_list*/);
257     zmax_(Zmaxvertex, qh num_vertices);
258     qh NEWfacets= False;
259     if (qh IStracing >= 4) {
260     if (qh num_facets < 2000)
261     qh_printlists();
262     qh_printfacetlist (qh newfacet_list, NULL, True);
263     qh_checkpolygon (qh facet_list);
264     }else if (qh CHECKfrequently) {
265     if (qh num_facets < 50)
266     qh_checkpolygon (qh facet_list);
267     else
268     qh_checkpolygon (qh newfacet_list);
269     }
270     if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1)
271     return False;
272     qh_resetlists (True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */);
273     /* qh_triangulate(); to test qh.TRInormals */
274     trace2((qh ferr, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n", qh_pointid (furthest), numnew, newbalance, pbalance));
275     return True;
276     } /* addpoint */
277    
278     /*-<a href="qh-qhull.htm#TOC"
279     >-------------------------------</a><a name="build_withrestart">-</a>
280    
281     qh_build_withrestart()
282     allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
283     qh.FIRSTpoint/qh.NUMpoints is point array
284     it may be moved by qh_joggleinput()
285     */
286     void qh_build_withrestart (void) {
287     int restart;
288    
289     qh ALLOWrestart= True;
290     while (True) {
291     restart= setjmp (qh restartexit); /* simple statement for CRAY J916 */
292     if (restart) { /* only from qh_precision() */
293     zzinc_(Zretry);
294     wmax_(Wretrymax, qh JOGGLEmax);
295     qh ERREXITcalled= False;
296     qh STOPcone= True; /* if break, prevents normal output */
297     }
298     if (!qh RERUN && qh JOGGLEmax < REALmax/2) {
299     if (qh build_cnt > qh_JOGGLEmaxretry) {
300     fprintf(qh ferr, "\n\
301     qhull precision error: %d attempts to construct a convex hull\n\
302     with joggled input. Increase joggle above 'QJ%2.2g'\n\
303     or modify qh_JOGGLE... parameters in user.h\n",
304     qh build_cnt, qh JOGGLEmax);
305     qh_errexit (qh_ERRqhull, NULL, NULL);
306     }
307     if (qh build_cnt && !restart)
308     break;
309     }else if (qh build_cnt && qh build_cnt >= qh RERUN)
310     break;
311     qh STOPcone= False;
312     qh_freebuild (True); /* first call is a nop */
313     qh build_cnt++;
314     if (!qh qhull_optionsiz)
315     qh qhull_optionsiz= strlen (qh qhull_options);
316     else {
317     qh qhull_options [qh qhull_optionsiz]= '\0';
318     qh qhull_optionlen= 80;
319     }
320     qh_option("_run", &qh build_cnt, NULL);
321     if (qh build_cnt == qh RERUN) {
322     qh IStracing= qh TRACElastrun; /* duplicated from qh_initqhull_globals */
323     if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
324     qh TRACElevel= (qh IStracing? qh IStracing : 3);
325     qh IStracing= 0;
326     }
327     qhmem.IStracing= qh IStracing;
328     }
329     if (qh JOGGLEmax < REALmax/2)
330     qh_joggleinput();
331     qh_initbuild();
332     qh_buildhull();
333     if (qh JOGGLEmax < REALmax/2 && !qh MERGING)
334     qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
335     }
336     qh ALLOWrestart= False;
337     } /* qh_build_withrestart */
338    
339     /*-<a href="qh-qhull.htm#TOC"
340     >-------------------------------</a><a name="buildhull">-</a>
341    
342     qh_buildhull()
343     construct a convex hull by adding outside points one at a time
344    
345     returns:
346    
347     notes:
348     may be called multiple times
349     checks facet and vertex lists for incorrect flags
350     to recover from STOPcone, call qh_deletevisible and qh_resetlists
351    
352     design:
353     check visible facet and newfacet flags
354     check newlist vertex flags and qh.STOPcone/STOPpoint
355     for each facet with a furthest outside point
356     add point to facet
357     exit if qh.STOPcone or qh.STOPpoint requested
358     if qh.NARROWhull for initial simplex
359     partition remaining outside points to coplanar sets
360     */
361     void qh_buildhull(void) {
362     facetT *facet;
363     pointT *furthest;
364     vertexT *vertex;
365     int id;
366    
367     trace1((qh ferr, "qh_buildhull: start build hull\n"));
368     FORALLfacets {
369     if (facet->visible || facet->newfacet) {
370     fprintf (qh ferr, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
371     facet->id);
372     qh_errexit (qh_ERRqhull, facet, NULL);
373     }
374     }
375     FORALLvertices {
376     if (vertex->newlist) {
377     fprintf (qh ferr, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
378     vertex->id);
379     qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
380     qh_errexit (qh_ERRqhull, NULL, NULL);
381     }
382     id= qh_pointid (vertex->point);
383     if ((qh STOPpoint>0 && id == qh STOPpoint-1) ||
384     (qh STOPpoint<0 && id == -qh STOPpoint-1) ||
385     (qh STOPcone>0 && id == qh STOPcone-1)) {
386     trace1((qh ferr,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
387     return;
388     }
389     }
390     qh facet_next= qh facet_list; /* advance facet when processed */
391     while ((furthest= qh_nextfurthest (&facet))) {
392     qh num_outside--; /* if ONLYmax, furthest may not be outside */
393     if (!qh_addpoint (furthest, facet, qh ONLYmax))
394     break;
395     }
396     if (qh NARROWhull) /* move points from outsideset to coplanarset */
397     qh_outcoplanar( /* facet_list */ );
398     if (qh num_outside && !furthest) {
399     fprintf (qh ferr, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside);
400     qh_errexit (qh_ERRqhull, NULL, NULL);
401     }
402     trace1((qh ferr, "qh_buildhull: completed the hull construction\n"));
403     } /* buildhull */
404    
405    
406     /*-<a href="qh-qhull.htm#TOC"
407     >-------------------------------</a><a name="buildtracing">-</a>
408    
409     qh_buildtracing( furthest, facet )
410     trace an iteration of qh_buildhull() for furthest point and facet
411     if !furthest, prints progress message
412    
413     returns:
414     tracks progress with qh.lastreport
415     updates qh.furthest_id (-3 if furthest is NULL)
416     also resets visit_id, vertext_visit on wrap around
417    
418     see:
419     qh_tracemerging()
420    
421     design:
422     if !furthest
423     print progress message
424     exit
425     if 'TFn' iteration
426     print progress message
427     else if tracing
428     trace furthest point and facet
429     reset qh.visit_id and qh.vertex_visit if overflow may occur
430     set qh.furthest_id for tracing
431     */
432     void qh_buildtracing (pointT *furthest, facetT *facet) {
433     realT dist= 0;
434     float cpu;
435     int total, furthestid;
436     time_t timedata;
437     struct tm *tp;
438     vertexT *vertex;
439    
440     qh old_randomdist= qh RANDOMdist;
441     qh RANDOMdist= False;
442     if (!furthest) {
443     time (&timedata);
444     tp= localtime (&timedata);
445     cpu= qh_CPUclock - qh hulltime;
446     cpu /= qh_SECticks;
447     total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
448     fprintf (qh ferr, "\n\
449     At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
450     The current hull contains %d facets and %d vertices. Last point was p%d\n",
451     tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
452     total, qh num_facets, qh num_vertices, qh furthest_id);
453     return;
454     }
455     furthestid= qh_pointid (furthest);
456     if (qh TRACEpoint == furthestid) {
457     qh IStracing= qh TRACElevel;
458     qhmem.IStracing= qh TRACElevel;
459     }else if (qh TRACEpoint != -1 && qh TRACEdist < REALmax/2) {
460     qh IStracing= 0;
461     qhmem.IStracing= 0;
462     }
463     if (qh REPORTfreq && (qh facet_id-1 > qh lastreport+qh REPORTfreq)) {
464     qh lastreport= qh facet_id-1;
465     time (&timedata);
466     tp= localtime (&timedata);
467     cpu= qh_CPUclock - qh hulltime;
468     cpu /= qh_SECticks;
469     total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
470     zinc_(Zdistio);
471     qh_distplane (furthest, facet, &dist);
472     fprintf (qh ferr, "\n\
473     At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
474     The current hull contains %d facets and %d vertices. There are %d\n\
475     outside points. Next is point p%d (v%d), %2.2g above f%d.\n",
476     tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1,
477     total, qh num_facets, qh num_vertices, qh num_outside+1,
478     furthestid, qh vertex_id, dist, getid_(facet));
479     }else if (qh IStracing >=1) {
480     cpu= qh_CPUclock - qh hulltime;
481     cpu /= qh_SECticks;
482     qh_distplane (furthest, facet, &dist);
483     fprintf (qh ferr, "qh_addpoint: add p%d (v%d) to hull of %d facets (%2.2g above f%d) and %d outside at %4.4g CPU secs. Previous was p%d.\n",
484     furthestid, qh vertex_id, qh num_facets, dist,
485     getid_(facet), qh num_outside+1, cpu, qh furthest_id);
486     }
487     if (qh visit_id > (unsigned) INT_MAX) {
488     qh visit_id= 0;
489     FORALLfacets
490     facet->visitid= qh visit_id;
491     }
492     if (qh vertex_visit > (unsigned) INT_MAX) {
493     qh vertex_visit= 0;
494     FORALLvertices
495     vertex->visitid= qh vertex_visit;
496     }
497     qh furthest_id= furthestid;
498     qh RANDOMdist= qh old_randomdist;
499     } /* buildtracing */
500    
501     /*-<a href="qh-qhull.htm#TOC"
502     >-------------------------------</a><a name="errexit2">-</a>
503    
504     qh_errexit2( exitcode, facet, otherfacet )
505     return exitcode to system after an error
506     report two facets
507    
508     returns:
509     assumes exitcode non-zero
510    
511     see:
512     normally use qh_errexit() in user.c (reports a facet and a ridge)
513     */
514     void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) {
515    
516     qh_errprint("ERRONEOUS", facet, otherfacet, NULL, NULL);
517     qh_errexit (exitcode, NULL, NULL);
518     } /* errexit2 */
519    
520    
521     /*-<a href="qh-qhull.htm#TOC"
522     >-------------------------------</a><a name="findhorizon">-</a>
523    
524     qh_findhorizon( point, facet, goodvisible, goodhorizon )
525     given a visible facet, find the point's horizon and visible facets
526     for all facets, !facet-visible
527    
528     returns:
529     returns qh.visible_list/num_visible with all visible facets
530     marks visible facets with ->visible
531     updates count of good visible and good horizon facets
532     updates qh.max_outside, qh.max_vertex, facet->maxoutside
533    
534     see:
535     similar to qh_delpoint()
536    
537     design:
538     move facet to qh.visible_list at end of qh.facet_list
539     for all visible facets
540     for each unvisited neighbor of a visible facet
541     compute distance of point to neighbor
542     if point above neighbor
543     move neighbor to end of qh.visible_list
544     else if point is coplanar with neighbor
545     update qh.max_outside, qh.max_vertex, neighbor->maxoutside
546     mark neighbor coplanar (will create a samecycle later)
547     update horizon statistics
548     */
549     void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
550     facetT *neighbor, **neighborp, *visible;
551     int numhorizon= 0, coplanar= 0;
552     realT dist;
553    
554     trace1((qh ferr,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id));
555     *goodvisible= *goodhorizon= 0;
556     zinc_(Ztotvisible);
557     qh_removefacet(facet); /* visible_list at end of qh facet_list */
558     qh_appendfacet(facet);
559     qh num_visible= 1;
560     if (facet->good)
561     (*goodvisible)++;
562     qh visible_list= facet;
563     facet->visible= True;
564     facet->f.replace= NULL;
565     if (qh IStracing >=4)
566     qh_errprint ("visible", facet, NULL, NULL, NULL);
567     qh visit_id++;
568     FORALLvisible_facets {
569     if (visible->tricoplanar && !qh TRInormals) {
570     fprintf (qh ferr, "qh_findhorizon: does not work for tricoplanar facets. Use option 'Q11'\n");
571     qh_errexit (qh_ERRqhull, visible, NULL);
572     }
573     visible->visitid= qh visit_id;
574     FOREACHneighbor_(visible) {
575     if (neighbor->visitid == qh visit_id)
576     continue;
577     neighbor->visitid= qh visit_id;
578     zzinc_(Znumvisibility);
579     qh_distplane(point, neighbor, &dist);
580     if (dist > qh MINvisible) {
581     zinc_(Ztotvisible);
582     qh_removefacet(neighbor); /* append to end of qh visible_list */
583     qh_appendfacet(neighbor);
584     neighbor->visible= True;
585     neighbor->f.replace= NULL;
586     qh num_visible++;
587     if (neighbor->good)
588     (*goodvisible)++;
589     if (qh IStracing >=4)
590     qh_errprint ("visible", neighbor, NULL, NULL, NULL);
591     }else {
592     if (dist > - qh MAXcoplanar) {
593     neighbor->coplanar= True;
594     zzinc_(Zcoplanarhorizon);
595     qh_precision ("coplanar horizon");
596     coplanar++;
597     if (qh MERGING) {
598     if (dist > 0) {
599     maximize_(qh max_outside, dist);
600     maximize_(qh max_vertex, dist);
601     #if qh_MAXoutside
602     maximize_(neighbor->maxoutside, dist);
603     #endif
604     }else
605     minimize_(qh min_vertex, dist); /* due to merge later */
606     }
607     trace2((qh ferr, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible (%2.7g)\n", qh_pointid(point), neighbor->id, dist, qh MINvisible));
608     }else
609     neighbor->coplanar= False;
610     zinc_(Ztothorizon);
611     numhorizon++;
612     if (neighbor->good)
613     (*goodhorizon)++;
614     if (qh IStracing >=4)
615     qh_errprint ("horizon", neighbor, NULL, NULL, NULL);
616     }
617     }
618     }
619     if (!numhorizon) {
620     qh_precision ("empty horizon");
621     fprintf(qh ferr, "qhull precision error (qh_findhorizon): empty horizon\n\
622     Point p%d was above all facets.\n", qh_pointid(point));
623     qh_printfacetlist (qh facet_list, NULL, True);
624     qh_errexit(qh_ERRprec, NULL, NULL);
625     }
626     trace1((qh ferr, "qh_findhorizon: %d horizon facets (good %d), %d visible (good %d), %d coplanar\n", numhorizon, *goodhorizon, qh num_visible, *goodvisible, coplanar));
627     if (qh IStracing >= 4 && qh num_facets < 50)
628     qh_printlists ();
629     } /* findhorizon */
630    
631     /*-<a href="qh-qhull.htm#TOC"
632     >-------------------------------</a><a name="nextfurthest">-</a>
633    
634     qh_nextfurthest( visible )
635     returns next furthest point and visible facet for qh_addpoint()
636     starts search at qh.facet_next
637    
638     returns:
639     removes furthest point from outside set
640     NULL if none available
641     advances qh.facet_next over facets with empty outside sets
642    
643     design:
644     for each facet from qh.facet_next
645     if empty outside set
646     advance qh.facet_next
647     else if qh.NARROWhull
648     determine furthest outside point
649     if furthest point is not outside
650     advance qh.facet_next (point will be coplanar)
651     remove furthest point from outside set
652     */
653     pointT *qh_nextfurthest (facetT **visible) {
654     facetT *facet;
655     int size, index;
656     realT randr, dist;
657     pointT *furthest;
658    
659     while ((facet= qh facet_next) != qh facet_tail) {
660     if (!facet->outsideset) {
661     qh facet_next= facet->next;
662     continue;
663     }
664     SETreturnsize_(facet->outsideset, size);
665     if (!size) {
666     qh_setfree (&facet->outsideset);
667     qh facet_next= facet->next;
668     continue;
669     }
670     if (qh NARROWhull) {
671     if (facet->notfurthest)
672     qh_furthestout (facet);
673     furthest= (pointT*)qh_setlast (facet->outsideset);
674     #if qh_COMPUTEfurthest
675     qh_distplane (furthest, facet, &dist);
676     zinc_(Zcomputefurthest);
677     #else
678     dist= facet->furthestdist;
679     #endif
680     if (dist < qh MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
681     qh facet_next= facet->next;
682     continue;
683     }
684     }
685     if (!qh RANDOMoutside && !qh VIRTUALmemory) {
686     if (qh PICKfurthest) {
687     qh_furthestnext (/* qh facet_list */);
688     facet= qh facet_next;
689     }
690     *visible= facet;
691     return ((pointT*)qh_setdellast (facet->outsideset));
692     }
693     if (qh RANDOMoutside) {
694     int outcoplanar = 0;
695     if (qh NARROWhull) {
696     FORALLfacets {
697     if (facet == qh facet_next)
698     break;
699     if (facet->outsideset)
700     outcoplanar += qh_setsize( facet->outsideset);
701     }
702     }
703     randr= qh_RANDOMint;
704     randr= randr/(qh_RANDOMmax+1);
705     index= (int)floor((qh num_outside - outcoplanar) * randr);
706     FORALLfacet_(qh facet_next) {
707     if (facet->outsideset) {
708     SETreturnsize_(facet->outsideset, size);
709     if (!size)
710     qh_setfree (&facet->outsideset);
711     else if (size > index) {
712     *visible= facet;
713     return ((pointT*)qh_setdelnth (facet->outsideset, index));
714     }else
715     index -= size;
716     }
717     }
718     fprintf (qh ferr, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n",
719     qh num_outside, index+1, randr);
720     qh_errexit (qh_ERRqhull, NULL, NULL);
721     }else { /* VIRTUALmemory */
722     facet= qh facet_tail->previous;
723     if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) {
724     if (facet->outsideset)
725     qh_setfree (&facet->outsideset);
726     qh_removefacet (facet);
727     qh_prependfacet (facet, &qh facet_list);
728     continue;
729     }
730     *visible= facet;
731     return furthest;
732     }
733     }
734     return NULL;
735     } /* nextfurthest */
736    
737     /*-<a href="qh-qhull.htm#TOC"
738     >-------------------------------</a><a name="partitionall">-</a>
739    
740     qh_partitionall( vertices, points, numpoints )
741     partitions all points in points/numpoints to the outsidesets of facets
742     vertices= vertices in qh.facet_list (not partitioned)
743    
744     returns:
745     builds facet->outsideset
746     does not partition qh.GOODpoint
747     if qh.ONLYgood && !qh.MERGING,
748     does not partition qh.GOODvertex
749    
750     notes:
751     faster if qh.facet_list sorted by anticipated size of outside set
752    
753     design:
754     initialize pointset with all points
755     remove vertices from pointset
756     remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
757     for all facets
758     for all remaining points in pointset
759     compute distance from point to facet
760     if point is outside facet
761     remove point from pointset (by not reappending)
762     update bestpoint
763     append point or old bestpoint to facet's outside set
764     append bestpoint to facet's outside set (furthest)
765     for all points remaining in pointset
766     partition point into facets' outside sets and coplanar sets
767     */
768     void qh_partitionall(setT *vertices, pointT *points, int numpoints){
769     setT *pointset;
770     vertexT *vertex, **vertexp;
771     pointT *point, **pointp, *bestpoint;
772     int size, point_i, point_n, point_end, remaining, i, id;
773     facetT *facet;
774     realT bestdist= -REALmax, dist, distoutside;
775    
776     trace1((qh ferr, "qh_partitionall: partition all points into outside sets\n"));
777     pointset= qh_settemp (numpoints);
778     qh num_outside= 0;
779     pointp= SETaddr_(pointset, pointT);
780     for (i=numpoints, point= points; i--; point += qh hull_dim)
781     *(pointp++)= point;
782     qh_settruncate (pointset, numpoints);
783     FOREACHvertex_(vertices) {
784     if ((id= qh_pointid(vertex->point)) >= 0)
785     SETelem_(pointset, id)= NULL;
786     }
787     id= qh_pointid (qh GOODpointp);
788     if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
789     SETelem_(pointset, id)= NULL;
790     if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/
791     if ((id= qh_pointid(qh GOODvertexp)) >= 0)
792     SETelem_(pointset, id)= NULL;
793     }
794     if (!qh BESToutside) { /* matches conditional for qh_partitionpoint below */
795     distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */
796     zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */
797     remaining= qh num_facets;
798     point_end= numpoints;
799     FORALLfacets {
800     size= point_end/(remaining--) + 100;
801     facet->outsideset= qh_setnew (size);
802     bestpoint= NULL;
803     point_end= 0;
804     FOREACHpoint_i_(pointset) {
805     if (point) {
806     zzinc_(Zpartitionall);
807     qh_distplane (point, facet, &dist);
808     if (dist < distoutside)
809     SETelem_(pointset, point_end++)= point;
810     else {
811     qh num_outside++;
812     if (!bestpoint) {
813     bestpoint= point;
814     bestdist= dist;
815     }else if (dist > bestdist) {
816     qh_setappend (&facet->outsideset, bestpoint);
817     bestpoint= point;
818     bestdist= dist;
819     }else
820     qh_setappend (&facet->outsideset, point);
821     }
822     }
823     }
824     if (bestpoint) {
825     qh_setappend (&facet->outsideset, bestpoint);
826     #if !qh_COMPUTEfurthest
827     facet->furthestdist= bestdist;
828     #endif
829     }else
830     qh_setfree (&facet->outsideset);
831     qh_settruncate (pointset, point_end);
832     }
833     }
834     /* if !qh BESToutside, pointset contains points not assigned to outsideset */
835     if (qh BESToutside || qh MERGING || qh KEEPcoplanar || qh KEEPinside) {
836     qh findbestnew= True;
837     FOREACHpoint_i_(pointset) {
838     if (point)
839     qh_partitionpoint(point, qh facet_list);
840     }
841     qh findbestnew= False;
842     }
843     zzadd_(Zpartitionall, zzval_(Zpartition));
844     zzval_(Zpartition)= 0;
845     qh_settempfree(&pointset);
846     if (qh IStracing >= 4)
847     qh_printfacetlist (qh facet_list, NULL, True);
848     } /* partitionall */
849    
850    
851     /*-<a href="qh-qhull.htm#TOC"
852     >-------------------------------</a><a name="partitioncoplanar">-</a>
853    
854     qh_partitioncoplanar( point, facet, dist )
855     partition coplanar point to a facet
856     dist is distance from point to facet
857     if dist NULL,
858     searches for bestfacet and does nothing if inside
859     if qh.findbestnew set,
860     searches new facets instead of using qh_findbest()
861    
862     returns:
863     qh.max_ouside updated
864     if qh.KEEPcoplanar or qh.KEEPinside
865     point assigned to best coplanarset
866    
867     notes:
868     facet->maxoutside is updated at end by qh_check_maxout
869    
870     design:
871     if dist undefined
872     find best facet for point
873     if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
874     exit
875     if keeping coplanar/nearinside/inside points
876     if point is above furthest coplanar point
877     append point to coplanar set (it is the new furthest)
878     update qh.max_outside
879     else
880     append point one before end of coplanar set
881     else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
882     and bestfacet is more than perpendicular to facet
883     repartition the point using qh_findbest() -- it may be put on an outsideset
884     else
885     update qh.max_outside
886     */
887     void qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist) {
888     facetT *bestfacet;
889     pointT *oldfurthest;
890     realT bestdist, dist2, angle;
891     int numpart= 0, oldfindbest;
892     boolT isoutside;
893    
894     qh WAScoplanar= True;
895     if (!dist) {
896     if (qh findbestnew)
897     bestfacet= qh_findbestnew (point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
898     else
899     bestfacet= qh_findbest (point, facet, qh_ALL, !qh_ISnewfacets, qh DELAUNAY,
900     &bestdist, &isoutside, &numpart);
901     zinc_(Ztotpartcoplanar);
902     zzadd_(Zpartcoplanar, numpart);
903     if (!qh DELAUNAY && !qh KEEPinside) { /* for 'd', bestdist skips upperDelaunay facets */
904     if (qh KEEPnearinside) {
905     if (bestdist < -qh NEARinside) {
906     zinc_(Zcoplanarinside);
907     trace4((qh ferr, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n", qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
908     return;
909     }
910     }else if (bestdist < -qh MAXcoplanar) {
911     trace4((qh ferr, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n", qh_pointid(point), bestfacet->id, bestdist, qh findbestnew));
912     zinc_(Zcoplanarinside);
913     return;
914     }
915     }
916     }else {
917     bestfacet= facet;
918     bestdist= *dist;
919     }
920     if (bestdist > qh max_outside) {
921     if (!dist && facet != bestfacet) {
922     zinc_(Zpartangle);
923     angle= qh_getangle(facet->normal, bestfacet->normal);
924     if (angle < 0) {
925     /* typically due to deleted vertex and coplanar facets, e.g.,
926     RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
927     zinc_(Zpartflip);
928     trace2((qh ferr, "qh_partitioncoplanar: repartition point p%d from f%d. It is above flipped facet f%d dist %2.2g\n", qh_pointid(point), facet->id, bestfacet->id, bestdist));
929     oldfindbest= qh findbestnew;
930     qh findbestnew= False;
931     qh_partitionpoint(point, bestfacet);
932     qh findbestnew= oldfindbest;
933     return;
934     }
935     }
936     qh max_outside= bestdist;
937     if (bestdist > qh TRACEdist) {
938     fprintf (qh ferr, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n",
939     qh_pointid(point), facet->id, bestdist, bestfacet->id, qh furthest_id);
940     qh_errprint ("DISTANT", facet, bestfacet, NULL, NULL);
941     }
942     }
943     if (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside) {
944     oldfurthest= (pointT*)qh_setlast (bestfacet->coplanarset);
945     if (oldfurthest) {
946     zinc_(Zcomputefurthest);
947     qh_distplane (oldfurthest, bestfacet, &dist2);
948     }
949     if (!oldfurthest || dist2 < bestdist)
950     qh_setappend(&bestfacet->coplanarset, point);
951     else
952     qh_setappend2ndlast(&bestfacet->coplanarset, point);
953     }
954     trace4((qh ferr, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n", qh_pointid(point), bestfacet->id, bestdist));
955     } /* partitioncoplanar */
956    
957     /*-<a href="qh-qhull.htm#TOC"
958     >-------------------------------</a><a name="partitionpoint">-</a>
959    
960     qh_partitionpoint( point, facet )
961     assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
962     if qh.findbestnew
963     uses qh_findbestnew() to search all new facets
964     else
965     uses qh_findbest()
966    
967     notes:
968     after qh_distplane(), this and qh_findbest() are most expensive in 3-d
969    
970     design:
971     find best facet for point
972     (either exhaustive search of new facets or directed search from facet)
973     if qh.NARROWhull
974     retain coplanar and nearinside points as outside points
975     if point is outside bestfacet
976     if point above furthest point for bestfacet
977     append point to outside set (it becomes the new furthest)
978     if outside set was empty
979     move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
980     update bestfacet->furthestdist
981     else
982     append point one before end of outside set
983     else if point is coplanar to bestfacet
984     if keeping coplanar points or need to update qh.max_outside
985     partition coplanar point into bestfacet
986     else if near-inside point
987     partition as coplanar point into bestfacet
988     else is an inside point
989     if keeping inside points
990     partition as coplanar point into bestfacet
991     */
992     void qh_partitionpoint (pointT *point, facetT *facet) {
993     realT bestdist;
994     boolT isoutside;
995     facetT *bestfacet;
996     int numpart;
997     #if qh_COMPUTEfurthest
998     realT dist;
999     #endif
1000    
1001     if (qh findbestnew)
1002     bestfacet= qh_findbestnew (point, facet, &bestdist, qh BESToutside, &isoutside, &numpart);
1003     else
1004     bestfacet= qh_findbest (point, facet, qh BESToutside, qh_ISnewfacets, !qh_NOupper,
1005     &bestdist, &isoutside, &numpart);
1006     zinc_(Ztotpartition);
1007     zzadd_(Zpartition, numpart);
1008     if (qh NARROWhull) {
1009     if (qh DELAUNAY && !isoutside && bestdist >= -qh MAXcoplanar)
1010     qh_precision ("nearly incident point (narrow hull)");
1011     if (qh KEEPnearinside) {
1012     if (bestdist >= -qh NEARinside)
1013     isoutside= True;
1014     }else if (bestdist >= -qh MAXcoplanar)
1015     isoutside= True;
1016     }
1017    
1018     if (isoutside) {
1019     if (!bestfacet->outsideset
1020     || !qh_setlast (bestfacet->outsideset)) {
1021     qh_setappend(&(bestfacet->outsideset), point);
1022     if (!bestfacet->newfacet) {
1023     qh_removefacet (bestfacet); /* make sure it's after qh facet_next */
1024     qh_appendfacet (bestfacet);
1025     }
1026     #if !qh_COMPUTEfurthest
1027     bestfacet->furthestdist= bestdist;
1028     #endif
1029     }else {
1030     #if qh_COMPUTEfurthest
1031     zinc_(Zcomputefurthest);
1032     qh_distplane (oldfurthest, bestfacet, &dist);
1033     if (dist < bestdist)
1034     qh_setappend(&(bestfacet->outsideset), point);
1035     else
1036     qh_setappend2ndlast(&(bestfacet->outsideset), point);
1037     #else
1038     if (bestfacet->furthestdist < bestdist) {
1039     qh_setappend(&(bestfacet->outsideset), point);
1040     bestfacet->furthestdist= bestdist;
1041     }else
1042     qh_setappend2ndlast(&(bestfacet->outsideset), point);
1043     #endif
1044     }
1045     qh num_outside++;
1046     trace4((qh ferr, "qh_partitionpoint: point p%d is outside facet f%d new? %d(or narrowhull)\n", qh_pointid(point), bestfacet->id, bestfacet->newfacet));
1047     }else if (qh DELAUNAY || bestdist >= -qh MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
1048     zzinc_(Zcoplanarpart);
1049     if (qh DELAUNAY)
1050     qh_precision ("nearly incident point");
1051     if ((qh KEEPcoplanar + qh KEEPnearinside) || bestdist > qh max_outside)
1052     qh_partitioncoplanar (point, bestfacet, &bestdist);
1053     else {
1054     trace4((qh ferr, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n", qh_pointid(point), bestfacet->id));
1055     }
1056     }else if (qh KEEPnearinside && bestdist > -qh NEARinside) {
1057     zinc_(Zpartnear);
1058     qh_partitioncoplanar (point, bestfacet, &bestdist);
1059     }else {
1060     zinc_(Zpartinside);
1061     trace4((qh ferr, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n", qh_pointid(point), bestfacet->id, bestdist));
1062     if (qh KEEPinside)
1063     qh_partitioncoplanar (point, bestfacet, &bestdist);
1064     }
1065     } /* partitionpoint */
1066    
1067     /*-<a href="qh-qhull.htm#TOC"
1068     >-------------------------------</a><a name="partitionvisible">-</a>
1069    
1070     qh_partitionvisible( allpoints, numoutside )
1071     partitions points in visible facets to qh.newfacet_list
1072     qh.visible_list= visible facets
1073     for visible facets
1074     1st neighbor (if any) points to a horizon facet or a new facet
1075     if allpoints (not used),
1076     repartitions coplanar points
1077    
1078     returns:
1079     updates outside sets and coplanar sets of qh.newfacet_list
1080     updates qh.num_outside (count of outside points)
1081    
1082     notes:
1083     qh.findbest_notsharp should be clear (extra work if set)
1084    
1085     design:
1086     for all visible facets with outside set or coplanar set
1087     select a newfacet for visible facet
1088     if outside set
1089     partition outside set into new facets
1090     if coplanar set and keeping coplanar/near-inside/inside points
1091     if allpoints
1092     partition coplanar set into new facets, may be assigned outside
1093     else
1094     partition coplanar set into coplanar sets of new facets
1095     for each deleted vertex
1096     if allpoints
1097     partition vertex into new facets, may be assigned outside
1098     else
1099     partition vertex into coplanar sets of new facets
1100     */
1101     void qh_partitionvisible(/*visible_list*/ boolT allpoints, int *numoutside) {
1102     facetT *visible, *newfacet;
1103     pointT *point, **pointp;
1104     int coplanar=0, size;
1105     unsigned count;
1106     vertexT *vertex, **vertexp;
1107    
1108     if (qh ONLYmax)
1109     maximize_(qh MINoutside, qh max_vertex);
1110     *numoutside= 0;
1111     FORALLvisible_facets {
1112     if (!visible->outsideset && !visible->coplanarset)
1113     continue;
1114     newfacet= visible->f.replace;
1115     count= 0;
1116     while (newfacet && newfacet->visible) {
1117     newfacet= newfacet->f.replace;
1118     if (count++ > qh facet_id)
1119     qh_infiniteloop (visible);
1120     }
1121     if (!newfacet)
1122     newfacet= qh newfacet_list;
1123     if (newfacet == qh facet_tail) {
1124     fprintf (qh ferr, "qhull precision error (qh_partitionvisible): all new facets deleted as\n degenerate facets. Can not continue.\n");
1125     qh_errexit (qh_ERRprec, NULL, NULL);
1126     }
1127     if (visible->outsideset) {
1128     size= qh_setsize (visible->outsideset);
1129     *numoutside += size;
1130     qh num_outside -= size;
1131     FOREACHpoint_(visible->outsideset)
1132     qh_partitionpoint (point, newfacet);
1133     }
1134     if (visible->coplanarset && (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside)) {
1135     size= qh_setsize (visible->coplanarset);
1136     coplanar += size;
1137     FOREACHpoint_(visible->coplanarset) {
1138     if (allpoints) /* not used */
1139     qh_partitionpoint (point, newfacet);
1140     else
1141     qh_partitioncoplanar (point, newfacet, NULL);
1142     }
1143     }
1144     }
1145     FOREACHvertex_(qh del_vertices) {
1146     if (vertex->point) {
1147     if (allpoints) /* not used */
1148     qh_partitionpoint (vertex->point, qh newfacet_list);
1149     else
1150     qh_partitioncoplanar (vertex->point, qh newfacet_list, NULL);
1151     }
1152     }
1153     trace1((qh ferr,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
1154     } /* partitionvisible */
1155    
1156    
1157    
1158     /*-<a href="qh-qhull.htm#TOC"
1159     >-------------------------------</a><a name="precision">-</a>
1160    
1161     qh_precision( reason )
1162     restart on precision errors if not merging and if 'QJn'
1163     */
1164     void qh_precision (char *reason) {
1165    
1166     if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) {
1167     if (qh JOGGLEmax < REALmax/2) {
1168     trace0((qh ferr, "qh_precision: qhull restart because of %s\n", reason));
1169     longjmp(qh restartexit, qh_ERRprec);
1170     }
1171     }
1172     } /* qh_precision */
1173    
1174     /*-<a href="qh-qhull.htm#TOC"
1175     >-------------------------------</a><a name="printsummary">-</a>
1176    
1177     qh_printsummary( fp )
1178     prints summary to fp
1179    
1180     notes:
1181     not in io.c so that user_eg.c can prevent io.c from loading
1182     qh_printsummary and qh_countfacets must match counts
1183    
1184     design:
1185     determine number of points, vertices, and coplanar points
1186     print summary
1187     */
1188     void qh_printsummary(FILE *fp) {
1189     realT ratio, outerplane, innerplane;
1190     float cpu;
1191     int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0;
1192     int goodused;
1193     facetT *facet;
1194     char *s;
1195     int numdel= zzval_(Zdelvertextot);
1196     int numtricoplanars= 0;
1197    
1198     size= qh num_points + qh_setsize (qh other_points);
1199     numvertices= qh num_vertices - qh_setsize (qh del_vertices);
1200     id= qh_pointid (qh GOODpointp);
1201     FORALLfacets {
1202     if (facet->coplanarset)
1203     numcoplanars += qh_setsize( facet->coplanarset);
1204     if (facet->good) {
1205     if (facet->simplicial) {
1206     if (facet->keepcentrum && facet->tricoplanar)
1207     numtricoplanars++;
1208     }else if (qh_setsize(facet->vertices) != qh hull_dim)
1209     nonsimplicial++;
1210     }
1211     }
1212     if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
1213     size--;
1214     if (qh STOPcone || qh STOPpoint)
1215     fprintf (fp, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error.");
1216     if (qh UPPERdelaunay)
1217     goodused= qh GOODvertex + qh GOODpoint + qh SPLITthresholds;
1218     else if (qh DELAUNAY)
1219     goodused= qh GOODvertex + qh GOODpoint + qh GOODthreshold;
1220     else
1221     goodused= qh num_good;
1222     nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
1223     if (qh VORONOI) {
1224     if (qh UPPERdelaunay)
1225     fprintf (fp, "\n\
1226     Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
1227     else
1228     fprintf (fp, "\n\
1229     Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
1230     fprintf(fp, " Number of Voronoi regions%s: %d\n",
1231     qh ATinfinity ? " and at-infinity" : "", numvertices);
1232     if (numdel)
1233     fprintf(fp, " Total number of deleted points due to merging: %d\n", numdel);
1234     if (numcoplanars - numdel > 0)
1235     fprintf(fp, " Number of nearly incident points: %d\n", numcoplanars - numdel);
1236     else if (size - numvertices - numdel > 0)
1237     fprintf(fp, " Total number of nearly incident points: %d\n", size - numvertices - numdel);
1238     fprintf(fp, " Number of%s Voronoi vertices: %d\n",
1239     goodused ? " 'good'" : "", qh num_good);
1240     if (nonsimplicial)
1241     fprintf(fp, " Number of%s non-simplicial Voronoi vertices: %d\n",
1242     goodused ? " 'good'" : "", nonsimplicial);
1243     }else if (qh DELAUNAY) {
1244     if (qh UPPERdelaunay)
1245     fprintf (fp, "\n\
1246     Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
1247     else
1248     fprintf (fp, "\n\
1249     Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
1250     fprintf(fp, " Number of input sites%s: %d\n",
1251     qh ATinfinity ? " and at-infinity" : "", numvertices);
1252     if (numdel)
1253     fprintf(fp, " Total number of deleted points due to merging: %d\n", numdel);
1254     if (numcoplanars - numdel > 0)
1255     fprintf(fp, " Number of nearly incident points: %d\n", numcoplanars - numdel);
1256     else if (size - numvertices - numdel > 0)
1257     fprintf(fp, " Total number of nearly incident points: %d\n", size - numvertices - numdel);
1258     fprintf(fp, " Number of%s Delaunay regions: %d\n",
1259     goodused ? " 'good'" : "", qh num_good);
1260     if (nonsimplicial)
1261     fprintf(fp, " Number of%s non-simplicial Delaunay regions: %d\n",
1262     goodused ? " 'good'" : "", nonsimplicial);
1263     }else if (qh HALFspace) {
1264     fprintf (fp, "\n\
1265     Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
1266     fprintf(fp, " Number of halfspaces: %d\n", size);
1267     fprintf(fp, " Number of non-redundant halfspaces: %d\n", numvertices);
1268     if (numcoplanars) {
1269     if (qh KEEPinside && qh KEEPcoplanar)
1270     s= "similar and redundant";
1271     else if (qh KEEPinside)
1272     s= "redundant";
1273     else
1274     s= "similar";
1275     fprintf(fp, " Number of %s halfspaces: %d\n", s, numcoplanars);
1276     }
1277     fprintf(fp, " Number of intersection points: %d\n", qh num_facets - qh num_visible);
1278     if (goodused)
1279     fprintf(fp, " Number of 'good' intersection points: %d\n", qh num_good);
1280     if (nonsimplicial)
1281     fprintf(fp, " Number of%s non-simplicial intersection points: %d\n",
1282     goodused ? " 'good'" : "", nonsimplicial);
1283     }else {
1284     fprintf (fp, "\n\
1285     Convex hull of %d points in %d-d:\n\n", size, qh hull_dim);
1286     fprintf(fp, " Number of vertices: %d\n", numvertices);
1287     if (numcoplanars) {
1288     if (qh KEEPinside && qh KEEPcoplanar)
1289     s= "coplanar and interior";
1290     else if (qh KEEPinside)
1291     s= "interior";
1292     else
1293     s= "coplanar";
1294     fprintf(fp, " Number of %s points: %d\n", s, numcoplanars);
1295     }
1296     fprintf(fp, " Number of facets: %d\n", qh num_facets - qh num_visible);
1297     if (goodused)
1298     fprintf(fp, " Number of 'good' facets: %d\n", qh num_good);
1299     if (nonsimplicial)
1300     fprintf(fp, " Number of%s non-simplicial facets: %d\n",
1301     goodused ? " 'good'" : "", nonsimplicial);
1302     }
1303     if (numtricoplanars)
1304     fprintf(fp, " Number of triangulated facets: %d\n", numtricoplanars);
1305     fprintf(fp, "\nStatistics for: %s | %s",
1306     qh rbox_command, qh qhull_command);
1307     if (qh ROTATErandom != INT_MIN)
1308     fprintf(fp, " QR%d\n\n", qh ROTATErandom);
1309     else
1310     fprintf(fp, "\n\n");
1311     fprintf(fp, " Number of points processed: %d\n", zzval_(Zprocessed));
1312     fprintf(fp, " Number of hyperplanes created: %d\n", zzval_(Zsetplane));
1313     if (qh DELAUNAY)
1314     fprintf(fp, " Number of facets in hull: %d\n", qh num_facets - qh num_visible);
1315     fprintf(fp, " Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
1316     zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
1317     #if 0
1318     /* NOTE: must print before printstatistics() */
1319     {realT stddev, ave;
1320     fprintf(fp, " average new facet balance: %2.2g\n",
1321     wval_(Wnewbalance)/zval_(Zprocessed));
1322     stddev= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance),
1323     wval_(Wnewbalance2), &ave);
1324     fprintf(fp, " new facet standard deviation: %2.2g\n", stddev);
1325     fprintf(fp, " average partition balance: %2.2g\n",
1326     wval_(Wpbalance)/zval_(Zpbalance));
1327     stddev= qh_stddev (zval_(Zpbalance), wval_(Wpbalance),
1328     wval_(Wpbalance2), &ave);
1329     fprintf(fp, " partition standard deviation: %2.2g\n", stddev);
1330     }
1331     #endif
1332     if (nummerged) {
1333     fprintf(fp," Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
1334     zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+
1335     zzval_(Zdistzero));
1336     fprintf(fp," Number of distance tests for checking: %d\n",zzval_(Zcheckpart));
1337     fprintf(fp," Number of merged facets: %d\n", nummerged);
1338     }
1339     if (!qh RANDOMoutside && qh QHULLfinished) {
1340     cpu= qh hulltime;
1341     cpu /= qh_SECticks;
1342     wval_(Wcpu)= cpu;
1343     fprintf (fp, " CPU seconds to compute hull (after input): %2.4g\n", cpu);
1344     }
1345     if (qh RERUN) {
1346     if (!qh PREmerge && !qh MERGEexact)
1347     fprintf(fp, " Percentage of runs with precision errors: %4.1f\n",
1348     zzval_(Zretry)*100.0/qh build_cnt); /* careful of order */
1349     }else if (qh JOGGLEmax < REALmax/2) {
1350     if (zzval_(Zretry))
1351     fprintf(fp, " After %d retries, input joggled by: %2.2g\n",
1352     zzval_(Zretry), qh JOGGLEmax);
1353     else
1354     fprintf(fp, " Input joggled by: %2.2g\n", qh JOGGLEmax);
1355     }
1356     if (qh totarea != 0.0)
1357     fprintf(fp, " %s facet area: %2.8g\n",
1358     zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea);
1359     if (qh totvol != 0.0)
1360     fprintf(fp, " %s volume: %2.8g\n",
1361     zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol);
1362     if (qh MERGING) {
1363     qh_outerinner (NULL, &outerplane, &innerplane);
1364     if (outerplane > 2 * qh DISTround) {
1365     fprintf(fp, " Maximum distance of %spoint above facet: %2.2g",
1366     (qh QHULLfinished ? "" : "merged "), outerplane);
1367     ratio= outerplane/(qh ONEmerge + qh DISTround);
1368     /* don't report ratio if MINoutside is large */
1369     if (ratio > 0.05 && 2* qh ONEmerge > qh MINoutside && qh JOGGLEmax > REALmax/2)
1370     fprintf (fp, " (%.1fx)\n", ratio);
1371     else
1372     fprintf (fp, "\n");
1373     }
1374     if (innerplane < -2 * qh DISTround) {
1375     fprintf(fp, " Maximum distance of %svertex below facet: %2.2g",
1376     (qh QHULLfinished ? "" : "merged "), innerplane);
1377     ratio= -innerplane/(qh ONEmerge+qh DISTround);
1378     if (ratio > 0.05 && qh JOGGLEmax > REALmax/2)
1379     fprintf (fp, " (%.1fx)\n", ratio);
1380     else
1381     fprintf (fp, "\n");
1382     }
1383     }
1384     fprintf(fp, "\n");
1385     } /* printsummary */
1386    
1387