1 /* qhull.c - For the Gambit Project
2
3 This file contains the implementation code taken from qhull and
4 incorporated into the Gambit source code. We have placed all qhull
5 code in qhull.h and qhull.c to avoid adding to the number of files
6 in Gambit, and, more importantly, to express the idea that, from our
7 point of view, this is a blackbox. We are unlikely to be able to
8 answer questions concerning this code, and those who wish to modify
9 it should consider beginning with the version distributed by the
10 Geometry Center.
11 */
12
13 #include "pelqhull.h"
14
15 /*************************************************************************/
16 /******************* implementation code from mem.c **********************/
17 /*************************************************************************/
18
19 /* mem.c - memory management routines for qhull
20
21 This is a standalone program.
22
23 To initialize memory:
24
25 qh_meminit (stderr); /
26 qh_meminitbuffers (qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
27 qh_memsize(sizeof(facetT));
28 qh_memsize(sizeof(facetT));
29 ...
30 qh_memsetup();
31
32 To free up all memory buffers:
33 qh_memfreeshort (&curlong, &totlong);
34
35
36 uses Quickfit algorithm (freelists for commonly allocated sizes)
37 assumes small sizes for freelists (it discards the tail of memory buffers)
38
39 see README and mem.h
40 see global.c (qh_initbuffers) for an example of using mem.c
41
42 copyright (c) 1993-1994 The Geometry Center
43 */
44
45 /* ============ -global data structure ==============
46 see mem.h for definition
47 */
48
49 qhmemT qhmem= {0}; /* remove "= {0}" if this causes a compiler error */
50
51 /* internal functions */
52
53 static int qh_intcompare(const void *i, const void *j);
54
55 /*========== functions in alphabetical order ======== */
56
57 /*-------------------------------------------------
58 -intcompare- used by qsort and bsearch to compare two integers
59 */
qh_intcompare(const void * i,const void * j)60 static int qh_intcompare(const void *i, const void *j) {
61 return(*((int *)i) - *((int *)j));
62 } /* intcompare */
63
64
65 /*-------------------------------------------------
66 -memalloc- allocates memory for object from qhmem
67 returns:
68 pointer to allocated memory (errors if insufficient memory)
69 outsize= actual size allocated, may be NULL
70 notes:
71 use qh_memalloc_() for inline code for quick allocations
72 */
qh_memalloc(int insize)73 void *qh_memalloc(int insize) {
74 void **freelistp, *newbuffer;
75 int index, size;
76 int outsize, bufsize;
77 void *object;
78
79 if ((unsigned) insize <= (unsigned) qhmem.LASTsize) {
80 index= qhmem.indextable[insize];
81 freelistp= qhmem.freelists+index;
82 if ((object= *freelistp)) {
83 qhmem.cntquick++;
84 *freelistp= *((void **)*freelistp); /* replace freelist with next object */
85 return (object);
86 }else {
87 outsize= qhmem.sizetable[index];
88 qhmem.cntshort++;
89 if (outsize > qhmem .freesize) {
90 if (!qhmem.curbuffer)
91 bufsize= qhmem.BUFinit;
92 else
93 bufsize= qhmem.BUFsize;
94 qhmem.totshort += bufsize;
95
96 if (!(newbuffer= malloc(bufsize))) qhull_fatal(1);
97
98 *((void **)newbuffer)= qhmem.curbuffer; /* prepend newbuffer to curbuffer
99 list */
100 qhmem.curbuffer= newbuffer;
101 size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
102 qhmem.freemem= (void *)((char *)newbuffer+size);
103 qhmem.freesize= bufsize - size;
104 }
105 object= qhmem.freemem;
106 qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
107 qhmem.freesize -= outsize;
108 return object;
109 }
110 }else { /* long allocation */
111
112 if (!qhmem.indextable) qhull_fatal(2);
113
114 outsize= insize;
115 qhmem .cntlong++;
116 qhmem .curlong++;
117 qhmem .totlong += outsize;
118 if (qhmem.maxlong < qhmem.totlong)
119 qhmem.maxlong= qhmem.totlong;
120
121 if (!(object= malloc(outsize))) qhull_fatal(3);
122
123 if (qhmem.IStracing >= 5)
124 fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", outsize, object);
125 }
126 return (object);
127 } /* memalloc */
128
129
130 /*-------------------------------------------------
131 -memfree- frees memory object (may be NULL)
132 size is either insize or outsize from qh_memalloc
133 type checking warns if using (void **)object
134 qh_memfree_()- in-line code for quick free's
135 */
qh_memfree(void * object,int size)136 void qh_memfree(void *object, int size) {
137 void **freelistp;
138
139 if (!object)
140 return;
141 if (size <= qhmem.LASTsize) {
142 qhmem .freeshort++;
143 freelistp= qhmem.freelists + qhmem.indextable[size];
144 *((void **)object)= *freelistp;
145 *freelistp= object;
146 }else {
147 qhmem .freelong++;
148 qhmem .totlong -= size;
149 free (object);
150 if (qhmem.IStracing >= 5)
151 fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
152 }
153 } /* memfree */
154
155
156 /*-------------------------------------------------
157 -memfreeshort- frees up all short and qhmem memory allocations
158 returns: number and size of current long allocations
159 */
qh_memfreeshort(int * curlong,int * totlong)160 void qh_memfreeshort (int *curlong, int *totlong) {
161 void *buffer, *nextbuffer;
162
163 *curlong= qhmem .cntlong - qhmem .freelong;
164 *totlong= qhmem .totlong;
165 for(buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
166 nextbuffer= *((void **) buffer);
167 free(buffer);
168 }
169 qhmem.curbuffer= NULL;
170 if (qhmem .LASTsize) {
171 free (qhmem .indextable);
172 free (qhmem .freelists);
173 free (qhmem .sizetable);
174 }
175 memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
176 } /* memfreeshort */
177
178
179 /*-------------------------------------------------
180 -meminit- initialize memory (memalloc errors until memsetup)
181 */
qh_meminit(FILE * ferr)182 void qh_meminit (FILE *ferr) {
183
184 memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
185 qhmem.ferr= ferr;
186
187 #ifndef __BCC55__
188 // This condition is always false under BCC55
189 if (sizeof(void*) < sizeof(int)) qhull_fatal(4);
190 #endif // __BCC55__
191 } /* meminit */
192
193 /*-------------------------------------------------
194 -meminitbuffers- initialize memory buffers
195 */
qh_meminitbuffers(int tracelevel,int alignment,int numsizes,int bufsize,int bufinit)196 void qh_meminitbuffers (int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
197
198 qhmem.IStracing= tracelevel;
199 qhmem.NUMsizes= numsizes;
200 qhmem.BUFsize= bufsize;
201 qhmem.BUFinit= bufinit;
202 qhmem.ALIGNmask= alignment-1;
203
204 if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) qhull_fatal(5);
205
206 qhmem.sizetable= (int *) calloc (numsizes, sizeof(int));
207 qhmem.freelists= (void **) calloc (numsizes, sizeof(void *));
208
209 if (!qhmem.sizetable || !qhmem.freelists) qhull_fatal(6);
210
211 if (qhmem.IStracing >= 1)
212 fprintf (qhmem.ferr, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
213 } /* meminitbuffers */
214
215 /*-------------------------------------------------
216 -memsetup- set up memory after running memsize()
217 */
qh_memsetup(void)218 void qh_memsetup (void) {
219 int k,i;
220
221 qsort(qhmem.sizetable, qhmem.TABLEsize, sizeof(int), qh_intcompare);
222 qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
223
224 if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit)
225 qhull_fatal(7);
226
227 if (!(qhmem.indextable= (int *)malloc((qhmem.LASTsize+1) * sizeof(int))))
228 qhull_fatal(8);
229
230 for(k=qhmem.LASTsize+1; k--; )
231 qhmem.indextable[k]= k;
232 i= 0;
233 for(k= 0; k <= qhmem.LASTsize; k++) {
234 if (qhmem.indextable[k] <= qhmem.sizetable[i])
235 qhmem.indextable[k]= i;
236 else
237 qhmem.indextable[k]= ++i;
238 }
239 } /* memsetup */
240
241 /*-------------------------------------------------
242 -memsize- define a free list for this size
243 */
qh_memsize(int size)244 void qh_memsize(int size) {
245 int k;
246
247 if (qhmem .LASTsize) qhull_fatal(9);
248
249 size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask;
250 for(k= qhmem.TABLEsize; k--; ) {
251 if (qhmem.sizetable[k] == size)
252 return;
253 }
254 if (qhmem.TABLEsize < qhmem.NUMsizes)
255 qhmem.sizetable[qhmem.TABLEsize++]= size;
256 else
257 fprintf(qhmem.ferr, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
258 } /* memsize */
259
260
261 /*-------------------------------------------------
262 -memstatistics- print out memory statistics
263 */
qh_memstatistics(FILE * fp)264 void qh_memstatistics (FILE *fp) {
265 int i, count;
266 void *object;
267
268 fprintf (fp, "\nmemory statistics:\n\
269 %7d quick allocations\n\
270 %7d short allocations\n\
271 %7d long allocations\n\
272 %7d short frees\n\
273 %7d long frees\n\
274 %7d bytes of short memory in use or on freelists\n\
275 %7d bytes of long memory allocated (except for input)\n\
276 %7d bytes of long memory in use (in %d pieces)\n\
277 %7d bytes per memory buffer (initially %d bytes)\n",
278 qhmem .cntquick, qhmem.cntshort, qhmem.cntlong,
279 qhmem .freeshort, qhmem.freelong,
280 qhmem .totshort - qhmem .freesize,
281 qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
282 qhmem .BUFsize, qhmem .BUFinit);
283 if (qhmem.cntlarger) {
284 fprintf (fp, "%7d calls to qh_setlarger\n%7.2g average copy size\n",
285 qhmem.cntlarger, ((float) qhmem.totlarger)/ qhmem.cntlarger);
286 fprintf (fp, " freelists (bytes->count):");
287 }
288 for (i=0; i<qhmem.TABLEsize; i++) {
289 count=0;
290 for (object= qhmem .freelists[i]; object; object= *((void **)object))
291 count++;
292 fprintf (fp, " %d->%d", qhmem.sizetable[i], count);
293 }
294 fprintf (fp, "\n\n");
295 } /* memstatistics */
296
297
298 /*************************************************************************/
299 /******************* implementation code from set.c **********************/
300 /*************************************************************************/
301
302 /* set.c -- implements set manipulations needed for quickhull
303
304 see README and set.h
305
306 copyright (c) 1993-1994 The Geometry Center
307 */
308
309 /*----------- internal macros -------------------
310 -SETsizeaddr_(set) - return pointer to actual size+1 of set (set CANNOT be NULL!!)
311 *SETsizeaddr==NULL or e[*SETsizeaddr-1]==NULL
312 */
313 #define SETsizeaddr_(set) ((int *)(&((set)->e[(set)->maxsize])))
314
315 /*============ functions in alphabetical order ===================*/
316
317 /*----------------------------------------
318 -setaddnth- adds newelem as n'th element of sorted or unsorted set
319 setp and newelem must be defined
320 set may be a temp set
321 nth=0 is first element
322 errors if nth is out of bounds
323 */
qh_setaddnth(setT ** setp,int nth,void * newelem)324 void qh_setaddnth(setT **setp, int nth, void *newelem) {
325 int *sizep, oldsize, i;
326 void **oldp, **newp;
327
328 if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
329 qh_setlarger(setp);
330 sizep= SETsizeaddr_(*setp);
331 }
332 oldsize= *sizep - 1;
333 if (nth < 0 || nth > oldsize) qhull_fatal(10);
334
335 (*sizep)++;
336 oldp= SETelemaddr_(*setp, oldsize, void); /* NULL */
337 newp= oldp+1;
338 for (i= oldsize-nth+1; i--; ) /* move at least NULL */
339 *(newp--)= *(oldp--); /* may overwrite *sizep */
340 *newp= newelem;
341 } /* setaddnth */
342
343
344 /*----------------------------------------
345 -setaddsorted- adds an element to a sorted set
346 setp and newelem must be defined
347 set may be a temp set
348 nop if newelem already in set
349 */
qh_setaddsorted(setT ** setp,void * newelem)350 void qh_setaddsorted(setT **setp, void *newelem) {
351 int newindex=0;
352 void *elem, **elemp;
353
354 FOREACHelem_(*setp) { /* could use binary search instead */
355 if (elem < newelem)
356 newindex++;
357 else if (elem == newelem)
358 return;
359 else
360 break;
361 }
362 qh_setaddnth(setp, newindex, newelem);
363 } /* setaddsorted */
364
365
366 /*----------------------------------------
367 -setappend- appends an element to a set
368 set may be a temp set
369 *setp and newelem may be NULL
370 */
qh_setappend(setT ** setp,void * newelem)371 void qh_setappend(setT **setp, void *newelem) {
372 int *sizep;
373 void **endp;
374
375 if (!newelem)
376 return;
377 if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
378 qh_setlarger(setp);
379 sizep= SETsizeaddr_(*setp);
380 }
381 *(endp= &((*setp)->e[(*sizep)++ - 1]))= newelem;
382 *(++endp)= NULL;
383 } /* setappend */
384
385 /*----------------------------------------
386 -setappend_set- appends a set to a set
387 *setp and set may be NULL
388 setp can not be a temp set
389 */
qh_setappend_set(setT ** setp,setT * setA)390 void qh_setappend_set(setT **setp, setT *setA) {
391 int *sizep, sizeA, size;
392 setT *oldset;
393
394 if (!setA)
395 return;
396 SETreturnsize_(setA, sizeA);
397 if (!*setp)
398 *setp= qh_setnew (sizeA);
399 sizep= SETsizeaddr_(*setp);
400 if (!(size= *sizep))
401 size= (*setp)->maxsize;
402 else
403 size--;
404 if (size + sizeA >(int) (*setp)->maxsize) {
405 oldset= *setp;
406 *setp= qh_setcopy (oldset, sizeA);
407 qh_setfree (&oldset);
408 sizep= SETsizeaddr_(*setp);
409 }
410 *sizep= size+sizeA+1; /* memcpy may overwrite */
411 if (sizeA > 0)
412 memcpy((char *)&((*setp)->e[size]), (char *)&(setA->e[0]), SETelemsize *(sizeA+1));
413 } /* setappend_set */
414
415
416 /*----------------------------------------
417 -setappend2ndlast- makes newelem the next to the last element in set
418 set must have at least one element, newelem must be defined
419 set may be a temp set
420 */
qh_setappend2ndlast(setT ** setp,void * newelem)421 void qh_setappend2ndlast(setT **setp, void *newelem) {
422 int *sizep;
423 void **endp, **lastp;
424
425 if (!*setp || !*(sizep= SETsizeaddr_(*setp))) {
426 qh_setlarger(setp);
427 sizep= SETsizeaddr_(*setp);
428 }
429 endp= SETelemaddr_(*setp, (*sizep)++ -1, void); /* NULL */
430 lastp= endp-1;
431 *(endp++)= *lastp;
432 *endp= NULL; /* may overwrite *sizep */
433 *lastp= newelem;
434 } /* setappend2ndlast */
435
436
437 /*----------------------------------------
438 -setcheck- check set for validity
439 */
qh_setcheck(setT * set,const char * typenameNEW,int id)440 void qh_setcheck(setT *set, const char *typenameNEW, int id) {
441 int maxsize, size;
442 int waserr= 0;
443
444 if (!set)
445 return;
446 SETreturnsize_(set, size);
447 maxsize= set->maxsize;
448 if (size > maxsize || !maxsize) {
449 fprintf (qhmem.ferr, "qhull internal error (setcheck): actual size %d of %s%d is greater than max size %d\n",
450 size, typenameNEW, id, maxsize);
451 waserr= 1;
452 }else if (set->e[size]) {
453 fprintf (qhmem.ferr, "qhull internal error (setcheck): %s%d (size %d max %d) is not null terminated.\n",
454 typenameNEW, id, maxsize, size-1);
455 waserr= 1;
456 }
457 if (waserr) qhull_fatal(11);
458
459 } /* setcheck */
460
461
462 /*----------------------------------------
463 -setcopy- copies a sorted or unsorted set into another
464 returns:
465 new set is actual size of old set plus extra
466 */
qh_setcopy(setT * set,int extra)467 setT *qh_setcopy(setT *set, int extra) {
468 setT *newset;
469 int size;
470
471 if (extra < 0)
472 extra= 0;
473 SETreturnsize_(set, size);
474 newset= qh_setnew(size+extra);
475 *SETsizeaddr_(newset)= size+1; /* memcpy may overwrite */
476 memcpy((char *)&(newset->e[0]), (char *)&(set->e[0]), SETelemsize *(size+1));
477 return (newset);
478 } /* setcopy */
479
480
481 /*----------------------------------------
482 -setdel- deletes oldelem from unsorted set.
483 if found, overwrites newlelem with lastelem
484 set may be NULL, oldelem must not be NULL;
485 returns:
486 returns oldelem if it was deleted
487 */
qh_setdel(setT * set,void * oldelem)488 void *qh_setdel(setT *set, void *oldelem) {
489 void **elemp, **lastp;
490 int *sizep;
491
492 if (!set)
493 return NULL;
494 elemp= SETaddr_(set, void);
495 while (*elemp != oldelem && *elemp)
496 elemp++;
497 if (*elemp) {
498 sizep= SETsizeaddr_(set);
499 if (!(*sizep)--) /* if was a full set */
500 *sizep= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
501 lastp= SETelemaddr_(set, *sizep-1, void);
502 *elemp= *lastp; /* may overwrite itself */
503 *lastp= NULL;
504 return oldelem;
505 }
506 return NULL;
507 } /* setdel */
508
509
510 /*----------------------------------------
511 -setdellast- return last element of set or NULL
512 delete element from set
513 set may be NULL
514 */
qh_setdellast(setT * set)515 void *qh_setdellast(setT *set) {
516 int setsize;
517 void **last;
518 void *returnvalue;
519
520 if (!set || !(set->e[0]))
521 return NULL;
522 if ((setsize= (long)*(last= &(set->e[set->maxsize])))) {
523 returnvalue= set->e[setsize - 2];
524 set->e[setsize - 2]= NULL;
525 *last= (void *)((long)*last - 1);
526 }else {
527 returnvalue= set->e[set->maxsize - 1];
528 set->e[set->maxsize - 1]= NULL;
529 // This (void *) cast was in the original, 1990s, pre-64-bit Pelican
530 *last= reinterpret_cast<void *>(set->maxsize);
531 }
532 return returnvalue;
533 } /* setdellast */
534
535
536 /*----------------------------------------
537 -setdelnth- deletes nth element from unsorted set
538 errors if nth invalid
539 returns the element
540 */
qh_setdelnth(setT * set,int nth)541 void *qh_setdelnth(setT *set, int nth) {
542 void **elemp, **lastp, *elem;
543 int *sizep;
544
545
546 elemp= SETelemaddr_(set, nth, void);
547 sizep= SETsizeaddr_(set);
548 if (!(*sizep)--) /* if was a full set */
549 *sizep= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
550
551 if (nth < 0 || nth >= *sizep) qhull_fatal(12);
552
553 lastp= SETelemaddr_(set, *sizep-1, void);
554 elem= *elemp;
555 *elemp= *lastp; /* may overwrite itself */
556 *lastp= NULL;
557 return elem;
558 } /* setdelnth */
559
560 /*----------------------------------------
561 -setdelnthsorted- deletes nth element from sorted set
562 sort order is undefined
563 errors if nth invalid
564 see also: setnew_delnthsorted
565 */
qh_setdelnthsorted(setT * set,int nth)566 void *qh_setdelnthsorted(setT *set, int nth) {
567 void **newp, **oldp, *elem;
568 int *sizep;
569
570 sizep= SETsizeaddr_(set);
571
572 if ( nth < 0 ||
573 (*sizep && nth >= *sizep-1) ||
574 nth >= (int)set->maxsize )
575 qhull_fatal(13);
576
577 newp= SETelemaddr_(set, nth, void);
578 elem= *newp;
579 oldp= newp+1;
580 while ((*(newp++)= *(oldp++)))
581 ; /* copy remaining elements and NULL */
582 if (!(*sizep)--) /* if was a full set */
583 *sizep= set->maxsize; /* *sizep= (max size-1)+ 1 */
584 return elem;
585 } /* setdelnthsorted */
586
587
588 /*----------------------------------------
589 -setdelsorted- deletes oldelem from sorted set
590 sort order is undefined
591 set may be NULL
592 returns oldelem if it was deleted
593 */
qh_setdelsorted(setT * set,void * oldelem)594 void *qh_setdelsorted(setT *set, void *oldelem) {
595 void **newp, **oldp;
596 int *sizep;
597
598 if (!set)
599 return NULL;
600 newp= SETaddr_(set, void);
601 while(*newp != oldelem && *newp)
602 newp++;
603 if (*newp) {
604 oldp= newp+1;
605 while ((*(newp++)= *(oldp++)))
606 ; /* copy remaining elements */
607 sizep= SETsizeaddr_(set);
608 if (!(*sizep)--) /* if was a full set */
609 *sizep= set->maxsize; /* *sizep= (max size-1)+ 1 */
610 return oldelem;
611 }
612 return NULL;
613 } /* setdelsorted */
614
615
616 /*----------------------------------------
617 -setequal- returns 1 if two sorted sets are equal, otherwise returns 0
618 either set may be NULL
619 */
qh_setequal(setT * setA,setT * setB)620 int qh_setequal(setT *setA, setT *setB) {
621 void **elemAp, **elemBp;
622 int sizeA, sizeB;
623
624 SETreturnsize_(setA, sizeA);
625 SETreturnsize_(setB, sizeB);
626 if (sizeA != sizeB)
627 return 0;
628 if (!sizeA)
629 return 1;
630 elemAp= SETaddr_(setA, void);
631 elemBp= SETaddr_(setB, void);
632 if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
633 return 1;
634 return 0;
635 } /* setequal */
636
637
638 /*----------------------------------------
639 -setequal_except- returns 1 if two sorted sets are equal except for 2 elements
640 neither set may be NULL
641 false if either skip is missing
642 if second skip is NULL,
643 can skip any one element
644 */
qh_setequal_except(setT * setA,void * skipelemA,setT * setB,void * skipelemB)645 int qh_setequal_except (setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
646 void **elemA, **elemB;
647 int skip=0;
648
649 elemA= SETaddr_(setA, void);
650 elemB= SETaddr_(setB, void);
651 while (1) {
652 if (*elemA == skipelemA) {
653 skip++;
654 elemA++;
655 }
656 if (skipelemB) {
657 if (*elemB == skipelemB) {
658 skip++;
659 elemB++;
660 }
661 }else if (*elemA != *elemB) {
662 skip++;
663 if (!(skipelemB= *elemB++))
664 return 0;
665 }
666 if (!*elemA)
667 break;
668 if (*elemA++ != *elemB++)
669 return 0;
670 }
671 if (skip != 2 || *elemB)
672 return 0;
673 return 1;
674 } /* setequal_except */
675
676
677 /*----------------------------------------
678 -setequal_skip- returns 1 if two sorted sets are equal except for skips
679 neither set may be NULL
680 false if different size
681 */
qh_setequal_skip(setT * setA,int skipA,setT * setB,int skipB)682 int qh_setequal_skip (setT *setA, int skipA, setT *setB, int skipB) {
683 void **elemA, **elemB, **skipAp, **skipBp;
684
685 elemA= SETaddr_(setA, void);
686 elemB= SETaddr_(setB, void);
687 skipAp= SETelemaddr_(setA, skipA, void);
688 skipBp= SETelemaddr_(setB, skipB, void);
689 while (1) {
690 if (elemA == skipAp)
691 elemA++;
692 if (elemB == skipBp)
693 elemB++;
694 if (!*elemA)
695 break;
696 if (*elemA++ != *elemB++)
697 return 0;
698 }
699 if (*elemB)
700 return 0;
701 return 1;
702 } /* setequal_skip */
703
704
705 /*----------------------------------------
706 -setfree- frees the space occupied by a sorted or unsorted set
707 set may be NULL
708 */
qh_setfree(setT ** setp)709 void qh_setfree(setT **setp) {
710 int size;
711 void **freelistp;
712
713 if (*setp) {
714 size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
715 if (size <= qhmem.LASTsize) {
716 qh_memfree_(*setp, size, freelistp);
717 }else
718 qh_memfree (*setp, size);
719 *setp= NULL;
720 }
721 } /* setfree */
722
723
724 /*----------------------------------------
725 -setfreelong- frees a set only if it's in long memory
726 set may be NULL
727 */
qh_setfreelong(setT ** setp)728 void qh_setfreelong(setT **setp) {
729 int size;
730
731 if (*setp) {
732 size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
733 if (size > qhmem.LASTsize) {
734 qh_memfree (*setp, size);
735 *setp= NULL;
736 }
737 }
738 } /* setfreelong */
739
740
741 /*----------------------------------------
742 -setin- returns 1 if setelem is in a set, 0 otherwise
743 set may be NULL or unsorted
744 */
qh_setin(setT * set,void * setelem)745 int qh_setin(setT *set, void *setelem) {
746 void *elem, **elemp;
747
748 FOREACHelem_(set) {
749 if (elem == setelem)
750 return 1;
751 }
752 return 0;
753 } /* setin */
754
755
756 /*----------------------------------------
757 -setindex- returns the index of elem in set. If none, returns -1
758 set may be NULL and may contain nulls.
759 */
qh_setindex(setT * set,void * atelem)760 int qh_setindex(setT *set, void *atelem) {
761 void **elem;
762 int size, i;
763
764 SETreturnsize_(set, size);
765 if (size > (int)set->maxsize)
766 return -1;
767 elem= SETaddr_(set, void);
768 for (i=0; i<size; i++) {
769 if (*elem++ == atelem)
770 return i;
771 }
772 return -1;
773 } /* setindex */
774
775
776 /*----------------------------------------
777 -setlarger- returns a larger set that contains elements of *setp
778 the set is at least twice as large
779 updates qhmem.tempstack if needed
780 */
qh_setlarger(setT ** oldsetp)781 void qh_setlarger(setT **oldsetp) {
782 int size= 1, *sizep;
783 setT *newset, *set, **setp, *oldset;
784 void **oldp, **newp;
785
786 if (*oldsetp) {
787 oldset= *oldsetp;
788 SETreturnsize_(oldset, size);
789 qhmem.cntlarger++;
790 qhmem.totlarger += size+1;
791 newset= qh_setnew(2 * size);
792 oldp= SETaddr_(oldset, void);
793 newp= SETaddr_(newset, void);
794 memcpy((char *)newp, (char *)oldp, (size+1) * SETelemsize);
795 sizep= SETsizeaddr_(newset);
796 *sizep= size+1;
797 FOREACHset_((setT *)qhmem.tempstack) {
798 if (set == oldset)
799 *(setp-1)= newset;
800 }
801 qh_setfree(oldsetp);
802 }else
803 newset= qh_setnew(3);
804 *oldsetp= newset;
805 } /* setlarger */
806
807
808 /*----------------------------------------
809 -setlast- return last element of set or NULL
810 set may be NULL
811 */
qh_setlast(setT * set)812 void *qh_setlast(setT *set) {
813 int size;
814
815 if (set) {
816 size= *SETsizeaddr_(set);
817 if (!size)
818 return SETelem_(set, set->maxsize - 1);
819 else if (size > 1)
820 return SETelem_(set, size - 2);
821 }
822 return NULL;
823 } /* setlast */
824
825
826 /*----------------------------------------
827 -setnew- creates and allocates space for a set
828 setsize means the number of elements (NOT including the NULL terminator)
829 use qh_settemp/qh_setfreetemp if set is temporary
830 */
qh_setnew(int setsize)831 setT *qh_setnew(int setsize) {
832 setT *set;
833 int sizereceived, size;
834 void **freelistp;
835
836 if (!setsize)
837 setsize++;
838 size= sizeof(setT) + setsize * SETelemsize;
839 if ((unsigned) size <= (unsigned) qhmem.LASTsize) {
840 qh_memalloc_(size, freelistp, set);
841 sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
842 if (sizereceived > size)
843 setsize += (sizereceived - size)/SETelemsize;
844 }else
845 set= (setT *)qh_memalloc ((int)size);
846 set->maxsize= setsize;
847 set->e[setsize]= (void *) 1;
848 set->e[0]= NULL;
849 return (set);
850 } /* setnew */
851
852
853 /*----------------------------------------
854 -setnew_delnthsorted- creates a sorted set not containing nth element
855 the new set may have prepended undefined entries
856 set must be defined
857 checks nth
858 see also: setdelnthsorted
859 */
qh_setnew_delnthsorted(setT * set,int size,int nth,int prepend)860 setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
861 setT *newset;
862 void **oldp, **newp;
863 int tailsize= size - nth -1, newsize;
864
865 if (tailsize < 0) qhull_fatal(14);
866
867 newsize= size-1 + prepend;
868 newset= qh_setnew(newsize);
869 // This (void *) cast was in the original, 1990s, pre-64-bit Pelican
870 newset->e[newset->maxsize]= reinterpret_cast<void *>(newsize+1); /* may be overwritten */
871 oldp= SETaddr_(set, void);
872 newp= SETaddr_(newset, void) + prepend;
873 switch (nth) {
874 case 0:
875 break;
876 case 1:
877 *(newp++)= *oldp++;
878 break;
879 case 2:
880 *(newp++)= *oldp++;
881 *(newp++)= *oldp++;
882 break;
883 case 3:
884 *(newp++)= *oldp++;
885 *(newp++)= *oldp++;
886 *(newp++)= *oldp++;
887 break;
888 case 4:
889 *(newp++)= *oldp++;
890 *(newp++)= *oldp++;
891 *(newp++)= *oldp++;
892 *(newp++)= *oldp++;
893 break;
894 default:
895 memcpy((char *)newp, (char *)oldp, nth * SETelemsize);
896 newp += nth;
897 oldp += nth;
898 break;
899 }
900 oldp++;
901 switch (tailsize) {
902 case 0:
903 break;
904 case 1:
905 *(newp++)= *oldp++;
906 break;
907 case 2:
908 *(newp++)= *oldp++;
909 *(newp++)= *oldp++;
910 break;
911 case 3:
912 *(newp++)= *oldp++;
913 *(newp++)= *oldp++;
914 *(newp++)= *oldp++;
915 break;
916 case 4:
917 *(newp++)= *oldp++;
918 *(newp++)= *oldp++;
919 *(newp++)= *oldp++;
920 *(newp++)= *oldp++;
921 break;
922 default:
923 memcpy((char *)newp, (char *)oldp, tailsize * SETelemsize);
924 newp += tailsize;
925 }
926 *newp= NULL;
927 return(newset);
928 } /* setnew_delnthsorted */
929
930
931 /*----------------------------------------
932 -setprint- print set elements to fp
933 notes:
934 never errors
935 */
qh_setprint(FILE * fp,const char * string,setT * set)936 void qh_setprint(FILE *fp, const char *string, setT *set) {
937 int size, k;
938
939 if (!set)
940 fprintf (fp, "%s set is null\n", string);
941 else {
942 SETreturnsize_(set, size);
943 //fprintf (fp, "%s set=%x maxsize=%d size=%d elems=",
944 // string, (unsigned int) set, set->maxsize, size);
945 fprintf (fp, "%s set=%p maxsize=%d size=%d elems=",
946 string, static_cast<void *>(set), set->maxsize, size);
947 if (size > (int)set->maxsize)
948 size= set->maxsize+1;
949 for (k=0; k<size; k++)
950 fprintf(fp, " %p", set->e[k]);
951 fprintf(fp, "\n");
952 }
953 } /* setprint */
954
955 /*----------------------------------------
956 -setreplace- replaces oldelem in set with newelem
957 errors if oldelem not in the set
958 if newelem is NULL then FOREACH no longer works
959 */
qh_setreplace(setT * set,void * oldelem,void * newelem)960 void qh_setreplace(setT *set, void *oldelem, void *newelem) {
961 void **elemp;
962
963 elemp= SETaddr_(set, void);
964 while(*elemp != oldelem && *elemp)
965 elemp++;
966 if (*elemp)
967 *elemp= newelem;
968
969 else qhull_fatal(15);
970
971 } /* setreplace */
972
973
974 /*----------------------------------------
975 -setsize- returns the size of a set
976 same as SETreturnsize_(set)
977 */
qh_setsize(setT * set)978 int qh_setsize(setT *set) {
979 int size, *sizep;
980
981 if (!set)
982 return (0);
983 sizep= SETsizeaddr_(set);
984 if ((size= *sizep)) {
985 size--;
986
987 if (size > (int)set->maxsize) qhull_fatal(16);
988
989 }else
990 size= set->maxsize;
991 return size;
992 } /* setsize */
993
994 /*----------------------------------------
995 -settemp- return a stacked, temporary set
996 use settempfree or settempfree_all to release from qhmem.tempstack
997 see also qh_setnew
998 */
qh_settemp(int setsize)999 setT *qh_settemp(int setsize) {
1000 setT *newset;
1001
1002 newset= qh_setnew (setsize);
1003 qh_setappend ((setT **)&qhmem.tempstack, newset);
1004 if (qhmem.IStracing >= 5)
1005 fprintf (qhmem.ferr, "qh_settemp: temp set %p of %d elements, depth %d\n",
1006 static_cast<void *>(newset),
1007 newset->maxsize, qh_setsize ((setT *)qhmem.tempstack));
1008 return newset;
1009 } /* settemp */
1010
1011 /*----------------------------------------
1012 -settempfree- free temporary set at top of qhmem.tempstack
1013 nop if NULL
1014 errors if set not from previous qh_settemp
1015 locate source by T2 and find mis-matching qh_settemp
1016 */
qh_settempfree(setT ** set)1017 void qh_settempfree(setT **set) {
1018 setT *stackedset;
1019
1020 if (!*set)
1021 return;
1022 stackedset= qh_settemppop ();
1023
1024 if (stackedset != *set) qhull_fatal(17);
1025
1026 qh_setfree (set);
1027 } /* settempfree */
1028
1029 /*----------------------------------------
1030 -settempfree_all- free all temporary sets in qhmem.tempstack
1031 */
qh_settempfree_all(void)1032 void qh_settempfree_all(void) {
1033 setT *set, **setp;
1034
1035 FOREACHset_((setT *)qhmem.tempstack)
1036 qh_setfree(&set);
1037 qh_setfree((setT **)&qhmem.tempstack);
1038 } /* settempfree_all */
1039
1040 /*----------------------------------------
1041 -settemppop- pop and return temporary set from qhmem.tempstack (makes it permanent)
1042 */
qh_settemppop(void)1043 setT *qh_settemppop(void) {
1044 setT *stackedset;
1045
1046 stackedset= (setT *)qh_setdellast((setT *)qhmem.tempstack);
1047
1048 if (!stackedset) qhull_fatal(18);
1049
1050 if (qhmem.IStracing >= 5)
1051 fprintf (qhmem.ferr, "qh_settemppop: depth %d temp set %p of %d elements\n",
1052 qh_setsize((setT *)qhmem.tempstack)+1, static_cast<void *>(stackedset),
1053 qh_setsize(stackedset));
1054 return stackedset;
1055 } /* settemppop */
1056
1057 /*----------------------------------------
1058 -settemppush- push temporary set unto qhmem.tempstack (makes it temporary)
1059 duplicates settemp() for tracing
1060 */
qh_settemppush(setT * set)1061 void qh_settemppush(setT *set) {
1062
1063 qh_setappend ((setT**)&qhmem.tempstack, set);
1064 if (qhmem.IStracing >= 5)
1065 fprintf (qhmem.ferr, "qh_settemppush: depth %d temp set %p of %d elements\n",
1066 qh_setsize((setT *)qhmem.tempstack), static_cast<void *>(set), qh_setsize(set));
1067 } /* settemppush */
1068
1069
1070 /*----------------------------------------
1071 -settruncate- truncate set to size elements
1072 set must be defined
1073 */
qh_settruncate(setT * set,int size)1074 void qh_settruncate (setT *set, int size) {
1075
1076 if (size < 0 || size > (int)set->maxsize) qhull_fatal(19);
1077
1078 // This (void *) cast was in the original, 1990s, pre-64-bit Pelican
1079 set->e[set->maxsize]= reinterpret_cast<void *>(size+1); /* maybe overwritten */
1080 set->e[size]= NULL;
1081 } /* setruncate */
1082
1083 /*----------------------------------------
1084 -setunique- add element if it isn't already
1085 returns 1 if it's appended
1086 */
qh_setunique(setT ** set,void * elem)1087 int qh_setunique (setT **set, void *elem) {
1088
1089 if (!qh_setin (*set, elem)) {
1090 qh_setappend (set, elem);
1091 return 1;
1092 }
1093 return 0;
1094 } /* setunique */
1095
1096 /*----------------------------------------
1097 -setzero- zero remainder of set and set its size
1098 set must be defined
1099 */
qh_setzero(setT * set,int index,int size)1100 void qh_setzero (setT *set, int index, int size) {
1101 int count;
1102
1103 if (index < 0 || index >= size || size > (int)set->maxsize) qhull_fatal(20);
1104
1105 // This (void *) cast was in the original, 1990s, pre-64-bit Pelican
1106 (set->e[set->maxsize])= reinterpret_cast<void *>(size+1); /* may be overwritten */
1107 count= size - index + 1; /* +1 for NULL terminator */
1108 memset ((char *)SETelemaddr_(set, index, void), 0, count * sizeof(void *));
1109 } /* setzero */
1110
1111
1112 /*************************************************************************/
1113 /****************** implementation code from geom.c **********************/
1114 /*************************************************************************/
1115
1116
1117 /* geom.c -- geometric routines of qhull
1118
1119 see README and geom.h
1120
1121 copyright (c) 1993-1994 The Geometry Center
1122 */
1123
1124 /*-------------------------------------------------
1125 -backnormal- solve for normal x using back substitution over rows U
1126 solves Ux=b where Ax=b and PA=LU
1127 b= [0,...,0,sign or 0] (-1 if sign, else +1)
1128 last row of A= [0,...,0,1]
1129 assumes numrow == numcol-1
1130 returns:
1131 normal= x
1132 if can't divzero() for later normalization (qh MINdenom_2 and qh MINdenom_1_2),
1133 sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...]
1134 sets nearzero, unless last row (i.e., hyperplane intersects [0,..,1])
1135 notes:
1136 1) Ly=Pb == y=b since P only permutes the 0's of b
1137 see Golub & van Loan 4.4-9 for back substitution
1138 */
qh_backnormal(realT ** rows,int numrow,int numcol,boolT sign,coordT * normal,boolT * nearzero)1139 void qh_backnormal (realT **rows, int numrow, int numcol, boolT sign,
1140 coordT *normal, boolT *nearzero) {
1141 int i, j;
1142 coordT *normalp, *normal_tail, *ai, *ak;
1143 realT diagonal;
1144 boolT waszero;
1145 int zerocol=-1;
1146
1147 normalp= normal + numcol - 1;
1148 *normalp--= (sign ? -1.0 : 1.0);
1149 for(i= numrow; i--; ) {
1150 *normalp= 0.0;
1151 ai= rows[i] + i + 1;
1152 ak= normalp+1;
1153 for(j= i+1; j < numcol; j++)
1154 *normalp -= *ai++ * *ak++;
1155 diagonal= (rows[i])[i];
1156 if (fabs_(diagonal) > qh MINdenom_2)
1157 *(normalp--) /= diagonal;
1158 else {
1159 waszero= False;
1160 *normalp= qh_divzero (*normalp, diagonal, qh MINdenom_1_2, &waszero);
1161 if (waszero) {
1162 zerocol= i;
1163 *(normalp--)= (sign ? -1.0 : 1.0);
1164 for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++)
1165 *normal_tail= 0.0;
1166 }else
1167 normalp--;
1168 }
1169 }
1170 if (zerocol != -1) {
1171 zzinc_(Zback0);
1172 *nearzero= True;
1173 trace4((qh ferr, "qh_backnormal: zero diagonal at column %d.\n", i));
1174 }
1175 } /* backnormal */
1176
1177 /*-------------------------------------------------
1178 -crossproduct- of 2 dim vectors, C= A x B
1179 from Glasner, Graphics Gems I, p. 639
1180 NOTE: only defined for dim==3
1181 */
qh_crossproduct(int dim,realT vecA[3],realT vecB[3],realT vecC[3])1182 void qh_crossproduct (int dim, realT vecA[3], realT vecB[3], realT vecC[3]){
1183
1184 if (dim == 3) {
1185 vecC[0]= det2_(vecA[1], vecA[2],
1186 vecB[1], vecB[2]);
1187 vecC[1]= - det2_(vecA[0], vecA[2],
1188 vecB[0], vecB[2]);
1189 vecC[2]= det2_(vecA[0], vecA[1],
1190 vecB[0], vecB[1]);
1191 }
1192 } /* vcross */
1193
1194 /*-------------------------------------------------
1195 -determinant- compute the determinant of a square matrix
1196 rows= row vectors
1197 uses qh NEARzero to test for degenerate matrices
1198 this does look right, probably no easy way of doing it
1199 returns:
1200 determinant
1201 overwrites rows and the matrix
1202 nearzero set if degenerate
1203 */
qh_determinant(realT ** rows,int dim,boolT * nearzero)1204 realT qh_determinant (realT **rows, int dim, boolT *nearzero) {
1205 realT det=0;
1206 int i;
1207 boolT sign= False;
1208
1209 *nearzero= False;
1210 if (dim < 2) { qhull_fatal(21); }
1211 else if (dim == 2) {
1212 det= det2_(rows[0][0], rows[0][1],
1213 rows[1][0], rows[1][1]);
1214 if (fabs_(det) < qh NEARzero[1]) /* not really correct, what should this be? */
1215 *nearzero= True;
1216 }else if (dim == 3) {
1217 det= det3_(rows[0][0], rows[0][1], rows[0][2],
1218 rows[1][0], rows[1][1], rows[1][2],
1219 rows[2][0], rows[2][1], rows[2][2]);
1220 if (fabs_(det) < qh NEARzero[2]) /* not really correct, what should this be? */
1221 *nearzero= True;
1222 }else {
1223 qh_gausselim(rows, dim, dim, &sign, nearzero); /* if nearzero, diagonal still ok*/
1224 det= 1.0;
1225 for (i= dim; i--; )
1226 det *= (rows[i])[i];
1227 if (sign)
1228 det= -det;
1229 }
1230 return det;
1231 } /* determinant */
1232
1233 /*-------------------------------------------------
1234 -detsimplex- compute determinant of a simplex with point apex and base points
1235 uses qh gm_matrix/qh gm_row (assumes they're big enough)
1236 uses dim coordinates of point and vertex->point
1237 returns:
1238 if dim == 2 or 3
1239 nearzero iff determinant < qh NEARzero[dim-1] (not quite correct)
1240 if dim >= 4
1241 nearzero iff diagonal[k] < qh NEARzero[k]
1242 */
qh_detsimplex(pointT * apex,setT * points,int dim,boolT * nearzero)1243 realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) {
1244 pointT *coorda, *coordp, *gmcoord, *point, **pointp;
1245 coordT **rows;
1246 int k, i=0;
1247 realT det= 0.0;
1248
1249 zinc_(Zdetsimplex);
1250 gmcoord= qh gm_matrix;
1251 rows= qh gm_row;
1252 FOREACHpoint_(points) {
1253 if (i == dim)
1254 break;
1255 rows[i++]= gmcoord;
1256 coordp= point;
1257 coorda= apex;
1258 for(k= dim; k--; )
1259 *(gmcoord++)= *coordp++ - *coorda++;
1260 }
1261 if (i < dim) { qhull_fatal(22); }
1262 det= qh_determinant (rows, dim, nearzero);
1263 trace2((qh ferr, "qh_detsimplex: det=%2.2g for point p%d, dimension %d, nearzero? %d\n",
1264 det, qh_pointid(apex), dim, *nearzero));
1265 return det;
1266 } /* detsimplex */
1267
1268 /*-------------------------------------------
1269 -distplane- get distance from point to facet
1270 returns:
1271 positive if point is above facet (i.e., outside)
1272 can not qhull_fatal (for sortfacets)
1273 */
qh_distplane(pointT * point,facetT * facet,realT * dist)1274 void qh_distplane (pointT *point, facetT *facet, realT *dist) {
1275 coordT *normal= facet->normal, *coordp, randr;
1276 int k;
1277
1278 switch(qh hull_dim){
1279 case 2:
1280 *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1];
1281 break;
1282 case 3:
1283 *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2];
1284 break;
1285 case 4:
1286 *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3];
1287 break;
1288 case 5:
1289 *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4];
1290 break;
1291 case 6:
1292 *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5];
1293 break;
1294 case 7:
1295 *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6];
1296 break;
1297 case 8:
1298 *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7];
1299 break;
1300 default:
1301 *dist= facet->offset;
1302 coordp= point;
1303 for (k= qh hull_dim; k--; )
1304 *dist += *coordp++ * *normal++;
1305 break;
1306 }
1307 zinc_(Zdistplane);
1308 if (!qh RANDOMdist && qh IStracing < 4)
1309 return;
1310 if (qh RANDOMdist) {
1311 randr= qh_RANDOMint;
1312 *dist += (2.0 * randr / qh_RANDOMmax - 1.0) *
1313 qh RANDOMfactor * qh maxmaxcoord;
1314 }
1315 /*
1316 if (qh IStracing >= 4) {
1317 fprintf (qh ferr, "qh_distplane: ");
1318 fprintf (qh ferr, qh_REAL_1, *dist);
1319 fprintf (qh ferr, "from p%d to f%d\n", qh_pointid(point), facet->id);
1320 }
1321 */
1322 return;
1323 } /* distplane */
1324
1325
1326 /*--------------------------------------------------
1327 -divzero -- divide by a number that's nearly zero
1328 mindenom1= minimum denominator for dividing into 1.0
1329 returns:
1330 zerodiv and 0.0 if it would overflow
1331 */
qh_divzero(realT numer,realT denom,realT mindenom1,boolT * zerodiv)1332 realT qh_divzero (realT numer, realT denom, realT mindenom1, boolT *zerodiv) {
1333 realT temp, numerx, denomx;
1334
1335
1336 if (numer < mindenom1 && numer > -mindenom1) {
1337 numerx= fabs_(numer);
1338 denomx= fabs_(denom);
1339 if (numerx < denomx) {
1340 *zerodiv= False;
1341 return numer/denom;
1342 }else {
1343 *zerodiv= True;
1344 return 0.0;
1345 }
1346 }
1347 temp= denom/numer;
1348 if (temp > mindenom1 || temp < -mindenom1) {
1349 *zerodiv= False;
1350 return numer/denom;
1351 }else {
1352 *zerodiv= True;
1353 return 0.0;
1354 }
1355 } /* divzero */
1356
1357
1358 /*-------------------------------------------------
1359 -facetcenter- return Voronoi center for a facet's vertices
1360 */
qh_facetcenter(setT * vertices)1361 pointT *qh_facetcenter (setT *vertices) {
1362 setT *points= qh_settemp (qh_setsize (vertices));
1363 vertexT *vertex, **vertexp;
1364 pointT *center;
1365
1366 FOREACHvertex_(vertices)
1367 qh_setappend (&points, vertex->point);
1368 center= qh_voronoi_center (qh hull_dim-1, points);
1369 qh_settempfree (&points);
1370 return center;
1371 } /* facetcenter */
1372
1373 /*-------------------------------------------------
1374 -findbest- find best facet for point starting at a facet (not flipped!)
1375 if bestoutside, searches all facets else stops at first outside
1376 MINoutside is DISTround in precise case
1377 if firstid, searches facets with ids >= firstid
1378 searches old facets if bestoutside || (not outside and imprecise)
1379 searches all neighbors of coplanar and flipped facets
1380 searchdist is arbitrarily set to min_vertex+max_outside+DISTround
1381 max_outside is needed for setting facet->maxoutside
1382 returns:
1383 if !firstid, updates facet->maxoutside for good, visited facets
1384 distance to facet
1385 isoutside true if point is outside of facet
1386 bumps visit_id and seen flags
1387 notes:
1388 uses visitid and seen
1389 statistics collected here for partitions, caller does outside/coplanar
1390 caller traces the results
1391 #2 after setfacetplane in D3, optimized for outside points and !bestoutside
1392 #1 when merging in D3
1393 see also partitionall()
1394 notes on searchdist:
1395 searchdist needed since vertex neighbors can be geometric neighbors of facet
1396 if searchdist=DISTround, gets stuck for rbox 50 W1e-3 D7 | qhull A-0.99 W0.2
1397 if !BESToutside and merging, gets stuck for rbox 1000 W8e-6 | qhull C-0
1398 because nearly coplanar widens when the point is outside of the facets
1399 searching all new facets does not prevent !BESToutside getting stuck
1400 check_maxoutside can also get stuck, should keep coplanars
1401 */
qh_findbest(pointT * point,facetT * facet,boolT bestoutside,unsigned firstid,realT * dist,boolT * isoutside,int * numpart)1402 facetT *qh_findbest (pointT *point, facetT *facet, boolT bestoutside,
1403 unsigned firstid, realT *dist, boolT *isoutside, int *numpart) {
1404 realT bestdist, searchdist;
1405 facetT *neighbor, **neighborp, *bestfacet;
1406 setT *search= NULL;
1407 int oldtrace= qh IStracing;
1408 boolT checkmax= (boolT)(bestoutside && !firstid && qh_MAXoutside
1409 && (qh MERGING || qh APPROXhull));
1410
1411 if (qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid (point)) {
1412 qh IStracing= qh TRACElevel;
1413 /*
1414 fprintf (qh ferr, "qh_findbest: point p%d starting at f%d bestoutside? %d firstid %d\n",
1415 qh TRACEpoint, facet->id, bestoutside, firstid);
1416 fprintf (qh ferr, " Last point added to hull was p%d.", qh furthest_id);
1417 fprintf(qh ferr, " Last merge was #%d.\n", zzval_(Ztotmerge));
1418 */
1419 }
1420 searchdist= - qh min_vertex + qh max_outside + 2* qh DISTround;
1421 *isoutside= True;
1422 *numpart= 1;
1423 qh_distplane (point, facet, dist);
1424 bestdist= *dist;
1425 bestfacet= facet;
1426 if (!bestoutside && *dist >= qh MINoutside)
1427 goto LABELreturn_best;
1428 #if qh_MAXoutside
1429 if (checkmax && (!qh ONLYgood || facet->good) && *dist > facet->maxoutside)
1430 facet->maxoutside= *dist;
1431 #endif
1432 facet->visitid= ++qh visit_id;
1433 facet->seen= False;
1434 if (True) { /* directed search for bestfacet */
1435 LABELrepeat: /* facet->seen if clearly worse */
1436 trace4((qh ferr, "qh_findbest: neighbors of f%d\n", facet->id));
1437 FOREACHneighbor_(facet) {
1438 if ((int)neighbor->visitid == qh visit_id)
1439 continue;
1440 if (neighbor->id < firstid) {
1441 neighbor->seen= True;
1442 continue;
1443 }
1444 neighbor->visitid= qh visit_id;
1445 neighbor->seen= False;
1446 if (neighbor->flipped)
1447 continue;
1448 (*numpart)++;
1449 qh_distplane (point, neighbor, dist);
1450 if (!bestoutside && *dist >= qh MINoutside) {
1451 bestfacet= neighbor;
1452 goto LABELreturn_best;
1453 }
1454 #if qh_MAXoutside
1455 if (checkmax && (!qh ONLYgood || neighbor->good)
1456 && *dist > neighbor->maxoutside)
1457 neighbor->maxoutside= *dist;
1458 #endif
1459 if (*dist >= bestdist) { /* >= for exact coplanar */
1460 bestdist= *dist;
1461 bestfacet= neighbor;
1462 if (*dist > bestdist + searchdist)
1463 facet->seen= True;
1464 facet= neighbor;
1465 goto LABELrepeat;
1466 }else if (*dist < bestdist - searchdist)
1467 neighbor->seen= True;
1468 }
1469 }
1470 do { /* search horizon of facet */
1471 FOREACHneighbor_(facet) {
1472 if ((int)neighbor->visitid == qh visit_id) {
1473 if (!neighbor->seen) {
1474 neighbor->seen= True;
1475 if (!search)
1476 search= qh_settemp (qh TEMPsize);
1477 qh_setappend (&search, neighbor);
1478 }
1479 continue;
1480 }
1481 neighbor->visitid= qh visit_id;
1482 neighbor->seen= True;
1483 if (neighbor->flipped) {
1484 if (!search)
1485 search= qh_settemp (qh TEMPsize);
1486 qh_setappend (&search, neighbor);
1487 continue;
1488 }
1489 if (neighbor->id < firstid) {
1490 if (!(bestoutside+qh APPROXhull+qh PREmerge))
1491 continue;
1492 }else
1493 zinc_(Zpartneighbor);
1494 (*numpart)++;
1495 qh_distplane (point, neighbor, dist);
1496 if (!bestoutside && *dist >= qh MINoutside) {
1497 bestfacet= neighbor;
1498 goto LABELreturn_best;
1499 }
1500 #if qh_MAXoutside
1501 if (checkmax && *dist > neighbor->maxoutside)
1502 neighbor->maxoutside= *dist;
1503 #endif
1504 if (*dist >= bestdist - searchdist) {
1505 if (!search)
1506 search= qh_settemp (qh TEMPsize);
1507 qh_setappend (&search, neighbor);
1508 if (*dist > bestdist) {
1509 bestdist= *dist;
1510 bestfacet= neighbor;
1511 }
1512 }
1513 }
1514 }while ((facet= (facetT *)qh_setdellast (search)));
1515 *dist= bestdist;
1516 if (!bestoutside || bestdist < qh MINoutside)
1517 *isoutside= False;
1518 LABELreturn_best:
1519 if (search)
1520 qh_settempfree (&search);
1521 qh IStracing= oldtrace;
1522 return bestfacet;
1523 } /* findbest */
1524
1525
1526 /*-------------------------------------------------
1527 -findgooddist- find best good facet visible for point from facetA
1528 assumes facetA is visible from point
1529 uses qh visit_id and qh visible_list (but doesn't set visible)
1530 returns:
1531 furthest distance to good facet, if any
1532 bumps visit_id and seen flags
1533 */
qh_findgooddist(pointT * point,facetT * facetA,realT * distp)1534 facetT *qh_findgooddist (pointT *point, facetT *facetA, realT *distp) {
1535 realT bestdist= -REALmax, dist;
1536 facetT *neighbor, **neighborp, *bestfacet=NULL, *facet;
1537 boolT goodseen= False;
1538
1539 if (facetA->good) {
1540 zinc_(Zverifypart);
1541 qh_distplane (point, facetA, &bestdist);
1542 bestfacet= facetA;
1543 goodseen= True;
1544 }
1545 qh_removefacet (facetA);
1546 qh_appendfacet (facetA);
1547 qh visible_list= facetA;
1548 facetA->visitid= ++qh visit_id;
1549 FORALLfacet_(qh visible_list) {
1550 FOREACHneighbor_(facet) {
1551 if ((int)neighbor->visitid == qh visit_id)
1552 continue;
1553 neighbor->visitid= qh visit_id;
1554 if (goodseen && !neighbor->good)
1555 continue;
1556 zinc_(Zverifypart);
1557 qh_distplane (point, neighbor, &dist);
1558 if (dist > 0) {
1559 qh_removefacet (neighbor);
1560 qh_appendfacet (neighbor);
1561 if (neighbor->good) {
1562 goodseen= True;
1563 if (dist > bestdist) {
1564 bestdist= dist;
1565 bestfacet= neighbor;
1566 }
1567 }
1568 }
1569 }
1570 }
1571 if (bestfacet) {
1572 *distp= bestdist;
1573 trace2((qh ferr, "qh_findgooddist: p%d is %2.2g above good facet f%d\n",
1574 qh_pointid(point), bestdist, bestfacet->id));
1575 return bestfacet;
1576 }
1577 trace4((qh ferr, "qh_findgooddist: no good facet for p%d above f%d\n",
1578 qh_pointid(point), facetA->id));
1579 return NULL;
1580 } /* findgooddist */
1581
1582 /*-------------------------------------------------
1583 -gausselim- Gaussian elimination with partial pivoting
1584 coordT data in rows
1585 assumes numrow <= numcol
1586 returns:
1587 rows is upper triangular (includes row exchanges)
1588 flips sign for each row exchange
1589 sets nearzero if pivot[k] < qh NEARzero[k], else False.
1590 if nearzero, the determinant's sign may be incorrect.
1591 */
qh_gausselim(realT ** rows,int numrow,int numcol,boolT * sign,boolT * nearzero)1592 void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) {
1593 realT *ai, *ak, *rowp, *pivotrow;
1594 realT n, pivot, pivot_abs= 0.0, temp;
1595 int i, j, k, pivoti, flip=0, tempint;
1596
1597 *nearzero= False;
1598 for(k= 0; k < numrow; k++) {
1599 pivot_abs= fabs_((rows[k])[k]);
1600 pivoti= k;
1601 for(i= k+1; i < numrow; i++) {
1602 if ((temp= fabs_((rows[i])[k])) > pivot_abs) {
1603 pivot_abs= temp;
1604 pivoti= i;
1605 }
1606 }
1607 if (pivoti != k) {
1608 rowp= rows[pivoti];
1609 rows[pivoti]= rows[k];
1610 rows[k]= rowp;
1611 tempint = (int)*sign;
1612 tempint ^= 1;
1613 *sign = (boolT)tempint;
1614 flip ^= 1;
1615 }
1616 if (pivot_abs <= qh NEARzero[k]) {
1617 *nearzero= True;
1618 if (pivot_abs == 0.0) { /* remainder of column == 0 */
1619
1620 /*
1621 if (qh IStracing >= 4) {
1622 fprintf (qh ferr, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh DISTround);
1623 qh_printmatrix (qh ferr, "Matrix:", rows, numrow, numcol);
1624 }
1625 */
1626
1627 zzinc_(Zgauss0);
1628 goto LABELnextcol;
1629 }
1630 }
1631 pivotrow= rows[k] + k;
1632 pivot= *pivotrow++; /* signed value of pivot, and remainder of row */
1633 for(i= k+1; i < numrow; i++) {
1634 ai= rows[i] + k;
1635 ak= pivotrow;
1636 n= (*ai++)/pivot; /* divzero() not needed since |pivot| >= |*ai| */
1637 for(j= numcol - (k+1); j--; )
1638 *ai++ -= n * *ak++;
1639 }
1640 LABELnextcol:
1641 ;
1642 }
1643 wmin_(Wmindenom, pivot_abs); /* last pivot element */
1644 if (qh IStracing >= 5)
1645 qh_printmatrix (qh ferr, "qh_gausselem: result", rows, numrow, numcol);
1646 } /* gausselim */
1647
1648
1649 /*----------------------------------------------
1650 -getangle- returns the dot product of two, qh hull_dim vectors
1651 may be > 1.0 or < -1.0
1652 */
qh_getangle(pointT * vect1,pointT * vect2)1653 realT qh_getangle(pointT *vect1, pointT *vect2) {
1654 realT angle= 0;
1655 int k;
1656
1657 for(k= qh hull_dim; k--; )
1658 angle += *vect1++ * *vect2++;
1659 trace4((qh ferr, "qh_getangle: %2.2g\n", angle));
1660 return(angle);
1661 } /* getangle */
1662
1663
1664 /*----------------------------------------------
1665 -getcenter- gets arithmetic center of a set of vertices as a new point
1666 assumes normal_size is in short memory
1667 */
qh_getcenter(setT * vertices)1668 pointT *qh_getcenter(setT *vertices) {
1669 int k;
1670 pointT *center, *coord;
1671 vertexT *vertex, **vertexp;
1672 int count= qh_setsize(vertices);
1673
1674 if (count < 2) qhull_fatal(23);
1675
1676 center= (pointT *)qh_memalloc(qh normal_size);
1677 for (k=0; k < qh hull_dim; k++) {
1678 coord= center+k;
1679 *coord= 0.0;
1680 FOREACHvertex_(vertices)
1681 *coord += vertex->point[k];
1682 *coord /= count;
1683 }
1684 return(center);
1685 } /* getcenter */
1686
1687
1688 /*----------------------------------------------
1689 -getcentrum- returns the centrum for a facet as a new point
1690 assumes normal_size is in short memory
1691 */
qh_getcentrum(facetT * facet)1692 pointT *qh_getcentrum(facetT *facet) {
1693 realT dist;
1694 pointT *centrum, *point;
1695
1696 point= qh_getcenter(facet->vertices);
1697 zinc_(Zcentrumtests);
1698 qh_distplane (point, facet, &dist);
1699 centrum= qh_projectpoint(point, facet, dist);
1700 qh_memfree(point, qh normal_size);
1701 trace4((qh ferr, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n",
1702 facet->id, qh_setsize(facet->vertices), dist));
1703 return centrum;
1704 } /* getcentrum */
1705
1706
1707 /*-------------------------------------------------
1708 -gram_schmidt- implements Gram-Schmidt orthogonalization by rows
1709 overwrites rows[dim][dim]
1710 returns:
1711 false if gets a zero norm
1712 notes:
1713 see Golub & van Loan Algorithm 6.2-2
1714 overflow due to small divisors not handled
1715 */
qh_gram_schmidt(int dim,realT ** row)1716 boolT qh_gram_schmidt(int dim, realT **row) {
1717 realT *rowi, *rowj, norm;
1718 int i, j, k;
1719
1720 for(i=0; i < dim; i++) {
1721 rowi= row[i];
1722 for (norm= 0.0, k= dim; k--; rowi++)
1723 norm += *rowi * *rowi;
1724 norm= sqrt(norm);
1725 wmin_(Wmindenom, norm);
1726 if (norm == 0.0) /* either 0 or overflow due to sqrt */
1727 return False;
1728 for(k= dim; k--; )
1729 *(--rowi) /= norm;
1730 for(j= i+1; j < dim; j++) {
1731 rowj= row[j];
1732 for(norm= 0.0, k=dim; k--; )
1733 norm += *rowi++ * *rowj++;
1734 for(k=dim; k--; )
1735 *(--rowj) -= *(--rowi) * norm;
1736 }
1737 }
1738 return True;
1739 } /* gram_schmidt */
1740
1741
1742
1743
1744 /*--------------------------------------------------
1745 -inthresholds- return True if normal within qh lower_/upper_threshold
1746 returns:
1747 angle cos to a threshold border (may be NULL, invalid if qh SPLITthresholds)
1748 */
qh_inthresholds(coordT * normal,realT * angle)1749 boolT qh_inthresholds (coordT *normal, realT *angle) {
1750 boolT within= True;
1751 int k;
1752
1753 if (angle)
1754 *angle= 0.0;
1755 for(k= 0; k < qh hull_dim; k++) {
1756 if (qh lower_threshold[k] > -REALmax/2) {
1757 if (normal[k] < qh lower_threshold[k])
1758 within= False;
1759 if (angle)
1760 *angle += normal[k] * qh lower_threshold[k];
1761 }
1762 if (qh upper_threshold[k] < REALmax/2) {
1763 if (normal[k] > qh upper_threshold[k])
1764 within= False;
1765 if (angle)
1766 *angle += normal[k] * qh upper_threshold[k];
1767 }
1768 }
1769 return within;
1770 } /* inthresholds */
1771
1772
1773 /*--------------------------------------------------
1774 -maxabsval -- return pointer to maximum absolute value of a dim vector
1775 returns NULL if dim==0
1776 */
qh_maxabsval(realT * normal,int dim)1777 realT *qh_maxabsval (realT *normal, int dim) {
1778 realT maxval= -REALmax;
1779 realT *maxp= NULL, *colp, absval;
1780 int k;
1781
1782 for (k= dim, colp= normal; k--; colp++) {
1783 absval= fabs_(*colp);
1784 if (absval > maxval) {
1785 maxval= absval;
1786 maxp= colp;
1787 }
1788 }
1789 return maxp;
1790 } /* maxabsval */
1791
1792
1793 /*-------------------------------------------------
1794 -maxmin- collects the maximum and minimum points of input into a set
1795 determines maximum roundoff errors
1796 returns:
1797 returns a temporary set, without qh GOODpoint
1798 points are not unique
1799 */
qh_maxmin(pointT * points,int numpoints,int dimension)1800 setT *qh_maxmin(pointT *points, int numpoints, int dimension) {
1801 int k;
1802 realT maxsum= 0.0, maxcoord, temp, maxdistsum;
1803 realT maxneg= REALmax, maxpos= -REALmax;
1804 pointT *minimum, *maximum, *point, *pointtemp;
1805 setT *set;
1806
1807 set= qh_settemp(2*dimension);
1808 for(k= 0; k < dimension; k++) {
1809 if (points == qh GOODpointp)
1810 minimum= maximum= points + qh hull_dim;
1811 else
1812 minimum= maximum= points;
1813 FORALLpoint_(points, numpoints) {
1814 if (point == qh GOODpointp)
1815 continue;
1816 if (maximum[k] < point[k])
1817 maximum= point;
1818 else if (minimum[k] > point[k])
1819 minimum= point;
1820 }
1821 maxcoord= fmax_(maximum[k], -minimum[k]);
1822 if (qh GOODpointp) {
1823 temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]);
1824 maximize_(maxcoord, temp);
1825 }
1826 maximize_(qh maxmaxcoord, maxcoord);
1827 maxsum += maxcoord;
1828 maximize_(maxpos, maximum[k]);
1829 minimize_(maxneg, minimum[k]);
1830 qh_setappend (&set, maximum);
1831 qh_setappend (&set, minimum);
1832 /* calculation of qh NEARzero is based on error formula 4.4-13 of
1833 Golub & van Loan, authors say n^3 can be ignored and 10 be used in
1834 place of rho */
1835 qh NEARzero[k]= 80 * maxsum * REALepsilon;
1836 }
1837 /* calculate roundoff error according to
1838 Lemma 3.2-1 of Golub and van Loan "Matrix Computation"
1839 use sqrt(dim) since one vector is normalized */
1840 maxdistsum= sqrt (qh hull_dim) * qh maxmaxcoord;
1841 if (!qh SETroundoff) {
1842 qh DISTround= REALepsilon * (qh hull_dim * maxdistsum * 1.01
1843 + qh maxmaxcoord); /* for offset */
1844 if (qh RANDOMdist)
1845 qh DISTround += qh RANDOMfactor * qh maxmaxcoord;
1846 }
1847 qh MINdenom= qh MINdenom_1 * qh maxmaxcoord;
1848 qh MINdenom_1_2= sqrt (qh MINdenom_1 * qh hull_dim) ; /* if will be normalized */
1849 qh MINdenom_2= qh MINdenom_1_2 * qh maxmaxcoord;
1850 if (qh premerge_cos < REALmax/2) /* for inner product */
1851 qh premerge_cos -= 1.01 * qh hull_dim * REALepsilon;
1852 if (qh postmerge_cos < REALmax/2)
1853 qh postmerge_cos -= 1.01 * qh hull_dim * REALepsilon;
1854 qh premerge_centrum += 2 * qh DISTround; /*2 for centrum and distplane()*/
1855 qh postmerge_centrum += 2 * qh DISTround;
1856 { /* compute ONEmerge, max vertex offset for merging simplicial facets */
1857 realT maxangle= 1.0, maxrho;
1858
1859 minimize_(maxangle, qh premerge_cos);
1860 minimize_(maxangle, qh postmerge_cos);
1861 /* max diameter * sin theta + DISTround for vertex to its hyperplane */
1862 qh ONEmerge= sqrt (qh hull_dim) * (maxpos - maxneg) *
1863 sqrt (1.0 - maxangle * maxangle) + qh DISTround;
1864 maxrho= qh hull_dim * qh premerge_centrum + qh DISTround;
1865 maximize_(qh ONEmerge, maxrho);
1866 maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround;
1867 maximize_(qh ONEmerge, maxrho);
1868 }
1869 if (!qh APPROXhull) { /* user may specify qh MINoutside */
1870 qh MINoutside= qh premerge_centrum - qh DISTround;
1871 if (qh premerge_cos < REALmax/2)
1872 maximize_(qh MINoutside, (1- qh premerge_cos) * qh maxmaxcoord);
1873 }
1874 if (qh MINvisible > REALmax/2)
1875 qh MINvisible= qh DISTround;
1876
1877 /*
1878 if (qh MINvisible > qh MINoutside + 3*REALepsilon && !qh BESToutside &&
1879 !qh FORCEoutput)
1880 fprintf (qh ferr, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g. Flipped facets are likely.\n",
1881 qh MINvisible, qh MINoutside);
1882 */
1883
1884 qh max_vertex= qh DISTround;
1885 qh min_vertex= -qh DISTround;
1886
1887 /*
1888 if (qh IStracing >=1)
1889 qh_printpoints (qh ferr, "qh_maxmin: found the max and min points (by dim):", set);
1890 */
1891
1892 /* numeric constants reported in printsummary */
1893 return(set);
1894 } /* maxmin */
1895
1896
1897 /*-------------------------------------------------
1898 -maxsimplex- determines maximum simplex for a set of points
1899 assumes at least pointsneeded points in points
1900 skips qh GOODpointp (assumes that it isn't in maxpoints)
1901 starts from points already in simplex
1902 returns:
1903 temporary set of dim+1 points
1904 notes:
1905 maximizes determinate for x,y,z,w, etc.
1906 uses maxpoints as long as determinate is clearly non-zero
1907 */
qh_maxsimplex(int dim,setT * maxpoints,pointT * points,int numpoints,setT ** simplex)1908 void qh_maxsimplex (int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) {
1909 pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL;
1910 boolT nearzero, maxnearzero= False;
1911 int k, sizinit;
1912 realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax;
1913
1914 sizinit= qh_setsize (*simplex);
1915 if (sizinit < 2) {
1916 if (qh_setsize (maxpoints) >= 2) {
1917 FOREACHpoint_(maxpoints) {
1918
1919 if (maxcoord < point[0]) {
1920 maxcoord= point[0];
1921 maxx= point;
1922 }
1923 if (mincoord > point[0]) {
1924 mincoord= point[0];
1925 minx= point;
1926 }
1927 }
1928 }else {
1929 FORALLpoint_(points, numpoints) {
1930 if (point == qh GOODpointp)
1931 continue;
1932 if (maxcoord < point[0]) {
1933 maxcoord= point[0];
1934 maxx= point;
1935 }
1936 if (mincoord > point[0]) {
1937 mincoord= point[0];
1938 minx= point;
1939 }
1940 }
1941 }
1942 qh_setunique (simplex, minx);
1943 if (qh_setsize (*simplex) < 2)
1944 qh_setunique (simplex, maxx);
1945 sizinit= qh_setsize (*simplex);
1946
1947 if (sizinit < 2) qhull_fatal(24);
1948 }
1949 for(k= sizinit; k < dim+1; k++) {
1950 maxpoint= NULL;
1951 maxdet= -REALmax;
1952 FOREACHpoint_(maxpoints) {
1953 if (!qh_setin (*simplex, point)) {
1954 det= qh_detsimplex(point, *simplex, k, &nearzero);
1955 if ((det= fabs_(det)) > maxdet) {
1956 maxdet= det;
1957 maxpoint= point;
1958 maxnearzero= nearzero;
1959 }
1960 }
1961 }
1962 if (!maxpoint || maxnearzero) {
1963 zinc_(Zsearchpoints);
1964 if (!maxpoint) {
1965 trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex\n", k));
1966 }else {
1967 trace0((qh ferr, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n",
1968 k+1, qh_pointid(maxpoint), maxdet));
1969 }
1970 FORALLpoint_(points, numpoints) {
1971 if (point == qh GOODpointp)
1972 continue;
1973 if (!qh_setin (*simplex, point)) {
1974 det= qh_detsimplex(point, *simplex, k, &nearzero);
1975 if ((det= fabs_(det)) > maxdet) {
1976 maxdet= det;
1977 maxpoint= point;
1978 maxnearzero= nearzero;
1979 }
1980 }
1981 }
1982 } /* !maxpoint */
1983 if (!maxpoint) qhull_fatal(25);
1984
1985 qh_setappend(simplex, maxpoint);
1986 trace1((qh ferr, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n",
1987 qh_pointid(maxpoint), k, maxdet));
1988 }
1989 } /* maxsimplex */
1990
1991 /*--------------------------------------------------
1992 -minabsval -- return min absolute value of a dim vector
1993 */
qh_minabsval(realT * normal,int dim)1994 realT qh_minabsval (realT *normal, int dim) {
1995 realT minval= 0;
1996 realT maxval= 0;
1997 realT *colp;
1998 int k;
1999
2000 for (k= dim, colp= normal; k--; colp++) {
2001 maximize_(maxval, *colp);
2002 minimize_(minval, *colp);
2003 }
2004 return fmax_(maxval, -minval);
2005 } /* maxabsval */
2006
2007
2008
2009 /*--------------------------------------------------
2010 -normalize -- normalize a vector
2011 qh MINdenom/MINdenom1 upper limits for divide overflow
2012 returns:
2013 normalized vector
2014 flips sign if !toporient
2015 if zero norm
2016 sets all elements to sqrt(1.0/dim)
2017 if divide by zero (divzero ())
2018 sets largest element to +/-1
2019 bumps Znearlysingular
2020 */
qh_normalize(coordT * normal,int dim,boolT toporient)2021 void qh_normalize (coordT *normal, int dim, boolT toporient) {
2022 int k;
2023 realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3;
2024 boolT zerodiv;
2025
2026 norm1= normal+1;
2027 norm2= normal+2;
2028 norm3= normal+3;
2029 if (dim == 2)
2030 norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1));
2031 else if (dim == 3)
2032 norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2));
2033 else if (dim == 4) {
2034 norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
2035 + (*norm3)*(*norm3));
2036 }else if (dim > 4) {
2037 norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)
2038 + (*norm3)*(*norm3);
2039 for (k= dim-4, colp= normal+4; k--; colp++)
2040 norm += (*colp) * (*colp);
2041 norm= sqrt(norm);
2042 }
2043 wmin_(Wmindenom, norm);
2044 if (norm > qh MINdenom) {
2045 if (!toporient)
2046 norm= -norm;
2047 *normal /= norm;
2048 *norm1 /= norm;
2049 if (dim == 2)
2050 ; /* all done */
2051 else if (dim == 3)
2052 *norm2 /= norm;
2053 else if (dim == 4) {
2054 *norm2 /= norm;
2055 *norm3 /= norm;
2056 }else if (dim >4) {
2057 *norm2 /= norm;
2058 *norm3 /= norm;
2059 for (k= dim-4, colp= normal+4; k--; )
2060 *colp++ /= norm;
2061 }
2062 }else if (norm == 0.0) {
2063 temp= sqrt (1.0/dim);
2064 for (k= dim, colp= normal; k--; )
2065 *colp++ = temp;
2066 }else {
2067 if (!toporient)
2068 norm= -norm;
2069 for (k= dim, colp= normal; k--; colp++) { /* k used below */
2070 temp= qh_divzero (*colp, norm, qh MINdenom_1, &zerodiv);
2071 if (!zerodiv)
2072 *colp= temp;
2073 else {
2074 maxp= qh_maxabsval(normal, dim);
2075 temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0);
2076 for (k= dim, colp= normal; k--; colp++)
2077 *colp= 0.0;
2078 *maxp= temp;
2079 zzinc_(Znearlysingular);
2080 trace0((qh ferr, "qh_normalize: norm=%2.2g too small\n", norm));
2081 return;
2082 }
2083 }
2084 }
2085 } /* normalize */
2086
2087
2088 /*-------------------------------------------
2089 -orientoutside- make facet outside oriented via qh interior_point
2090 returns True if reversed orientation.
2091 */
qh_orientoutside(facetT * facet)2092 boolT qh_orientoutside (facetT *facet) {
2093 int k;
2094 realT dist;
2095
2096 qh_distplane (qh interior_point, facet, &dist);
2097 if (dist > 0) {
2098 for (k= qh hull_dim; k--; )
2099 facet->normal[k]= -facet->normal[k];
2100 facet->offset= -facet->offset;
2101 return True;
2102 }
2103 return False;
2104 } /* orientoutside */
2105
2106 /*-------------------------------------------
2107 -pointdist- distance between points
2108 */
qh_pointdist(pointT * point1,pointT * point2,int dim)2109 coordT qh_pointdist(pointT *point1, pointT *point2, int dim) {
2110 coordT dist, diff;
2111 int k;
2112
2113 dist= 0.0;
2114 for (k= dim; k--; ) {
2115 diff= *point1++ - *point2++;
2116 dist += diff * diff;
2117 }
2118 return(sqrt(dist));
2119 } /* pointdist */
2120
2121
2122 /*-------------------------------------------------
2123 -printmatrix- print matrix given by row vectors
2124 print a vector by (fp, "", &vect, 1, len)
2125 */
qh_printmatrix(FILE * fp,const char * string,realT ** rows,int numrow,int numcol)2126 void qh_printmatrix (FILE *fp, const char *string, realT **rows, int numrow, int numcol) {
2127 realT *rowp;
2128 int i,k;
2129
2130 fprintf (fp, "%s\n", string);
2131 for (i= 0; i<numrow; i++) {
2132 rowp= rows[i];
2133 for (k= 0; k<numcol; k++)
2134 fprintf (fp, "%6.3g ", *rowp++);
2135 fprintf (fp, "\n");
2136 }
2137 } /* printmatrix */
2138
2139
2140 /*-------------------------------------------------
2141 -printpoints- print pointids for a set of points starting at index
2142 prints string and 'p' if defined
2143 */
qh_printpoints(FILE * fp,const char * string,setT * points)2144 void qh_printpoints (FILE *fp, const char *string, setT *points) {
2145 pointT *point, **pointp;
2146
2147 if (string) {
2148 fprintf (fp, "%s", string);
2149 FOREACHpoint_(points)
2150 fprintf (fp, " p%d", qh_pointid(point));
2151 fprintf (fp, "\n");
2152 }else {
2153 FOREACHpoint_(points)
2154 fprintf (fp, " %d", qh_pointid(point));
2155 fprintf (fp, "\n");
2156 }
2157 } /* printpoints */
2158
2159
2160 /*-------------------------------------------------
2161 -projectinput- project input points using qh DELAUNAY and qh low_bound/high_bound
2162 input points in qh first_point, num_points, input_dim
2163 if POINTSmalloc, will free old point array
2164 if low[k]=high[k]= 0, removes dimension k
2165 checks that hull_dim agrees with input_dim, PROJECTinput, and DELAUNAY
2166 if DELAUNAY
2167 projects points to paraboloid
2168 returns:
2169 new point array in first_point of qh hull_dim coordinates
2170 sets POINTSmalloc
2171 lowbound/highbound is also projected
2172 */
qh_projectinput(void)2173 void qh_projectinput (void) {
2174 int k,i;
2175 int newdim= qh input_dim, newnum= qh num_points;
2176 signed char *project;
2177 int size= (qh input_dim+1)*sizeof(*project);
2178 pointT *newpoints, *coord, *infinity;
2179 realT paraboloid, maxboloid= 0;
2180
2181 project= (signed char *)qh_memalloc (size);
2182 memset ((char*)project, 0, size);
2183 for (k= 0; k<qh input_dim; k++) { /* skip Delaunay bound */
2184 if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) {
2185 project[k]= -1;
2186 newdim--;
2187 }
2188 }
2189 if (qh DELAUNAY) {
2190 project[k]= 1;
2191 newdim++;
2192 newnum++;
2193 }
2194 if (newdim != qh hull_dim) qhull_fatal(26);
2195
2196 if (!(newpoints=(coordT*)malloc(newnum*newdim*sizeof(coordT))))
2197 qhull_fatal(27);
2198
2199 qh_projectpoints (project, qh input_dim+1, qh first_point,
2200 qh num_points, qh input_dim, newpoints, newdim);
2201 trace1((qh ferr, "qh_projectinput: updating lower and upper_bound\n"));
2202 qh_projectpoints (project, qh input_dim+1, qh lower_bound,
2203 1, qh input_dim+1, qh lower_bound, newdim+1);
2204 qh_projectpoints (project, qh input_dim+1, qh upper_bound,
2205 1, qh input_dim+1, qh upper_bound, newdim+1);
2206 qh_memfree(project, ((qh input_dim+1)*sizeof(*project)));
2207 if (qh POINTSmalloc)
2208 free (qh first_point);
2209 qh first_point= newpoints;
2210 qh POINTSmalloc= True;
2211 if (qh DELAUNAY) {
2212 coord= qh first_point;
2213 infinity= qh first_point + qh hull_dim * qh num_points;
2214 for (k=qh hull_dim-1; k--; )
2215 infinity[k]= 0.0;
2216 for (i=qh num_points; i--; ) {
2217 paraboloid= 0.0;
2218 for (k=qh hull_dim-1; k--; ) {
2219 paraboloid += *coord * *coord;
2220 infinity[k] += *coord;
2221 coord++;
2222 }
2223 *(coord++)= paraboloid;
2224 maximize_(maxboloid, paraboloid);
2225 }
2226 for (k=qh hull_dim-1; k--; )
2227 *(coord++) /= qh num_points;
2228 *(coord++)= maxboloid * 1.1;
2229 qh num_points++;
2230 trace0((qh ferr, "qh_projectinput: projected points to paraboloid for Delaunay\n"));
2231 }
2232 } /* projectinput */
2233
2234
2235 /*-------------------------------------------------
2236 -projectpoint- project point onto a facet by dist
2237 projects point to hyperplane if dist= distplane(point,facet)
2238 returns:
2239 returns a new point
2240 assumes normal_size is in short memory
2241 */
2242
qh_projectpoint(pointT * point,facetT * facet,realT dist)2243 pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist) {
2244 pointT *newpoint, *np, *normal;
2245 int normsize= qh normal_size,k;
2246 void **freelistp;
2247
2248 float_qh_memalloc_(normsize, freelistp, newpoint);
2249 np= newpoint;
2250 normal= facet->normal;
2251 for(k= qh hull_dim; k--; )
2252 *(np++)= *point++ - dist * *normal++;
2253 return(newpoint);
2254 } /* projectpoint */
2255
2256
2257 /*-------------------------------------------------
2258 -projectpoints- project along one or more dimensions
2259 delete dimension k if project[k] == -1
2260 add dimension k if project[k] == 1
2261 n is size of project
2262 points, numpoints, dim is old points
2263 newpoints, newdim is buffer for new points (already allocated)
2264 newpoints may be points if only adding dimension at end
2265 */
qh_projectpoints(signed char * project,int n,realT * points,int numpoints,int dim,realT * newpoints,int newdim)2266 void qh_projectpoints (signed char *project, int n, realT *points,
2267 int numpoints, int dim, realT *newpoints, int newdim) {
2268 int testdim= dim, oldk=0, newk=0, i,j=0,k;
2269 realT *newp, *oldp;
2270
2271 for (k= 0; k<n; k++)
2272 testdim += project[k];
2273 if (testdim != newdim) qhull_fatal(28);
2274
2275 for (j= 0; j<n; j++) {
2276 if (project[j] == -1)
2277 oldk++;
2278 else {
2279 newp= newpoints+newk++;
2280 if (project[j] == +1) {
2281 if (oldk >= dim)
2282 continue;
2283 oldp= points+oldk;
2284 }else
2285 oldp= points+oldk++;
2286 for (i=numpoints; i--; ) {
2287 *newp= *oldp;
2288 newp += newdim;
2289 oldp += dim;
2290 }
2291 }
2292 if (oldk >= dim)
2293 break;
2294 }
2295 trace1((qh ferr, "qh_projectpoints: projected %d points from dim %d to dim %d\n",
2296 numpoints, dim, newdim));
2297 } /* projectpoints */
2298
2299
2300 /*-------------------------------------------------
2301 -randomfactor- return a random factor within qh RANDOMmax of 1.0
2302 RANDOMa/b definedin global.c
2303 */
qh_randomfactor(void)2304 realT qh_randomfactor (void) {
2305 realT randr;
2306
2307 randr= qh_RANDOMint;
2308 return randr * qh RANDOMa + qh RANDOMb;
2309 } /* randomfactor */
2310
2311 /*-------------------------------------------------
2312 -randommatrix- generate a random dimXdim matrix in range (-1,1)
2313 assumes buffer is dim+1Xdim
2314 returns:
2315 returns row vector for buffer
2316 plus row[dim] for scratch
2317 */
qh_randommatrix(realT * buffer,int dim,realT ** row)2318 void qh_randommatrix (realT *buffer, int dim, realT **row) {
2319 int i, k;
2320 realT **rowi, *coord, realr;
2321
2322 coord= buffer;
2323 rowi= row;
2324 for (i=0; i<dim; i++) {
2325 *(rowi++)= coord;
2326 for (k=0; k<dim; k++) {
2327 realr= qh_RANDOMint;
2328 *(coord++)= 2.0 * realr/(qh_RANDOMmax+1.0) - 1.0;
2329 }
2330 }
2331 *rowi= coord;
2332 } /* randommatrix */
2333
2334
2335 /*-------------------------------------------------
2336 -rotateinput- rotate input using row matrix
2337 input points given by qh first_point, num_points, hull_dim
2338 if qh POINTSmalloc, overwrites input points, else mallocs a new array
2339 assumes rows[dim] is a scratch buffer
2340 returns:
2341 sets qh POINTSmalloc
2342 */
qh_rotateinput(realT ** rows)2343 void qh_rotateinput (realT **rows) {
2344 int size;
2345 pointT *newpoints;
2346
2347 if (!qh POINTSmalloc) {
2348 size= qh num_points*qh hull_dim*sizeof(pointT);
2349 if (!(newpoints=(coordT*)malloc(size))) qhull_fatal(29);
2350
2351 memcpy ((char *)newpoints, (char *)qh first_point, size);
2352 qh first_point= newpoints;
2353 qh POINTSmalloc= True;
2354 }
2355 qh_rotatepoints (qh first_point, qh num_points, qh hull_dim, rows);
2356 } /* rotateinput */
2357
2358 /*-------------------------------------------------
2359 -rotatepoints- rotate numpoints points by a row matrix
2360 assumes rows[dim] is a scratch buffer
2361 */
qh_rotatepoints(realT * points,int numpoints,int dim,realT ** row)2362 void qh_rotatepoints (realT *points, int numpoints, int dim, realT **row) {
2363 realT *point, *rowi, *coord= NULL, sum, *newval;
2364 int i,j,k;
2365
2366 for (point= points, j= numpoints; j--; point += dim) {
2367 newval= row[dim];
2368 for (i= 0; i<dim; i++) {
2369 rowi= row[i];
2370 coord= point;
2371 for (sum= 0.0, k= dim; k--; )
2372 sum += *rowi++ * *coord++;
2373 *(newval++)= sum;
2374 }
2375 for (k= dim; k--; )
2376 *(--coord)= *(--newval);
2377 }
2378 } /* rotatepoints */
2379
2380
2381 /*-------------------------------------------------
2382 -scaleinput- scale input points using qh low_bound/high_bound
2383 input points given by qh first_point, num_points, hull_dim
2384 if qh POINTSmalloc, overwrites input points, else mallocs a new array
2385 returns:
2386 scales points to low[k], high[k]
2387 sets qh POINTSmalloc
2388 */
qh_scaleinput(void)2389 void qh_scaleinput (void) {
2390 int size;
2391 pointT *newpoints;
2392
2393 if (!qh POINTSmalloc) {
2394 size= qh num_points*qh hull_dim*sizeof(pointT);
2395
2396 if (!(newpoints=(coordT*)malloc(size))) qhull_fatal(30);
2397
2398 memcpy ((char *)newpoints, (char *)qh first_point, size);
2399 qh first_point= newpoints;
2400 qh POINTSmalloc= True;
2401 }
2402 qh_scalepoints (qh first_point, qh num_points, qh hull_dim,
2403 qh lower_bound, qh upper_bound);
2404 } /* scaleinput */
2405
2406 /*-------------------------------------------------
2407 -scalepoints- scale points to new lowbound and highbound
2408 retains old bound when newlow= -REALmax or newhigh= +REALmax
2409 overwrites old points
2410 */
qh_scalepoints(pointT * points,int numpoints,int dim,realT * newlows,realT * newhighs)2411 void qh_scalepoints (pointT *points, int numpoints, int dim,
2412 realT *newlows, realT *newhighs) {
2413 int i,k;
2414 realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord;
2415 boolT nearzero= False;
2416
2417 for (k= 0; k<dim; k++) {
2418 newhigh= newhighs[k];
2419 newlow= newlows[k];
2420 if (newhigh > REALmax/2 && newlow < -REALmax/2)
2421 continue;
2422 low= REALmax;
2423 high= -REALmax;
2424 for (i= numpoints, coord= points+k; i--; coord += dim) {
2425 minimize_(low, *coord);
2426 maximize_(high, *coord);
2427 }
2428 if (newhigh > REALmax/2)
2429 newhigh= high;
2430 if (newlow < -REALmax/2)
2431 newlow= low;
2432 scale= qh_divzero (newhigh - newlow, high - low,
2433 qh MINdenom_1, &nearzero);
2434 if (nearzero) qhull_fatal(31);
2435
2436 shift= (newlow * high - low * newhigh)/(high-low);
2437 coord= points+k;
2438 for (i= numpoints; i--; coord += dim)
2439 *coord= *coord * scale + shift;
2440 coord= points+k;
2441 if (newlow < newhigh) {
2442 mincoord= newlow;
2443 maxcoord= newhigh;
2444 }else {
2445 mincoord= newhigh;
2446 maxcoord= newlow;
2447 }
2448 for (i= numpoints; i--; coord += dim) {
2449 minimize_(*coord, maxcoord); /* because of roundoff error */
2450 maximize_(*coord, mincoord);
2451 }
2452 trace0((qh ferr, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n",
2453 k, low, high, newlow, newhigh, numpoints, scale, shift));
2454 }
2455 } /* scalepoints */
2456
2457
2458 /*-------------------------------------------------
2459 -setfacetplane- sets the hyperplane for a facet
2460 uses global buffers qh gm_matrix and qh gm_row
2461 overwrites facet->normal if already defined
2462 updates Wnewvertex if PRINTstatistics
2463 */
qh_setfacetplane(facetT * facet)2464 void qh_setfacetplane(facetT *facet) {
2465 pointT *point;
2466 vertexT *vertex, **vertexp;
2467 int k,i=0;
2468 int normsize= qh normal_size;
2469 int oldtrace = 0;
2470 realT dist;
2471 void **freelistp;
2472 coordT *coord, *gmcoord= qh gm_matrix;
2473 pointT *point0= ((vertexT*)SETfirst_(facet->vertices))->point;
2474 boolT nearzero;
2475
2476 zzinc_(Zsetplane);
2477 if (!facet->normal)
2478 float_qh_memalloc_(normsize, freelistp, facet->normal);
2479 if (facet == qh tracefacet) {
2480 oldtrace= qh IStracing;
2481 qh IStracing= 5;
2482
2483 /*
2484 fprintf (qh ferr, "qh_setfacetplane: facet f%d created.\n", facet->id);
2485 fprintf (qh ferr, " Last point added to hull was p%d.", qh furthest_id);
2486 if (zzval_(Ztotmerge))
2487 fprintf(qh ferr, " Last merge was #%d.", zzval_(Ztotmerge));
2488 fprintf (qh ferr, "\n\nSorry, qh_printsummary no longer supported:\n");
2489 fprintf (qh ferr, "\n\nCurrent summary is:\n");
2490 qh_printsummary (qh ferr); */
2491 }
2492 if (qh hull_dim <= 4) {
2493 if (qh RANDOMdist) {
2494 FOREACHvertex_(facet->vertices) {
2495 qh gm_row[i++]= gmcoord;
2496 coord= vertex->point;
2497 for (k= qh hull_dim; k--; )
2498 *(gmcoord++)= *coord++ * qh_randomfactor();
2499 }
2500 }else {
2501 FOREACHvertex_(facet->vertices)
2502 qh gm_row[i++]= vertex->point;
2503 }
2504 qh_sethyperplane_det(qh hull_dim, qh gm_row, point0,
2505 (boolT)facet->toporient,
2506 facet->normal, &facet->offset);
2507 }else {
2508 FOREACHvertex_(facet->vertices) {
2509 if (vertex->point != point0) {
2510 qh gm_row[i++]= gmcoord;
2511 coord= vertex->point;
2512 point= point0;
2513 for(k= qh hull_dim; k--; )
2514 *(gmcoord++)= *coord++ - *point++;
2515 }
2516 }
2517 qh gm_row[i]= gmcoord; /* for areasimplex */
2518 if (qh RANDOMdist) {
2519 gmcoord= qh gm_matrix;
2520 for (i= qh hull_dim-1; i--; ) {
2521 for (k= qh hull_dim; k--; )
2522 *(gmcoord++) *= qh_randomfactor();
2523 }
2524 }
2525 qh_sethyperplane_gauss(qh hull_dim, qh gm_row, point0,
2526 (boolT)facet->toporient,
2527 facet->normal, &facet->offset, &nearzero);
2528 if (nearzero) {
2529 if (qh_orientoutside (facet)) {
2530 trace0((qh ferr, "qh_setfacetplane: flipped orientation after testing interior_point\n"));
2531 /* this is part of using Gaussian Elimination. For example in 5-d
2532 1 1 1 1 0
2533 1 1 1 1 1
2534 0 0 0 1 0
2535 0 1 0 0 0
2536 1 0 0 0 0
2537 norm= 0.38 0.38 -0.76 0.38 0
2538 has a determinate of 1, but g.e. after subtracting pt. 0 has
2539 0's in the diagonal, even with full pivoting. It does work
2540 if you subtract pt. 4 instead. */
2541 }
2542 }
2543 }
2544 if (qh PRINTstatistics) {
2545 FOREACHvertex_(facet->vertices) {
2546 if (vertex->point != point0) {
2547 zinc_(Zdiststat);
2548 qh_distplane(vertex->point, facet, &dist);
2549 dist= fabs_(dist);
2550 zinc_(Znewvertex);
2551 wadd_(Wnewvertex, dist);
2552 if (dist > wval_(Wnewvertexmax)) {
2553 wval_(Wnewvertexmax)= dist;
2554 maximize_(qh max_outside, dist);
2555 }
2556 }
2557 }
2558 }
2559
2560 if (qh IStracing >= 3) {
2561 /*
2562 fprintf (qh ferr, "qh_setfacetplane: f%d offset %2.2g normal: ",
2563 facet->id, facet->offset);
2564 for (k=0; k<qh hull_dim; k++)
2565 fprintf (qh ferr, "%2.2g ", facet->normal[k]);
2566 fprintf (qh ferr, "\n");
2567 */
2568 }
2569
2570 if (facet == qh tracefacet)
2571 qh IStracing= oldtrace;
2572 } /* setfacetplane */
2573
2574
2575 /*-------------------------------------------------
2576 -sethyperplane_det- set normalized hyperplane equation from oriented simplex
2577 dim X dim array indexed by rows[], one row per point, point0 is any row
2578 only defined for dim == 2..4
2579 returns:
2580 offset, normal
2581 bumps Znearlysingular if normalization fails
2582 rows[] is not modified
2583 notes:
2584 solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane
2585 offset places point0 on the hyperplane
2586 toporient just flips all signs, so orientation is correct
2587 see Bower & Woodworth, A programmer's geometry, Butterworths 1983.
2588 */
qh_sethyperplane_det(int dim,coordT ** rows,coordT * point0,boolT toporient,coordT * normal,realT * offset)2589 void qh_sethyperplane_det (int dim, coordT **rows, coordT *point0,
2590 boolT toporient, coordT *normal, realT *offset) {
2591
2592 if (dim == 2) {
2593 normal[0]= dY(1,0);
2594 normal[1]= dX(0,1);
2595 qh_normalize (normal, dim, toporient);
2596 *offset= -(point0[0]*normal[0]+point0[1]*normal[1]);
2597 }else if (dim == 3) {
2598 normal[0]= det2_(dY(2,0), dZ(2,0),
2599 dY(1,0), dZ(1,0));
2600 normal[1]= det2_(dX(1,0), dZ(1,0),
2601 dX(2,0), dZ(2,0));
2602 normal[2]= det2_(dX(2,0), dY(2,0),
2603 dX(1,0), dY(1,0));
2604 qh_normalize (normal, dim, toporient);
2605 *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
2606 + point0[2]*normal[2]);
2607 }else if (dim == 4) {
2608 normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0),
2609 dY(1,0), dZ(1,0), dW(1,0),
2610 dY(3,0), dZ(3,0), dW(3,0));
2611 normal[1]= det3_(dX(2,0), dZ(2,0), dW(2,0),
2612 dX(1,0), dZ(1,0), dW(1,0),
2613 dX(3,0), dZ(3,0), dW(3,0));
2614 normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0),
2615 dX(1,0), dY(1,0), dW(1,0),
2616 dX(3,0), dY(3,0), dW(3,0));
2617 normal[3]= det3_(dX(2,0), dY(2,0), dZ(2,0),
2618 dX(1,0), dY(1,0), dZ(1,0),
2619 dX(3,0), dY(3,0), dZ(3,0));
2620 qh_normalize (normal, dim, toporient);
2621 *offset= -(point0[0]*normal[0] + point0[1]*normal[1]
2622 + point0[2]*normal[2] + point0[3]*normal[3]);
2623 }
2624 } /* sethyperplane_det */
2625
2626
2627 /*-------------------------------------------------
2628 -sethyperplane_gauss- set normalized hyperplane equation from oriented simplex
2629 (dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0)
2630 returns:
2631 offset, normal
2632 if nearzero, bumps Znearlysingular
2633 orientation may be incorrect because of incorrect sign flips in gausselim
2634 notes:
2635 solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1]
2636 or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0]
2637 i.e., N is normal to the hyperplane, and the unnormalized
2638 distance to [0 .. 1] is either 1 or 0
2639 offset places point0 on the hyperplane
2640 */
qh_sethyperplane_gauss(int dim,coordT ** rows,pointT * point0,boolT toporient,coordT * normal,coordT * offset,boolT * nearzero)2641 void qh_sethyperplane_gauss (int dim, coordT **rows, pointT *point0,
2642 boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) {
2643 coordT *pointcoord, *normalcoef;
2644 int k, tempint;
2645 boolT sign= (boolT)!toporient, nearzero2= False;
2646
2647 qh_gausselim(rows, dim-1, dim, &sign, nearzero);
2648 for(k= dim-1; k--; ) {
2649 if ((rows[k])[k] < 0) {
2650 tempint = (int)sign;
2651 tempint ^= 1;
2652 sign = (boolT)tempint;
2653 }
2654 }
2655 if (*nearzero) {
2656 zinc_(Znearlysingular);
2657 trace0((qh ferr, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane.\n"));
2658 qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
2659 }else {
2660 qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2);
2661 if (nearzero2) {
2662 zinc_(Znearlysingular);
2663 trace0((qh ferr, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization\n"));
2664 }
2665 }
2666 if (nearzero2)
2667 *nearzero= True;
2668 qh_normalize(normal, dim, True);
2669 pointcoord= point0;
2670 normalcoef= normal;
2671 *offset= -(*pointcoord++ * *normalcoef++);
2672 for(k= dim-1; k--; )
2673 *offset -= *pointcoord++ * *normalcoef++;
2674 } /* sethyperplane_gauss */
2675
2676 /*-------------------------------------------
2677 -voronoi_center- return Voronoi center for a set of points
2678 dim is the orginal dimension of the points
2679 notes:
2680 if non-simplicial, returns center for max simplex of points
2681 from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65
2682 */
qh_voronoi_center(int dim,setT * points)2683 pointT *qh_voronoi_center (int dim, setT *points) {
2684 pointT *point, **pointp, *point0;
2685 pointT *center= (pointT *)qh_memalloc (qh center_size);
2686 setT *simplex = NULL;
2687 int i, j, k, num, size= qh_setsize(points);
2688 coordT *gmcoord;
2689 realT *diffp, sum2, *sum2row, *sum2p, det, factor;
2690 boolT nearzero, infinite;
2691
2692 if (size == dim+1) {
2693 simplex = points;
2694 }
2695 else if (size < dim+1) {
2696 qhull_fatal(32);
2697 }
2698 else {
2699 simplex = qh_settemp (dim+1);
2700 qh_maxsimplex (dim, points, NULL, 0, &simplex);
2701 }
2702 num= qh_setsize (simplex);
2703 point0= (pointT *)SETfirst_(simplex);
2704 gmcoord= qh gm_matrix;
2705 for (k=0; k<dim; k++) {
2706 qh gm_row[k]= gmcoord;
2707 FOREACHpoint_(simplex) {
2708 if (point != point0)
2709 *(gmcoord++)= point[k] - point0[k];
2710 }
2711 }
2712 sum2row= gmcoord;
2713 for (i=0; i<dim; i++) {
2714 sum2= 0.0;
2715 for (k= 0; k<dim; k++) {
2716 diffp= qh gm_row[k] + i;
2717 sum2 += *diffp * *diffp;
2718 }
2719 *(gmcoord++)= sum2;
2720 }
2721 det= qh_determinant (qh gm_row, dim, &nearzero);
2722 factor= qh_divzero (0.5, det, qh MINdenom, &infinite);
2723 if (infinite) {
2724 for (k=dim; k--; )
2725 center[k]= qh_INFINITE;
2726 if (qh IStracing)
2727 qh_printpoints (qh ferr, "qh_voronoi_center: at infinity for ", simplex);
2728 }else {
2729 for (i=0; i<dim; i++) {
2730 gmcoord= qh gm_matrix;
2731 sum2p= sum2row;
2732 for (k=0; k<dim; k++) {
2733 qh gm_row[k]= gmcoord;
2734 if (k == i) {
2735 for (j= dim; j--; )
2736 *(gmcoord++)= *sum2p++;
2737 }else {
2738 FOREACHpoint_(simplex) {
2739 if (point != point0)
2740 *(gmcoord++)= point[k] - point0[k];
2741 }
2742 }
2743 }
2744 center[i]= qh_determinant (qh gm_row, dim, &nearzero)*factor + point0[i];
2745 }
2746 if (qh IStracing >= 3) {
2747
2748 /*
2749 fprintf (qh ferr, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor);
2750 qh_printmatrix (qh ferr, "center:", ¢er, 1, dim);
2751 if (qh IStracing >= 5) {
2752 qh_printpoints (qh ferr, "points", simplex);
2753 FOREACHpoint_(simplex)
2754 fprintf (qh ferr, "p%d dist %.2g, ", qh_pointid (point),
2755 qh_pointdist (point, center, dim));
2756 fprintf (qh ferr, "\n");
2757 }
2758 */
2759
2760 }
2761 }
2762 if (simplex != points)
2763 qh_settempfree (&simplex);
2764 return center;
2765 } /* voronoi_center */
2766
2767
2768 /*************************************************************************/
2769 /****************** implementation code from stat.c **********************/
2770 /*************************************************************************/
2771
2772 /* stat.c - contains all statistics that are collected for qhull
2773
2774 see README and stat.h
2775
2776 copyright (c) 1993-1994, The Geometry Center
2777 */
2778
2779 #if qh_QHpointer
2780 qhstatT *qh_qhstat=NULL; /* global data structure */
2781 #else
2782 qhstatT qh_qhstat; /* remove "={0}" if this causes a compiler error */
2783 #endif
2784
2785
2786 /*-------------------------------------------------
2787 -allstatA -- define statistics in groups of 20
2788 (otherwise, 'gcc -O2' uses too much memory)
2789 uses qhstat next
2790 */
qh_allstatA(void)2791 void qh_allstatA (void) {
2792
2793 /* zdef_(type,name,doc,average) */
2794 zzdef_(zdoc, Zdoc2, "precision statistics", -1);
2795 zdef_(zinc, Znewvertex, static_cast<const char *>(NULL), -1);
2796 zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet (not 0s)", Znewvertex);
2797 zdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1);
2798 zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1);
2799 zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1);
2800 zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1);
2801
2802 qhstat precision= qhstat next;
2803 zzdef_(zdoc, Zdoc3, "precision problems", -1);
2804 zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1);
2805 zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1);
2806 zzdef_(zinc, Zflippedfacets, "flipped facets", -1);
2807 zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1);
2808 zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1);
2809 zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1);
2810 zzdef_(zinc, Zback0, "zero divisors during back substitute", -1);
2811 zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1);
2812 zzdef_(zinc, Zmultimatch, "ridges with multiple neighbors (same flip)", -1);
2813 zzdef_(zinc, Zmultiflip, "ridges with multiple neighbors (diff flip)", -1);
2814
2815 }
qh_allstatB(void)2816 void qh_allstatB (void) {
2817 zzdef_(zdoc, Zdoc1, "summary information", -1);
2818 zdef_(zinc, Zvertices, "number of vertices in output", -1);
2819 zdef_(zinc, Znumfacets, "number of facets in output", -1);
2820 zdef_(zinc, Znumridges, "number of ridges in output", -1);
2821 zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets);
2822 zdef_(zmax, Zmaxridges, "maximum number of ridges", -1);
2823 zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets);
2824 zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1);
2825 zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets);
2826 zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1);
2827 zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices);
2828 zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1);
2829 zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1);
2830 zdef_(zinc, Ztotvertices, "vertices created altogether", -1);
2831 zzdef_(zinc, Zsetplane, "facets created altogether", -1);
2832 zdef_(zinc, Ztotridges, "ridges created altogether", -1);
2833 zdef_(zinc, Zpostfacets, "facets before post merge", -1);
2834 zdef_(zinc, Zangle, static_cast<const char *>(NULL), -1);
2835 zdef_(wadd, Wangle, "average angle (cosine) for all ridges", Zangle);
2836 zdef_(wmax, Wanglemax, "maximum angle (cosine) of a ridge", -1);
2837 zdef_(wmin, Wanglemin, "minimum angle (cosine) of a ridge", -1);
2838
2839
2840 zdef_(zdoc, Zdoc9, "build hull statistics", -1);
2841 zdef_(zinc, Zdetsimplex, "determinates computed (initial hull)", -1);
2842 zzdef_(zinc, Zprocessed, "points processed", -1);
2843 zdef_(zinc, Ztotvisible, "visible facets for all new vertices", -1);
2844 zdef_(zinc, Zinsidevisible, "visible facets without an horizon neighbor", -1);
2845 zdef_(zinc, Ztothorizon, "horizon facets for all new vertices", -1);
2846 zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed);
2847 zdef_(wadd, Wnewbalance2, " standard deviation", -1);
2848 zdef_(wadd, Wpbalance, "average partition balance", Zpbalance);
2849 zdef_(wadd, Wpbalance2, " standard deviation", -1);
2850 zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1);
2851 zdef_(zinc, Znotmax, "points ignored (not above max_outside)", -1);
2852 zdef_(zinc, Znotgood, "points ignored (not above a good facet)", -1);
2853 zdef_(zinc, Znotgoodnew, "points ignored (didn't create a good new facet)", -1);
2854 zdef_(zinc, Zgoodfacet, "good facets found", -1);
2855 zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1);
2856 zdef_(zinc, Ztotverify, "points verified", -1);
2857 zdef_(zinc, Zverifypart, " ave. distance tests per verify", Ztotverify);
2858 }
qh_allstatC(void)2859 void qh_allstatC(void) {
2860 zdef_(zdoc, Zdoc4, "partitioning statistics", -1);
2861 zdef_(zinc, Zpartinside, "inside points", -1);
2862 zdef_(zinc, Zcoplanarinside, " inside points that were coplanar with a facet", -1);
2863 zdef_(zinc, Ztotpartition, "partitions of a point", -1);
2864
2865 zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1);
2866 zzdef_(zinc, Zpartition, "distance tests for other partitions", -1);
2867 zdef_(zinc, Zpartneighbor, "extra distance tests for coplanar and flipped neighbors", -1);
2868 zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1);
2869 zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1);
2870 zdef_(zinc, Zdistgood, "distance tests for checking good point", -1);
2871 zdef_(zinc, Zdistio, "distance tests for output", -1);
2872 zdef_(zinc, Zdiststat, "distance tests for statistics", -1);
2873 zdef_(zinc, Zdistplane, "total number of distance tests", -1);
2874 zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1);
2875 zzdef_(zinc, Zpartcoplanar, " distance tests for these partitions", -1);
2876 zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1);
2877
2878 }
qh_allstatD(void)2879 void qh_allstatD(void) {
2880 zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1);
2881 zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1);
2882 zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup);
2883 zdef_(zinc, Zhashridge, "total lookups of subridges (duplicates and boundary)", -1);
2884 zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge);
2885
2886 zdef_(zdoc, Zdoc6, "statistics for determining merges", -1);
2887 zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1);
2888 zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices", -1);
2889 zzdef_(zinc, Zbestdist, "distance tests for best merge", -1);
2890 zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1);
2891 zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1);
2892 zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1);
2893 zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1);
2894 }
qh_allstatE(void)2895 void qh_allstatE(void) {
2896 zdef_(zdoc, Zdoc7, "statistics for merging", -1);
2897 zdef_(wmax, Wmaxoutside, "max distance of merged vertex above facet", -1);
2898 zdef_(wmin, Wminvertex, "max distance of merged vertex below facet", -1);
2899 zzdef_(zinc, Ztotmerge, "total number of facets merged", -1);
2900 zdef_(zinc, Zmergenew, "new facets merged", -1);
2901 zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1);
2902 zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1);
2903 zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1);
2904 zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1);
2905 zdef_(zinc, Zmergeflip, "merges due to flipped neighbors", -1);
2906 zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1);
2907 zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1);
2908 zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1);
2909 zdef_(wadd, Wacoplanartot, " average merge distance", Zacoplanar);
2910 zdef_(wmax, Wacoplanarmax, " maximum merge distance", -1);
2911 zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1);
2912 zdef_(wadd, Wcoplanartot, " average merge distance", Zcoplanar);
2913 zdef_(wmax, Wcoplanarmax, " maximum merge distance", -1);
2914 zdef_(zinc, Zconcave, "merges due to concave facets", -1);
2915 zdef_(wadd, Wconcavetot, " average merge distance", Zconcave);
2916 zdef_(wmax, Wconcavemax, " maximum merge distance", -1);
2917 zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1);
2918 zdef_(wadd, Wavoidoldtot, " average merge distance", Zavoidold);
2919 zdef_(wmax, Wavoidoldmax, " maximum merge distance", -1);
2920 zdef_(zinc, Zdegen, "merges due to degenerate facets", -1);
2921 zdef_(wadd, Wdegentot, " average merge distance", Zdegen);
2922 zdef_(wmax, Wdegenmax, " maximum merge distance", -1);
2923 zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1);
2924 zdef_(wadd, Wflippedtot, " average merge distance", Zflipped);
2925 zdef_(wmax, Wflippedmax, " maximum merge distance", -1);
2926 zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1);
2927 zdef_(wadd, Wduplicatetot, " average merge distance", Zduplicate);
2928 zdef_(wmax, Wduplicatemax, " maximum merge distance", -1);
2929
2930 }
qh_allstatF(void)2931 void qh_allstatF(void) {
2932 zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1);
2933 zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1);
2934 zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1);
2935 zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1);
2936 zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1);
2937 zdef_(zinc, Zdupridge, " duplicate ridges detected", -1);
2938 zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1);
2939 zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1);
2940 zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1);
2941 zdef_(zinc, Zdelfacetdup, " facets deleted because of no neighbors", -1);
2942 zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1);
2943 zdef_(zinc, Zremvertexdel, "vertices deleted due to no ridges", -1);
2944 zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1);
2945 zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1);
2946 zdef_(zinc, Zintersect, "intersections found redundant vertices", -1);
2947 zdef_(zadd, Zintersecttot, " ave. number found per vertex", Zintersect);
2948 zdef_(zmax, Zintersectmax, " max. found for a vertex", -1);
2949 zdef_(zinc, Zvertexridge, static_cast<const char *>(NULL), -1);
2950 zdef_(zadd, Zvertexridgetot, " ave. number of ridges per tested vertex", Zvertexridge);
2951 zdef_(zmax, Zvertexridgemax, " max. number of ridges per tested vertex", -1);
2952
2953 zdef_(zdoc, Zdoc10, "memory usage statistics (in bytes)", -1);
2954 zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1);
2955 zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1);
2956 zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1);
2957 zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1);
2958 } /* allstat */
2959
2960
2961 #if qh_KEEPstatistics
2962 /*-------------------------------------------------
2963 -collectstatistics- collect statistics for qh facet_list
2964 */
qh_collectstatistics(void)2965 void qh_collectstatistics (void) {
2966 facetT *facet, *neighbor, **neighborp;
2967 vertexT *vertex, **vertexp;
2968 realT dotproduct, dist;
2969 int sizneighbors, sizridges, sizvertices;
2970
2971 zval_(Zmempoints)= qh num_points * qh normal_size +
2972 sizeof (qhT) + sizeof (qhstatT);
2973 zval_(Zmemfacets)= 0;
2974 zval_(Zmemridges)= 0;
2975 zval_(Zmemvertices)= 0;
2976 zval_(Zangle)= 0;
2977 wval_(Wangle)= 0.0;
2978 zval_(Znumridges)= 0;
2979 zval_(Znumfacets)= 0;
2980 zval_(Znumneighbors)= 0;
2981 zval_(Znumvertices)= 0;
2982 zval_(Znumvneighbors)= 0;
2983 zval_(Zvertices)= qh num_vertices - qh_setsize (qh del_vertices);
2984 if (qh MERGING || qh APPROXhull)
2985 wmax_(Wmaxoutside, qh max_outside);
2986 if (qh MERGING)
2987 wmin_(Wminvertex, qh min_vertex);
2988 FORALLfacets
2989 facet->seen= False;
2990 if (qh DELAUNAY) {
2991 FORALLfacets {
2992 if (facet->normal && facet->normal[qh hull_dim - 1] > 0.0)
2993 facet->seen= True;
2994 }
2995 }
2996 FORALLfacets {
2997 if (facet->visible && qh NEWfacets)
2998 continue;
2999 sizvertices= qh_setsize (facet->vertices);
3000 sizneighbors= qh_setsize (facet->neighbors);
3001 sizridges= qh_setsize (facet->ridges);
3002 zinc_(Znumfacets);
3003 zadd_(Znumvertices, sizvertices);
3004 zmax_(Zmaxvertices, sizvertices);
3005 zadd_(Znumneighbors, sizneighbors);
3006 zmax_(Zmaxneighbors, sizneighbors);
3007 if (sizridges) {
3008 zadd_(Znumridges, sizridges);
3009 zmax_(Zmaxridges, sizridges);
3010 }
3011 zadd_(Zmemfacets, sizeof (facetT) + qh normal_size + 2*sizeof (setT)
3012 + SETelemsize * (sizneighbors + sizvertices));
3013 if (facet->ridges) {
3014 zadd_(Zmemridges,
3015 sizeof (setT) + SETelemsize * sizridges + sizridges *
3016 (sizeof (ridgeT) + sizeof (setT) + SETelemsize * (qh hull_dim-1))/2);
3017 }
3018 if (facet->outsideset)
3019 zadd_(Zmempoints, sizeof (setT) + SETelemsize * qh_setsize (facet->outsideset));
3020 if (facet->coplanarset)
3021 zadd_(Zmempoints, sizeof (setT) + SETelemsize * qh_setsize (facet->coplanarset));
3022 if (facet->seen) /* Delaunay upper envelope */
3023 continue;
3024 facet->seen= True;
3025 FOREACHneighbor_(facet) {
3026 if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge
3027 || neighbor->seen || !facet->normal || !neighbor->normal)
3028 continue;
3029 dotproduct= qh_getangle(facet->normal, neighbor->normal);
3030 zinc_(Zangle);
3031 wadd_(Wangle, dotproduct);
3032 wmax_(Wanglemax, dotproduct)
3033 wmin_(Wanglemin, dotproduct)
3034 }
3035 FOREACHvertex_(facet->vertices) {
3036 zinc_(Zdiststat);
3037 qh_distplane(vertex->point, facet, &dist);
3038 wmax_(Wvertexmax, dist);
3039 wmin_(Wvertexmin, dist);
3040 }
3041 }
3042 FORALLvertices {
3043 if (vertex->deleted)
3044 continue;
3045 zadd_(Zmemvertices, sizeof (vertexT));
3046 if (vertex->neighbors) {
3047 sizneighbors= qh_setsize (vertex->neighbors);
3048 zadd_(Znumvneighbors, sizneighbors);
3049 zmax_(Zmaxvneighbors, sizneighbors);
3050 zadd_(Zmemvertices, sizeof (vertexT) + SETelemsize * sizneighbors);
3051 }
3052 }
3053 } /* collectstatistics */
3054 #endif /* qh_KEEPstatistics */
3055
3056 /*-------------------------------------------------
3057 -freestatistics- free memory used for statistics
3058 */
qh_freestatistics(void)3059 void qh_freestatistics (void) {
3060
3061 #if qh_QHpointer /* duplicated if !KEEPstatistics */
3062 free (qh_qhstat);
3063 qh_qhstat= NULL;
3064 #endif
3065 } /* freestatistics */
3066
3067 /*-------------------------------------------------
3068 -initstatistics- allocate and initialize statistics
3069 uses malloc instead of memalloc since mem.c not setup yet
3070 */
qh_initstatistics(void)3071 void qh_initstatistics (void) {
3072 int i;
3073 realT realx;
3074 int intx;
3075
3076 #if qh_QHpointer /* duplicated if !KEEPstatistics */
3077 if (!(qh_qhstat= (qhstatT *)malloc (sizeof(qhstatT)))) qhull_fatal(33);
3078 #endif
3079
3080 qhstat next= 0;
3081 qh_allstatA();
3082 qh_allstatB();
3083 qh_allstatC();
3084 qh_allstatD();
3085 qh_allstatE();
3086 qh_allstatF();
3087
3088 qhstat init[zinc].i= 0;
3089 qhstat init[zadd].i= 0;
3090 qhstat init[zmin].i= INT_MAX;
3091 qhstat init[zmax].i= INT_MIN;
3092 qhstat init[wadd].r= 0;
3093 qhstat init[wmin].r= REALmax;
3094 qhstat init[wmax].r= -REALmax;
3095 for (i=0; i<ZEND; i++) {
3096 if (qhstat type[i] > ZTYPEreal) {
3097 realx= qhstat init[(unsigned char)(qhstat type[i])].r;
3098 qhstat stats[i].r= realx;
3099 }else if (qhstat type[i] != zdoc) {
3100 intx= qhstat init[(unsigned char)(qhstat type[i])].i;
3101 qhstat stats[i].i= intx;
3102 }
3103 }
3104 } /* initstatistics */
3105
3106 /*-------------------------------------------
3107 -newstats- returns True if statistics for zdoc
3108 returns:
3109 next zdoc
3110 */
qh_newstats(int index,int * nextindex)3111 boolT qh_newstats (int index, int *nextindex) {
3112 boolT isnew= False;
3113 int start, i;
3114
3115 if (qhstat type[qhstat id[index]] == zdoc)
3116 start= index+1;
3117 else
3118 start= index;
3119 for (i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) {
3120 if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]])
3121 isnew= True;
3122 }
3123 *nextindex= i;
3124 return isnew;
3125 } /* newstats */
3126
3127 /*-------------------------------------------
3128 -nostatistic- true if no statistic to print
3129 */
qh_nostatistic(int i)3130 boolT qh_nostatistic (int i) {
3131
3132 if ((qhstat type[i] > ZTYPEreal
3133 &&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r)
3134 || (qhstat type[i] < ZTYPEreal
3135 &&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i))
3136 return True;
3137 return False;
3138 } /* nostatistic */
3139
3140 #if qh_KEEPstatistics
3141 /*-------------------------------------------
3142 -qh_printallstatistics- print all statistics to a file
3143 */
qh_printallstatistics(FILE * fp,const char * string)3144 void qh_printallstatistics (FILE *fp, const char *string) {
3145 int i;
3146
3147 for (i=ZEND; i--; )
3148 qhstat printed[i]= False;
3149 qh_printstatistics (fp, string);
3150 }
3151
3152
3153 /*-------------------------------------------
3154 -printstatistics- print statistics to a file
3155 */
qh_printstatistics(FILE * fp,const char * string)3156 void qh_printstatistics (FILE *fp, const char *string) {
3157 int i, k;
3158 realT ave;
3159
3160 if (qh num_points != qh num_vertices) {
3161 wval_(Wpbalance)= 0;
3162 wval_(Wpbalance2)= 0;
3163 }else
3164 wval_(Wpbalance2)= qh_stddev (zval_(Zpbalance), wval_(Wpbalance),
3165 wval_(Wpbalance2), &ave);
3166 wval_(Wnewbalance2)= qh_stddev (zval_(Zprocessed), wval_(Wnewbalance),
3167 wval_(Wnewbalance2), &ave);
3168 fprintf (fp, "\n\
3169 %s\n\
3170 qhull invoked by: %s | %s\n", string, qh rbox_command, qh qhull_command);
3171 fprintf (fp, "\nprecision constants:\n\
3172 %6.2g max. coordinate in the input\n\
3173 %6.2g max. roundoff error for distance computation\n\
3174 %6.2g min. distance for outside points\n",
3175 qh maxmaxcoord, qh DISTround, qh MINoutside);
3176 if (qh premerge_cos < REALmax/2) fprintf (fp, "\
3177 %6.2g max. cosine for pre-merge angle\n", qh premerge_cos);
3178 if (qh PREmerge) fprintf (fp, "\
3179 %6.2g radius of pre-merge centrum\n", qh premerge_centrum);
3180 if (qh postmerge_cos < REALmax/2) fprintf (fp, "\
3181 %6.2g max. cosine for post-merge angle\n", qh postmerge_cos);
3182 if (qh POSTmerge) fprintf (fp, "\
3183 %6.2g radius of post-merge centrum\n", qh postmerge_centrum);
3184 fprintf (fp, "\
3185 %6.2g max. distance for merging two simplicial facets\n\
3186 %6.2g max. roundoff error for arithmetic operations\n\
3187 %6.2g min. denominator for divisions\n\
3188 zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom);
3189 for (k=0; k<qh hull_dim; k++)
3190 fprintf (fp, "%6.2e ", qh NEARzero[k]);
3191 fprintf (fp, "\n\n");
3192 for (i=0 ; i<qhstat next; )
3193 qh_printstats (fp, i, &i);
3194 } /* printstatistics */
3195 #endif /* qh_KEEPstatistics */
3196
3197 /*-------------------------------------------
3198 -printstatlevel- print level information for a statistic
3199 start is 1st level to print
3200 nop if id >= ZEND, printed, or same as initial value
3201 */
qh_printstatlevel(FILE * fp,int id,int start)3202 void qh_printstatlevel (FILE *fp, int id, int start) {
3203 #define NULLfield " "
3204
3205 if (id >= ZEND || qhstat printed[id])
3206 return;
3207 if (qhstat type[id] == zdoc) {
3208 fprintf (fp, "%s\n", qhstat doc[id]);
3209 return;
3210 }
3211 if (qh_nostatistic(id) || !qhstat doc[id])
3212 return;
3213 qhstat printed[id]= True;
3214 if (qhstat count[id] != -1
3215 && qhstat stats[(unsigned char)(qhstat count[id])].i == 0)
3216 fprintf (fp, " *0 cnt*");
3217 else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1)
3218 fprintf (fp, " %6.2g", qhstat stats[id].r);
3219 else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1)
3220 fprintf (fp, " %6.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i);
3221 else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1)
3222 fprintf (fp, " %6d", qhstat stats[id].i);
3223 else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1)
3224 fprintf (fp, " %6.2g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i);
3225 fprintf (fp, " %s\n", qhstat doc[id]);
3226 } /* printstatlevel */
3227
3228
3229 /*-------------------------------------------------------
3230 -printstats- print statistics for a zdoc group
3231 returns:
3232 next zdoc if non-null
3233 */
qh_printstats(FILE * fp,int index,int * nextindex)3234 void qh_printstats (FILE *fp, int index, int *nextindex) {
3235 int j, nexti;
3236
3237 if (qh_newstats (index, &nexti)) {
3238 for (j=index; j<nexti; j++)
3239 qh_printstatlevel (fp, qhstat id[j], 0);
3240 fprintf (fp, "\n");
3241 }
3242 if (nextindex)
3243 *nextindex= nexti;
3244 } /* printstats */
3245
3246 #if qh_KEEPstatistics
3247
3248 /*-----------------------------------------
3249 -stddev- compute the standard deviation and average from statistics
3250 tot2 is the sum of the squares
3251 notes:
3252 computes r.m.s.: (x-ave)^2 == x^2 - 2x tot/num + (tot/num)^2
3253 == tot2 - 2 tot tot/num + tot tot/num == tot2 - tot ave
3254 */
qh_stddev(int num,realT tot,realT tot2,realT * ave)3255 realT qh_stddev (int num, realT tot, realT tot2, realT *ave) {
3256 realT stddev;
3257
3258 *ave= tot/num;
3259 stddev= sqrt (tot2/num - *ave * *ave);
3260 return stddev;
3261 } /* stddev */
3262
3263 #endif /* qh_KEEPstatistics */
3264
3265 #if !qh_KEEPstatistics
qh_collectstatistics(void)3266 void qh_collectstatistics (void) {}
qh_printallstatistics(FILE * fp,const char * string)3267 void qh_printallstatistics (FILE *fp, const char *string) {}
qh_printstatistics(FILE * fp,const char * string)3268 void qh_printstatistics (FILE *fp, const char *string) {}
3269 #endif
3270
3271
3272 /*************************************************************************/
3273 /****************** implementation code from poly.c **********************/
3274 /*************************************************************************/
3275
3276 /* Ppoly.c -- implements polygons and simplices
3277
3278 see README, poly.h and qhull.h
3279
3280 copyright (c) 1993-1994, The Geometry Center
3281 */
3282
3283 /*======== functions in alphabetical order ==========*/
3284
3285 /*-------------------------------------------------
3286 -appendfacet- appends facet to end of qh facet_list,
3287 updates qh facet_list, facet_tail, newfacet_list, facet_next
3288 increments qh numfacets
3289 assumes qh facet_list/facet_tail is defined (createsimplex)
3290 */
qh_appendfacet(facetT * facet)3291 void qh_appendfacet(facetT *facet) {
3292 facetT *tail= qh facet_tail;
3293
3294 if (tail == qh newfacet_list)
3295 qh newfacet_list= facet;
3296 if (tail == qh facet_next)
3297 qh facet_next= facet;
3298 facet->previous= tail->previous;
3299 facet->next= tail;
3300 if (tail->previous)
3301 tail->previous->next= facet;
3302 else
3303 qh facet_list= facet;
3304 tail->previous= facet;
3305 qh num_facets++;
3306 trace4((qh ferr, "qh_appendfacet: append f%d to facet_list\n", facet->id));
3307 } /* appendfacet */
3308
3309
3310 /*-------------------------------------------------
3311 -appendvertex- appends vertex to end of qh vertex_list,
3312 updates qh vertex_list, vertex_tail, newvertex_list
3313 increments qh num_vertices
3314 assumes qh vertex_list/vertex_tail is defined (createsimplex)
3315 */
qh_appendvertex(vertexT * vertex)3316 void qh_appendvertex (vertexT *vertex) {
3317 vertexT *tail= qh vertex_tail;
3318
3319 if (tail == qh newvertex_list)
3320 qh newvertex_list= vertex;
3321 vertex->previous= tail->previous;
3322 vertex->next= tail;
3323 if (tail->previous)
3324 tail->previous->next= vertex;
3325 else
3326 qh vertex_list= vertex;
3327 tail->previous= vertex;
3328 qh num_vertices++;
3329 trace4((qh ferr, "qh_appendvertex: append v%d to vertex_list\n", vertex->id));
3330 } /* appendvertex */
3331
3332
3333 /*-------------------------------------------------
3334 -attachnewfacets- attach horizon facets to new facets in qh newfacet_list
3335 if (qh ONLYgood)
3336 newfacets have neighbor and ridge links to horizon but not vice versa
3337 else
3338 newfacets attached to horizon and visible facets attached to new
3339 qh visible_list is all visible facets
3340 returns:
3341 horizon facets linked to new facets
3342 ridges changed from visible facets to new facets
3343 simplicial ridges deleted
3344 for non-simplicial horizon facets, the first neighbor is a new facet
3345 qh visible_list, no ridges valid, only newfacet neighbors (if any)
3346 sets qh NEWfacets
3347 if qh VERTEXneighbors, update neighbors for each vertex
3348 interior vertices added to qh del_vertices for later partitioning
3349 */
qh_attachnewfacets(void)3350 void qh_attachnewfacets (void ) {
3351 facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible;
3352 ridgeT *ridge, **ridgep;
3353 vertexT *vertex, **vertexp;
3354
3355 qh NEWfacets= True;
3356 if (qh ONLYgood) {
3357 trace3((qh ferr, "qh_attachnewfacets: delete interior ridges\n"));
3358 qh visit_id++;
3359 FORALLvisible_facets {
3360 visible->visitid= qh visit_id;
3361 if (visible->ridges) {
3362 FOREACHridge_(visible->ridges) {
3363 neighbor= otherfacet_(ridge, visible);
3364 if ((int)neighbor->visitid == qh visit_id
3365 || (!neighbor->visible && neighbor->simplicial)) {
3366 if (!neighbor->visible) /* delete ridge for simplicial horizon */
3367 qh_setdel (neighbor->ridges, ridge);
3368 qh_setfree (&(ridge->vertices)); /* delete on 2nd visit */
3369 qh_memfree (ridge, sizeof(ridgeT));
3370 }
3371 }
3372 SETfirst_(visible->ridges)= NULL;
3373 }
3374 SETfirst_(visible->neighbors)= NULL;
3375 SETsecond_(visible->neighbors)= NULL;
3376 }
3377 trace1((qh ferr, "qh_attachnewfacets: attach horizon facets to new facets\n"));
3378 FORALLnew_facets {
3379 horizon= (facetT *)SETfirst_(newfacet->neighbors);
3380 if (horizon->simplicial) {
3381 visible= NULL;
3382 FOREACHneighbor_(horizon) { /* may have more than one horizon ridge */
3383 if (neighbor->visible) {
3384 if (visible) {
3385 if (qh_setequal_skip (newfacet->vertices, 0, horizon->vertices,
3386 SETindex_(horizon->neighbors, neighbor))) {
3387 visible= neighbor;
3388 break;
3389 }
3390 }else
3391 visible= neighbor;
3392 }
3393 }
3394 if (visible) {
3395 SETfirst_(visible->neighbors)= newfacet;
3396 qh_setreplace (horizon->neighbors, visible, newfacet);
3397 }
3398
3399 else qhull_fatal(34);
3400
3401 }else { /* non-simplicial, with a ridge for newfacet */
3402 FOREACHneighbor_(horizon) { /* may hold for many new facets */
3403 if (neighbor->visible) {
3404 SETfirst_(neighbor->neighbors)= newfacet;
3405 qh_setdelnth (horizon->neighbors,
3406 SETindex_(horizon->neighbors, neighbor));
3407 neighborp--; /* repeat */
3408 }
3409 }
3410 qh_setappend (&horizon->neighbors, newfacet);
3411 ridge= (ridgeT *)SETfirst_(newfacet->ridges);
3412 if (ridge->top == horizon)
3413 ridge->bottom= newfacet;
3414 else
3415 ridge->top= newfacet;
3416 }
3417 } /* newfacets */
3418 if (qh PRINTstatistics) {
3419 FORALLvisible_facets {
3420 if (!SETfirst_(visible->neighbors))
3421 zinc_(Zinsidevisible);
3422 }
3423 }
3424 }
3425 trace3((qh ferr, "qh_attachnewfacets: delete interior vertices and update vertex->neighbors\n"));
3426 if (qh VERTEXneighbors) {
3427 FORALLvisible_facets {
3428 FOREACHvertex_(visible->vertices) {
3429 if (vertex->newlist)
3430 qh_setdel (vertex->neighbors, visible);
3431 else if (!vertex->deleted) {
3432 FOREACHneighbor_(vertex) { /* this can happen under merging,
3433 see checkfacet() */
3434 if (!neighbor->visible)
3435 break;
3436 }
3437 if (neighbor)
3438 qh_setdel (vertex->neighbors, visible);
3439 else {
3440 vertex->deleted= True;
3441 qh_setappend (&qh del_vertices, vertex);
3442 trace2((qh ferr, "qh_attachnewfacets: delete vertex p%d (v%d) in f%d\n",
3443 qh_pointid(vertex->point), vertex->id, visible->id));
3444 }
3445 }
3446 }
3447 }
3448 FORALLnew_facets {
3449 FOREACHvertex_(newfacet->vertices)
3450 qh_setappend (&vertex->neighbors, newfacet);
3451 }
3452 }else { /* !VERTEXneighbors */
3453 FORALLvisible_facets {
3454 FOREACHvertex_(visible->vertices) {
3455 if (!vertex->newlist && !vertex->deleted) {
3456 vertex->deleted= True;
3457 qh_setappend (&qh del_vertices, vertex);
3458 trace2((qh ferr, "qh_attachnewfacets: delete vertex p%d (v%d) in f%d\n",
3459 qh_pointid(vertex->point), vertex->id, visible->id));
3460 }
3461 }
3462 }
3463 }
3464 } /* attachnewfacets */
3465
3466 /*-----------------------------------------------
3467 -check_bestdist- check that points are within max_outside of the nearest facet
3468 if ONLYgood, ignores !good facets
3469 see: check_maxout
3470 */
qh_check_bestdist(void)3471 void qh_check_bestdist (void) {
3472 boolT waserror= False, isoutside;
3473 facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL;
3474 realT dist, maxoutside;
3475 pointT *point;
3476 int numpart, facet_i, facet_n, notgood= 0;
3477 setT *facets;
3478
3479 maxoutside= fmax_(qh max_outside, qh DISTround);
3480 maxoutside += 2 * qh DISTround;
3481 /* 1 DISTround to actual point and another DISTround to computed point */
3482 trace1((qh ferr, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside));
3483 facets= qh_pointfacet (/*qh facet_list*/);
3484 if (!qh_QUICKhelp && qh PRINTprecision)
3485 fprintf (qh ferr, "\n\
3486 qhull output completed. Verifying that %d points are\n\
3487 below %2.2g of the nearest %sfacet.\n",
3488 qh_setsize(facets), maxoutside, (qh ONLYgood ? "good " : ""));
3489 FOREACHfacet_i_(facets) {
3490 zinc_(Ztotverify);
3491 if (!facet)
3492 facet= qh facet_list;
3493 point= qh_point(facet_i);
3494 if (point == qh GOODpointp)
3495 continue;
3496 bestfacet= qh_findbest (point, facet, qh_ALL, 0,
3497 &dist, &isoutside, &numpart);
3498 zadd_(Zverifypart, numpart);
3499 if (dist > maxoutside) {
3500 if (qh ONLYgood && !bestfacet->good
3501 && !((bestfacet= qh_findgooddist (point, bestfacet, &dist))
3502 && dist > maxoutside))
3503 notgood++;
3504 else {
3505 waserror= True;
3506 fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance = %6.8g maxoutside= %6.8g\n",
3507 facet_i, bestfacet->id, dist, maxoutside);
3508 errfacet2= errfacet1;
3509 errfacet1= bestfacet;
3510 }
3511 }
3512 }
3513 qh_settempfree (&facets);
3514
3515 if (waserror) qhull_fatal(35);
3516
3517 } /* check_bestdist */
3518
3519 /*-----------------------------------------------
3520 -check_maxout- updates max_outside by checking all points against bestfacet
3521 updates facet->maxoutside via findbest
3522 updates facet->coplanarset to qh min_vertex
3523 if PRINTnone, updates min_vertex for printsummary()
3524 if ONLYgood, ignores !good facets
3525 see check_bestdist
3526 notes:
3527 may not need to check inside points if KEEPcoplanar
3528 (since coplanar is now min_vertex instead of -DISTround)
3529 */
qh_check_maxout(void)3530 void qh_check_maxout (void) {
3531 boolT isoutside;
3532 facetT *facet, *bestfacet, *neighbor, **neighborp;
3533 realT dist, maxoutside, minvertex;
3534 pointT *point;
3535 int numpart, facet_i, facet_n, notgood= 0;
3536 setT *facets, *vertices= NULL;
3537 vertexT *vertex;
3538
3539 maxoutside= minvertex= 0;
3540 trace1((qh ferr, "qh_check_maxout: determine actual maxoutside and minoutside\n"));
3541 facets= qh_pointfacet (/*qh facet_list*/);
3542 if (qh PRINTout[0] == qh_PRINTnone || qh PRINTsummary) {
3543 vertices= qh_pointvertex (/*qh facet_list*/);
3544 FORALLvertices {
3545 FOREACHneighbor_(vertex) {
3546 zinc_(Zverifypart);
3547 qh_distplane (vertex->point, neighbor, &dist);
3548 minimize_(minvertex, dist);
3549 if (-dist > qh TRACEdist
3550 || neighbor == qh tracefacet || vertex == qh tracevertex)
3551 fprintf (qh ferr, "qh_check_maxout: p%d (v%d) is %.2g below f%d\n",
3552 qh_pointid (vertex->point), vertex->id, dist, neighbor->id);
3553 }
3554 }
3555 if (qh MERGING)
3556 wmin_(Wminvertex, qh min_vertex);
3557 qh min_vertex= minvertex;
3558 }
3559 FOREACHfacet_i_(facets) {
3560 if (True) { /* inside points can end up outside after merging */
3561 zinc_(Ztotverify);
3562 if (!facet)
3563 facet= qh facet_list;
3564 point= qh_point(facet_i);
3565 if (point == qh GOODpointp)
3566 continue;
3567 bestfacet= qh_findbest (point, facet, qh_ALL, 0,
3568 &dist, &isoutside, &numpart);
3569 zadd_(Zverifypart, numpart);
3570 if (dist > maxoutside) {
3571 if (qh ONLYgood && !bestfacet->good
3572 && !((bestfacet= qh_findgooddist (point, bestfacet, &dist))
3573 && dist > maxoutside))
3574 notgood++;
3575 else
3576 maxoutside= dist;
3577 }
3578 if (!facet && dist > qh min_vertex)
3579 qh_partitioncoplanar (point, bestfacet, &dist);
3580 if (dist > qh TRACEdist || bestfacet == qh tracefacet)
3581 fprintf (qh ferr, "qh_check_maxout: p%d is %.2g above f%d\n",
3582 qh_pointid (point), dist, bestfacet->id);
3583 }
3584 }
3585 qh_settempfree (&vertices);
3586 qh_settempfree (&facets);
3587 wmax_(Wmaxoutside, qh max_outside);
3588 qh max_outside= maxoutside;
3589 trace1((qh ferr, "qh_check_maxout: maxoutside %2.2g outside of not good %d\n",
3590 maxoutside, notgood));
3591 } /* check_maxout */
3592
3593 /*----------------------------------------
3594 -check_output- performs the checks at the end of qhull algorithm
3595 does not check points (may take a long time)
3596 */
qh_check_output(void)3597 void qh_check_output (void) {
3598 int i;
3599
3600 if (qh STOPcone)
3601 return;
3602 if (qh VERIFYoutput | qh IStracing | qh CHECKfrequently) {
3603 qh_checkpolygon (qh facet_list);
3604 qh_checkflipped_all (qh facet_list);
3605 qh_checkconvex(qh facet_list, qh_ALGORITHMfault);
3606 }else if (!qh MERGING && qh_newstats (qhstat precision, &i)) {
3607 qh_checkflipped_all (qh facet_list);
3608 qh_checkconvex (qh facet_list, qh_ALGORITHMfault);
3609 }
3610 } /* check_output */
3611
3612
3613
3614 /*-------------------------------------------------------------
3615 -check_point- check that point is not outside facet
3616 if maxerror, doesn't report an error
3617 */
qh_check_point(pointT * point,facetT * facet,realT * maxoutside,facetT ** errfacet1,facetT ** errfacet2)3618 void qh_check_point (pointT *point, facetT *facet, realT *maxoutside, facetT **errfacet1, facetT **errfacet2) {
3619 realT dist;
3620
3621 zinc_(Zverifypart);
3622 qh_distplane(point, facet, &dist);
3623 if (dist > *maxoutside) {
3624 *errfacet2= *errfacet1;
3625 *errfacet1= facet;
3626 fprintf(qh ferr, "qhull precision error: point p%d is outside facet f%d, distance = %6.8g maxoutside= %6.8g\n",
3627 qh_pointid(point), facet->id, dist, *maxoutside);
3628 }
3629 } /* qh_check_point */
3630
3631
3632 /*-------------------------------------------------
3633 -check_points- checks that all points are inside all facets
3634 uses findbest if lots of points
3635 ignores flipped facets
3636 */
qh_check_points(void)3637 void qh_check_points (void) {
3638 facetT *facet, *errfacet1= NULL, *errfacet2= NULL;
3639 realT total, maxoutside;
3640 pointT *point, **pointp, *pointtemp;
3641
3642 maxoutside= fmax_(qh max_outside, qh DISTround);
3643 maxoutside += 2* qh DISTround;
3644 /* 1 DISTround to actual point and another DISTround to computed point */
3645 if (qh RANDOMdist) /* repeated computations can differ by 2*distround */
3646 maxoutside += qh DISTround;
3647 trace1((qh ferr, "qh_check_points: check all points below %2.2g of all facet planes\n",
3648 maxoutside));
3649 if (qh num_good)
3650 total= (float) qh num_good * qh num_points;
3651 else
3652 total= (float) qh num_facets * qh num_points;
3653 if (total >= qh_VERIFYdirect && !qh MERGING) /* MERGING qh_check_maxout */
3654 qh_check_bestdist();
3655 else {
3656 if (!qh_QUICKhelp && qh PRINTprecision) { /* miss counts other_points and !good facets */
3657 if (qh PREmerge && !qh KEEPcoplanar && zzval_(Zcoplanarpart) > 10)
3658 fprintf (qh ferr, "\n\
3659 qhull input warning: pre-merging ('C-n' or 'A-n') without retaining coplanar\n\
3660 points ('Qc'). Verify may report that an outer plane is incorrect.\n");
3661 fprintf (qh ferr, "\n\
3662 Output completed. Verifying that all points are below %2.2g of\n\
3663 all %sfacets. Will make %2.0f distance computations.\n",
3664 maxoutside, (qh ONLYgood ? "good " : ""), total);
3665 }
3666 FORALLfacets {
3667 if (!facet->good && qh ONLYgood)
3668 continue;
3669 if (facet->flipped)
3670 continue;
3671 #if qh_MAXoutside
3672 maxoutside= facet->maxoutside + 2* qh DISTround;
3673 /* 1 DISTround to actual point and another DISTround to computed point */
3674 #endif
3675 FORALLpoints {
3676 if (point != qh GOODpointp)
3677 qh_check_point (point, facet, &maxoutside, &errfacet1, &errfacet2);
3678 }
3679 FOREACHpoint_(qh other_points) {
3680 if (point != qh GOODpointp)
3681 qh_check_point (point, facet, &maxoutside, &errfacet1, &errfacet2);
3682 }
3683 }
3684
3685 if (errfacet1) qhull_fatal(36);
3686
3687 }
3688 } /* check_points */
3689
3690
3691 /*-------------------------------------------------
3692 -checkconvex- check that each ridge in facetlist is convex
3693 returns:
3694 counts Zconcaveridges and Zcoplanarridges
3695 errors if concaveridge or if merging an coplanar ridge
3696 note:
3697 optimized for simplicial facets
3698 */
qh_checkconvex(facetT * facetlist,int fault)3699 void qh_checkconvex(facetT *facetlist, int fault) {
3700 facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL;
3701 vertexT *vertex;
3702 realT dist;
3703 pointT *centrum;
3704 boolT waserror= False;
3705 int neighbor_i;
3706
3707 trace1((qh ferr, "qh_checkconvex: check all ridges are convex\n"));
3708 zzval_(Zconcaveridges)= 0;
3709 zzval_(Zcoplanarridges)= 0;
3710 FORALLfacet_(facetlist) {
3711 if (facet->flipped) {
3712 fprintf (qh ferr, "qhull precision error: f%d is flipped (interior point is outside)\n",
3713 facet->id);
3714 errfacet1= facet;
3715 waserror= True;
3716 continue;
3717 }
3718 if (!qh MERGING) { /* simplicial facet */
3719 neighbor_i= 0;
3720 FOREACHneighbor_(facet) {
3721 vertex= (vertexT *)SETelem_(facet->vertices, neighbor_i++);
3722 zzinc_(Zdistconvex);
3723 qh_distplane (vertex->point, neighbor, &dist);
3724 if (dist > -qh DISTround) {
3725
3726 if (fault == qh_DATAfault) qhull_fatal(37);
3727
3728 if (dist > qh DISTround) {
3729 zzinc_(Zconcaveridges);
3730 fprintf (qh ferr, "qhull precision error: f%d is concave to f%d, since p%d (v%d) is %6.4g above\n",
3731 facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist);
3732 errfacet1= facet;
3733 errfacet2= neighbor;
3734 waserror= True;
3735 }else {
3736 zzinc_(Zcoplanarridges);
3737 trace0((qh ferr, "qhull precision error: f%d may be coplanar to f%d, since p%d (v%d) is within %6.4g\n",
3738 facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist));
3739 }
3740 }
3741 }
3742 }else { /* qh MERGING */
3743 if (qh CENTERtype == qh_centrum) {
3744 if (!facet->center)
3745 facet->center= qh_getcentrum (facet);
3746 centrum= facet->center;
3747 }else
3748 centrum= qh_getcentrum(facet);
3749 FOREACHneighbor_(facet) {
3750 zzinc_(Zdistconvex);
3751 qh_distplane (centrum, neighbor, &dist);
3752 if (dist > qh DISTround) {
3753 zzinc_(Zconcaveridges);
3754 fprintf (qh ferr, "qhull precision error: f%d is concave to f%d, since its centrum is %6.4g above\n",
3755 facet->id, neighbor->id, dist);
3756 errfacet1= facet;
3757 errfacet2= neighbor;
3758 waserror= True;
3759 }else if (dist >= 0.0) { /* if arithmetic always rounds the same,
3760 can test against centrum radius instead */
3761 zzinc_(Zcoplanarridges);
3762 fprintf (qh ferr, "qhull precision error: f%d is coplanar or concave to f%d, since its centrum is %6.4g above\n",
3763 facet->id, neighbor->id, dist);
3764 errfacet1= facet;
3765 errfacet2= neighbor;
3766 waserror= True;
3767 }
3768 }
3769 if (qh CENTERtype != qh_centrum)
3770 qh_memfree(centrum, qh normal_size);
3771 }
3772 }
3773
3774 if (waserror && !qh FORCEoutput) qhull_fatal(38);
3775
3776 } /* checkconvex */
3777
3778
3779 /*-------------------------------------------------
3780 -checkfacet- checks for consistency errors in facet
3781 vertex ids are inverse sorted
3782 unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial)
3783 if non-simplicial, at least as many ridges as neighbors
3784 neighbors are not duplicated
3785 ridges are not duplicated
3786 in 3-d, ridges=verticies
3787 (hull_dim-1) ridge vertices
3788 neighbors are reciprocated
3789 ridge neighbors are facet neighbors and a ridge for every neighbor
3790 simplicial neighbors match facetintersect
3791 vertex intersection matches vertices of common ridges
3792 vertex neighbors and facet vertices agree
3793 sets waserror if any error occurs
3794 uses neighbor->seen
3795 */
qh_checkfacet(facetT * facet,boolT newmerge,boolT * waserrorp)3796 void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp) {
3797 facetT *neighbor, **neighborp, *errother=NULL;
3798 ridgeT *ridge, **ridgep, *errridge= NULL;
3799 vertexT *vertex, **vertexp;
3800 unsigned previousid= INT_MAX;
3801 int numneighbors, numvertices, numridges=0, numRvertices=0;
3802 boolT waserror= False;
3803 int skipA, skipB;
3804 setT *intersection;
3805
3806 if (facet->visible) qhull_fatal(39);
3807
3808 if (!facet->normal) {
3809 fprintf (qh ferr, "qhull internal error (checkfacet): facet f%d does not have a normal\n",
3810 facet->id);
3811 waserror= True;
3812 }
3813 qh_setcheck (facet->vertices, "vertices for f", facet->id);
3814 qh_setcheck (facet->ridges, "ridges for f", facet->id);
3815 qh_setcheck (facet->outsideset, "outsideset for f", facet->id);
3816 qh_setcheck (facet->coplanarset, "coplanarset for f", facet->id);
3817 qh_setcheck (facet->neighbors, "neighbors for f", facet->id);
3818 FOREACHvertex_(facet->vertices) {
3819 if (vertex->deleted) {
3820 fprintf(qh ferr, "qhull internal error (checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id);
3821
3822 /*
3823 qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
3824 NO LONGER IN SERVICE */
3825
3826 waserror= True;
3827 }
3828 if (vertex->id >= previousid) {
3829 fprintf(qh ferr, "qhull internal error (checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id);
3830 waserror= True;
3831 break;
3832 }
3833 previousid= vertex->id;
3834 }
3835 numneighbors= qh_setsize(facet->neighbors);
3836 numvertices= qh_setsize(facet->vertices);
3837 numridges= qh_setsize(facet->ridges);
3838 if (facet->simplicial) {
3839 if (numvertices+numneighbors != 2*qh hull_dim && !qh_facetdegen(facet)) {
3840 fprintf(qh ferr, "qhull internal error (checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n",
3841 facet->id, numvertices, numneighbors);
3842 qh_setprint (qh ferr, "", facet->neighbors);
3843 waserror= True;
3844 }
3845 }else { /* non-simplicial */
3846 if (!newmerge
3847 &&(numvertices < qh hull_dim || numneighbors < qh hull_dim)
3848 && !qh_facetdegen(facet)) {
3849 fprintf(qh ferr, "qhull internal error (checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n",
3850 facet->id, numvertices, numneighbors);
3851 waserror= True;
3852 }
3853 if (numridges < numneighbors
3854 ||(qh hull_dim == 3 && !qh NEWmerges && numvertices != numridges)
3855 ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) {
3856 if (!qh_facetdegen(facet)) {
3857 fprintf(qh ferr, "qhull internal error (checkfacet): for facet f%d, #ridges %d < #neighbors %d or (3-d) != #vertices %d or (2-d) not all 2\n",
3858 facet->id, numridges, numneighbors, numvertices);
3859 waserror= True;
3860 }
3861 }
3862 }
3863 FOREACHneighbor_(facet) {
3864
3865 if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
3866 qhull_fatal(40);
3867
3868 neighbor->seen= True;
3869 }
3870 FOREACHneighbor_(facet) {
3871 if (!qh_setin(neighbor->neighbors, facet)) {
3872 fprintf(qh ferr, "qhull internal error (checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n",
3873 facet->id, neighbor->id, neighbor->id, facet->id);
3874 errother= neighbor;
3875 waserror= True;
3876 }
3877 if (!neighbor->seen) {
3878 fprintf(qh ferr, "qhull internal error (checkfacet): facet f%d has a duplicate neighbor f%d\n",
3879 facet->id, neighbor->id);
3880 errother= neighbor;
3881 waserror= True;
3882 }
3883 neighbor->seen= False;
3884 }
3885 FOREACHridge_(facet->ridges) {
3886 qh_setcheck (ridge->vertices, "vertices for r", ridge->id);
3887 ridge->seen= False;
3888 if (ridge->mergeridge && !newmerge) {
3889 fprintf (qh ferr, "qhull internal error (checkfacet): mergeridge r%d still in facetlist\n", ridge->id);
3890
3891 /*
3892 qh_errprint ("ERRONEOUS", NULL, NULL, ridge, NULL);
3893 NO LONGER IN SERVICE */
3894
3895 waserror= True;
3896 }
3897 }
3898 FOREACHridge_(facet->ridges) {
3899 if (ridge->seen) {
3900 fprintf(qh ferr, "qhull internal error (checkfacet): facet f%d has a duplicate ridge r%d\n",
3901 facet->id, ridge->id);
3902 errridge= ridge;
3903 waserror= True;
3904 }
3905 ridge->seen= True;
3906 numRvertices= qh_setsize(ridge->vertices);
3907 if (numRvertices != qh hull_dim - 1) {
3908 fprintf(qh ferr, "qhull internal error (checkfacet): ridge between f%d and f%d has %d vertices\n",
3909 ridge->top->id, ridge->bottom->id, numRvertices);
3910 errridge= ridge;
3911 waserror= True;
3912 }
3913 neighbor= otherfacet_(ridge, facet);
3914 neighbor->seen= True;
3915 if (!qh_setin(facet->neighbors, neighbor)) {
3916 fprintf(qh ferr, "qhull internal error (checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n",
3917 facet->id, neighbor->id, ridge->id);
3918 errridge= ridge;
3919 waserror= True;
3920 }
3921 }
3922 if (!facet->simplicial) {
3923 FOREACHneighbor_(facet) {
3924 if (!neighbor->seen) {
3925 fprintf(qh ferr, "qhull internal error (checkfacet): facet f%d does not have a ridge for neighbor f%d\n",
3926 facet->id, neighbor->id);
3927 errother= neighbor;
3928 waserror= True;
3929 }
3930 intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices);
3931 qh_settemppush (intersection);
3932 FOREACHvertex_(facet->vertices) {
3933 vertex->seen= False;
3934 vertex->seen2= False;
3935 }
3936 FOREACHvertex_(intersection)
3937 vertex->seen= True;
3938 FOREACHridge_(facet->ridges) {
3939 if (neighbor != otherfacet_(ridge, facet))
3940 continue;
3941 FOREACHvertex_(ridge->vertices) {
3942
3943 if (!vertex->seen) qhull_fatal(41);
3944
3945 vertex->seen2= True;
3946 }
3947 }
3948 if (!newmerge) {
3949 FOREACHvertex_(intersection) {
3950 if (!vertex->seen2) {
3951 if (qh IStracing >=3 || !qh MERGING) {
3952 fprintf (qh ferr, "qhull precision error (checkfacet): vertex v%d in f%d intersect f%d but\n\
3953 not in a ridge. This is ok under merging. Last point was p%d\n",
3954 vertex->id, facet->id, neighbor->id, qh furthest_id);
3955
3956 if (!qh FORCEoutput && !qh MERGING) qhull_fatal(42);
3957
3958 }
3959 }
3960 }
3961 }
3962 qh_settempfree (&intersection);
3963 }
3964 }else { /* simplicial */
3965 FOREACHneighbor_(facet) {
3966 if (neighbor->simplicial) {
3967 skipA= SETindex_(facet->neighbors, neighbor);
3968 skipB= qh_setindex (neighbor->neighbors, facet);
3969 if (!qh_setequal_skip (facet->vertices, skipA, neighbor->vertices, skipB)) {
3970 fprintf (qh ferr, "qhull internal error (checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n",
3971 facet->id, skipA, neighbor->id, skipB);
3972 errother= neighbor;
3973 waserror= True;
3974 }
3975 }
3976 }
3977 }
3978
3979 if (waserror) {
3980
3981 /*
3982 qh_errprint("ERRONEOUS", facet, errother, errridge, NULL);
3983 NO LONGER IN SERVICE */
3984
3985 *waserrorp= True;
3986 }
3987 } /* checkfacet */
3988
3989
3990 /*-------------------------------------------------
3991 -checkflipped- checks facet orientation to interior point
3992 tests against 0 if !allerror since tested against DISTround before
3993 returns:
3994 False if flipped orientation (sets facet->flipped)
3995 distance if non-NULL
3996 */
qh_checkflipped(facetT * facet,realT * distp,boolT allerror)3997 boolT qh_checkflipped (facetT *facet, realT *distp, boolT allerror) {
3998 realT dist;
3999
4000 if (facet->flipped && !distp)
4001 return False;
4002 zzinc_(Zdistcheck);
4003 qh_distplane(qh interior_point, facet, &dist);
4004 if (distp)
4005 *distp= dist;
4006 if ((allerror && dist > -qh DISTround)|| (!allerror && dist >= 0.0)) {
4007 facet->flipped= True;
4008 zzinc_(Zflippedfacets);
4009 trace0((qh ferr, "qh_checkflipped: facet f%d is flipped, distance= %6.12g\n",
4010 facet->id, dist));
4011 return False;
4012 }
4013 return True;
4014 } /* checkflipped */
4015
4016 /*-------------------------------------------------
4017 -checkflipped_all- checks orientation of facets in list against interior point
4018 */
qh_checkflipped_all(facetT * facetlist)4019 void qh_checkflipped_all (facetT *facetlist) {
4020 facetT *facet;
4021 boolT waserror= False;
4022 realT dist;
4023
4024 if (facetlist == qh facet_list)
4025 zzval_(Zflippedfacets)= 0;
4026 FORALLfacet_(facetlist) {
4027 if (!qh_checkflipped (facet, &dist, (boolT)!qh_ALL)) {
4028 fprintf(qh ferr, "qhull precision error: facet f%d is flipped, distance= %6.12g\n",
4029 facet->id, dist);
4030 if (!qh FORCEoutput) {
4031
4032 /*
4033 qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL);
4034 NO LONGER IN SERVICE */
4035
4036 waserror= True;
4037 }
4038 }
4039 }
4040 if (waserror) qhull_fatal(43);
4041
4042 } /* checkflipped_all */
4043
4044 /*-------------------------------------------------
4045 -checkpolygon- checks the correctness of the structure
4046 check num_facets and num_vertices if qh facet_list
4047 call with either qh facet_list or qh newfacet_list
4048 */
qh_checkpolygon(facetT * facetlist)4049 void qh_checkpolygon(facetT *facetlist) {
4050 facetT *facet;
4051 vertexT *vertex, **vertexp, *vertexlist;
4052 int numfacets= 0, numvertices= 0, numridges= 0;
4053 boolT waserror= False, nextseen= False, visibleseen= False;
4054
4055 trace1((qh ferr, "qh_checkpolygon: check all facets from f%d\n", facetlist->id));
4056 if (facetlist != qh facet_list || qh ONLYgood)
4057 nextseen= True;
4058 FORALLfacet_(facetlist) {
4059 if (facet == qh visible_list)
4060 visibleseen= True;
4061 if (!facet->visible) {
4062 if (!nextseen) {
4063 if (facet == qh facet_next)
4064 nextseen= True;
4065 else
4066
4067 if (qh_setsize (facet->outsideset)) qhull_fatal(44);
4068
4069 }
4070 numfacets++;
4071 qh_checkfacet(facet, False, &waserror);
4072 }
4073 }
4074
4075 if (qh visible_list && !visibleseen && facetlist == qh facet_list)
4076 qhull_fatal(45);
4077
4078 if (facetlist == qh facet_list)
4079 vertexlist= qh vertex_list;
4080 else if (facetlist == qh newfacet_list)
4081 vertexlist= qh newvertex_list;
4082 else
4083 vertexlist= NULL;
4084 FORALLvertex_(vertexlist) {
4085 vertex->seen= False;
4086 vertex->visitid= 0;
4087 }
4088 FORALLfacet_(facetlist) {
4089 if (facet->visible)
4090 continue;
4091 if (facet->simplicial)
4092 numridges += qh hull_dim;
4093 else
4094 numridges += qh_setsize (facet->ridges);
4095 FOREACHvertex_(facet->vertices) {
4096 vertex->visitid++;
4097 if (!vertex->seen) {
4098 vertex->seen= True;
4099 numvertices++;
4100 if (qh_pointid (vertex->point) == -1) {
4101 fprintf (qh ferr, "qhull internal error (checkpolygon): unknown point %p for vertex v%d first_point %p\n",
4102 static_cast<void *>(vertex->point), vertex->id,
4103 static_cast<void *>(qh first_point));
4104 waserror= True;
4105 }
4106 }
4107 }
4108 }
4109 qh vertex_visit += numfacets;
4110 if (facetlist == qh facet_list) {
4111 if (numfacets != qh num_facets - qh num_visible) {
4112 fprintf(qh ferr, "qhull internal error (checkpolygon): actual number of facets is %d, cumulative facet count is %d\n",
4113 numfacets, qh num_facets- qh num_visible);
4114 waserror= True;
4115 }
4116 qh vertex_visit++;
4117 if (qh VERTEXneighbors) {
4118 FORALLvertices {
4119 qh_setcheck (vertex->neighbors, "neighbors for v", vertex->id);
4120 if ((int)vertex->visitid != qh vertex_visit && !vertex->deleted) {
4121 if ((int)vertex->visitid != qh_setsize (vertex->neighbors)) {
4122 fprintf (qh ferr, "qhull internal error (checkpolygon): v%d neighbors is wrong, actually in %d facets\n",
4123 vertex->id, vertex->visitid);
4124
4125 /*
4126 qh_errprint ("ERRONEOUS", NULL, NULL, NULL, vertex);
4127 NO LONGER IN SERVICE */
4128
4129 waserror= True;
4130 }
4131 }
4132 }
4133 }
4134 if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) {
4135 fprintf(qh ferr, "qhull internal error (checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n",
4136 numvertices, qh num_vertices - qh_setsize(qh del_vertices));
4137 waserror= True;
4138 }
4139 if (qh hull_dim == 2 && numvertices != numfacets) {
4140 fprintf (qh ferr, "qhull internal error (checkpolygon): #vertices %d != #facets %d\n",
4141 numvertices, numfacets);
4142 waserror= True;
4143 }
4144 if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) {
4145 fprintf (qh ferr, "qhull internal error (checkpolygon): #vertices %d + #facets %d - #edges %d != 2\n",
4146 numvertices, numfacets, numridges/2);
4147 waserror= True;
4148 }
4149 }
4150
4151 if (waserror) qhull_fatal(46);
4152
4153 } /* checkpolygon */
4154
4155
4156 /*-------------------------------------------------
4157 -checkvertex- check vertex for consistency
4158 notes:
4159 neighbors checked efficiently in checkpolygon
4160 */
qh_checkvertex(vertexT * vertex)4161 void qh_checkvertex (vertexT *vertex) {
4162 boolT waserror= False;
4163 facetT *neighbor, **neighborp, *errfacet=NULL;
4164
4165 if (qh_pointid (vertex->point) == -1) {
4166 fprintf (qh ferr, "qhull internal error (checkvertex): unknown point id %p\n",
4167 static_cast<void *>(vertex->point));
4168 waserror= True;
4169 }
4170 if (vertex->id >= qh vertex_id) {
4171 fprintf (qh ferr, "qhull internal error (checkvertex): unknown vertex id %d\n", vertex->id);
4172 waserror= True;
4173 }
4174 if (!waserror && !vertex->deleted) {
4175 FOREACHneighbor_(vertex) {
4176 if (!qh_setin (neighbor->vertices, vertex)) {
4177 fprintf (qh ferr, "qhull internal error (checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id);
4178 errfacet= neighbor;
4179 waserror= True;
4180 }
4181 }
4182 }
4183
4184 if (waserror) qhull_fatal(47);
4185
4186 } /* checkvertex */
4187
4188 /*-------------------------------------------------
4189 -clearcenters- clear old data from facet->center
4190 sets new centertype
4191 nop if CENTERtype is the same
4192 */
qh_clearcenters(int type)4193 void qh_clearcenters (int type) {
4194 facetT *facet;
4195
4196 if (qh CENTERtype != type) {
4197 FORALLfacets {
4198 if (facet->center) {
4199 if (qh CENTERtype == qh_voronoi)
4200 qh_memfree (facet->center, qh center_size);
4201 else
4202 qh_memfree (facet->center, qh normal_size);
4203 facet->center= NULL;
4204 }
4205 }
4206 qh CENTERtype= type;
4207 }
4208 trace2((qh ferr, "clearcenters: switched to center type %d\n", type));
4209 } /* clearcenters */
4210
4211 /*-------------------------------------------------
4212 -clearnewvertices- clear vertices from newvertex_list
4213 */
qh_clearnewvertices(void)4214 void qh_clearnewvertices (void /*qh newvertex_list*/) {
4215 vertexT *vertex;
4216
4217 FORALLvertex_(qh newvertex_list)
4218 vertex->newlist= False;
4219 qh newvertex_list= NULL;
4220 } /* clearnewvertices */
4221
4222 /*-------------------------------------------------
4223 -clearvisible- clear facets from visible list
4224 resets NEWfacets
4225 */
qh_clearvisible(void)4226 void qh_clearvisible (void /*qh visible_list*/) {
4227 facetT *visible;
4228
4229 FORALLvisible_facets
4230 visible->visible= False;
4231 qh num_visible= 0;
4232 qh visible_list= NULL;
4233 qh NEWfacets= False;
4234 } /* clearvisible */
4235
4236 /*----------------------------------------
4237 -createsimplex- creates a simplex from a set of vertices
4238 returns:
4239 initializes qh facet_list to the simplex
4240 */
qh_createsimplex(setT * vertices)4241 void qh_createsimplex(setT *vertices) {
4242 facetT *facet= NULL, *newfacet;
4243 boolT toporient= True;
4244 int vertex_i, vertex_n, nth, tempint;
4245 setT *newfacets= qh_settemp (qh hull_dim+1);
4246 vertexT *vertex;
4247
4248 qh facet_list= qh newfacet_list= qh facet_tail= qh_newfacet();
4249 qh vertex_list= qh newvertex_list= qh vertex_tail= qh_newvertex(NULL);
4250 FOREACHvertex_i_(vertices) {
4251 newfacet= qh_newfacet();
4252 newfacet->vertices= qh_setnew_delnthsorted (vertices, vertex_n,
4253 vertex_i, 0);
4254 newfacet->toporient= toporient;
4255 qh_appendfacet(newfacet);
4256 qh_appendvertex (vertex);
4257 qh_setappend (&newfacets, newfacet);
4258 tempint = (int)toporient;
4259 tempint ^= True;
4260 toporient = (boolT)tempint;
4261 }
4262 FORALLnew_facets {
4263 nth= 0;
4264 FORALLfacet_(qh newfacet_list) {
4265 if (facet != newfacet)
4266 SETelem_(newfacet->neighbors, nth++)= facet;
4267 }
4268 qh_settruncate (newfacet->neighbors, qh hull_dim);
4269 }
4270 qh_settempfree (&newfacets);
4271 trace1((qh ferr, "qh_createsimplex: created simplex\n"));
4272 } /* createsimplex */
4273
4274
4275 /*-------------------------------------------------
4276 -deletevisible- delete visible facets
4277 ridges and vertices already deleted
4278 horizon facets do not reference facets on qh visible_list
4279 new facets in qh newfacet_list
4280 returns:
4281 deletes each facet and removes from facetlist
4282 calls qh_clearvisible()
4283 uses qh visit_id;
4284 */
qh_deletevisible()4285 void qh_deletevisible (/*qh visible_list*/) {
4286 facetT *visible, *nextfacet;
4287 vertexT *vertex, **vertexp;
4288 int numvisible= 0;
4289
4290 trace1((qh ferr, "qh_deletevisible: delete visible facets\n"));
4291 for (visible= qh visible_list; visible && visible->visible;
4292 visible= nextfacet) { /* deleting current */
4293 nextfacet= visible->next;
4294 numvisible++;
4295 qh_delfacet(visible);
4296 }
4297
4298 if (numvisible != qh num_visible) qhull_fatal(48);
4299
4300 FOREACHvertex_(qh del_vertices)
4301 qh_delvertex (vertex);
4302 qh_settruncate (qh del_vertices, 0);
4303 qh_clearvisible();
4304 } /* deletevisible */
4305
4306
4307 /*-------------------------------------------------
4308 -delfacet- removes facet from facet_list and frees up its memory
4309 assumes vertices and ridges already freed
4310 */
qh_delfacet(facetT * facet)4311 void qh_delfacet(facetT *facet) {
4312 void **freelistp;
4313
4314 trace5((qh ferr, "qh_delfacet: delete f%d\n", facet->id));
4315 if (facet == qh tracefacet)
4316 qh tracefacet= NULL;
4317 qh_removefacet(facet);
4318 qh_memfree_(facet->normal, qh normal_size, freelistp);
4319 if (qh CENTERtype == qh_voronoi) {
4320 qh_memfree_(facet->center, qh center_size, freelistp);
4321 }else {
4322 qh_memfree_(facet->center, qh normal_size, freelistp);
4323 }
4324 qh_setfree(&(facet->neighbors));
4325 if (facet->ridges)
4326 qh_setfree(&(facet->ridges));
4327 qh_setfree(&(facet->vertices));
4328 if (facet->outsideset)
4329 qh_setfree(&(facet->outsideset));
4330 if (facet->coplanarset)
4331 qh_setfree(&(facet->coplanarset));
4332 qh_memfree_(facet, sizeof(facetT), freelistp);
4333 } /* delfacet */
4334
4335
4336 /*-------------------------------------------------
4337 -delridge- deletes ridge from data structures it belongs to and frees up the
4338 memory occupied by it
4339 notes:
4340 in merge.c, caller sets vertex->delridge for each vertex
4341 also freed in qh_freeqhull
4342 */
qh_delridge(ridgeT * ridge)4343 void qh_delridge(ridgeT *ridge) {
4344 void **freelistp;
4345
4346 qh_setdel(ridge->top->ridges, ridge);
4347 qh_setdel(ridge->bottom->ridges, ridge);
4348 qh_setfree(&(ridge->vertices));
4349 qh_memfree_(ridge, sizeof(ridgeT), freelistp);
4350 } /* delridge */
4351
4352
4353 /*-------------------------------------------------
4354 -delvertex- deletes a vertex and frees its memory
4355 assumes vertex->adjacencies have been updated if needed
4356 unlinks for vertex_list
4357 */
qh_delvertex(vertexT * vertex)4358 void qh_delvertex (vertexT *vertex) {
4359
4360 if (vertex == qh tracevertex)
4361 qh tracevertex= NULL;
4362 qh_removevertex (vertex);
4363 qh_setfree (&vertex->neighbors);
4364 qh_memfree(vertex, sizeof(vertexT));
4365 } /* delvertex */
4366
4367
4368 /*----------------------------------------
4369 -facet3vertex- return temporary set of 3-d vertices
4370 in qh_ORIENTclock order
4371 */
qh_facet3vertex(facetT * facet)4372 setT *qh_facet3vertex (facetT *facet) {
4373 ridgeT *ridge, *firstridge;
4374 vertexT *vertex;
4375 int cntvertices, cntprojected=0;
4376 setT *vertices;
4377
4378 cntvertices= qh_setsize(facet->vertices);
4379 vertices= qh_settemp (cntvertices);
4380 if (facet->simplicial) {
4381
4382 if (cntvertices != 3) qhull_fatal(49);
4383
4384 qh_setappend (&vertices, SETfirst_(facet->vertices));
4385 if (facet->toporient ^ qh_ORIENTclock)
4386 qh_setappend (&vertices, SETsecond_(facet->vertices));
4387 else
4388 qh_setaddnth (&vertices, 0, SETsecond_(facet->vertices));
4389 qh_setappend (&vertices, SETelem_(facet->vertices, 2));
4390 }else {
4391 ridge= firstridge= (ridgeT *)SETfirst_(facet->ridges); /* no infinite */
4392 while ((ridge= qh_nextridge3d (ridge, facet, &vertex))) {
4393 qh_setappend (&vertices, vertex);
4394 if (++cntprojected > cntvertices || ridge == firstridge)
4395 break;
4396 }
4397
4398 if (!ridge || cntprojected != cntvertices) qhull_fatal(50);
4399
4400 }
4401 return vertices;
4402 } /* facet3vertex */
4403
4404
4405 /*-------------------------------------------------
4406 -facetintersect- return vertices for intersection of two simplicial facets
4407 may include 1 prepended entry (if more, need to settemppush)
4408 returns:
4409 returns set of hull_dim-1 + optional extra
4410 returns skipped index for each test and checks for exactly one
4411 notes:
4412 does not need settemp since set in quick memory
4413 see also qh_vertexintersect and qh_vertexintersect_new
4414 use qh_setnew_delnthsorted to get nth ridge (no skip information)
4415 */
qh_facetintersect(facetT * facetA,facetT * facetB,int * skipA,int * skipB,int prepend)4416 setT *qh_facetintersect (facetT *facetA, facetT *facetB,
4417 int *skipA,int *skipB, int prepend) {
4418 setT *intersect;
4419 int dim= qh hull_dim, i, j;
4420 facetT **neighborsA, **neighborsB;
4421
4422 neighborsA= SETaddr_(facetA->neighbors, facetT);
4423 neighborsB= SETaddr_(facetB->neighbors, facetT);
4424 i= j= 0;
4425 if (facetB == *neighborsA++)
4426 *skipA= 0;
4427 else if (facetB == *neighborsA++)
4428 *skipA= 1;
4429 else if (facetB == *neighborsA++)
4430 *skipA= 2;
4431 else {
4432 for (i= 3; i < dim; i++) {
4433 if (facetB == *neighborsA++) {
4434 *skipA= i;
4435 break;
4436 }
4437 }
4438 }
4439 if (facetA == *neighborsB++)
4440 *skipB= 0;
4441 else if (facetA == *neighborsB++)
4442 *skipB= 1;
4443 else if (facetA == *neighborsB++)
4444 *skipB= 2;
4445 else {
4446 for (j= 3; j < dim; j++) {
4447 if (facetA == *neighborsB++) {
4448 *skipB= j;
4449 break;
4450 }
4451 }
4452 }
4453
4454 if (i >= dim || j >= dim) qhull_fatal(51);
4455
4456 intersect= qh_setnew_delnthsorted (facetA->vertices, qh hull_dim, *skipA, prepend);
4457 trace4((qh ferr, "qh_facetintersect: f%d skip %d matches f%d skip %d\n",
4458 facetA->id, *skipA, facetB->id, *skipB));
4459 return(intersect);
4460 } /* facetintersect */
4461
4462
4463 /*----------------------------------------
4464 -gethash- return hashvalue for a set with firstindex and skipelem
4465 assumes at least firstindex+1 elements
4466 sum of elements does badly in high d
4467 assumes skipelem is NULL, in set, or part of hash
4468 */
qh_gethash(int hashsize,setT * set,int size,int firstindex,void * skipelem)4469 unsigned qh_gethash (int hashsize, setT *set, int size, int firstindex, void *skipelem) {
4470 void **elemp= SETelemaddr_(set, firstindex, void);
4471 unsigned hash, elem;
4472 int i;
4473
4474 switch (size-firstindex) {
4475 case 1:
4476 hash= (unsigned long)(*elemp) - (unsigned long) skipelem;
4477 break;
4478 case 2:
4479 hash= (unsigned long)(*elemp) + (unsigned long)elemp[1] - (unsigned long) skipelem;
4480 break;
4481 case 3:
4482 hash= (unsigned long)(*elemp) + (unsigned long)elemp[1] + (unsigned long)elemp[2]
4483 - (unsigned long) skipelem;
4484 break;
4485 case 4:
4486 hash= (unsigned long)(*elemp) + (unsigned long)elemp[1] + (unsigned long)elemp[2]
4487 + (unsigned long)elemp[3] - (unsigned long) skipelem;
4488 break;
4489 case 5:
4490 hash= (unsigned long)(*elemp) + (unsigned long)elemp[1] + (unsigned long)elemp[2]
4491 + (unsigned long)elemp[3] + (unsigned long)elemp[4] - (unsigned long) skipelem;
4492 break;
4493 case 6:
4494 hash= (unsigned long)(*elemp) + (unsigned long)elemp[1] + (unsigned long)elemp[2]
4495 + (unsigned long)elemp[3] + (unsigned long)elemp[4]+ (unsigned long)elemp[5]
4496 - (unsigned long) skipelem;
4497 break;
4498 default:
4499 hash= 0;
4500 i= 3;
4501 do { /* this is about 10% in 10-d */
4502 if ((elem= (unsigned long)*elemp++) != (unsigned long)skipelem) {
4503 hash ^= (elem << i) + (elem >> (32-i));
4504 i += 3;
4505 if (i >= 32)
4506 i -= 32;
4507 }
4508 }while(*elemp);
4509 break;
4510 }
4511 hash %= (unsigned) hashsize;
4512 /* hash= 0; for debugging purposes */
4513 return hash;
4514 } /* gethash */
4515
4516 /*-------------------------------------------------
4517 -isvertex- returns vertex if point is in vertex set, else returns NULL
4518 */
qh_isvertex(pointT * point,setT * vertices)4519 vertexT *qh_isvertex (pointT *point, setT *vertices) {
4520 vertexT *vertex, **vertexp;
4521
4522 FOREACHvertex_(vertices) {
4523 if (vertex->point == point)
4524 return vertex;
4525 }
4526 return NULL;
4527 } /* isvertex */
4528
4529
4530 /*-------------------------------------------------
4531 -makenewfacet- creates a toporient? facet from vertices and apex
4532 modifies vertices
4533 returns:
4534 adds newfacet to qh facet_list
4535 facet->neighbor= horizon, but not vice versa
4536 facet->vertices= vertices= apex+vertices
4537 facet->hyperplane defined
4538 newvertex_list updated
4539 */
qh_makenewfacet(setT * vertices,boolT toporient,facetT * horizon)4540 facetT *qh_makenewfacet(setT *vertices, boolT toporient,facetT *horizon) {
4541 facetT *newfacet;
4542 vertexT *vertex, **vertexp;
4543
4544 FOREACHvertex_(vertices) {
4545 if (!vertex->newlist) {
4546 vertex->newlist= True;
4547 qh_removevertex (vertex);
4548 qh_appendvertex (vertex);
4549 }
4550 }
4551 newfacet= qh_newfacet();
4552 newfacet->vertices= vertices;
4553 newfacet->toporient= toporient;
4554 qh_setfacetplane (newfacet);
4555 qh_setappend(&(newfacet->neighbors), horizon);
4556 qh_appendfacet(newfacet);
4557 return(newfacet);
4558 } /* makenewfacet */
4559
4560
4561 /*-------------------------------------------------
4562 -makenewfacets- make new facets from point and qh visible_list
4563 returns:
4564 qh newfacet_list= list of new facets with hyperplanes and id >= newfacet_id
4565 qh newvertex_list= list of vertices in new facets with 'new' set
4566 if (qh ONLYgood)
4567 newfacets reference horizon facets, but not vice versa
4568 ridges reference non-simplicial horizon ridges, but not vice versa
4569 does not change existing facets
4570 otherwise
4571 newfacets attached to horizon facets and ridges
4572 first neighbor of visible facet is corresponding new facet
4573 */
qh_makenewfacets(pointT * point)4574 vertexT *qh_makenewfacets (pointT *point /*visible_list*/) {
4575 facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp;
4576 vertexT *apex;
4577 int numnew=0;
4578
4579 qh newfacet_list= qh facet_tail;
4580 qh newvertex_list= qh vertex_tail;
4581 qh newfacet_id= qh facet_id;
4582 apex= qh_newvertex(point);
4583 apex->newlist= True;
4584 qh_appendvertex (apex);
4585 qh visit_id++;
4586 if (!qh ONLYgood)
4587 qh NEWfacets= True;
4588 FORALLvisible_facets {
4589 FOREACHneighbor_(visible)
4590 neighbor->seen= False;
4591 if (visible->ridges) {
4592 visible->visitid= qh visit_id;
4593 newfacet2= qh_makenew_nonsimplicial (visible, apex, &numnew);
4594 }
4595 if (visible->simplicial)
4596 newfacet= qh_makenew_simplicial (visible, apex, &numnew);
4597 if (!qh ONLYgood) {
4598 if (newfacet2)
4599 newfacet= newfacet2;
4600 if (!newfacet)
4601 zinc_(Zinsidevisible);
4602 SETfirst_(visible->neighbors)= newfacet;
4603 SETsecond_(visible->neighbors)= NULL;
4604 }
4605 }
4606 trace1((qh ferr, "qh_makenewfacets: created %d new facets from point p%d to horizon\n",
4607 numnew, qh_pointid(point)));
4608
4609 /*
4610 if (qh IStracing >= 4)
4611 qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
4612 THIS IS NO LONGER IN SERVICE */
4613
4614 return apex;
4615 } /* makenewfacets */
4616
4617 /*---------------------------------------------
4618 -makenew_nonsimplicial- make new facets for ridges of visible facets
4619 qh visit_id if visible has already been seen
4620 attaches new facets if !qh ONLY good
4621 assumes all 'seen' flags false
4622 returns:
4623 newfacet or NULL, bumps numnew as needed
4624 marks ridge neighbors for simplicial visible
4625 if (qh ONLYgood)
4626 ridges on newfacet, horizon, and visible
4627 else
4628 ridge and neighbors between newfacet and horizon
4629 visible facet's ridges are deleted
4630 */
qh_makenew_nonsimplicial(facetT * visible,vertexT * apex,int * numnew)4631 facetT *qh_makenew_nonsimplicial (facetT *visible, vertexT *apex, int *numnew) {
4632 void **freelistp;
4633 ridgeT *ridge, **ridgep;
4634 facetT *neighbor, *newfacet= NULL;
4635 setT *vertices;
4636 boolT toporient = False;
4637
4638 FOREACHridge_(visible->ridges) {
4639 neighbor= otherfacet_(ridge, visible);
4640 if (neighbor->visible) {
4641 if (!qh ONLYgood) {
4642 if ((int)neighbor->visitid == qh visit_id) {
4643 qh_setfree (&(ridge->vertices)); /* delete on 2nd visit */
4644 qh_memfree_(ridge, sizeof(ridgeT), freelistp);
4645 }
4646 }
4647 }else { /* neighbor is an horizon facet */
4648 toporient= (boolT)(ridge->top == visible);
4649 vertices= qh_setnew (qh hull_dim); /* makes sure this is quick */
4650 qh_setappend (&vertices, apex);
4651 qh_setappend_set (&vertices, ridge->vertices);
4652 newfacet= qh_makenewfacet(vertices, toporient, neighbor);
4653 (*numnew)++;
4654 if (qh ONLYgood) {
4655 if (!neighbor->simplicial)
4656 qh_setappend(&(newfacet->ridges), ridge);
4657 }else { /* qh_attachnewfacets */
4658 if (neighbor->seen) {
4659
4660 if (neighbor->simplicial) qhull_fatal(52);
4661
4662 qh_setappend (&(neighbor->neighbors), newfacet);
4663 }else
4664 qh_setreplace (neighbor->neighbors, visible, newfacet);
4665 if (neighbor->simplicial) {
4666 qh_setdel (neighbor->ridges, ridge);
4667 qh_setfree (&(ridge->vertices));
4668 qh_memfree (ridge, sizeof(ridgeT));
4669 }else {
4670 qh_setappend(&(newfacet->ridges), ridge);
4671 if (toporient)
4672 ridge->top= newfacet;
4673 else
4674 ridge->bottom= newfacet;
4675 }
4676 trace4((qh ferr, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n",
4677 newfacet->id, apex->id, ridge->id, neighbor->id));
4678 }
4679 }
4680 neighbor->seen= True;
4681 } /* for each ridge */
4682 if (!qh ONLYgood)
4683 SETfirst_(visible->ridges)= NULL;
4684 return newfacet;
4685 } /* makenew_nonsimplicial */
4686
4687 /*---------------------------------------------
4688 -makenew_simplicial- make new facets for simplicial facet
4689 uses 'seen' flag
4690 attaches new facets if !qh ONLY good
4691 returns:
4692 newfacet or NULL, bumps numnew as needed
4693 if (!qh ONLYgood)
4694 neighbors between newfacet and horizon
4695 */
qh_makenew_simplicial(facetT * visible,vertexT * apex,int * numnew)4696 facetT *qh_makenew_simplicial (facetT *visible, vertexT *apex, int *numnew) {
4697 facetT *neighbor, **neighborp, *newfacet= NULL;
4698 setT *vertices;
4699 boolT flip, toporient;
4700 int horizonskip, visibleskip;
4701
4702 FOREACHneighbor_(visible) {
4703 if (!neighbor->seen && !neighbor->visible) {
4704 vertices= qh_facetintersect(neighbor,visible, &horizonskip, &visibleskip, 1);
4705 SETfirst_(vertices)= apex;
4706 flip= (boolT) ((horizonskip & 0x1) ^ (visibleskip & 0x1));
4707 toporient=(boolT)( neighbor->toporient ^ !(horizonskip & 0x1) );
4708 newfacet= qh_makenewfacet(vertices, toporient, neighbor);
4709 (*numnew)++;
4710 if (!qh ONLYgood)
4711 SETelem_(neighbor->neighbors, horizonskip)= newfacet;
4712 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",
4713 newfacet->id, toporient, apex->id, neighbor->id, horizonskip,
4714 neighbor->toporient, visible->id, visibleskip, flip));
4715 }
4716 }
4717 return newfacet;
4718 } /* makenew_simplicial */
4719
4720 /*-------------------------------------------------
4721 -matchduplicate- try to match an unmatched duplicated ridge
4722 returns:
4723 True if a match was made
4724 notes:
4725 found matching facet for a duplicate ridge.
4726 1) if keep already found, merge this pair
4727 2) if !flip&!flip, keep this
4728 3) if flip & flip, merge this pair
4729 4) otherwise, return False and continue
4730 */
qh_matchduplicate(facetT * facet,int skip,facetT * newfacet,int newskip,boolT keepfound)4731 boolT qh_matchduplicate (facetT *facet, int skip, facetT *newfacet, int newskip, boolT keepfound) {
4732 boolT ismatched= False;
4733
4734 trace2((qh ferr, "qh_matchduplicate: duplicated f%d skip %d matches new f%d skip %d. ",
4735 facet->id, skip, newfacet->id, newskip));
4736 if (keepfound) {
4737 SETelem_(facet->neighbors, skip)= newfacet;
4738 if (qh PREmerge)
4739 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
4740 else
4741 SETelem_(newfacet->neighbors, newskip)= facet;
4742 trace2((qh ferr, "Merge this pair.\n"));
4743 ismatched= True;
4744 }else if (!facet->flipped && !newfacet->flipped) {
4745 SETelem_(facet->neighbors, skip)= newfacet;
4746 SETelem_(newfacet->neighbors, newskip)= facet;
4747 trace2((qh ferr, "Match good pair\n"));
4748 ismatched= True;
4749 }else if (facet->flipped && newfacet->flipped) {
4750 SETelem_(facet->neighbors, skip)= newfacet;
4751 if (qh PREmerge)
4752 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
4753 else
4754 SETelem_(newfacet->neighbors, newskip)= facet;
4755 trace2((qh ferr, "Merge flipped pair\n"));
4756 ismatched= True;
4757 }else
4758 trace2((qh ferr, "No match, continue\n"));
4759 if (qh IStracing >= 4) {
4760
4761 /*
4762 qh_errprint ("OLD/NEW", facet, newfacet, NULL, NULL);
4763 NO LONGER IN SERVICE */
4764
4765 qh_setprint (qh ferr, "facet's neighbors", facet->neighbors);
4766 qh_setprint (qh ferr, "newfacet's", newfacet->neighbors);
4767 }
4768 return ismatched;
4769 } /* matchduplicate */
4770
4771 /*--------------------------------------------
4772 -matchmatch- try to match duplicate matching pair and newfacet
4773 returns:
4774 True if existing match is ok and continue with newfacet
4775 False if need to place matchfacet
4776 newmatched set if newfacet matched
4777 notes:
4778 1) if pair is !flip&!flip, keep is found and continue
4779 2) if pair is flip&flip, merge them and continue
4780 3) otherwise, replace matchfacet
4781 if new pair is !flip&!flip, keep is found
4782 if new pair is flip&flip, merge them
4783 otherwise, mark duplicated and continue
4784 */
qh_matchmatch(facetT * facet,int skip,facetT * matchfacet,facetT * newfacet,int newskip,boolT ismatch,boolT * keepfound,boolT * newmatched)4785 boolT qh_matchmatch (facetT *facet, int skip, facetT *matchfacet, facetT *newfacet,
4786 int newskip, boolT ismatch, boolT *keepfound, boolT *newmatched) {
4787 int matchskip;
4788 boolT ismatched= False;
4789
4790 matchskip= qh_setindex (matchfacet->neighbors, facet);
4791 trace2((qh ferr, "qh_matchmatch: duplicated f%d skip %d matches f%d skip %d and new f%d skip %d. ",
4792 facet->id, skip, matchfacet->id, matchskip, newfacet->id, newskip));
4793 if (!facet->flipped && !matchfacet->flipped) {
4794 *keepfound= True;
4795 trace2((qh ferr, "Keep good match\n"));
4796 ismatched= True;
4797 }else if (facet->flipped && matchfacet->flipped) {
4798 if (matchskip >= 0 && qh PREmerge)
4799 SETelem_(matchfacet->neighbors, matchskip)= qh_MERGEridge;
4800 trace2((qh ferr, "Both flipped, merge\n"));
4801 ismatched= True;
4802 }else {
4803 /* matched facets have opposite orientations, undo matchfacet */
4804 SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge;
4805 if (ismatch && (facet->flipped == newfacet->flipped)) {
4806 SETelem_(facet->neighbors, skip)= newfacet;
4807 if (newfacet->flipped && qh PREmerge)
4808 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
4809 else
4810 SETelem_(newfacet->neighbors, newskip)= facet;
4811 trace2((qh ferr, "Substitute new\n"));
4812 *newmatched= True;
4813 }else {
4814 SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge;
4815 *newmatched= False;
4816 trace2((qh ferr, "Undo match\n"));
4817 }
4818 }
4819 if (qh IStracing >= 4) {
4820
4821 /*
4822 qh_errprint ("OLD/MATCH", facet, matchfacet, NULL, NULL);
4823 qh_errprint ("NEW", newfacet, NULL, NULL, NULL);
4824 NO LONGER IN SERVICE */
4825
4826 qh_setprint (qh ferr, "facet's neighbors", facet->neighbors);
4827 qh_setprint (qh ferr, "matchfacet's", matchfacet->neighbors);
4828 qh_setprint (qh ferr, "newfacet's", newfacet->neighbors);
4829 }
4830 return ismatched;
4831 } /* qh_matchmatch */
4832
4833 /*-------------------------------------------------
4834 -matchneighbor- match subridge of newfacet with neighbor or add to hash_table
4835 ridge is newfacet->vertices w/o newskip vertex
4836 flipped tested if PREmerge or FORCEoutput
4837 use matchall to match unmatched duplicates
4838 returns:
4839 at end of matching duplicate ridges,
4840 one !flipped,!flipped matched
4841 flipped,flipped matched with MERGEridge back pointers
4842 rest are unmatched, with a DUPLICATEridge link
4843 all facets involved have seen set and flip tested
4844 notes:
4845 do not allocate memory (need to free hash_table cleanly)
4846 matches flipped,flipped since these get merged anyway
4847 uses linear hash chains
4848 */
qh_matchneighbor(facetT * newfacet,int newskip,int hashsize,int * hashcount,boolT matchall)4849 void qh_matchneighbor (facetT *newfacet, int newskip, int hashsize, int *hashcount, boolT matchall) {
4850 boolT keepfound= False; /* True, if !flip,!flip duplicate ridge found */
4851 boolT duplicated= False; /* True, if duplicate ridge detected */
4852 boolT newfound= False; /* True, if new facet is already in hash chain */
4853 boolT same, ismatch, newmatched;
4854 unsigned hash, scan;
4855 facetT *facet, *matchfacet;
4856 int skip;
4857
4858 hash= qh_gethash (hashsize, newfacet->vertices, qh hull_dim, 1,
4859 SETelem_(newfacet->vertices, newskip));
4860 trace4((qh ferr, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n",
4861 newfacet->id, newskip, hash, *hashcount));
4862 zinc_(Zhashlookup);
4863 while ((facet= (facetT *)SETelem_(qh hash_table, hash))) {
4864 if (facet == newfacet) {
4865 newfound= True;
4866 goto LABELnexthash;
4867 }
4868 zinc_(Zhashtests);
4869 if (qh_matchvertices (1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) {
4870
4871 if (SETelem_(newfacet->vertices, newskip) ==
4872 SETelem_(facet->vertices, skip))
4873 qhull_fatal(53);
4874
4875 ismatch=
4876 (boolT) (same == (int)(newfacet->toporient ^ facet->toporient));
4877 matchfacet= (facetT *)SETelem_(facet->neighbors, skip);
4878 if (matchfacet == qh_MERGEridge)
4879 goto LABELnexthash;
4880 else if (matchfacet == qh_DUPLICATEridge) {
4881 duplicated= True;
4882 matchfacet= NULL;
4883 }else if (ismatch && !matchfacet && !duplicated) {
4884 SETelem_(facet->neighbors, skip)= newfacet;
4885 SETelem_(newfacet->neighbors, newskip)= facet;
4886 (*hashcount)--;
4887 trace4((qh ferr, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n",
4888 facet->id, skip, newfacet->id, newskip));
4889 return;
4890 }
4891
4892 if (!qh PREmerge) qhull_fatal(54);
4893
4894 if (matchall) {
4895 if (matchfacet || !ismatch)
4896 goto LABELnexthash;
4897 SETelem_(facet->neighbors, skip)= newfacet;
4898 SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge;
4899 /* this may merge one more ridge than necessary, but hard to detect */
4900 (*hashcount) -= 2; /* removed two unmatched facets */
4901 zzinc_(Zmultiflip);
4902 trace2((qh ferr, "qh_matchneighbor: duplicate f%d skip %d matched with new f%d skip %d\n",
4903 facet->id, skip, newfacet->id, newskip));
4904 return;
4905 }
4906 duplicated= True;
4907 newfacet->seen= True;
4908 facet->seen= True;
4909 if (matchfacet)
4910 matchfacet->seen= True;
4911 if (!matchfacet && ismatch) {
4912 if (qh_matchduplicate (facet, skip, newfacet, newskip, keepfound)) {
4913 zzinc_(Zmultimatch);
4914 (*hashcount)--;
4915 return;
4916 }
4917 }else if (matchfacet && !keepfound) {
4918 if (!qh_matchmatch (facet, skip, matchfacet, newfacet, newskip,
4919 ismatch, &keepfound, &newmatched)) {
4920 scan= hash;
4921 while ((facet= (facetT *)SETelem_(qh hash_table, scan))) {
4922 if (facet == matchfacet)
4923 break;
4924 if ((int)(++scan) >= hashsize)
4925 scan= 0;
4926 }
4927 if (!facet)
4928 SETelem_(qh hash_table, scan)= matchfacet;
4929 (*hashcount)++;
4930 if (newmatched)
4931 return;
4932 else
4933 (*hashcount)++;
4934 }
4935 }
4936 }
4937 LABELnexthash:
4938 if ((int)(++hash) >= hashsize)
4939 hash= 0;
4940 /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */
4941 }
4942 (*hashcount)++;
4943 if (!newfound)
4944 SETelem_(qh hash_table, hash)= newfacet;
4945 if (duplicated) {
4946 SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge;
4947 trace4((qh ferr, "qh_matchneighbor: no match for duplicated f%d skip %d at hash %d\n",
4948 newfacet->id, newskip, hash));
4949 }else
4950 trace4((qh ferr, "qh_matchneighbor: no match for f%d skip %d at hash %d\n",
4951 newfacet->id, newskip, hash));
4952 } /* matchneighbor */
4953
4954
4955 /*-------------------------------------------------
4956 -matchnewfacets- match newfacets in qh newfacet_list to their newfacet neighbors
4957 newfacets already have neighbor[0] (horizon facet)
4958 assumes qh hash_table is NULL
4959 returns:
4960 qh newfacet_list with full neighbor sets
4961 get vertices with nth neighbor by deleting nth vertex
4962 if PREmerge or FORCEoutput
4963 all facets check for flipped (also prevents point partitioning)
4964 if duplicate ridges and PREmerge
4965 facet->seen set
4966 missing neighbor links identifies extra ridges to be merging
4967 notes:
4968 do not allocate memory after hash_table (need to free it cleanly)
4969 */
qh_matchnewfacets(void)4970 void qh_matchnewfacets (void) {
4971 int numnew=0, numfree= 0, hashcount=0, newskip, nth=0;
4972 facetT *newfacet, *neighbor, **neighborp, *facet;
4973 int facet_i, facet_n, dim= qh hull_dim, hashsize;
4974 setT *neighbors;
4975
4976 trace1((qh ferr, "qh_matchnewfacets: match neighbors for new facets.\n"));
4977 FORALLnew_facets {
4978 numnew++;
4979 { /* qh_setzero (newfacet->neighbors, 1, qh hull_dim); */
4980 neighbors= newfacet->neighbors;
4981 // This (void *) cast was in the original, 1990s, pre-64-bit Pelican
4982 neighbors->e[neighbors->maxsize]= reinterpret_cast<void *>(dim+1); /*may be overwritten*/
4983 memset ((char *)&neighbors->e[1], 0, dim * sizeof(void *));
4984 }
4985 if (qh MERGING)
4986 qh_checkflipped (newfacet, NULL, qh_ALL);
4987 }
4988 if (qh FORCEoutput && !qh MERGING)
4989 qh_checkflipped_all (qh newfacet_list); /* prints warnings for flipped */
4990 qh_newhashtable (numnew*(qh hull_dim-1)); /* twice what is normally needed,
4991 but every ridge could be DUPLICATEridge */
4992 hashsize= qh_setsize (qh hash_table);
4993 FORALLnew_facets {
4994 newfacet->seen= False;
4995 for (newskip=1; newskip<qh hull_dim; newskip++) /* furthest/horizon already matched */
4996 qh_matchneighbor (newfacet, newskip, hashsize, &hashcount,
4997 (boolT)!qh_ALL);
4998 #if 0 /* use the following to trap hashcount errors */
4999 {
5000 int count= 0, k;
5001 facetT *facet, *neighbor;
5002
5003 count= 0;
5004 FORALLfacet_(qh newfacet_list) { /* newfacet already in use */
5005 for (k=1; k<qh hull_dim; k++) {
5006 neighbor= SETelem_(facet->neighbors, k);
5007 if (!neighbor || neighbor == qh_DUPLICATEridge)
5008 count++;
5009 }
5010 if (facet == newfacet)
5011 break;
5012 }
5013
5014 if (count != hashcount) qhull_fatal(55);
5015
5016 }
5017 #endif /* end of trap code */
5018 }
5019 if (hashcount) {
5020 FORALLnew_facets {
5021 if (newfacet->seen) {
5022 nth= 0;
5023 FOREACHneighbor_(newfacet) {
5024 if (neighbor == qh_DUPLICATEridge) {
5025 trace2((qh ferr, "qh_matchnewfacets: find good/flip match for duplicated f%d skip %d\n",
5026 newfacet->id, nth));
5027 qh_matchneighbor (newfacet, nth, hashsize, &hashcount, qh_ALL);
5028
5029 /*
5030 if (qh IStracing >= 4)
5031 qh_errprint ("DUPLICATED/MATCH", newfacet,
5032 (facetT*)SETelem_(newfacet->neighbors, nth), NULL, NULL);
5033 NO LONGER IN SERVICE */
5034 /* this may report MERGEfacet */
5035 }
5036 nth++;
5037 }
5038 }
5039 }
5040 }
5041
5042 if (hashcount) qhull_fatal(56);
5043
5044 if (qh IStracing >= 2) {
5045 FOREACHfacet_i_(qh hash_table) {
5046 if (!facet)
5047 numfree++;
5048 }
5049 fprintf (qh ferr, "qh_matchnewfacets: %d new facets, %d unused hash entries . hashsize %d\n",
5050 numnew, numfree, qh_setsize (qh hash_table));
5051 }
5052 qh_setfree (&qh hash_table);
5053
5054 /*
5055 if (qh IStracing >= 4 && qh PREmerge)
5056 qh_printfacetlist (qh newfacet_list, NULL, qh_ALL);
5057 THIS IS NO LONGER IN SERVICE */
5058
5059 } /* matchnewfacets */
5060
5061
5062 /*----------------------------------------
5063 -matchvertices- tests whether vertices match with a single skip
5064 starts match at firstindex since all new facets have a common vertex
5065 assumes skipA is in A and both sets are the same size
5066 returns:
5067 skip index
5068 sets same iff vertices have the same orientation
5069 */
qh_matchvertices(int firstindex,setT * verticesA,int skipA,setT * verticesB,int * skipB,boolT * same)5070 boolT qh_matchvertices (int firstindex, setT *verticesA, int skipA,
5071 setT *verticesB, int *skipB, boolT *same) {
5072 vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp;
5073
5074 elemAp= SETelemaddr_(verticesA, firstindex, vertexT);
5075 elemBp= SETelemaddr_(verticesB, firstindex, vertexT);
5076 skipAp= SETelemaddr_(verticesA, skipA, vertexT);
5077 do if (elemAp != skipAp) {
5078 while (*elemAp != *elemBp++) {
5079 if (skipBp)
5080 return False;
5081 skipBp= elemBp; /* one extra like FOREACH */
5082 }
5083 }while(*(++elemAp));
5084 if (!skipBp)
5085 skipBp= ++elemBp;
5086 *skipB= (int)SETindex_(verticesB, skipB);
5087 *same= (boolT)(!(((unsigned)skipA & 0x1) ^ ((unsigned)*skipB & 0x1)));
5088 trace4((qh ferr, "qh_matchvertices: matched by skip %d (v%d) and skip %d (v%d) same? %d\n",
5089 skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same));
5090 return (True);
5091 } /* matchvertices */
5092
5093 /*----------------------------------------
5094 -nextridge3d- return next ridge and vertex for a 3d facet
5095 in qh_ORIENTclock order
5096 n^2 implementation to trace all ridges
5097 be sure to stop on any 2nd visit
5098 */
qh_nextridge3d(ridgeT * atridge,facetT * facet,vertexT ** vertexp)5099 ridgeT *qh_nextridge3d (ridgeT *atridge, facetT *facet, vertexT **vertexp) {
5100 vertexT *atvertex, *vertex, *othervertex;
5101 ridgeT *ridge, **ridgep;
5102
5103 if ((atridge->top == facet) ^ qh_ORIENTclock)
5104 atvertex= (vertexT *)SETsecond_(atridge->vertices);
5105 else
5106 atvertex= (vertexT *)SETfirst_(atridge->vertices);
5107 FOREACHridge_(facet->ridges) {
5108 if (ridge == atridge)
5109 continue;
5110 if ((ridge->top == facet) ^ qh_ORIENTclock) {
5111 othervertex= (vertexT *)SETsecond_(ridge->vertices);
5112 vertex= (vertexT *)SETfirst_(ridge->vertices);
5113 }else {
5114 vertex= (vertexT *)SETsecond_(ridge->vertices);
5115 othervertex= (vertexT *)SETfirst_(ridge->vertices);
5116 }
5117 if (vertex == atvertex) {
5118 if (vertexp)
5119 *vertexp= othervertex;
5120 return ridge;
5121 }
5122 }
5123 return NULL;
5124 } /* nextridge3d */
5125
5126
5127 /*----------------------------------------
5128 -newfacet- creates and allocates space for a facet
5129 returns:
5130 all fields initialized or cleared (NULL)
5131 preallocates neighbors
5132 */
qh_newfacet(void)5133 facetT *qh_newfacet(void) {
5134 facetT *facet = NULL;
5135 void **freelistp;
5136
5137 facetT_qh_memalloc_(sizeof(facetT), freelistp, facet);
5138 memset ((char *)facet, 0, sizeof(facetT));
5139 if (qh facet_id == 0xFFFFFF) {
5140 fprintf(qh ferr, "\
5141 qhull warning: more than %d facets. Id field overflows and two facets\n\
5142 may have the same identifier. Otherwise output ok.\n", 0xFFFFFF);
5143 }
5144 if (qh facet_id == (int)qh tracefacet_id)
5145 qh tracefacet= facet;
5146 facet->id= qh facet_id++;
5147 facet->neighbors= qh_setnew(qh hull_dim);
5148 #if !qh_COMPUTEfurthest
5149 facet->furthestdist= 0.0;
5150 #endif
5151 #if qh_MAXoutside
5152 if (qh FORCEoutput && qh APPROXhull)
5153 facet->maxoutside= qh MINoutside;
5154 else
5155 facet->maxoutside= qh DISTround;
5156 #endif
5157 facet->simplicial= True;
5158 facet->good= True;
5159 trace4((qh ferr, "qh_newfacet: created facet f%d\n", facet->id));
5160 return (facet);
5161 } /* newfacet */
5162
5163
5164 /*-------------------------------------------------
5165 -newhashtable- returns size of qh hash_table of at least newsize slots
5166 assumes qh hash_table is NULL
5167 qh_HASHfactor determines the number of extra slots
5168 */
qh_newhashtable(int newsize)5169 int qh_newhashtable(int newsize) {
5170 int size;
5171
5172 size= ((newsize+1)*qh_HASHfactor) | 0x1; /* odd number */
5173 while (True) {
5174 if ((size%3) && (size%5))
5175 break;
5176 size += 2;
5177 /* loop terminates because there is an infinite number of primes */
5178 }
5179 qh hash_table= qh_setnew (size);
5180 qh_setzero (qh hash_table, 0, size);
5181 return size;
5182 } /* newhashtable */
5183
5184 /*----------------------------------------
5185 -newridge- creates and allocates space for a ridge
5186 */
qh_newridge(void)5187 ridgeT *qh_newridge(void) {
5188 ridgeT *ridge = NULL;
5189 void **freelistp;
5190
5191 ridgeT_qh_memalloc_(sizeof(ridgeT), freelistp, ridge);
5192 memset ((char *)ridge, 0, sizeof(ridgeT));
5193 zinc_(Ztotridges);
5194 if (qh ridge_id == 0xFFFFFF) {
5195 fprintf(qh ferr, "\
5196 qhull warning: more than %d ridges. Id field overflows and two ridges\n\
5197 may have the same identifier. Otherwise output ok.\n", 0xFFFFFF);
5198 }
5199 ridge->id= qh ridge_id++;
5200 trace4((qh ferr, "qh_newridge: created ridge r%d\n", ridge->id));
5201 return (ridge);
5202 } /* newridge */
5203
5204
5205 /*----------------------------------------
5206 -newvertex- creates and allocates space for a vertex
5207 */
qh_newvertex(pointT * point)5208 vertexT *qh_newvertex(pointT *point) {
5209 vertexT *vertex;
5210
5211 zinc_(Ztotvertices);
5212 vertex= (vertexT *)qh_memalloc(sizeof(vertexT));
5213 memset ((char *) vertex, 0, sizeof (vertexT));
5214
5215 if (qh vertex_id == 0xFFFFFF) qhull_fatal(57);
5216
5217 if (qh vertex_id == qh tracevertex_id)
5218 qh tracevertex= vertex;
5219 vertex->id= qh vertex_id++;
5220 vertex->point= point;
5221 trace4((qh ferr, "qh_newvertex: vertex p%d (v%d) created\n", qh_pointid(vertex->point),
5222 vertex->id));
5223 return (vertex);
5224 } /* newvertex */
5225
5226 /*-------------------------------------------------
5227 -point- return point for a point id, or NULL if unknown
5228 */
qh_point(int id)5229 pointT *qh_point (int id) {
5230
5231 if (id < 0)
5232 return NULL;
5233 if (id < qh num_points)
5234 return ((pointT *)((unsigned long)qh first_point+(unsigned long)((id)*qh normal_size)));
5235 id -= qh num_points;
5236 if (id < qh_setsize (qh other_points))
5237 return (pointT *)SETelem_(qh other_points, id);
5238 return NULL;
5239 } /* point */
5240
5241 /*-------------------------------------------------
5242 -point_add- access function for pointfacet and pointvertex
5243 */
qh_point_add(setT * set,pointT * point,void * elem)5244 void qh_point_add (setT *set, pointT *point, void *elem) {
5245 int id;
5246
5247 if ((id= qh_pointid(point)) == -1)
5248 fprintf (qh ferr,
5249 "qhull internal warning (pointfacet,pointvertex): unknown point %p\n",
5250 static_cast<void *>(point));
5251 else
5252 SETelem_(set, id)= elem;
5253 } /* point_add */
5254
5255
5256 /*-------------------------------------------------
5257 -pointfacet- return temporary set of facets indexed by point id
5258 for vertices, coplanarset, and outsideset
5259 access with FOREACHfacet_i_(facets) and SETelem_(facets, i)
5260 NULL if no facet for point (inside)
5261 this will include qh GOODpointp
5262 */
qh_pointfacet(void)5263 setT *qh_pointfacet (void /*qh facet_list*/) {
5264 int numpoints= qh num_points + qh_setsize (qh other_points);
5265 setT *facets;
5266 facetT *facet;
5267 vertexT *vertex, **vertexp;
5268 pointT *point, **pointp;
5269
5270 facets= qh_settemp (numpoints);
5271 qh_setzero (facets, 0, numpoints);
5272 qh vertex_visit++;
5273 FORALLfacets {
5274 FOREACHvertex_(facet->vertices) {
5275 if ((int)vertex->visitid != qh vertex_visit) {
5276 vertex->visitid= qh vertex_visit;
5277 qh_point_add (facets, vertex->point, facet);
5278 }
5279 }
5280 FOREACHpoint_(facet->coplanarset)
5281 qh_point_add (facets, point, facet);
5282 FOREACHpoint_(facet->outsideset)
5283 qh_point_add (facets, point, facet);
5284 }
5285 return facets;
5286 } /* pointfacet */
5287
5288 /*-------------------------------------------------
5289 -pointid- return id for a point, -3 if null, -2 if interior, or -1 if not known
5290 */
qh_pointid(pointT * point)5291 int qh_pointid (pointT *point) {
5292 unsigned id;
5293
5294 if (!point)
5295 return -3;
5296 id= ((unsigned long) point - (unsigned long) qh first_point)/qh normal_size;
5297 if ((int)id >= qh num_points) {
5298 if (point == qh interior_point)
5299 id= (unsigned int) -2;
5300 else if ((int)(id= qh_setindex (qh other_points, point)) != -1)
5301 id += qh num_points;
5302 }
5303 return (int) id;
5304 } /* pointid */
5305
5306 /*-------------------------------------------------
5307 -pointvertex- return temporary set of vertices indexed by point id
5308 access with FOREACHvertex_i_(vertices) and SETelem_(vertices, i)
5309 NULL if no vertex for point
5310 this will include qh GOODpointp
5311 */
qh_pointvertex(void)5312 setT *qh_pointvertex (void /*qh facet_list*/) {
5313 int numpoints= qh num_points + qh_setsize (qh other_points);
5314 setT *vertices;
5315 vertexT *vertex;
5316
5317 vertices= qh_settemp (numpoints);
5318 qh_setzero (vertices, 0, numpoints);
5319 FORALLvertices
5320 qh_point_add (vertices, vertex->point, vertex);
5321 return vertices;
5322 } /* pointvertex */
5323
5324
5325 /*-------------------------------------------------
5326 -prependfacet- prepend facet to the start of a facetlist
5327 increments qh numfacets
5328 updates facetlist, qh facet_list, facet_next
5329 notes:
5330 be careful of prepending since it can lose a pointer.
5331 e.g., can lose _next by deleting and then prepending before _next
5332 */
qh_prependfacet(facetT * facet,facetT ** facetlist)5333 void qh_prependfacet(facetT *facet, facetT **facetlist) {
5334 facetT *prevfacet, *list= *facetlist;
5335
5336
5337 trace4((qh ferr, "qh_prependfacet: prepend f%d before f%d\n",
5338 facet->id, list->id));
5339 prevfacet= list->previous;
5340 facet->previous= prevfacet;
5341 if (prevfacet)
5342 prevfacet->next= facet;
5343 list->previous= facet;
5344 facet->next= *facetlist;
5345 if (qh facet_list == list) /* this may change *facetlist */
5346 qh facet_list= facet;
5347 if (qh facet_next == list)
5348 qh facet_next= facet;
5349 *facetlist= facet;
5350 qh num_facets++;
5351 } /* prependfacet */
5352
5353
5354 /*-----------------------------------------
5355 -printhashtable- print hash table
5356 not in I/O to avoid bringing io.c in
5357 */
qh_printhashtable(FILE * fp)5358 void qh_printhashtable(FILE *fp) {
5359 facetT *facet, *neighbor;
5360 int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0;
5361 vertexT *vertex, **vertexp;
5362
5363 FOREACHfacet_i_(qh hash_table) {
5364 if (facet) {
5365 FOREACHneighbor_i_(facet) {
5366 if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge)
5367 break;
5368 }
5369 if (neighbor_i == neighbor_n)
5370 continue;
5371 fprintf (fp, "hash %d f%d ", facet_i, facet->id);
5372 FOREACHvertex_(facet->vertices)
5373 fprintf (fp, "v%d ", vertex->id);
5374 fprintf (fp, "\n neighbors:");
5375 FOREACHneighbor_i_(facet) {
5376 if (neighbor == qh_MERGEridge)
5377 id= -3;
5378 else if (neighbor == qh_DUPLICATEridge)
5379 id= -2;
5380 else
5381 id= getid_(neighbor);
5382 fprintf (fp, " %d", id);
5383 }
5384 fprintf (fp, "\n");
5385 }
5386 }
5387 } /* printhashtable */
5388
5389
5390 /*-------------------------------------------------
5391 -printlists- print out facet and vertex list for debugging (without 'f/v' tags)
5392 */
qh_printlists(void)5393 void qh_printlists (void) {
5394 facetT *facet;
5395 vertexT *vertex;
5396
5397 fprintf (qh ferr, "qh_printlists: facets:");
5398 FORALLfacets
5399 fprintf (qh ferr, " %d", facet->id);
5400 fprintf (qh ferr, "\n new facets %d visible facets %d next facet for addpoint %d\n vertices (new %d):",
5401 getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_next),
5402 getid_(qh newvertex_list));
5403 FORALLvertices
5404 fprintf (qh ferr, " %d", vertex->id);
5405 fprintf (qh ferr, "\n");
5406 } /* printlists */
5407
5408 /*-------------------------------------------------
5409 -removefacet- unlinks facet from qh facet_list,
5410 updates qh facet_list .newfacet_list .facet_next visible_list
5411
5412 decrements qh num_facets
5413 */
qh_removefacet(facetT * facet)5414 void qh_removefacet(facetT *facet) {
5415 facetT *next= facet->next, *previous= facet->previous;
5416
5417 if (facet == qh newfacet_list)
5418 qh newfacet_list= next;
5419 if (facet == qh facet_next)
5420 qh facet_next= next;
5421 if (facet == qh visible_list)
5422 qh visible_list= next;
5423 if (previous) {
5424 previous->next= next;
5425 next->previous= previous;
5426 }else { /* 1st facet in qh facet_list */
5427 qh facet_list= next;
5428 qh facet_list->previous= NULL;
5429 }
5430 qh num_facets--;
5431 trace4((qh ferr, "qh_removefacet: remove f%d from facet_list\n", facet->id));
5432 } /* removefacet */
5433
5434
5435 /*-------------------------------------------------
5436 -removevertex- unlinks vertex from qh vertex_list,
5437 updates qh vertex_list .newvertex_list
5438
5439 decrements qh num_vertices
5440 */
qh_removevertex(vertexT * vertex)5441 void qh_removevertex(vertexT *vertex) {
5442 vertexT *next= vertex->next, *previous= vertex->previous;
5443
5444 if (vertex == qh newvertex_list)
5445 qh newvertex_list= next;
5446 if (previous) {
5447 previous->next= next;
5448 next->previous= previous;
5449 }else { /* 1st vertex in qh vertex_list */
5450 qh vertex_list= vertex->next;
5451 qh vertex_list->previous= NULL;
5452 }
5453 qh num_vertices--;
5454 trace4((qh ferr, "qh_removevertex: remove v%d from vertex_list\n", vertex->id));
5455 } /* removevertex */
5456
5457
5458 /*-------------------------------------------------
5459 -vertexintersect- intersects two vertex sets (inverse id ordered)
5460 temporary set vertexsetA is replaced by the intersection
5461 must be at top of stack
5462 could overwrite vertexsetA if currently too slow
5463 */
qh_vertexintersect(setT ** vertexsetA,setT * vertexsetB)5464 void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB) {
5465 setT *intersection;
5466
5467 intersection= qh_vertexintersect_new (*vertexsetA, vertexsetB);
5468 qh_settempfree (vertexsetA);
5469 *vertexsetA= intersection;
5470 qh_settemppush (intersection);
5471 } /* vertexintersect */
5472
5473 /*-------------------------------------------------
5474 -vertexintersect_new- intersects two vertex sets (inverse id ordered)
5475 returns:
5476 a new set
5477 */
qh_vertexintersect_new(setT * vertexsetA,setT * vertexsetB)5478 setT *qh_vertexintersect_new (setT *vertexsetA,setT *vertexsetB) {
5479 setT *intersection= qh_setnew (qh hull_dim - 1);
5480 vertexT **vertexA= SETaddr_(vertexsetA, vertexT);
5481 vertexT **vertexB= SETaddr_(vertexsetB, vertexT);
5482
5483 while (*vertexA && *vertexB) {
5484 if (*vertexA == *vertexB) {
5485 qh_setappend(&intersection, *vertexA);
5486 vertexA++; vertexB++;
5487 }else {
5488 if ((*vertexA)->id > (*vertexB)->id)
5489 vertexA++;
5490 else
5491 vertexB++;
5492 }
5493 }
5494 return intersection;
5495 } /* vertexintersect_new */
5496
5497
5498 /*-------------------------------------------
5499 -vertexneighhbors- for each vertex in hull, determine facet neighbors
5500 nop if VERTEXneighbors
5501 assumes all vertex->neighbors are NULL
5502 returns:
5503 sets qh VERTEXneighbors, qh_addpoint() will maintain them
5504 */
qh_vertexneighbors(void)5505 void qh_vertexneighbors (void /*qh facet_list*/) {
5506 facetT *facet;
5507 vertexT *vertex, **vertexp;
5508
5509 if (qh VERTEXneighbors)
5510 return;
5511 trace1((qh ferr, "qh_vertexneighbors: determing neighboring facets for each vertex\n"));
5512 qh vertex_visit++;
5513 FORALLfacets {
5514 FOREACHvertex_(facet->vertices) {
5515 if ((int)vertex->visitid != qh vertex_visit) {
5516 vertex->visitid= qh vertex_visit;
5517 vertex->neighbors= qh_setnew (qh hull_dim);
5518 }
5519 qh_setappend (&vertex->neighbors, facet);
5520 }
5521 }
5522 qh VERTEXneighbors= True;
5523 } /* vertexneighbors */
5524
5525 /*-------------------------------------------------
5526 -vertexsubset- returns True if vertexsetA is a subset of vertexsetB, False
5527 otherwise; relies on vertexsets being sorted;
5528 an empty set is a subset of any other set
5529 */
qh_vertexsubset(setT * vertexsetA,setT * vertexsetB)5530 boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) {
5531 vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT);
5532 vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT);
5533
5534 while (True) {
5535 if (!*vertexA)
5536 return True;
5537 if (!*vertexB)
5538 return False;
5539 if ((*vertexA)->id > (*vertexB)->id)
5540 return False;
5541 if (*vertexA == *vertexB)
5542 vertexA++;
5543 vertexB++;
5544 }
5545 } /* vertexsubset */
5546
5547
5548 /*************************************************************************/
5549 /****************** implementation code from merge.c *********************/
5550 /*************************************************************************/
5551
5552 /* merge.c - merges non-convex facets
5553
5554 see README and merge.h
5555
5556 other modules call qh_merge_nonconvex() and facetdegen()
5557 to avoid loading merge.o, redefine them to null procedures (user.c)
5558
5559 assumes neighbor sets for each vertex (qh VERTEXneighbors)
5560
5561 assumes qh CENTERtype= centrum
5562
5563 copyright (c) 1993-1994 The Geometry Center
5564 */
5565
5566 static int qh_compareangle(const void *p1, const void *p2);
5567 static int qh_comparevisit (const void *p1, const void *p2);
5568
5569 /*-------------------------------------------------
5570 -appendmergeset- appends an entry to facet_mergeset, angle is optional
5571 all other fields 0
5572 returns:
5573 merge
5574 notes:
5575 see test_appendmerge()
5576 */
qh_appendmergeset(facetT * facet,facetT * neighbor,realT * angle)5577 mergeT *qh_appendmergeset(facetT *facet, facetT *neighbor, realT *angle) {
5578 mergeT *merge;
5579 void **freelistp;
5580
5581 mergeT_qh_memalloc_(sizeof(mergeT), freelistp, merge);
5582 memset ((char*) merge, 0, sizeof(mergeT));
5583 merge->facet1= facet;
5584 merge->facet2= neighbor;
5585 if (angle)
5586 merge->angle= *angle;
5587 qh_setappend(&(qh facet_mergeset), merge);
5588 return merge;
5589 } /* appendmergeset */
5590
5591
5592 /*-------------------------------------------------
5593 -checkridge_boundary- checks that ridges of a facet are boundaryless,
5594 nop if qh hull_dim < 3 or simplicial
5595 may miss a few errors if pinched facets
5596 */
qh_checkridge_boundary(facetT * facet)5597 void qh_checkridge_boundary (facetT *facet) {
5598 #if 0
5599 ridgeT *ridge, **ridgep, *ridgeA, *errridge= NULL;
5600 vertexT *vertex, **vertexp;
5601 int unmatched= 0, matches=0, hashsize, hashslot;
5602
5603 /* this code doesn't work because hash buckets can coalesce */
5604 if (qh hull_dim < 3 || facet->simplicial)
5605 return;
5606 trace3((qh ferr, "qh_checkridge_boundary: check subridges for f%d\n", facet->id));
5607 hashsize= qh_newhashtable (qh_setsize (facet->ridges));
5608 FOREACHridge_(facet->ridges)
5609 ridge->seen= False;
5610 FOREACHridge_(facet->ridges) {
5611 FOREACHvertex_(ridge->vertices) {
5612 if ((ridgeA= qh_hashridge_find (qh hash_table, hashsize,
5613 ridge, vertex, NULL, &hashslot))) {
5614 matches++;
5615 ridgeA->seen ^= True;
5616 }else {
5617 unmatched++;
5618 ridge->seen ^= True;
5619 if (hashslot != -1)
5620 SETelem_(qh hash_table, hashslot)= ridge;
5621 }
5622 }
5623 }
5624 FOREACHridge_(facet->ridges) {
5625 if (ridge->seen) {
5626 fprintf(qh ferr, "qhull internal error (checkridge_boundary): subridges of r%d in f%d don't match up\n",
5627 ridge->id, facet->id);
5628 errridge= ridge;
5629 }
5630 }
5631
5632 if (errridge || unmatched > matches || ((matches-unmatched) ^ 0x1))
5633 qhull_fatal(58);
5634
5635 qh_settempfree (&qh hash_table);
5636 #endif
5637 } /* checkridge_boundary */
5638
5639
5640 /*-------------------------------------------------
5641 -compareangle- used by qsort() to order merges by the angle between
5642 them
5643 */
qh_compareangle(const void * p1,const void * p2)5644 static int qh_compareangle(const void *p1, const void *p2) {
5645 mergeT *a= *((mergeT **)p1), *b= *((mergeT **)p2);
5646
5647 return ((a->angle > b->angle) ? 1 : -1);
5648 } /* compareangle */
5649
5650 /*-------------------------------------------------
5651 -comparevisit- used by qsort() to order vertices by their visitid
5652 */
qh_comparevisit(const void * p1,const void * p2)5653 static int qh_comparevisit (const void *p1, const void *p2) {
5654 vertexT *a= *((vertexT **)p1), *b= *((vertexT **)p2);
5655
5656 return (a->visitid - b->visitid);
5657 } /* comparevisit */
5658
5659 /*------------------------------------------------
5660 -copynonconvex- copy non-convex flag to all ridges between same neighbors
5661 */
qh_copynonconvex(ridgeT * atridge)5662 void qh_copynonconvex (ridgeT *atridge) {
5663 boolT nonconvex = False;
5664 facetT *facet, *otherfacet;
5665 ridgeT *ridge, **ridgep;
5666
5667 nonconvex= (boolT) atridge->nonconvex;
5668 facet= atridge->top;
5669 otherfacet= atridge->bottom;
5670 FOREACHridge_(facet->ridges) {
5671 if (otherfacet == otherfacet_(ridge, facet))
5672 ridge->nonconvex= nonconvex;
5673 }
5674 } /* copynonconvex */
5675
5676 /*------------------------------------------------
5677 -degen_redundant_neighbors- append degen. and redundant neighbors to facet_mergeset
5678 also checks current facet for degeneracy
5679 bumps visitid
5680 called for each mergefacet(), merge and statistics occur in merge_nonconvex
5681 redundant facets will be merged before degenerate ones
5682 notes:
5683 a degenerate facet doesn't have enough neighbors
5684 a redundant facet's vertices is a subset of its neighbor's vertices
5685 */
qh_degen_redundant_neighbors(facetT * facet)5686 void qh_degen_redundant_neighbors (facetT *facet) {
5687 vertexT *vertex, **vertexp;
5688 facetT *neighbor, **neighborp;
5689 int size;
5690 realT angledegen= qh_ANGLEdegen, angleredundant= qh_ANGLEredundant;
5691
5692 trace3((qh ferr, "qh_degen_redundant_neighbors: test neighbors of f%d\n", facet->id));
5693 if ((size= qh_setsize (facet->neighbors)) < qh hull_dim) {
5694 qh_appendmergeset (facet, facet, &angledegen);
5695 trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id));
5696 }
5697 FOREACHneighbor_(facet) { /* first so that redundant merges occur first */
5698 if ((size= qh_setsize (neighbor->neighbors)) < qh hull_dim) {
5699 qh_appendmergeset (neighbor, neighbor, &angledegen);
5700 trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is degenerate. Neighbor of f%d.\n", neighbor->id, facet->id));
5701 }
5702 }
5703 qh vertex_visit++;
5704 FOREACHvertex_(facet->vertices)
5705 vertex->visitid= qh vertex_visit;
5706 FOREACHneighbor_(facet) {
5707 FOREACHvertex_(neighbor->vertices) {
5708 if ((int)vertex->visitid != qh vertex_visit)
5709 break;
5710 }
5711 if (!vertex) {
5712 qh_appendmergeset (neighbor, facet, &angleredundant);
5713 trace2((qh ferr, "qh_degen_redundant_neighbors: f%d is contained in f%d. merge\n", neighbor->id, facet->id));
5714 }
5715 }
5716 } /* degen_redundant_neighbors */
5717
5718
5719 /*-------------------------------------------------
5720 -facetdegen- true if facet already in mergeset as a degenerate
5721 */
qh_facetdegen(facetT * facet)5722 boolT qh_facetdegen (facetT *facet) {
5723 mergeT *merge, **mergep;
5724
5725 FOREACHmerge_(qh facet_mergeset) {
5726 if (merge->facet1 == facet && merge->angle == qh_ANGLEdegen)
5727 return True;
5728 }
5729 return False;
5730 } /* facetdegen */
5731
5732
5733 /*-----------------------------------------
5734 -find_newvertex - locate new vertex for renaming old vertex
5735 each ridge includes oldvertex
5736 vertices consists of possible new vertices
5737 returns:
5738 newvertex or NULL
5739 vertices sorted by number of deleted ridges
5740 notes:
5741 new vertex is in one of the ridges
5742 renaming will not cause a duplicate ridge
5743 renaming will minimize the number of deleted ridges
5744 newvertex may not be adjacent in the dual (though unlikely)
5745 */
qh_find_newvertex(vertexT * oldvertex,setT * vertices,setT * ridges)5746 vertexT *qh_find_newvertex (vertexT *oldvertex, setT *vertices, setT *ridges) {
5747 vertexT *vertex, **vertexp;
5748 setT *newridges;
5749 ridgeT *ridge, **ridgep, *dupridge;
5750 int size, hashsize;
5751 int hash;
5752
5753 if (qh IStracing >= 4) {
5754 fprintf (qh ferr, "qh_find_newvertex: find new vertex for v%d from ",
5755 oldvertex->id);
5756 FOREACHvertex_(vertices)
5757 fprintf (qh ferr, "v%d ", vertex->id);
5758 FOREACHridge_(ridges)
5759 fprintf (qh ferr, "r%d ", ridge->id);
5760 fprintf (qh ferr, "\n");
5761 }
5762 FOREACHvertex_(vertices)
5763 vertex->visitid= 0;
5764 FOREACHridge_(ridges) {
5765 FOREACHvertex_(ridge->vertices)
5766 vertex->visitid++;
5767 }
5768 FOREACHvertex_(vertices) {
5769 if (!vertex->visitid) {
5770 qh_setdelnth (vertices, SETindex_(vertices,vertex));
5771 vertexp--; /* repeat since deleted this vertex */
5772 }
5773 }
5774 qh vertex_visit += qh_setsize (ridges);
5775 if (!qh_setsize (vertices)) {
5776 trace4((qh ferr, "qh_find_newvertex: vertices not in ridges for v%d\n",
5777 oldvertex->id));
5778 return NULL;
5779 }
5780 qsort (SETaddr_(vertices, vertexT), qh_setsize (vertices),
5781 sizeof (vertexT *), qh_comparevisit);
5782 /* can now use qh vertex_visit */
5783 if (qh PRINTstatistics) {
5784 size= qh_setsize (vertices);
5785 zinc_(Zintersect);
5786 zadd_(Zintersecttot, size);
5787 zmax_(Zintersectmax, size);
5788 }
5789 hashsize= qh_newhashtable (qh_setsize (ridges));
5790 FOREACHridge_(ridges)
5791 qh_hashridge (qh hash_table, hashsize, ridge, oldvertex);
5792 FOREACHvertex_(vertices) {
5793 newridges= qh_vertexridges (vertex);
5794 FOREACHridge_(newridges) {
5795 if ((dupridge= qh_hashridge_find (qh hash_table, hashsize, ridge, vertex, oldvertex, &hash))) {
5796 zinc_(Zdupridge);
5797 break;
5798 }
5799 }
5800 qh_settempfree (&newridges);
5801 if (!ridge)
5802 break; /* found a rename */
5803 }
5804 if (vertex) {
5805 zinc_(Zfindvertex);
5806 trace2((qh ferr, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n",
5807 vertex->id, oldvertex->id, qh_setsize (vertices), qh_setsize (ridges)));
5808 }else {
5809 zinc_(Zfindfail);
5810 trace0((qh ferr, "qh_find_newvertex: no vertex for renaming v%d (all duplicated ridges)\n",
5811 oldvertex->id));
5812 }
5813 qh_setfree (&qh hash_table);
5814 return vertex;
5815 } /* find_newvertex */
5816
5817 /*-------------------------------------------------
5818 -findbest_test- test neighbor for findbestneighbor()
5819 either test centrum or vertices
5820 */
qh_findbest_test(boolT testcentrum,facetT * facet,facetT * neighbor,facetT ** bestfacet,realT * distp,realT * mindistp,realT * maxdistp)5821 void qh_findbest_test (boolT testcentrum, facetT *facet, facetT *neighbor,
5822 facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) {
5823 realT dist, mindist, maxdist;
5824
5825 if (testcentrum) {
5826 zzinc_(Zbestdist);
5827 qh_distplane(facet->center, neighbor, &dist);
5828 dist *= qh hull_dim; /* estimate furthest vertex */
5829 if (dist < 0) {
5830 maxdist= 0;
5831 mindist= dist;
5832 dist= -dist;
5833 }else
5834 maxdist= dist;
5835 }else
5836 dist= qh_getdistance (facet, neighbor, &mindist, &maxdist);
5837 if (dist < *distp) {
5838 *bestfacet= neighbor;
5839 *mindistp= mindist;
5840 *maxdistp= maxdist;
5841 *distp= dist;
5842 }
5843 } /* findbest_test */
5844
5845 /*-------------------------------------------------
5846 -findbestneighbor- finds best neighbor (least dist) of a facet for merging
5847 returns min and max distances and their max absolute value
5848 avoids merging old into new
5849 */
qh_findbestneighbor(facetT * facet,realT * distp,realT * mindistp,realT * maxdistp)5850 facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) {
5851 facetT *neighbor, **neighborp, *bestfacet= NULL;
5852 ridgeT *ridge, **ridgep;
5853 boolT nonconvex= True, testcentrum= False;
5854 int size= qh_setsize (facet->vertices);
5855
5856 *distp= REALmax;
5857 if (size > qh hull_dim + qh_BESTcentrum) {
5858 testcentrum= True;
5859 zinc_(Zbestcentrum);
5860 if (!facet->center)
5861 facet->center= qh_getcentrum (facet);
5862 }
5863 if (size > qh hull_dim * qh_BESTnonconvex) {
5864 FOREACHridge_(facet->ridges) {
5865 if (ridge->nonconvex) {
5866 neighbor= otherfacet_(ridge, facet);
5867 qh_findbest_test (testcentrum, facet, neighbor,
5868 &bestfacet, distp, mindistp, maxdistp);
5869 }
5870 }
5871 }
5872 if (!bestfacet) {
5873 nonconvex= False;
5874 FOREACHneighbor_(facet)
5875 qh_findbest_test (testcentrum, facet, neighbor,
5876 &bestfacet, distp, mindistp, maxdistp);
5877 }
5878
5879 if (!bestfacet) qhull_fatal(59);
5880
5881 trace4((qh ferr, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n",
5882 bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp));
5883 return(bestfacet);
5884 } /* findbestneighbor */
5885
5886
5887 /*-------------------------------------------------
5888 -flippedmerges- merge flipped facets into best neighbor
5889 facet_mergeset may have degen/redundant from forced merges
5890 assumes facet_mergeset at top of temp stack
5891 returns:
5892 no flipped facets on facetlist
5893 degen/redundant merges passed through
5894 */
qh_flippedmerges(facetT * facetlist)5895 void qh_flippedmerges(facetT *facetlist) {
5896 facetT *facet, *neighbor, *facet1, *facet2;
5897 realT dist, mindist, maxdist;
5898 mergeT *merge;
5899 setT *othermerges= qh_settemp (qh TEMPsize);
5900 int nummerge=0;
5901
5902 trace2((qh ferr, "qh_flippedmerges: begin\n"));
5903 FORALLfacet_(facetlist) {
5904 if (facet->flipped)
5905 qh_appendmergeset (facet, facet, NULL);
5906 }
5907 while ((merge= (mergeT *)qh_setdellast (qh facet_mergeset))) {
5908 if (merge->angle >= qh_ANGLEdegen) { /* and qh_ANGLEredundant */
5909 qh_setappend (&othermerges, merge);
5910 continue;
5911 }
5912 facet1= merge->facet1;
5913 facet2= merge->facet2;
5914 qh_memfree (merge, sizeof(mergeT));
5915 if (facet1->visible || facet2->visible)
5916 continue;
5917 if (qh TRACEmerge-1 == zzval_(Ztotmerge))
5918 qhmem.IStracing= qh IStracing= qh TRACElevel;
5919 neighbor= qh_findbestneighbor (facet1, &dist, &mindist, &maxdist);
5920 trace0((qh ferr, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g\n",
5921 facet1->id, neighbor->id, dist));
5922 qh_mergefacet (facet1, neighbor, &mindist, &maxdist, NULL);
5923 nummerge++;
5924 if (qh PRINTstatistics) {
5925 zinc_(Zflipped);
5926 wadd_(Wflippedtot, dist);
5927 wmax_(Wflippedmax, dist);
5928 }
5929 }
5930 if (qh_setsize (othermerges)) {
5931 qh_settemppop(); /* othermerges, errors here will leave memory */
5932 qh_settempfree (&qh facet_mergeset);
5933 qh facet_mergeset= othermerges;
5934 qh_settemppush (othermerges);
5935 }else
5936 qh_settempfree (&othermerges);
5937 trace1((qh ferr, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge));
5938 } /* flippedmerges */
5939
5940
5941 /*-------------------------------------------------
5942 -forcedmerges- merge across duplicated ridges and mutually flipped facets
5943 duplicate ridges marked by MERGEridge and both sides facet->seen
5944 bumps visit_id
5945 assumes no merge has merge->newmerge
5946 returns:
5947 all neighboring, flipped facets merged together
5948 no duplicate ridges
5949 facet_mergeset includes any degen/redundant merges
5950 uses facet-tested
5951 notes:
5952 duplicate ridges occur when the horizon is pinched,
5953 i.e. a subridge occurs in more than two horizon ridges.
5954 could rename vertices that pinch the horizon
5955 */
qh_forcedmerges(facetT * facetlist)5956 void qh_forcedmerges(facetT *facetlist) {
5957 facetT *facet, *neighbor, **neighborp, *facet1, *facet2;
5958 mergeT *merge, **mergep;
5959 realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2;
5960 int nummerge=0, numflip=0;
5961
5962 if (qh TRACEmerge-1 == zzval_(Ztotmerge))
5963 qhmem.IStracing= qh IStracing= qh TRACElevel;
5964 trace2((qh ferr, "qh_forcedmerges: begin\n"));
5965 qh visit_id++;
5966 FORALLfacet_(facetlist) {
5967 facet->tested= True;
5968 if (facet->seen || facet->flipped) {
5969 facet->visitid= qh visit_id;
5970 FOREACHneighbor_(facet) {
5971 if (neighbor == qh_MERGEridge) {
5972 facet->tested= False;
5973 continue;
5974 }
5975 if (neighbor->seen && facet->seen
5976 && !qh_setin (neighbor->neighbors, facet)) { /* qh_MERGEridge */
5977 merge= qh_appendmergeset (facet, neighbor, NULL);
5978 merge->mergeridge= True;
5979 }
5980 if ((int)neighbor->visitid == qh visit_id)
5981 continue;
5982 if (neighbor->flipped && facet->flipped)
5983 qh_appendmergeset (facet, neighbor, NULL);
5984 }
5985 }
5986 }
5987 FORALLfacet_(facetlist) { /* gets rid of qh_MERGEridge */
5988 if (!facet->tested)
5989 qh_makeridges (facet);
5990 }
5991 FOREACHmerge_(qh facet_mergeset) { /* restore the missing neighbors */
5992 if (merge->mergeridge) {
5993 qh_setappend (&merge->facet2->neighbors, merge->facet1);
5994 qh_makeridges (merge->facet1); /* and the missing ridges */
5995 }
5996 }
5997 LABELrestart_merges:
5998 FOREACHmerge_(qh facet_mergeset) { /* do duplicates first */
5999 if (!merge->mergeridge)
6000 continue;
6001 facet1= merge->facet1;
6002 facet2= merge->facet2;
6003 while (facet1->visible)
6004 facet1= (facetT *)SETfirst_(facet1->neighbors);
6005 while (facet2->visible)
6006 facet2= (facetT *)SETfirst_(facet2->neighbors);
6007 if (facet1 == facet2)
6008 continue;
6009 if (!qh_setin (facet2->neighbors, facet1)) qhull_fatal(60);
6010
6011 if (qh TRACEmerge-1 == zzval_(Ztotmerge))
6012 qhmem.IStracing= qh IStracing= qh TRACElevel;
6013 if (facet1->flipped || facet2->flipped) {
6014 zinc_(Zmergeflipdup);
6015 numflip++;
6016 trace0((qh ferr, "qh_forcedmerges: duplicate ridge with a flipped facet for f%d and f%d\n",
6017 facet1->id, facet2->id));
6018 if (facet1->flipped) /* delay until qh_flippedmerges */
6019 qh_mergefacet (facet2, facet1, NULL, NULL, NULL);
6020 else
6021 qh_mergefacet (facet1, facet2, NULL, NULL, NULL);
6022 zinc_(Zmergeflip);
6023 }else {
6024 dist1= qh_getdistance (facet1, facet2, &mindist1, &maxdist1);
6025 dist2= qh_getdistance (facet2, facet1, &mindist2, &maxdist2);
6026 trace0((qh ferr, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g\n",
6027 facet1->id, facet2->id, dist1, dist2));
6028 if (dist1 < dist2)
6029 qh_mergefacet (facet1, facet2, &mindist1, &maxdist1, NULL);
6030 else {
6031 dist1= dist2;
6032 qh_mergefacet (facet2, facet1, &mindist2, &maxdist2, NULL);
6033 }
6034 nummerge++;
6035 if (qh PRINTstatistics) {
6036 zinc_(Zduplicate);
6037 wadd_(Wduplicatetot, dist1);
6038 wmax_(Wduplicatemax, dist1);
6039 }
6040 }
6041 goto LABELrestart_merges; /* facet_mergeset may have changed */
6042 }
6043 while ((merge= (mergeT *)qh_setdellast (qh facet_mergeset))) {
6044 if (merge->newmerge)
6045 break;
6046 facet1= merge->facet1;
6047 facet2= merge->facet2;
6048 if (merge->mergeridge || facet1->visible || facet2->visible)
6049 qh_memfree (merge, sizeof(mergeT));
6050 else if (facet1 == facet2 || !facet1->flipped || !facet2->flipped) {
6051 merge->newmerge= True;
6052 qh_setaddnth (&qh facet_mergeset, 0, merge);
6053 }else {
6054 if (qh TRACEmerge-1 == zzval_(Ztotmerge))
6055 qhmem.IStracing= qh IStracing= qh TRACElevel;
6056 qh_memfree (merge, sizeof(mergeT));
6057 zinc_(Zmergeflip);
6058 trace3((qh ferr, "qh_forcedmerges: merge flipped facets f%d and f%d\n",
6059 facet1->id, facet2->id));
6060 qh_mergefacet (facet1, facet2, NULL, NULL, NULL);
6061 numflip++;
6062 }
6063 }
6064 trace1((qh ferr, "qh_forcedmerges: merged %d facets across duplicated ridges and %d flipped facets\n", nummerge, numflip));
6065 } /* forcedmerges */
6066
6067
6068 /*-------------------------------------------------
6069 -getdistance- returns the max and min distance of any vertex from neighbor
6070 returns the max absolute value
6071 */
qh_getdistance(facetT * facet,facetT * neighbor,realT * mindist,realT * maxdist)6072 realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) {
6073 vertexT *vertex, **vertexp;
6074 realT dist;
6075
6076 FOREACHvertex_(facet->vertices)
6077 vertex->seen= False;
6078 FOREACHvertex_(neighbor->vertices)
6079 vertex->seen= True;
6080 *mindist= 0.0;
6081 *maxdist= 0.0;
6082 FOREACHvertex_(facet->vertices) {
6083 if (!vertex->seen) {
6084 zzinc_(Zbestdist);
6085 qh_distplane(vertex->point, neighbor, &dist);
6086 if (dist > *maxdist)
6087 *maxdist= dist;
6088 else if (dist < *mindist)
6089 *mindist= dist;
6090 }
6091 }
6092 return fmax_(*maxdist, -(*mindist));
6093 } /* getdistance */
6094
6095
6096 /*-------------------------------------------------
6097 -getmergeset- returns facet_mergeset of facet-neighbor pairs to be merged
6098 only tests !tested ridges of !tested facets
6099 returns:
6100 sorted mergeset
6101 all ridges tested
6102 notes:
6103 uses ridge->tested to prevent duplicate tests
6104 resets ridge->tested if !facet->center
6105 can not limit tests to modified ridges since the centrum changed
6106 */
qh_getmergeset(facetT * facetlist)6107 void qh_getmergeset(facetT *facetlist) {
6108 facetT *facet, *neighbor, **neighborp;
6109 ridgeT *ridge, **ridgep;
6110 int nummerges;
6111
6112 nummerges= qh_setsize (qh facet_mergeset);
6113 trace2((qh ferr, "qh_getmergeset: started.\n"));
6114 FORALLfacet_(facetlist) {
6115 if (!facet->center) {
6116 facet->tested= False;
6117 FOREACHridge_(facet->ridges)
6118 ridge->tested= False;
6119 }
6120 if (facet->tested)
6121 continue;
6122 facet->tested= True; /* must be non-simplicial */
6123 FOREACHneighbor_(facet)
6124 neighbor->seen= False;
6125 FOREACHridge_(facet->ridges) {
6126 if (ridge->tested && !ridge->nonconvex)
6127 continue;
6128 ridge->tested= True;
6129 ridge->nonconvex= False;
6130 neighbor= otherfacet_(ridge, facet);
6131 if (!neighbor->seen) {
6132 neighbor->seen= True;
6133 if (qh_test_appendmerge (facet, neighbor))
6134 ridge->nonconvex= True;
6135 }
6136 }
6137 }
6138 nummerges= qh_setsize (qh facet_mergeset);
6139 qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
6140 trace2((qh ferr, "qh_getmergeset: %d merges found\n", nummerges));
6141 } /* getmergeset */
6142
6143
6144 /*------------------------------------------------
6145 -getmergeset_initial- initial mergeset for facets
6146 tests all facet/neighbor pairs on facetlist
6147 uses visit_id
6148 facet_mergeset may have degen/redundant from flipped and forced merges
6149 returns:
6150 sorted mergeset
6151 sets facet->tested and ridge->tested
6152 */
qh_getmergeset_initial(facetT * facetlist)6153 void qh_getmergeset_initial (facetT *facetlist) {
6154 facetT *facet, *neighbor, **neighborp;
6155 ridgeT *ridge, **ridgep;
6156 int nummerges;
6157
6158 qh visit_id++;
6159 FORALLfacet_(facetlist) {
6160 facet->visitid= qh visit_id;
6161 facet->tested= True;
6162 FOREACHneighbor_(facet) {
6163 if ((int)neighbor->visitid != qh visit_id) {
6164 if (qh_test_appendmerge (facet, neighbor)) {
6165 if (!neighbor->simplicial) {
6166 FOREACHridge_(neighbor->ridges) {
6167 if (facet == otherfacet_(ridge, neighbor)) {
6168 ridge->nonconvex= True;
6169 break;
6170 }
6171 }
6172 }
6173 }
6174 }
6175 }
6176 FOREACHridge_(facet->ridges)
6177 ridge->tested= True;
6178 }
6179 nummerges= qh_setsize (qh facet_mergeset);
6180 qsort(SETaddr_(qh facet_mergeset, mergeT), nummerges,sizeof(mergeT *),qh_compareangle);
6181 trace2((qh ferr, "qh_getmergeset_initial: %d merges found\n", nummerges));
6182 } /* getmergeset_initial */
6183
6184
6185 /*-----------------------------------------
6186 -hashridge- add ridge to hashtable without oldvertex
6187 assumes hashtable is large enough
6188 */
qh_hashridge(setT * hashtable,int hashsize,ridgeT * ridge,vertexT * oldvertex)6189 void qh_hashridge (setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) {
6190 unsigned hash;
6191 ridgeT *ridgeA;
6192
6193 hash= qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex);
6194 while (True) {
6195 if (!(ridgeA= (ridgeT *)SETelem_(hashtable, hash))) {
6196 SETelem_(hashtable, hash)= ridge;
6197 break;
6198 }else if (ridgeA == ridge)
6199 break;
6200 if ((int)(++hash) == hashsize)
6201 hash= 0;
6202 }
6203 } /* hashridge */
6204
6205
6206 /*-----------------------------------------
6207 -hashridge_find- returns matching ridge in hashtable without oldvertex
6208 assumes hashtable is large enough
6209 can't match ridge to itself
6210 if oldvertex is NULL matches with one skip
6211 returns:
6212 returns matching ridge;
6213 if no match,
6214 hashslot= -1 if ridge already in table
6215 else next NULL index
6216 */
qh_hashridge_find(setT * hashtable,int hashsize,ridgeT * ridge,vertexT * vertex,vertexT * oldvertex,int * hashslot)6217 ridgeT *qh_hashridge_find (setT *hashtable, int hashsize, ridgeT *ridge,
6218 vertexT *vertex, vertexT *oldvertex, int *hashslot) {
6219 unsigned hash;
6220 ridgeT *ridgeA;
6221
6222 *hashslot= 0;
6223 zinc_(Zhashridge);
6224 hash= qh_gethash (hashsize, ridge->vertices, qh hull_dim-1, 0, vertex);
6225 while ((ridgeA= (ridgeT *)SETelem_(hashtable, hash))) {
6226 if (ridgeA == ridge)
6227 *hashslot= -1;
6228 else {
6229 zinc_(Zhashridgetest);
6230 if (qh_setequal_except (ridge->vertices, vertex, ridgeA->vertices, oldvertex))
6231 return ridgeA;
6232 }
6233 if ((int)(++hash) == hashsize)
6234 hash= 0;
6235 }
6236 if (!*hashslot)
6237 *hashslot= hash;
6238 return NULL;
6239 } /* hashridge_find */
6240
6241
6242 /*-------------------------------------------------
6243 -makeridges- creates explicit ridges between simplicial facets
6244 allows qh_MERGEridge flag
6245 uses existing ridges
6246 returns:
6247 facet with ridges and without qh_MERGEridge
6248 */
qh_makeridges(facetT * facet)6249 void qh_makeridges(facetT *facet) {
6250 facetT *neighbor, **neighborp;
6251 ridgeT *ridge, **ridgep;
6252 int neighbor_i, neighbor_n;
6253 boolT toporient=False, mergeridge= False;
6254
6255 if (!facet->simplicial)
6256 return;
6257 trace4((qh ferr, "qh_makeridges: make ridges for f%d\n", facet->id));
6258 facet->simplicial= False;
6259 FOREACHneighbor_(facet) {
6260 if (neighbor == qh_MERGEridge)
6261 mergeridge= True;
6262 else
6263 neighbor->seen= False;
6264 }
6265 FOREACHridge_(facet->ridges)
6266 otherfacet_(ridge, facet)->seen= True;
6267 FOREACHneighbor_i_(facet) {
6268 if (neighbor == qh_MERGEridge) {
6269 FOREACHridge_(facet->ridges) {
6270 if (!qh_setin (facet->neighbors, otherfacet_(ridge, facet)))
6271 ridge->mergeridge= True;
6272 }
6273 }else if (!neighbor->seen) {
6274 ridge= qh_newridge();
6275 if (!neighbor->simplicial) /* only in forced merges, checkfacet */
6276 ridge->mergeridge= True;
6277 ridge->vertices= qh_setnew_delnthsorted (facet->vertices, qh hull_dim,
6278 neighbor_i, 0);
6279 toporient= (boolT)( facet->toporient ^ (neighbor_i & 0x1) );
6280 if (toporient) {
6281 ridge->top= facet;
6282 ridge->bottom= neighbor;
6283 }else {
6284 ridge->top= neighbor;
6285 ridge->bottom= facet;
6286 }
6287 #if 0 /* this also works */
6288 flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1);
6289 if (facet->toporient ^ (skip1 & 0x1) ^ flip) {
6290 ridge->top= neighbor;
6291 ridge->bottom= facet;
6292 }else {
6293 ridge->top= facet;
6294 ridge->bottom= neighbor;
6295 }
6296 #endif
6297 qh_setappend(&(facet->ridges), ridge);
6298 qh_setappend(&(neighbor->ridges), ridge);
6299 }
6300 }
6301 if (mergeridge) {
6302 while (qh_setdel (facet->neighbors, qh_MERGEridge))
6303 ; /* delete each one */
6304 }
6305 } /* makeridges */
6306
6307
6308 /*-------------------------------------------
6309 -maydropneighbor -- drop neighbor relationship if no ridge between facet and neighbor
6310 bumps qh visit_id
6311 returns:
6312 appends degenerate facets to facet_mergeset
6313 won't cause redundant facets since vertex inclusion is the same
6314 may drop vertex and neighbor if no ridge
6315 */
qh_maydropneighbor(facetT * facet)6316 void qh_maydropneighbor (facetT *facet) {
6317 ridgeT *ridge, **ridgep;
6318 realT angledegen= qh_ANGLEdegen;
6319 facetT *neighbor, **neighborp;
6320
6321 qh visit_id++;
6322 trace4((qh ferr, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n",
6323 facet->id));
6324 FOREACHridge_(facet->ridges) {
6325 ridge->top->visitid= qh visit_id;
6326 ridge->bottom->visitid= qh visit_id;
6327 }
6328 FOREACHneighbor_(facet) {
6329 if ((int)neighbor->visitid != qh visit_id) {
6330 trace0((qh ferr, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors\n",
6331 facet->id, neighbor->id));
6332 zinc_(Zdropneighbor);
6333 qh_setdel (facet->neighbors, neighbor);
6334 neighborp--; /* repeat, deleted a neighbor */
6335 qh_setdel (neighbor->neighbors, facet);
6336 if (qh_setsize (neighbor->neighbors) < qh hull_dim) {
6337 zinc_(Zdropdegen);
6338 qh_appendmergeset (neighbor, neighbor, &angledegen);
6339 trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id));
6340 }
6341 }
6342 }
6343 if (qh_setsize (facet->neighbors) < qh hull_dim) {
6344 zinc_(Zdropdegen);
6345 qh_appendmergeset (facet, facet, &angledegen);
6346 trace2((qh ferr, "qh_maydropneighbors: f%d is degenerate.\n", facet->id));
6347 }
6348 } /* maydropneighbor */
6349
6350
6351 /*---------------------------------------
6352 -merge_degenredundant- merge degenerate and redundant facets
6353 if facet1 undefined, tests last merge on facet_mergeset and sets angle
6354 returns:
6355 True if merge performed or degen merge not needed
6356 notes:
6357 need this since renaming vertices can result in degen/redundant facets
6358 any merge can also result in degen/redundant facets
6359 */
qh_merge_degenredundant(facetT * facet1,facetT * facet2,realT * angle)6360 boolT qh_merge_degenredundant (facetT *facet1, facetT *facet2, realT *angle) {
6361 int numnewmerges= 0, size;
6362 mergeT *merge;
6363 facetT *bestneighbor;
6364 realT dist, mindist, maxdist;
6365 vertexT *vertex, **vertexp;
6366
6367 if (qh TRACEmerge-1 == zzval_(Ztotmerge))
6368 qhmem.IStracing= qh IStracing= qh TRACElevel;
6369 while (!facet1 && (merge= (mergeT *)qh_setlast (qh facet_mergeset))
6370 && merge->angle >= qh_ANGLEdegen) {
6371 merge= (mergeT *)qh_setdellast (qh facet_mergeset);
6372 facet1= merge->facet1;
6373 facet2= merge->facet2;
6374 *angle= merge->angle;
6375 qh_memfree (merge, sizeof(mergeT));
6376 if (facet1->visible || facet2->visible)
6377 facet1= NULL;
6378 }
6379 if (!facet1)
6380 return False;
6381 if (*angle == qh_ANGLEredundant) {
6382 trace2((qh ferr, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n",
6383 facet1->id, facet2->id));
6384 qh_mergefacet(facet1, facet2, NULL, NULL, angle);
6385 qh_newmerge_(facet2);
6386 zinc_(Zneighbor);
6387 }else if (*angle == qh_ANGLEdegen) { /* other merges may have fixed */
6388 if (!(size= qh_setsize (facet1->neighbors))) {
6389 trace2((qh ferr, "qh_merge_degenredundant: facet f%d has no neighbors. Deleted\n", facet1->id));
6390 zinc_(Zdelfacetdup);
6391 qh_removefacet(facet1);
6392 qh_prependfacet (facet1, &qh visible_list);
6393 qh num_visible++;
6394 facet1->visible= True;
6395 /* SETfirst_(facet1->neighbors) == NULL */
6396 FOREACHvertex_(facet1->vertices) {
6397 qh_setdel (vertex->neighbors, facet1);
6398 if (!SETfirst_(vertex->neighbors)) {
6399 zinc_(Zdegenvertex);
6400 trace2((qh ferr, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n",
6401 vertex->id, facet1->id));
6402 vertex->deleted= True;
6403 qh_setappend (&qh del_vertices, vertex);
6404 }
6405 }
6406 numnewmerges++; /* needed since cleared this merge */
6407 }else if (size < qh hull_dim) {
6408 bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist);
6409 trace2((qh ferr, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n",
6410 facet1->id, size, bestneighbor->id, dist));
6411 qh_mergefacet(facet1, bestneighbor, &mindist, &maxdist, angle);
6412 qh_newmerge_(bestneighbor);
6413 if (qh PRINTstatistics) {
6414 zinc_(Zdegen);
6415 wadd_(Wdegentot, dist);
6416 wmax_(Wdegenmax, dist);
6417 }
6418 }else
6419 numnewmerges++; /* needed since cleared this merge */
6420 }
6421 return (boolT)numnewmerges;
6422 } /* merge_degenredundant */
6423
6424 /*-------------------------------------------------
6425 -merge_nonconvex- merges all nonconvex facets
6426 assumes qh_vertexneighbors() already called
6427 need to use qh newfacet_list since merge calls removefacet()
6428 returns:
6429 deleted facets added to visible_list
6430 notes:
6431 numdegenredun also counts degen facets that become ok
6432 */
qh_merge_nonconvex(void)6433 void qh_merge_nonconvex (void /*qh newfacet_list*/) {
6434 facetT *bestfacet, *neighbor, *facet1, *facet2;
6435 facetT *bestneighbor;
6436 mergeT *merge;
6437 realT dist, dist2, mindist, mindist2, maxdist, maxdist2, angle;
6438 boolT wasmerge= True, ismodified=False, anglecoplanar = False;
6439 void **freelistp;
6440 vertexT *vertex;
6441 int nummerge=0, numconcave=0, numdegenredun= 0, numnewmerges= 0;
6442
6443 trace2((qh ferr, "qh_merge_nonconvex: starting to merge facets beginning from f%d\n",
6444 getid_(qh newfacet_list)));
6445 if (qh IStracing >= 4 && qh num_facets < 50)
6446 qh_printlists();
6447 qh facet_mergeset= qh_settemp (qh TEMPsize);
6448 qh_forcedmerges (qh newfacet_list); /* also sets tested */
6449 qh_flippedmerges (qh newfacet_list);
6450 qh NEWmerges= True;
6451 if (qh POSTmerging)
6452 qh_tracemerging ("after flipped merges");
6453 qh_getmergeset_initial (qh newfacet_list); /* facet_mergeset */
6454 while (wasmerge) {
6455 wasmerge= False;
6456 while (qh_setsize (qh facet_mergeset)) {
6457 while ((merge= (mergeT *)qh_setdellast(qh facet_mergeset))) {
6458 facet1= merge->facet1;
6459 facet2= merge->facet2;
6460 angle= merge->angle;
6461 anglecoplanar= (boolT)merge->anglecoplanar;
6462 qh_memfree_(merge, sizeof(mergeT), freelistp);
6463 if ((facet1->id >= qh newfacet_id && !facet1->tested)
6464 || (facet2->id >= qh newfacet_id && !facet2->tested))
6465 ismodified= True;
6466 else
6467 ismodified= False;
6468 if (facet1->visible || facet2->visible) /*deleted facet*/
6469 continue;
6470 if (ismodified && angle < qh_ANGLEconcave)
6471 continue;
6472 if (qh TRACEmerge-1 == zzval_(Ztotmerge))
6473 qhmem.IStracing= qh IStracing= qh TRACElevel;
6474 trace4((qh ferr, "qh_merge_nonconvex: merge #%d for f%d and f%d angle %2.2g modified? %d\n",
6475 zzval_(Ztotmerge)+1, facet1->id, facet2->id, angle, ismodified));
6476 if (qh_merge_degenredundant (facet1, facet2, &angle)) {
6477 numdegenredun++;
6478 wasmerge= True;
6479 continue;
6480 }else { /* ANGLEconcave or coplanar */
6481 if (facet1->id < qh newfacet_id) {
6482 bestfacet= facet2; /* avoid merging old facet if new is ok */
6483 facet2= facet1;
6484 facet1= bestfacet;
6485 }else
6486 bestfacet= facet1;
6487 bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist);
6488 neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2);
6489 wasmerge= True;
6490 if (dist < dist2) {
6491 qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, &angle);
6492 qh_newmerge_(bestneighbor);
6493 }else if (facet2->id < qh newfacet_id
6494 && ((mindist >= qh min_vertex && maxdist <= qh max_outside)
6495 || dist * 1.5 < dist2)) {
6496 zinc_(Zavoidold);
6497 wadd_(Wavoidoldtot, dist);
6498 wmax_(Wavoidoldmax, dist);
6499 trace2((qh ferr, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g. Use f%d dist %2.2g insted\n",
6500 facet2->id, dist2, facet1->id, dist2));
6501 qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, &angle);
6502 qh_newmerge_(bestneighbor);
6503 }else {
6504 qh_mergefacet(facet2, neighbor, &mindist2, &maxdist2, &angle);
6505 qh_newmerge_(neighbor);
6506 dist= dist2;
6507 }
6508 if (qh PRINTstatistics) {
6509 if (anglecoplanar) {
6510 nummerge++;
6511 zinc_(Zacoplanar);
6512 wadd_(Wacoplanartot, dist);
6513 wmax_(Wacoplanarmax, dist);
6514 }else if (angle > qh_ANGLEconcave) {
6515 numconcave++;
6516 zinc_(Zconcave);
6517 wadd_(Wconcavetot, dist);
6518 wmax_(Wconcavemax, dist);
6519 }else {
6520 nummerge++;
6521 zinc_(Zcoplanar);
6522 wadd_(Wcoplanartot, dist);
6523 wmax_(Wcoplanarmax, dist);
6524 }
6525 }else if (angle > qh_ANGLEconcave)
6526 numconcave++;
6527 else
6528 nummerge++;
6529 }
6530 /* reducing vertices here in 5-d, 50% more time, maybe fewer vertices,
6531 and better bounds */
6532 } /* while setdellast */
6533 if (qh POSTmerging)
6534 qh_tracemerging ("after a merge set");
6535 if (numnewmerges > qh_MAXnewmerges) { /* needed for large post merges */
6536 numnewmerges= 0;
6537 qh_reducevertices_centrums();
6538 }
6539 qh_getmergeset (qh newfacet_list); /* facet_mergeset */
6540 } /* while mergeset */
6541 if (wasmerge || (qh hull_dim >=4 && qh POSTmerging)) {
6542 if (qh hull_dim >=4 && qh POSTmerging) { /*duplicate ridges may changed*/
6543 FORALLvertices
6544 vertex->delridge= True;
6545 }
6546 if (qh_reducevertices_centrums())
6547 qh_getmergeset (qh newfacet_list); /* facet_mergeset */
6548 else
6549 wasmerge= False;
6550 }
6551 } /* while (wasmerge) */
6552 qh NEWmerges= False;
6553 if (qh CHECKfrequently)
6554 qh_checkconvex (qh newfacet_list, qh_ALGORITHMfault);
6555 qh_settempfree(&qh facet_mergeset);
6556 trace1((qh ferr, "qh_merge_nonconvex: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n",
6557 nummerge, numconcave, numdegenredun));
6558 if (qh IStracing >= 4 && qh num_facets < 50)
6559 qh_printlists ();
6560 } /* merge_nonconvex */
6561
6562
6563 /*-------------------------------------------------
6564 -mergefacet- merges facet1 into facet2
6565 traces merge if fmax_(maxdist,-mindist) > TRACEdist
6566 mindist/maxdist and angle may be NULL
6567 max_outside and min_vertex updated
6568 returns:
6569 facet1 prepended to visible_list for later deletion and partitioning
6570 qh num_visible updated.
6571 SETfirst_(facet1->neighbors) == facet2
6572 facet2 moved to end of qh facet_list
6573 facet2 is new (get's facet1->id if it was old)
6574 adds neighboring facets to facet_mergeset if redundant or degenerate
6575 clears facet->tested and ridge->tested ffrom facet1
6576 */
qh_mergefacet(facetT * facet1,facetT * facet2,realT * mindist,realT * maxdist,realT * angle)6577 void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, realT *angle) {
6578 boolT traceonce= False, waserror= False;
6579 vertexT *vertex, **vertexp;
6580 ridgeT *ridge, **ridgep;
6581 int tracerestore=0;
6582
6583 zzinc_(Ztotmerge);
6584 if ((mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist))
6585 || facet1 == qh tracefacet || facet2 == qh tracefacet) {
6586 if (facet1 == qh tracefacet || facet2 == qh tracefacet) {
6587 tracerestore= qh IStracing;
6588 qh IStracing= 4;
6589 fprintf (qh ferr, "qh_mergefacet: ========= trace merge %d involving f%d, furthest is p%d\n",
6590 zzval_(Ztotmerge), qh tracefacet_id, qh furthest_id);
6591 }else {
6592 tracerestore= 0;
6593 qh IStracing= qh TRACElevel;
6594 fprintf (qh ferr, "qh_mergefacet: ========= trace wide merge %d (%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge),
6595 fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh furthest_id);
6596 }
6597 traceonce= True;
6598 }
6599 if (qh IStracing >= 2) {
6600 realT mergemin= -2;
6601 realT mergemax= -2;
6602 realT mergeangle= -2;
6603
6604 if (mindist) {
6605 mergemin= *mindist;
6606 mergemax= *maxdist;
6607 }
6608 if (angle)
6609 mergeangle= *angle;
6610 fprintf (qh ferr, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g, angle = %2.2g\n",
6611 zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax, mergeangle);
6612 }
6613
6614 if (facet1 == facet2 || facet1->visible || facet2->visible)
6615 qhull_fatal(61);
6616
6617 if (qh num_facets -qh num_visible <= qh hull_dim + 1) qhull_fatal(62);
6618
6619 if (mindist) {
6620 maximize_(qh max_outside, *maxdist);
6621 maximize_(qh max_vertex, *maxdist);
6622 #if qh_MAXoutside
6623 maximize_(facet2->maxoutside, *maxdist);
6624 #endif
6625 minimize_(qh min_vertex, *mindist);
6626 }
6627 qh_makeridges(facet1);
6628 qh_makeridges(facet2);
6629
6630 /*
6631 if (qh IStracing >=4)
6632 qh_errprint ("MERGING", facet1, facet2, NULL, NULL);
6633 NO LONGER IN SERVICE */
6634
6635 if (facet2->center && qh hull_dim == 2) { /* only two vertices */
6636 qh_memfree (facet2->center, qh center_size);
6637 facet2->center= NULL;
6638 }
6639 qh_mergeneighbors(facet1, facet2);
6640 FOREACHridge_(facet1->ridges)
6641 ridge->tested= False;
6642 qh_mergeridges(facet1, facet2);
6643 qh vertex_visit++;
6644 FOREACHvertex_(facet2->vertices)
6645 vertex->visitid= qh vertex_visit;
6646 if (qh hull_dim == 2)
6647 qh_mergevertices2d(facet1->vertices, facet2->vertices);
6648 else
6649 qh_mergevertices(facet1->vertices, &facet2->vertices);
6650 qh_mergevertex_neighbors(facet1, facet2);
6651 if (facet1->id < qh newfacet_id && facet2->id >= qh newfacet_id) {
6652 zinc_(Zmergehorizon);
6653 }else if (facet2->id >= qh newfacet_id)
6654 zinc_(Zmergenew);
6655 qh_removefacet(facet1);
6656 qh_prependfacet (facet1, &qh visible_list);
6657 qh num_visible++;
6658 facet1->visible= True;
6659 SETfirst_(facet1->neighbors)= facet2;
6660 qh_settruncate (facet1->neighbors, 1);
6661 qh_removefacet(facet2); /* append as a newfacet to end of qh facet_list */
6662 qh_appendfacet(facet2);
6663 if (facet2->id < qh newfacet_id) {
6664 zinc_(Zmergeintohorizon);
6665 trace3((qh ferr, "qh_mergefacet: RENAME - f%d as new facet f%d\n",
6666 facet2->id, qh facet_id));
6667 if (qh facet_id == (int)qh tracefacet_id) {
6668 qh tracefacet= facet2;
6669 fprintf (qh ferr, "qh_mergefacet: RENAME f%d as trace facet f%d. Current furthest is p%d\n",
6670 facet2->id, qh facet_id, qh furthest_id);
6671 }
6672 facet2->id= qh facet_id++;
6673 }
6674 qh_degen_redundant_neighbors (facet2);
6675 facet2->tested= False;
6676
6677 /*
6678 if (qh IStracing >= 4)
6679 qh_errprint ("MERGED", facet2, NULL, NULL, NULL);
6680 NO LONGER IN SERVICE */
6681
6682 if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newlist)) {
6683 fprintf (qh ferr, "qh_mergefacets: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh furthest_id);
6684
6685 /*
6686 if (facet2 != qh tracefacet)
6687 qh_errprint ("TRACE", qh tracefacet,
6688 (qh tracevertex ? (facetT *)SETfirst_(qh tracevertex->neighbors):NULL),
6689 NULL, qh tracevertex);
6690 NO LONGER IN SERVICE */
6691
6692 }
6693 if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */
6694 qh_checkfacet (facet2, True, &waserror);
6695
6696 if (waserror) qhull_fatal(63);
6697
6698 qh_checkridge_boundary (facet2);
6699 }
6700 if (qh tracevertex) {
6701 if (qh tracevertex->deleted)
6702 fprintf (qh ferr, "qh_mergefacet: trace vertex deleted at furthest p%d\n",
6703 qh furthest_id);
6704 else
6705 qh_checkvertex (qh tracevertex);
6706 }
6707 if (qh tracefacet) {
6708 qh_checkfacet (qh tracefacet, True, &waserror);
6709
6710 if (waserror) qhull_fatal(64);
6711
6712 }
6713 if (traceonce) {
6714 fprintf (qh ferr, "qh_mergefacet: end of wide tracing\n");
6715 qh IStracing= tracerestore;
6716 }
6717 } /* mergefacet */
6718
6719
6720 /*-------------------------------------------------
6721 -mergeneighbors- merges the neighbors of facet1 into facet2
6722 */
qh_mergeneighbors(facetT * facet1,facetT * facet2)6723 void qh_mergeneighbors(facetT *facet1, facetT *facet2) {
6724 facetT *neighbor, **neighborp;
6725
6726 trace4((qh ferr, "qh_mergeneighbors: merge neighbors of f%d and f%d\n",
6727 facet1->id, facet2->id));
6728 qh visit_id++;
6729 FOREACHneighbor_(facet2) {
6730 neighbor->visitid= qh visit_id;
6731 }
6732 FOREACHneighbor_(facet1) {
6733 if ((int)neighbor->visitid == qh visit_id) {
6734 if (neighbor->simplicial) /* is degen, needs ridges */
6735 qh_makeridges (neighbor);
6736 if (SETfirst_(neighbor->neighbors) != facet1) /*keep horizon->newfacet*/
6737 qh_setdel (neighbor->neighbors, facet1);
6738 else {
6739 qh_setdel(neighbor->neighbors, facet2);
6740 qh_setreplace(neighbor->neighbors, facet1, facet2);
6741 }
6742 }else if (neighbor != facet2) {
6743 qh_setappend(&(facet2->neighbors), neighbor);
6744 qh_setreplace(neighbor->neighbors, facet1, facet2);
6745 }
6746 }
6747 qh_setdel(facet1->neighbors, facet2); /* here for makeridges */
6748 qh_setdel(facet2->neighbors, facet1);
6749 } /* mergeneighbors */
6750
6751
6752 /*-------------------------------------------------
6753 -mergeridges- merges the ridge set of facet1 into facet2
6754 may delete all ridges for a vertex
6755 */
qh_mergeridges(facetT * facet1,facetT * facet2)6756 void qh_mergeridges(facetT *facet1, facetT *facet2) {
6757 ridgeT *ridge, **ridgep;
6758 vertexT *vertex, **vertexp;
6759
6760 trace4((qh ferr, "qh_mergeridges: merge ridges of f%d and f%d\n",
6761 facet1->id, facet2->id));
6762 FOREACHridge_(facet2->ridges) {
6763 if ((ridge->top == facet1) || (ridge->bottom == facet1)) {
6764 FOREACHvertex_(ridge->vertices)
6765 vertex->delridge= True;
6766 qh_delridge(ridge);
6767 ridgep--; /*repeat*/
6768 }
6769 }
6770 FOREACHridge_(facet1->ridges) {
6771 if (ridge->top == facet1)
6772 ridge->top= facet2;
6773 else
6774 ridge->bottom= facet2;
6775 qh_setappend(&(facet2->ridges), ridge);
6776 }
6777 } /* mergeridges */
6778
6779
6780 /*-------------------------------------------------
6781 -mergevertex_neighbors- merge the vertex neighbors of facet1 to facet2
6782 deletes vertices if only one neighbor
6783 assumes neighbor sets are good
6784 */
qh_mergevertex_neighbors(facetT * facet1,facetT * facet2)6785 void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) {
6786 vertexT *vertex, **vertexp;
6787
6788 trace4((qh ferr, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n",
6789 facet1->id, facet2->id));
6790 if (qh tracevertex) {
6791 fprintf (qh ferr, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n",
6792 facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0]);
6793
6794 /*
6795 qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
6796 NO LONGER IN SERVICE */
6797
6798 }
6799 FOREACHvertex_(facet1->vertices) {
6800 if ((int)vertex->visitid != qh vertex_visit) {
6801 qh_setreplace(vertex->neighbors, facet1, facet2);
6802 }else {
6803 qh_setdel(vertex->neighbors, facet1);
6804 if (!SETsecond_(vertex->neighbors)) {
6805 zinc_(Zmergevertex);
6806 trace2((qh ferr, "qh_mergevertex_neighbors: deleted v%d when merging f%d into f%d\n",
6807 vertex->id, facet1->id, facet2->id));
6808 qh_setdelsorted (facet2->vertices, vertex);
6809 vertex->deleted= True;
6810 qh_setappend (&qh del_vertices, vertex);
6811 }
6812 }
6813 }
6814
6815 /*
6816 if (qh tracevertex)
6817 qh_errprint ("TRACE", NULL, NULL, NULL, qh tracevertex);
6818 NO LONGER IN SERVICE */
6819
6820 } /* mergevertex_neighbors */
6821
6822
6823 /*-------------------------------------------------
6824 -mergevertices- merges the vertex set of facet1 into facet2
6825 preserves vertex_visit for qh_mergevertex_neighbors
6826 updates qh newvertex_list
6827 */
qh_mergevertices(setT * vertices1,setT ** vertices2)6828 void qh_mergevertices(setT *vertices1, setT **vertices2) {
6829 int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1;
6830 setT *mergedvertices;
6831 vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT);
6832
6833 mergedvertices= qh_settemp (newsize);
6834 FOREACHvertex_(vertices1) {
6835 if (!*vertex2 || vertex->id > (*vertex2)->id)
6836 qh_setappend (&mergedvertices, vertex);
6837 else {
6838 while (*vertex2 && (*vertex2)->id > vertex->id)
6839 qh_setappend (&mergedvertices, *vertex2++);
6840 if (!*vertex2 || (*vertex2)->id < vertex->id)
6841 qh_setappend (&mergedvertices, vertex);
6842 else
6843 qh_setappend (&mergedvertices, *vertex2++);
6844 }
6845 }
6846 while (*vertex2)
6847 qh_setappend (&mergedvertices, *vertex2++);
6848 FOREACHvertex_(mergedvertices) {
6849 if (!vertex->newlist) {
6850 vertex->newlist= True;
6851 qh_removevertex (vertex);
6852 qh_appendvertex (vertex);
6853 }
6854 }
6855
6856 if (newsize < qh_setsize (mergedvertices)) qhull_fatal(65);
6857
6858 qh_setfree(vertices2);
6859 *vertices2= mergedvertices;
6860 qh_settemppop ();
6861 } /* mergevertices */
6862
6863
6864 /*-------------------------------------------------
6865 -mergevertices2d- merges vertices1 into vertices2 in 2-d case
6866 preserves vertex_visit for qh_mergevertex_neighbors
6867 */
qh_mergevertices2d(setT * vertices1,setT * vertices2)6868 void qh_mergevertices2d(setT *vertices1, setT *vertices2) {
6869 vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB;
6870
6871 vertex1A= (vertexT *)SETfirst_(vertices1);
6872 vertex1B= (vertexT *)SETsecond_(vertices1);
6873 vertex2A= (vertexT *)SETfirst_(vertices2);
6874 vertex2B= (vertexT *)SETsecond_(vertices2);
6875 if (vertex1A == vertex2A) {
6876 vertexA= vertex1B;
6877 vertexB= vertex2B;
6878 }else if (vertex1A == vertex2B) {
6879 vertexA= vertex1B;
6880 vertexB= vertex2A;
6881 }else if (vertex1B == vertex2A) {
6882 vertexA= vertex1A;
6883 vertexB= vertex2B;
6884 }else { /* 1B == 2B */
6885 vertexA= vertex1A;
6886 vertexB= vertex2A;
6887 }
6888 if (vertexA->id > vertexB->id) {
6889 SETfirst_(vertices2)= vertexA;
6890 SETsecond_(vertices2)= vertexB;
6891 }else {
6892 SETfirst_(vertices2)= vertexB;
6893 SETsecond_(vertices2)= vertexA;
6894 }
6895 } /* mergevertices2d */
6896
6897 /*-------------------------------------------------
6898 -neighbor_intersections- return intersection for vertex->neighbors
6899 returns temporary set of vertices
6900 does not include vertex
6901 NULL if an neighbor is simplicial
6902 NULL if empty set
6903 */
qh_neighbor_intersections(vertexT * vertex)6904 setT *qh_neighbor_intersections (vertexT *vertex) {
6905 facetT *neighbor, **neighborp, *neighborA, *neighborB;
6906 setT *intersect;
6907 int neighbor_i, neighbor_n;
6908
6909 FOREACHneighbor_(vertex) {
6910 if (neighbor->simplicial)
6911 return NULL;
6912 }
6913 neighborA= (facetT *)SETfirst_(vertex->neighbors);
6914 neighborB= (facetT *)SETsecond_(vertex->neighbors);
6915 zinc_(Zintersectnum);
6916 if (!neighborA)
6917 return NULL;
6918 if (!neighborB)
6919 intersect= qh_setcopy (neighborA->vertices, 0);
6920 else
6921 intersect= qh_vertexintersect_new (neighborA->vertices, neighborB->vertices);
6922 qh_settemppush (intersect);
6923 qh_setdelsorted (intersect, vertex);
6924 FOREACHneighbor_i_(vertex) {
6925 if (neighbor_i >= 2) {
6926 zinc_(Zintersectnum);
6927 qh_vertexintersect (&intersect, neighbor->vertices);
6928 if (!SETfirst_(intersect)) {
6929 zinc_(Zintersectfail);
6930 qh_settempfree (&intersect);
6931 return NULL;
6932 }
6933 }
6934 }
6935 trace3((qh ferr, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n",
6936 qh_setsize (intersect), vertex->id));
6937 return intersect;
6938 } /* neighbor_intersections */
6939
6940 /*-------------------------------------------------
6941 -reducevertices_centrums reduce vertex sets and reset centrums
6942 qh_isnewmerge_(facet) [i.e., flipped] true if merged since last call
6943 if 2-d, just clears newmerge flags
6944 returns:
6945 True if degen_redundant facets or redefined centrums
6946 vertices are renamed if possible
6947 centrum's reset for small (qh_MAXnewcentrum), newly merged or renamed facets
6948 */
qh_reducevertices_centrums(void)6949 boolT qh_reducevertices_centrums (void) {
6950 int numshare=0, numrename= 0, numcentrums= 0;
6951 int numdegenredun= 0;
6952 facetT *newfacet;
6953 vertexT *vertex, **vertexp;
6954 realT angle;
6955 ridgeT *ridge, **ridgep;
6956
6957 if (qh hull_dim == 2) {
6958 FORALLnew_facets
6959 qh_clearnewmerge_(newfacet);
6960 return False;
6961 }
6962 LABELrestart:
6963 while (qh_merge_degenredundant (NULL, NULL, &angle))
6964 numdegenredun++;
6965 FORALLnew_facets {
6966 if (qh_isnewmerge_(newfacet)) /* this is seldom needed */
6967 qh_remove_extravertices (newfacet);
6968 }
6969 FORALLnew_facets {
6970 if (qh_isnewmerge_(newfacet)) {
6971 FOREACHvertex_(newfacet->vertices) {
6972 if (vertex->delridge) {
6973 if (qh_rename_sharedvertex (vertex, newfacet)) {
6974 numshare++;
6975 vertexp--; /* repeat since deleted vertex */
6976 }
6977 }
6978 }
6979 }
6980 }
6981 FORALLvertex_(qh newvertex_list) {
6982 if (vertex->delridge && !vertex->deleted) {
6983 vertex->delridge= False;
6984 if (qh hull_dim >= 4 && qh_redundant_vertex (vertex)) {
6985 numrename++;
6986 if (qh_merge_degenredundant (NULL, NULL, &angle)) {
6987 numdegenredun++;
6988 goto LABELrestart;
6989 }
6990 }
6991 }
6992 }
6993 FORALLnew_facets {
6994 if (qh_isnewmerge_(newfacet)) {
6995 qh_clearnewmerge_(newfacet);
6996 if (newfacet->center
6997 && qh_setsize (newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) {
6998 qh_memfree (newfacet->center, qh center_size);
6999 newfacet->center= NULL;
7000 newfacet->tested= False;
7001 FOREACHridge_(newfacet->ridges)
7002 ridge->tested= False;
7003 numcentrums++;
7004 }
7005 }
7006 }
7007 trace1((qh ferr, "qh_reducevertices_centrums: renamed %d shared vertices and %d redundant\nvertices. Redefined %d centrums and merged %d degen, redundant facets\n",
7008 numshare, numrename, numcentrums, numdegenredun));
7009 if (numdegenredun + numcentrums)
7010 return True;
7011 return False;
7012 } /* reducevertices_centrums */
7013
7014 /*-------------------------------------------------
7015 -redundant_vertex- returns true if detect and rename redundant vertex
7016 vertices have full ->neighbors
7017 only needed if vertex->delridge and hull_dim >= 4
7018 returns:
7019 may add degen facets to facet_mergeset
7020 doesn't change vertex->neighbors or create redundant facets
7021 */
qh_redundant_vertex(vertexT * vertex)7022 vertexT *qh_redundant_vertex (vertexT *vertex) {
7023 vertexT *newvertex= NULL;
7024 setT *vertices, *ridges;
7025
7026 trace3((qh ferr, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id));
7027 if ((vertices= qh_neighbor_intersections (vertex))) {
7028 ridges= qh_vertexridges (vertex);
7029 if ((newvertex= qh_find_newvertex (vertex, vertices, ridges)))
7030 qh_renamevertex (vertex, newvertex, ridges, NULL, NULL);
7031 qh_settempfree (&ridges);
7032 qh_settempfree (&vertices);
7033 }
7034 return newvertex;
7035 } /* redundant_vertex */
7036
7037 /*-------------------------------------------------
7038 -remove_extravertices in non-simplicial facets
7039 returns True if it finds them
7040 */
qh_remove_extravertices(facetT * facet)7041 boolT qh_remove_extravertices (facetT *facet) {
7042 ridgeT *ridge, **ridgep;
7043 vertexT *vertex, **vertexp, *vertexA, **vertexAp;
7044 boolT foundrem= False;
7045
7046 trace4((qh ferr, "qh_remove_extravertices: test f%d for extra vertices\n",
7047 facet->id));
7048 FOREACHvertex_(facet->vertices)
7049 vertex->seen= False;
7050 FOREACHridge_(facet->ridges) {
7051 FOREACHvertexA_(ridge->vertices)
7052 vertexA->seen= True;
7053 }
7054 FOREACHvertex_(facet->vertices) {
7055 if (!vertex->seen) {
7056 foundrem= True;
7057 zinc_(Zremvertex);
7058 qh_setdelsorted (facet->vertices, vertex);
7059 qh_setdel (vertex->neighbors, facet);
7060 if (!qh_setsize (vertex->neighbors)) {
7061 vertex->deleted= True;
7062 qh_setappend (&qh del_vertices, vertex);
7063 zinc_(Zremvertexdel);
7064 trace2((qh ferr, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id));
7065 }else
7066 trace3((qh ferr, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id));
7067 vertexp--; /*repeat*/
7068 }
7069 }
7070 return foundrem;
7071 } /* remove_extravertices */
7072
7073 /*-------------------------------------------------
7074 -rename_sharedvertex- detect and rename if shared vertex in facet
7075 vertices have full ->neighbors
7076 returns:
7077 newvertex or NULL
7078 the vertex may still exist in other facets (i.e., a neighbor was pinched)
7079 does not change facet->neighbors, updates vertex->neighbors
7080 notes:
7081 a shared vertex for a facet is only in ridges to one neighbor
7082 this may undo a pinched facet
7083
7084 it does not catch pinches involving multiple facets. These appear
7085 to be difficult to detect, since an exhaustive search is too expensive.
7086 */
qh_rename_sharedvertex(vertexT * vertex,facetT * facet)7087 vertexT *qh_rename_sharedvertex (vertexT *vertex, facetT *facet) {
7088 facetT *neighbor, **neighborp, *neighborA= NULL;
7089 setT *vertices, *ridges;
7090 vertexT *newvertex;
7091
7092 if (qh_setsize (vertex->neighbors) == 2) {
7093 neighborA= (facetT *)SETfirst_(vertex->neighbors);
7094 if (neighborA == facet)
7095 neighborA= (facetT *)SETsecond_(vertex->neighbors);
7096 }else if (qh hull_dim == 3)
7097 return NULL;
7098 else {
7099 qh visit_id++;
7100 FOREACHneighbor_(facet)
7101 neighbor->visitid= qh visit_id;
7102 FOREACHneighbor_(vertex) {
7103 if ((int)neighbor->visitid == qh visit_id) {
7104 if (neighborA)
7105 return NULL;
7106 neighborA= neighbor;
7107 }
7108 }
7109
7110 if (!neighborA) qhull_fatal(66);
7111
7112 }
7113 /* the vertex is shared by facet and neighborA */
7114 ridges= qh_settemp (qh TEMPsize);
7115 neighborA->visitid= ++qh visit_id;
7116 qh_vertexridges_facet (vertex, facet, &ridges);
7117 trace2((qh ferr, "qh_rename_sharedvertex: p%d (v%d) is shared by f%d (%d ridges) and f%d\n",
7118 qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize (ridges), neighborA->id));
7119 zinc_(Zintersectnum);
7120 vertices= qh_vertexintersect_new (facet->vertices, neighborA->vertices);
7121 qh_setdel (vertices, vertex);
7122 qh_settemppush (vertices);
7123 if ((newvertex= qh_find_newvertex (vertex, vertices, ridges)))
7124 qh_renamevertex (vertex, newvertex, ridges, facet, neighborA);
7125 qh_settempfree (&vertices);
7126 qh_settempfree (&ridges);
7127 return newvertex;
7128 } /* rename_sharedvertex */
7129
7130 /*-------------------------------------------------
7131 -renameridgevertex- renames oldvertex as newvertex in ridge
7132 */
qh_renameridgevertex(ridgeT * ridge,vertexT * oldvertex,vertexT * newvertex)7133 void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) {
7134 int nth= 0, oldnth;
7135 facetT *temp;
7136 vertexT *vertex, **vertexp;
7137
7138 oldnth= qh_setindex (ridge->vertices, oldvertex);
7139 qh_setdelnthsorted (ridge->vertices, oldnth);
7140 FOREACHvertex_(ridge->vertices) {
7141 if (vertex == newvertex) {
7142 zinc_(Zdelridge);
7143 if (ridge->tested && ridge->nonconvex)
7144 qh_copynonconvex (ridge);
7145 qh_delridge (ridge);
7146 trace2((qh ferr, "qh_renameridgevertex: ridge r%d deleted. It contained both v%d and v%d\n",
7147 ridge->id, oldvertex->id, newvertex->id));
7148 return;
7149 }
7150 if (vertex->id < newvertex->id)
7151 break;
7152 nth++;
7153 }
7154 qh_setaddnth(&ridge->vertices, nth, newvertex);
7155 if (abs(oldnth - nth)%2) {
7156 trace3((qh ferr, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n",
7157 ridge->id));
7158 temp= ridge->top;
7159 ridge->top= ridge->bottom;
7160 ridge->bottom= temp;
7161 }
7162 } /* renameridgevertex */
7163
7164
7165 /*-------------------------------------------------
7166 -renamevertex- renames oldvertex as newvertex in ridges
7167 oldvertex may still exist afterwards
7168 gives oldfacet/neighborA if shared between facets
7169 notes:
7170 can not change neighbors of newvertex (since it's a subset)
7171 */
qh_renamevertex(vertexT * oldvertex,vertexT * newvertex,setT * ridges,facetT * oldfacet,facetT * neighborA)7172 void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) {
7173 facetT *neighbor, **neighborp;
7174 ridgeT *ridge, **ridgep;
7175 boolT istrace= False;
7176
7177 if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id ||
7178 newvertex->id == qh tracevertex_id)
7179 istrace= True;
7180 FOREACHridge_(ridges)
7181 qh_renameridgevertex (ridge, oldvertex, newvertex);
7182 if (qh CHECKfrequently) {
7183 FOREACHneighbor_(oldvertex) {
7184 qh_checkridge_boundary (neighbor);
7185 }
7186 }
7187 if (!oldfacet) {
7188 zinc_(Zrenameall);
7189 if (istrace)
7190 fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in several facets\n",
7191 oldvertex->id, newvertex->id);
7192 FOREACHneighbor_(oldvertex) {
7193 qh_maydropneighbor (neighbor);
7194 qh_setdelsorted (neighbor->vertices, oldvertex);
7195 if (qh_remove_extravertices (neighbor))
7196 neighborp--; /* neighbor may be deleted */
7197 }
7198 if (!oldvertex->deleted) {
7199 oldvertex->deleted= True;
7200 qh_setappend (&qh del_vertices, oldvertex);
7201 }
7202 }else if (qh_setsize (oldvertex->neighbors) == 2) {
7203 zinc_(Zrenameshare);
7204 if (istrace)
7205 fprintf (qh ferr, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n",
7206 oldvertex->id, newvertex->id, oldfacet->id);
7207 FOREACHneighbor_(oldvertex)
7208 qh_setdelsorted (neighbor->vertices, oldvertex);
7209 oldvertex->deleted= True;
7210 qh_setappend (&qh del_vertices, oldvertex);
7211 }else {
7212 zinc_(Zrenamepinch);
7213 if (istrace || qh IStracing)
7214 fprintf (qh ferr, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n",
7215 oldvertex->id, newvertex->id, oldfacet->id, neighborA->id);
7216 qh_setdelsorted (oldfacet->vertices, oldvertex);
7217 qh_setdel (oldvertex->neighbors, oldfacet);
7218 qh_remove_extravertices (neighborA);
7219 }
7220 } /* renamevertex */
7221
7222
7223 /*-----------------------------------------
7224 -test_appendmerge- tests facet/neighbor and appends to mergeset if nonconvex
7225 sets facet->center as needed
7226 returns:
7227 true if appends to mergeset
7228 sets 'acoplanar' if angle coplanar
7229 */
qh_test_appendmerge(facetT * facet,facetT * neighbor)7230 boolT qh_test_appendmerge (facetT *facet, facetT *neighbor) {
7231 realT dist, dist2= -REALmax, angle;
7232 boolT isconcave= False, iscoplanar= False;
7233 mergeT *merge;
7234
7235 angle= qh_getangle(facet->normal, neighbor->normal);
7236 zinc_(Zangletests);
7237 if (angle > qh cos_max) {
7238 zinc_(Zcoplanarangle);
7239 merge= qh_appendmergeset(facet, neighbor, &angle);
7240 merge->anglecoplanar= True;
7241 trace2((qh ferr, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n",
7242 angle, facet->id, neighbor->id));
7243 return True;
7244 }else {
7245 if (!facet->center)
7246 facet->center= qh_getcentrum (facet);
7247 zzinc_(Zcentrumtests);
7248 qh_distplane(facet->center, neighbor, &dist);
7249 if (dist > qh centrum_radius)
7250 isconcave= True;
7251 else {
7252 if (dist > -qh centrum_radius)
7253 iscoplanar= True;
7254 if (!neighbor->center)
7255 neighbor->center= qh_getcentrum (neighbor);
7256 zinc_(Zcentrumtests);
7257 qh_distplane(neighbor->center, facet, &dist2);
7258 if (dist2 > qh centrum_radius)
7259 isconcave= True;
7260 else if (dist2 > -qh centrum_radius)
7261 iscoplanar= True;
7262 }
7263 if (isconcave) {
7264 zinc_(Zconcaveridge);
7265 angle += qh_ANGLEconcave + 0.5;
7266 qh_appendmergeset(facet, neighbor, &angle);
7267 trace0((qh ferr, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g\n",
7268 facet->id, neighbor->id, dist, dist2, angle));
7269 return True;
7270 }else if (iscoplanar) {
7271 zinc_(Zcoplanarcentrum);
7272 qh_appendmergeset(facet, neighbor, &angle);
7273 trace2((qh ferr, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n",
7274 facet->id, neighbor->id, dist, dist2, angle));
7275 return True;
7276 }
7277 }
7278 return False;
7279 } /* test_appendmerge */
7280
7281
7282 /*------------------------------------------
7283 -tracemerging- print trace message if active
7284 */
qh_tracemerging(const char * string)7285 void qh_tracemerging (const char *string) {
7286 realT cpu;
7287 time_t timedata;
7288 struct tm *tp;
7289
7290 if (qh REPORTfreq && (zzval_(Ztotmerge) > qh mergereport+qh REPORTfreq/2)) {
7291 qh mergereport= zzval_(Ztotmerge);
7292 time (&timedata);
7293 tp= localtime (&timedata);
7294 cpu= clock();
7295 cpu /= qh_SECticks;
7296 zinc_(Zdistio);
7297 fprintf (qh ferr, "\n\
7298 At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets. The hull\n\
7299 contains %d facets and %d vertices. p%d was the last point.\n",
7300 tp->tm_hour, tp->tm_min, tp->tm_sec, cpu,
7301 zzval_(Ztotmerge), qh num_facets - qh num_visible,
7302 qh num_vertices-qh_setsize (qh del_vertices), qh furthest_id);
7303 }
7304 } /* tracemerging */
7305
7306 /*------------------------------------------
7307 -vertexridges- return temporary set of ridges adjacent to a vertex
7308 vertex->neighbors defined
7309 uses qh visit_id
7310 does not include implicit ridges for simplicial facets
7311 */
qh_vertexridges(vertexT * vertex)7312 setT *qh_vertexridges (vertexT *vertex) {
7313 facetT *neighbor, **neighborp;
7314 setT *ridges= qh_settemp (qh TEMPsize);
7315 int size;
7316
7317 qh visit_id++;
7318 FOREACHneighbor_(vertex)
7319 neighbor->visitid= qh visit_id;
7320 FOREACHneighbor_(vertex) {
7321 if (*neighborp) /* no new ridges in last neighbor */
7322 qh_vertexridges_facet (vertex, neighbor, &ridges);
7323 }
7324 if (qh PRINTstatistics || qh IStracing) {
7325 size= qh_setsize (ridges);
7326 zinc_(Zvertexridge);
7327 zadd_(Zvertexridgetot, size);
7328 zmax_(Zvertexridgemax, size);
7329 trace3((qh ferr, "qh_vertexridges: found %d ridges for v%d\n",
7330 size, vertex->id));
7331 }
7332 return ridges;
7333 } /* vertexridges */
7334
7335 /*------------------------------------------
7336 -vertexridges_facet- add adjacent ridges for vertex in facet
7337 skips ridges if neighbor->visitid< visit_id
7338 returns:
7339 sets facet->visitid to visit_id-1
7340 */
qh_vertexridges_facet(vertexT * vertex,facetT * facet,setT ** ridges)7341 void qh_vertexridges_facet (vertexT *vertex, facetT *facet, setT **ridges) {
7342 ridgeT *ridge, **ridgep;
7343 facetT *neighbor;
7344
7345 FOREACHridge_(facet->ridges) {
7346 neighbor= otherfacet_(ridge, facet);
7347 if ((int)neighbor->visitid == qh visit_id
7348 && qh_setin (ridge->vertices, vertex))
7349 qh_setappend (ridges, ridge);
7350 }
7351 facet->visitid= qh visit_id-1;
7352 } /* vertexridges_facet */
7353
7354
7355
7356
7357 /*************************************************************************/
7358 /****************** implementation code from global.c ********************/
7359 /*************************************************************************/
7360
7361 /* global.c -- contains all the globals of the qhull application
7362
7363 see README
7364
7365 see qhull.h for qh globals and function prototypes
7366
7367 see qhull_a.h for internal functions
7368
7369 copyright (c) 1993-1994, The Geometry Center
7370 */
7371
7372 #if qh_QHpointer
7373 qhT *qh_qh= NULL;
7374 #else
7375 qhT qh_qh; /*= {0};*/ /* remove "= {0}" if this causes a compiler error. Also
7376 qh_qhstat in stat.c and qhmem in mem.c. */
7377 #endif
7378
7379 /* ------------Simple all purpose error report-------------*/
7380
7381 #ifdef GAMBIT_EXCEPTIONS
~ErrorInQhull()7382 ErrorInQhull::~ErrorInQhull() { }
7383
GetDescription(void) const7384 std::string ErrorInQhull::GetDescription(void) const
7385 {
7386 return "Error somewhere in Qhull";
7387 }
7388 #endif
7389
qhull_fatal(int errorno)7390 void qhull_fatal(int errorno)
7391 {
7392 #ifdef GAMBIT_EXCEPTIONS
7393 throw ErrorInQhull();
7394 #endif
7395
7396 printf("\nError number %d in qhull.\n", errorno);
7397 exit(0);
7398 }
7399
7400
7401 /*-------------------------------------------
7402 -appendprint- append output format to qh PRINTout unless already defined
7403 */
qh_appendprint(int format)7404 void qh_appendprint (int format) {
7405 int i;
7406
7407 for (i=0; i < qh_PRINTEND; i++) {
7408 if (qh PRINTout[i] == format)
7409 break;
7410 if (!qh PRINTout[i]) {
7411 qh PRINTout[i]= format;
7412 break;
7413 }
7414 }
7415 } /* appendprint */
7416
7417 /*-------------------------------------------
7418 -freebuffers- free up global memory buffers
7419 must match initbuffers()
7420 */
7421
qh_freebuffers(void)7422 void qh_freebuffers (void) {
7423
7424 trace5((qh ferr, "qh_freebuffers: freeing up global memory buffers\n"));
7425 qh_memfree (qh NEARzero, qh hull_dim * sizeof(realT));
7426 qh_memfree (qh lower_threshold, (qh input_dim+1) * sizeof(realT));
7427 qh_memfree (qh upper_threshold, (qh input_dim+1) * sizeof(realT));
7428 qh_memfree (qh lower_bound, (qh input_dim+1) * sizeof(realT));
7429 qh_memfree (qh upper_bound, (qh input_dim+1) * sizeof(realT));
7430 qh_memfree (qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT));
7431 qh_memfree (qh gm_row, (qh hull_dim+1) * sizeof(coordT *));
7432 qh_setfree (&qh hash_table);
7433 qh_setfree (&qh other_points);
7434 qh_setfree (&qh del_vertices);
7435 /* qh facet_mergeset is a temp */
7436 qh NEARzero= qh lower_threshold= qh upper_threshold= NULL;
7437 qh lower_bound= qh upper_bound= NULL;
7438 qh gm_matrix= NULL;
7439 qh gm_row= NULL;
7440 if (qh line)
7441 free (qh line);
7442 if (qh first_point && qh POINTSmalloc)
7443 free(qh first_point);
7444 trace5((qh ferr, "qh_freebuffers: finished\n"));
7445 } /* freebuffers */
7446
7447
7448 /*-------------------------------------------
7449 -freeqhull- free global memory
7450 if allmem, frees all allocated data structures
7451 else, frees all long memory
7452 rest of memory freed by qh_memfreeshort();
7453 */
qh_freeqhull(boolT allmem)7454 void qh_freeqhull (boolT allmem) {
7455 facetT *facet;
7456 vertexT *vertex;
7457 ridgeT *ridge, **ridgep;
7458 mergeT *merge, **mergep;
7459
7460 trace1((qh ferr, "qh_freeqhull: free global memory\n"));
7461 qh NOerrexit= True; /* no more setjmp */
7462 if (allmem) {
7463 qh_clearcenters (qh_none);
7464 while ((vertex= qh vertex_list)) {
7465 if (vertex->next)
7466 qh_delvertex (vertex);
7467 else {
7468 qh_memfree (vertex, sizeof(vertexT));
7469 qh vertex_list= NULL;
7470 }
7471 }
7472 }else if (qh VERTEXneighbors) {
7473 FORALLvertices
7474 qh_setfreelong (&(vertex->neighbors));
7475 }
7476 if (allmem) {
7477 FORALLfacets {
7478 if (!facet->visible) {
7479 FOREACHridge_(facet->ridges)
7480 ridge->seen= False;
7481 }
7482 }
7483 FORALLfacets {
7484 FOREACHridge_(facet->ridges)
7485 ridge->seen ^= True;
7486 }
7487 while ((facet= qh facet_list)) {
7488 FOREACHridge_(facet->ridges) {
7489 if (ridge->seen) {
7490 qh_setfree(&(ridge->vertices));
7491 qh_memfree(ridge, sizeof(ridgeT));
7492 }else
7493 ridge->seen= True;
7494 }
7495 if (facet->next)
7496 qh_delfacet (facet);
7497 else {
7498 qh_memfree (facet, sizeof(facetT));
7499 qh facet_list= NULL;
7500 }
7501 }
7502 }else {
7503 FORALLfacets {
7504 qh_setfreelong (&(facet->outsideset));
7505 qh_setfreelong (&(facet->coplanarset));
7506 if (!facet->simplicial) {
7507 qh_setfreelong (&(facet->neighbors));
7508 qh_setfreelong (&(facet->ridges));
7509 qh_setfreelong (&(facet->vertices));
7510 }
7511 }
7512 }
7513 qh_setfree (&qh hash_table);
7514 FOREACHmerge_(qh facet_mergeset) /* usually empty */
7515 qh_memfree (merge, sizeof(mergeT));
7516 qh_freebuffers();
7517 qh_freestatistics();
7518 qh_settempfree_all();
7519 #if qh_QHpointer
7520 free (qh_qh);
7521 qh_qh= NULL;
7522 #endif
7523 } /* freeqhull */
7524
7525
7526 /*---------------------------------------------
7527 -init_qhull_command- build qhull_command from argc/argv
7528 */
qh_init_qhull_command(int argc,char * argv[])7529 void qh_init_qhull_command(int argc, char *argv[]) {
7530 int i;
7531
7532 strcpy (qh qhull_command, argv[0]);
7533 for (i=1; i<argc; i++) {
7534 if (strlen (qh qhull_command) + strlen(argv[i]) + 1 < sizeof(qh qhull_command)) {
7535 strcat (qh qhull_command, " ");
7536 strcat (qh qhull_command, argv[i]);
7537 }else qhull_fatal(67);
7538
7539 }
7540 } /* init_qhull_command */
7541
7542 /*---------------------------------------------
7543 -initflags- set flags and initialized constants from command line
7544 strips off first word
7545 see 'prompt' in unix.c for documentation
7546 see also initthresholds
7547 strtol/strtod may or may not skip trailing spaces
7548 does not reset any flags
7549 use the qh structure to change flags during execution of qhull
7550
7551 */
7552
qh_initflags(char * command)7553 void qh_initflags(char *command) {
7554 int k;
7555 char *s= command, *t, *prev_s;
7556
7557 while (*s && !isspace(*s)) /* need a better convention */
7558 s++;
7559 while (*s) {
7560 while (*s && isspace(*s))
7561 s++;
7562 if (*s == '-')
7563 s++;
7564 prev_s= s;
7565 switch (*s++) {
7566 case 'd':
7567 qh DELAUNAY= True;
7568 break;
7569 case 'f':
7570 qh_appendprint (qh_PRINTfacets);
7571 break;
7572 case 'i':
7573 qh_appendprint (qh_PRINTincidences);
7574 break;
7575 case 'm':
7576 qh_appendprint (qh_PRINTmathematica);
7577 break;
7578 case 'n':
7579 qh_appendprint (qh_PRINTnormals);
7580 break;
7581 case 'o':
7582 qh_appendprint (qh_PRINToff);
7583 break;
7584 case 'p':
7585 qh_appendprint (qh_PRINTpoints);
7586 break;
7587 case 's':
7588 qh PRINTsummary= True;
7589 break;
7590 case 'v':
7591 qh VORONOI= True;
7592 qh DELAUNAY= True;
7593 break;
7594 case 'A':
7595 if (!isdigit(*s) && *s != '.' && *s != '-')
7596 fprintf(qh ferr, "qhull warning: no maximum cosine angle given for option A. Ignored.\n");
7597 else {
7598 if (*s == '-') {
7599 qh premerge_cos= -qh_strtod (s, &s);
7600 qh PREmerge= True;
7601 }else {
7602 qh postmerge_cos= qh_strtod (s, &s);
7603 qh POSTmerge= True;
7604 }
7605 qh MERGING= True;
7606 }
7607 break;
7608 case 'C':
7609 if (!isdigit(*s) && *s != '.' && *s != '-')
7610 fprintf(qh ferr, "qhull warning: no centrum radius given for option C. Ignored.\n");
7611 else {
7612 if (*s == '-') {
7613 qh premerge_centrum= -qh_strtod (s, &s);
7614 qh PREmerge= True;
7615 }else {
7616 qh postmerge_centrum= qh_strtod (s, &s);
7617 qh POSTmerge= True;
7618 }
7619 qh MERGING= True;
7620 }
7621 break;
7622 case 'E':
7623 if (*s == '-')
7624 fprintf(qh ferr, "qhull warning: negative maximum roundoff given for option A. Ignored.\n");
7625 else if (!isdigit(*s))
7626 fprintf(qh ferr, "qhull warning: no maximum roundoff given for option E. Ignored.\n");
7627 else {
7628 qh DISTround= qh_strtod (s, &s);
7629 qh SETroundoff= True;
7630 }
7631 break;
7632 case 'R':
7633 if (!isdigit(*s))
7634 fprintf(qh ferr, "qhull warning: no random perturbation given for option R. Ignored\n");
7635 else {
7636 qh RANDOMfactor= qh_strtod (s, &s);
7637 qh RANDOMdist= True;
7638 }
7639 break;
7640 case 'V':
7641 if (!isdigit(*s) && *s != '-')
7642 fprintf(qh ferr, "qhull warning: no distance given for option V. Ignored\n");
7643 else
7644 qh MINvisible= qh_strtod (s, &s);
7645 break;
7646 case 'W':
7647 if (*s == '-')
7648 fprintf(qh ferr, "qhull warning: negative width for option W. Ignored.\n");
7649 else if (!isdigit(*s))
7650 fprintf(qh ferr, "qhull warning: no hull width given for option W. Ignored\n");
7651 else {
7652 qh MINoutside= qh_strtod (s, &s);
7653 qh APPROXhull= True;
7654 }
7655 break;
7656 /************ sub menus ***************/
7657 case 'G':
7658 qh_appendprint (qh_PRINTgeom);
7659 while (*s && !isspace(*s)) {
7660 switch(*s++) {
7661 case 'a':
7662 qh PRINTdots= True;
7663 break;
7664 case 'c':
7665 qh PRINTcentrums= True;
7666 break;
7667 case 'h':
7668 qh DOintersections= True;
7669 break;
7670 case 'i':
7671 qh PRINTinner= True;
7672 break;
7673 case 'n':
7674 qh PRINTnoplanes= True;
7675 break;
7676 case 'o':
7677 qh PRINTouter= True;
7678 break;
7679 case 'p':
7680 qh PRINTcoplanar= True;
7681 break;
7682 case 'r':
7683 qh PRINTridges= True;
7684 break;
7685 case 'v':
7686 qh PRINTspheres= True;
7687 break;
7688 case 'D':
7689 if (!isdigit (*s))
7690 fprintf (qh ferr, "qhull input error: missing dimension for 'GD' option\n");
7691 else
7692 qh DROPdim= qh_strtol (s, &s);
7693 break;
7694 default:
7695 s--;
7696 fprintf (qh ferr, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]);
7697 while (*++s && !isspace(*s));
7698 break;
7699 }
7700 }
7701 break;
7702 case 'P':
7703 while (*s && !isspace(*s)) {
7704 switch(*s++) {
7705 case 'd': case 'D':
7706 qh_strtol (s, &s);
7707 if (*s == ':') {
7708 ++s;
7709 qh_strtod (s, &s);
7710 }
7711 break;
7712 case 'g':
7713 qh PRINTgood= True;
7714 break;
7715 case 'G':
7716 qh PRINTneighbors= True;
7717 break;
7718 case 'o':
7719 qh FORCEoutput= True;
7720 break;
7721 case 'p':
7722 qh PRINTprecision= False;
7723 break;
7724 default:
7725 s--;
7726 fprintf (qh ferr, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[-1]);
7727 while (*++s && !isspace(*s));
7728 break;
7729 }
7730 }
7731 break;
7732 case 'Q':
7733 while (*s && !isspace(*s)) {
7734 switch(*s++) {
7735 case 'b': case 'B':
7736 k= qh_strtol (s, &s);
7737 t= NULL;
7738 if (*s == ':' && qh_strtod(++s, &s) == 0.0) {
7739 t= s; /* need true dimension for memory allocation */
7740 while (*t && !isspace(*t)) {
7741 if (toupper(*t++) == 'B'
7742 && k == qh_strtol (t, &t)
7743 && *t++ == ':'
7744 && qh_strtod(t, &t) == 0.0) {
7745 qh PROJECTinput++;
7746 trace2((qh ferr, "qh_initflags: project dimension %d\n", k));
7747 break;
7748 }
7749 }
7750 }
7751 if (!t || !isspace(*t))
7752 qh SCALEinput= True;
7753 break;
7754 case 'c':
7755 qh KEEPcoplanar= True;
7756 break;
7757 case 'f':
7758 qh BESToutside= True;
7759 break;
7760 case 'g':
7761 qh ONLYgood= True;
7762 break;
7763 case 'i':
7764 qh KEEPinside= True;
7765 break;
7766 case 'm':
7767 qh ONLYmax= True;
7768 break;
7769 case 'r':
7770 qh RANDOMoutside= True;
7771 break;
7772 case 's':
7773 qh ALLpoints= True;
7774 break;
7775 case 'v':
7776 qh VIRTUALmemory= True;
7777 break;
7778 case 'G':
7779 if (qh GOODpoint) {
7780 fprintf (qh ferr, "qhull warning: good point already defined for QGn. Ignored\n");
7781 qh_strtol(s, &s);
7782 }else if (!isdigit(*s) && (*s != '-'))
7783 fprintf (qh ferr, "qhull warning: no good point id given for option QGn. Ignored\n");
7784 else if (*s == '-')
7785 qh GOODpoint= qh_strtol(s, &s)-1;
7786 else
7787 qh GOODpoint= qh_strtol(s, &s)+1;
7788 break;
7789 case 'R':
7790 if (!isdigit(*s) && *s != '-')
7791 fprintf (qh ferr, "qhull warning: missing random seed for option QRn. Ignored\n");
7792 else
7793 qh ROTATErandom= qh_strtol(s, &s);
7794 break;
7795 case 'V':
7796 if (qh GOODvertex) {
7797 fprintf (qh ferr, "qhull warning: good vertex already defined for QV. Ignored\n");
7798 qh_strtol(s, &s);
7799 }else if (!isdigit(*s) && (*s != '-'))
7800 fprintf (qh ferr, "qhull warning: no good point id given for QV. Ignored\n");
7801 else if (*s == '-')
7802 qh GOODvertex= qh_strtol(s, &s)-1;
7803 else
7804 qh GOODvertex= qh_strtol(s, &s)+1;
7805 break;
7806 default:
7807 fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[-1]);
7808 while (*++s && !isspace(*s));
7809 break;
7810 }
7811 }
7812 break;
7813 case 'T':
7814 while (*s && !isspace(*s)) {
7815 if (isdigit(*s) || *s == '-')
7816 qh IStracing= qh_strtol(s, &s);
7817 else switch(*s++) {
7818 case 'c':
7819 qh CHECKfrequently= True;
7820 break;
7821 case 's':
7822 qh PRINTstatistics= True;
7823 break;
7824 case 'v':
7825 qh VERIFYoutput= True;
7826 break;
7827 case 'C':
7828 if (!isdigit(*s))
7829 fprintf (qh ferr, "qhull warning: no point given for trace option C. Ignored\n");
7830 else
7831 qh STOPcone= qh_strtol (s, &s)+1;
7832 break;
7833 case 'F':
7834 if (!isdigit(*s))
7835 fprintf (qh ferr, "qhull warning: no count of new facets for trace option P. Ignored\n");
7836 else
7837 qh REPORTfreq= qh_strtol (s, &s);
7838 break;
7839 case 'P':
7840 if (!isdigit(*s))
7841 fprintf (qh ferr, "qhull warning: no point given for trace option P. Ignored\n");
7842 else
7843 qh TRACEpoint= qh_strtol (s, &s);
7844 break;
7845 case 'M':
7846 if (!isdigit(*s))
7847 fprintf (qh ferr, "qhull warning: no merge given for trace option M. Ignored\n");
7848 else
7849 qh TRACEmerge= qh_strtol (s, &s);
7850 break;
7851 case 'V':
7852 if (!isdigit(*s) && *s != '-')
7853 fprintf (qh ferr, "qhull warning: no point given for trace option V. Ignored\n");
7854 else if (*s == '-')
7855 qh STOPpoint= qh_strtol (s, &s)-1;
7856 else
7857 qh STOPpoint= qh_strtol (s, &s)+1;
7858 break;
7859 case 'W':
7860 if (!isdigit(*s))
7861 fprintf (qh ferr, "qhull warning: no max width given for trace option D. Ignored\n");
7862 else
7863 qh TRACEdist= (realT) qh_strtod (s, &s);
7864 break;
7865 default:
7866 fprintf (qh ferr, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[-1]);
7867 while (*++s && !isspace(*s));
7868 break;
7869 }
7870 }
7871 break;
7872 default:
7873 fprintf (qh ferr, "qhull warning: unknown flag %c (%x)\n", (int)s[-1],
7874 (int)s[-1]);
7875 break;
7876 }
7877 if (s-1 == prev_s && *s && !isspace(*s)) {
7878 fprintf (qh ferr, "qhull warning: missing space after flag %c (%x); reserved for menu. Skipped.\n",
7879 (int)*prev_s, (int)*prev_s);
7880 while (*s && !isspace(*s))
7881 s++;
7882 }
7883 }
7884 } /* initflags */
7885
7886
7887 /*-------------------------------------------
7888 -initqhull_buffers- initialize global memory buffers
7889 must match freebuffers()
7890 */
qh_initqhull_buffers(void)7891 void qh_initqhull_buffers (void) {
7892 int k;
7893
7894 qh TEMPsize= (qhmem.LASTsize - sizeof (setT))/SETelemsize;
7895 qh other_points= qh_setnew (qh TEMPsize);
7896 qh del_vertices= qh_setnew (qh TEMPsize);
7897 qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT));
7898 qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
7899 qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
7900 qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
7901 qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
7902 for(k= qh input_dim+1; k--; ) {
7903 qh lower_threshold[k]= -REALmax;
7904 qh upper_threshold[k]= REALmax;
7905 qh lower_bound[k]= -REALmax;
7906 qh upper_bound[k]= REALmax;
7907 }
7908 qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT));
7909 qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *));
7910 } /* initqhull_buffers */
7911
7912 /*---------------------------------------------
7913 -initqhull_globals- initialize globals
7914 ismalloc set if points were malloc'd and qhull should free at end
7915 returns:
7916 sets qh first_point, num_points, input_dim, hull_dim and others
7917 modifies hull_dim if ((DELAUNAY and PROJECTdelaunay) or PROJECTinput)
7918 seeds random number generator (seed=1 if tracing)
7919 adjust user flags as needed
7920 also checks hull_dim dependencies and constants
7921 */
qh_initqhull_globals(coordT * points,int numpoints,int dim,boolT ismalloc)7922 void qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc) {
7923 int seed, pointsneeded, extra= 0, i, randi;
7924 boolT printgeom= False, printother= False, printmath= False;
7925 realT randr;
7926
7927 time_t timedata;
7928
7929 trace0((qh ferr, "qh_initqhull_globals: for %s | %s\n", qh rbox_command,
7930 qh qhull_command));
7931 qh POINTSmalloc= ismalloc;
7932 qh first_point= points;
7933 qh num_points= numpoints;
7934 qh hull_dim= qh input_dim= dim;
7935 if (qh DELAUNAY) {
7936 qh KEEPcoplanar= True;
7937 qh KEEPinside= True;
7938 }
7939 if (qh PREmerge) {
7940 /* e.g., rbox 1000 t W8e-6 | qhull C-0, can drop an outside point, since
7941 qh_findbest doesn't detect nearly coplanar when point beyond facets */
7942 qh BESToutside= True;
7943 }
7944 if (qh MERGING)
7945 qh CENTERtype= qh_centrum;
7946 else if (qh VORONOI)
7947 qh CENTERtype= qh_voronoi;
7948 if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) {
7949 qh hull_dim -= qh PROJECTinput;
7950 if (qh DELAUNAY) {
7951 qh hull_dim++;
7952 extra= 1;
7953 }
7954 }
7955
7956 if (qh hull_dim <= 1) qhull_fatal(68);
7957
7958 trace2((qh ferr, "qh_initqhull_globals: initialize globals. dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n",
7959 dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim));
7960 qh normal_size= qh hull_dim * sizeof(coordT);
7961 qh center_size= qh normal_size - sizeof(coordT);
7962 pointsneeded= qh hull_dim+1;
7963 if (qh GOODpoint)
7964 pointsneeded++;
7965 if (qh GOODpoint > 0)
7966 qh GOODpointp= qh_point (qh GOODpoint-1);
7967 else if (qh GOODpoint < 0)
7968 qh GOODpointp= qh_point (-qh GOODpoint-1);
7969 if (qh GOODvertex > 0)
7970 qh GOODvertexp= qh_point (qh GOODvertex-1);
7971 else if (qh GOODvertex < 0)
7972 qh GOODvertexp= qh_point (-qh GOODvertex-1);
7973
7974 if ((qh GOODpointp
7975 && (qh GOODpointp < qh first_point
7976 || qh GOODpointp > qh_point (qh num_points-1)))
7977 || (qh GOODvertexp
7978 && (qh GOODvertexp < qh first_point
7979 || qh GOODvertexp > qh_point (qh num_points-1)))) qhull_fatal(69);
7980
7981 if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
7982 qh TRACElevel= (qh IStracing? qh IStracing : 3);
7983 qh IStracing= 0;
7984 }
7985 if (qh ROTATErandom == 0 || qh ROTATErandom == -1) {
7986 seed= time (&timedata);
7987 qh ROTATErandom= seed;
7988 }else if (qh ROTATErandom > 0)
7989 seed= qh ROTATErandom;
7990 else
7991 seed= 1;
7992 qh_RANDOMseed_(seed);
7993 randr= 0.0;
7994 for (i= 1000; i--; ) {
7995 randi= qh_RANDOMint;
7996 randr += randi;
7997
7998 /* DEBUG */
7999 /* - I reset qh_RANDOMmax in qhull.h, but not intelligently.
8000 Expect more trouble inn the future.
8001 printf("qh_RANDOMmax is %d.\n", qh_RANDOMmax);
8002 printf("randi is %d.\n", randi); */
8003
8004
8005 if (randi > qh_RANDOMmax) qhull_fatal(70);
8006
8007 }
8008 if (randr/1000 < qh_RANDOMmax/10)
8009 fprintf (qh ferr, "qhull configuration warning (initqhull_globals): average of 1000 randoms %.2g much less than expected (%.2g). Is qh_RANDOMmax wrong?\n",
8010 randr/1000, (double) (qh_RANDOMmax/2));
8011 qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
8012 qh RANDOMb= 1.0 - qh RANDOMfactor;
8013
8014 #ifndef __BCC55__
8015 // This condition is always false under BCC55
8016 if (qh_HASHfactor < 1.1) qhull_fatal(71);
8017 #endif // __BCC55__
8018
8019 if (numpoints+extra < pointsneeded) qhull_fatal(72);
8020
8021 for (i= qh_PRINTEND; i--; ) {
8022 if (qh PRINTout[i] == qh_PRINTmathematica)
8023 printmath= True;
8024 if (qh PRINTout[i] == qh_PRINTgeom)
8025 printgeom= True;
8026 else if (qh PRINTout[i])
8027 printother= True;
8028 }
8029 if (printmath && qh hull_dim > 3) qhull_fatal(73);
8030
8031 if (printgeom) {
8032
8033 if (qh hull_dim > 4) qhull_fatal(74);
8034
8035 if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums
8036 + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges))
8037 qhull_fatal(75);
8038
8039 if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) qhull_fatal(76);
8040
8041 if (qh hull_dim == 4 && qh DROPdim == -1 &&
8042 (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
8043 fprintf (qh ferr, "qhull input warning: coplanars, vertices, and centrums output not\n\
8044 available for 4-d output (ignored). Could use 'GDn' instead.\n");
8045 qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False;
8046 }
8047 }
8048 qh PRINTdim= qh hull_dim;
8049 if (qh DROPdim >=0) { /* after Geomview checks */
8050 if (qh DROPdim < qh hull_dim) {
8051 qh PRINTdim--;
8052 if (printother || qh hull_dim < 3)
8053 fprintf (qh ferr, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim);
8054 }else
8055 qh DROPdim= -1;
8056 }else if (qh VORONOI) {
8057 qh DROPdim= qh hull_dim-1;
8058 qh PRINTdim= qh hull_dim-1;
8059 }
8060 } /* initqhull_globals */
8061
8062 /*-----------------------------------------------------
8063 -initqhull_mem- initialize mem.c for qhull
8064 qh.hull_dim and normal_size determines some of the allocation sizes
8065 if qh MERGING, includes ridgeT
8066 returns:
8067 mem.c already for memalloc/memfree (errors if called beforehand)
8068 notes:
8069 the user can add up to 10 additional sizes for quick allocation (increase numsizes)
8070 */
qh_initqhull_mem(void)8071 void qh_initqhull_mem (void) {
8072 int numsizes;
8073 int i;
8074
8075 numsizes= 7+10;
8076 qh_meminitbuffers (qh IStracing, qh_MEMalign, numsizes,
8077 qh_MEMbufsize,qh_MEMinitbuf);
8078 qh_memsize(sizeof(vertexT));
8079 if (qh MERGING)
8080 qh_memsize(sizeof(ridgeT));
8081 qh_memsize(sizeof(facetT));
8082 qh_memsize(sizeof(hashentryT));
8083 i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize; /* ridge.vertices */
8084 qh_memsize(i);
8085 qh_memsize(qh normal_size); /* normal */
8086 i += SETelemsize; /* facet.vertices, .ridges, .neighbors */
8087 qh_memsize(i);
8088 /* qh_user_memsizes(); - THIS DID NOTHING */
8089 qh_memsetup();
8090 } /* initqhull_mem */
8091
8092 /*-------------------------------------------
8093 -initqhull_start -- start initialization of qhull
8094 inits statistics
8095 */
qh_initqhull_start(FILE * infile,FILE * outfile,FILE * errfile)8096 void qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile) {
8097
8098 clock(); /* start the clock */
8099 #if qh_QHpointer
8100 if (!(qh_qh= (qhT *)malloc (sizeof(qhT)))) {
8101 fprintf (errfile, "qhull error (initqhull_globals): insufficient memory\n");
8102 exit (qh_ERRmem); /* no error handler */
8103 }
8104 memset((char *)qh_qh, 0, sizeof(qhT)); /* every field is 0, FALSE, NULL */
8105 #else
8106 memset((char *)&qh_qh, 0, sizeof(qhT));
8107 #endif
8108 strcat (qh qhull, "qhull");
8109 qh_initstatistics();
8110 qh ferr= errfile;
8111 qh fin= infile;
8112 qh fout= outfile;
8113 qh lastreport= INT_MIN;
8114 qh mergereport= INT_MIN;
8115 qh max_outside= 0.0;
8116 qh maxmaxcoord= 0.0;
8117 qh max_vertex= 0.0;
8118 qh min_vertex= 0.0;
8119 qh MINdenom_1= fmax_(1.0/REALmax, REALmin);
8120 qh MINoutside= 0.0;
8121 qh MINvisible= REALmax;
8122 qh premerge_centrum= 0.0;
8123 qh premerge_cos= REALmax;
8124 qh PRINTprecision= True;
8125 qh PRINTradius= 0.0;
8126 qh postmerge_cos= REALmax;
8127 qh postmerge_centrum= 0.0;
8128 qh ROTATErandom= INT_MIN;
8129 qh DROPdim= -1;
8130 qh TRACEdist= REALmax;
8131 qh TRACEpoint= -1;
8132 qh tracefacet_id= (unsigned int) -1; /* stderr set these to id for tracefacet/tracevertex */
8133 qh tracevertex_id= (unsigned int) -1;
8134 } /* initqhull_start */
8135
8136 /*---------------------------------------------
8137 -initthresholds set thresholds for printing and scaling from command line
8138 see 'prompt' in unix.c for documentation
8139 see also initflags()
8140 sets qh GOODthreshold or qh SPLITthreshold if 'Pd0D1' used
8141 */
qh_initthresholds(char * command)8142 void qh_initthresholds(char *command) {
8143 realT value;
8144 int index, maxdim, k;
8145 char *s= command;
8146 char key;
8147
8148 maxdim= qh input_dim;
8149 if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput))
8150 maxdim++;
8151 while (*s) {
8152 if (*s == '-')
8153 s++;
8154 if (*s == 'P') {
8155 s++;
8156 while (*s && !isspace(key= *s++)) {
8157 if (key == 'd' || key == 'D') {
8158 if (!isdigit(*s)) {
8159 fprintf(qh ferr, "qhull warning: no dimension given for Print option %c. Ignored\n",
8160 key);
8161 continue;
8162 }
8163 index= qh_strtol (s, &s);
8164 if (index >= qh hull_dim) {
8165 fprintf(qh ferr, "qhull warning: dimension %d for Print option %c is >= %d. Ignored\n",
8166 index, key, qh hull_dim);
8167 continue;
8168 }
8169 if (*s == ':') {
8170 ++s;
8171 value= qh_strtod(s, &s);
8172 if (fabs((double)value) > 1.0) {
8173 fprintf(qh ferr, "qhull warning: value %2.4g for Print option %c is > +1 or < -1. Ignored\n",
8174 value, key);
8175 continue;
8176 }
8177 }else
8178 value= 0.0;
8179 if (key == 'd')
8180 qh lower_threshold[index]= value;
8181 else
8182 qh upper_threshold[index]= value;
8183 }
8184 }
8185 }else if (*s == 'Q') {
8186 s++;
8187 while (*s && !isspace(key= *s++)) {
8188 if (key == 'b' && *s == 'B') {
8189 s++;
8190 for (k=maxdim; k--; ) {
8191 qh lower_bound[k]= -qh_DEFAULTbox;
8192 qh upper_bound[k]= qh_DEFAULTbox;
8193 }
8194 }else if (key == 'b' || key == 'B') {
8195 if (!isdigit(*s)) {
8196 fprintf(qh ferr, "qhull warning: no dimension given for Qhull option %c. Ignored\n",
8197 key);
8198 continue;
8199 }
8200 index= qh_strtol (s, &s);
8201 if (index >= maxdim) {
8202 fprintf(qh ferr, "qhull warning: dimension %d for Qhull option %c is >= %d. Ignored\n",
8203 index, key, maxdim);
8204 continue;
8205 }
8206 if (*s == ':') {
8207 ++s;
8208 value= qh_strtod(s, &s);
8209 }
8210 else if (key == 'b')
8211 value= -qh_DEFAULTbox;
8212 else
8213 value= qh_DEFAULTbox;
8214 if (key == 'b')
8215 qh lower_bound[index]= value;
8216 else
8217 qh upper_bound[index]= value;
8218 }
8219 }
8220 }else {
8221 while (!isspace (*s))
8222 s++;
8223 }
8224 while (isspace (*s))
8225 s++;
8226 }
8227 for (k= qh hull_dim; k--; ) {
8228 if (qh lower_threshold[k] > -REALmax/2) {
8229 qh GOODthreshold= True;
8230 if (qh upper_threshold[k] < REALmax/2) {
8231 qh SPLITthresholds= True;
8232 qh GOODthreshold= False;
8233 break;
8234 }
8235 }else if (qh upper_threshold[k] < REALmax/2)
8236 qh GOODthreshold= True;
8237 }
8238 } /* initthresholds */
8239
8240 #if qh_QHpointer
8241 /*------------------------------------------
8242 -restore_qhull- restores a previously saved qhull
8243 also restores qh_qhstat and qhmem.tempstack
8244 errors if current qhull hasn't been saved or freed
8245 uses qhmem for error reporting
8246 */
qh_restore_qhull(qhT ** oldqh)8247 void qh_restore_qhull (qhT **oldqh) {
8248
8249 if (*oldqh && strcmp ((*oldqh)->qhull, "qhull")) qhull_fatal(77);
8250
8251 if (qh_qh) qhull_fatal(78);
8252
8253 if (!*oldqh || !(*oldqh)->old_qhstat) qhull_fatal(79);
8254
8255 qh_qh= *oldqh;
8256 *oldqh= NULL;
8257 qh_qhstat= qh old_qhstat;
8258 qhmem.tempstack= qh old_tempstack;
8259 trace1((qh ferr, "qh_restore_qhull: restored qhull from %x\n", (int) *oldqh));
8260 } /* restore_qhull */
8261
8262 /*------------------------------------------
8263 -save_qhull- saves qhull for a later qh_restore_qhull
8264 also saves qh_qhstat and qhmem.tempstack
8265 returns:
8266 qhull for a later restore_qhull
8267 qh_qh=NULL
8268 notes:
8269 need to initialize qhull or call qh_restore_qhull before continuing
8270 */
qh_save_qhull(void)8271 qhT *qh_save_qhull (void) {
8272 qhT *oldqh;
8273
8274 if (!qh_qh) qhull_fatal(80);
8275
8276 qh old_qhstat= qh_qhstat;
8277 qh_qhstat= NULL;
8278 qh old_tempstack= qhmem.tempstack;
8279 qhmem.tempstack= NULL;
8280 oldqh= qh_qh;
8281 qh_qh= NULL;
8282 trace1((qhmem.ferr, "qh_save_qhull: saved qhull %x\n", (int) oldqh));
8283 return oldqh;
8284 } /* save_qhull */
8285
8286 #endif
8287
8288 /*-----------------------------------------
8289 -strtol/tod -- internal versions that don't skip trailing spaces
8290 */
qh_strtod(const char * s,char ** endp)8291 double qh_strtod (const char *s, char **endp) {
8292 double result;
8293
8294 result= strtod (s, endp);
8295 if (s < (*endp) && (*endp)[-1] == ' ')
8296 (*endp)--;
8297 return result;
8298 } /* strtod */
8299
qh_strtol(const char * s,char ** endp)8300 int qh_strtol (const char *s, char **endp) {
8301 int result;
8302
8303 result= (int) strtol (s, endp, 10);
8304 if (s< (*endp) && (*endp)[-1] == ' ')
8305 (*endp)--;
8306 return result;
8307 } /* strtol */
8308
8309
8310
8311 /*************************************************************************/
8312 /****************** implementation code from qhull.c *********************/
8313 /*************************************************************************/
8314
8315 /* qhull - Quickhull algorithm for convex hulls
8316
8317 qhull() and top-level routines
8318
8319 see README, qhull.h, unix.c and mac.c
8320
8321 see qhull_a.h for internal functions
8322
8323 copyright (c) 1993-1994 The Geometry Center
8324 */
8325
8326
8327 /*-------------------------------------------------
8328 -qhull- hull_dim convex hull of num_points starting at first_point
8329 returns:
8330 returns facet_list, numfacets, etc.
8331 */
qh_qhull(void)8332 void qh_qhull (void) {
8333 setT *maxpoints, *vertices;
8334 facetT *facet;
8335 int numpart, numoutside, i;
8336 vertexT *vertex;
8337 realT dist;
8338 boolT isoutside;
8339
8340 qh hulltime= clock();
8341 if (qh DELAUNAY && qh upper_threshold[qh hull_dim-1] > REALmax/2
8342 && qh lower_threshold[qh hull_dim-1] < -REALmax/2) {
8343 for (i= qh_PRINTEND; i--; ) {
8344 if (qh PRINTout[i] == qh_PRINTgeom && qh DROPdim < 0
8345 && !qh GOODthreshold && !qh SPLITthresholds)
8346 break; /* in this case, don't set upper_threshold */
8347 }
8348 if (i < 0) {
8349 qh upper_threshold[qh hull_dim-1]= 0.0;
8350 if (!qh GOODthreshold)
8351 qh SPLITthresholds= True;
8352 }
8353 }
8354 maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim);
8355 /* qh_maxmin sets DISTround and other precision constants */
8356 vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points);
8357 qh_initialhull (vertices); /* initial qh facet_list */
8358 qh_partitionall (vertices, qh first_point, qh num_points);
8359 if (qh PREmerge) {
8360 qh cos_max= qh premerge_cos;
8361 qh centrum_radius= qh premerge_centrum;
8362 }
8363 if (qh ONLYgood) {
8364
8365 if (!(qh GOODthreshold || qh GOODpoint
8366 || (qh GOODvertex > 0 && !qh MERGING))) qhull_fatal(81);
8367
8368 if (qh GOODvertex > 0 && !qh MERGING /* matches qh_partitionall */
8369 && !qh_isvertex (qh GOODvertexp, vertices)) {
8370 facet= qh_findbest (qh GOODvertexp, qh facet_list, False, 0,
8371 &dist, &isoutside, &numpart);
8372 zadd_(Zdistgood, numpart);
8373
8374 if (!isoutside) qhull_fatal(82);
8375
8376 if (!qh_addpoint (qh GOODvertexp, facet, False)) {
8377 qh_settempfree(&vertices);
8378 qh_settempfree(&maxpoints);
8379 return;
8380 }
8381 }
8382 qh_findgood (qh facet_list, 0);
8383 }
8384 qh_settempfree(&vertices);
8385 qh_settempfree(&maxpoints);
8386 qh_buildhull();
8387 if (qh POSTmerge && !qh STOPpoint && !qh STOPcone) {
8388 qh POSTmerging= True;
8389 qh cos_max= qh postmerge_cos;
8390 qh centrum_radius= qh postmerge_centrum;
8391 FORALLfacets
8392 zinc_(Zpostfacets);
8393 qh newfacet_list= qh facet_list;
8394 qh visible_list= qh facet_list;
8395 qh newfacet_id= 0;
8396 qh newvertex_list= qh vertex_list;
8397 FORALLvertices
8398 vertex->newlist= True;
8399 qh_vertexneighbors (/*qh facet_list*/);
8400 qh_merge_nonconvex(/*qh newfacet_list*/);
8401 qh_partitionvisible (/*visible_list, newfacet_list*/ (boolT)!qh_ALL, &numoutside);
8402 qh_deletevisible (/*qh visible_list*/);
8403 qh POSTmerging= False;
8404 qh cos_max= qh premerge_cos;
8405 qh centrum_radius= qh premerge_centrum;
8406 }
8407 if (!qh FORCEoutput && (qh MERGING || qh APPROXhull))
8408 qh_check_maxout ();
8409
8410 if (qh_setsize ((setT *)qhmem.tempstack) != 0) qhull_fatal(83);
8411
8412 qh hulltime= clock() - qh hulltime;
8413 qh QHULLfinished= True;
8414 trace1((qh ferr, "qh_qhull: algorithm completed\n"));
8415 } /* qhull */
8416
8417 /*-------------------------------------------------
8418 -addpoint- add point to hull above a facet
8419 if checkdist or !facet, locates a facet for the point
8420 if !checkdist and facet, assumes point is above facet (major damage if below)
8421 returns:
8422 if unknown point, adds it to qh other_points
8423 False if user requested break
8424 */
qh_addpoint(pointT * furthest,facetT * facet,boolT checkdist)8425 boolT qh_addpoint (pointT *furthest, facetT *facet, boolT checkdist) {
8426 int goodvisible, goodhorizon;
8427 vertexT *vertex;
8428 facetT *newfacet;
8429 realT dist, newbalance, pbalance;
8430 boolT isoutside= False;
8431 int numpart, numpoints;
8432
8433 if (qh_pointid (furthest) == -1)
8434 qh_setappend (&qh other_points, furthest);
8435 if (checkdist || !facet) {
8436 if (!facet)
8437 facet= qh facet_list;
8438 facet= qh_findbest (furthest, facet, False, 0, &dist, &isoutside, &numpart);
8439 zzadd_(Zpartition, numpart);
8440 if (!isoutside) {
8441 zinc_(Znotmax); /* last point of outsideset is no longer furthest. */
8442 qh_partitioncoplanar (furthest, facet, &dist);
8443 return True;
8444 }
8445 }
8446 qh_buildtracing (furthest, facet);
8447 if (qh STOPpoint < 0 && qh furthest_id == -qh STOPpoint-1)
8448 return False;
8449 qh_findhorizon (furthest, facet, &goodvisible, &goodhorizon);
8450 if (qh ONLYgood && !(goodvisible+goodhorizon)) {
8451 zinc_(Znotgood);
8452 /* last point of outsideset is no longer furthest. This is ok
8453 since all points of the outside are likely to be bad */
8454 qh_clearvisible (/*qh visible_list*/);
8455 return True;
8456 }
8457 zzinc_(Zprocessed);
8458 vertex= qh_makenewfacets (furthest /*visible_list, attaches if !ONLYgood */);
8459 newbalance= qh facet_id - qh newfacet_id;
8460 newbalance -= (realT) (qh num_facets-qh num_visible)*qh hull_dim/qh num_vertices;
8461 wadd_(Wnewbalance, newbalance);
8462 wadd_(Wnewbalance2, newbalance * newbalance);
8463 if (qh ONLYgood && !qh_findgood (qh newfacet_list, goodhorizon)) {
8464 FORALLnew_facets
8465 qh_delfacet (newfacet);
8466 qh_delvertex (vertex);
8467 qh_clearvisible (/*qh visible_list*/);
8468 qh_clearnewvertices (/* qh newvertex_list*/);
8469 zinc_(Znotgoodnew);
8470 return True;
8471 }
8472 qh_attachnewfacets(/*visible_list*/);
8473 qh_matchnewfacets();
8474 if (qh STOPcone && qh furthest_id == qh STOPcone-1)
8475 return False;
8476 if (qh PREmerge)
8477 qh_merge_nonconvex(/*qh newfacet_list*/);
8478 qh_partitionvisible (/*visible_list, newfacet_list*/ (boolT)!qh_ALL, &numpoints);
8479 zinc_(Zpbalance);
8480 pbalance= numpoints - (realT) qh hull_dim /* assumes all points extreme */
8481 * (qh num_points - qh num_vertices)/qh num_vertices;
8482 wadd_(Wpbalance, pbalance);
8483 wadd_(Wpbalance2, pbalance * pbalance);
8484 qh_deletevisible (/*qh visible_list*/);
8485 qh_clearnewvertices (/* qh newvertex_list*/);
8486
8487 /*
8488 if (qh IStracing >= 4)
8489 qh_printfacetlist (qh newfacet_list, NULL, True);
8490 NO LONGER IN SERVICE */
8491
8492 if (qh CHECKfrequently) {
8493 if (qh num_facets < 50)
8494 qh_checkpolygon (qh facet_list);
8495 else
8496 qh_checkpolygon (qh newfacet_list);
8497 }
8498 if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1)
8499 return False;
8500 trace2((qh ferr, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n",
8501 qh_pointid (furthest), qh facet_id - qh newfacet_id, newbalance, pbalance));
8502 qh newfacet_id= qh facet_id;
8503 qh newfacet_list= NULL;
8504 return True;
8505 } /* addpoint */
8506
8507 /*-------------------------------------------------
8508 -buildhull- constructs a hull by adding outside points one at a time
8509 may be called multiple times
8510 checks facet and vertex lists for 'visible' and 'newlist'
8511 notes:
8512 to recover from STOPcone, call qh_deletevisible and qh_clearnewvertices
8513 */
qh_buildhull(void)8514 void qh_buildhull(void) {
8515 facetT *facet;
8516 pointT *furthest;
8517 vertexT *vertex;
8518 int id;
8519
8520 trace1((qh ferr, "qh_buildhull: start build hull\n"));
8521 FORALLfacets {
8522
8523 if (facet->visible) qhull_fatal(84);
8524
8525 }
8526 FORALLvertices {
8527
8528 if (vertex->newlist) qhull_fatal(85);
8529
8530 id= qh_pointid (vertex->point);
8531 if ((qh STOPpoint>0 && id == qh STOPpoint-1) ||
8532 (qh STOPpoint<0 && id == -qh STOPpoint-1) ||
8533 (qh STOPcone>0 && id == qh STOPcone-1)) {
8534 trace1((qh ferr,"qh_buildhull: stop point or cone P%d in initial hull\n", id));
8535 return;
8536 }
8537 }
8538 qh facet_next= qh facet_list; /* advance facet when processed */
8539 while ((furthest= qh_nextfurthest (&facet))) {
8540 qh num_outside--;
8541 if (!qh_addpoint (furthest, facet, qh ONLYmax))
8542 break;
8543 }
8544 if (qh num_outside && !furthest) qhull_fatal(86);
8545
8546 trace1((qh ferr, "qh_buildhull: completed the hull construction\n"));
8547 } /* buildhull */
8548
8549
8550 /*-------------------------------------------
8551 -buildtracing- for tracing execution of buildhull
8552 also resets visit_id, vertext_visit on wrap around
8553 */
qh_buildtracing(pointT * furthest,facetT * facet)8554 void qh_buildtracing (pointT *furthest, facetT *facet) {
8555 realT cpu, dist;
8556 time_t timedata;
8557 struct tm *tp;
8558 vertexT *vertex;
8559
8560 qh furthest_id= qh_pointid(furthest);
8561 if (qh TRACEpoint == qh furthest_id) {
8562 qh IStracing= qh TRACElevel;
8563 qhmem.IStracing= qh TRACElevel;
8564 }
8565 if (qh REPORTfreq && (zzval_(Zsetplane) > qh lastreport+qh REPORTfreq)) {
8566 qh lastreport= zzval_(Zsetplane);
8567 time (&timedata);
8568 tp= localtime (&timedata);
8569 cpu= clock();
8570 cpu /= qh_SECticks;
8571 zinc_(Zdistio);
8572 qh_distplane (furthest, facet, &dist);
8573 fprintf (qh ferr, "\n\
8574 At %d:%d:%d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\
8575 The current hull contains %d facets and %d vertices. There are %d\n\
8576 outside points. Next is point p%d (v%d), %2.2g above f%d.\n",
8577 tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, zzval_(Zsetplane),
8578 zzval_(Ztotmerge), qh num_facets, qh num_vertices, qh num_outside+1,
8579 qh furthest_id, qh vertex_id, dist, facet->id);
8580 }else if (qh IStracing >=1) {
8581 cpu= clock();
8582 cpu /= qh_SECticks;
8583 qh_distplane (furthest, facet, &dist);
8584 fprintf (qh ferr, "qh_buildhull: add p%d (v%d) to hull of %d facets (%2.2g above f%d) and %d outside. %4.4g CPU secs.\n",
8585 qh furthest_id, qh vertex_id, qh num_facets, dist,
8586 facet->id, qh num_outside+1, cpu);
8587 }
8588 #ifndef __BCC55__
8589 // This condition is always false under BCC55
8590 if (qh visit_id > INT_MAX) {
8591 qh visit_id= 0;
8592 FORALLfacets
8593 facet->visitid= qh visit_id;
8594 }
8595 #endif // __BCC55__
8596 #ifndef __BCC55__
8597 // This condition is always false under BCC55
8598 if (qh vertex_visit > INT_MAX) {
8599 qh vertex_visit= 0;
8600 FORALLvertices
8601 vertex->visitid= qh vertex_visit;
8602 }
8603 #endif // __BCC55__
8604 } /* buildtracing */
8605
8606 /*-------------------------------------------
8607 -errexit2- return exitcode to system after an error
8608 assumes exitcode non-zero
8609 for two facets, see qh_errexit() in user.c
8610 */
qh_errexit2(int exitcode,facetT * facet,facetT * otherfacet)8611 void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) {
8612 qhull_fatal(87);
8613 } /* errexit2 */
8614
8615
8616 /*-------------------------------------------------
8617 -findgood- identify good facets for qh ONLYgood
8618 GOODvertex>0 - facet includes point as vertex
8619 if !match, returns goodhorizon
8620 inactive if qh MERGING
8621 GOODpoint - facet is visible or coplanar (>0) or not visible (<0)
8622 GOODthreshold - facet->normal matches threshold
8623 if !goodhorizon and !match, selects facet with closest angle
8624 and sets GOODclosest
8625 returns:
8626 number of new, good facets found
8627 determins facet->good
8628 may update GOODclosest
8629 notes:
8630 findgood_all further reduces the good region
8631 */
qh_findgood(facetT * facetlist,int goodhorizon)8632 int qh_findgood (facetT *facetlist, int goodhorizon) {
8633 facetT *facet, *bestfacet;
8634 realT angle, bestangle, dist;
8635 int numgood=0;
8636
8637 if (qh GOODclosest) {
8638 bestfacet= qh GOODclosest;
8639 qh_inthresholds (bestfacet->normal, &bestangle);
8640 }else {
8641 bestfacet= NULL;
8642 bestangle= -REALmax;
8643 }
8644 FORALLfacet_(facetlist) {
8645 if (facet->good)
8646 numgood++;
8647 }
8648 if (qh GOODvertex>0 && !qh MERGING) {
8649 FORALLfacet_(facetlist) {
8650 if (!qh_isvertex (qh GOODvertexp, facet->vertices)) {
8651 facet->good= False;
8652 numgood--;
8653 }
8654 }
8655 }
8656 if (qh GOODpoint && numgood) {
8657 FORALLfacet_(facetlist) {
8658 if (facet->good) {
8659 zinc_(Zdistgood);
8660 qh_distplane (qh GOODpointp, facet, &dist);
8661 if ((qh GOODpoint > 0) ^ (dist > 0.0)) {
8662 facet->good= False;
8663 numgood--;
8664 }
8665 }
8666 }
8667 }
8668 if (qh GOODthreshold && (numgood || goodhorizon)) {
8669 FORALLfacet_(facetlist) {
8670 if (facet->good) {
8671 if (!qh_inthresholds (facet->normal, &angle)) {
8672 facet->good= False;
8673 numgood--;
8674 angle= fabs_(angle);
8675 if (angle > bestangle) {
8676 bestangle= angle;
8677 bestfacet= facet;
8678 }
8679 }
8680 }
8681 }
8682 if (!numgood && bestfacet && bestfacet != qh GOODclosest) {
8683 if (qh GOODclosest)
8684 qh GOODclosest->good= False;
8685 qh GOODclosest= bestfacet;
8686 bestfacet->good= True;
8687 numgood++;
8688 trace2((qh ferr, "qh_findgood: f%d is closest (%2.2g) to thresholds\n",
8689 bestfacet->id, bestangle));
8690 return numgood;
8691 }else if (numgood && qh GOODclosest)
8692 qh GOODclosest->good= False;
8693 }
8694 zadd_(Zgoodfacet, numgood);
8695 trace2((qh ferr, "qh_findgood: found %d good facets\n", numgood));
8696 if (!numgood && qh GOODvertex>0 && !qh MERGING)
8697 return goodhorizon;
8698 return numgood;
8699 } /* findgood */
8700
8701 /*-------------------------------------------------
8702 -findgood_all- apply other constraints for good facets (used by qh PRINTgood)
8703 GOODvertex - facet includes (>0) or doesn't include (<0) point as vertex
8704 if last good facet, prints warning and continues
8705 SPLITthreshold - facet->normal matches threshold, or if none, the closest one
8706 calls findgood if !ONLYgood
8707 returns:
8708 clears facet->good if not good
8709 sets qh num_good
8710 notes:
8711 this is like findgood but more restrictive
8712 */
qh_findgood_all(facetT * facetlist)8713 void qh_findgood_all (facetT *facetlist) {
8714 facetT *facet, *bestfacet=NULL;
8715 realT angle, bestangle= REALmax;
8716 int numgood=0, startgood;
8717
8718 if (!qh ONLYgood)
8719 qh_findgood (qh facet_list, 0);
8720 FORALLfacet_(facetlist) {
8721 if (facet->good)
8722 numgood++;
8723 }
8724 if (qh GOODvertex <0 || (qh GOODvertex > 0 && qh MERGING)) {
8725 FORALLfacet_(facetlist) {
8726 if ((qh GOODvertex > 0) ^ !!qh_isvertex (qh GOODvertexp, facet->vertices)) {
8727 if (!--numgood) {
8728 fprintf (qh ferr, "qhull warning: good vertex p%d does not match last good facet f%d. Ignored.\n",
8729 qh_pointid(qh GOODvertexp), facet->id);
8730 return;
8731 }
8732 facet->good= False;
8733 }
8734 }
8735 }
8736 startgood= numgood;
8737 if (qh SPLITthresholds) {
8738 FORALLfacet_(facetlist) {
8739 if (facet->good) {
8740 if (!qh_inthresholds (facet->normal, &angle)) {
8741 facet->good= False;
8742 numgood--;
8743 angle= fabs_(angle);
8744 if (angle < bestangle) {
8745 bestangle= angle;
8746 bestfacet= facet;
8747 }
8748 }
8749 }
8750 }
8751 if (!numgood) {
8752 bestfacet->good= True;
8753 numgood++;
8754 trace0((qh ferr, "qh_findgood_all: f%d is closest (%2.2g) to thresholds\n",
8755 bestfacet->id, bestangle));
8756 return;
8757 }
8758 }
8759 qh num_good= numgood;
8760 trace0((qh ferr, "qh_findgood_all: %d good facets remain out of %d facets\n",
8761 numgood, startgood));
8762 } /* findgood_all */
8763
8764 /*-------------------------------------------------
8765 -findhorizon- given a visible facet, find the point's horizon and visible facets
8766 returns:
8767 qh visible_list to all visible facets
8768 marks visible facets with ->visible
8769 goodvisible counts visible->good
8770 initializes num_visible
8771 notes:
8772 similar to delpoint()
8773 */
qh_findhorizon(pointT * point,facetT * facet,int * goodvisible,int * goodhorizon)8774 void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) {
8775 facetT *neighbor, **neighborp, *visible;
8776 int numhorizon= 0;
8777 realT dist;
8778 #if qh_MAXoutside
8779 boolT ckminvis= (boolT)(qh MINvisible > qh DISTround), isoutside;
8780 #endif
8781
8782 trace1((qh ferr,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id));
8783 *goodvisible= *goodhorizon= 0;
8784 zinc_(Ztotvisible);
8785 qh_removefacet(facet); /* visible_list at end of qh facet_list */
8786 qh_appendfacet(facet);
8787 qh num_visible= 1;
8788 if (facet->good)
8789 (*goodvisible)++;
8790 qh visible_list= facet;
8791 facet->visible= True;
8792
8793 /*
8794 if (qh IStracing >=4)
8795 qh_errprint ("visible", facet, NULL, NULL, NULL);
8796 NO LONGER IN SERVICE */
8797
8798 qh visit_id++;
8799 FORALLvisible_facets {
8800 visible->visitid= qh visit_id;
8801 FOREACHneighbor_(visible) {
8802 if ((int)neighbor->visitid == qh visit_id)
8803 continue;
8804 neighbor->visitid= qh visit_id;
8805 zzinc_(Znumvisibility);
8806 qh_distplane(point, neighbor, &dist);
8807 #if qh_MAXoutside
8808 isoutside= False;
8809 if (ckminvis) {
8810 if (dist >= qh MINvisible)
8811 isoutside= True;
8812 }else if (qh ONLYmax) { /* furthest points are at least maxoutside above */
8813 if (dist >= neighbor->maxoutside || dist >= qh max_vertex)
8814 isoutside= True;
8815 }else if (qh PREmerge) {
8816 if (dist >= qh MINoutside)
8817 isoutside= True;
8818 }else if (dist > qh DISTround)
8819 isoutside= True;
8820 if (isoutside) {
8821 #else
8822 if (dist > qh MINvisible) {
8823 #endif
8824 zinc_(Ztotvisible);
8825 qh_removefacet(neighbor); /* append to end of qh visible_list */
8826 qh_appendfacet(neighbor);
8827 neighbor->visible= True;
8828 qh num_visible++;
8829 if (neighbor->good)
8830 (*goodvisible)++;
8831
8832 /*
8833 if (qh IStracing >=4)
8834 qh_errprint ("visible", neighbor, NULL, NULL, NULL);
8835 NO LONGER IN SERVICE */
8836
8837 }else {
8838 if (dist > -qh DISTround) {
8839 zzinc_(Zcoplanarhorizon);
8840 trace0((qh ferr, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible (%2.7g)\n",
8841 qh_pointid(point), neighbor->id, dist, qh MINvisible));
8842 }
8843 zinc_(Ztothorizon);
8844 numhorizon++;
8845 if (neighbor->good)
8846 (*goodhorizon)++;
8847
8848 /*
8849 if (qh IStracing >=4)
8850 qh_errprint ("horizon", neighbor, NULL, NULL, NULL);
8851 NO LONGER IN SERVICE */
8852
8853 }
8854 }
8855 }
8856
8857 if (!numhorizon) qhull_fatal(88);
8858
8859 trace1((qh ferr, "qh_findhorizon: %d horizon facets (good %d), %d visible (good %d) min visible %2.2g\n",
8860 numhorizon, *goodhorizon, qh num_visible, *goodvisible, qh MINvisible));
8861 if (qh IStracing >= 4 && qh num_facets < 50)
8862 qh_printlists ();
8863 } /* findhorizon */
8864
8865
8866 /*--------------------------------------------------
8867 -initialhull- constructs the initial hull as a qh hull_dim simplex of vertices
8868 */
8869 void qh_initialhull(setT *vertices) {
8870 facetT *facet, *firstfacet;
8871 int k;
8872 realT dist;
8873
8874 qh_createsimplex(vertices); /* qh facet_list */
8875 qh interior_point= qh_getcenter(vertices);
8876 firstfacet= qh facet_list;
8877 qh_setfacetplane(firstfacet);
8878 zinc_(Znumvisibility); /* needs to be in printsummary */
8879 qh_distplane(qh interior_point, firstfacet, &dist);
8880 if (dist > 0) {
8881 FORALLfacets
8882 facet->toporient ^= True;
8883 }
8884 FORALLfacets
8885 qh_setfacetplane(facet);
8886 FORALLfacets {
8887 if (!qh_checkflipped (facet, NULL, qh_ALL)) {/* due to axis-parallel facet */
8888 trace1((qh ferr, "qh_initialhull: initial orientation incorrect. Correct all facets\n"));
8889 facet->flipped= False;
8890 FORALLfacets {
8891 facet->toporient ^= True;
8892 qh_orientoutside (facet);
8893 }
8894 break;
8895 }
8896 }
8897 FORALLfacets {
8898
8899 if (!qh_checkflipped (facet, NULL, (boolT)!qh_ALL)) qhull_fatal(89);
8900
8901 }
8902 zzval_(Zprocessed)= qh hull_dim+1;
8903 qh_checkpolygon (qh facet_list);
8904 qh_checkconvex(qh facet_list, qh_DATAfault);
8905 if (qh IStracing >= 1) {
8906 fprintf(qh ferr, "qh_initialhull: simplex constructed, interior point:");
8907 for (k=0; k<qh hull_dim; k++)
8908 fprintf (qh ferr, " %6.4g", qh interior_point[k]);
8909 fprintf (qh ferr, "\n");
8910 }
8911 if (qh PREmerge)
8912 qh_vertexneighbors (/*qh facet_list*/);
8913 } /* initialhull */
8914
8915 /*-------------------------------------------------
8916 -initialvertices- determines a non-singular set of initial vertices
8917 picks random points if qh RANDOMoutside && !ALLpoints
8918 all maxpoints are unique
8919 returns:
8920 temporary set of dim+1 vertices in descending order by vertex id
8921 notes:
8922 unless qh ALLpoints, uses maxpoints as long as determinate is non-zero
8923 */
8924 setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) {
8925 pointT *point, **pointp;
8926 setT *vertices, *simplex;
8927 realT randr;
8928 int index, point_i, point_n;
8929
8930 vertices= qh_settemp (dim + 1);
8931 simplex= qh_settemp (dim+1);
8932 if (qh ALLpoints)
8933 qh_maxsimplex (dim, NULL, points, numpoints, &simplex);
8934 else if (qh RANDOMoutside) {
8935 while (qh_setsize (simplex) != dim+1) {
8936 randr= qh_RANDOMint;
8937 randr= randr/(qh_RANDOMmax+1.0);
8938 index= (int)floor(qh num_points * randr);
8939 point= qh_point (index);
8940 qh_setunique (&simplex, point);
8941 }
8942 }else if (qh hull_dim >= 8) {
8943 qh_setunique (&simplex, SETfirst_(maxpoints));
8944 FOREACHpoint_i_(maxpoints) {
8945 if (point_i & 0x1) { /* first pick up max/min x and max points */
8946 qh_setunique (&simplex, point);
8947 if (qh_setsize (simplex) == dim) /* search for last point */
8948 break;
8949 }
8950 }
8951 if (qh_setsize (simplex) != dim) {
8952 while ((point= (pointT *)qh_setdellast (maxpoints))) {
8953 qh_setunique (&simplex, point);
8954 if (qh_setsize (simplex) == dim)
8955 break;
8956 }
8957 }
8958 index= 0;
8959 while (qh_setsize (simplex) != dim) {
8960 point= qh_point (index++);
8961 qh_setunique (&simplex, point);
8962 }
8963 qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
8964 }else
8965 qh_maxsimplex (dim, maxpoints, points, numpoints, &simplex);
8966 FOREACHpoint_(simplex)
8967 qh_setaddnth (&vertices, 0, qh_newvertex(point)); /* descending order */
8968 qh_settempfree (&simplex);
8969 return vertices;
8970 } /* initialvertices */
8971
8972
8973 /*------------------------------------------------
8974 -nextfurthest- returns next furthest point for processing
8975 returns:
8976 NULL if none available
8977 visible facet for furthest
8978 removes empty outside sets
8979 */
8980 pointT *qh_nextfurthest (facetT **visible) {
8981 facetT *facet;
8982 int size; /* , index; UNUSED */
8983 /* realT randr; UNUSED */
8984 pointT *furthest;
8985
8986 while ((facet= qh facet_next) != qh facet_tail) {
8987 if (!facet->outsideset) {
8988 qh facet_next= facet->next;
8989 continue;
8990 }
8991 SETreturnsize_(facet->outsideset, size);
8992 if (!size) {
8993 qh_setfree (&facet->outsideset);
8994 qh facet_next= facet->next;
8995 continue;
8996 }
8997 if (!qh RANDOMoutside && !qh VIRTUALmemory) {
8998 *visible= facet;
8999 return (pointT *)(qh_setdellast (facet->outsideset));
9000 }
9001 if (qh RANDOMoutside) qhull_fatal(90);
9002
9003 else { /* VIRTUALmemory */
9004 facet= qh facet_tail->previous;
9005 if (!(furthest= (pointT *)qh_setdellast(facet->outsideset))) {
9006 if (facet->outsideset)
9007 qh_setfree (&facet->outsideset);
9008 qh_removefacet (facet);
9009 qh_prependfacet (facet, &qh facet_list);
9010 continue;
9011 }
9012 *visible= facet;
9013 return furthest;
9014 }
9015 }
9016 return NULL;
9017 } /* nextfurthest */
9018
9019 /*-------------------------------------------------
9020 -partitionall- partitions all points into the outsidesets of facets
9021 vertices= set of vertices used by qh facet_list
9022 does not partition qh GOODpoint
9023 if ONLYgood && !MERGING, does not partition GOODvertex
9024 qh newfacet_id=0 for qh_findbest
9025 notes:
9026 faster if qh facet_list sorted by anticipated size of outside set
9027 */
9028 void qh_partitionall(setT *vertices, pointT *points, int numpoints){
9029 setT *pointset;
9030 vertexT *vertex, **vertexp;
9031 pointT *point, **pointp, *bestpoint;
9032 int size, point_i, point_n, point_end, remaining, i, id;
9033 facetT *facet;
9034 realT bestdist= -REALmax, dist;
9035
9036 trace1((qh ferr, "qh_partitionall: partition all points into outside sets\n"));
9037 pointset= qh_settemp (numpoints);
9038 pointp= SETaddr_(pointset, pointT);
9039 for (i=numpoints, point= points; i--; point += qh hull_dim)
9040 *(pointp++)= point;
9041 qh_settruncate (pointset, numpoints);
9042 FOREACHvertex_(vertices) {
9043 if ((id= qh_pointid(vertex->point)) >= 0)
9044 SETelem_(pointset, id)= NULL;
9045 }
9046 id= qh_pointid (qh GOODpointp);
9047 if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id)
9048 SETelem_(pointset, id)= NULL;
9049 if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/
9050 if ((id= qh_pointid(qh GOODvertexp)) >= 0)
9051 SETelem_(pointset, id)= NULL;
9052 }
9053 if (!qh BESToutside) {
9054 zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */
9055 remaining= qh num_facets;
9056 point_end= numpoints;
9057 FORALLfacets {
9058 size= point_end/(remaining--) + 100;
9059 facet->outsideset= qh_setnew (size);
9060 bestpoint= NULL;
9061 point_end= 0;
9062 FOREACHpoint_i_(pointset) {
9063 if (point) {
9064 zzinc_(Zpartitionall);
9065 qh_distplane (point, facet, &dist);
9066 if (dist < qh MINoutside)
9067 SETelem_(pointset, point_end++)= point;
9068 else {
9069 qh num_outside++;
9070 if (!bestpoint) {
9071 bestpoint= point;
9072 bestdist= dist;
9073 }else if (dist > bestdist) {
9074 qh_setappend (&facet->outsideset, bestpoint);
9075 bestpoint= point;
9076 bestdist= dist;
9077 }else
9078 qh_setappend (&facet->outsideset, point);
9079 }
9080 }
9081 }
9082 if (bestpoint) {
9083 qh_setappend (&facet->outsideset, bestpoint);
9084 #if !qh_COMPUTEfurthest
9085 facet->furthestdist= bestdist;
9086 #endif
9087 }else
9088 qh_setfree (&facet->outsideset);
9089 qh_settruncate (pointset, point_end);
9090 }
9091 }
9092 FOREACHpoint_i_(pointset) {
9093 if (point)
9094 qh_partitionpoint(point, qh facet_list);
9095 }
9096 qh_settempfree(&pointset);
9097
9098 /*
9099 if (qh IStracing >= 4)
9100 qh_printfacetlist (qh facet_list, NULL, True);
9101 NO LONGER IN SERVICE */
9102
9103 } /* partitionall */
9104
9105
9106 /*-------------------------------------------------
9107 -partitioncoplanar- partition coplanar point to a facet
9108 if dist NULL, searches from bestfacet, and does nothing if inside
9109 returns:
9110 max_ouside, num_coplanar updated
9111 if KEEPcoplanar or KEEPinside
9112 point assigned to best coplanarset
9113 */
9114 void qh_partitioncoplanar (pointT *point, facetT *facet, realT *dist) {
9115 facetT *bestfacet;
9116 pointT *oldfurthest;
9117 realT bestdist, dist2;
9118 int numpart= 0;
9119 boolT isoutside;
9120
9121 if (!dist) {
9122 bestfacet= qh_findbest (point, facet, True, 0, &bestdist, &isoutside, &numpart);
9123 zinc_(Ztotpartcoplanar);
9124 zzadd_(Zpartcoplanar, numpart);
9125 if (bestdist < qh min_vertex) {
9126 zinc_(Zcoplanarinside);
9127 if (!qh KEEPinside)
9128 return;
9129 }else
9130 qh num_coplanar++;
9131 }else {
9132 bestfacet= facet;
9133 bestdist= *dist;
9134 if (!qh KEEPinside || bestdist >= qh min_vertex)
9135 qh num_coplanar++;
9136 }
9137 if (qh KEEPcoplanar + qh KEEPinside) {
9138 oldfurthest= (pointT *)qh_setlast (bestfacet->coplanarset);
9139 if (oldfurthest) {
9140 zinc_(Zcomputefurthest);
9141 qh_distplane (oldfurthest, bestfacet, &dist2);
9142 }
9143 if (!oldfurthest || dist2 < bestdist) {
9144 qh_setappend(&bestfacet->coplanarset, point);
9145 maximize_(qh max_outside, bestdist);
9146 }else
9147 qh_setappend2ndlast(&bestfacet->coplanarset, point);
9148 }else
9149 maximize_(qh max_outside, bestdist);
9150 trace2((qh ferr, "qh_partitioncoplanar: point p%d is coplanar with facet f%d (or inside) dist %2.2g\n",
9151 qh_pointid(point), bestfacet->id, bestdist));
9152 } /* partitioncoplanar */
9153
9154
9155 /*-------------------------------------------------
9156 -partitionpoint- assigns point to a visible facet
9157 !BESToutside stops search when point is outside or new facets
9158 findbest does not search !newfacet_id if precise and !BESToutside
9159 */
9160 void qh_partitionpoint (pointT *point, facetT *facet) {
9161 realT bestdist;
9162 pointT *oldfurthest;
9163 boolT isoutside;
9164 facetT *bestfacet;
9165 int numpart;
9166
9167 bestfacet= qh_findbest (point, facet, qh BESToutside, qh newfacet_id,
9168 &bestdist, &isoutside, &numpart);
9169 zinc_(Ztotpartition);
9170 zzadd_(Zpartition, numpart);
9171 if (isoutside) {
9172 if (!bestfacet->outsideset
9173 || !(oldfurthest= (pointT *)qh_setlast (bestfacet->outsideset))) {
9174 qh_setappend(&(bestfacet->outsideset), point);
9175 if (bestfacet->id < qh newfacet_id) {
9176 qh_removefacet (bestfacet); /* move after qh facet_next */
9177 qh_appendfacet (bestfacet);
9178 }
9179 }else {
9180 #if qh_COMPUTEfurthest
9181 zinc_(Zcomputefurthest);
9182 qh_distplane (oldfurthest, bestfacet, &dist);
9183 if (dist < bestdist)
9184 qh_setappend(&(bestfacet->outsideset), point);
9185 else
9186 qh_setappend2ndlast(&(bestfacet->outsideset), point);
9187 #else
9188 if (bestfacet->furthestdist < bestdist) {
9189 qh_setappend(&(bestfacet->outsideset), point);
9190 bestfacet->furthestdist= bestdist;
9191 }else
9192 qh_setappend2ndlast(&(bestfacet->outsideset), point);
9193 #endif
9194 }
9195 qh num_outside++;
9196 trace4((qh ferr, "qh_partitionpoint: point p%d is outside facet f%d\n",
9197 qh_pointid(point), bestfacet->id));
9198 }else if (bestdist < qh min_vertex) {
9199 zinc_(Zpartinside);
9200 trace4((qh ferr, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n",
9201 qh_pointid(point), bestfacet->id, bestdist));
9202 if (qh KEEPinside)
9203 qh_partitioncoplanar (point, bestfacet, &bestdist);
9204 }else {
9205 zzinc_(Zcoplanarpart);
9206 if (qh KEEPcoplanar || bestdist > qh max_outside
9207 || (!qh BESToutside && qh newfacet_id && !qh MERGING))
9208 qh_partitioncoplanar (point, bestfacet, &bestdist);
9209 }
9210 } /* partitionpoint */
9211
9212 /*-------------------------------------------------
9213 -partitionvisible- partitions points in visible_list to newfacet_list
9214 1st neighbor (if any) points to a horizon facet or a new facet
9215 repartitions coplanar points if allpoints
9216 */
9217 void qh_partitionvisible(/*visible_list*/ boolT allpoints, int *numoutside) {
9218 facetT *visible, *newfacet;
9219 pointT *point, **pointp;
9220 int coplanar=0, size;
9221 vertexT *vertex, **vertexp;
9222
9223 if (qh ONLYmax)
9224 maximize_(qh MINoutside, qh max_vertex);
9225 *numoutside= 0;
9226 FORALLvisible_facets {
9227 if (!visible->outsideset && !visible->coplanarset)
9228 continue;
9229 newfacet= (facetT *)SETfirst_(visible->neighbors);
9230 while (newfacet && newfacet->visible)
9231 newfacet= (facetT *)SETfirst_(newfacet->neighbors);
9232 if (!newfacet)
9233 newfacet= qh newfacet_list;
9234 if (visible->outsideset) {
9235 size= qh_setsize (visible->outsideset);
9236 *numoutside += size;
9237 qh num_outside -= size;
9238 FOREACHpoint_(visible->outsideset)
9239 qh_partitionpoint (point, newfacet);
9240 }
9241 if (visible->coplanarset && (qh KEEPcoplanar || qh KEEPinside)) {
9242 size= qh_setsize (visible->coplanarset);
9243 coplanar += size;
9244 qh num_coplanar -= size;
9245 FOREACHpoint_(visible->coplanarset) {
9246 if (allpoints)
9247 qh_partitionpoint (point, newfacet);
9248 else
9249 qh_partitioncoplanar (point, newfacet, NULL);
9250 }
9251 }
9252 }
9253 FOREACHvertex_(qh del_vertices) {
9254 if (vertex->point) {
9255 if (qh DELAUNAY && !allpoints && !(qh APPROXhull | qh MERGING))
9256 fprintf (qh ferr, "qhull precision warning: point p%d (v%d) deleted due to roundoff errors\n",
9257 qh_pointid(vertex->point), vertex->id);
9258 if (allpoints)
9259 qh_partitionpoint (vertex->point, qh newfacet_list);
9260 else
9261 qh_partitioncoplanar (vertex->point, qh newfacet_list, NULL);
9262 }
9263 }
9264 trace1((qh ferr,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar));
9265 } /* partitionvisible */
9266
9267
9268