| 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 |
|