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