ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/QuickHull/qhull.c
Revision: 3138
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

# Content
1 /*<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