[10207] | 1 | /*<html><pre> -<a href="qh-set.htm"
|
---|
| 2 | >-------------------------------</a><a name="TOP">-</a>
|
---|
| 3 |
|
---|
| 4 | qset.c
|
---|
| 5 | implements set manipulations needed for quickhull
|
---|
| 6 |
|
---|
| 7 | see qh-set.htm and qset.h
|
---|
| 8 |
|
---|
| 9 | Be careful of strict aliasing (two pointers of different types
|
---|
| 10 | that reference the same location). The last slot of a set is
|
---|
| 11 | either the actual size of the set plus 1, or the NULL terminator
|
---|
| 12 | of the set (i.e., setelemT).
|
---|
| 13 |
|
---|
| 14 | Copyright (c) 1993-2012 The Geometry Center.
|
---|
| 15 | $Id: //main/2011/qhull/src/libqhull/qset.c#6 $$Change: 1475 $
|
---|
| 16 | $DateTime: 2012/01/27 22:32:16 $$Author: bbarber $
|
---|
| 17 | */
|
---|
| 18 |
|
---|
| 19 | #include "qset.h"
|
---|
| 20 | #include "mem.h"
|
---|
| 21 | #include <stdio.h>
|
---|
| 22 | #include <string.h>
|
---|
| 23 | /*** uncomment here and qhull_a.h
|
---|
| 24 | if string.h does not define memcpy()
|
---|
| 25 | #include <memory.h>
|
---|
| 26 | */
|
---|
| 27 |
|
---|
| 28 | #ifndef qhDEFlibqhull
|
---|
| 29 | typedef struct ridgeT ridgeT;
|
---|
| 30 | typedef struct facetT facetT;
|
---|
| 31 | void qh_errexit(int exitcode, facetT *, ridgeT *);
|
---|
| 32 | void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
|
---|
| 33 | # ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */
|
---|
| 34 | # pragma warning( disable : 4127) /* conditional expression is constant */
|
---|
| 35 | # pragma warning( disable : 4706) /* assignment within conditional function */
|
---|
| 36 | # endif
|
---|
| 37 | #endif
|
---|
| 38 |
|
---|
| 39 | /*=============== internal macros ===========================*/
|
---|
| 40 |
|
---|
| 41 | /*============ functions in alphabetical order ===================*/
|
---|
| 42 |
|
---|
| 43 | /*-<a href="qh-set.htm#TOC"
|
---|
| 44 | >--------------------------------<a name="setaddnth">-</a>
|
---|
| 45 |
|
---|
| 46 | qh_setaddnth( setp, nth, newelem)
|
---|
| 47 | adds newelem as n'th element of sorted or unsorted *setp
|
---|
| 48 |
|
---|
| 49 | notes:
|
---|
| 50 | *setp and newelem must be defined
|
---|
| 51 | *setp may be a temp set
|
---|
| 52 | nth=0 is first element
|
---|
| 53 | errors if nth is out of bounds
|
---|
| 54 |
|
---|
| 55 | design:
|
---|
| 56 | expand *setp if empty or full
|
---|
| 57 | move tail of *setp up one
|
---|
| 58 | insert newelem
|
---|
| 59 | */
|
---|
| 60 | void qh_setaddnth(setT **setp, int nth, void *newelem) {
|
---|
| 61 | int oldsize, i;
|
---|
| 62 | setelemT *sizep; /* avoid strict aliasing */
|
---|
| 63 | setelemT *oldp, *newp;
|
---|
| 64 |
|
---|
| 65 | if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
|
---|
| 66 | qh_setlarger(setp);
|
---|
| 67 | sizep= SETsizeaddr_(*setp);
|
---|
| 68 | }
|
---|
| 69 | oldsize= sizep->i - 1;
|
---|
| 70 | if (nth < 0 || nth > oldsize) {
|
---|
| 71 | qh_fprintf(qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
|
---|
| 72 | qh_setprint(qhmem.ferr, "", *setp);
|
---|
| 73 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 74 | }
|
---|
| 75 | sizep->i++;
|
---|
| 76 | oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void); /* NULL */
|
---|
| 77 | newp= oldp+1;
|
---|
| 78 | for (i=oldsize-nth+1; i--; ) /* move at least NULL */
|
---|
| 79 | (newp--)->p= (oldp--)->p; /* may overwrite *sizep */
|
---|
| 80 | newp->p= newelem;
|
---|
| 81 | } /* setaddnth */
|
---|
| 82 |
|
---|
| 83 |
|
---|
| 84 | /*-<a href="qh-set.htm#TOC"
|
---|
| 85 | >--------------------------------<a name="setaddsorted">-</a>
|
---|
| 86 |
|
---|
| 87 | setaddsorted( setp, newelem )
|
---|
| 88 | adds an newelem into sorted *setp
|
---|
| 89 |
|
---|
| 90 | notes:
|
---|
| 91 | *setp and newelem must be defined
|
---|
| 92 | *setp may be a temp set
|
---|
| 93 | nop if newelem already in set
|
---|
| 94 |
|
---|
| 95 | design:
|
---|
| 96 | find newelem's position in *setp
|
---|
| 97 | insert newelem
|
---|
| 98 | */
|
---|
| 99 | void qh_setaddsorted(setT **setp, void *newelem) {
|
---|
| 100 | int newindex=0;
|
---|
| 101 | void *elem, **elemp;
|
---|
| 102 |
|
---|
| 103 | FOREACHelem_(*setp) { /* could use binary search instead */
|
---|
| 104 | if (elem < newelem)
|
---|
| 105 | newindex++;
|
---|
| 106 | else if (elem == newelem)
|
---|
| 107 | return;
|
---|
| 108 | else
|
---|
| 109 | break;
|
---|
| 110 | }
|
---|
| 111 | qh_setaddnth(setp, newindex, newelem);
|
---|
| 112 | } /* setaddsorted */
|
---|
| 113 |
|
---|
| 114 |
|
---|
| 115 | /*-<a href="qh-set.htm#TOC"
|
---|
| 116 | >-------------------------------<a name="setappend">-</a>
|
---|
| 117 |
|
---|
| 118 | qh_setappend( setp, newelem)
|
---|
| 119 | append newelem to *setp
|
---|
| 120 |
|
---|
| 121 | notes:
|
---|
| 122 | *setp may be a temp set
|
---|
| 123 | *setp and newelem may be NULL
|
---|
| 124 |
|
---|
| 125 | design:
|
---|
| 126 | expand *setp if empty or full
|
---|
| 127 | append newelem to *setp
|
---|
| 128 |
|
---|
| 129 | */
|
---|
| 130 | void qh_setappend(setT **setp, void *newelem) {
|
---|
| 131 | setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */
|
---|
| 132 | setelemT *endp;
|
---|
| 133 | int count;
|
---|
| 134 |
|
---|
| 135 | if (!newelem)
|
---|
| 136 | return;
|
---|
| 137 | if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
|
---|
| 138 | qh_setlarger(setp);
|
---|
| 139 | sizep= SETsizeaddr_(*setp);
|
---|
| 140 | }
|
---|
| 141 | count= (sizep->i)++ - 1;
|
---|
| 142 | endp= (setelemT *)SETelemaddr_(*setp, count, void);
|
---|
| 143 | (endp++)->p= newelem;
|
---|
| 144 | endp->p= NULL;
|
---|
| 145 | } /* setappend */
|
---|
| 146 |
|
---|
| 147 | /*-<a href="qh-set.htm#TOC"
|
---|
| 148 | >-------------------------------<a name="setappend_set">-</a>
|
---|
| 149 |
|
---|
| 150 | qh_setappend_set( setp, setA)
|
---|
| 151 | appends setA to *setp
|
---|
| 152 |
|
---|
| 153 | notes:
|
---|
| 154 | *setp can not be a temp set
|
---|
| 155 | *setp and setA may be NULL
|
---|
| 156 |
|
---|
| 157 | design:
|
---|
| 158 | setup for copy
|
---|
| 159 | expand *setp if it is too small
|
---|
| 160 | append all elements of setA to *setp
|
---|
| 161 | */
|
---|
| 162 | void qh_setappend_set(setT **setp, setT *setA) {
|
---|
| 163 | int sizeA, size;
|
---|
| 164 | setT *oldset;
|
---|
| 165 | setelemT *sizep;
|
---|
| 166 |
|
---|
| 167 | if (!setA)
|
---|
| 168 | return;
|
---|
| 169 | SETreturnsize_(setA, sizeA);
|
---|
| 170 | if (!*setp)
|
---|
| 171 | *setp= qh_setnew(sizeA);
|
---|
| 172 | sizep= SETsizeaddr_(*setp);
|
---|
| 173 | if (!(size= sizep->i))
|
---|
| 174 | size= (*setp)->maxsize;
|
---|
| 175 | else
|
---|
| 176 | size--;
|
---|
| 177 | if (size + sizeA > (*setp)->maxsize) {
|
---|
| 178 | oldset= *setp;
|
---|
| 179 | *setp= qh_setcopy(oldset, sizeA);
|
---|
| 180 | qh_setfree(&oldset);
|
---|
| 181 | sizep= SETsizeaddr_(*setp);
|
---|
| 182 | }
|
---|
| 183 | if (sizeA > 0) {
|
---|
| 184 | sizep->i= size+sizeA+1; /* memcpy may overwrite */
|
---|
| 185 | memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
|
---|
| 186 | }
|
---|
| 187 | } /* setappend_set */
|
---|
| 188 |
|
---|
| 189 |
|
---|
| 190 | /*-<a href="qh-set.htm#TOC"
|
---|
| 191 | >-------------------------------<a name="setappend2ndlast">-</a>
|
---|
| 192 |
|
---|
| 193 | qh_setappend2ndlast( setp, newelem )
|
---|
| 194 | makes newelem the next to the last element in *setp
|
---|
| 195 |
|
---|
| 196 | notes:
|
---|
| 197 | *setp must have at least one element
|
---|
| 198 | newelem must be defined
|
---|
| 199 | *setp may be a temp set
|
---|
| 200 |
|
---|
| 201 | design:
|
---|
| 202 | expand *setp if empty or full
|
---|
| 203 | move last element of *setp up one
|
---|
| 204 | insert newelem
|
---|
| 205 | */
|
---|
| 206 | void qh_setappend2ndlast(setT **setp, void *newelem) {
|
---|
| 207 | setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */
|
---|
| 208 | setelemT *endp, *lastp;
|
---|
| 209 | int count;
|
---|
| 210 |
|
---|
| 211 | if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
|
---|
| 212 | qh_setlarger(setp);
|
---|
| 213 | sizep= SETsizeaddr_(*setp);
|
---|
| 214 | }
|
---|
| 215 | count= (sizep->i)++ - 1;
|
---|
| 216 | endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
|
---|
| 217 | lastp= endp-1;
|
---|
| 218 | *(endp++)= *lastp;
|
---|
| 219 | endp->p= NULL; /* may overwrite *sizep */
|
---|
| 220 | lastp->p= newelem;
|
---|
| 221 | } /* setappend2ndlast */
|
---|
| 222 |
|
---|
| 223 | /*-<a href="qh-set.htm#TOC"
|
---|
| 224 | >-------------------------------<a name="setcheck">-</a>
|
---|
| 225 |
|
---|
| 226 | qh_setcheck( set, typename, id )
|
---|
| 227 | check set for validity
|
---|
| 228 | report errors with typename and id
|
---|
| 229 |
|
---|
| 230 | design:
|
---|
| 231 | checks that maxsize, actual size, and NULL terminator agree
|
---|
| 232 | */
|
---|
| 233 | void qh_setcheck(setT *set, const char *tname, unsigned id) {
|
---|
| 234 | int maxsize, size;
|
---|
| 235 | int waserr= 0;
|
---|
| 236 |
|
---|
| 237 | if (!set)
|
---|
| 238 | return;
|
---|
| 239 | SETreturnsize_(set, size);
|
---|
| 240 | maxsize= set->maxsize;
|
---|
| 241 | if (size > maxsize || !maxsize) {
|
---|
| 242 | qh_fprintf(qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
|
---|
| 243 | size, tname, id, maxsize);
|
---|
| 244 | waserr= 1;
|
---|
| 245 | }else if (set->e[size].p) {
|
---|
| 246 | qh_fprintf(qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
|
---|
| 247 | tname, id, size-1, maxsize);
|
---|
| 248 | waserr= 1;
|
---|
| 249 | }
|
---|
| 250 | if (waserr) {
|
---|
| 251 | qh_setprint(qhmem.ferr, "ERRONEOUS", set);
|
---|
| 252 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 253 | }
|
---|
| 254 | } /* setcheck */
|
---|
| 255 |
|
---|
| 256 |
|
---|
| 257 | /*-<a href="qh-set.htm#TOC"
|
---|
| 258 | >-------------------------------<a name="setcompact">-</a>
|
---|
| 259 |
|
---|
| 260 | qh_setcompact( set )
|
---|
| 261 | remove internal NULLs from an unsorted set
|
---|
| 262 |
|
---|
| 263 | returns:
|
---|
| 264 | updated set
|
---|
| 265 |
|
---|
| 266 | notes:
|
---|
| 267 | set may be NULL
|
---|
| 268 | it would be faster to swap tail of set into holes, like qh_setdel
|
---|
| 269 |
|
---|
| 270 | design:
|
---|
| 271 | setup pointers into set
|
---|
| 272 | skip NULLs while copying elements to start of set
|
---|
| 273 | update the actual size
|
---|
| 274 | */
|
---|
| 275 | void qh_setcompact(setT *set) {
|
---|
| 276 | int size;
|
---|
| 277 | void **destp, **elemp, **endp, **firstp;
|
---|
| 278 |
|
---|
| 279 | if (!set)
|
---|
| 280 | return;
|
---|
| 281 | SETreturnsize_(set, size);
|
---|
| 282 | destp= elemp= firstp= SETaddr_(set, void);
|
---|
| 283 | endp= destp + size;
|
---|
| 284 | while (1) {
|
---|
| 285 | if (!(*destp++ = *elemp++)) {
|
---|
| 286 | destp--;
|
---|
| 287 | if (elemp > endp)
|
---|
| 288 | break;
|
---|
| 289 | }
|
---|
| 290 | }
|
---|
| 291 | qh_settruncate(set, (int)(destp-firstp)); /* WARN64 */
|
---|
| 292 | } /* setcompact */
|
---|
| 293 |
|
---|
| 294 |
|
---|
| 295 | /*-<a href="qh-set.htm#TOC"
|
---|
| 296 | >-------------------------------<a name="setcopy">-</a>
|
---|
| 297 |
|
---|
| 298 | qh_setcopy( set, extra )
|
---|
| 299 | make a copy of a sorted or unsorted set with extra slots
|
---|
| 300 |
|
---|
| 301 | returns:
|
---|
| 302 | new set
|
---|
| 303 |
|
---|
| 304 | design:
|
---|
| 305 | create a newset with extra slots
|
---|
| 306 | copy the elements to the newset
|
---|
| 307 |
|
---|
| 308 | */
|
---|
| 309 | setT *qh_setcopy(setT *set, int extra) {
|
---|
| 310 | setT *newset;
|
---|
| 311 | int size;
|
---|
| 312 |
|
---|
| 313 | if (extra < 0)
|
---|
| 314 | extra= 0;
|
---|
| 315 | SETreturnsize_(set, size);
|
---|
| 316 | newset= qh_setnew(size+extra);
|
---|
| 317 | SETsizeaddr_(newset)->i= size+1; /* memcpy may overwrite */
|
---|
| 318 | memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
|
---|
| 319 | return(newset);
|
---|
| 320 | } /* setcopy */
|
---|
| 321 |
|
---|
| 322 |
|
---|
| 323 | /*-<a href="qh-set.htm#TOC"
|
---|
| 324 | >-------------------------------<a name="setdel">-</a>
|
---|
| 325 |
|
---|
| 326 | qh_setdel( set, oldelem )
|
---|
| 327 | delete oldelem from an unsorted set
|
---|
| 328 |
|
---|
| 329 | returns:
|
---|
| 330 | returns oldelem if found
|
---|
| 331 | returns NULL otherwise
|
---|
| 332 |
|
---|
| 333 | notes:
|
---|
| 334 | set may be NULL
|
---|
| 335 | oldelem must not be NULL;
|
---|
| 336 | only deletes one copy of oldelem in set
|
---|
| 337 |
|
---|
| 338 | design:
|
---|
| 339 | locate oldelem
|
---|
| 340 | update actual size if it was full
|
---|
| 341 | move the last element to the oldelem's location
|
---|
| 342 | */
|
---|
| 343 | void *qh_setdel(setT *set, void *oldelem) {
|
---|
| 344 | setelemT *sizep;
|
---|
| 345 | setelemT *elemp;
|
---|
| 346 | setelemT *lastp;
|
---|
| 347 |
|
---|
| 348 | if (!set)
|
---|
| 349 | return NULL;
|
---|
| 350 | elemp= (setelemT *)SETaddr_(set, void);
|
---|
| 351 | while (elemp->p != oldelem && elemp->p)
|
---|
| 352 | elemp++;
|
---|
| 353 | if (elemp->p) {
|
---|
| 354 | sizep= SETsizeaddr_(set);
|
---|
| 355 | if (!(sizep->i)--) /* if was a full set */
|
---|
| 356 | sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
|
---|
| 357 | lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
|
---|
| 358 | elemp->p= lastp->p; /* may overwrite itself */
|
---|
| 359 | lastp->p= NULL;
|
---|
| 360 | return oldelem;
|
---|
| 361 | }
|
---|
| 362 | return NULL;
|
---|
| 363 | } /* setdel */
|
---|
| 364 |
|
---|
| 365 |
|
---|
| 366 | /*-<a href="qh-set.htm#TOC"
|
---|
| 367 | >-------------------------------<a name="setdellast">-</a>
|
---|
| 368 |
|
---|
| 369 | qh_setdellast( set)
|
---|
| 370 | return last element of set or NULL
|
---|
| 371 |
|
---|
| 372 | notes:
|
---|
| 373 | deletes element from set
|
---|
| 374 | set may be NULL
|
---|
| 375 |
|
---|
| 376 | design:
|
---|
| 377 | return NULL if empty
|
---|
| 378 | if full set
|
---|
| 379 | delete last element and set actual size
|
---|
| 380 | else
|
---|
| 381 | delete last element and update actual size
|
---|
| 382 | */
|
---|
| 383 | void *qh_setdellast(setT *set) {
|
---|
| 384 | int setsize; /* actually, actual_size + 1 */
|
---|
| 385 | int maxsize;
|
---|
| 386 | setelemT *sizep;
|
---|
| 387 | void *returnvalue;
|
---|
| 388 |
|
---|
| 389 | if (!set || !(set->e[0].p))
|
---|
| 390 | return NULL;
|
---|
| 391 | sizep= SETsizeaddr_(set);
|
---|
| 392 | if ((setsize= sizep->i)) {
|
---|
| 393 | returnvalue= set->e[setsize - 2].p;
|
---|
| 394 | set->e[setsize - 2].p= NULL;
|
---|
| 395 | sizep->i--;
|
---|
| 396 | }else {
|
---|
| 397 | maxsize= set->maxsize;
|
---|
| 398 | returnvalue= set->e[maxsize - 1].p;
|
---|
| 399 | set->e[maxsize - 1].p= NULL;
|
---|
| 400 | sizep->i= maxsize;
|
---|
| 401 | }
|
---|
| 402 | return returnvalue;
|
---|
| 403 | } /* setdellast */
|
---|
| 404 |
|
---|
| 405 |
|
---|
| 406 | /*-<a href="qh-set.htm#TOC"
|
---|
| 407 | >-------------------------------<a name="setdelnth">-</a>
|
---|
| 408 |
|
---|
| 409 | qh_setdelnth( set, nth )
|
---|
| 410 | deletes nth element from unsorted set
|
---|
| 411 | 0 is first element
|
---|
| 412 |
|
---|
| 413 | returns:
|
---|
| 414 | returns the element (needs type conversion)
|
---|
| 415 |
|
---|
| 416 | notes:
|
---|
| 417 | errors if nth invalid
|
---|
| 418 |
|
---|
| 419 | design:
|
---|
| 420 | setup points and check nth
|
---|
| 421 | delete nth element and overwrite with last element
|
---|
| 422 | */
|
---|
| 423 | void *qh_setdelnth(setT *set, int nth) {
|
---|
| 424 | void *elem;
|
---|
| 425 | setelemT *sizep;
|
---|
| 426 | setelemT *elemp, *lastp;
|
---|
| 427 |
|
---|
| 428 | elemp= (setelemT *)SETelemaddr_(set, nth, void);
|
---|
| 429 | sizep= SETsizeaddr_(set);
|
---|
| 430 | if ((sizep->i--)==0) /* if was a full set */
|
---|
| 431 | sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
|
---|
| 432 | if (nth < 0 || nth >= sizep->i) {
|
---|
| 433 | qh_fprintf(qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
|
---|
| 434 | qh_setprint(qhmem.ferr, "", set);
|
---|
| 435 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 436 | }
|
---|
| 437 | lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
|
---|
| 438 | elem= elemp->p;
|
---|
| 439 | elemp->p= lastp->p; /* may overwrite itself */
|
---|
| 440 | lastp->p= NULL;
|
---|
| 441 | return elem;
|
---|
| 442 | } /* setdelnth */
|
---|
| 443 |
|
---|
| 444 | /*-<a href="qh-set.htm#TOC"
|
---|
| 445 | >-------------------------------<a name="setdelnthsorted">-</a>
|
---|
| 446 |
|
---|
| 447 | qh_setdelnthsorted( set, nth )
|
---|
| 448 | deletes nth element from sorted set
|
---|
| 449 |
|
---|
| 450 | returns:
|
---|
| 451 | returns the element (use type conversion)
|
---|
| 452 |
|
---|
| 453 | notes:
|
---|
| 454 | errors if nth invalid
|
---|
| 455 |
|
---|
| 456 | see also:
|
---|
| 457 | setnew_delnthsorted
|
---|
| 458 |
|
---|
| 459 | design:
|
---|
| 460 | setup points and check nth
|
---|
| 461 | copy remaining elements down one
|
---|
| 462 | update actual size
|
---|
| 463 | */
|
---|
| 464 | void *qh_setdelnthsorted(setT *set, int nth) {
|
---|
| 465 | void *elem;
|
---|
| 466 | setelemT *sizep;
|
---|
| 467 | setelemT *newp, *oldp;
|
---|
| 468 |
|
---|
| 469 | sizep= SETsizeaddr_(set);
|
---|
| 470 | if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
|
---|
| 471 | qh_fprintf(qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
|
---|
| 472 | qh_setprint(qhmem.ferr, "", set);
|
---|
| 473 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 474 | }
|
---|
| 475 | newp= (setelemT *)SETelemaddr_(set, nth, void);
|
---|
| 476 | elem= newp->p;
|
---|
| 477 | oldp= newp+1;
|
---|
| 478 | while (((newp++)->p= (oldp++)->p))
|
---|
| 479 | ; /* copy remaining elements and NULL */
|
---|
| 480 | if ((sizep->i--)==0) /* if was a full set */
|
---|
| 481 | sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */
|
---|
| 482 | return elem;
|
---|
| 483 | } /* setdelnthsorted */
|
---|
| 484 |
|
---|
| 485 |
|
---|
| 486 | /*-<a href="qh-set.htm#TOC"
|
---|
| 487 | >-------------------------------<a name="setdelsorted">-</a>
|
---|
| 488 |
|
---|
| 489 | qh_setdelsorted( set, oldelem )
|
---|
| 490 | deletes oldelem from sorted set
|
---|
| 491 |
|
---|
| 492 | returns:
|
---|
| 493 | returns oldelem if it was deleted
|
---|
| 494 |
|
---|
| 495 | notes:
|
---|
| 496 | set may be NULL
|
---|
| 497 |
|
---|
| 498 | design:
|
---|
| 499 | locate oldelem in set
|
---|
| 500 | copy remaining elements down one
|
---|
| 501 | update actual size
|
---|
| 502 | */
|
---|
| 503 | void *qh_setdelsorted(setT *set, void *oldelem) {
|
---|
| 504 | setelemT *sizep;
|
---|
| 505 | setelemT *newp, *oldp;
|
---|
| 506 |
|
---|
| 507 | if (!set)
|
---|
| 508 | return NULL;
|
---|
| 509 | newp= (setelemT *)SETaddr_(set, void);
|
---|
| 510 | while(newp->p != oldelem && newp->p)
|
---|
| 511 | newp++;
|
---|
| 512 | if (newp->p) {
|
---|
| 513 | oldp= newp+1;
|
---|
| 514 | while (((newp++)->p= (oldp++)->p))
|
---|
| 515 | ; /* copy remaining elements */
|
---|
| 516 | sizep= SETsizeaddr_(set);
|
---|
| 517 | if ((sizep->i--)==0) /* if was a full set */
|
---|
| 518 | sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */
|
---|
| 519 | return oldelem;
|
---|
| 520 | }
|
---|
| 521 | return NULL;
|
---|
| 522 | } /* setdelsorted */
|
---|
| 523 |
|
---|
| 524 |
|
---|
| 525 | /*-<a href="qh-set.htm#TOC"
|
---|
| 526 | >-------------------------------<a name="setduplicate">-</a>
|
---|
| 527 |
|
---|
| 528 | qh_setduplicate( set, elemsize )
|
---|
| 529 | duplicate a set of elemsize elements
|
---|
| 530 |
|
---|
| 531 | notes:
|
---|
| 532 | use setcopy if retaining old elements
|
---|
| 533 |
|
---|
| 534 | design:
|
---|
| 535 | create a new set
|
---|
| 536 | for each elem of the old set
|
---|
| 537 | create a newelem
|
---|
| 538 | append newelem to newset
|
---|
| 539 | */
|
---|
| 540 | setT *qh_setduplicate(setT *set, int elemsize) {
|
---|
| 541 | void *elem, **elemp, *newElem;
|
---|
| 542 | setT *newSet;
|
---|
| 543 | int size;
|
---|
| 544 |
|
---|
| 545 | if (!(size= qh_setsize(set)))
|
---|
| 546 | return NULL;
|
---|
| 547 | newSet= qh_setnew(size);
|
---|
| 548 | FOREACHelem_(set) {
|
---|
| 549 | newElem= qh_memalloc(elemsize);
|
---|
| 550 | memcpy(newElem, elem, (size_t)elemsize);
|
---|
| 551 | qh_setappend(&newSet, newElem);
|
---|
| 552 | }
|
---|
| 553 | return newSet;
|
---|
| 554 | } /* setduplicate */
|
---|
| 555 |
|
---|
| 556 |
|
---|
| 557 | /*-<a href="qh-set.htm#TOC"
|
---|
| 558 | >-------------------------------<a name="setendpointer">-</a>
|
---|
| 559 |
|
---|
| 560 | qh_setendpointer( set )
|
---|
| 561 | Returns pointer to NULL terminator of a set's elements
|
---|
| 562 | set can not be NULL
|
---|
| 563 |
|
---|
| 564 | */
|
---|
| 565 | void **qh_setendpointer(setT *set) {
|
---|
| 566 |
|
---|
| 567 | setelemT *sizep= SETsizeaddr_(set);
|
---|
| 568 | int n= sizep->i;
|
---|
| 569 | return (n ? &set->e[n-1].p : &sizep->p);
|
---|
| 570 | } /* qh_setendpointer */
|
---|
| 571 |
|
---|
| 572 | /*-<a href="qh-set.htm#TOC"
|
---|
| 573 | >-------------------------------<a name="setequal">-</a>
|
---|
| 574 |
|
---|
| 575 | qh_setequal( )
|
---|
| 576 | returns 1 if two sorted sets are equal, otherwise returns 0
|
---|
| 577 |
|
---|
| 578 | notes:
|
---|
| 579 | either set may be NULL
|
---|
| 580 |
|
---|
| 581 | design:
|
---|
| 582 | check size of each set
|
---|
| 583 | setup pointers
|
---|
| 584 | compare elements of each set
|
---|
| 585 | */
|
---|
| 586 | int qh_setequal(setT *setA, setT *setB) {
|
---|
| 587 | void **elemAp, **elemBp;
|
---|
| 588 | int sizeA= 0, sizeB= 0;
|
---|
| 589 |
|
---|
| 590 | if (setA) {
|
---|
| 591 | SETreturnsize_(setA, sizeA);
|
---|
| 592 | }
|
---|
| 593 | if (setB) {
|
---|
| 594 | SETreturnsize_(setB, sizeB);
|
---|
| 595 | }
|
---|
| 596 | if (sizeA != sizeB)
|
---|
| 597 | return 0;
|
---|
| 598 | if (!sizeA)
|
---|
| 599 | return 1;
|
---|
| 600 | elemAp= SETaddr_(setA, void);
|
---|
| 601 | elemBp= SETaddr_(setB, void);
|
---|
| 602 | if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
|
---|
| 603 | return 1;
|
---|
| 604 | return 0;
|
---|
| 605 | } /* setequal */
|
---|
| 606 |
|
---|
| 607 |
|
---|
| 608 | /*-<a href="qh-set.htm#TOC"
|
---|
| 609 | >-------------------------------<a name="setequal_except">-</a>
|
---|
| 610 |
|
---|
| 611 | qh_setequal_except( setA, skipelemA, setB, skipelemB )
|
---|
| 612 | returns 1 if sorted setA and setB are equal except for skipelemA & B
|
---|
| 613 |
|
---|
| 614 | returns:
|
---|
| 615 | false if either skipelemA or skipelemB are missing
|
---|
| 616 |
|
---|
| 617 | notes:
|
---|
| 618 | neither set may be NULL
|
---|
| 619 |
|
---|
| 620 | if skipelemB is NULL,
|
---|
| 621 | can skip any one element of setB
|
---|
| 622 |
|
---|
| 623 | design:
|
---|
| 624 | setup pointers
|
---|
| 625 | search for skipelemA, skipelemB, and mismatches
|
---|
| 626 | check results
|
---|
| 627 | */
|
---|
| 628 | int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
|
---|
| 629 | void **elemA, **elemB;
|
---|
| 630 | int skip=0;
|
---|
| 631 |
|
---|
| 632 | elemA= SETaddr_(setA, void);
|
---|
| 633 | elemB= SETaddr_(setB, void);
|
---|
| 634 | while (1) {
|
---|
| 635 | if (*elemA == skipelemA) {
|
---|
| 636 | skip++;
|
---|
| 637 | elemA++;
|
---|
| 638 | }
|
---|
| 639 | if (skipelemB) {
|
---|
| 640 | if (*elemB == skipelemB) {
|
---|
| 641 | skip++;
|
---|
| 642 | elemB++;
|
---|
| 643 | }
|
---|
| 644 | }else if (*elemA != *elemB) {
|
---|
| 645 | skip++;
|
---|
| 646 | if (!(skipelemB= *elemB++))
|
---|
| 647 | return 0;
|
---|
| 648 | }
|
---|
| 649 | if (!*elemA)
|
---|
| 650 | break;
|
---|
| 651 | if (*elemA++ != *elemB++)
|
---|
| 652 | return 0;
|
---|
| 653 | }
|
---|
| 654 | if (skip != 2 || *elemB)
|
---|
| 655 | return 0;
|
---|
| 656 | return 1;
|
---|
| 657 | } /* setequal_except */
|
---|
| 658 |
|
---|
| 659 |
|
---|
| 660 | /*-<a href="qh-set.htm#TOC"
|
---|
| 661 | >-------------------------------<a name="setequal_skip">-</a>
|
---|
| 662 |
|
---|
| 663 | qh_setequal_skip( setA, skipA, setB, skipB )
|
---|
| 664 | returns 1 if sorted setA and setB are equal except for elements skipA & B
|
---|
| 665 |
|
---|
| 666 | returns:
|
---|
| 667 | false if different size
|
---|
| 668 |
|
---|
| 669 | notes:
|
---|
| 670 | neither set may be NULL
|
---|
| 671 |
|
---|
| 672 | design:
|
---|
| 673 | setup pointers
|
---|
| 674 | search for mismatches while skipping skipA and skipB
|
---|
| 675 | */
|
---|
| 676 | int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
|
---|
| 677 | void **elemA, **elemB, **skipAp, **skipBp;
|
---|
| 678 |
|
---|
| 679 | elemA= SETaddr_(setA, void);
|
---|
| 680 | elemB= SETaddr_(setB, void);
|
---|
| 681 | skipAp= SETelemaddr_(setA, skipA, void);
|
---|
| 682 | skipBp= SETelemaddr_(setB, skipB, void);
|
---|
| 683 | while (1) {
|
---|
| 684 | if (elemA == skipAp)
|
---|
| 685 | elemA++;
|
---|
| 686 | if (elemB == skipBp)
|
---|
| 687 | elemB++;
|
---|
| 688 | if (!*elemA)
|
---|
| 689 | break;
|
---|
| 690 | if (*elemA++ != *elemB++)
|
---|
| 691 | return 0;
|
---|
| 692 | }
|
---|
| 693 | if (*elemB)
|
---|
| 694 | return 0;
|
---|
| 695 | return 1;
|
---|
| 696 | } /* setequal_skip */
|
---|
| 697 |
|
---|
| 698 |
|
---|
| 699 | /*-<a href="qh-set.htm#TOC"
|
---|
| 700 | >-------------------------------<a name="setfree">-</a>
|
---|
| 701 |
|
---|
| 702 | qh_setfree( setp )
|
---|
| 703 | frees the space occupied by a sorted or unsorted set
|
---|
| 704 |
|
---|
| 705 | returns:
|
---|
| 706 | sets setp to NULL
|
---|
| 707 |
|
---|
| 708 | notes:
|
---|
| 709 | set may be NULL
|
---|
| 710 |
|
---|
| 711 | design:
|
---|
| 712 | free array
|
---|
| 713 | free set
|
---|
| 714 | */
|
---|
| 715 | void qh_setfree(setT **setp) {
|
---|
| 716 | int size;
|
---|
| 717 | void **freelistp; /* used !qh_NOmem */
|
---|
| 718 |
|
---|
| 719 | if (*setp) {
|
---|
| 720 | size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
|
---|
| 721 | if (size <= qhmem.LASTsize) {
|
---|
| 722 | qh_memfree_(*setp, size, freelistp);
|
---|
| 723 | }else
|
---|
| 724 | qh_memfree(*setp, size);
|
---|
| 725 | *setp= NULL;
|
---|
| 726 | }
|
---|
| 727 | } /* setfree */
|
---|
| 728 |
|
---|
| 729 |
|
---|
| 730 | /*-<a href="qh-set.htm#TOC"
|
---|
| 731 | >-------------------------------<a name="setfree2">-</a>
|
---|
| 732 |
|
---|
| 733 | qh_setfree2( setp, elemsize )
|
---|
| 734 | frees the space occupied by a set and its elements
|
---|
| 735 |
|
---|
| 736 | notes:
|
---|
| 737 | set may be NULL
|
---|
| 738 |
|
---|
| 739 | design:
|
---|
| 740 | free each element
|
---|
| 741 | free set
|
---|
| 742 | */
|
---|
| 743 | void qh_setfree2 (setT **setp, int elemsize) {
|
---|
| 744 | void *elem, **elemp;
|
---|
| 745 |
|
---|
| 746 | FOREACHelem_(*setp)
|
---|
| 747 | qh_memfree(elem, elemsize);
|
---|
| 748 | qh_setfree(setp);
|
---|
| 749 | } /* setfree2 */
|
---|
| 750 |
|
---|
| 751 |
|
---|
| 752 |
|
---|
| 753 | /*-<a href="qh-set.htm#TOC"
|
---|
| 754 | >-------------------------------<a name="setfreelong">-</a>
|
---|
| 755 |
|
---|
| 756 | qh_setfreelong( setp )
|
---|
| 757 | frees a set only if it's in long memory
|
---|
| 758 |
|
---|
| 759 | returns:
|
---|
| 760 | sets setp to NULL if it is freed
|
---|
| 761 |
|
---|
| 762 | notes:
|
---|
| 763 | set may be NULL
|
---|
| 764 |
|
---|
| 765 | design:
|
---|
| 766 | if set is large
|
---|
| 767 | free it
|
---|
| 768 | */
|
---|
| 769 | void qh_setfreelong(setT **setp) {
|
---|
| 770 | int size;
|
---|
| 771 |
|
---|
| 772 | if (*setp) {
|
---|
| 773 | size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
|
---|
| 774 | if (size > qhmem.LASTsize) {
|
---|
| 775 | qh_memfree(*setp, size);
|
---|
| 776 | *setp= NULL;
|
---|
| 777 | }
|
---|
| 778 | }
|
---|
| 779 | } /* setfreelong */
|
---|
| 780 |
|
---|
| 781 |
|
---|
| 782 | /*-<a href="qh-set.htm#TOC"
|
---|
| 783 | >-------------------------------<a name="setin">-</a>
|
---|
| 784 |
|
---|
| 785 | qh_setin( set, setelem )
|
---|
| 786 | returns 1 if setelem is in a set, 0 otherwise
|
---|
| 787 |
|
---|
| 788 | notes:
|
---|
| 789 | set may be NULL or unsorted
|
---|
| 790 |
|
---|
| 791 | design:
|
---|
| 792 | scans set for setelem
|
---|
| 793 | */
|
---|
| 794 | int qh_setin(setT *set, void *setelem) {
|
---|
| 795 | void *elem, **elemp;
|
---|
| 796 |
|
---|
| 797 | FOREACHelem_(set) {
|
---|
| 798 | if (elem == setelem)
|
---|
| 799 | return 1;
|
---|
| 800 | }
|
---|
| 801 | return 0;
|
---|
| 802 | } /* setin */
|
---|
| 803 |
|
---|
| 804 |
|
---|
| 805 | /*-<a href="qh-set.htm#TOC"
|
---|
| 806 | >-------------------------------<a name="setindex">-</a>
|
---|
| 807 |
|
---|
| 808 | qh_setindex( set, atelem )
|
---|
| 809 | returns the index of atelem in set.
|
---|
| 810 | returns -1, if not in set or maxsize wrong
|
---|
| 811 |
|
---|
| 812 | notes:
|
---|
| 813 | set may be NULL and may contain nulls.
|
---|
| 814 | NOerrors returned (qh_pointid, QhullPoint::id)
|
---|
| 815 |
|
---|
| 816 | design:
|
---|
| 817 | checks maxsize
|
---|
| 818 | scans set for atelem
|
---|
| 819 | */
|
---|
| 820 | int qh_setindex(setT *set, void *atelem) {
|
---|
| 821 | void **elem;
|
---|
| 822 | int size, i;
|
---|
| 823 |
|
---|
| 824 | if (!set)
|
---|
| 825 | return -1;
|
---|
| 826 | SETreturnsize_(set, size);
|
---|
| 827 | if (size > set->maxsize)
|
---|
| 828 | return -1;
|
---|
| 829 | elem= SETaddr_(set, void);
|
---|
| 830 | for (i=0; i < size; i++) {
|
---|
| 831 | if (*elem++ == atelem)
|
---|
| 832 | return i;
|
---|
| 833 | }
|
---|
| 834 | return -1;
|
---|
| 835 | } /* setindex */
|
---|
| 836 |
|
---|
| 837 |
|
---|
| 838 | /*-<a href="qh-set.htm#TOC"
|
---|
| 839 | >-------------------------------<a name="setlarger">-</a>
|
---|
| 840 |
|
---|
| 841 | qh_setlarger( oldsetp )
|
---|
| 842 | returns a larger set that contains all elements of *oldsetp
|
---|
| 843 |
|
---|
| 844 | notes:
|
---|
| 845 | the set is at least twice as large
|
---|
| 846 | if temp set, updates qhmem.tempstack
|
---|
| 847 |
|
---|
| 848 | design:
|
---|
| 849 | creates a new set
|
---|
| 850 | copies the old set to the new set
|
---|
| 851 | updates pointers in tempstack
|
---|
| 852 | deletes the old set
|
---|
| 853 | */
|
---|
| 854 | void qh_setlarger(setT **oldsetp) {
|
---|
| 855 | int size= 1;
|
---|
| 856 | setT *newset, *set, **setp, *oldset;
|
---|
| 857 | setelemT *sizep;
|
---|
| 858 | setelemT *newp, *oldp;
|
---|
| 859 |
|
---|
| 860 | if (*oldsetp) {
|
---|
| 861 | oldset= *oldsetp;
|
---|
| 862 | SETreturnsize_(oldset, size);
|
---|
| 863 | qhmem.cntlarger++;
|
---|
| 864 | qhmem.totlarger += size+1;
|
---|
| 865 | newset= qh_setnew(2 * size);
|
---|
| 866 | oldp= (setelemT *)SETaddr_(oldset, void);
|
---|
| 867 | newp= (setelemT *)SETaddr_(newset, void);
|
---|
| 868 | memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize);
|
---|
| 869 | sizep= SETsizeaddr_(newset);
|
---|
| 870 | sizep->i= size+1;
|
---|
| 871 | FOREACHset_((setT *)qhmem.tempstack) {
|
---|
| 872 | if (set == oldset)
|
---|
| 873 | *(setp-1)= newset;
|
---|
| 874 | }
|
---|
| 875 | qh_setfree(oldsetp);
|
---|
| 876 | }else
|
---|
| 877 | newset= qh_setnew(3);
|
---|
| 878 | *oldsetp= newset;
|
---|
| 879 | } /* setlarger */
|
---|
| 880 |
|
---|
| 881 |
|
---|
| 882 | /*-<a href="qh-set.htm#TOC"
|
---|
| 883 | >-------------------------------<a name="setlast">-</a>
|
---|
| 884 |
|
---|
| 885 | qh_setlast( )
|
---|
| 886 | return last element of set or NULL (use type conversion)
|
---|
| 887 |
|
---|
| 888 | notes:
|
---|
| 889 | set may be NULL
|
---|
| 890 |
|
---|
| 891 | design:
|
---|
| 892 | return last element
|
---|
| 893 | */
|
---|
| 894 | void *qh_setlast(setT *set) {
|
---|
| 895 | int size;
|
---|
| 896 |
|
---|
| 897 | if (set) {
|
---|
| 898 | size= SETsizeaddr_(set)->i;
|
---|
| 899 | if (!size)
|
---|
| 900 | return SETelem_(set, set->maxsize - 1);
|
---|
| 901 | else if (size > 1)
|
---|
| 902 | return SETelem_(set, size - 2);
|
---|
| 903 | }
|
---|
| 904 | return NULL;
|
---|
| 905 | } /* setlast */
|
---|
| 906 |
|
---|
| 907 |
|
---|
| 908 | /*-<a href="qh-set.htm#TOC"
|
---|
| 909 | >-------------------------------<a name="setnew">-</a>
|
---|
| 910 |
|
---|
| 911 | qh_setnew( setsize )
|
---|
| 912 | creates and allocates space for a set
|
---|
| 913 |
|
---|
| 914 | notes:
|
---|
| 915 | setsize means the number of elements (!including the NULL terminator)
|
---|
| 916 | use qh_settemp/qh_setfreetemp if set is temporary
|
---|
| 917 |
|
---|
| 918 | design:
|
---|
| 919 | allocate memory for set
|
---|
| 920 | roundup memory if small set
|
---|
| 921 | initialize as empty set
|
---|
| 922 | */
|
---|
| 923 | setT *qh_setnew(int setsize) {
|
---|
| 924 | setT *set;
|
---|
| 925 | int sizereceived; /* used !qh_NOmem */
|
---|
| 926 | int size;
|
---|
| 927 | void **freelistp; /* used !qh_NOmem */
|
---|
| 928 |
|
---|
| 929 | if (!setsize)
|
---|
| 930 | setsize++;
|
---|
| 931 | size= sizeof(setT) + setsize * SETelemsize;
|
---|
| 932 | if (size>0 && size <= qhmem.LASTsize) {
|
---|
| 933 | qh_memalloc_(size, freelistp, set, setT);
|
---|
| 934 | #ifndef qh_NOmem
|
---|
| 935 | sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
|
---|
| 936 | if (sizereceived > size)
|
---|
| 937 | setsize += (sizereceived - size)/SETelemsize;
|
---|
| 938 | #endif
|
---|
| 939 | }else
|
---|
| 940 | set= (setT*)qh_memalloc(size);
|
---|
| 941 | set->maxsize= setsize;
|
---|
| 942 | set->e[setsize].i= 1;
|
---|
| 943 | set->e[0].p= NULL;
|
---|
| 944 | return(set);
|
---|
| 945 | } /* setnew */
|
---|
| 946 |
|
---|
| 947 |
|
---|
| 948 | /*-<a href="qh-set.htm#TOC"
|
---|
| 949 | >-------------------------------<a name="setnew_delnthsorted">-</a>
|
---|
| 950 |
|
---|
| 951 | qh_setnew_delnthsorted( set, size, nth, prepend )
|
---|
| 952 | creates a sorted set not containing nth element
|
---|
| 953 | if prepend, the first prepend elements are undefined
|
---|
| 954 |
|
---|
| 955 | notes:
|
---|
| 956 | set must be defined
|
---|
| 957 | checks nth
|
---|
| 958 | see also: setdelnthsorted
|
---|
| 959 |
|
---|
| 960 | design:
|
---|
| 961 | create new set
|
---|
| 962 | setup pointers and allocate room for prepend'ed entries
|
---|
| 963 | append head of old set to new set
|
---|
| 964 | append tail of old set to new set
|
---|
| 965 | */
|
---|
| 966 | setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
|
---|
| 967 | setT *newset;
|
---|
| 968 | void **oldp, **newp;
|
---|
| 969 | int tailsize= size - nth -1, newsize;
|
---|
| 970 |
|
---|
| 971 | if (tailsize < 0) {
|
---|
| 972 | qh_fprintf(qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
|
---|
| 973 | qh_setprint(qhmem.ferr, "", set);
|
---|
| 974 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 975 | }
|
---|
| 976 | newsize= size-1 + prepend;
|
---|
| 977 | newset= qh_setnew(newsize);
|
---|
| 978 | newset->e[newset->maxsize].i= newsize+1; /* may be overwritten */
|
---|
| 979 | oldp= SETaddr_(set, void);
|
---|
| 980 | newp= SETaddr_(newset, void) + prepend;
|
---|
| 981 | switch (nth) {
|
---|
| 982 | case 0:
|
---|
| 983 | break;
|
---|
| 984 | case 1:
|
---|
| 985 | *(newp++)= *oldp++;
|
---|
| 986 | break;
|
---|
| 987 | case 2:
|
---|
| 988 | *(newp++)= *oldp++;
|
---|
| 989 | *(newp++)= *oldp++;
|
---|
| 990 | break;
|
---|
| 991 | case 3:
|
---|
| 992 | *(newp++)= *oldp++;
|
---|
| 993 | *(newp++)= *oldp++;
|
---|
| 994 | *(newp++)= *oldp++;
|
---|
| 995 | break;
|
---|
| 996 | case 4:
|
---|
| 997 | *(newp++)= *oldp++;
|
---|
| 998 | *(newp++)= *oldp++;
|
---|
| 999 | *(newp++)= *oldp++;
|
---|
| 1000 | *(newp++)= *oldp++;
|
---|
| 1001 | break;
|
---|
| 1002 | default:
|
---|
| 1003 | memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
|
---|
| 1004 | newp += nth;
|
---|
| 1005 | oldp += nth;
|
---|
| 1006 | break;
|
---|
| 1007 | }
|
---|
| 1008 | oldp++;
|
---|
| 1009 | switch (tailsize) {
|
---|
| 1010 | case 0:
|
---|
| 1011 | break;
|
---|
| 1012 | case 1:
|
---|
| 1013 | *(newp++)= *oldp++;
|
---|
| 1014 | break;
|
---|
| 1015 | case 2:
|
---|
| 1016 | *(newp++)= *oldp++;
|
---|
| 1017 | *(newp++)= *oldp++;
|
---|
| 1018 | break;
|
---|
| 1019 | case 3:
|
---|
| 1020 | *(newp++)= *oldp++;
|
---|
| 1021 | *(newp++)= *oldp++;
|
---|
| 1022 | *(newp++)= *oldp++;
|
---|
| 1023 | break;
|
---|
| 1024 | case 4:
|
---|
| 1025 | *(newp++)= *oldp++;
|
---|
| 1026 | *(newp++)= *oldp++;
|
---|
| 1027 | *(newp++)= *oldp++;
|
---|
| 1028 | *(newp++)= *oldp++;
|
---|
| 1029 | break;
|
---|
| 1030 | default:
|
---|
| 1031 | memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
|
---|
| 1032 | newp += tailsize;
|
---|
| 1033 | }
|
---|
| 1034 | *newp= NULL;
|
---|
| 1035 | return(newset);
|
---|
| 1036 | } /* setnew_delnthsorted */
|
---|
| 1037 |
|
---|
| 1038 |
|
---|
| 1039 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1040 | >-------------------------------<a name="setprint">-</a>
|
---|
| 1041 |
|
---|
| 1042 | qh_setprint( fp, string, set )
|
---|
| 1043 | print set elements to fp with identifying string
|
---|
| 1044 |
|
---|
| 1045 | notes:
|
---|
| 1046 | never errors
|
---|
| 1047 | */
|
---|
| 1048 | void qh_setprint(FILE *fp, const char* string, setT *set) {
|
---|
| 1049 | int size, k;
|
---|
| 1050 |
|
---|
| 1051 | if (!set)
|
---|
| 1052 | qh_fprintf(fp, 9346, "%s set is null\n", string);
|
---|
| 1053 | else {
|
---|
| 1054 | SETreturnsize_(set, size);
|
---|
| 1055 | qh_fprintf(fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
|
---|
| 1056 | string, set, set->maxsize, size);
|
---|
| 1057 | if (size > set->maxsize)
|
---|
| 1058 | size= set->maxsize+1;
|
---|
| 1059 | for (k=0; k < size; k++)
|
---|
| 1060 | qh_fprintf(fp, 9348, " %p", set->e[k].p);
|
---|
| 1061 | qh_fprintf(fp, 9349, "\n");
|
---|
| 1062 | }
|
---|
| 1063 | } /* setprint */
|
---|
| 1064 |
|
---|
| 1065 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1066 | >-------------------------------<a name="setreplace">-</a>
|
---|
| 1067 |
|
---|
| 1068 | qh_setreplace( set, oldelem, newelem )
|
---|
| 1069 | replaces oldelem in set with newelem
|
---|
| 1070 |
|
---|
| 1071 | notes:
|
---|
| 1072 | errors if oldelem not in the set
|
---|
| 1073 | newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
|
---|
| 1074 |
|
---|
| 1075 | design:
|
---|
| 1076 | find oldelem
|
---|
| 1077 | replace with newelem
|
---|
| 1078 | */
|
---|
| 1079 | void qh_setreplace(setT *set, void *oldelem, void *newelem) {
|
---|
| 1080 | void **elemp;
|
---|
| 1081 |
|
---|
| 1082 | elemp= SETaddr_(set, void);
|
---|
| 1083 | while (*elemp != oldelem && *elemp)
|
---|
| 1084 | elemp++;
|
---|
| 1085 | if (*elemp)
|
---|
| 1086 | *elemp= newelem;
|
---|
| 1087 | else {
|
---|
| 1088 | qh_fprintf(qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
|
---|
| 1089 | oldelem);
|
---|
| 1090 | qh_setprint(qhmem.ferr, "", set);
|
---|
| 1091 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 1092 | }
|
---|
| 1093 | } /* setreplace */
|
---|
| 1094 |
|
---|
| 1095 |
|
---|
| 1096 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1097 | >-------------------------------<a name="setsize">-</a>
|
---|
| 1098 |
|
---|
| 1099 | qh_setsize( set )
|
---|
| 1100 | returns the size of a set
|
---|
| 1101 |
|
---|
| 1102 | notes:
|
---|
| 1103 | errors if set's maxsize is incorrect
|
---|
| 1104 | same as SETreturnsize_(set)
|
---|
| 1105 | same code for qh_setsize [qset.c] and QhullSetBase::count
|
---|
| 1106 |
|
---|
| 1107 | design:
|
---|
| 1108 | determine actual size of set from maxsize
|
---|
| 1109 | */
|
---|
| 1110 | int qh_setsize(setT *set) {
|
---|
| 1111 | int size;
|
---|
| 1112 | setelemT *sizep;
|
---|
| 1113 |
|
---|
| 1114 | if (!set)
|
---|
| 1115 | return(0);
|
---|
| 1116 | sizep= SETsizeaddr_(set);
|
---|
| 1117 | if ((size= sizep->i)) {
|
---|
| 1118 | size--;
|
---|
| 1119 | if (size > set->maxsize) {
|
---|
| 1120 | qh_fprintf(qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
|
---|
| 1121 | size, set->maxsize);
|
---|
| 1122 | qh_setprint(qhmem.ferr, "set: ", set);
|
---|
| 1123 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 1124 | }
|
---|
| 1125 | }else
|
---|
| 1126 | size= set->maxsize;
|
---|
| 1127 | return size;
|
---|
| 1128 | } /* setsize */
|
---|
| 1129 |
|
---|
| 1130 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1131 | >-------------------------------<a name="settemp">-</a>
|
---|
| 1132 |
|
---|
| 1133 | qh_settemp( setsize )
|
---|
| 1134 | return a stacked, temporary set of upto setsize elements
|
---|
| 1135 |
|
---|
| 1136 | notes:
|
---|
| 1137 | use settempfree or settempfree_all to release from qhmem.tempstack
|
---|
| 1138 | see also qh_setnew
|
---|
| 1139 |
|
---|
| 1140 | design:
|
---|
| 1141 | allocate set
|
---|
| 1142 | append to qhmem.tempstack
|
---|
| 1143 |
|
---|
| 1144 | */
|
---|
| 1145 | setT *qh_settemp(int setsize) {
|
---|
| 1146 | setT *newset;
|
---|
| 1147 |
|
---|
| 1148 | newset= qh_setnew(setsize);
|
---|
| 1149 | qh_setappend(&qhmem.tempstack, newset);
|
---|
| 1150 | if (qhmem.IStracing >= 5)
|
---|
| 1151 | qh_fprintf(qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
|
---|
| 1152 | newset, newset->maxsize, qh_setsize(qhmem.tempstack));
|
---|
| 1153 | return newset;
|
---|
| 1154 | } /* settemp */
|
---|
| 1155 |
|
---|
| 1156 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1157 | >-------------------------------<a name="settempfree">-</a>
|
---|
| 1158 |
|
---|
| 1159 | qh_settempfree( set )
|
---|
| 1160 | free temporary set at top of qhmem.tempstack
|
---|
| 1161 |
|
---|
| 1162 | notes:
|
---|
| 1163 | nop if set is NULL
|
---|
| 1164 | errors if set not from previous qh_settemp
|
---|
| 1165 |
|
---|
| 1166 | to locate errors:
|
---|
| 1167 | use 'T2' to find source and then find mis-matching qh_settemp
|
---|
| 1168 |
|
---|
| 1169 | design:
|
---|
| 1170 | check top of qhmem.tempstack
|
---|
| 1171 | free it
|
---|
| 1172 | */
|
---|
| 1173 | void qh_settempfree(setT **set) {
|
---|
| 1174 | setT *stackedset;
|
---|
| 1175 |
|
---|
| 1176 | if (!*set)
|
---|
| 1177 | return;
|
---|
| 1178 | stackedset= qh_settemppop();
|
---|
| 1179 | if (stackedset != *set) {
|
---|
| 1180 | qh_settemppush(stackedset);
|
---|
| 1181 | qh_fprintf(qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
|
---|
| 1182 | *set, qh_setsize(*set), qh_setsize(qhmem.tempstack)+1,
|
---|
| 1183 | stackedset, qh_setsize(stackedset));
|
---|
| 1184 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 1185 | }
|
---|
| 1186 | qh_setfree(set);
|
---|
| 1187 | } /* settempfree */
|
---|
| 1188 |
|
---|
| 1189 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1190 | >-------------------------------<a name="settempfree_all">-</a>
|
---|
| 1191 |
|
---|
| 1192 | qh_settempfree_all( )
|
---|
| 1193 | free all temporary sets in qhmem.tempstack
|
---|
| 1194 |
|
---|
| 1195 | design:
|
---|
| 1196 | for each set in tempstack
|
---|
| 1197 | free set
|
---|
| 1198 | free qhmem.tempstack
|
---|
| 1199 | */
|
---|
| 1200 | void qh_settempfree_all(void) {
|
---|
| 1201 | setT *set, **setp;
|
---|
| 1202 |
|
---|
| 1203 | FOREACHset_(qhmem.tempstack)
|
---|
| 1204 | qh_setfree(&set);
|
---|
| 1205 | qh_setfree(&qhmem.tempstack);
|
---|
| 1206 | } /* settempfree_all */
|
---|
| 1207 |
|
---|
| 1208 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1209 | >-------------------------------<a name="settemppop">-</a>
|
---|
| 1210 |
|
---|
| 1211 | qh_settemppop( )
|
---|
| 1212 | pop and return temporary set from qhmem.tempstack
|
---|
| 1213 |
|
---|
| 1214 | notes:
|
---|
| 1215 | the returned set is permanent
|
---|
| 1216 |
|
---|
| 1217 | design:
|
---|
| 1218 | pop and check top of qhmem.tempstack
|
---|
| 1219 | */
|
---|
| 1220 | setT *qh_settemppop(void) {
|
---|
| 1221 | setT *stackedset;
|
---|
| 1222 |
|
---|
| 1223 | stackedset= (setT*)qh_setdellast(qhmem.tempstack);
|
---|
| 1224 | if (!stackedset) {
|
---|
| 1225 | qh_fprintf(qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
|
---|
| 1226 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 1227 | }
|
---|
| 1228 | if (qhmem.IStracing >= 5)
|
---|
| 1229 | qh_fprintf(qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
|
---|
| 1230 | qh_setsize(qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
|
---|
| 1231 | return stackedset;
|
---|
| 1232 | } /* settemppop */
|
---|
| 1233 |
|
---|
| 1234 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1235 | >-------------------------------<a name="settemppush">-</a>
|
---|
| 1236 |
|
---|
| 1237 | qh_settemppush( set )
|
---|
| 1238 | push temporary set unto qhmem.tempstack (makes it temporary)
|
---|
| 1239 |
|
---|
| 1240 | notes:
|
---|
| 1241 | duplicates settemp() for tracing
|
---|
| 1242 |
|
---|
| 1243 | design:
|
---|
| 1244 | append set to tempstack
|
---|
| 1245 | */
|
---|
| 1246 | void qh_settemppush(setT *set) {
|
---|
| 1247 | if (!set) {
|
---|
| 1248 | fprintf (qhmem.ferr, "qhull error (qh_settemppush): can not push a NULL temp\n");
|
---|
| 1249 | qh_errexit (qhmem_ERRqhull, NULL, NULL);
|
---|
| 1250 | }
|
---|
| 1251 | qh_setappend(&qhmem.tempstack, set);
|
---|
| 1252 | if (qhmem.IStracing >= 5)
|
---|
| 1253 | qh_fprintf(qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
|
---|
| 1254 | qh_setsize(qhmem.tempstack), set, qh_setsize(set));
|
---|
| 1255 | } /* settemppush */
|
---|
| 1256 |
|
---|
| 1257 |
|
---|
| 1258 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1259 | >-------------------------------<a name="settruncate">-</a>
|
---|
| 1260 |
|
---|
| 1261 | qh_settruncate( set, size )
|
---|
| 1262 | truncate set to size elements
|
---|
| 1263 |
|
---|
| 1264 | notes:
|
---|
| 1265 | set must be defined
|
---|
| 1266 |
|
---|
| 1267 | see:
|
---|
| 1268 | SETtruncate_
|
---|
| 1269 |
|
---|
| 1270 | design:
|
---|
| 1271 | check size
|
---|
| 1272 | update actual size of set
|
---|
| 1273 | */
|
---|
| 1274 | void qh_settruncate(setT *set, int size) {
|
---|
| 1275 |
|
---|
| 1276 | if (size < 0 || size > set->maxsize) {
|
---|
| 1277 | qh_fprintf(qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
|
---|
| 1278 | qh_setprint(qhmem.ferr, "", set);
|
---|
| 1279 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 1280 | }
|
---|
| 1281 | set->e[set->maxsize].i= size+1; /* maybe overwritten */
|
---|
| 1282 | set->e[size].p= NULL;
|
---|
| 1283 | } /* settruncate */
|
---|
| 1284 |
|
---|
| 1285 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1286 | >-------------------------------<a name="setunique">-</a>
|
---|
| 1287 |
|
---|
| 1288 | qh_setunique( set, elem )
|
---|
| 1289 | add elem to unsorted set unless it is already in set
|
---|
| 1290 |
|
---|
| 1291 | notes:
|
---|
| 1292 | returns 1 if it is appended
|
---|
| 1293 |
|
---|
| 1294 | design:
|
---|
| 1295 | if elem not in set
|
---|
| 1296 | append elem to set
|
---|
| 1297 | */
|
---|
| 1298 | int qh_setunique(setT **set, void *elem) {
|
---|
| 1299 |
|
---|
| 1300 | if (!qh_setin(*set, elem)) {
|
---|
| 1301 | qh_setappend(set, elem);
|
---|
| 1302 | return 1;
|
---|
| 1303 | }
|
---|
| 1304 | return 0;
|
---|
| 1305 | } /* setunique */
|
---|
| 1306 |
|
---|
| 1307 | /*-<a href="qh-set.htm#TOC"
|
---|
| 1308 | >-------------------------------<a name="setzero">-</a>
|
---|
| 1309 |
|
---|
| 1310 | qh_setzero( set, index, size )
|
---|
| 1311 | zero elements from index on
|
---|
| 1312 | set actual size of set to size
|
---|
| 1313 |
|
---|
| 1314 | notes:
|
---|
| 1315 | set must be defined
|
---|
| 1316 | the set becomes an indexed set (can not use FOREACH...)
|
---|
| 1317 |
|
---|
| 1318 | see also:
|
---|
| 1319 | qh_settruncate
|
---|
| 1320 |
|
---|
| 1321 | design:
|
---|
| 1322 | check index and size
|
---|
| 1323 | update actual size
|
---|
| 1324 | zero elements starting at e[index]
|
---|
| 1325 | */
|
---|
| 1326 | void qh_setzero(setT *set, int idx, int size) {
|
---|
| 1327 | int count;
|
---|
| 1328 |
|
---|
| 1329 | if (idx < 0 || idx >= size || size > set->maxsize) {
|
---|
| 1330 | qh_fprintf(qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
|
---|
| 1331 | qh_setprint(qhmem.ferr, "", set);
|
---|
| 1332 | qh_errexit(qhmem_ERRqhull, NULL, NULL);
|
---|
| 1333 | }
|
---|
| 1334 | set->e[set->maxsize].i= size+1; /* may be overwritten */
|
---|
| 1335 | count= size - idx + 1; /* +1 for NULL terminator */
|
---|
| 1336 | memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
|
---|
| 1337 | } /* setzero */
|
---|
| 1338 |
|
---|
| 1339 |
|
---|