1 |
/*<html><pre> -<a href="qh-poly.htm" |
2 |
>-------------------------------</a><a name="TOP">-</a> |
3 |
|
4 |
poly.c |
5 |
implements polygons and simplices |
6 |
|
7 |
see qh-poly.htm, poly.h and qhull.h |
8 |
|
9 |
infrequent code is in poly2.c |
10 |
(all but top 50 and their callers 12/3/95) |
11 |
|
12 |
copyright (c) 1993-2003, The Geometry Center |
13 |
*/ |
14 |
|
15 |
#include "QuickHull/qhull_a.h" |
16 |
|
17 |
/*======== functions in alphabetical order ==========*/ |
18 |
|
19 |
/*-<a href="qh-poly.htm#TOC" |
20 |
>-------------------------------</a><a name="appendfacet">-</a> |
21 |
|
22 |
qh_appendfacet( facet ) |
23 |
appends facet to end of qh.facet_list, |
24 |
|
25 |
returns: |
26 |
updates qh.newfacet_list, facet_next, facet_list |
27 |
increments qh.numfacets |
28 |
|
29 |
notes: |
30 |
assumes qh.facet_list/facet_tail is defined (createsimplex) |
31 |
|
32 |
see: |
33 |
qh_removefacet() |
34 |
|
35 |
*/ |
36 |
void qh_appendfacet(facetT *facet) { |
37 |
facetT *tail= qh facet_tail; |
38 |
|
39 |
if (tail == qh newfacet_list) |
40 |
qh newfacet_list= facet; |
41 |
if (tail == qh facet_next) |
42 |
qh facet_next= facet; |
43 |
facet->previous= tail->previous; |
44 |
facet->next= tail; |
45 |
if (tail->previous) |
46 |
tail->previous->next= facet; |
47 |
else |
48 |
qh facet_list= facet; |
49 |
tail->previous= facet; |
50 |
qh num_facets++; |
51 |
trace4((qh ferr, "qh_appendfacet: append f%d to facet_list\n", facet->id)); |
52 |
} /* appendfacet */ |
53 |
|
54 |
|
55 |
/*-<a href="qh-poly.htm#TOC" |
56 |
>-------------------------------</a><a name="appendvertex">-</a> |
57 |
|
58 |
qh_appendvertex( vertex ) |
59 |
appends vertex to end of qh.vertex_list, |
60 |
|
61 |
returns: |
62 |
sets vertex->newlist |
63 |
updates qh.vertex_list, newvertex_list |
64 |
increments qh.num_vertices |
65 |
|
66 |
notes: |
67 |
assumes qh.vertex_list/vertex_tail is defined (createsimplex) |
68 |
|
69 |
*/ |
70 |
void qh_appendvertex (vertexT *vertex) { |
71 |
vertexT *tail= qh vertex_tail; |
72 |
|
73 |
if (tail == qh newvertex_list) |
74 |
qh newvertex_list= vertex; |
75 |
vertex->newlist= True; |
76 |
vertex->previous= tail->previous; |
77 |
vertex->next= tail; |
78 |
if (tail->previous) |
79 |
tail->previous->next= vertex; |
80 |
else |
81 |
qh vertex_list= vertex; |
82 |
tail->previous= vertex; |
83 |
qh num_vertices++; |
84 |
trace4((qh ferr, "qh_appendvertex: append v%d to vertex_list\n", vertex->id)); |
85 |
} /* appendvertex */ |
86 |
|
87 |
|
88 |
/*-<a href="qh-poly.htm#TOC" |
89 |
>-------------------------------</a><a name="attachnewfacets">-</a> |
90 |
|
91 |
qh_attachnewfacets( ) |
92 |
attach horizon facets to new facets in qh.newfacet_list |
93 |
newfacets have neighbor and ridge links to horizon but not vice versa |
94 |
only needed for qh.ONLYgood |
95 |
|
96 |
returns: |
97 |
set qh.NEWfacets |
98 |
horizon facets linked to new facets |
99 |
ridges changed from visible facets to new facets |
100 |
simplicial ridges deleted |
101 |
qh.visible_list, no ridges valid |
102 |
facet->f.replace is a newfacet (if any) |
103 |
|
104 |
design: |
105 |
delete interior ridges and neighbor sets by |
106 |
for each visible, non-simplicial facet |
107 |
for each ridge |
108 |
if last visit or if neighbor is simplicial |
109 |
if horizon neighbor |
110 |
delete ridge for horizon's ridge set |
111 |
delete ridge |
112 |
erase neighbor set |
113 |
attach horizon facets and new facets by |
114 |
for all new facets |
115 |
if corresponding horizon facet is simplicial |
116 |
locate corresponding visible facet {may be more than one} |
117 |
link visible facet to new facet |
118 |
replace visible facet with new facet in horizon |
119 |
else it's non-simplicial |
120 |
for all visible neighbors of the horizon facet |
121 |
link visible neighbor to new facet |
122 |
delete visible neighbor from horizon facet |
123 |
append new facet to horizon's neighbors |
124 |
the first ridge of the new facet is the horizon ridge |
125 |
link the new facet into the horizon ridge |
126 |
*/ |
127 |
void qh_attachnewfacets (void ) { |
128 |
facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible; |
129 |
ridgeT *ridge, **ridgep; |
130 |
|
131 |
qh NEWfacets= True; |
132 |
trace3((qh ferr, "qh_attachnewfacets: delete interior ridges\n")); |
133 |
qh visit_id++; |
134 |
FORALLvisible_facets { |
135 |
visible->visitid= qh visit_id; |
136 |
if (visible->ridges) { |
137 |
FOREACHridge_(visible->ridges) { |
138 |
neighbor= otherfacet_(ridge, visible); |
139 |
if (neighbor->visitid == qh visit_id |
140 |
|| (!neighbor->visible && neighbor->simplicial)) { |
141 |
if (!neighbor->visible) /* delete ridge for simplicial horizon */ |
142 |
qh_setdel (neighbor->ridges, ridge); |
143 |
qh_setfree (&(ridge->vertices)); /* delete on 2nd visit */ |
144 |
qh_memfree (ridge, sizeof(ridgeT)); |
145 |
} |
146 |
} |
147 |
SETfirst_(visible->ridges)= NULL; |
148 |
} |
149 |
SETfirst_(visible->neighbors)= NULL; |
150 |
} |
151 |
trace1((qh ferr, "qh_attachnewfacets: attach horizon facets to new facets\n")); |
152 |
FORALLnew_facets { |
153 |
horizon= SETfirstt_(newfacet->neighbors, facetT); |
154 |
if (horizon->simplicial) { |
155 |
visible= NULL; |
156 |
FOREACHneighbor_(horizon) { /* may have more than one horizon ridge */ |
157 |
if (neighbor->visible) { |
158 |
if (visible) { |
159 |
if (qh_setequal_skip (newfacet->vertices, 0, horizon->vertices, |
160 |
SETindex_(horizon->neighbors, neighbor))) { |
161 |
visible= neighbor; |
162 |
break; |
163 |
} |
164 |
}else |
165 |
visible= neighbor; |
166 |
} |
167 |
} |
168 |
if (visible) { |
169 |
visible->f.replace= newfacet; |
170 |
qh_setreplace (horizon->neighbors, visible, newfacet); |
171 |
}else { |
172 |
fprintf (qh ferr, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n", |
173 |
horizon->id, newfacet->id); |
174 |
qh_errexit2 (qh_ERRqhull, horizon, newfacet); |
175 |
} |
176 |
}else { /* non-simplicial, with a ridge for newfacet */ |
177 |
FOREACHneighbor_(horizon) { /* may hold for many new facets */ |
178 |
if (neighbor->visible) { |
179 |
neighbor->f.replace= newfacet; |
180 |
qh_setdelnth (horizon->neighbors, |
181 |
SETindex_(horizon->neighbors, neighbor)); |
182 |
neighborp--; /* repeat */ |
183 |
} |
184 |
} |
185 |
qh_setappend (&horizon->neighbors, newfacet); |
186 |
ridge= SETfirstt_(newfacet->ridges, ridgeT); |
187 |
if (ridge->top == horizon) |
188 |
ridge->bottom= newfacet; |
189 |
else |
190 |
ridge->top= newfacet; |
191 |
} |
192 |
} /* newfacets */ |
193 |
if (qh PRINTstatistics) { |
194 |
FORALLvisible_facets { |
195 |
if (!visible->f.replace) |
196 |
zinc_(Zinsidevisible); |
197 |
} |
198 |
} |
199 |
} /* attachnewfacets */ |
200 |
|
201 |
/*-<a href="qh-poly.htm#TOC" |
202 |
>-------------------------------</a><a name="checkflipped">-</a> |
203 |
|
204 |
qh_checkflipped( facet, dist, allerror ) |
205 |
checks facet orientation to interior point |
206 |
|
207 |
if allerror set, |
208 |
tests against qh.DISTround |
209 |
else |
210 |
tests against 0 since tested against DISTround before |
211 |
|
212 |
returns: |
213 |
False if it flipped orientation (sets facet->flipped) |
214 |
distance if non-NULL |
215 |
*/ |
216 |
boolT qh_checkflipped (facetT *facet, realT *distp, boolT allerror) { |
217 |
realT dist; |
218 |
|
219 |
if (facet->flipped && !distp) |
220 |
return False; |
221 |
zzinc_(Zdistcheck); |
222 |
qh_distplane(qh interior_point, facet, &dist); |
223 |
if (distp) |
224 |
*distp= dist; |
225 |
if ((allerror && dist > -qh DISTround)|| (!allerror && dist >= 0.0)) { |
226 |
facet->flipped= True; |
227 |
zzinc_(Zflippedfacets); |
228 |
trace0((qh ferr, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n", facet->id, dist, qh furthest_id)); |
229 |
qh_precision ("flipped facet"); |
230 |
return False; |
231 |
} |
232 |
return True; |
233 |
} /* checkflipped */ |
234 |
|
235 |
/*-<a href="qh-poly.htm#TOC" |
236 |
>-------------------------------</a><a name="delfacet">-</a> |
237 |
|
238 |
qh_delfacet( facet ) |
239 |
removes facet from facet_list and frees up its memory |
240 |
|
241 |
notes: |
242 |
assumes vertices and ridges already freed |
243 |
*/ |
244 |
void qh_delfacet(facetT *facet) { |
245 |
void **freelistp; /* used !qh_NOmem */ |
246 |
|
247 |
trace4((qh ferr, "qh_delfacet: delete f%d\n", facet->id)); |
248 |
if (facet == qh tracefacet) |
249 |
qh tracefacet= NULL; |
250 |
if (facet == qh GOODclosest) |
251 |
qh GOODclosest= NULL; |
252 |
qh_removefacet(facet); |
253 |
if (!facet->tricoplanar || facet->keepcentrum) { |
254 |
qh_memfree_(facet->normal, qh normal_size, freelistp); |
255 |
if (qh CENTERtype == qh_ASvoronoi) { /* uses macro calls */ |
256 |
qh_memfree_(facet->center, qh center_size, freelistp); |
257 |
}else /* AScentrum */ { |
258 |
qh_memfree_(facet->center, qh normal_size, freelistp); |
259 |
} |
260 |
} |
261 |
qh_setfree(&(facet->neighbors)); |
262 |
if (facet->ridges) |
263 |
qh_setfree(&(facet->ridges)); |
264 |
qh_setfree(&(facet->vertices)); |
265 |
if (facet->outsideset) |
266 |
qh_setfree(&(facet->outsideset)); |
267 |
if (facet->coplanarset) |
268 |
qh_setfree(&(facet->coplanarset)); |
269 |
qh_memfree_(facet, sizeof(facetT), freelistp); |
270 |
} /* delfacet */ |
271 |
|
272 |
|
273 |
/*-<a href="qh-poly.htm#TOC" |
274 |
>-------------------------------</a><a name="deletevisible">-</a> |
275 |
|
276 |
qh_deletevisible() |
277 |
delete visible facets and vertices |
278 |
|
279 |
returns: |
280 |
deletes each facet and removes from facetlist |
281 |
at exit, qh.visible_list empty (== qh.newfacet_list) |
282 |
|
283 |
notes: |
284 |
ridges already deleted |
285 |
horizon facets do not reference facets on qh.visible_list |
286 |
new facets in qh.newfacet_list |
287 |
uses qh.visit_id; |
288 |
*/ |
289 |
void qh_deletevisible (void /*qh visible_list*/) { |
290 |
facetT *visible, *nextfacet; |
291 |
vertexT *vertex, **vertexp; |
292 |
int numvisible= 0, numdel= qh_setsize(qh del_vertices); |
293 |
|
294 |
trace1((qh ferr, "qh_deletevisible: delete %d visible facets and %d vertices\n", qh num_visible, numdel)); |
295 |
for (visible= qh visible_list; visible && visible->visible; |
296 |
visible= nextfacet) { /* deleting current */ |
297 |
nextfacet= visible->next; |
298 |
numvisible++; |
299 |
qh_delfacet(visible); |
300 |
} |
301 |
if (numvisible != qh num_visible) { |
302 |
fprintf (qh ferr, "qhull internal error (qh_deletevisible): qh num_visible %d is not number of visible facets %d\n", |
303 |
qh num_visible, numvisible); |
304 |
qh_errexit (qh_ERRqhull, NULL, NULL); |
305 |
} |
306 |
qh num_visible= 0; |
307 |
zadd_(Zvisfacettot, numvisible); |
308 |
zmax_(Zvisfacetmax, numvisible); |
309 |
zzadd_(Zdelvertextot, numdel); |
310 |
zmax_(Zdelvertexmax, numdel); |
311 |
FOREACHvertex_(qh del_vertices) |
312 |
qh_delvertex (vertex); |
313 |
qh_settruncate (qh del_vertices, 0); |
314 |
} /* deletevisible */ |
315 |
|
316 |
/*-<a href="qh-poly.htm#TOC" |
317 |
>-------------------------------</a><a name="facetintersect">-</a> |
318 |
|
319 |
qh_facetintersect( facetA, facetB, skipa, skipB, prepend ) |
320 |
return vertices for intersection of two simplicial facets |
321 |
may include 1 prepended entry (if more, need to settemppush) |
322 |
|
323 |
returns: |
324 |
returns set of qh.hull_dim-1 + prepend vertices |
325 |
returns skipped index for each test and checks for exactly one |
326 |
|
327 |
notes: |
328 |
does not need settemp since set in quick memory |
329 |
|
330 |
see also: |
331 |
qh_vertexintersect and qh_vertexintersect_new |
332 |
please use qh_setnew_delnthsorted to get nth ridge (no skip information) |
333 |
|
334 |
design: |
335 |
locate skipped vertex by scanning facet A's neighbors |
336 |
locate skipped vertex by scanning facet B's neighbors |
337 |
intersect the vertex sets |
338 |
*/ |
339 |
setT *qh_facetintersect (facetT *facetA, facetT *facetB, |
340 |
int *skipA,int *skipB, int prepend) { |
341 |
setT *intersect; |
342 |
int dim= qh hull_dim, i, j; |
343 |
facetT **neighborsA, **neighborsB; |
344 |
|
345 |
neighborsA= SETaddr_(facetA->neighbors, facetT); |
346 |
neighborsB= SETaddr_(facetB->neighbors, facetT); |
347 |
i= j= 0; |
348 |
if (facetB == *neighborsA++) |
349 |
*skipA= 0; |
350 |
else if (facetB == *neighborsA++) |
351 |
*skipA= 1; |
352 |
else if (facetB == *neighborsA++) |
353 |
*skipA= 2; |
354 |
else { |
355 |
for (i= 3; i < dim; i++) { |
356 |
if (facetB == *neighborsA++) { |
357 |
*skipA= i; |
358 |
break; |
359 |
} |
360 |
} |
361 |
} |
362 |
if (facetA == *neighborsB++) |
363 |
*skipB= 0; |
364 |
else if (facetA == *neighborsB++) |
365 |
*skipB= 1; |
366 |
else if (facetA == *neighborsB++) |
367 |
*skipB= 2; |
368 |
else { |
369 |
for (j= 3; j < dim; j++) { |
370 |
if (facetA == *neighborsB++) { |
371 |
*skipB= j; |
372 |
break; |
373 |
} |
374 |
} |
375 |
} |
376 |
if (i >= dim || j >= dim) { |
377 |
fprintf (qh ferr, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n", |
378 |
facetA->id, facetB->id); |
379 |
qh_errexit2 (qh_ERRqhull, facetA, facetB); |
380 |
} |
381 |
intersect= qh_setnew_delnthsorted (facetA->vertices, qh hull_dim, *skipA, prepend); |
382 |
trace4((qh ferr, "qh_facetintersect: f%d skip %d matches f%d skip %d\n", facetA->id, *skipA, facetB->id, *skipB)); |
383 |
return(intersect); |
384 |
} /* facetintersect */ |
385 |
|
386 |
/*-<a href="qh-poly.htm#TOC" |
387 |
>-------------------------------</a><a name="gethash">-</a> |
388 |
|
389 |
qh_gethash( hashsize, set, size, firstindex, skipelem ) |
390 |
return hashvalue for a set with firstindex and skipelem |
391 |
|
392 |
notes: |
393 |
assumes at least firstindex+1 elements |
394 |
assumes skipelem is NULL, in set, or part of hash |
395 |
|
396 |
hashes memory addresses which may change over different runs of the same data |
397 |
using sum for hash does badly in high d |
398 |
*/ |
399 |
unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem) { |
400 |
void **elemp= SETelemaddr_(set, firstindex, void); |
401 |
ptr_intT hash = 0, elem; |
402 |
int i; |
403 |
|
404 |
switch (size-firstindex) { |
405 |
case 1: |
406 |
hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem; |
407 |
break; |
408 |
case 2: |
409 |
hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem; |
410 |
break; |
411 |
case 3: |
412 |
hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] |
413 |
- (ptr_intT) skipelem; |
414 |
break; |
415 |
case 4: |
416 |
hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] |
417 |
+ (ptr_intT)elemp[3] - (ptr_intT) skipelem; |
418 |
break; |
419 |
case 5: |
420 |
hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] |
421 |
+ (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem; |
422 |
break; |
423 |
case 6: |
424 |
hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] |
425 |
+ (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5] |
426 |
- (ptr_intT) skipelem; |
427 |
break; |
428 |
default: |
429 |
hash= 0; |
430 |
i= 3; |
431 |
do { /* this is about 10% in 10-d */ |
432 |
if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) { |
433 |
hash ^= (elem << i) + (elem >> (32-i)); |
434 |
i += 3; |
435 |
if (i >= 32) |
436 |
i -= 32; |
437 |
} |
438 |
}while(*elemp); |
439 |
break; |
440 |
} |
441 |
hash %= (ptr_intT) hashsize; |
442 |
/* hash= 0; for debugging purposes */ |
443 |
return hash; |
444 |
} /* gethash */ |
445 |
|
446 |
/*-<a href="qh-poly.htm#TOC" |
447 |
>-------------------------------</a><a name="makenewfacet">-</a> |
448 |
|
449 |
qh_makenewfacet( vertices, toporient, horizon ) |
450 |
creates a toporient? facet from vertices |
451 |
|
452 |
returns: |
453 |
returns newfacet |
454 |
adds newfacet to qh.facet_list |
455 |
newfacet->vertices= vertices |
456 |
if horizon |
457 |
newfacet->neighbor= horizon, but not vice versa |
458 |
newvertex_list updated with vertices |
459 |
*/ |
460 |
facetT *qh_makenewfacet(setT *vertices, boolT toporient,facetT *horizon) { |
461 |
facetT *newfacet; |
462 |
vertexT *vertex, **vertexp; |
463 |
|
464 |
FOREACHvertex_(vertices) { |
465 |
if (!vertex->newlist) { |
466 |
qh_removevertex (vertex); |
467 |
qh_appendvertex (vertex); |
468 |
} |
469 |
} |
470 |
newfacet= qh_newfacet(); |
471 |
newfacet->vertices= vertices; |
472 |
newfacet->toporient= toporient; |
473 |
if (horizon) |
474 |
qh_setappend(&(newfacet->neighbors), horizon); |
475 |
qh_appendfacet(newfacet); |
476 |
return(newfacet); |
477 |
} /* makenewfacet */ |
478 |
|
479 |
|
480 |
/*-<a href="qh-poly.htm#TOC" |
481 |
>-------------------------------</a><a name="makenewplanes">-</a> |
482 |
|
483 |
qh_makenewplanes() |
484 |
make new hyperplanes for facets on qh.newfacet_list |
485 |
|
486 |
returns: |
487 |
all facets have hyperplanes or are marked for merging |
488 |
doesn't create hyperplane if horizon is coplanar (will merge) |
489 |
updates qh.min_vertex if qh.JOGGLEmax |
490 |
|
491 |
notes: |
492 |
facet->f.samecycle is defined for facet->mergehorizon facets |
493 |
*/ |
494 |
void qh_makenewplanes (void /* newfacet_list */) { |
495 |
facetT *newfacet; |
496 |
|
497 |
FORALLnew_facets { |
498 |
if (!newfacet->mergehorizon) |
499 |
qh_setfacetplane (newfacet); |
500 |
} |
501 |
if (qh JOGGLEmax < REALmax/2) |
502 |
minimize_(qh min_vertex, -wwval_(Wnewvertexmax)); |
503 |
} /* makenewplanes */ |
504 |
|
505 |
/*-<a href="qh-poly.htm#TOC" |
506 |
>-------------------------------</a><a name="makenew_nonsimplicial">-</a> |
507 |
|
508 |
qh_makenew_nonsimplicial( visible, apex, numnew ) |
509 |
make new facets for ridges of a visible facet |
510 |
|
511 |
returns: |
512 |
first newfacet, bumps numnew as needed |
513 |
attaches new facets if !qh.ONLYgood |
514 |
marks ridge neighbors for simplicial visible |
515 |
if (qh.ONLYgood) |
516 |
ridges on newfacet, horizon, and visible |
517 |
else |
518 |
ridge and neighbors between newfacet and horizon |
519 |
visible facet's ridges are deleted |
520 |
|
521 |
notes: |
522 |
qh.visit_id if visible has already been processed |
523 |
sets neighbor->seen for building f.samecycle |
524 |
assumes all 'seen' flags initially false |
525 |
|
526 |
design: |
527 |
for each ridge of visible facet |
528 |
get neighbor of visible facet |
529 |
if neighbor was already processed |
530 |
delete the ridge (will delete all visible facets later) |
531 |
if neighbor is a horizon facet |
532 |
create a new facet |
533 |
if neighbor coplanar |
534 |
adds newfacet to f.samecycle for later merging |
535 |
else |
536 |
updates neighbor's neighbor set |
537 |
(checks for non-simplicial facet with multiple ridges to visible facet) |
538 |
updates neighbor's ridge set |
539 |
(checks for simplicial neighbor to non-simplicial visible facet) |
540 |
(deletes ridge if neighbor is simplicial) |
541 |
|
542 |
*/ |
543 |
#ifndef qh_NOmerge |
544 |
facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) { |
545 |
void **freelistp; /* used !qh_NOmem */ |
546 |
ridgeT *ridge, **ridgep; |
547 |
facetT *neighbor, *newfacet= NULL, *samecycle; |
548 |
setT *vertices; |
549 |
boolT toporient; |
550 |
int ridgeid; |
551 |
|
552 |
FOREACHridge_(visible->ridges) { |
553 |
ridgeid= ridge->id; |
554 |
neighbor= otherfacet_(ridge, visible); |
555 |
if (neighbor->visible) { |
556 |
if (!qh ONLYgood) { |
557 |
if (neighbor->visitid == qh visit_id) { |
558 |
qh_setfree (&(ridge->vertices)); /* delete on 2nd visit */ |
559 |
qh_memfree_(ridge, sizeof(ridgeT), freelistp); |
560 |
} |
561 |
} |
562 |
}else { /* neighbor is an horizon facet */ |
563 |
toporient= (ridge->top == visible); |
564 |
vertices= qh_setnew (qh hull_dim); /* makes sure this is quick */ |
565 |
qh_setappend (&vertices, apex); |
566 |
qh_setappend_set (&vertices, ridge->vertices); |
567 |
newfacet= qh_makenewfacet(vertices, toporient, neighbor); |
568 |
(*numnew)++; |
569 |
if (neighbor->coplanar) { |
570 |
newfacet->mergehorizon= True; |
571 |
if (!neighbor->seen) { |
572 |
newfacet->f.samecycle= newfacet; |
573 |
neighbor->f.newcycle= newfacet; |
574 |
}else { |
575 |
samecycle= neighbor->f.newcycle; |
576 |
newfacet->f.samecycle= samecycle->f.samecycle; |
577 |
samecycle->f.samecycle= newfacet; |
578 |
} |
579 |
} |
580 |
if (qh ONLYgood) { |
581 |
if (!neighbor->simplicial) |
582 |
qh_setappend(&(newfacet->ridges), ridge); |
583 |
}else { /* qh_attachnewfacets */ |
584 |
if (neighbor->seen) { |
585 |
if (neighbor->simplicial) { |
586 |
fprintf (qh ferr, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n", |
587 |
neighbor->id, visible->id); |
588 |
qh_errexit2 (qh_ERRqhull, neighbor, visible); |
589 |
} |
590 |
qh_setappend (&(neighbor->neighbors), newfacet); |
591 |
}else |
592 |
qh_setreplace (neighbor->neighbors, visible, newfacet); |
593 |
if (neighbor->simplicial) { |
594 |
qh_setdel (neighbor->ridges, ridge); |
595 |
qh_setfree (&(ridge->vertices)); |
596 |
qh_memfree (ridge, sizeof(ridgeT)); |
597 |
}else { |
598 |
qh_setappend(&(newfacet->ridges), ridge); |
599 |
if (toporient) |
600 |
ridge->top= newfacet; |
601 |
else |
602 |
ridge->bottom= newfacet; |
603 |
} |
604 |
trace4((qh ferr, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n", newfacet->id, apex->id, ridgeid, neighbor->id)); |
605 |
} |
606 |
} |
607 |
neighbor->seen= True; |
608 |
} /* for each ridge */ |
609 |
if (!qh ONLYgood) |
610 |
SETfirst_(visible->ridges)= NULL; |
611 |
return newfacet; |
612 |
} /* makenew_nonsimplicial */ |
613 |
#else /* qh_NOmerge */ |
614 |
facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) { |
615 |
return NULL; |
616 |
} |
617 |
#endif /* qh_NOmerge */ |
618 |
|
619 |
/*-<a href="qh-poly.htm#TOC" |
620 |
>-------------------------------</a><a name="makenew_simplicial">-</a> |
621 |
|
622 |
qh_makenew_simplicial( visible, apex, numnew ) |
623 |
make new facets for simplicial visible facet and apex |
624 |
|
625 |
returns: |
626 |
attaches new facets if (!qh.ONLYgood) |
627 |
neighbors between newfacet and horizon |
628 |
|
629 |
notes: |
630 |
nop if neighbor->seen or neighbor->visible (see qh_makenew_nonsimplicial) |
631 |
|
632 |
design: |
633 |
locate neighboring horizon facet for visible facet |
634 |
determine vertices and orientation |
635 |
create new facet |
636 |
if coplanar, |
637 |
add new facet to f.samecycle |
638 |
update horizon facet's neighbor list |
639 |
*/ |
640 |
facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew) { |
641 |
facetT *neighbor, **neighborp, *newfacet= NULL; |
642 |
setT *vertices; |
643 |
boolT flip, toporient; |
644 |
int horizonskip, visibleskip; |
645 |
|
646 |
FOREACHneighbor_(visible) { |
647 |
if (!neighbor->seen && !neighbor->visible) { |
648 |
vertices= qh_facetintersect(neighbor,visible, &horizonskip, &visibleskip, 1); |
649 |
SETfirst_(vertices)= apex; |
650 |
flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1)); |
651 |
if (neighbor->toporient) |
652 |
toporient= horizonskip & 0x1; |
653 |
else |
654 |
toporient= (horizonskip & 0x1) ^ 0x1; |
655 |
newfacet= qh_makenewfacet(vertices, toporient, neighbor); |
656 |
(*numnew)++; |
657 |
if (neighbor->coplanar && (qh PREmerge || qh MERGEexact)) { |
658 |
#ifndef qh_NOmerge |
659 |
newfacet->f.samecycle= newfacet; |
660 |
newfacet->mergehorizon= True; |
661 |
#endif |
662 |
} |
663 |
if (!qh ONLYgood) |
664 |
SETelem_(neighbor->neighbors, horizonskip)= newfacet; |
665 |
trace4((qh ferr, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n", newfacet->id, toporient, apex->id, neighbor->id, horizonskip, neighbor->toporient, visible->id, visibleskip, flip)); |
666 |
} |
667 |
} |
668 |
return newfacet; |
669 |
} /* makenew_simplicial */ |
670 |
|
671 |
/*-<a href="qh-poly.htm#TOC" |
672 |
>-------------------------------</a><a name="matchneighbor">-</a> |
673 |
|
674 |
qh_matchneighbor( newfacet, newskip, hashsize, hashcount ) |
675 |
either match subridge of newfacet with neighbor or add to hash_table |
676 |
|
677 |
returns: |
678 |
duplicate ridges are unmatched and marked by qh_DUPLICATEridge |
679 |
|
680 |
notes: |
681 |
ridge is newfacet->vertices w/o newskip vertex |
682 |
do not allocate memory (need to free hash_table cleanly) |
683 |
uses linear hash chains |
684 |
|
685 |
see also: |
686 |
qh_matchduplicates |
687 |
|
688 |
design: |
689 |
for each possible matching facet in qh.hash_table |
690 |
if vertices match |
691 |
set ismatch, if facets have opposite orientation |
692 |
if ismatch and matching facet doesn't have a match |
693 |
match the facets by updating their neighbor sets |
694 |
else |
695 |
indicate a duplicate ridge |
696 |
set facet hyperplane for later testing |
697 |
add facet to hashtable |
698 |
unless the other facet was already a duplicate ridge |
699 |
mark both facets with a duplicate ridge |
700 |
add other facet (if defined) to hash table |
701 |
*/ |
702 |
void qh_matchneighbor (facetT *newfacet, int newskip, int hashsize, int *hashcount) { |
703 |
boolT newfound= False; /* True, if new facet is already in hash chain */ |
704 |
boolT same, ismatch; |
705 |
int hash, scan; |
706 |
facetT *facet, *matchfacet; |
707 |
int skip, matchskip; |
708 |
|
709 |
hash= (int)qh_gethash (hashsize, newfacet->vertices, qh hull_dim, 1, |
710 |
SETelem_(newfacet->vertices, newskip)); |
711 |
trace4((qh ferr, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n", newfacet->id, newskip, hash, *hashcount)); |
712 |
zinc_(Zhashlookup); |
713 |
for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); |
714 |
scan= (++scan >= hashsize ? 0 : scan)) { |
715 |
if (facet == newfacet) { |
716 |
newfound= True; |
717 |
continue; |
718 |
} |
719 |
zinc_(Zhashtests); |
720 |
if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) { |
721 |
if (SETelem_(newfacet->vertices, newskip) == |
722 |
SETelem_(facet->vertices, skip)) { |
723 |
qh_precision ("two facets with the same vertices"); |
724 |
fprintf (qh ferr, "qhull precision error: Vertex sets are the same for f%d and f%d. Can not force output.\n", |
725 |
facet->id, newfacet->id); |
726 |
qh_errexit2 (qh_ERRprec, facet, newfacet); |
727 |
} |
728 |
ismatch= (same == (newfacet->toporient ^ facet->toporient)); |
729 |
matchfacet= SETelemt_(facet->neighbors, skip, facetT); |
730 |
if (ismatch && !matchfacet) { |
731 |
SETelem_(facet->neighbors, skip)= newfacet; |
732 |
SETelem_(newfacet->neighbors, newskip)= facet; |
733 |
(*hashcount)--; |
734 |
trace4((qh ferr, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n", facet->id, skip, newfacet->id, newskip)); |
735 |
return; |
736 |
} |
737 |
if (!qh PREmerge && !qh MERGEexact) { |
738 |
qh_precision ("a ridge with more than two neighbors"); |
739 |
fprintf (qh ferr, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors. Can not continue.\n", |
740 |
facet->id, newfacet->id, getid_(matchfacet)); |
741 |
qh_errexit2 (qh_ERRprec, facet, newfacet); |
742 |
} |
743 |
SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge; |
744 |
newfacet->dupridge= True; |
745 |
if (!newfacet->normal) |
746 |
qh_setfacetplane (newfacet); |
747 |
qh_addhash (newfacet, qh hash_table, hashsize, hash); |
748 |
(*hashcount)++; |
749 |
if (!facet->normal) |
750 |
qh_setfacetplane (facet); |
751 |
if (matchfacet != qh_DUPLICATEridge) { |
752 |
SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge; |
753 |
facet->dupridge= True; |
754 |
if (!facet->normal) |
755 |
qh_setfacetplane (facet); |
756 |
if (matchfacet) { |
757 |
matchskip= qh_setindex (matchfacet->neighbors, facet); |
758 |
SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; |
759 |
matchfacet->dupridge= True; |
760 |
if (!matchfacet->normal) |
761 |
qh_setfacetplane (matchfacet); |
762 |
qh_addhash (matchfacet, qh hash_table, hashsize, hash); |
763 |
*hashcount += 2; |
764 |
} |
765 |
} |
766 |
trace4((qh ferr, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n", newfacet->id, newskip, facet->id, skip, (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)), ismatch, hash)); |
767 |
return; /* end of duplicate ridge */ |
768 |
} |
769 |
} |
770 |
if (!newfound) |
771 |
SETelem_(qh hash_table, scan)= newfacet; /* same as qh_addhash */ |
772 |
(*hashcount)++; |
773 |
trace4((qh ferr, "qh_matchneighbor: no match for f%d skip %d at hash %d\n", newfacet->id, newskip, hash)); |
774 |
} /* matchneighbor */ |
775 |
|
776 |
|
777 |
/*-<a href="qh-poly.htm#TOC" |
778 |
>-------------------------------</a><a name="matchnewfacets">-</a> |
779 |
|
780 |
qh_matchnewfacets() |
781 |
match newfacets in qh.newfacet_list to their newfacet neighbors |
782 |
|
783 |
returns: |
784 |
qh.newfacet_list with full neighbor sets |
785 |
get vertices with nth neighbor by deleting nth vertex |
786 |
if qh.PREmerge/MERGEexact or qh.FORCEoutput |
787 |
sets facet->flippped if flipped normal (also prevents point partitioning) |
788 |
if duplicate ridges and qh.PREmerge/MERGEexact |
789 |
sets facet->dupridge |
790 |
missing neighbor links identifies extra ridges to be merging (qh_MERGEridge) |
791 |
|
792 |
notes: |
793 |
newfacets already have neighbor[0] (horizon facet) |
794 |
assumes qh.hash_table is NULL |
795 |
vertex->neighbors has not been updated yet |
796 |
do not allocate memory after qh.hash_table (need to free it cleanly) |
797 |
|
798 |
design: |
799 |
delete neighbor sets for all new facets |
800 |
initialize a hash table |
801 |
for all new facets |
802 |
match facet with neighbors |
803 |
if unmatched facets (due to duplicate ridges) |
804 |
for each new facet with a duplicate ridge |
805 |
match it with a facet |
806 |
check for flipped facets |
807 |
*/ |
808 |
void qh_matchnewfacets (void /* qh newfacet_list */) { |
809 |
int numnew=0, hashcount=0, newskip; |
810 |
facetT *newfacet, *neighbor; |
811 |
int dim= qh hull_dim, hashsize, neighbor_i, neighbor_n; |
812 |
setT *neighbors; |
813 |
#ifndef qh_NOtrace |
814 |
int facet_i, facet_n, numfree= 0; |
815 |
facetT *facet; |
816 |
#endif |
817 |
|
818 |
trace1((qh ferr, "qh_matchnewfacets: match neighbors for new facets.\n")); |
819 |
FORALLnew_facets { |
820 |
numnew++; |
821 |
{ /* inline qh_setzero (newfacet->neighbors, 1, qh hull_dim); */ |
822 |
neighbors= newfacet->neighbors; |
823 |
neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/ |
824 |
memset ((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize); |
825 |
} |
826 |
} |
827 |
qh_newhashtable (numnew*(qh hull_dim-1)); /* twice what is normally needed, |
828 |
but every ridge could be DUPLICATEridge */ |
829 |
hashsize= qh_setsize (qh hash_table); |
830 |
FORALLnew_facets { |
831 |
for (newskip=1; newskip<qh hull_dim; newskip++) /* furthest/horizon already matched */ |
832 |
qh_matchneighbor (newfacet, newskip, hashsize, &hashcount); |
833 |
#if 0 |
834 |
/* use the following to trap hashcount errors */ |
835 |
{ |
836 |
int count= 0, k; |
837 |
facetT *facet, *neighbor; |
838 |
|
839 |
count= 0; |
840 |
FORALLfacet_(qh newfacet_list) { /* newfacet already in use */ |
841 |
for (k=1; k < qh hull_dim; k++) { |
842 |
neighbor= SETelemt_(facet->neighbors, k, facetT); |
843 |
if (!neighbor || neighbor == qh_DUPLICATEridge) |
844 |
count++; |
845 |
} |
846 |
if (facet == newfacet) |
847 |
break; |
848 |
} |
849 |
if (count != hashcount) { |
850 |
fprintf (qh ferr, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n", |
851 |
newfacet->id, hashcount, count); |
852 |
qh_errexit (qh_ERRqhull, newfacet, NULL); |
853 |
} |
854 |
} |
855 |
#endif /* end of trap code */ |
856 |
} |
857 |
if (hashcount) { |
858 |
FORALLnew_facets { |
859 |
if (newfacet->dupridge) { |
860 |
FOREACHneighbor_i_(newfacet) { |
861 |
if (neighbor == qh_DUPLICATEridge) { |
862 |
qh_matchduplicates (newfacet, neighbor_i, hashsize, &hashcount); |
863 |
/* this may report MERGEfacet */ |
864 |
} |
865 |
} |
866 |
} |
867 |
} |
868 |
} |
869 |
if (hashcount) { |
870 |
fprintf (qh ferr, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n", |
871 |
hashcount); |
872 |
qh_printhashtable (qh ferr); |
873 |
qh_errexit (qh_ERRqhull, NULL, NULL); |
874 |
} |
875 |
#ifndef qh_NOtrace |
876 |
if (qh IStracing >= 2) { |
877 |
FOREACHfacet_i_(qh hash_table) { |
878 |
if (!facet) |
879 |
numfree++; |
880 |
} |
881 |
fprintf (qh ferr, "qh_matchnewfacets: %d new facets, %d unused hash entries . hashsize %d\n", |
882 |
numnew, numfree, qh_setsize (qh hash_table)); |
883 |
} |
884 |
#endif /* !qh_NOtrace */ |
885 |
qh_setfree (&qh hash_table); |
886 |
if (qh PREmerge || qh MERGEexact) { |
887 |
if (qh IStracing >= 4) |
888 |
qh_printfacetlist (qh newfacet_list, NULL, qh_ALL); |
889 |
FORALLnew_facets { |
890 |
if (newfacet->normal) |
891 |
qh_checkflipped (newfacet, NULL, qh_ALL); |
892 |
} |
893 |
}else if (qh FORCEoutput) |
894 |
qh_checkflipped_all (qh newfacet_list); /* prints warnings for flipped */ |
895 |
} /* matchnewfacets */ |
896 |
|
897 |
|
898 |
/*-<a href="qh-poly.htm#TOC" |
899 |
>-------------------------------</a><a name="matchvertices">-</a> |
900 |
|
901 |
qh_matchvertices( firstindex, verticesA, skipA, verticesB, skipB, same ) |
902 |
tests whether vertices match with a single skip |
903 |
starts match at firstindex since all new facets have a common vertex |
904 |
|
905 |
returns: |
906 |
true if matched vertices |
907 |
skip index for each set |
908 |
sets same iff vertices have the same orientation |
909 |
|
910 |
notes: |
911 |
assumes skipA is in A and both sets are the same size |
912 |
|
913 |
design: |
914 |
set up pointers |
915 |
scan both sets checking for a match |
916 |
test orientation |
917 |
*/ |
918 |
boolT qh_matchvertices (int firstindex, setT *verticesA, int skipA, |
919 |
setT *verticesB, int *skipB, boolT *same) { |
920 |
vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp; |
921 |
|
922 |
elemAp= SETelemaddr_(verticesA, firstindex, vertexT); |
923 |
elemBp= SETelemaddr_(verticesB, firstindex, vertexT); |
924 |
skipAp= SETelemaddr_(verticesA, skipA, vertexT); |
925 |
do if (elemAp != skipAp) { |
926 |
while (*elemAp != *elemBp++) { |
927 |
if (skipBp) |
928 |
return False; |
929 |
skipBp= elemBp; /* one extra like FOREACH */ |
930 |
} |
931 |
}while(*(++elemAp)); |
932 |
if (!skipBp) |
933 |
skipBp= ++elemBp; |
934 |
*skipB= SETindex_(verticesB, skipB); |
935 |
*same= !(((ptr_intT)skipA & 0x1) ^ ((ptr_intT)*skipB & 0x1)); |
936 |
trace4((qh ferr, "qh_matchvertices: matched by skip %d (v%d) and skip %d (v%d) same? %d\n", skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same)); |
937 |
return (True); |
938 |
} /* matchvertices */ |
939 |
|
940 |
/*-<a href="qh-poly.htm#TOC" |
941 |
>-------------------------------</a><a name="newfacet">-</a> |
942 |
|
943 |
qh_newfacet() |
944 |
return a new facet |
945 |
|
946 |
returns: |
947 |
all fields initialized or cleared (NULL) |
948 |
preallocates neighbors set |
949 |
*/ |
950 |
facetT *qh_newfacet(void) { |
951 |
facetT *facet; |
952 |
void **freelistp; /* used !qh_NOmem */ |
953 |
|
954 |
qh_memalloc_(sizeof(facetT), freelistp, facet, facetT); |
955 |
memset ((char *)facet, 0, sizeof(facetT)); |
956 |
if (qh facet_id == qh tracefacet_id) |
957 |
qh tracefacet= facet; |
958 |
facet->id= qh facet_id++; |
959 |
facet->neighbors= qh_setnew(qh hull_dim); |
960 |
#if !qh_COMPUTEfurthest |
961 |
facet->furthestdist= 0.0; |
962 |
#endif |
963 |
#if qh_MAXoutside |
964 |
if (qh FORCEoutput && qh APPROXhull) |
965 |
facet->maxoutside= qh MINoutside; |
966 |
else |
967 |
facet->maxoutside= qh DISTround; |
968 |
#endif |
969 |
facet->simplicial= True; |
970 |
facet->good= True; |
971 |
facet->newfacet= True; |
972 |
trace4((qh ferr, "qh_newfacet: created facet f%d\n", facet->id)); |
973 |
return (facet); |
974 |
} /* newfacet */ |
975 |
|
976 |
|
977 |
/*-<a href="qh-poly.htm#TOC" |
978 |
>-------------------------------</a><a name="newridge">-</a> |
979 |
|
980 |
qh_newridge() |
981 |
return a new ridge |
982 |
*/ |
983 |
ridgeT *qh_newridge(void) { |
984 |
ridgeT *ridge; |
985 |
void **freelistp; /* used !qh_NOmem */ |
986 |
|
987 |
qh_memalloc_(sizeof(ridgeT), freelistp, ridge, ridgeT); |
988 |
memset ((char *)ridge, 0, sizeof(ridgeT)); |
989 |
zinc_(Ztotridges); |
990 |
if (qh ridge_id == 0xFFFFFF) { |
991 |
fprintf(qh ferr, "\ |
992 |
qhull warning: more than %d ridges. ID field overflows and two ridges\n\ |
993 |
may have the same identifier. Otherwise output ok.\n", 0xFFFFFF); |
994 |
} |
995 |
ridge->id= qh ridge_id++; |
996 |
trace4((qh ferr, "qh_newridge: created ridge r%d\n", ridge->id)); |
997 |
return (ridge); |
998 |
} /* newridge */ |
999 |
|
1000 |
|
1001 |
/*-<a href="qh-poly.htm#TOC" |
1002 |
>-------------------------------</a><a name="pointid">-</a> |
1003 |
|
1004 |
qh_pointid( ) |
1005 |
return id for a point, |
1006 |
returns -3 if null, -2 if interior, or -1 if not known |
1007 |
|
1008 |
alternative code: |
1009 |
unsigned long id; |
1010 |
id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size; |
1011 |
|
1012 |
notes: |
1013 |
if point not in point array |
1014 |
the code does a comparison of unrelated pointers. |
1015 |
*/ |
1016 |
int qh_pointid (pointT *point) { |
1017 |
long offset, id; |
1018 |
|
1019 |
if (!point) |
1020 |
id= -3; |
1021 |
else if (point == qh interior_point) |
1022 |
id= -2; |
1023 |
else if (point >= qh first_point |
1024 |
&& point < qh first_point + qh num_points * qh hull_dim) { |
1025 |
offset= point - qh first_point; |
1026 |
id= offset / qh hull_dim; |
1027 |
}else if ((id= qh_setindex (qh other_points, point)) != -1) |
1028 |
id += qh num_points; |
1029 |
else |
1030 |
id= -1; |
1031 |
return (int) id; |
1032 |
} /* pointid */ |
1033 |
|
1034 |
/*-<a href="qh-poly.htm#TOC" |
1035 |
>-------------------------------</a><a name="removefacet">-</a> |
1036 |
|
1037 |
qh_removefacet( facet ) |
1038 |
unlinks facet from qh.facet_list, |
1039 |
|
1040 |
returns: |
1041 |
updates qh.facet_list .newfacet_list .facet_next visible_list |
1042 |
decrements qh.num_facets |
1043 |
|
1044 |
see: |
1045 |
qh_appendfacet |
1046 |
*/ |
1047 |
void qh_removefacet(facetT *facet) { |
1048 |
facetT *next= facet->next, *previous= facet->previous; |
1049 |
|
1050 |
if (facet == qh newfacet_list) |
1051 |
qh newfacet_list= next; |
1052 |
if (facet == qh facet_next) |
1053 |
qh facet_next= next; |
1054 |
if (facet == qh visible_list) |
1055 |
qh visible_list= next; |
1056 |
if (previous) { |
1057 |
previous->next= next; |
1058 |
next->previous= previous; |
1059 |
}else { /* 1st facet in qh facet_list */ |
1060 |
qh facet_list= next; |
1061 |
qh facet_list->previous= NULL; |
1062 |
} |
1063 |
qh num_facets--; |
1064 |
trace4((qh ferr, "qh_removefacet: remove f%d from facet_list\n", facet->id)); |
1065 |
} /* removefacet */ |
1066 |
|
1067 |
|
1068 |
/*-<a href="qh-poly.htm#TOC" |
1069 |
>-------------------------------</a><a name="removevertex">-</a> |
1070 |
|
1071 |
qh_removevertex( vertex ) |
1072 |
unlinks vertex from qh.vertex_list, |
1073 |
|
1074 |
returns: |
1075 |
updates qh.vertex_list .newvertex_list |
1076 |
decrements qh.num_vertices |
1077 |
*/ |
1078 |
void qh_removevertex(vertexT *vertex) { |
1079 |
vertexT *next= vertex->next, *previous= vertex->previous; |
1080 |
|
1081 |
if (vertex == qh newvertex_list) |
1082 |
qh newvertex_list= next; |
1083 |
if (previous) { |
1084 |
previous->next= next; |
1085 |
next->previous= previous; |
1086 |
}else { /* 1st vertex in qh vertex_list */ |
1087 |
qh vertex_list= vertex->next; |
1088 |
qh vertex_list->previous= NULL; |
1089 |
} |
1090 |
qh num_vertices--; |
1091 |
trace4((qh ferr, "qh_removevertex: remove v%d from vertex_list\n", vertex->id)); |
1092 |
} /* removevertex */ |
1093 |
|
1094 |
|
1095 |
/*-<a href="qh-poly.htm#TOC" |
1096 |
>-------------------------------</a><a name="updatevertices">-</a> |
1097 |
|
1098 |
qh_updatevertices() |
1099 |
update vertex neighbors and delete interior vertices |
1100 |
|
1101 |
returns: |
1102 |
if qh.VERTEXneighbors, updates neighbors for each vertex |
1103 |
if qh.newvertex_list, |
1104 |
removes visible neighbors from vertex neighbors |
1105 |
if qh.newfacet_list |
1106 |
adds new facets to vertex neighbors |
1107 |
if qh.visible_list |
1108 |
interior vertices added to qh.del_vertices for later partitioning |
1109 |
|
1110 |
design: |
1111 |
if qh.VERTEXneighbors |
1112 |
deletes references to visible facets from vertex neighbors |
1113 |
appends new facets to the neighbor list for each vertex |
1114 |
checks all vertices of visible facets |
1115 |
removes visible facets from neighbor lists |
1116 |
marks unused vertices for deletion |
1117 |
*/ |
1118 |
void qh_updatevertices (void /*qh newvertex_list, newfacet_list, visible_list*/) { |
1119 |
facetT *newfacet= NULL, *neighbor, **neighborp, *visible; |
1120 |
vertexT *vertex, **vertexp; |
1121 |
|
1122 |
trace3((qh ferr, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n")); |
1123 |
if (qh VERTEXneighbors) { |
1124 |
FORALLvertex_(qh newvertex_list) { |
1125 |
FOREACHneighbor_(vertex) { |
1126 |
if (neighbor->visible) |
1127 |
SETref_(neighbor)= NULL; |
1128 |
} |
1129 |
qh_setcompact (vertex->neighbors); |
1130 |
} |
1131 |
FORALLnew_facets { |
1132 |
FOREACHvertex_(newfacet->vertices) |
1133 |
qh_setappend (&vertex->neighbors, newfacet); |
1134 |
} |
1135 |
FORALLvisible_facets { |
1136 |
FOREACHvertex_(visible->vertices) { |
1137 |
if (!vertex->newlist && !vertex->deleted) { |
1138 |
FOREACHneighbor_(vertex) { /* this can happen under merging */ |
1139 |
if (!neighbor->visible) |
1140 |
break; |
1141 |
} |
1142 |
if (neighbor) |
1143 |
qh_setdel (vertex->neighbors, visible); |
1144 |
else { |
1145 |
vertex->deleted= True; |
1146 |
qh_setappend (&qh del_vertices, vertex); |
1147 |
trace2((qh ferr, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n", qh_pointid(vertex->point), vertex->id, visible->id)); |
1148 |
} |
1149 |
} |
1150 |
} |
1151 |
} |
1152 |
}else { /* !VERTEXneighbors */ |
1153 |
FORALLvisible_facets { |
1154 |
FOREACHvertex_(visible->vertices) { |
1155 |
if (!vertex->newlist && !vertex->deleted) { |
1156 |
vertex->deleted= True; |
1157 |
qh_setappend (&qh del_vertices, vertex); |
1158 |
trace2((qh ferr, "qh_updatevertices: delete vertex p%d (v%d) in f%d\n", qh_pointid(vertex->point), vertex->id, visible->id)); |
1159 |
} |
1160 |
} |
1161 |
} |
1162 |
} |
1163 |
} /* updatevertices */ |
1164 |
|
1165 |
|
1166 |
|