ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/QuickHull/qset.c
Revision: 1138
Committed: Tue May 29 22:51:00 2007 UTC (17 years, 11 months ago) by chuckv
Content type: text/plain
File size: 31985 byte(s)
Log Message:
Addded QuickHull to cvs.

File Contents

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