Line data Source code
1 : /*<html><pre> -<a href="qh-qhull_r.htm"
2 : >-------------------------------</a><a name="TOP">-</a>
3 :
4 : libqhull_r.c
5 : Quickhull algorithm for convex hulls
6 :
7 : qhull() and top-level routines
8 :
9 : see qh-qhull_r.htm, libqhull_r.h, unix_r.c
10 :
11 : see qhull_ra.h for internal functions
12 :
13 : Copyright (c) 1993-2020 The Geometry Center.
14 : $Id: //main/2019/qhull/src/libqhull_r/libqhull_r.c#17 $$Change: 2953 $
15 : $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
16 : */
17 :
18 : #include "qhull_ra.h"
19 :
20 : /*============= functions in alphabetic order after qhull() =======*/
21 :
22 : /*-<a href="qh-qhull_r.htm#TOC"
23 : >-------------------------------</a><a name="qhull">-</a>
24 :
25 : qh_qhull(qh)
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 4 : void qh_qhull(qhT *qh) {
61 : int numoutside;
62 :
63 4 : qh->hulltime= qh_CPUclock;
64 4 : if (qh->RERUN || qh->JOGGLEmax < REALmax/2)
65 0 : qh_build_withrestart(qh);
66 : else {
67 4 : qh_initbuild(qh);
68 3 : qh_buildhull(qh);
69 : }
70 3 : if (!qh->STOPadd && !qh->STOPcone && !qh->STOPpoint) {
71 3 : if (qh->ZEROall_ok && !qh->TESTvneighbors && qh->MERGEexact)
72 0 : qh_checkzero(qh, qh_ALL);
73 3 : if (qh->ZEROall_ok && !qh->TESTvneighbors && !qh->WAScoplanar) {
74 0 : trace2((qh, qh->ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points. Post-merging and check of maxout not needed.\n"));
75 0 : qh->DOcheckmax= False;
76 : }else {
77 3 : qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
78 3 : if (qh->MERGEexact || (qh->hull_dim > qh_DIMreduceBuild && qh->PREmerge))
79 0 : qh_postmerge(qh, "First post-merge", qh->premerge_centrum, qh->premerge_cos,
80 0 : (qh->POSTmerge ? False : qh->TESTvneighbors)); /* calls qh_reducevertices */
81 3 : else if (!qh->POSTmerge && qh->TESTvneighbors)
82 0 : qh_postmerge(qh, "For testing vertex neighbors", qh->premerge_centrum,
83 : qh->premerge_cos, True); /* calls qh_test_vneighbors */
84 3 : if (qh->POSTmerge)
85 0 : qh_postmerge(qh, "For post-merging", qh->postmerge_centrum,
86 : qh->postmerge_cos, qh->TESTvneighbors);
87 3 : if (qh->visible_list == qh->facet_list) { /* qh_postmerge was called */
88 0 : qh->findbestnew= True;
89 0 : qh_partitionvisible(qh, !qh_ALL, &numoutside /* qh.visible_list */);
90 0 : qh->findbestnew= False;
91 0 : qh_deletevisible(qh /* qh.visible_list */); /* stops at first !f.visible */
92 0 : qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
93 : }
94 3 : qh_all_vertexmerges(qh, -1, NULL, NULL);
95 3 : qh_freemergesets(qh);
96 : }
97 3 : if (qh->TRACEpoint == qh_IDunknown && qh->TRACElevel > qh->IStracing) {
98 0 : qh->IStracing= qh->TRACElevel;
99 0 : qh_fprintf(qh, qh->ferr, 2112, "qh_qhull: finished qh_buildhull and qh_postmerge, start tracing (TP-1)\n");
100 : }
101 3 : if (qh->DOcheckmax){
102 3 : if (qh->REPORTfreq) {
103 0 : qh_buildtracing(qh, NULL, NULL);
104 0 : qh_fprintf(qh, qh->ferr, 8115, "\nTesting all coplanar points.\n");
105 : }
106 3 : qh_check_maxout(qh);
107 : }
108 3 : if (qh->KEEPnearinside && !qh->maxoutdone)
109 0 : qh_nearcoplanar(qh);
110 : }
111 3 : if (qh_setsize(qh, qh->qhmem.tempstack) != 0) {
112 0 : qh_fprintf(qh, qh->ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d) at end of Qhull\n",
113 : qh_setsize(qh, qh->qhmem.tempstack));
114 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
115 : }
116 3 : qh->hulltime= qh_CPUclock - qh->hulltime;
117 3 : qh->QHULLfinished= True;
118 3 : trace1((qh, qh->ferr, 1036, "Qhull: algorithm completed\n"));
119 3 : } /* qhull */
120 :
121 : /*-<a href="qh-qhull_r.htm#TOC"
122 : >-------------------------------</a><a name="addpoint">-</a>
123 :
124 : qh_addpoint(qh, furthest, facet, checkdist )
125 : add point (usually furthest point) above facet to hull
126 : if checkdist,
127 : check that point is above facet.
128 : if point is not outside of the hull, uses qh_partitioncoplanar()
129 : assumes that facet is defined by qh_findbestfacet()
130 : else if facet specified,
131 : assumes that point is above facet (major damage if below)
132 : for Delaunay triangulations,
133 : Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed
134 : Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates.
135 :
136 : returns:
137 : returns False if user requested an early termination
138 : qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined
139 : updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
140 : clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside)
141 : if unknown point, adds a pointer to qh.other_points
142 : do not deallocate the point's coordinates
143 :
144 : notes:
145 : called from qh_initbuild, qh_buildhull, and qh_addpoint
146 : tail recursive call if merged a pinchedvertex due to a duplicated ridge
147 : no more than qh.num_vertices calls (QH6296)
148 : assumes point is near its best facet and not at a local minimum of a lens
149 : distributions. Use qh_findbestfacet to avoid this case.
150 : uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets
151 : if called from a user application after qh_qhull and 'QJ' (joggle),
152 : facet merging for precision problems is disabled by default
153 :
154 : design:
155 : exit if qh.STOPadd vertices 'TAn'
156 : add point to other_points if needed
157 : if checkdist
158 : if point not above facet
159 : partition coplanar point
160 : exit
161 : exit if pre STOPpoint requested
162 : find horizon and visible facets for point
163 : build cone of new facets to the horizon
164 : exit if build cone fails due to qh.ONLYgood
165 : tail recursive call if build cone fails due to pinched vertices
166 : exit if STOPcone requested
167 : merge non-convex new facets
168 : if merge found, many merges, or 'Qf'
169 : use qh_findbestnew() instead of qh_findbest()
170 : partition outside points from visible facets
171 : delete visible facets
172 : check polyhedron if requested
173 : exit if post STOPpoint requested
174 : reset working lists of facets and vertices
175 : */
176 14660 : boolT qh_addpoint(qhT *qh, pointT *furthest, facetT *facet, boolT checkdist) {
177 : realT dist, pbalance;
178 : facetT *replacefacet, *newfacet;
179 : vertexT *apex;
180 14660 : boolT isoutside= False;
181 : int numpart, numpoints, goodvisible, goodhorizon, apexpointid;
182 :
183 14660 : qh->maxoutdone= False;
184 14660 : if (qh_pointid(qh, furthest) == qh_IDunknown)
185 0 : qh_setappend(qh, &qh->other_points, furthest);
186 14660 : if (!facet) {
187 0 : qh_fprintf(qh, qh->ferr, 6213, "qhull internal error (qh_addpoint): NULL facet. Need to call qh_findbestfacet first\n");
188 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
189 : }
190 14660 : qh_detmaxoutside(qh);
191 14660 : if (checkdist) {
192 0 : facet= qh_findbest(qh, furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper,
193 : &dist, &isoutside, &numpart);
194 0 : zzadd_(Zpartition, numpart);
195 0 : if (!isoutside) {
196 0 : zinc_(Znotmax); /* last point of outsideset is no longer furthest. */
197 0 : facet->notfurthest= True;
198 0 : qh_partitioncoplanar(qh, furthest, facet, &dist, qh->findbestnew);
199 0 : return True;
200 : }
201 : }
202 14660 : qh_buildtracing(qh, furthest, facet);
203 14660 : if (qh->STOPpoint < 0 && qh->furthest_id == -qh->STOPpoint-1) {
204 0 : facet->notfurthest= True;
205 0 : return False;
206 : }
207 14660 : qh_findhorizon(qh, furthest, facet, &goodvisible, &goodhorizon);
208 14660 : if (qh->ONLYgood && !qh->GOODclosest && !(goodvisible+goodhorizon)) {
209 0 : zinc_(Znotgood);
210 0 : facet->notfurthest= True;
211 : /* last point of outsideset is no longer furthest. This is ok
212 : since all points of the outside are likely to be bad */
213 0 : qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
214 0 : return True;
215 : }
216 14660 : apex= qh_buildcone(qh, furthest, facet, goodhorizon, &replacefacet);
217 : /* qh.newfacet_list, visible_list, newvertex_list */
218 14660 : if (!apex) {
219 0 : if (qh->ONLYgood)
220 0 : return True; /* ignore this furthest point, a good new facet was not found */
221 0 : if (replacefacet) {
222 0 : if (qh->retry_addpoint++ >= qh->num_vertices) {
223 0 : qh_fprintf(qh, qh->ferr, 6296, "qhull internal error (qh_addpoint): infinite loop (%d retries) of merging pinched vertices due to dupridge for point p%d, facet f%d, and %d vertices\n",
224 : qh->retry_addpoint, qh_pointid(qh, furthest), facet->id, qh->num_vertices);
225 0 : qh_errexit(qh, qh_ERRqhull, facet, NULL);
226 : }
227 : /* retry qh_addpoint after resolving a dupridge via qh_merge_pinchedvertices */
228 0 : return qh_addpoint(qh, furthest, replacefacet, True /* checkdisk */);
229 : }
230 0 : qh->retry_addpoint= 0;
231 0 : return True; /* ignore this furthest point, resolved a dupridge by making furthest a coplanar point */
232 : }
233 14660 : if (qh->retry_addpoint) {
234 0 : zinc_(Zretryadd);
235 0 : zadd_(Zretryaddtot, qh->retry_addpoint);
236 0 : zmax_(Zretryaddmax, qh->retry_addpoint);
237 0 : qh->retry_addpoint= 0;
238 : }
239 14660 : apexpointid= qh_pointid(qh, apex->point);
240 14660 : zzinc_(Zprocessed);
241 14660 : if (qh->STOPcone && qh->furthest_id == qh->STOPcone-1) {
242 0 : facet->notfurthest= True;
243 0 : return False; /* visible_list etc. still defined */
244 : }
245 14660 : qh->findbestnew= False;
246 14660 : if (qh->PREmerge || qh->MERGEexact) {
247 14660 : qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
248 14660 : qh_premerge(qh, apexpointid, qh->premerge_centrum, qh->premerge_cos /* qh.newfacet_list */);
249 14660 : if (qh_USEfindbestnew)
250 14603 : qh->findbestnew= True;
251 : else {
252 237 : FORALLnew_facets {
253 210 : if (!newfacet->simplicial) {
254 30 : qh->findbestnew= True; /* use qh_findbestnew instead of qh_findbest*/
255 30 : break;
256 : }
257 : }
258 : }
259 0 : }else if (qh->BESToutside)
260 0 : qh->findbestnew= True;
261 14660 : if (qh->IStracing >= 4)
262 0 : qh_checkpolygon(qh, qh->visible_list);
263 14660 : qh_partitionvisible(qh, !qh_ALL, &numpoints /* qh.visible_list */);
264 14660 : qh->findbestnew= False;
265 14660 : qh->findbest_notsharp= False;
266 14660 : zinc_(Zpbalance);
267 14660 : pbalance= numpoints - (realT) qh->hull_dim /* assumes all points extreme */
268 14660 : * (qh->num_points - qh->num_vertices)/qh->num_vertices;
269 14660 : wadd_(Wpbalance, pbalance);
270 14660 : wadd_(Wpbalance2, pbalance * pbalance);
271 14660 : qh_deletevisible(qh /* qh.visible_list */);
272 14660 : zmax_(Zmaxvertex, qh->num_vertices);
273 14660 : qh->NEWfacets= False;
274 14660 : if (qh->IStracing >= 4) {
275 0 : if (qh->num_facets < 200)
276 0 : qh_printlists(qh);
277 0 : qh_printfacetlist(qh, qh->newfacet_list, NULL, True);
278 0 : qh_checkpolygon(qh, qh->facet_list);
279 14660 : }else if (qh->CHECKfrequently) {
280 0 : if (qh->num_facets < 1000)
281 0 : qh_checkpolygon(qh, qh->facet_list);
282 : else
283 0 : qh_checkpolygon(qh, qh->newfacet_list);
284 : }
285 14660 : if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1 && qh_setsize(qh, qh->vertex_mergeset) > 0)
286 0 : return False;
287 14660 : qh_resetlists(qh, True, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
288 14660 : if (qh->facet_mergeset) {
289 : /* vertex merges occur after facet merges (qh_premerge) and qh_resetlists */
290 14660 : qh_all_vertexmerges(qh, apexpointid, NULL, NULL);
291 14660 : qh_freemergesets(qh);
292 : }
293 : /* qh_triangulate(qh); to test qh.TRInormals */
294 14660 : if (qh->STOPpoint > 0 && qh->furthest_id == qh->STOPpoint-1)
295 0 : return False;
296 14660 : trace2((qh, qh->ferr, 2056, "qh_addpoint: added p%d to convex hull with point balance %2.2g\n",
297 : qh_pointid(qh, furthest), pbalance));
298 14660 : return True;
299 : } /* addpoint */
300 :
301 : /*-<a href="qh-qhull_r.htm#TOC"
302 : >-------------------------------</a><a name="build_withrestart">-</a>
303 :
304 : qh_build_withrestart(qh)
305 : allow restarts due to qh.JOGGLEmax while calling qh_buildhull()
306 : qh_errexit always undoes qh_build_withrestart()
307 : qh.FIRSTpoint/qh.NUMpoints is point array
308 : it may be moved by qh_joggleinput
309 : */
310 0 : void qh_build_withrestart(qhT *qh) {
311 : int restart;
312 : vertexT *vertex, **vertexp;
313 :
314 0 : qh->ALLOWrestart= True;
315 : while (True) {
316 0 : restart= setjmp(qh->restartexit); /* simple statement for CRAY J916 */
317 0 : if (restart) { /* only from qh_joggle_restart() */
318 0 : qh->last_errcode= qh_ERRnone;
319 0 : zzinc_(Zretry);
320 0 : wmax_(Wretrymax, qh->JOGGLEmax);
321 : /* QH7078 warns about using 'TCn' with 'QJn' */
322 0 : qh->STOPcone= qh_IDunknown; /* if break from joggle, prevents normal output */
323 0 : FOREACHvertex_(qh->del_vertices) {
324 0 : if (vertex->point && !vertex->partitioned)
325 0 : vertex->partitioned= True; /* avoid error in qh_freebuild -> qh_delvertex */
326 : }
327 : }
328 0 : if (!qh->RERUN && qh->JOGGLEmax < REALmax/2) {
329 0 : if (qh->build_cnt > qh_JOGGLEmaxretry) {
330 0 : qh_fprintf(qh, qh->ferr, 6229, "qhull input error: %d attempts to construct a convex hull with joggled input. Increase joggle above 'QJ%2.2g' or modify qh_JOGGLE... parameters in user_r.h\n",
331 : qh->build_cnt, qh->JOGGLEmax);
332 0 : qh_errexit(qh, qh_ERRinput, NULL, NULL);
333 : }
334 0 : if (qh->build_cnt && !restart)
335 0 : break;
336 0 : }else if (qh->build_cnt && qh->build_cnt >= qh->RERUN)
337 0 : break;
338 0 : qh->STOPcone= 0;
339 0 : qh_freebuild(qh, True); /* first call is a nop */
340 0 : qh->build_cnt++;
341 0 : if (!qh->qhull_optionsiz)
342 0 : qh->qhull_optionsiz= (int)strlen(qh->qhull_options); /* WARN64 */
343 : else {
344 0 : qh->qhull_options[qh->qhull_optionsiz]= '\0';
345 0 : qh->qhull_optionlen= qh_OPTIONline; /* starts a new line */
346 : }
347 0 : qh_option(qh, "_run", &qh->build_cnt, NULL);
348 0 : if (qh->build_cnt == qh->RERUN) {
349 0 : qh->IStracing= qh->TRACElastrun; /* duplicated from qh_initqhull_globals */
350 0 : if (qh->TRACEpoint != qh_IDnone || qh->TRACEdist < REALmax/2 || qh->TRACEmerge) {
351 0 : qh->TRACElevel= (qh->IStracing? qh->IStracing : 3);
352 0 : qh->IStracing= 0;
353 : }
354 0 : qh->qhmem.IStracing= qh->IStracing;
355 : }
356 0 : if (qh->JOGGLEmax < REALmax/2)
357 0 : qh_joggleinput(qh);
358 0 : qh_initbuild(qh);
359 0 : qh_buildhull(qh);
360 0 : if (qh->JOGGLEmax < REALmax/2 && !qh->MERGING)
361 0 : qh_checkconvex(qh, qh->facet_list, qh_ALGORITHMfault);
362 : }
363 0 : qh->ALLOWrestart= False;
364 0 : } /* qh_build_withrestart */
365 :
366 : /*-<a href="qh-qhull_r.htm#TOC"
367 : >-------------------------------</a><a name="buildcone">-</a>
368 :
369 : qh_buildcone(qh, furthest, facet, goodhorizon, &replacefacet )
370 : build cone of new facets from furthest to the horizon
371 : goodhorizon is count of good, horizon facets from qh_find_horizon
372 :
373 : returns:
374 : returns apex of cone with qh.newfacet_list and qh.first_newfacet (f.id)
375 : returns NULL if qh.ONLYgood and no good facets
376 : returns NULL and retryfacet if merging pinched vertices will resolve a dupridge
377 : a horizon vertex was nearly adjacent to another vertex
378 : will retry qh_addpoint
379 : returns NULL if resolve a dupridge by making furthest a coplanar point
380 : furthest was nearly adjacent to an existing vertex
381 : updates qh.degen_mergeset (MRGridge) if resolve a dupridge by merging facets
382 : updates qh.newfacet_list, visible_list, newvertex_list
383 : updates qh.facet_list, vertex_list, num_facets, num_vertices
384 :
385 : notes:
386 : called by qh_addpoint
387 : see qh_triangulate, it triangulates non-simplicial facets in post-processing
388 :
389 : design:
390 : make new facets for point to horizon
391 : compute balance statistics
392 : make hyperplanes for point
393 : exit if qh.ONLYgood and not good (qh_buildcone_onlygood)
394 : match neighboring new facets
395 : if dupridges
396 : exit if !qh.IGNOREpinched and dupridge resolved by coplanar furthest
397 : retry qh_buildcone if !qh.IGNOREpinched and dupridge resolved by qh_buildcone_mergepinched
398 : otherwise dupridges resolved by merging facets
399 : update vertex neighbors and delete interior vertices
400 : */
401 14660 : vertexT *qh_buildcone(qhT *qh, pointT *furthest, facetT *facet, int goodhorizon, facetT **retryfacet) {
402 : vertexT *apex;
403 : realT newbalance;
404 : int numnew;
405 :
406 14660 : *retryfacet= NULL;
407 14660 : qh->first_newfacet= qh->facet_id;
408 14660 : qh->NEWtentative= (qh->MERGEpinched || qh->ONLYgood); /* cleared by qh_attachnewfacets or qh_resetlists */
409 14660 : apex= qh_makenewfacets(qh, furthest /* qh.newfacet_list visible_list, attaches new facets if !qh.NEWtentative */);
410 14660 : numnew= (int)(qh->facet_id - qh->first_newfacet);
411 14660 : newbalance= numnew - (realT)(qh->num_facets - qh->num_visible) * qh->hull_dim / qh->num_vertices;
412 : /* newbalance statistics updated below if the new facets are accepted */
413 14660 : if (qh->ONLYgood) { /* qh.MERGEpinched is false by QH6362 */
414 0 : if (!qh_buildcone_onlygood(qh, apex, goodhorizon /* qh.newfacet_list */)) {
415 0 : facet->notfurthest= True;
416 0 : return NULL;
417 : }
418 14660 : }else if(qh->MERGEpinched) {
419 : #ifndef qh_NOmerge
420 0 : if (qh_buildcone_mergepinched(qh, apex, facet, retryfacet /* qh.newfacet_list */))
421 0 : return NULL;
422 : #else
423 : qh_fprintf(qh, qh->ferr, 6375, "qhull option error (qh_buildcone): option 'Q14' (qh.MERGEpinched) is not available due to qh_NOmerge\n");
424 : qh_errexit(qh, qh_ERRinput, NULL, NULL);
425 : #endif
426 : }else {
427 : /* qh_makenewfacets attached new facets to the horizon */
428 14660 : qh_matchnewfacets(qh); /* ignore returned value. qh_forcedmerges will merge dupridges if any */
429 14660 : qh_makenewplanes(qh /* qh.newfacet_list */);
430 14660 : qh_update_vertexneighbors_cone(qh);
431 : }
432 14660 : wadd_(Wnewbalance, newbalance);
433 14660 : wadd_(Wnewbalance2, newbalance * newbalance);
434 14660 : trace2((qh, qh->ferr, 2067, "qh_buildcone: created %d newfacets for p%d(v%d) new facet balance %2.2g\n",
435 : numnew, qh_pointid(qh, furthest), apex->id, newbalance));
436 14660 : return apex;
437 : } /* buildcone */
438 :
439 : #ifndef qh_NOmerge
440 : /*-<a href="qh-qhull_r.htm#TOC"
441 : >-------------------------------</a><a name="buildcone_mergepinched">-</a>
442 :
443 : qh_buildcone_mergepinched(qh, apex, facet, maxdupdist, &retryfacet )
444 : build cone of new facets from furthest to the horizon
445 : maxdupdist>0.0 for merging dupridges (qh_matchdupridge)
446 :
447 : returns:
448 : returns True if merged a pinched vertex and deleted the cone of new facets
449 : if retryfacet is set
450 : a dupridge was resolved by qh_merge_pinchedvertices
451 : retry qh_addpoint
452 : otherwise
453 : apex/furthest was partitioned as a coplanar point
454 : ignore this furthest point
455 : returns False if no dupridges or if dupridges will be resolved by MRGridge
456 : updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
457 :
458 : notes:
459 : only called from qh_buildcone with qh.MERGEpinched
460 :
461 : design:
462 : match neighboring new facets
463 : if matching detected dupridges with a wide merge (qh_RATIOtrypinched)
464 : if pinched vertices (i.e., nearly adjacent)
465 : delete the cone of new facets
466 : delete the apex and reset the facet lists
467 : if coplanar, pinched apex
468 : partition the apex as a coplanar point
469 : else
470 : repeatedly merge the nearest pair of pinched vertices and subsequent facet merges
471 : return True
472 : otherwise
473 : MRGridge are better than vertex merge, but may report an error
474 : attach new facets
475 : make hyperplanes for point
476 : update vertex neighbors and delete interior vertices
477 : */
478 0 : boolT qh_buildcone_mergepinched(qhT *qh, vertexT *apex, facetT *facet, facetT **retryfacet) {
479 : facetT *newfacet, *nextfacet;
480 : pointT *apexpoint;
481 : coordT maxdupdist;
482 : int apexpointid;
483 : boolT iscoplanar;
484 :
485 0 : *retryfacet= NULL;
486 0 : maxdupdist= qh_matchnewfacets(qh);
487 0 : if (maxdupdist > qh_RATIOtrypinched * qh->ONEmerge) { /* one or more dupridges with a wide merge */
488 0 : if (qh->IStracing >= 4 && qh->num_facets < 1000)
489 0 : qh_printlists(qh);
490 0 : qh_initmergesets(qh /* qh.facet_mergeset,degen_mergeset,vertex_mergeset */);
491 0 : if (qh_getpinchedmerges(qh, apex, maxdupdist, &iscoplanar /* qh.newfacet_list, qh.vertex_mergeset */)) {
492 0 : for (newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
493 0 : nextfacet= newfacet->next;
494 0 : qh_delfacet(qh, newfacet);
495 : }
496 0 : apexpoint= apex->point;
497 0 : apexpointid= qh_pointid(qh, apexpoint);
498 0 : qh_delvertex(qh, apex);
499 0 : qh_resetlists(qh, False, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
500 0 : if (iscoplanar) {
501 0 : zinc_(Zpinchedapex);
502 0 : facet->notfurthest= True;
503 0 : qh_partitioncoplanar(qh, apexpoint, facet, NULL, qh->findbestnew);
504 : }else {
505 0 : qh_all_vertexmerges(qh, apexpointid, facet, retryfacet);
506 : }
507 0 : qh_freemergesets(qh); /* errors if not empty */
508 0 : return True;
509 : }
510 : /* MRGridge are better than vertex merge, but may report an error */
511 0 : qh_freemergesets(qh);
512 : }
513 0 : qh_attachnewfacets(qh /* qh.visible_list */);
514 0 : qh_makenewplanes(qh /* qh.newfacet_list */);
515 0 : qh_update_vertexneighbors_cone(qh);
516 0 : return False;
517 : } /* buildcone_mergepinched */
518 : #endif /* !qh_NOmerge */
519 :
520 : /*-<a href="qh-qhull_r.htm#TOC"
521 : >-------------------------------</a><a name="buildcone_onlygood">-</a>
522 :
523 : qh_buildcone_onlygood(qh, apex, goodhorizon )
524 : build cone of good, new facets from apex and its qh.newfacet_list to the horizon
525 : goodhorizon is count of good, horizon facets from qh_find_horizon
526 :
527 : returns:
528 : False if a f.good facet or a qh.GOODclosest facet is not found
529 : updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices
530 :
531 : notes:
532 : called from qh_buildcone
533 : QH11030 FIX: Review effect of qh.GOODclosest on qh_buildcone_onlygood ('Qg'). qh_findgood preserves old value if didn't find a good facet. See qh_findgood_all for disabling
534 :
535 : design:
536 : make hyperplanes for point
537 : if qh_findgood fails to find a f.good facet or a qh.GOODclosest facet
538 : delete cone of new facets
539 : return NULL (ignores apex)
540 : else
541 : attach cone to horizon
542 : match neighboring new facets
543 : */
544 0 : boolT qh_buildcone_onlygood(qhT *qh, vertexT *apex, int goodhorizon) {
545 : facetT *newfacet, *nextfacet;
546 :
547 0 : qh_makenewplanes(qh /* qh.newfacet_list */);
548 0 : if(qh_findgood(qh, qh->newfacet_list, goodhorizon) == 0) {
549 0 : if (!qh->GOODclosest) {
550 0 : for (newfacet=qh->newfacet_list; newfacet && newfacet->next; newfacet= nextfacet) {
551 0 : nextfacet= newfacet->next;
552 0 : qh_delfacet(qh, newfacet);
553 : }
554 0 : qh_delvertex(qh, apex);
555 0 : qh_resetlists(qh, False /*no stats*/, qh_RESETvisible /* qh.visible_list newvertex_list qh.newfacet_list */);
556 0 : zinc_(Znotgoodnew);
557 : /* !good outside points dropped from hull */
558 0 : return False;
559 : }
560 : }
561 0 : qh_attachnewfacets(qh /* qh.visible_list */);
562 0 : qh_matchnewfacets(qh); /* ignore returned value. qh_forcedmerges will merge dupridges if any */
563 0 : qh_update_vertexneighbors_cone(qh);
564 0 : return True;
565 : } /* buildcone_onlygood */
566 :
567 : /*-<a href="qh-qhull_r.htm#TOC"
568 : >-------------------------------</a><a name="buildhull">-</a>
569 :
570 : qh_buildhull(qh)
571 : construct a convex hull by adding outside points one at a time
572 :
573 : returns:
574 :
575 : notes:
576 : may be called multiple times
577 : checks facet and vertex lists for incorrect flags
578 : to recover from STOPcone, call qh_deletevisible and qh_resetlists
579 :
580 : design:
581 : check visible facet and newfacet flags
582 : check newfacet vertex flags and qh.STOPcone/STOPpoint
583 : for each facet with a furthest outside point
584 : add point to facet
585 : exit if qh.STOPcone or qh.STOPpoint requested
586 : if qh.NARROWhull for initial simplex
587 : partition remaining outside points to coplanar sets
588 : */
589 3 : void qh_buildhull(qhT *qh) {
590 : facetT *facet;
591 : pointT *furthest;
592 : vertexT *vertex;
593 : int id;
594 :
595 3 : trace1((qh, qh->ferr, 1037, "qh_buildhull: start build hull\n"));
596 15 : FORALLfacets {
597 12 : if (facet->visible || facet->newfacet) {
598 0 : qh_fprintf(qh, qh->ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n",
599 0 : facet->id);
600 0 : qh_errexit(qh, qh_ERRqhull, facet, NULL);
601 : }
602 : }
603 15 : FORALLvertices {
604 12 : if (vertex->newfacet) {
605 0 : qh_fprintf(qh, qh->ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n",
606 : vertex->id);
607 0 : qh_errprint(qh, "ERRONEOUS", NULL, NULL, NULL, vertex);
608 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
609 : }
610 12 : id= qh_pointid(qh, vertex->point);
611 12 : if ((qh->STOPpoint>0 && id == qh->STOPpoint-1) ||
612 12 : (qh->STOPpoint<0 && id == -qh->STOPpoint-1) ||
613 12 : (qh->STOPcone>0 && id == qh->STOPcone-1)) {
614 0 : trace1((qh, qh->ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
615 0 : return;
616 : }
617 : }
618 3 : qh->facet_next= qh->facet_list; /* advance facet when processed */
619 14663 : while ((furthest= qh_nextfurthest(qh, &facet))) {
620 14660 : qh->num_outside--; /* if ONLYmax, furthest may not be outside */
621 14660 : if (qh->STOPadd>0 && (qh->num_vertices - qh->hull_dim - 1 >= qh->STOPadd - 1)) {
622 0 : trace1((qh, qh->ferr, 1059, "qh_buildhull: stop after adding %d vertices\n", qh->STOPadd-1));
623 0 : return;
624 : }
625 14660 : if (!qh_addpoint(qh, furthest, facet, qh->ONLYmax))
626 0 : break;
627 : }
628 3 : if (qh->NARROWhull) /* move points from outsideset to coplanarset */
629 0 : qh_outcoplanar(qh /* facet_list */ );
630 3 : if (qh->num_outside && !furthest) {
631 0 : qh_fprintf(qh, qh->ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh->num_outside);
632 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
633 : }
634 3 : trace1((qh, qh->ferr, 1039, "qh_buildhull: completed the hull construction\n"));
635 : } /* buildhull */
636 :
637 :
638 : /*-<a href="qh-qhull_r.htm#TOC"
639 : >-------------------------------</a><a name="buildtracing">-</a>
640 :
641 : qh_buildtracing(qh, furthest, facet )
642 : trace an iteration of qh_buildhull() for furthest point and facet
643 : if !furthest, prints progress message
644 :
645 : returns:
646 : tracks progress with qh.lastreport, lastcpu, lastfacets, lastmerges, lastplanes, lastdist
647 : updates qh.furthest_id (-3 if furthest is NULL)
648 : also resets visit_id, vertext_visit on wrap around
649 :
650 : see:
651 : qh_tracemerging()
652 :
653 : design:
654 : if !furthest
655 : print progress message
656 : exit
657 : if 'TFn' iteration
658 : print progress message
659 : else if tracing
660 : trace furthest point and facet
661 : reset qh.visit_id and qh.vertex_visit if overflow may occur
662 : set qh.furthest_id for tracing
663 : */
664 14660 : void qh_buildtracing(qhT *qh, pointT *furthest, facetT *facet) {
665 14660 : realT dist= 0;
666 : double cpu;
667 : int total, furthestid;
668 : time_t timedata;
669 : struct tm *tp;
670 : vertexT *vertex;
671 :
672 14660 : qh->old_randomdist= qh->RANDOMdist;
673 14660 : qh->RANDOMdist= False;
674 14660 : if (!furthest) {
675 0 : time(&timedata);
676 0 : tp= localtime(&timedata);
677 0 : cpu= (double)qh_CPUclock - (double)qh->hulltime;
678 0 : cpu /= (double)qh_SECticks;
679 0 : total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
680 0 : qh_fprintf(qh, qh->ferr, 8118, "\n\
681 : At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
682 : The current hull contains %d facets and %d vertices. Last point was p%d\n",
683 0 : tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
684 : total, qh->num_facets, qh->num_vertices, qh->furthest_id);
685 0 : return;
686 : }
687 14660 : furthestid= qh_pointid(qh, furthest);
688 : #ifndef qh_NOtrace
689 14660 : if (qh->TRACEpoint == furthestid) {
690 0 : trace1((qh, qh->ferr, 1053, "qh_buildtracing: start trace T%d for point TP%d above facet f%d\n", qh->TRACElevel, furthestid, facet->id));
691 0 : qh->IStracing= qh->TRACElevel;
692 0 : qh->qhmem.IStracing= qh->TRACElevel;
693 14660 : }else if (qh->TRACEpoint != qh_IDnone && qh->TRACEdist < REALmax/2) {
694 0 : qh->IStracing= 0;
695 0 : qh->qhmem.IStracing= 0;
696 : }
697 : #endif
698 14660 : if (qh->REPORTfreq && (qh->facet_id-1 > qh->lastreport + (unsigned int)qh->REPORTfreq)) {
699 0 : qh->lastreport= qh->facet_id-1;
700 0 : time(&timedata);
701 0 : tp= localtime(&timedata);
702 0 : cpu= (double)qh_CPUclock - (double)qh->hulltime;
703 0 : cpu /= (double)qh_SECticks;
704 0 : total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
705 0 : zinc_(Zdistio);
706 0 : qh_distplane(qh, furthest, facet, &dist);
707 0 : qh_fprintf(qh, qh->ferr, 8119, "\n\
708 : At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
709 : The current hull contains %d facets and %d vertices. There are %d\n\
710 : outside points. Next is point p%d(v%d), %2.2g above f%d.\n",
711 0 : tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh->facet_id -1,
712 0 : total, qh->num_facets, qh->num_vertices, qh->num_outside+1,
713 0 : furthestid, qh->vertex_id, dist, getid_(facet));
714 14660 : }else if (qh->IStracing >=1) {
715 0 : cpu= (double)qh_CPUclock - (double)qh->hulltime;
716 0 : cpu /= (double)qh_SECticks;
717 0 : qh_distplane(qh, furthest, facet, &dist);
718 0 : qh_fprintf(qh, qh->ferr, 1049, "qh_addpoint: add p%d(v%d) %2.2g above f%d to hull of %d facets, %d merges, %d outside at %4.4g CPU secs. Previous p%d(v%d) delta %4.4g CPU, %d facets, %d merges, %d hyperplanes, %d distplanes, %d retries\n",
719 0 : furthestid, qh->vertex_id, dist, getid_(facet), qh->num_facets, zzval_(Ztotmerge), qh->num_outside+1, cpu, qh->furthest_id, qh->vertex_id - 1,
720 0 : cpu - qh->lastcpu, qh->num_facets - qh->lastfacets, zzval_(Ztotmerge) - qh->lastmerges, zzval_(Zsetplane) - qh->lastplanes, zzval_(Zdistplane) - qh->lastdist, qh->retry_addpoint);
721 0 : qh->lastcpu= cpu;
722 0 : qh->lastfacets= qh->num_facets;
723 0 : qh->lastmerges= zzval_(Ztotmerge);
724 0 : qh->lastplanes= zzval_(Zsetplane);
725 0 : qh->lastdist= zzval_(Zdistplane);
726 : }
727 14660 : zmax_(Zvisit2max, (int)qh->visit_id/2);
728 14660 : if (qh->visit_id > (unsigned int) INT_MAX) { /* 31 bits */
729 0 : zinc_(Zvisit);
730 0 : if (!qh_checklists(qh, qh->facet_list)) {
731 0 : qh_fprintf(qh, qh->ferr, 6370, "qhull internal error: qh_checklists failed on reset of qh.visit_id %u\n", qh->visit_id);
732 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
733 : }
734 0 : qh->visit_id= 0;
735 0 : FORALLfacets
736 0 : facet->visitid= 0;
737 : }
738 14660 : zmax_(Zvvisit2max, (int)qh->vertex_visit/2);
739 14660 : if (qh->vertex_visit > (unsigned int) INT_MAX) { /* 31 bits */
740 0 : zinc_(Zvvisit);
741 0 : if (qh->visit_id && !qh_checklists(qh, qh->facet_list)) {
742 0 : qh_fprintf(qh, qh->ferr, 6371, "qhull internal error: qh_checklists failed on reset of qh.vertex_visit %u\n", qh->vertex_visit);
743 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
744 : }
745 0 : qh->vertex_visit= 0;
746 0 : FORALLvertices
747 0 : vertex->visitid= 0;
748 : }
749 14660 : qh->furthest_id= furthestid;
750 14660 : qh->RANDOMdist= qh->old_randomdist;
751 : } /* buildtracing */
752 :
753 : /*-<a href="qh-qhull_r.htm#TOC"
754 : >-------------------------------</a><a name="errexit2">-</a>
755 :
756 : qh_errexit2(qh, exitcode, facet, otherfacet )
757 : return exitcode to system after an error
758 : report two facets
759 :
760 : returns:
761 : assumes exitcode non-zero
762 :
763 : see:
764 : normally use qh_errexit() in user_r.c(reports a facet and a ridge)
765 : */
766 0 : void qh_errexit2(qhT *qh, int exitcode, facetT *facet, facetT *otherfacet) {
767 0 : qh->tracefacet= NULL; /* avoid infinite recursion through qh_fprintf */
768 0 : qh->traceridge= NULL;
769 0 : qh->tracevertex= NULL;
770 0 : qh_errprint(qh, "ERRONEOUS", facet, otherfacet, NULL, NULL);
771 0 : qh_errexit(qh, exitcode, NULL, NULL);
772 0 : } /* errexit2 */
773 :
774 :
775 : /*-<a href="qh-qhull_r.htm#TOC"
776 : >-------------------------------</a><a name="findhorizon">-</a>
777 :
778 : qh_findhorizon(qh, point, facet, goodvisible, goodhorizon )
779 : given a visible facet, find the point's horizon and visible facets
780 : for all facets, !facet-visible
781 :
782 : returns:
783 : returns qh.visible_list/num_visible with all visible facets
784 : marks visible facets with ->visible
785 : updates count of good visible and good horizon facets
786 : updates qh.max_outside, qh.max_vertex, facet->maxoutside
787 :
788 : see:
789 : similar to qh_delpoint()
790 :
791 : design:
792 : move facet to qh.visible_list at end of qh.facet_list
793 : for all visible facets
794 : for each unvisited neighbor of a visible facet
795 : compute distance of point to neighbor
796 : if point above neighbor
797 : move neighbor to end of qh.visible_list
798 : else if point is coplanar with neighbor
799 : update qh.max_outside, qh.max_vertex, neighbor->maxoutside
800 : mark neighbor coplanar (will create a samecycle later)
801 : update horizon statistics
802 : */
803 14660 : void qh_findhorizon(qhT *qh, pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
804 : facetT *neighbor, **neighborp, *visible;
805 14660 : int numhorizon= 0, coplanar= 0;
806 : realT dist;
807 :
808 14660 : trace1((qh, qh->ferr, 1040, "qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(qh, point),facet->id));
809 14660 : *goodvisible= *goodhorizon= 0;
810 14660 : zinc_(Ztotvisible);
811 14660 : qh_removefacet(qh, facet); /* visible_list at end of qh->facet_list */
812 14660 : qh_appendfacet(qh, facet);
813 14660 : qh->num_visible= 1;
814 14660 : if (facet->good)
815 14660 : (*goodvisible)++;
816 14660 : qh->visible_list= facet;
817 14660 : facet->visible= True;
818 14660 : facet->f.replace= NULL;
819 14660 : if (qh->IStracing >=4)
820 0 : qh_errprint(qh, "visible", facet, NULL, NULL, NULL);
821 14660 : qh->visit_id++;
822 53569 : FORALLvisible_facets {
823 38909 : if (visible->tricoplanar && !qh->TRInormals) {
824 0 : qh_fprintf(qh, qh->ferr, 6230, "qhull internal error (qh_findhorizon): does not work for tricoplanar facets. Use option 'Q11'\n");
825 0 : qh_errexit(qh, qh_ERRqhull, visible, NULL);
826 : }
827 38909 : if (qh_setsize(qh, visible->neighbors) == 0) {
828 0 : qh_fprintf(qh, qh->ferr, 6295, "qhull internal error (qh_findhorizon): visible facet f%d does not have neighbors\n", visible->id);
829 0 : qh_errexit(qh, qh_ERRqhull, visible, NULL);
830 : }
831 38909 : visible->visitid= qh->visit_id;
832 160811 : FOREACHneighbor_(visible) {
833 121902 : if (neighbor->visitid == qh->visit_id)
834 24313 : continue;
835 97589 : neighbor->visitid= qh->visit_id;
836 97589 : zzinc_(Znumvisibility);
837 97589 : qh_distplane(qh, point, neighbor, &dist);
838 97589 : if (dist > qh->MINvisible) {
839 24249 : zinc_(Ztotvisible);
840 24249 : qh_removefacet(qh, neighbor); /* append to end of qh->visible_list */
841 24249 : qh_appendfacet(qh, neighbor);
842 24249 : neighbor->visible= True;
843 24249 : neighbor->f.replace= NULL;
844 24249 : qh->num_visible++;
845 24249 : if (neighbor->good)
846 24249 : (*goodvisible)++;
847 24249 : if (qh->IStracing >=4)
848 0 : qh_errprint(qh, "visible", neighbor, NULL, NULL, NULL);
849 : }else {
850 73340 : if (dist >= -qh->MAXcoplanar) {
851 20047 : neighbor->coplanarhorizon= True;
852 20047 : zzinc_(Zcoplanarhorizon);
853 20047 : qh_joggle_restart(qh, "coplanar horizon");
854 20047 : coplanar++;
855 20047 : if (qh->MERGING) {
856 20047 : if (dist > 0) {
857 9224 : maximize_(qh->max_outside, dist);
858 9224 : maximize_(qh->max_vertex, dist);
859 : #if qh_MAXoutside
860 9224 : maximize_(neighbor->maxoutside, dist);
861 : #endif
862 : }else
863 10823 : minimize_(qh->min_vertex, dist); /* due to merge later */
864 : }
865 20047 : trace2((qh, qh->ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh->MINvisible(%2.7g)\n",
866 : qh_pointid(qh, point), neighbor->id, dist, qh->MINvisible));
867 : }else
868 53293 : neighbor->coplanarhorizon= False;
869 73340 : zinc_(Ztothorizon);
870 73340 : numhorizon++;
871 73340 : if (neighbor->good)
872 73340 : (*goodhorizon)++;
873 73340 : if (qh->IStracing >=4)
874 0 : qh_errprint(qh, "horizon", neighbor, NULL, NULL, NULL);
875 : }
876 : }
877 : }
878 14660 : if (!numhorizon) {
879 0 : qh_joggle_restart(qh, "empty horizon");
880 0 : qh_fprintf(qh, qh->ferr, 6168, "qhull topology error (qh_findhorizon): empty horizon for p%d. It was above all facets.\n", qh_pointid(qh, point));
881 0 : if (qh->num_facets < 100) {
882 0 : qh_printfacetlist(qh, qh->facet_list, NULL, True);
883 : }
884 0 : qh_errexit(qh, qh_ERRtopology, NULL, NULL);
885 : }
886 14660 : trace1((qh, qh->ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n",
887 : numhorizon, *goodhorizon, qh->num_visible, *goodvisible, coplanar));
888 14660 : if (qh->IStracing >= 4 && qh->num_facets < 100)
889 0 : qh_printlists(qh);
890 14660 : } /* findhorizon */
891 :
892 : /*-<a href="qh-qhull_r.htm#TOC"
893 : >-------------------------------</a><a name="joggle_restart">-</a>
894 :
895 : qh_joggle_restart(qh, reason )
896 : if joggle ('QJn') and not merging, restart on precision and topology errors
897 : */
898 20049 : void qh_joggle_restart(qhT *qh, const char *reason) {
899 :
900 20049 : if (qh->JOGGLEmax < REALmax/2) {
901 0 : if (qh->ALLOWrestart && !qh->PREmerge && !qh->MERGEexact) {
902 0 : trace0((qh, qh->ferr, 26, "qh_joggle_restart: qhull restart because of %s\n", reason));
903 : /* May be called repeatedly if qh->ALLOWrestart */
904 0 : longjmp(qh->restartexit, qh_ERRprec);
905 : }
906 : }
907 20049 : } /* qh_joggle_restart */
908 :
909 : /*-<a href="qh-qhull_r.htm#TOC"
910 : >-------------------------------</a><a name="nextfurthest">-</a>
911 :
912 : qh_nextfurthest(qh, visible )
913 : returns next furthest point and visible facet for qh_addpoint()
914 : starts search at qh.facet_next
915 :
916 : returns:
917 : removes furthest point from outside set
918 : NULL if none available
919 : advances qh.facet_next over facets with empty outside sets
920 :
921 : design:
922 : for each facet from qh.facet_next
923 : if empty outside set
924 : advance qh.facet_next
925 : else if qh.NARROWhull
926 : determine furthest outside point
927 : if furthest point is not outside
928 : advance qh.facet_next(point will be coplanar)
929 : remove furthest point from outside set
930 : */
931 14663 : pointT *qh_nextfurthest(qhT *qh, facetT **visible) {
932 : facetT *facet;
933 14663 : int size, idx, loopcount= 0;
934 : realT randr, dist;
935 : pointT *furthest;
936 :
937 42296 : while ((facet= qh->facet_next) != qh->facet_tail) {
938 42293 : if (!facet || loopcount++ > qh->num_facets) {
939 0 : qh_fprintf(qh, qh->ferr, 6406, "qhull internal error (qh_nextfurthest): null facet or infinite loop detected for qh.facet_next f%d facet_tail f%d\n",
940 0 : getid_(facet), getid_(qh->facet_tail));
941 0 : qh_printlists(qh);
942 0 : qh_errexit2(qh, qh_ERRqhull, facet, qh->facet_tail);
943 : }
944 42293 : if (!facet->outsideset) {
945 27633 : qh->facet_next= facet->next;
946 27633 : continue;
947 : }
948 14660 : SETreturnsize_(facet->outsideset, size);
949 14660 : if (!size) {
950 0 : qh_setfree(qh, &facet->outsideset);
951 0 : qh->facet_next= facet->next;
952 0 : continue;
953 : }
954 14660 : if (qh->NARROWhull) {
955 0 : if (facet->notfurthest)
956 0 : qh_furthestout(qh, facet);
957 0 : furthest= (pointT *)qh_setlast(facet->outsideset);
958 : #if qh_COMPUTEfurthest
959 : qh_distplane(qh, furthest, facet, &dist);
960 : zinc_(Zcomputefurthest);
961 : #else
962 0 : dist= facet->furthestdist;
963 : #endif
964 0 : if (dist < qh->MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */
965 0 : qh->facet_next= facet->next;
966 0 : continue;
967 : }
968 : }
969 14660 : if (!qh->RANDOMoutside && !qh->VIRTUALmemory) {
970 14660 : if (qh->PICKfurthest) {
971 0 : qh_furthestnext(qh /* qh.facet_list */);
972 0 : facet= qh->facet_next;
973 : }
974 14660 : *visible= facet;
975 14660 : return ((pointT *)qh_setdellast(facet->outsideset));
976 : }
977 0 : if (qh->RANDOMoutside) {
978 0 : int outcoplanar= 0;
979 0 : if (qh->NARROWhull) {
980 0 : FORALLfacets {
981 0 : if (facet == qh->facet_next)
982 0 : break;
983 0 : if (facet->outsideset)
984 0 : outcoplanar += qh_setsize(qh, facet->outsideset);
985 : }
986 : }
987 0 : randr= qh_RANDOMint;
988 0 : randr= randr/(qh_RANDOMmax+1);
989 0 : randr= floor((qh->num_outside - outcoplanar) * randr);
990 0 : idx= (int)randr;
991 0 : FORALLfacet_(qh->facet_next) {
992 0 : if (facet->outsideset) {
993 0 : SETreturnsize_(facet->outsideset, size);
994 0 : if (!size)
995 0 : qh_setfree(qh, &facet->outsideset);
996 0 : else if (size > idx) {
997 0 : *visible= facet;
998 0 : return ((pointT *)qh_setdelnth(qh, facet->outsideset, idx));
999 : }else
1000 0 : idx -= size;
1001 : }
1002 : }
1003 0 : qh_fprintf(qh, 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",
1004 : qh->num_outside, idx+1, randr);
1005 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
1006 : }else { /* VIRTUALmemory */
1007 0 : facet= qh->facet_tail->previous;
1008 0 : if (!(furthest= (pointT *)qh_setdellast(facet->outsideset))) {
1009 0 : if (facet->outsideset)
1010 0 : qh_setfree(qh, &facet->outsideset);
1011 0 : qh_removefacet(qh, facet);
1012 0 : qh_prependfacet(qh, facet, &qh->facet_list);
1013 0 : continue;
1014 : }
1015 0 : *visible= facet;
1016 0 : return furthest;
1017 : }
1018 : }
1019 3 : return NULL;
1020 : } /* nextfurthest */
1021 :
1022 : /*-<a href="qh-qhull_r.htm#TOC"
1023 : >-------------------------------</a><a name="partitionall">-</a>
1024 :
1025 : qh_partitionall(qh, vertices, points, numpoints )
1026 : partitions all points in points/numpoints to the outsidesets of facets
1027 : vertices= vertices in qh.facet_list(!partitioned)
1028 :
1029 : returns:
1030 : builds facet->outsideset
1031 : does not partition qh.GOODpoint
1032 : if qh.ONLYgood && !qh.MERGING,
1033 : does not partition qh.GOODvertex
1034 :
1035 : notes:
1036 : faster if qh.facet_list sorted by anticipated size of outside set
1037 :
1038 : design:
1039 : initialize pointset with all points
1040 : remove vertices from pointset
1041 : remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint)
1042 : for all facets
1043 : for all remaining points in pointset
1044 : compute distance from point to facet
1045 : if point is outside facet
1046 : remove point from pointset (by not reappending)
1047 : update bestpoint
1048 : append point or old bestpoint to facet's outside set
1049 : append bestpoint to facet's outside set (furthest)
1050 : for all points remaining in pointset
1051 : partition point into facets' outside sets and coplanar sets
1052 : */
1053 3 : void qh_partitionall(qhT *qh, setT *vertices, pointT *points, int numpoints){
1054 : setT *pointset;
1055 : vertexT *vertex, **vertexp;
1056 : pointT *point, **pointp, *bestpoint;
1057 : int size, point_i, point_n, point_end, remaining, i, id;
1058 : facetT *facet;
1059 3 : realT bestdist= -REALmax, dist, distoutside;
1060 :
1061 3 : trace1((qh, qh->ferr, 1042, "qh_partitionall: partition all points into outside sets\n"));
1062 3 : pointset= qh_settemp(qh, numpoints);
1063 3 : qh->num_outside= 0;
1064 3 : pointp= SETaddr_(pointset, pointT);
1065 14676 : for (i=numpoints, point= points; i--; point += qh->hull_dim)
1066 14673 : *(pointp++)= point;
1067 3 : qh_settruncate(qh, pointset, numpoints);
1068 15 : FOREACHvertex_(vertices) {
1069 12 : if ((id= qh_pointid(qh, vertex->point)) >= 0)
1070 12 : SETelem_(pointset, id)= NULL;
1071 : }
1072 3 : id= qh_pointid(qh, qh->GOODpointp);
1073 3 : if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
1074 0 : SETelem_(pointset, id)= NULL;
1075 3 : if (qh->GOODvertexp && qh->ONLYgood && !qh->MERGING) { /* matches qhull()*/
1076 0 : if ((id= qh_pointid(qh, qh->GOODvertexp)) >= 0)
1077 0 : SETelem_(pointset, id)= NULL;
1078 : }
1079 3 : if (!qh->BESToutside) { /* matches conditional for qh_partitionpoint below */
1080 3 : distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user_r.h */
1081 3 : zval_(Ztotpartition)= qh->num_points - qh->hull_dim - 1; /*misses GOOD... */
1082 3 : remaining= qh->num_facets;
1083 3 : point_end= numpoints;
1084 15 : FORALLfacets {
1085 12 : size= point_end/(remaining--) + 100;
1086 12 : facet->outsideset= qh_setnew(qh, size);
1087 12 : bestpoint= NULL;
1088 12 : point_end= 0;
1089 14699 : FOREACHpoint_i_(qh, pointset) {
1090 14687 : if (point) {
1091 14675 : zzinc_(Zpartitionall);
1092 14675 : qh_distplane(qh, point, facet, &dist);
1093 14675 : if (dist < distoutside)
1094 14 : SETelem_(pointset, point_end++)= point;
1095 : else {
1096 14661 : qh->num_outside++;
1097 14661 : if (!bestpoint) {
1098 6 : bestpoint= point;
1099 6 : bestdist= dist;
1100 14655 : }else if (dist > bestdist) {
1101 533 : qh_setappend(qh, &facet->outsideset, bestpoint);
1102 533 : bestpoint= point;
1103 533 : bestdist= dist;
1104 : }else
1105 14122 : qh_setappend(qh, &facet->outsideset, point);
1106 : }
1107 : }
1108 : }
1109 12 : if (bestpoint) {
1110 6 : qh_setappend(qh, &facet->outsideset, bestpoint);
1111 : #if !qh_COMPUTEfurthest
1112 6 : facet->furthestdist= bestdist;
1113 : #endif
1114 : }else
1115 6 : qh_setfree(qh, &facet->outsideset);
1116 12 : qh_settruncate(qh, pointset, point_end);
1117 : }
1118 : }
1119 : /* if !qh->BESToutside, pointset contains points not assigned to outsideset */
1120 3 : if (qh->BESToutside || qh->MERGING || qh->KEEPcoplanar || qh->KEEPinside || qh->KEEPnearinside) {
1121 3 : qh->findbestnew= True;
1122 3 : FOREACHpoint_i_(qh, pointset) {
1123 0 : if (point)
1124 0 : qh_partitionpoint(qh, point, qh->facet_list);
1125 : }
1126 3 : qh->findbestnew= False;
1127 : }
1128 3 : zzadd_(Zpartitionall, zzval_(Zpartition));
1129 3 : zzval_(Zpartition)= 0;
1130 3 : qh_settempfree(qh, &pointset);
1131 3 : if (qh->IStracing >= 4)
1132 0 : qh_printfacetlist(qh, qh->facet_list, NULL, True);
1133 3 : } /* partitionall */
1134 :
1135 :
1136 : /*-<a href="qh-qhull_r.htm#TOC"
1137 : >-------------------------------</a><a name="partitioncoplanar">-</a>
1138 :
1139 : qh_partitioncoplanar(qh, point, facet, dist, allnew )
1140 : partition coplanar point to a facet
1141 : dist is distance from point to facet
1142 : if dist NULL,
1143 : searches for bestfacet and does nothing if inside
1144 : if allnew (qh.findbestnew)
1145 : searches new facets instead of using qh_findbest()
1146 :
1147 : returns:
1148 : qh.max_ouside updated
1149 : if qh.KEEPcoplanar or qh.KEEPinside
1150 : point assigned to best coplanarset
1151 : qh.repart_facetid==0 (for detecting infinite recursion via qh_partitionpoint)
1152 :
1153 : notes:
1154 : facet->maxoutside is updated at end by qh_check_maxout
1155 :
1156 : design:
1157 : if dist undefined
1158 : find best facet for point
1159 : if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside)
1160 : exit
1161 : if keeping coplanar/nearinside/inside points
1162 : if point is above furthest coplanar point
1163 : append point to coplanar set (it is the new furthest)
1164 : update qh.max_outside
1165 : else
1166 : append point one before end of coplanar set
1167 : else if point is clearly outside of qh.max_outside and bestfacet->coplanarset
1168 : and bestfacet is more than perpendicular to facet
1169 : repartition the point using qh_findbest() -- it may be put on an outsideset
1170 : else
1171 : update qh.max_outside
1172 : */
1173 4 : void qh_partitioncoplanar(qhT *qh, pointT *point, facetT *facet, realT *dist, boolT allnew) {
1174 : facetT *bestfacet;
1175 : pointT *oldfurthest;
1176 4 : realT bestdist, angle, nearest, dist2= 0.0;
1177 4 : int numpart= 0;
1178 4 : boolT isoutside, oldfindbest, repartition= False;
1179 :
1180 4 : trace4((qh, qh->ferr, 4090, "qh_partitioncoplanar: partition coplanar point p%d starting with f%d dist? %2.2g, allnew? %d, gh.repart_facetid f%d\n",
1181 : qh_pointid(qh, point), facet->id, (dist ? *dist : 0.0), allnew, qh->repart_facetid));
1182 4 : qh->WAScoplanar= True;
1183 4 : if (!dist) {
1184 3 : if (allnew)
1185 1 : bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh_ALL, &isoutside, &numpart);
1186 : else
1187 2 : bestfacet= qh_findbest(qh, point, facet, qh_ALL, !qh_ISnewfacets, qh->DELAUNAY,
1188 : &bestdist, &isoutside, &numpart);
1189 3 : zinc_(Ztotpartcoplanar);
1190 3 : zzadd_(Zpartcoplanar, numpart);
1191 3 : if (!qh->DELAUNAY && !qh->KEEPinside) { /* for 'd', bestdist skips upperDelaunay facets */
1192 0 : if (qh->KEEPnearinside) {
1193 0 : if (bestdist < -qh->NEARinside) {
1194 0 : zinc_(Zcoplanarinside);
1195 0 : trace4((qh, qh->ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g allnew? %d\n",
1196 : qh_pointid(qh, point), bestfacet->id, bestdist, allnew));
1197 0 : qh->repart_facetid= 0;
1198 0 : return;
1199 : }
1200 0 : }else if (bestdist < -qh->MAXcoplanar) {
1201 0 : trace4((qh, qh->ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g allnew? %d\n",
1202 : qh_pointid(qh, point), bestfacet->id, bestdist, allnew));
1203 0 : zinc_(Zcoplanarinside);
1204 0 : qh->repart_facetid= 0;
1205 0 : return;
1206 : }
1207 : }
1208 : }else {
1209 1 : bestfacet= facet;
1210 1 : bestdist= *dist;
1211 : }
1212 4 : if(bestfacet->visible){
1213 0 : qh_fprintf(qh, qh->ferr, 6405, "qhull internal error (qh_partitioncoplanar): cannot partition coplanar p%d of f%d into visible facet f%d\n",
1214 : qh_pointid(qh, point), facet->id, bestfacet->id);
1215 0 : qh_errexit2(qh, qh_ERRqhull, facet, bestfacet);
1216 : }
1217 4 : if (bestdist > qh->max_outside) {
1218 1 : if (!dist && facet != bestfacet) { /* can't be recursive from qh_partitionpoint since facet != bestfacet */
1219 0 : zinc_(Zpartangle);
1220 0 : angle= qh_getangle(qh, facet->normal, bestfacet->normal);
1221 0 : if (angle < 0) {
1222 : /* nearest= qh_vertex_bestdist(qh, bestfacet->vertices) */;
1223 : /* typically due to deleted vertex and coplanar facets, e.g.,
1224 : RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */
1225 0 : zinc_(Zpartcorner);
1226 0 : trace2((qh, qh->ferr, 2058, "qh_partitioncoplanar: repartition coplanar point p%d from f%d as an outside point above corner facet f%d dist %2.2g with angle %2.2g\n",
1227 : qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, angle));
1228 0 : repartition= True;
1229 : }
1230 : }
1231 1 : if (!repartition) {
1232 1 : if (bestdist > qh->MAXoutside * qh_RATIOcoplanaroutside) {
1233 0 : nearest= qh_vertex_bestdist(qh, bestfacet->vertices);
1234 0 : if (facet->id == bestfacet->id) {
1235 0 : if (facet->id == qh->repart_facetid) {
1236 0 : qh_fprintf(qh, qh->ferr, 6404, "Qhull internal error (qh_partitioncoplanar): infinite loop due to recursive call to qh_partitionpoint. Repartition point p%d from f%d as a outside point dist %2.2g nearest vertices %2.2g\n",
1237 : qh_pointid(qh, point), facet->id, bestdist, nearest);
1238 0 : qh_errexit(qh, qh_ERRqhull, facet, NULL);
1239 : }
1240 0 : qh->repart_facetid= facet->id; /* reset after call to qh_partitionpoint */
1241 : }
1242 0 : if (point == qh->coplanar_apex) {
1243 : /* otherwise may loop indefinitely, the point is well above a facet, yet near a vertex */
1244 0 : qh_fprintf(qh, qh->ferr, 6425, "Qhull topology error (qh_partitioncoplanar): can not repartition coplanar point p%d from f%d as outside point above f%d. It previously failed to form a cone of facets, dist %2.2g, nearest vertices %2.2g\n",
1245 : qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
1246 0 : qh_errexit(qh, qh_ERRtopology, facet, NULL);
1247 : }
1248 0 : if (nearest < 2 * qh->MAXoutside * qh_RATIOcoplanaroutside) {
1249 0 : zinc_(Zparttwisted);
1250 0 : qh_fprintf(qh, qh->ferr, 7085, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above twisted facet f%d dist %2.2g nearest vertices %2.2g\n",
1251 : qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
1252 : }else {
1253 0 : zinc_(Zparthidden);
1254 0 : qh_fprintf(qh, qh->ferr, 7086, "Qhull precision warning: repartition coplanar point p%d from f%d as an outside point above hidden facet f%d dist %2.2g nearest vertices %2.2g\n",
1255 : qh_pointid(qh, point), facet->id, bestfacet->id, bestdist, nearest);
1256 : }
1257 0 : repartition= True;
1258 : }
1259 : }
1260 1 : if (repartition) {
1261 0 : oldfindbest= qh->findbestnew;
1262 0 : qh->findbestnew= False;
1263 0 : qh_partitionpoint(qh, point, bestfacet);
1264 0 : qh->findbestnew= oldfindbest;
1265 0 : qh->repart_facetid= 0;
1266 0 : return;
1267 : }
1268 1 : qh->repart_facetid= 0;
1269 1 : qh->max_outside= bestdist;
1270 1 : if (bestdist > qh->TRACEdist || qh->IStracing >= 3) {
1271 0 : qh_fprintf(qh, qh->ferr, 3041, "qh_partitioncoplanar: == p%d from f%d increases qh.max_outside to %2.2g of f%d last p%d\n",
1272 : qh_pointid(qh, point), facet->id, bestdist, bestfacet->id, qh->furthest_id);
1273 0 : qh_errprint(qh, "DISTANT", facet, bestfacet, NULL, NULL);
1274 : }
1275 : }
1276 4 : if (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside) {
1277 4 : oldfurthest= (pointT *)qh_setlast(bestfacet->coplanarset);
1278 4 : if (oldfurthest) {
1279 0 : zinc_(Zcomputefurthest);
1280 0 : qh_distplane(qh, oldfurthest, bestfacet, &dist2);
1281 : }
1282 4 : if (!oldfurthest || dist2 < bestdist)
1283 4 : qh_setappend(qh, &bestfacet->coplanarset, point);
1284 : else
1285 0 : qh_setappend2ndlast(qh, &bestfacet->coplanarset, point);
1286 : }
1287 4 : trace4((qh, qh->ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
1288 : qh_pointid(qh, point), bestfacet->id, bestdist));
1289 : } /* partitioncoplanar */
1290 :
1291 : /*-<a href="qh-qhull_r.htm#TOC"
1292 : >-------------------------------</a><a name="partitionpoint">-</a>
1293 :
1294 : qh_partitionpoint(qh, point, facet )
1295 : assigns point to an outside set, coplanar set, or inside set (i.e., dropt)
1296 : if qh.findbestnew
1297 : uses qh_findbestnew() to search all new facets
1298 : else
1299 : uses qh_findbest()
1300 :
1301 : notes:
1302 : after qh_distplane(), this and qh_findbest() are most expensive in 3-d
1303 :
1304 : design:
1305 : find best facet for point
1306 : (either exhaustive search of new facets or directed search from facet)
1307 : if qh.NARROWhull
1308 : retain coplanar and nearinside points as outside points
1309 : if point is outside bestfacet
1310 : if point above furthest point for bestfacet
1311 : append point to outside set (it becomes the new furthest)
1312 : if outside set was empty
1313 : move bestfacet to end of qh.facet_list (i.e., after qh.facet_next)
1314 : update bestfacet->furthestdist
1315 : else
1316 : append point one before end of outside set
1317 : else if point is coplanar to bestfacet
1318 : if keeping coplanar points or need to update qh.max_outside
1319 : partition coplanar point into bestfacet
1320 : else if near-inside point
1321 : partition as coplanar point into bestfacet
1322 : else is an inside point
1323 : if keeping inside points
1324 : partition as coplanar point into bestfacet
1325 : */
1326 208091 : void qh_partitionpoint(qhT *qh, pointT *point, facetT *facet) {
1327 : realT bestdist, previousdist;
1328 208091 : boolT isoutside, isnewoutside= False;
1329 : facetT *bestfacet;
1330 : int numpart;
1331 :
1332 208091 : if (qh->findbestnew)
1333 184782 : bestfacet= qh_findbestnew(qh, point, facet, &bestdist, qh->BESToutside, &isoutside, &numpart);
1334 : else
1335 23309 : bestfacet= qh_findbest(qh, point, facet, qh->BESToutside, qh_ISnewfacets, !qh_NOupper,
1336 : &bestdist, &isoutside, &numpart);
1337 208091 : zinc_(Ztotpartition);
1338 208091 : zzadd_(Zpartition, numpart);
1339 208091 : if(bestfacet->visible){
1340 0 : qh_fprintf(qh, qh->ferr, 6293, "qhull internal error (qh_partitionpoint): cannot partition p%d of f%d into visible facet f%d\n",
1341 : qh_pointid(qh, point), facet->id, bestfacet->id);
1342 0 : qh_errexit2(qh, qh_ERRqhull, facet, bestfacet);
1343 : }
1344 208091 : if (qh->NARROWhull) {
1345 0 : if (qh->DELAUNAY && !isoutside && bestdist >= -qh->MAXcoplanar)
1346 0 : qh_joggle_restart(qh, "nearly incident point (narrow hull)");
1347 0 : if (qh->KEEPnearinside) {
1348 0 : if (bestdist >= -qh->NEARinside)
1349 0 : isoutside= True;
1350 0 : }else if (bestdist >= -qh->MAXcoplanar)
1351 0 : isoutside= True;
1352 : }
1353 :
1354 208091 : if (isoutside) {
1355 208090 : if (!bestfacet->outsideset
1356 181577 : || !qh_setlast(bestfacet->outsideset)) { /* empty outside set */
1357 26513 : qh_setappend(qh, &(bestfacet->outsideset), point);
1358 26513 : if (!qh->NARROWhull || bestdist > qh->MINoutside)
1359 26513 : isnewoutside= True;
1360 : #if !qh_COMPUTEfurthest
1361 26513 : bestfacet->furthestdist= bestdist;
1362 : #endif
1363 : }else {
1364 : #if qh_COMPUTEfurthest
1365 : zinc_(Zcomputefurthest);
1366 : qh_distplane(qh, oldfurthest, bestfacet, &previousdist);
1367 : if (previousdist < bestdist)
1368 : qh_setappend(qh, &(bestfacet->outsideset), point);
1369 : else
1370 : qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
1371 : #else
1372 181577 : previousdist= bestfacet->furthestdist;
1373 181577 : if (previousdist < bestdist) {
1374 31526 : qh_setappend(qh, &(bestfacet->outsideset), point);
1375 31526 : bestfacet->furthestdist= bestdist;
1376 31526 : if (qh->NARROWhull && previousdist < qh->MINoutside && bestdist >= qh->MINoutside)
1377 0 : isnewoutside= True;
1378 : }else
1379 150051 : qh_setappend2ndlast(qh, &(bestfacet->outsideset), point);
1380 : #endif
1381 : }
1382 208090 : if (isnewoutside && qh->facet_next != bestfacet) {
1383 26513 : if (bestfacet->newfacet) {
1384 26513 : if (qh->facet_next->newfacet)
1385 0 : qh->facet_next= qh->newfacet_list; /* make sure it's after qh.facet_next */
1386 : }else {
1387 0 : qh_removefacet(qh, bestfacet); /* make sure it's after qh.facet_next */
1388 0 : qh_appendfacet(qh, bestfacet);
1389 0 : if(qh->newfacet_list){
1390 0 : bestfacet->newfacet= True;
1391 : }
1392 : }
1393 : }
1394 208090 : qh->num_outside++;
1395 208090 : trace4((qh, qh->ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d newfacet? %d, newoutside? %d (or narrowhull)\n",
1396 : qh_pointid(qh, point), bestfacet->id, bestfacet->newfacet, isnewoutside));
1397 1 : }else if (qh->DELAUNAY || bestdist >= -qh->MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */
1398 1 : if (qh->DELAUNAY)
1399 1 : qh_joggle_restart(qh, "nearly incident point");
1400 : /* allow coplanar points with joggle, may be interior */
1401 1 : zzinc_(Zcoplanarpart);
1402 1 : if ((qh->KEEPcoplanar + qh->KEEPnearinside) || bestdist > qh->max_outside)
1403 1 : qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
1404 : else {
1405 0 : trace4((qh, qh->ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n",
1406 : qh_pointid(qh, point), bestfacet->id));
1407 : }
1408 0 : }else if (qh->KEEPnearinside && bestdist >= -qh->NEARinside) {
1409 0 : zinc_(Zpartnear);
1410 0 : qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
1411 : }else {
1412 0 : zinc_(Zpartinside);
1413 0 : trace4((qh, qh->ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
1414 : qh_pointid(qh, point), bestfacet->id, bestdist));
1415 0 : if (qh->KEEPinside)
1416 0 : qh_partitioncoplanar(qh, point, bestfacet, &bestdist, qh->findbestnew);
1417 : }
1418 208091 : } /* partitionpoint */
1419 :
1420 : /*-<a href="qh-qhull_r.htm#TOC"
1421 : >-------------------------------</a><a name="partitionvisible">-</a>
1422 :
1423 : qh_partitionvisible(qh, allpoints, numoutside )
1424 : partitions outside points in visible facets (qh.visible_list) to qh.newfacet_list
1425 : if keeping coplanar/near-inside/inside points
1426 : partitions coplanar points; repartitions if 'allpoints' (not used)
1427 : 1st neighbor (if any) of visible facets points to a horizon facet or a new facet
1428 :
1429 : returns:
1430 : updates outside sets and coplanar sets of qh.newfacet_list
1431 : updates qh.num_outside (count of outside points)
1432 : does not truncate f.outsideset, f.coplanarset, or qh.del_vertices (see qh_deletevisible)
1433 :
1434 : notes:
1435 : called by qh_qhull, qh_addpoint, and qh_all_vertexmerges
1436 : qh.findbest_notsharp should be clear (extra work if set)
1437 :
1438 : design:
1439 : for all visible facets with outside set or coplanar set
1440 : select a newfacet for visible facet
1441 : if outside set
1442 : partition outside set into new facets
1443 : if coplanar set and keeping coplanar/near-inside/inside points
1444 : if allpoints
1445 : partition coplanar set into new facets, may be assigned outside
1446 : else
1447 : partition coplanar set into coplanar sets of new facets
1448 : for each deleted vertex
1449 : if allpoints
1450 : partition vertex into new facets, may be assigned outside
1451 : else
1452 : partition vertex into coplanar sets of new facets
1453 : */
1454 14660 : void qh_partitionvisible(qhT *qh, boolT allpoints, int *numoutside /* qh.visible_list */) {
1455 : facetT *visible, *newfacet;
1456 : pointT *point, **pointp;
1457 14660 : int delsize, coplanar=0, size;
1458 : vertexT *vertex, **vertexp;
1459 :
1460 14660 : trace3((qh, qh->ferr, 3042, "qh_partitionvisible: partition outside and coplanar points of visible and merged facets f%d into new facets f%d\n",
1461 : qh->visible_list->id, qh->newfacet_list->id));
1462 14660 : if (qh->ONLYmax)
1463 0 : maximize_(qh->MINoutside, qh->max_vertex);
1464 14660 : *numoutside= 0;
1465 73617 : FORALLvisible_facets {
1466 58957 : if (!visible->outsideset && !visible->coplanarset)
1467 32435 : continue;
1468 26522 : newfacet= qh_getreplacement(qh, visible);
1469 26522 : if (!newfacet)
1470 637 : newfacet= qh->newfacet_list;
1471 26522 : if (!newfacet->next) {
1472 0 : qh_fprintf(qh, qh->ferr, 6170, "qhull topology error (qh_partitionvisible): all new facets deleted as\n degenerate facets. Can not continue.\n");
1473 0 : qh_errexit(qh, qh_ERRtopology, NULL, NULL);
1474 : }
1475 26522 : if (visible->outsideset) {
1476 26519 : size= qh_setsize(qh, visible->outsideset);
1477 26519 : *numoutside += size;
1478 26519 : qh->num_outside -= size;
1479 234610 : FOREACHpoint_(visible->outsideset)
1480 208091 : qh_partitionpoint(qh, point, newfacet);
1481 : }
1482 26522 : if (visible->coplanarset && (qh->KEEPcoplanar + qh->KEEPinside + qh->KEEPnearinside)) {
1483 3 : size= qh_setsize(qh, visible->coplanarset);
1484 3 : coplanar += size;
1485 6 : FOREACHpoint_(visible->coplanarset) {
1486 3 : if (allpoints) /* not used */
1487 0 : qh_partitionpoint(qh, point, newfacet);
1488 : else
1489 3 : qh_partitioncoplanar(qh, point, newfacet, NULL, qh->findbestnew);
1490 : }
1491 : }
1492 : }
1493 14660 : delsize= qh_setsize(qh, qh->del_vertices);
1494 14660 : if (delsize > 0) {
1495 0 : trace3((qh, qh->ferr, 3049, "qh_partitionvisible: partition %d deleted vertices as coplanar? %d points into new facets f%d\n",
1496 : delsize, !allpoints, qh->newfacet_list->id));
1497 0 : FOREACHvertex_(qh->del_vertices) {
1498 0 : if (vertex->point && !vertex->partitioned) {
1499 0 : if (!qh->newfacet_list || qh->newfacet_list == qh->facet_tail) {
1500 0 : qh_fprintf(qh, qh->ferr, 6284, "qhull internal error (qh_partitionvisible): all new facets deleted or none defined. Can not partition deleted v%d.\n", vertex->id);
1501 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
1502 : }
1503 0 : if (allpoints) /* not used */
1504 : /* [apr'2019] infinite loop if vertex recreates the same facets from the same horizon
1505 : e.g., qh_partitionpoint if qh.DELAUNAY with qh.MERGEindependent for all mergetype, ../eg/qtest.sh t427764 '1000 s W1e-13 D3' 'd' */
1506 0 : qh_partitionpoint(qh, vertex->point, qh->newfacet_list);
1507 : else
1508 0 : qh_partitioncoplanar(qh, vertex->point, qh->newfacet_list, NULL, qh_ALL); /* search all new facets */
1509 0 : vertex->partitioned= True;
1510 : }
1511 : }
1512 : }
1513 14660 : trace1((qh, qh->ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets, %d points from coplanarsets, and %d deleted vertices\n", *numoutside, coplanar, delsize));
1514 14660 : } /* partitionvisible */
1515 :
1516 : /*-<a href="qh-qhull_r.htm#TOC"
1517 : >-------------------------------</a><a name="printsummary">-</a>
1518 :
1519 : qh_printsummary(qh, fp )
1520 : prints summary to fp
1521 :
1522 : notes:
1523 : not in io_r.c so that user_eg.c can prevent io_r.c from loading
1524 : qh_printsummary and qh_countfacets must match counts
1525 : updates qh.facet_visit to detect infinite loop
1526 :
1527 : design:
1528 : determine number of points, vertices, and coplanar points
1529 : print summary
1530 : */
1531 0 : void qh_printsummary(qhT *qh, FILE *fp) {
1532 : realT ratio, outerplane, innerplane;
1533 : double cpu;
1534 0 : int size, id, nummerged, numpinched, numvertices, numcoplanars= 0, nonsimplicial=0, numdelaunay= 0;
1535 : facetT *facet;
1536 : const char *s;
1537 0 : int numdel= zzval_(Zdelvertextot);
1538 0 : int numtricoplanars= 0;
1539 : boolT goodused;
1540 :
1541 0 : size= qh->num_points + qh_setsize(qh, qh->other_points);
1542 0 : numvertices= qh->num_vertices - qh_setsize(qh, qh->del_vertices);
1543 0 : id= qh_pointid(qh, qh->GOODpointp);
1544 0 : if (!qh_checklists(qh, qh->facet_list) && !qh->ERREXITcalled) {
1545 0 : qh_fprintf(qh, fp, 6372, "qhull internal error: qh_checklists failed at qh_printsummary\n");
1546 0 : if (qh->num_facets < 4000)
1547 0 : qh_printlists(qh);
1548 0 : qh_errexit(qh, qh_ERRqhull, NULL, NULL);
1549 : }
1550 0 : if (qh->DELAUNAY && qh->ERREXITcalled) {
1551 : /* update f.good and determine qh.num_good as in qh_findgood_all */
1552 0 : FORALLfacets {
1553 0 : if (facet->visible)
1554 0 : facet->good= False; /* will be deleted */
1555 0 : else if (facet->good) {
1556 0 : if (facet->normal && !qh_inthresholds(qh, facet->normal, NULL))
1557 0 : facet->good= False;
1558 : else
1559 0 : numdelaunay++;
1560 : }
1561 : }
1562 0 : qh->num_good= numdelaunay;
1563 : }
1564 0 : FORALLfacets {
1565 0 : if (facet->coplanarset)
1566 0 : numcoplanars += qh_setsize(qh, facet->coplanarset);
1567 0 : if (facet->good) {
1568 0 : if (facet->simplicial) {
1569 0 : if (facet->keepcentrum && facet->tricoplanar)
1570 0 : numtricoplanars++;
1571 0 : }else if (qh_setsize(qh, facet->vertices) != qh->hull_dim)
1572 0 : nonsimplicial++;
1573 : }
1574 : }
1575 0 : if (id >=0 && qh->STOPcone-1 != id && -qh->STOPpoint-1 != id)
1576 0 : size--;
1577 0 : if (qh->STOPadd || qh->STOPcone || qh->STOPpoint)
1578 0 : qh_fprintf(qh, fp, 9288, "\nEarly exit due to 'TAn', 'TVn', 'TCn', 'TRn', or precision error with 'QJn'.");
1579 0 : goodused= False;
1580 0 : if (qh->ERREXITcalled)
1581 : ; /* qh_findgood_all not called */
1582 0 : else if (qh->UPPERdelaunay) {
1583 0 : if (qh->GOODvertex || qh->GOODpoint || qh->SPLITthresholds)
1584 0 : goodused= True;
1585 0 : }else if (qh->DELAUNAY) {
1586 0 : if (qh->GOODvertex || qh->GOODpoint || qh->GOODthreshold)
1587 0 : goodused= True;
1588 0 : }else if (qh->num_good > 0 || qh->GOODthreshold)
1589 0 : goodused= True;
1590 0 : nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot);
1591 0 : if (qh->VORONOI) {
1592 0 : if (qh->UPPERdelaunay)
1593 0 : qh_fprintf(qh, fp, 9289, "\n\
1594 : Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
1595 : else
1596 0 : qh_fprintf(qh, fp, 9290, "\n\
1597 : Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
1598 0 : qh_fprintf(qh, fp, 9291, " Number of Voronoi regions%s: %d\n",
1599 0 : qh->ATinfinity ? " and at-infinity" : "", numvertices);
1600 0 : if (numdel)
1601 0 : qh_fprintf(qh, fp, 9292, " Total number of deleted points due to merging: %d\n", numdel);
1602 0 : if (numcoplanars - numdel > 0)
1603 0 : qh_fprintf(qh, fp, 9293, " Number of nearly incident points: %d\n", numcoplanars - numdel);
1604 0 : else if (size - numvertices - numdel > 0)
1605 0 : qh_fprintf(qh, fp, 9294, " Total number of nearly incident points: %d\n", size - numvertices - numdel);
1606 0 : qh_fprintf(qh, fp, 9295, " Number of%s Voronoi vertices: %d\n",
1607 : goodused ? " 'good'" : "", qh->num_good);
1608 0 : if (nonsimplicial)
1609 0 : qh_fprintf(qh, fp, 9296, " Number of%s non-simplicial Voronoi vertices: %d\n",
1610 : goodused ? " 'good'" : "", nonsimplicial);
1611 0 : }else if (qh->DELAUNAY) {
1612 0 : if (qh->UPPERdelaunay)
1613 0 : qh_fprintf(qh, fp, 9297, "\n\
1614 : Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
1615 : else
1616 0 : qh_fprintf(qh, fp, 9298, "\n\
1617 : Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
1618 0 : qh_fprintf(qh, fp, 9299, " Number of input sites%s: %d\n",
1619 0 : qh->ATinfinity ? " and at-infinity" : "", numvertices);
1620 0 : if (numdel)
1621 0 : qh_fprintf(qh, fp, 9300, " Total number of deleted points due to merging: %d\n", numdel);
1622 0 : if (numcoplanars - numdel > 0)
1623 0 : qh_fprintf(qh, fp, 9301, " Number of nearly incident points: %d\n", numcoplanars - numdel);
1624 0 : else if (size - numvertices - numdel > 0)
1625 0 : qh_fprintf(qh, fp, 9302, " Total number of nearly incident points: %d\n", size - numvertices - numdel);
1626 0 : qh_fprintf(qh, fp, 9303, " Number of%s Delaunay regions: %d\n",
1627 : goodused ? " 'good'" : "", qh->num_good);
1628 0 : if (nonsimplicial)
1629 0 : qh_fprintf(qh, fp, 9304, " Number of%s non-simplicial Delaunay regions: %d\n",
1630 : goodused ? " 'good'" : "", nonsimplicial);
1631 0 : }else if (qh->HALFspace) {
1632 0 : qh_fprintf(qh, fp, 9305, "\n\
1633 : Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
1634 0 : qh_fprintf(qh, fp, 9306, " Number of halfspaces: %d\n", size);
1635 0 : qh_fprintf(qh, fp, 9307, " Number of non-redundant halfspaces: %d\n", numvertices);
1636 0 : if (numcoplanars) {
1637 0 : if (qh->KEEPinside && qh->KEEPcoplanar)
1638 0 : s= "similar and redundant";
1639 0 : else if (qh->KEEPinside)
1640 0 : s= "redundant";
1641 : else
1642 0 : s= "similar";
1643 0 : qh_fprintf(qh, fp, 9308, " Number of %s halfspaces: %d\n", s, numcoplanars);
1644 : }
1645 0 : qh_fprintf(qh, fp, 9309, " Number of intersection points: %d\n", qh->num_facets - qh->num_visible);
1646 0 : if (goodused)
1647 0 : qh_fprintf(qh, fp, 9310, " Number of 'good' intersection points: %d\n", qh->num_good);
1648 0 : if (nonsimplicial)
1649 0 : qh_fprintf(qh, fp, 9311, " Number of%s non-simplicial intersection points: %d\n",
1650 : goodused ? " 'good'" : "", nonsimplicial);
1651 : }else {
1652 0 : qh_fprintf(qh, fp, 9312, "\n\
1653 : Convex hull of %d points in %d-d:\n\n", size, qh->hull_dim);
1654 0 : qh_fprintf(qh, fp, 9313, " Number of vertices: %d\n", numvertices);
1655 0 : if (numcoplanars) {
1656 0 : if (qh->KEEPinside && qh->KEEPcoplanar)
1657 0 : s= "coplanar and interior";
1658 0 : else if (qh->KEEPinside)
1659 0 : s= "interior";
1660 : else
1661 0 : s= "coplanar";
1662 0 : qh_fprintf(qh, fp, 9314, " Number of %s points: %d\n", s, numcoplanars);
1663 : }
1664 0 : qh_fprintf(qh, fp, 9315, " Number of facets: %d\n", qh->num_facets - qh->num_visible);
1665 0 : if (goodused)
1666 0 : qh_fprintf(qh, fp, 9316, " Number of 'good' facets: %d\n", qh->num_good);
1667 0 : if (nonsimplicial)
1668 0 : qh_fprintf(qh, fp, 9317, " Number of%s non-simplicial facets: %d\n",
1669 : goodused ? " 'good'" : "", nonsimplicial);
1670 : }
1671 0 : if (numtricoplanars)
1672 0 : qh_fprintf(qh, fp, 9318, " Number of triangulated facets: %d\n", numtricoplanars);
1673 0 : qh_fprintf(qh, fp, 9319, "\nStatistics for: %s | %s",
1674 0 : qh->rbox_command, qh->qhull_command);
1675 0 : if (qh->ROTATErandom != INT_MIN)
1676 0 : qh_fprintf(qh, fp, 9320, " QR%d\n\n", qh->ROTATErandom);
1677 : else
1678 0 : qh_fprintf(qh, fp, 9321, "\n\n");
1679 0 : qh_fprintf(qh, fp, 9322, " Number of points processed: %d\n", zzval_(Zprocessed));
1680 0 : qh_fprintf(qh, fp, 9323, " Number of hyperplanes created: %d\n", zzval_(Zsetplane));
1681 0 : if (qh->DELAUNAY)
1682 0 : qh_fprintf(qh, fp, 9324, " Number of facets in hull: %d\n", qh->num_facets - qh->num_visible);
1683 0 : qh_fprintf(qh, fp, 9325, " Number of distance tests for qhull: %d\n", zzval_(Zpartition)+
1684 0 : zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar));
1685 : #if 0 /* NOTE: must print before printstatistics() */
1686 : {realT stddev, ave;
1687 : qh_fprintf(qh, fp, 9326, " average new facet balance: %2.2g\n",
1688 : wval_(Wnewbalance)/zval_(Zprocessed));
1689 : stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance),
1690 : wval_(Wnewbalance2), &ave);
1691 : qh_fprintf(qh, fp, 9327, " new facet standard deviation: %2.2g\n", stddev);
1692 : qh_fprintf(qh, fp, 9328, " average partition balance: %2.2g\n",
1693 : wval_(Wpbalance)/zval_(Zpbalance));
1694 : stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance),
1695 : wval_(Wpbalance2), &ave);
1696 : qh_fprintf(qh, fp, 9329, " partition standard deviation: %2.2g\n", stddev);
1697 : }
1698 : #endif
1699 0 : if (nummerged) {
1700 0 : qh_fprintf(qh, fp, 9330," Number of distance tests for merging: %d\n",zzval_(Zbestdist)+
1701 0 : zzval_(Zcentrumtests)+zzval_(Zvertextests)+zzval_(Zdistcheck)+zzval_(Zdistzero));
1702 0 : qh_fprintf(qh, fp, 9331," Number of distance tests for checking: %d\n",zzval_(Zcheckpart)+zzval_(Zdistconvex));
1703 0 : qh_fprintf(qh, fp, 9332," Number of merged facets: %d\n", nummerged);
1704 : }
1705 0 : numpinched= zzval_(Zpinchduplicate) + zzval_(Zpinchedvertex);
1706 0 : if (numpinched)
1707 0 : qh_fprintf(qh, fp, 9375," Number of merged pinched vertices: %d\n", numpinched);
1708 0 : if (!qh->RANDOMoutside && qh->QHULLfinished) {
1709 0 : cpu= (double)qh->hulltime;
1710 0 : cpu /= (double)qh_SECticks;
1711 0 : wval_(Wcpu)= cpu;
1712 0 : qh_fprintf(qh, fp, 9333, " CPU seconds to compute hull (after input): %2.4g\n", cpu);
1713 : }
1714 0 : if (qh->RERUN) {
1715 0 : if (!qh->PREmerge && !qh->MERGEexact)
1716 0 : qh_fprintf(qh, fp, 9334, " Percentage of runs with precision errors: %4.1f\n",
1717 0 : zzval_(Zretry)*100.0/qh->build_cnt); /* careful of order */
1718 0 : }else if (qh->JOGGLEmax < REALmax/2) {
1719 0 : if (zzval_(Zretry))
1720 0 : qh_fprintf(qh, fp, 9335, " After %d retries, input joggled by: %2.2g\n",
1721 : zzval_(Zretry), qh->JOGGLEmax);
1722 : else
1723 0 : qh_fprintf(qh, fp, 9336, " Input joggled by: %2.2g\n", qh->JOGGLEmax);
1724 : }
1725 0 : if (qh->totarea != 0.0)
1726 0 : qh_fprintf(qh, fp, 9337, " %s facet area: %2.8g\n",
1727 0 : zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totarea);
1728 0 : if (qh->totvol != 0.0)
1729 0 : qh_fprintf(qh, fp, 9338, " %s volume: %2.8g\n",
1730 0 : zzval_(Ztotmerge) ? "Approximate" : "Total", qh->totvol);
1731 0 : if (qh->MERGING) {
1732 0 : qh_outerinner(qh, NULL, &outerplane, &innerplane);
1733 0 : if (outerplane > 2 * qh->DISTround) {
1734 0 : qh_fprintf(qh, fp, 9339, " Maximum distance of point above facet: %2.2g", outerplane);
1735 0 : ratio= outerplane/(qh->ONEmerge + qh->DISTround);
1736 : /* don't report ratio if MINoutside is large */
1737 0 : if (ratio > 0.05 && 2* qh->ONEmerge > qh->MINoutside && qh->JOGGLEmax > REALmax/2)
1738 0 : qh_fprintf(qh, fp, 9340, " (%.1fx)\n", ratio);
1739 : else
1740 0 : qh_fprintf(qh, fp, 9341, "\n");
1741 : }
1742 0 : if (innerplane < -2 * qh->DISTround) {
1743 0 : qh_fprintf(qh, fp, 9342, " Maximum distance of vertex below facet: %2.2g", innerplane);
1744 0 : ratio= -innerplane/(qh->ONEmerge+qh->DISTround);
1745 0 : if (ratio > 0.05 && qh->JOGGLEmax > REALmax/2)
1746 0 : qh_fprintf(qh, fp, 9343, " (%.1fx)\n", ratio);
1747 : else
1748 0 : qh_fprintf(qh, fp, 9344, "\n");
1749 : }
1750 : }
1751 0 : qh_fprintf(qh, fp, 9345, "\n");
1752 0 : } /* printsummary */
1753 :
1754 :
|