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