1 
2 /*<html><pre>  -<a                             href="qh-globa.htm"
3   >-------------------------------</a><a name="TOP">-</a>
4 
5    global.c
6    initializes all the globals of the qhull application
7 
8    see README
9 
10    see libqhull.h for qh.globals and function prototypes
11 
12    see qhull_a.h for internal functions
13 
14    Copyright (c) 1993-2015 The Geometry Center.
15    $Id: //main/2015/qhull/src/libqhull/global.c#17 $$Change: 2066 $
16    $DateTime: 2016/01/18 19:29:17 $$Author: bbarber $
17  */
18 
19 #include "qhull_a.h"
20 
21 /*========= qh definition -- globals defined in libqhull.h =======================*/
22 
23 #if qh_QHpointer
24 qhT *qh_qh= NULL;       /* pointer to all global variables */
25 #else
26 qhT qh_qh;              /* all global variables.
27                            Add "= {0}" if this causes a compiler error.
28                            Also qh_qhstat in stat.c and qhmem in mem.c.  */
29 #endif
30 
31 /*-<a                             href  ="qh-globa.htm#TOC"
32   >--------------------------------</a><a name="qh_version">-</a>
33 
34   qh_version
35     version string by year and date
36     qh_version2 for Unix users and -V
37 
38     the revision increases on code changes only
39 
40   notes:
41     change date:    Changes.txt, Announce.txt, index.htm, README.txt,
42                     qhull-news.html, Eudora signatures, CMakeLists.txt
43     change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt, CMakeLists.txt
44     check that CmakeLists @version is the same as qh_version2
45     change year:    Copying.txt
46     check download size
47     recompile user_eg.c, rbox.c, libqhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c, testqset.c
48 */
49 
50 const char qh_version[]= "2015.2 2016/01/18";
51 const char qh_version2[]= "qhull 7.2.0 (2015.2 2016/01/18)";
52 
53 /*-<a                             href="qh-globa.htm#TOC"
54   >-------------------------------</a><a name="appendprint">-</a>
55 
56   qh_appendprint( printFormat )
57     append printFormat to qh.PRINTout unless already defined
58 */
qh_appendprint(qh_PRINT format)59 void qh_appendprint(qh_PRINT format) {
60   int i;
61 
62   for (i=0; i < qh_PRINTEND; i++) {
63     if (qh PRINTout[i] == format && format != qh_PRINTqhull)
64       break;
65     if (!qh PRINTout[i]) {
66       qh PRINTout[i]= format;
67       break;
68     }
69   }
70 } /* appendprint */
71 
72 /*-<a                             href="qh-globa.htm#TOC"
73   >-------------------------------</a><a name="checkflags">-</a>
74 
75   qh_checkflags( commandStr, hiddenFlags )
76     errors if commandStr contains hiddenFlags
77     hiddenFlags starts and ends with a space and is space delimited (checked)
78 
79   notes:
80     ignores first word (e.g., "qconvex i")
81     use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
82 
83   see:
84     qh_initflags() initializes Qhull according to commandStr
85 */
qh_checkflags(char * command,char * hiddenflags)86 void qh_checkflags(char *command, char *hiddenflags) {
87   char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */
88   char key, opt, prevopt;
89   char chkkey[]= "   ";
90   char chkopt[]=  "    ";
91   char chkopt2[]= "     ";
92   boolT waserr= False;
93 
94   if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') {
95     qh_fprintf(qh ferr, 6026, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags);
96     qh_errexit(qh_ERRinput, NULL, NULL);
97   }
98   if (strpbrk(hiddenflags, ",\n\r\t")) {
99     qh_fprintf(qh ferr, 6027, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags);
100     qh_errexit(qh_ERRinput, NULL, NULL);
101   }
102   while (*s && !isspace(*s))  /* skip program name */
103     s++;
104   while (*s) {
105     while (*s && isspace(*s))
106       s++;
107     if (*s == '-')
108       s++;
109     if (!*s)
110       break;
111     key = *s++;
112     chkerr = NULL;
113     if (key == 'T' && (*s == 'I' || *s == 'O')) {  /* TI or TO 'file name' */
114       s= qh_skipfilename(++s);
115       continue;
116     }
117     chkkey[1]= key;
118     if (strstr(hiddenflags, chkkey)) {
119       chkerr= chkkey;
120     }else if (isupper(key)) {
121       opt= ' ';
122       prevopt= ' ';
123       chkopt[1]= key;
124       chkopt2[1]= key;
125       while (!chkerr && *s && !isspace(*s)) {
126         opt= *s++;
127         if (isalpha(opt)) {
128           chkopt[2]= opt;
129           if (strstr(hiddenflags, chkopt))
130             chkerr= chkopt;
131           if (prevopt != ' ') {
132             chkopt2[2]= prevopt;
133             chkopt2[3]= opt;
134             if (strstr(hiddenflags, chkopt2))
135               chkerr= chkopt2;
136           }
137         }else if (key == 'Q' && isdigit(opt) && prevopt != 'b'
138               && (prevopt == ' ' || islower(prevopt))) {
139             chkopt[2]= opt;
140             if (strstr(hiddenflags, chkopt))
141               chkerr= chkopt;
142         }else {
143           qh_strtod(s-1, &t);
144           if (s < t)
145             s= t;
146         }
147         prevopt= opt;
148       }
149     }
150     if (chkerr) {
151       *chkerr= '\'';
152       chkerr[strlen(chkerr)-1]=  '\'';
153       qh_fprintf(qh ferr, 6029, "qhull error: option %s is not used with this program.\n             It may be used with qhull.\n", chkerr);
154       waserr= True;
155     }
156   }
157   if (waserr)
158     qh_errexit(qh_ERRinput, NULL, NULL);
159 } /* checkflags */
160 
161 /*-<a                             href="qh-globa.htm#TOC"
162   >-------------------------------</a><a name="qh_clear_outputflags">-</a>
163 
164   qh_clear_outputflags()
165     Clear output flags for QhullPoints
166 */
qh_clear_outputflags(void)167 void qh_clear_outputflags(void) {
168   int i,k;
169 
170   qh ANNOTATEoutput= False;
171   qh DOintersections= False;
172   qh DROPdim= -1;
173   qh FORCEoutput= False;
174   qh GETarea= False;
175   qh GOODpoint= 0;
176   qh GOODpointp= NULL;
177   qh GOODthreshold= False;
178   qh GOODvertex= 0;
179   qh GOODvertexp= NULL;
180   qh IStracing= 0;
181   qh KEEParea= False;
182   qh KEEPmerge= False;
183   qh KEEPminArea= REALmax;
184   qh PRINTcentrums= False;
185   qh PRINTcoplanar= False;
186   qh PRINTdots= False;
187   qh PRINTgood= False;
188   qh PRINTinner= False;
189   qh PRINTneighbors= False;
190   qh PRINTnoplanes= False;
191   qh PRINToptions1st= False;
192   qh PRINTouter= False;
193   qh PRINTprecision= True;
194   qh PRINTridges= False;
195   qh PRINTspheres= False;
196   qh PRINTstatistics= False;
197   qh PRINTsummary= False;
198   qh PRINTtransparent= False;
199   qh SPLITthresholds= False;
200   qh TRACElevel= 0;
201   qh TRInormals= False;
202   qh USEstdout= False;
203   qh VERIFYoutput= False;
204   for (k=qh input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
205     qh lower_threshold[k]= -REALmax;
206     qh upper_threshold[k]= REALmax;
207     qh lower_bound[k]= -REALmax;
208     qh upper_bound[k]= REALmax;
209   }
210 
211   for (i=0; i < qh_PRINTEND; i++) {
212     qh PRINTout[i]= qh_PRINTnone;
213   }
214 
215   if (!qh qhull_commandsiz2)
216       qh qhull_commandsiz2= (int)strlen(qh qhull_command); /* WARN64 */
217   else {
218       qh qhull_command[qh qhull_commandsiz2]= '\0';
219   }
220   if (!qh qhull_optionsiz2)
221     qh qhull_optionsiz2= (int)strlen(qh qhull_options);  /* WARN64 */
222   else {
223     qh qhull_options[qh qhull_optionsiz2]= '\0';
224     qh qhull_optionlen= qh_OPTIONline;  /* start a new line */
225   }
226 } /* clear_outputflags */
227 
228 /*-<a                             href="qh-globa.htm#TOC"
229   >-------------------------------</a><a name="clock">-</a>
230 
231   qh_clock()
232     return user CPU time in 100ths (qh_SECtick)
233     only defined for qh_CLOCKtype == 2
234 
235   notes:
236     use first value to determine time 0
237     from Stevens '92 8.15
238 */
qh_clock(void)239 unsigned long qh_clock(void) {
240 
241 #if (qh_CLOCKtype == 2)
242   struct tms time;
243   static long clktck;  /* initialized first call and never updated */
244   double ratio, cpu;
245   unsigned long ticks;
246 
247   if (!clktck) {
248     if ((clktck= sysconf(_SC_CLK_TCK)) < 0) {
249       qh_fprintf(qh ferr, 6030, "qhull internal error (qh_clock): sysconf() failed.  Use qh_CLOCKtype 1 in user.h\n");
250       qh_errexit(qh_ERRqhull, NULL, NULL);
251     }
252   }
253   if (times(&time) == -1) {
254     qh_fprintf(qh ferr, 6031, "qhull internal error (qh_clock): times() failed.  Use qh_CLOCKtype 1 in user.h\n");
255     qh_errexit(qh_ERRqhull, NULL, NULL);
256   }
257   ratio= qh_SECticks / (double)clktck;
258   ticks= time.tms_utime * ratio;
259   return ticks;
260 #else
261   qh_fprintf(qh ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n");
262   qh_errexit(qh_ERRqhull, NULL, NULL); /* never returns */
263   return 0;
264 #endif
265 } /* clock */
266 
267 /*-<a                             href="qh-globa.htm#TOC"
268   >-------------------------------</a><a name="freebuffers">-</a>
269 
270   qh_freebuffers()
271     free up global memory buffers
272 
273   notes:
274     must match qh_initbuffers()
275 */
qh_freebuffers(void)276 void qh_freebuffers(void) {
277 
278   trace5((qh ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n"));
279   /* allocated by qh_initqhull_buffers */
280   qh_memfree(qh NEARzero, qh hull_dim * sizeof(realT));
281   qh_memfree(qh lower_threshold, (qh input_dim+1) * sizeof(realT));
282   qh_memfree(qh upper_threshold, (qh input_dim+1) * sizeof(realT));
283   qh_memfree(qh lower_bound, (qh input_dim+1) * sizeof(realT));
284   qh_memfree(qh upper_bound, (qh input_dim+1) * sizeof(realT));
285   qh_memfree(qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT));
286   qh_memfree(qh gm_row, (qh hull_dim+1) * sizeof(coordT *));
287   qh NEARzero= qh lower_threshold= qh upper_threshold= NULL;
288   qh lower_bound= qh upper_bound= NULL;
289   qh gm_matrix= NULL;
290   qh gm_row= NULL;
291   qh_setfree(&qh other_points);
292   qh_setfree(&qh del_vertices);
293   qh_setfree(&qh coplanarfacetset);
294   if (qh line)                /* allocated by qh_readinput, freed if no error */
295     qh_free(qh line);
296   if (qh half_space)
297     qh_free(qh half_space);
298   if (qh temp_malloc)
299     qh_free(qh temp_malloc);
300   if (qh feasible_point)      /* allocated by qh_readfeasible */
301     qh_free(qh feasible_point);
302   if (qh feasible_string)     /* allocated by qh_initflags */
303     qh_free(qh feasible_string);
304   qh line= qh feasible_string= NULL;
305   qh half_space= qh feasible_point= qh temp_malloc= NULL;
306   /* usually allocated by qh_readinput */
307   if (qh first_point && qh POINTSmalloc) {
308     qh_free(qh first_point);
309     qh first_point= NULL;
310   }
311   if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */
312     qh_free(qh input_points);
313     qh input_points= NULL;
314   }
315   trace5((qh ferr, 5002, "qh_freebuffers: finished\n"));
316 } /* freebuffers */
317 
318 
319 /*-<a                             href="qh-globa.htm#TOC"
320   >-------------------------------</a><a name="freebuild">-</a>
321 
322   qh_freebuild( allmem )
323     free global memory used by qh_initbuild and qh_buildhull
324     if !allmem,
325       does not free short memory (e.g., facetT, freed by qh_memfreeshort)
326 
327   design:
328     free centrums
329     free each vertex
330     mark unattached ridges
331     for each facet
332       free ridges
333       free outside set, coplanar set, neighbor set, ridge set, vertex set
334       free facet
335     free hash table
336     free interior point
337     free merge set
338     free temporary sets
339 */
qh_freebuild(boolT allmem)340 void qh_freebuild(boolT allmem) {
341   facetT *facet;
342   vertexT *vertex;
343   ridgeT *ridge, **ridgep;
344   mergeT *merge, **mergep;
345 
346   trace1((qh ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n"));
347   if (qh del_vertices)
348     qh_settruncate(qh del_vertices, 0);
349   if (allmem) {
350     while ((vertex= qh vertex_list)) {
351       if (vertex->next)
352         qh_delvertex(vertex);
353       else {
354         qh_memfree(vertex, (int)sizeof(vertexT));
355         qh newvertex_list= qh vertex_list= NULL;
356       }
357     }
358   }else if (qh VERTEXneighbors) {
359     FORALLvertices
360       qh_setfreelong(&(vertex->neighbors));
361   }
362   qh VERTEXneighbors= False;
363   qh GOODclosest= NULL;
364   if (allmem) {
365     FORALLfacets {
366       FOREACHridge_(facet->ridges)
367         ridge->seen= False;
368     }
369     FORALLfacets {
370       if (facet->visible) {
371         FOREACHridge_(facet->ridges) {
372           if (!otherfacet_(ridge, facet)->visible)
373             ridge->seen= True;  /* an unattached ridge */
374         }
375       }
376     }
377     while ((facet= qh facet_list)) {
378       FOREACHridge_(facet->ridges) {
379         if (ridge->seen) {
380           qh_setfree(&(ridge->vertices));
381           qh_memfree(ridge, (int)sizeof(ridgeT));
382         }else
383           ridge->seen= True;
384       }
385       qh_setfree(&(facet->outsideset));
386       qh_setfree(&(facet->coplanarset));
387       qh_setfree(&(facet->neighbors));
388       qh_setfree(&(facet->ridges));
389       qh_setfree(&(facet->vertices));
390       if (facet->next)
391         qh_delfacet(facet);
392       else {
393         qh_memfree(facet, (int)sizeof(facetT));
394         qh visible_list= qh newfacet_list= qh facet_list= NULL;
395       }
396     }
397   }else {
398     FORALLfacets {
399       qh_setfreelong(&(facet->outsideset));
400       qh_setfreelong(&(facet->coplanarset));
401       if (!facet->simplicial) {
402         qh_setfreelong(&(facet->neighbors));
403         qh_setfreelong(&(facet->ridges));
404         qh_setfreelong(&(facet->vertices));
405       }
406     }
407   }
408   qh_setfree(&(qh hash_table));
409   qh_memfree(qh interior_point, qh normal_size);
410   qh interior_point= NULL;
411   FOREACHmerge_(qh facet_mergeset)  /* usually empty */
412     qh_memfree(merge, (int)sizeof(mergeT));
413   qh facet_mergeset= NULL;  /* temp set */
414   qh degen_mergeset= NULL;  /* temp set */
415   qh_settempfree_all();
416 } /* freebuild */
417 
418 /*-<a                             href="qh-globa.htm#TOC"
419   >-------------------------------</a><a name="freeqhull">-</a>
420 
421   qh_freeqhull( allmem )
422     see qh_freeqhull2
423     if qh_QHpointer, frees qh_qh
424 */
qh_freeqhull(boolT allmem)425 void qh_freeqhull(boolT allmem) {
426     qh_freeqhull2(allmem);
427 #if qh_QHpointer
428     qh_free(qh_qh);
429     qh_qh= NULL;
430 #endif
431 }
432 
433 /*-<a                             href="qh-globa.htm#TOC"
434 >-------------------------------</a><a name="freeqhull2">-</a>
435 
436 qh_freeqhull2( allmem )
437   free global memory and set qhT to 0
438   if !allmem,
439     does not free short memory (freed by qh_memfreeshort unless qh_NOmem)
440 
441 notes:
442   sets qh.NOerrexit in case caller forgets to
443   Does not throw errors
444 
445 see:
446   see qh_initqhull_start2()
447 
448 design:
449   free global and temporary memory from qh_initbuild and qh_buildhull
450   free buffers
451   free statistics
452 */
qh_freeqhull2(boolT allmem)453 void qh_freeqhull2(boolT allmem) {
454 
455   qh NOerrexit= True;  /* no more setjmp since called at exit and ~QhullQh */
456   trace1((qh ferr, 1006, "qh_freeqhull: free global memory\n"));
457   qh_freebuild(allmem);
458   qh_freebuffers();
459   qh_freestatistics();
460 #if qh_QHpointer
461   memset((char *)qh_qh, 0, sizeof(qhT));
462   /* qh_qh freed by caller, qh_freeqhull() */
463 #else
464   memset((char *)&qh_qh, 0, sizeof(qhT));
465 #endif
466   qh NOerrexit= True;
467 } /* freeqhull2 */
468 
469 /*-<a                             href="qh-globa.htm#TOC"
470   >-------------------------------</a><a name="init_A">-</a>
471 
472   qh_init_A( infile, outfile, errfile, argc, argv )
473     initialize memory and stdio files
474     convert input options to option string (qh.qhull_command)
475 
476   notes:
477     infile may be NULL if qh_readpoints() is not called
478 
479     errfile should always be defined.  It is used for reporting
480     errors.  outfile is used for output and format options.
481 
482     argc/argv may be 0/NULL
483 
484     called before error handling initialized
485     qh_errexit() may not be used
486 */
qh_init_A(FILE * infile,FILE * outfile,FILE * errfile,int argc,char * argv[])487 void qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) {
488   qh_meminit(errfile);
489   qh_initqhull_start(infile, outfile, errfile);
490   qh_init_qhull_command(argc, argv);
491 } /* init_A */
492 
493 /*-<a                             href="qh-globa.htm#TOC"
494   >-------------------------------</a><a name="init_B">-</a>
495 
496   qh_init_B( points, numpoints, dim, ismalloc )
497     initialize globals for points array
498 
499     points has numpoints dim-dimensional points
500       points[0] is the first coordinate of the first point
501       points[1] is the second coordinate of the first point
502       points[dim] is the first coordinate of the second point
503 
504     ismalloc=True
505       Qhull will call qh_free(points) on exit or input transformation
506     ismalloc=False
507       Qhull will allocate a new point array if needed for input transformation
508 
509     qh.qhull_command
510       is the option string.
511       It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags
512 
513   returns:
514     if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay)
515       projects the input to a new point array
516 
517         if qh.DELAUNAY,
518           qh.hull_dim is increased by one
519         if qh.ATinfinity,
520           qh_projectinput adds point-at-infinity for Delaunay tri.
521 
522     if qh.SCALEinput
523       changes the upper and lower bounds of the input, see qh_scaleinput()
524 
525     if qh.ROTATEinput
526       rotates the input by a random rotation, see qh_rotateinput()
527       if qh.DELAUNAY
528         rotates about the last coordinate
529 
530   notes:
531     called after points are defined
532     qh_errexit() may be used
533 */
qh_init_B(coordT * points,int numpoints,int dim,boolT ismalloc)534 void qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc) {
535   qh_initqhull_globals(points, numpoints, dim, ismalloc);
536   if (qhmem.LASTsize == 0)
537     qh_initqhull_mem();
538   /* mem.c and qset.c are initialized */
539   qh_initqhull_buffers();
540   qh_initthresholds(qh qhull_command);
541   if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay))
542     qh_projectinput();
543   if (qh SCALEinput)
544     qh_scaleinput();
545   if (qh ROTATErandom >= 0) {
546     qh_randommatrix(qh gm_matrix, qh hull_dim, qh gm_row);
547     if (qh DELAUNAY) {
548       int k, lastk= qh hull_dim-1;
549       for (k=0; k < lastk; k++) {
550         qh gm_row[k][lastk]= 0.0;
551         qh gm_row[lastk][k]= 0.0;
552       }
553       qh gm_row[lastk][lastk]= 1.0;
554     }
555     qh_gram_schmidt(qh hull_dim, qh gm_row);
556     qh_rotateinput(qh gm_row);
557   }
558 } /* init_B */
559 
560 /*-<a                             href="qh-globa.htm#TOC"
561   >-------------------------------</a><a name="init_qhull_command">-</a>
562 
563   qh_init_qhull_command( argc, argv )
564     build qh.qhull_command from argc/argv
565     Calls qh_exit if qhull_command is too short
566 
567   returns:
568     a space-delimited string of options (just as typed)
569 
570   notes:
571     makes option string easy to input and output
572 
573     argc/argv may be 0/NULL
574 */
qh_init_qhull_command(int argc,char * argv[])575 void qh_init_qhull_command(int argc, char *argv[]) {
576 
577   if (!qh_argv_to_command(argc, argv, qh qhull_command, (int)sizeof(qh qhull_command))){
578     /* Assumes qh.ferr is defined. */
579     qh_fprintf(qh ferr, 6033, "qhull input error: more than %d characters in command line\n",
580           (int)sizeof(qh qhull_command));
581     qh_exit(qh_ERRinput);  /* error reported, can not use qh_errexit */
582   }
583 } /* init_qhull_command */
584 
585 /*-<a                             href="qh-globa.htm#TOC"
586   >-------------------------------</a><a name="initflags">-</a>
587 
588   qh_initflags( commandStr )
589     set flags and initialized constants from commandStr
590     calls qh_exit() if qh->NOerrexit
591 
592   returns:
593     sets qh.qhull_command to command if needed
594 
595   notes:
596     ignores first word (e.g., "qhull d")
597     use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces
598 
599   see:
600     qh_initthresholds() continues processing of 'Pdn' and 'PDn'
601     'prompt' in unix.c for documentation
602 
603   design:
604     for each space-delimited option group
605       if top-level option
606         check syntax
607         append appropriate option to option string
608         set appropriate global variable or append printFormat to print options
609       else
610         for each sub-option
611           check syntax
612           append appropriate option to option string
613           set appropriate global variable or append printFormat to print options
614 */
qh_initflags(char * command)615 void qh_initflags(char *command) {
616   int k, i, lastproject;
617   char *s= command, *t, *prev_s, *start, key;
618   boolT isgeom= False, wasproject;
619   realT r;
620 
621   if(qh NOerrexit){/* without this comment, segfault in gcc 4.4.0 mingw32 */
622     qh_fprintf(qh ferr, 6245, "qhull initflags error: qh.NOerrexit was not cleared before calling qh_initflags().  It should be cleared after setjmp().  Exit qhull.");
623     qh_exit(6245);
624   }
625   if (command <= &qh qhull_command[0] || command > &qh qhull_command[0] + sizeof(qh qhull_command)) {
626     if (command != &qh qhull_command[0]) {
627       *qh qhull_command= '\0';
628       strncat(qh qhull_command, command, sizeof(qh qhull_command)-strlen(qh qhull_command)-1);
629     }
630     while (*s && !isspace(*s))  /* skip program name */
631       s++;
632   }
633   while (*s) {
634     while (*s && isspace(*s))
635       s++;
636     if (*s == '-')
637       s++;
638     if (!*s)
639       break;
640     prev_s= s;
641     switch (*s++) {
642     case 'd':
643       qh_option("delaunay", NULL, NULL);
644       qh DELAUNAY= True;
645       break;
646     case 'f':
647       qh_option("facets", NULL, NULL);
648       qh_appendprint(qh_PRINTfacets);
649       break;
650     case 'i':
651       qh_option("incidence", NULL, NULL);
652       qh_appendprint(qh_PRINTincidences);
653       break;
654     case 'm':
655       qh_option("mathematica", NULL, NULL);
656       qh_appendprint(qh_PRINTmathematica);
657       break;
658     case 'n':
659       qh_option("normals", NULL, NULL);
660       qh_appendprint(qh_PRINTnormals);
661       break;
662     case 'o':
663       qh_option("offFile", NULL, NULL);
664       qh_appendprint(qh_PRINToff);
665       break;
666     case 'p':
667       qh_option("points", NULL, NULL);
668       qh_appendprint(qh_PRINTpoints);
669       break;
670     case 's':
671       qh_option("summary", NULL, NULL);
672       qh PRINTsummary= True;
673       break;
674     case 'v':
675       qh_option("voronoi", NULL, NULL);
676       qh VORONOI= True;
677       qh DELAUNAY= True;
678       break;
679     case 'A':
680       if (!isdigit(*s) && *s != '.' && *s != '-')
681         qh_fprintf(qh ferr, 7002, "qhull warning: no maximum cosine angle given for option 'An'.  Ignored.\n");
682       else {
683         if (*s == '-') {
684           qh premerge_cos= -qh_strtod(s, &s);
685           qh_option("Angle-premerge-", NULL, &qh premerge_cos);
686           qh PREmerge= True;
687         }else {
688           qh postmerge_cos= qh_strtod(s, &s);
689           qh_option("Angle-postmerge", NULL, &qh postmerge_cos);
690           qh POSTmerge= True;
691         }
692         qh MERGING= True;
693       }
694       break;
695     case 'C':
696       if (!isdigit(*s) && *s != '.' && *s != '-')
697         qh_fprintf(qh ferr, 7003, "qhull warning: no centrum radius given for option 'Cn'.  Ignored.\n");
698       else {
699         if (*s == '-') {
700           qh premerge_centrum= -qh_strtod(s, &s);
701           qh_option("Centrum-premerge-", NULL, &qh premerge_centrum);
702           qh PREmerge= True;
703         }else {
704           qh postmerge_centrum= qh_strtod(s, &s);
705           qh_option("Centrum-postmerge", NULL, &qh postmerge_centrum);
706           qh POSTmerge= True;
707         }
708         qh MERGING= True;
709       }
710       break;
711     case 'E':
712       if (*s == '-')
713         qh_fprintf(qh ferr, 7004, "qhull warning: negative maximum roundoff given for option 'An'.  Ignored.\n");
714       else if (!isdigit(*s))
715         qh_fprintf(qh ferr, 7005, "qhull warning: no maximum roundoff given for option 'En'.  Ignored.\n");
716       else {
717         qh DISTround= qh_strtod(s, &s);
718         qh_option("Distance-roundoff", NULL, &qh DISTround);
719         qh SETroundoff= True;
720       }
721       break;
722     case 'H':
723       start= s;
724       qh HALFspace= True;
725       qh_strtod(s, &t);
726       while (t > s)  {
727         if (*t && !isspace(*t)) {
728           if (*t == ',')
729             t++;
730           else
731             qh_fprintf(qh ferr, 7006, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n");
732         }
733         s= t;
734         qh_strtod(s, &t);
735       }
736       if (start < t) {
737         if (!(qh feasible_string= (char*)calloc((size_t)(t-start+1), (size_t)1))) {
738           qh_fprintf(qh ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n");
739           qh_errexit(qh_ERRmem, NULL, NULL);
740         }
741         strncpy(qh feasible_string, start, (size_t)(t-start));
742         qh_option("Halfspace-about", NULL, NULL);
743         qh_option(qh feasible_string, NULL, NULL);
744       }else
745         qh_option("Halfspace", NULL, NULL);
746       break;
747     case 'R':
748       if (!isdigit(*s))
749         qh_fprintf(qh ferr, 7007, "qhull warning: missing random perturbation for option 'Rn'.  Ignored\n");
750       else {
751         qh RANDOMfactor= qh_strtod(s, &s);
752         qh_option("Random_perturb", NULL, &qh RANDOMfactor);
753         qh RANDOMdist= True;
754       }
755       break;
756     case 'V':
757       if (!isdigit(*s) && *s != '-')
758         qh_fprintf(qh ferr, 7008, "qhull warning: missing visible distance for option 'Vn'.  Ignored\n");
759       else {
760         qh MINvisible= qh_strtod(s, &s);
761         qh_option("Visible", NULL, &qh MINvisible);
762       }
763       break;
764     case 'U':
765       if (!isdigit(*s) && *s != '-')
766         qh_fprintf(qh ferr, 7009, "qhull warning: missing coplanar distance for option 'Un'.  Ignored\n");
767       else {
768         qh MAXcoplanar= qh_strtod(s, &s);
769         qh_option("U-coplanar", NULL, &qh MAXcoplanar);
770       }
771       break;
772     case 'W':
773       if (*s == '-')
774         qh_fprintf(qh ferr, 7010, "qhull warning: negative outside width for option 'Wn'.  Ignored.\n");
775       else if (!isdigit(*s))
776         qh_fprintf(qh ferr, 7011, "qhull warning: missing outside width for option 'Wn'.  Ignored\n");
777       else {
778         qh MINoutside= qh_strtod(s, &s);
779         qh_option("W-outside", NULL, &qh MINoutside);
780         qh APPROXhull= True;
781       }
782       break;
783     /************  sub menus ***************/
784     case 'F':
785       while (*s && !isspace(*s)) {
786         switch (*s++) {
787         case 'a':
788           qh_option("Farea", NULL, NULL);
789           qh_appendprint(qh_PRINTarea);
790           qh GETarea= True;
791           break;
792         case 'A':
793           qh_option("FArea-total", NULL, NULL);
794           qh GETarea= True;
795           break;
796         case 'c':
797           qh_option("Fcoplanars", NULL, NULL);
798           qh_appendprint(qh_PRINTcoplanars);
799           break;
800         case 'C':
801           qh_option("FCentrums", NULL, NULL);
802           qh_appendprint(qh_PRINTcentrums);
803           break;
804         case 'd':
805           qh_option("Fd-cdd-in", NULL, NULL);
806           qh CDDinput= True;
807           break;
808         case 'D':
809           qh_option("FD-cdd-out", NULL, NULL);
810           qh CDDoutput= True;
811           break;
812         case 'F':
813           qh_option("FFacets-xridge", NULL, NULL);
814           qh_appendprint(qh_PRINTfacets_xridge);
815           break;
816         case 'i':
817           qh_option("Finner", NULL, NULL);
818           qh_appendprint(qh_PRINTinner);
819           break;
820         case 'I':
821           qh_option("FIDs", NULL, NULL);
822           qh_appendprint(qh_PRINTids);
823           break;
824         case 'm':
825           qh_option("Fmerges", NULL, NULL);
826           qh_appendprint(qh_PRINTmerges);
827           break;
828         case 'M':
829           qh_option("FMaple", NULL, NULL);
830           qh_appendprint(qh_PRINTmaple);
831           break;
832         case 'n':
833           qh_option("Fneighbors", NULL, NULL);
834           qh_appendprint(qh_PRINTneighbors);
835           break;
836         case 'N':
837           qh_option("FNeighbors-vertex", NULL, NULL);
838           qh_appendprint(qh_PRINTvneighbors);
839           break;
840         case 'o':
841           qh_option("Fouter", NULL, NULL);
842           qh_appendprint(qh_PRINTouter);
843           break;
844         case 'O':
845           if (qh PRINToptions1st) {
846             qh_option("FOptions", NULL, NULL);
847             qh_appendprint(qh_PRINToptions);
848           }else
849             qh PRINToptions1st= True;
850           break;
851         case 'p':
852           qh_option("Fpoint-intersect", NULL, NULL);
853           qh_appendprint(qh_PRINTpointintersect);
854           break;
855         case 'P':
856           qh_option("FPoint-nearest", NULL, NULL);
857           qh_appendprint(qh_PRINTpointnearest);
858           break;
859         case 'Q':
860           qh_option("FQhull", NULL, NULL);
861           qh_appendprint(qh_PRINTqhull);
862           break;
863         case 's':
864           qh_option("Fsummary", NULL, NULL);
865           qh_appendprint(qh_PRINTsummary);
866           break;
867         case 'S':
868           qh_option("FSize", NULL, NULL);
869           qh_appendprint(qh_PRINTsize);
870           qh GETarea= True;
871           break;
872         case 't':
873           qh_option("Ftriangles", NULL, NULL);
874           qh_appendprint(qh_PRINTtriangles);
875           break;
876         case 'v':
877           /* option set in qh_initqhull_globals */
878           qh_appendprint(qh_PRINTvertices);
879           break;
880         case 'V':
881           qh_option("FVertex-average", NULL, NULL);
882           qh_appendprint(qh_PRINTaverage);
883           break;
884         case 'x':
885           qh_option("Fxtremes", NULL, NULL);
886           qh_appendprint(qh_PRINTextremes);
887           break;
888         default:
889           s--;
890           qh_fprintf(qh ferr, 7012, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]);
891           while (*++s && !isspace(*s));
892           break;
893         }
894       }
895       break;
896     case 'G':
897       isgeom= True;
898       qh_appendprint(qh_PRINTgeom);
899       while (*s && !isspace(*s)) {
900         switch (*s++) {
901         case 'a':
902           qh_option("Gall-points", NULL, NULL);
903           qh PRINTdots= True;
904           break;
905         case 'c':
906           qh_option("Gcentrums", NULL, NULL);
907           qh PRINTcentrums= True;
908           break;
909         case 'h':
910           qh_option("Gintersections", NULL, NULL);
911           qh DOintersections= True;
912           break;
913         case 'i':
914           qh_option("Ginner", NULL, NULL);
915           qh PRINTinner= True;
916           break;
917         case 'n':
918           qh_option("Gno-planes", NULL, NULL);
919           qh PRINTnoplanes= True;
920           break;
921         case 'o':
922           qh_option("Gouter", NULL, NULL);
923           qh PRINTouter= True;
924           break;
925         case 'p':
926           qh_option("Gpoints", NULL, NULL);
927           qh PRINTcoplanar= True;
928           break;
929         case 'r':
930           qh_option("Gridges", NULL, NULL);
931           qh PRINTridges= True;
932           break;
933         case 't':
934           qh_option("Gtransparent", NULL, NULL);
935           qh PRINTtransparent= True;
936           break;
937         case 'v':
938           qh_option("Gvertices", NULL, NULL);
939           qh PRINTspheres= True;
940           break;
941         case 'D':
942           if (!isdigit(*s))
943             qh_fprintf(qh ferr, 6035, "qhull input error: missing dimension for option 'GDn'\n");
944           else {
945             if (qh DROPdim >= 0)
946               qh_fprintf(qh ferr, 7013, "qhull warning: can only drop one dimension.  Previous 'GD%d' ignored\n",
947                    qh DROPdim);
948             qh DROPdim= qh_strtol(s, &s);
949             qh_option("GDrop-dim", &qh DROPdim, NULL);
950           }
951           break;
952         default:
953           s--;
954           qh_fprintf(qh ferr, 7014, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]);
955           while (*++s && !isspace(*s));
956           break;
957         }
958       }
959       break;
960     case 'P':
961       while (*s && !isspace(*s)) {
962         switch (*s++) {
963         case 'd': case 'D':  /* see qh_initthresholds() */
964           key= s[-1];
965           i= qh_strtol(s, &s);
966           r= 0;
967           if (*s == ':') {
968             s++;
969             r= qh_strtod(s, &s);
970           }
971           if (key == 'd')
972             qh_option("Pdrop-facets-dim-less", &i, &r);
973           else
974             qh_option("PDrop-facets-dim-more", &i, &r);
975           break;
976         case 'g':
977           qh_option("Pgood-facets", NULL, NULL);
978           qh PRINTgood= True;
979           break;
980         case 'G':
981           qh_option("PGood-facet-neighbors", NULL, NULL);
982           qh PRINTneighbors= True;
983           break;
984         case 'o':
985           qh_option("Poutput-forced", NULL, NULL);
986           qh FORCEoutput= True;
987           break;
988         case 'p':
989           qh_option("Pprecision-ignore", NULL, NULL);
990           qh PRINTprecision= False;
991           break;
992         case 'A':
993           if (!isdigit(*s))
994             qh_fprintf(qh ferr, 6036, "qhull input error: missing facet count for keep area option 'PAn'\n");
995           else {
996             qh KEEParea= qh_strtol(s, &s);
997             qh_option("PArea-keep", &qh KEEParea, NULL);
998             qh GETarea= True;
999           }
1000           break;
1001         case 'F':
1002           if (!isdigit(*s))
1003             qh_fprintf(qh ferr, 6037, "qhull input error: missing facet area for option 'PFn'\n");
1004           else {
1005             qh KEEPminArea= qh_strtod(s, &s);
1006             qh_option("PFacet-area-keep", NULL, &qh KEEPminArea);
1007             qh GETarea= True;
1008           }
1009           break;
1010         case 'M':
1011           if (!isdigit(*s))
1012             qh_fprintf(qh ferr, 6038, "qhull input error: missing merge count for option 'PMn'\n");
1013           else {
1014             qh KEEPmerge= qh_strtol(s, &s);
1015             qh_option("PMerge-keep", &qh KEEPmerge, NULL);
1016           }
1017           break;
1018         default:
1019           s--;
1020           qh_fprintf(qh ferr, 7015, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]);
1021           while (*++s && !isspace(*s));
1022           break;
1023         }
1024       }
1025       break;
1026     case 'Q':
1027       lastproject= -1;
1028       while (*s && !isspace(*s)) {
1029         switch (*s++) {
1030         case 'b': case 'B':  /* handled by qh_initthresholds */
1031           key= s[-1];
1032           if (key == 'b' && *s == 'B') {
1033             s++;
1034             r= qh_DEFAULTbox;
1035             qh SCALEinput= True;
1036             qh_option("QbBound-unit-box", NULL, &r);
1037             break;
1038           }
1039           if (key == 'b' && *s == 'b') {
1040             s++;
1041             qh SCALElast= True;
1042             qh_option("Qbbound-last", NULL, NULL);
1043             break;
1044           }
1045           k= qh_strtol(s, &s);
1046           r= 0.0;
1047           wasproject= False;
1048           if (*s == ':') {
1049             s++;
1050             if ((r= qh_strtod(s, &s)) == 0.0) {
1051               t= s;            /* need true dimension for memory allocation */
1052               while (*t && !isspace(*t)) {
1053                 if (toupper(*t++) == 'B'
1054                  && k == qh_strtol(t, &t)
1055                  && *t++ == ':'
1056                  && qh_strtod(t, &t) == 0.0) {
1057                   qh PROJECTinput++;
1058                   trace2((qh ferr, 2004, "qh_initflags: project dimension %d\n", k));
1059                   qh_option("Qb-project-dim", &k, NULL);
1060                   wasproject= True;
1061                   lastproject= k;
1062                   break;
1063                 }
1064               }
1065             }
1066           }
1067           if (!wasproject) {
1068             if (lastproject == k && r == 0.0)
1069               lastproject= -1;  /* doesn't catch all possible sequences */
1070             else if (key == 'b') {
1071               qh SCALEinput= True;
1072               if (r == 0.0)
1073                 r= -qh_DEFAULTbox;
1074               qh_option("Qbound-dim-low", &k, &r);
1075             }else {
1076               qh SCALEinput= True;
1077               if (r == 0.0)
1078                 r= qh_DEFAULTbox;
1079               qh_option("QBound-dim-high", &k, &r);
1080             }
1081           }
1082           break;
1083         case 'c':
1084           qh_option("Qcoplanar-keep", NULL, NULL);
1085           qh KEEPcoplanar= True;
1086           break;
1087         case 'f':
1088           qh_option("Qfurthest-outside", NULL, NULL);
1089           qh BESToutside= True;
1090           break;
1091         case 'g':
1092           qh_option("Qgood-facets-only", NULL, NULL);
1093           qh ONLYgood= True;
1094           break;
1095         case 'i':
1096           qh_option("Qinterior-keep", NULL, NULL);
1097           qh KEEPinside= True;
1098           break;
1099         case 'm':
1100           qh_option("Qmax-outside-only", NULL, NULL);
1101           qh ONLYmax= True;
1102           break;
1103         case 'r':
1104           qh_option("Qrandom-outside", NULL, NULL);
1105           qh RANDOMoutside= True;
1106           break;
1107         case 's':
1108           qh_option("Qsearch-initial-simplex", NULL, NULL);
1109           qh ALLpoints= True;
1110           break;
1111         case 't':
1112           qh_option("Qtriangulate", NULL, NULL);
1113           qh TRIangulate= True;
1114           break;
1115         case 'T':
1116           qh_option("QTestPoints", NULL, NULL);
1117           if (!isdigit(*s))
1118             qh_fprintf(qh ferr, 6039, "qhull input error: missing number of test points for option 'QTn'\n");
1119           else {
1120             qh TESTpoints= qh_strtol(s, &s);
1121             qh_option("QTestPoints", &qh TESTpoints, NULL);
1122           }
1123           break;
1124         case 'u':
1125           qh_option("QupperDelaunay", NULL, NULL);
1126           qh UPPERdelaunay= True;
1127           break;
1128         case 'v':
1129           qh_option("Qvertex-neighbors-convex", NULL, NULL);
1130           qh TESTvneighbors= True;
1131           break;
1132         case 'x':
1133           qh_option("Qxact-merge", NULL, NULL);
1134           qh MERGEexact= True;
1135           break;
1136         case 'z':
1137           qh_option("Qz-infinity-point", NULL, NULL);
1138           qh ATinfinity= True;
1139           break;
1140         case '0':
1141           qh_option("Q0-no-premerge", NULL, NULL);
1142           qh NOpremerge= True;
1143           break;
1144         case '1':
1145           if (!isdigit(*s)) {
1146             qh_option("Q1-no-angle-sort", NULL, NULL);
1147             qh ANGLEmerge= False;
1148             break;
1149           }
1150           switch (*s++) {
1151           case '0':
1152             qh_option("Q10-no-narrow", NULL, NULL);
1153             qh NOnarrow= True;
1154             break;
1155           case '1':
1156             qh_option("Q11-trinormals Qtriangulate", NULL, NULL);
1157             qh TRInormals= True;
1158             qh TRIangulate= True;
1159             break;
1160           case '2':
1161             qh_option("Q12-no-wide-dup", NULL, NULL);
1162             qh NOwide= True;
1163             break;
1164           default:
1165             s--;
1166             qh_fprintf(qh ferr, 7016, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]);
1167             while (*++s && !isspace(*s));
1168             break;
1169           }
1170           break;
1171         case '2':
1172           qh_option("Q2-no-merge-independent", NULL, NULL);
1173           qh MERGEindependent= False;
1174           goto LABELcheckdigit;
1175           break; /* no warnings */
1176         case '3':
1177           qh_option("Q3-no-merge-vertices", NULL, NULL);
1178           qh MERGEvertices= False;
1179         LABELcheckdigit:
1180           if (isdigit(*s))
1181             qh_fprintf(qh ferr, 7017, "qhull warning: can not follow '1', '2', or '3' with a digit.  '%c' skipped.\n",
1182                      *s++);
1183           break;
1184         case '4':
1185           qh_option("Q4-avoid-old-into-new", NULL, NULL);
1186           qh AVOIDold= True;
1187           break;
1188         case '5':
1189           qh_option("Q5-no-check-outer", NULL, NULL);
1190           qh SKIPcheckmax= True;
1191           break;
1192         case '6':
1193           qh_option("Q6-no-concave-merge", NULL, NULL);
1194           qh SKIPconvex= True;
1195           break;
1196         case '7':
1197           qh_option("Q7-no-breadth-first", NULL, NULL);
1198           qh VIRTUALmemory= True;
1199           break;
1200         case '8':
1201           qh_option("Q8-no-near-inside", NULL, NULL);
1202           qh NOnearinside= True;
1203           break;
1204         case '9':
1205           qh_option("Q9-pick-furthest", NULL, NULL);
1206           qh PICKfurthest= True;
1207           break;
1208         case 'G':
1209           i= qh_strtol(s, &t);
1210           if (qh GOODpoint)
1211             qh_fprintf(qh ferr, 7018, "qhull warning: good point already defined for option 'QGn'.  Ignored\n");
1212           else if (s == t)
1213             qh_fprintf(qh ferr, 7019, "qhull warning: missing good point id for option 'QGn'.  Ignored\n");
1214           else if (i < 0 || *s == '-') {
1215             qh GOODpoint= i-1;
1216             qh_option("QGood-if-dont-see-point", &i, NULL);
1217           }else {
1218             qh GOODpoint= i+1;
1219             qh_option("QGood-if-see-point", &i, NULL);
1220           }
1221           s= t;
1222           break;
1223         case 'J':
1224           if (!isdigit(*s) && *s != '-')
1225             qh JOGGLEmax= 0.0;
1226           else {
1227             qh JOGGLEmax= (realT) qh_strtod(s, &s);
1228             qh_option("QJoggle", NULL, &qh JOGGLEmax);
1229           }
1230           break;
1231         case 'R':
1232           if (!isdigit(*s) && *s != '-')
1233             qh_fprintf(qh ferr, 7020, "qhull warning: missing random seed for option 'QRn'.  Ignored\n");
1234           else {
1235             qh ROTATErandom= i= qh_strtol(s, &s);
1236             if (i > 0)
1237               qh_option("QRotate-id", &i, NULL );
1238             else if (i < -1)
1239               qh_option("QRandom-seed", &i, NULL );
1240           }
1241           break;
1242         case 'V':
1243           i= qh_strtol(s, &t);
1244           if (qh GOODvertex)
1245             qh_fprintf(qh ferr, 7021, "qhull warning: good vertex already defined for option 'QVn'.  Ignored\n");
1246           else if (s == t)
1247             qh_fprintf(qh ferr, 7022, "qhull warning: no good point id given for option 'QVn'.  Ignored\n");
1248           else if (i < 0) {
1249             qh GOODvertex= i - 1;
1250             qh_option("QV-good-facets-not-point", &i, NULL);
1251           }else {
1252             qh_option("QV-good-facets-point", &i, NULL);
1253             qh GOODvertex= i + 1;
1254           }
1255           s= t;
1256           break;
1257         default:
1258           s--;
1259           qh_fprintf(qh ferr, 7023, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]);
1260           while (*++s && !isspace(*s));
1261           break;
1262         }
1263       }
1264       break;
1265     case 'T':
1266       while (*s && !isspace(*s)) {
1267         if (isdigit(*s) || *s == '-')
1268           qh IStracing= qh_strtol(s, &s);
1269         else switch (*s++) {
1270         case 'a':
1271           qh_option("Tannotate-output", NULL, NULL);
1272           qh ANNOTATEoutput= True;
1273           break;
1274         case 'c':
1275           qh_option("Tcheck-frequently", NULL, NULL);
1276           qh CHECKfrequently= True;
1277           break;
1278         case 's':
1279           qh_option("Tstatistics", NULL, NULL);
1280           qh PRINTstatistics= True;
1281           break;
1282         case 'v':
1283           qh_option("Tverify", NULL, NULL);
1284           qh VERIFYoutput= True;
1285           break;
1286         case 'z':
1287           if (qh ferr == qh_FILEstderr) {
1288             /* The C++ interface captures the output in qh_fprint_qhull() */
1289             qh_option("Tz-stdout", NULL, NULL);
1290             qh USEstdout= True;
1291           }else if (!qh fout)
1292             qh_fprintf(qh ferr, 7024, "qhull warning: output file undefined(stdout).  Option 'Tz' ignored.\n");
1293           else {
1294             qh_option("Tz-stdout", NULL, NULL);
1295             qh USEstdout= True;
1296             qh ferr= qh fout;
1297             qhmem.ferr= qh fout;
1298           }
1299           break;
1300         case 'C':
1301           if (!isdigit(*s))
1302             qh_fprintf(qh ferr, 7025, "qhull warning: missing point id for cone for trace option 'TCn'.  Ignored\n");
1303           else {
1304             i= qh_strtol(s, &s);
1305             qh_option("TCone-stop", &i, NULL);
1306             qh STOPcone= i + 1;
1307           }
1308           break;
1309         case 'F':
1310           if (!isdigit(*s))
1311             qh_fprintf(qh ferr, 7026, "qhull warning: missing frequency count for trace option 'TFn'.  Ignored\n");
1312           else {
1313             qh REPORTfreq= qh_strtol(s, &s);
1314             qh_option("TFacet-log", &qh REPORTfreq, NULL);
1315             qh REPORTfreq2= qh REPORTfreq/2;  /* for tracemerging() */
1316           }
1317           break;
1318         case 'I':
1319           if (!isspace(*s))
1320             qh_fprintf(qh ferr, 7027, "qhull warning: missing space between 'TI' and filename, %s\n", s);
1321           while (isspace(*s))
1322             s++;
1323           t= qh_skipfilename(s);
1324           {
1325             char filename[qh_FILENAMElen];
1326 
1327             qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s));   /* WARN64 */
1328             s= t;
1329             if (!freopen(filename, "r", stdin)) {
1330               qh_fprintf(qh ferr, 6041, "qhull error: could not open file \"%s\".", filename);
1331               qh_errexit(qh_ERRinput, NULL, NULL);
1332             }else {
1333               qh_option("TInput-file", NULL, NULL);
1334               qh_option(filename, NULL, NULL);
1335             }
1336           }
1337           break;
1338         case 'O':
1339             if (!isspace(*s))
1340                 qh_fprintf(qh ferr, 7028, "qhull warning: missing space between 'TO' and filename, %s\n", s);
1341             while (isspace(*s))
1342                 s++;
1343             t= qh_skipfilename(s);
1344             {
1345               char filename[qh_FILENAMElen];
1346 
1347               qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s));  /* WARN64 */
1348               s= t;
1349               if (!qh fout) {
1350                 qh_fprintf(qh ferr, 6266, "qhull input warning: qh.fout was not set by caller.  Cannot use option 'TO' to redirect output.  Ignoring option 'TO'\n");
1351               }else if (!freopen(filename, "w", qh fout)) {
1352                 qh_fprintf(qh ferr, 6044, "qhull error: could not open file \"%s\".", filename);
1353                 qh_errexit(qh_ERRinput, NULL, NULL);
1354               }else {
1355                 qh_option("TOutput-file", NULL, NULL);
1356               qh_option(filename, NULL, NULL);
1357             }
1358           }
1359           break;
1360         case 'P':
1361           if (!isdigit(*s))
1362             qh_fprintf(qh ferr, 7029, "qhull warning: missing point id for trace option 'TPn'.  Ignored\n");
1363           else {
1364             qh TRACEpoint= qh_strtol(s, &s);
1365             qh_option("Trace-point", &qh TRACEpoint, NULL);
1366           }
1367           break;
1368         case 'M':
1369           if (!isdigit(*s))
1370             qh_fprintf(qh ferr, 7030, "qhull warning: missing merge id for trace option 'TMn'.  Ignored\n");
1371           else {
1372             qh TRACEmerge= qh_strtol(s, &s);
1373             qh_option("Trace-merge", &qh TRACEmerge, NULL);
1374           }
1375           break;
1376         case 'R':
1377           if (!isdigit(*s))
1378             qh_fprintf(qh ferr, 7031, "qhull warning: missing rerun count for trace option 'TRn'.  Ignored\n");
1379           else {
1380             qh RERUN= qh_strtol(s, &s);
1381             qh_option("TRerun", &qh RERUN, NULL);
1382           }
1383           break;
1384         case 'V':
1385           i= qh_strtol(s, &t);
1386           if (s == t)
1387             qh_fprintf(qh ferr, 7032, "qhull warning: missing furthest point id for trace option 'TVn'.  Ignored\n");
1388           else if (i < 0) {
1389             qh STOPpoint= i - 1;
1390             qh_option("TV-stop-before-point", &i, NULL);
1391           }else {
1392             qh STOPpoint= i + 1;
1393             qh_option("TV-stop-after-point", &i, NULL);
1394           }
1395           s= t;
1396           break;
1397         case 'W':
1398           if (!isdigit(*s))
1399             qh_fprintf(qh ferr, 7033, "qhull warning: missing max width for trace option 'TWn'.  Ignored\n");
1400           else {
1401             qh TRACEdist= (realT) qh_strtod(s, &s);
1402             qh_option("TWide-trace", NULL, &qh TRACEdist);
1403           }
1404           break;
1405         default:
1406           s--;
1407           qh_fprintf(qh ferr, 7034, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]);
1408           while (*++s && !isspace(*s));
1409           break;
1410         }
1411       }
1412       break;
1413     default:
1414       qh_fprintf(qh ferr, 7035, "qhull warning: unknown flag %c(%x)\n", (int)s[-1],
1415                (int)s[-1]);
1416       break;
1417     }
1418     if (s-1 == prev_s && *s && !isspace(*s)) {
1419       qh_fprintf(qh ferr, 7036, "qhull warning: missing space after flag %c(%x); reserved for menu. Skipped.\n",
1420                (int)*prev_s, (int)*prev_s);
1421       while (*s && !isspace(*s))
1422         s++;
1423     }
1424   }
1425   if (qh STOPcone && qh JOGGLEmax < REALmax/2)
1426     qh_fprintf(qh ferr, 7078, "qhull warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n");
1427   if (isgeom && !qh FORCEoutput && qh PRINTout[1])
1428     qh_fprintf(qh ferr, 7037, "qhull warning: additional output formats are not compatible with Geomview\n");
1429   /* set derived values in qh_initqhull_globals */
1430 } /* initflags */
1431 
1432 
1433 /*-<a                             href="qh-globa.htm#TOC"
1434   >-------------------------------</a><a name="initqhull_buffers">-</a>
1435 
1436   qh_initqhull_buffers()
1437     initialize global memory buffers
1438 
1439   notes:
1440     must match qh_freebuffers()
1441 */
qh_initqhull_buffers(void)1442 void qh_initqhull_buffers(void) {
1443   int k;
1444 
1445   qh TEMPsize= (qhmem.LASTsize - sizeof(setT))/SETelemsize;
1446   if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize)
1447     qh TEMPsize= 8;  /* e.g., if qh_NOmem */
1448   qh other_points= qh_setnew(qh TEMPsize);
1449   qh del_vertices= qh_setnew(qh TEMPsize);
1450   qh coplanarfacetset= qh_setnew(qh TEMPsize);
1451   qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT));
1452   qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
1453   qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
1454   qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
1455   qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT));
1456   for (k=qh input_dim+1; k--; ) {  /* duplicated in qh_initqhull_buffers and qh_clear_outputflags */
1457     qh lower_threshold[k]= -REALmax;
1458     qh upper_threshold[k]= REALmax;
1459     qh lower_bound[k]= -REALmax;
1460     qh upper_bound[k]= REALmax;
1461   }
1462   qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT));
1463   qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *));
1464 } /* initqhull_buffers */
1465 
1466 /*-<a                             href="qh-globa.htm#TOC"
1467   >-------------------------------</a><a name="initqhull_globals">-</a>
1468 
1469   qh_initqhull_globals( points, numpoints, dim, ismalloc )
1470     initialize globals
1471     if ismalloc
1472       points were malloc'd and qhull should free at end
1473 
1474   returns:
1475     sets qh.first_point, num_points, input_dim, hull_dim and others
1476     seeds random number generator (seed=1 if tracing)
1477     modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput)
1478     adjust user flags as needed
1479     also checks DIM3 dependencies and constants
1480 
1481   notes:
1482     do not use qh_point() since an input transformation may move them elsewhere
1483 
1484   see:
1485     qh_initqhull_start() sets default values for non-zero globals
1486 
1487   design:
1488     initialize points array from input arguments
1489     test for qh.ZEROcentrum
1490       (i.e., use opposite vertex instead of cetrum for convexity testing)
1491     initialize qh.CENTERtype, qh.normal_size,
1492       qh.center_size, qh.TRACEpoint/level,
1493     initialize and test random numbers
1494     qh_initqhull_outputflags() -- adjust and test output flags
1495 */
qh_initqhull_globals(coordT * points,int numpoints,int dim,boolT ismalloc)1496 void qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc) {
1497   int seed, pointsneeded, extra= 0, i, randi, k;
1498   realT randr;
1499   realT factorial;
1500 
1501   time_t timedata;
1502 
1503   trace0((qh ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh rbox_command,
1504       qh qhull_command));
1505   qh POINTSmalloc= ismalloc;
1506   qh first_point= points;
1507   qh num_points= numpoints;
1508   qh hull_dim= qh input_dim= dim;
1509   if (!qh NOpremerge && !qh MERGEexact && !qh PREmerge && qh JOGGLEmax > REALmax/2) {
1510     qh MERGING= True;
1511     if (qh hull_dim <= 4) {
1512       qh PREmerge= True;
1513       qh_option("_pre-merge", NULL, NULL);
1514     }else {
1515       qh MERGEexact= True;
1516       qh_option("Qxact_merge", NULL, NULL);
1517     }
1518   }else if (qh MERGEexact)
1519     qh MERGING= True;
1520   if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) {
1521 #ifdef qh_NOmerge
1522     qh JOGGLEmax= 0.0;
1523 #endif
1524   }
1525   if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && qh PRINTprecision)
1526     qh_fprintf(qh ferr, 7038, "qhull warning: joggle('QJ') always produces simplicial output.  Triangulated output('Qt') does nothing.\n");
1527   if (qh JOGGLEmax < REALmax/2 && qh DELAUNAY && !qh SCALEinput && !qh SCALElast) {
1528     qh SCALElast= True;
1529     qh_option("Qbbound-last-qj", NULL, NULL);
1530   }
1531   if (qh MERGING && !qh POSTmerge && qh premerge_cos > REALmax/2
1532   && qh premerge_centrum == 0) {
1533     qh ZEROcentrum= True;
1534     qh ZEROall_ok= True;
1535     qh_option("_zero-centrum", NULL, NULL);
1536   }
1537   if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision)
1538     qh_fprintf(qh ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user.h).\n",
1539           REALepsilon);
1540 #ifdef qh_NOmerge
1541   if (qh MERGING) {
1542     qh_fprintf(qh ferr, 6045, "qhull input error: merging not installed(qh_NOmerge + 'Qx', 'Cn' or 'An')\n");
1543     qh_errexit(qh_ERRinput, NULL, NULL);
1544   }
1545 #endif
1546   if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) {
1547     qh KEEPinside= True;
1548     qh_option("Qinterior-keep", NULL, NULL);
1549   }
1550   if (qh DELAUNAY && qh HALFspace) {
1551     qh_fprintf(qh ferr, 6046, "qhull input error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n");
1552     qh_errexit(qh_ERRinput, NULL, NULL);
1553   }
1554   if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) {
1555     qh_fprintf(qh ferr, 6047, "qhull input error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n");
1556     qh_errexit(qh_ERRinput, NULL, NULL);
1557   }
1558   if (qh UPPERdelaunay && qh ATinfinity) {
1559     qh_fprintf(qh ferr, 6048, "qhull input error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n");
1560     qh_errexit(qh_ERRinput, NULL, NULL);
1561   }
1562   if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision)
1563     qh_fprintf(qh ferr, 7040, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n");
1564   qh DOcheckmax= (!qh SKIPcheckmax && qh MERGING );
1565   qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar)
1566                           && !qh NOnearinside);
1567   if (qh MERGING)
1568     qh CENTERtype= qh_AScentrum;
1569   else if (qh VORONOI)
1570     qh CENTERtype= qh_ASvoronoi;
1571   if (qh TESTvneighbors && !qh MERGING) {
1572     qh_fprintf(qh ferr, 6049, "qhull input error: test vertex neighbors('Qv') needs a merge option\n");
1573     qh_errexit(qh_ERRinput, NULL ,NULL);
1574   }
1575   if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) {
1576     qh hull_dim -= qh PROJECTinput;
1577     if (qh DELAUNAY) {
1578       qh hull_dim++;
1579       if (qh ATinfinity)
1580         extra= 1;
1581     }
1582   }
1583   if (qh hull_dim <= 1) {
1584     qh_fprintf(qh ferr, 6050, "qhull error: dimension %d must be > 1\n", qh hull_dim);
1585     qh_errexit(qh_ERRinput, NULL, NULL);
1586   }
1587   for (k=2, factorial=1.0; k < qh hull_dim; k++)
1588     factorial *= k;
1589   qh AREAfactor= 1.0 / factorial;
1590   trace2((qh ferr, 2005, "qh_initqhull_globals: initialize globals.  dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n",
1591         dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim));
1592   qh normal_size= qh hull_dim * sizeof(coordT);
1593   qh center_size= qh normal_size - sizeof(coordT);
1594   pointsneeded= qh hull_dim+1;
1595   if (qh hull_dim > qh_DIMmergeVertex) {
1596     qh MERGEvertices= False;
1597     qh_option("Q3-no-merge-vertices-dim-high", NULL, NULL);
1598   }
1599   if (qh GOODpoint)
1600     pointsneeded++;
1601 #ifdef qh_NOtrace
1602   if (qh IStracing) {
1603     qh_fprintf(qh ferr, 6051, "qhull input error: tracing is not installed(qh_NOtrace in user.h)");
1604     qh_errexit(qh_ERRqhull, NULL, NULL);
1605   }
1606 #endif
1607   if (qh RERUN > 1) {
1608     qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */
1609     if (qh IStracing != -1)
1610       qh IStracing= 0;
1611   }else if (qh TRACEpoint != qh_IDunknown || qh TRACEdist < REALmax/2 || qh TRACEmerge) {
1612     qh TRACElevel= (qh IStracing? qh IStracing : 3);
1613     qh IStracing= 0;
1614   }
1615   if (qh ROTATErandom == 0 || qh ROTATErandom == -1) {
1616     seed= (int)time(&timedata);
1617     if (qh ROTATErandom  == -1) {
1618       seed= -seed;
1619       qh_option("QRandom-seed", &seed, NULL );
1620     }else
1621       qh_option("QRotate-random", &seed, NULL);
1622     qh ROTATErandom= seed;
1623   }
1624   seed= qh ROTATErandom;
1625   if (seed == INT_MIN)    /* default value */
1626     seed= 1;
1627   else if (seed < 0)
1628     seed= -seed;
1629   qh_RANDOMseed_(seed);
1630   randr= 0.0;
1631   for (i=1000; i--; ) {
1632     randi= qh_RANDOMint;
1633     randr += randi;
1634     if (randi > qh_RANDOMmax) {
1635       qh_fprintf(qh ferr, 8036, "\
1636 qhull configuration error (qh_RANDOMmax in user.h):\n\
1637    random integer %d > qh_RANDOMmax(%.8g)\n",
1638                randi, qh_RANDOMmax);
1639       qh_errexit(qh_ERRinput, NULL, NULL);
1640     }
1641   }
1642   qh_RANDOMseed_(seed);
1643   randr = randr/1000;
1644   if (randr < qh_RANDOMmax * 0.1
1645   || randr > qh_RANDOMmax * 0.9)
1646     qh_fprintf(qh ferr, 8037, "\
1647 qhull configuration warning (qh_RANDOMmax in user.h):\n\
1648    average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\
1649    Is qh_RANDOMmax (%.2g) wrong?\n",
1650              randr, qh_RANDOMmax * 0.5, qh_RANDOMmax);
1651   qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax;
1652   qh RANDOMb= 1.0 - qh RANDOMfactor;
1653   if (qh_HASHfactor < 1.1) {
1654     qh_fprintf(qh ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1.  Qhull uses linear hash probing\n",
1655       qh_HASHfactor);
1656     qh_errexit(qh_ERRqhull, NULL, NULL);
1657   }
1658   if (numpoints+extra < pointsneeded) {
1659     qh_fprintf(qh ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n",
1660             numpoints, pointsneeded);
1661     qh_errexit(qh_ERRinput, NULL, NULL);
1662   }
1663   qh_initqhull_outputflags();
1664 } /* initqhull_globals */
1665 
1666 /*-<a                             href="qh-globa.htm#TOC"
1667   >-------------------------------</a><a name="initqhull_mem">-</a>
1668 
1669   qh_initqhull_mem(  )
1670     initialize mem.c for qhull
1671     qh.hull_dim and qh.normal_size determine some of the allocation sizes
1672     if qh.MERGING,
1673       includes ridgeT
1674     calls qh_user_memsizes() to add up to 10 additional sizes for quick allocation
1675       (see numsizes below)
1676 
1677   returns:
1678     mem.c already for qh_memalloc/qh_memfree (errors if called beforehand)
1679 
1680   notes:
1681     qh_produceoutput() prints memsizes
1682 
1683 */
qh_initqhull_mem(void)1684 void qh_initqhull_mem(void) {
1685   int numsizes;
1686   int i;
1687 
1688   numsizes= 8+10;
1689   qh_meminitbuffers(qh IStracing, qh_MEMalign, numsizes,
1690                      qh_MEMbufsize,qh_MEMinitbuf);
1691   qh_memsize((int)sizeof(vertexT));
1692   if (qh MERGING) {
1693     qh_memsize((int)sizeof(ridgeT));
1694     qh_memsize((int)sizeof(mergeT));
1695   }
1696   qh_memsize((int)sizeof(facetT));
1697   i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize;  /* ridge.vertices */
1698   qh_memsize(i);
1699   qh_memsize(qh normal_size);        /* normal */
1700   i += SETelemsize;                 /* facet.vertices, .ridges, .neighbors */
1701   qh_memsize(i);
1702   qh_user_memsizes();
1703   qh_memsetup();
1704 } /* initqhull_mem */
1705 
1706 /*-<a                             href="qh-globa.htm#TOC"
1707   >-------------------------------</a><a name="initqhull_outputflags">-</a>
1708 
1709   qh_initqhull_outputflags
1710     initialize flags concerned with output
1711 
1712   returns:
1713     adjust user flags as needed
1714 
1715   see:
1716     qh_clear_outputflags() resets the flags
1717 
1718   design:
1719     test for qh.PRINTgood (i.e., only print 'good' facets)
1720     check for conflicting print output options
1721 */
qh_initqhull_outputflags(void)1722 void qh_initqhull_outputflags(void) {
1723   boolT printgeom= False, printmath= False, printcoplanar= False;
1724   int i;
1725 
1726   trace3((qh ferr, 3024, "qh_initqhull_outputflags: %s\n", qh qhull_command));
1727   if (!(qh PRINTgood || qh PRINTneighbors)) {
1728     if (qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge || qh DELAUNAY
1729         || (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) {
1730       qh PRINTgood= True;
1731       qh_option("Pgood", NULL, NULL);
1732     }
1733   }
1734   if (qh PRINTtransparent) {
1735     if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) {
1736       qh_fprintf(qh ferr, 6215, "qhull input error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n");
1737       qh_errexit(qh_ERRinput, NULL, NULL);
1738     }
1739     qh DROPdim = 3;
1740     qh PRINTridges = True;
1741   }
1742   for (i=qh_PRINTEND; i--; ) {
1743     if (qh PRINTout[i] == qh_PRINTgeom)
1744       printgeom= True;
1745     else if (qh PRINTout[i] == qh_PRINTmathematica || qh PRINTout[i] == qh_PRINTmaple)
1746       printmath= True;
1747     else if (qh PRINTout[i] == qh_PRINTcoplanars)
1748       printcoplanar= True;
1749     else if (qh PRINTout[i] == qh_PRINTpointnearest)
1750       printcoplanar= True;
1751     else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) {
1752       qh_fprintf(qh ferr, 6053, "qhull input error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n");
1753       qh_errexit(qh_ERRinput, NULL, NULL);
1754     }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) {
1755       qh_fprintf(qh ferr, 6054, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n");
1756       qh_errexit(qh_ERRinput, NULL, NULL);
1757     }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) {
1758       qh_fprintf(qh ferr, 6055, "qhull input error: option 'FC' is not available for Voronoi vertices('v')\n");
1759       qh_errexit(qh_ERRinput, NULL, NULL);
1760     }else if (qh PRINTout[i] == qh_PRINTvertices) {
1761       if (qh VORONOI)
1762         qh_option("Fvoronoi", NULL, NULL);
1763       else
1764         qh_option("Fvertices", NULL, NULL);
1765     }
1766   }
1767   if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) {
1768     if (qh PRINTprecision)
1769       qh_fprintf(qh ferr, 7041, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n");
1770   }
1771   if (printmath && (qh hull_dim > 3 || qh VORONOI)) {
1772     qh_fprintf(qh ferr, 6056, "qhull input error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n");
1773     qh_errexit(qh_ERRinput, NULL, NULL);
1774   }
1775   if (printgeom) {
1776     if (qh hull_dim > 4) {
1777       qh_fprintf(qh ferr, 6057, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n");
1778       qh_errexit(qh_ERRinput, NULL, NULL);
1779     }
1780     if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums
1781      + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) {
1782       qh_fprintf(qh ferr, 6058, "qhull input error: no output specified for Geomview\n");
1783       qh_errexit(qh_ERRinput, NULL, NULL);
1784     }
1785     if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) {
1786       qh_fprintf(qh ferr, 6059, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n");
1787       qh_errexit(qh_ERRinput, NULL, NULL);
1788     }
1789     /* can not warn about furthest-site Geomview output: no lower_threshold */
1790     if (qh hull_dim == 4 && qh DROPdim == -1 &&
1791         (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) {
1792       qh_fprintf(qh ferr, 7042, "qhull input warning: coplanars, vertices, and centrums output not\n\
1793 available for 4-d output(ignored).  Could use 'GDn' instead.\n");
1794       qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False;
1795     }
1796   }
1797   if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) {
1798     if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) {
1799       if (qh QHULLfinished) {
1800         qh_fprintf(qh ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n");
1801       }else {
1802         qh KEEPcoplanar = True;
1803         qh_option("Qcoplanar", NULL, NULL);
1804       }
1805     }
1806   }
1807   qh PRINTdim= qh hull_dim;
1808   if (qh DROPdim >=0) {    /* after Geomview checks */
1809     if (qh DROPdim < qh hull_dim) {
1810       qh PRINTdim--;
1811       if (!printgeom || qh hull_dim < 3)
1812         qh_fprintf(qh ferr, 7043, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim);
1813     }else
1814       qh DROPdim= -1;
1815   }else if (qh VORONOI) {
1816     qh DROPdim= qh hull_dim-1;
1817     qh PRINTdim= qh hull_dim-1;
1818   }
1819 } /* qh_initqhull_outputflags */
1820 
1821 /*-<a                             href="qh-globa.htm#TOC"
1822   >-------------------------------</a><a name="initqhull_start">-</a>
1823 
1824   qh_initqhull_start( infile, outfile, errfile )
1825     allocate memory if needed and call qh_initqhull_start2()
1826 */
qh_initqhull_start(FILE * infile,FILE * outfile,FILE * errfile)1827 void qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile) {
1828 
1829 #if qh_QHpointer
1830   if (qh_qh) {
1831     qh_fprintf(errfile, 6205, "qhull error (qh_initqhull_start): qh_qh already defined.  Call qh_save_qhull() first\n");
1832     qh_exit(qh_ERRqhull);  /* no error handler */
1833   }
1834   if (!(qh_qh= (qhT *)qh_malloc(sizeof(qhT)))) {
1835     qh_fprintf(errfile, 6060, "qhull error (qh_initqhull_start): insufficient memory\n");
1836     qh_exit(qh_ERRmem);  /* no error handler */
1837   }
1838 #endif
1839   qh_initstatistics();
1840   qh_initqhull_start2(infile, outfile, errfile);
1841 } /* initqhull_start */
1842 
1843 /*-<a                             href="qh-globa.htm#TOC"
1844   >-------------------------------</a><a name="initqhull_start2">-</a>
1845 
1846   qh_initqhull_start2( infile, outfile, errfile )
1847     start initialization of qhull
1848     initialize statistics, stdio, default values for global variables
1849     assumes qh_qh is defined
1850   notes:
1851     report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized
1852   see:
1853     qh_maxmin() determines the precision constants
1854     qh_freeqhull2()
1855 */
qh_initqhull_start2(FILE * infile,FILE * outfile,FILE * errfile)1856 void qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile) {
1857   time_t timedata;
1858   int seed;
1859 
1860   qh_CPUclock; /* start the clock(for qh_clock).  One-shot. */
1861 #if qh_QHpointer
1862   memset((char *)qh_qh, 0, sizeof(qhT));   /* every field is 0, FALSE, NULL */
1863 #else
1864   memset((char *)&qh_qh, 0, sizeof(qhT));
1865 #endif
1866   qh ANGLEmerge= True;
1867   qh DROPdim= -1;
1868   qh ferr= errfile;
1869   qh fin= infile;
1870   qh fout= outfile;
1871   qh furthest_id= qh_IDunknown;
1872   qh JOGGLEmax= REALmax;
1873   qh KEEPminArea = REALmax;
1874   qh last_low= REALmax;
1875   qh last_high= REALmax;
1876   qh last_newhigh= REALmax;
1877   qh max_outside= 0.0;
1878   qh max_vertex= 0.0;
1879   qh MAXabs_coord= 0.0;
1880   qh MAXsumcoord= 0.0;
1881   qh MAXwidth= -REALmax;
1882   qh MERGEindependent= True;
1883   qh MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */
1884   qh MINoutside= 0.0;
1885   qh MINvisible= REALmax;
1886   qh MAXcoplanar= REALmax;
1887   qh outside_err= REALmax;
1888   qh premerge_centrum= 0.0;
1889   qh premerge_cos= REALmax;
1890   qh PRINTprecision= True;
1891   qh PRINTradius= 0.0;
1892   qh postmerge_cos= REALmax;
1893   qh postmerge_centrum= 0.0;
1894   qh ROTATErandom= INT_MIN;
1895   qh MERGEvertices= True;
1896   qh totarea= 0.0;
1897   qh totvol= 0.0;
1898   qh TRACEdist= REALmax;
1899   qh TRACEpoint= qh_IDunknown; /* recompile or use 'TPn' */
1900   qh tracefacet_id= UINT_MAX;  /* recompile to trace a facet */
1901   qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex */
1902   seed= (int)time(&timedata);
1903   qh_RANDOMseed_(seed);
1904   qh run_id= qh_RANDOMint;
1905   if(!qh run_id)
1906       qh run_id++;  /* guarantee non-zero */
1907   qh_option("run-id", &qh run_id, NULL);
1908   strcat(qh qhull, "qhull");
1909 } /* initqhull_start2 */
1910 
1911 /*-<a                             href="qh-globa.htm#TOC"
1912   >-------------------------------</a><a name="initthresholds">-</a>
1913 
1914   qh_initthresholds( commandString )
1915     set thresholds for printing and scaling from commandString
1916 
1917   returns:
1918     sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used
1919 
1920   see:
1921     qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk'
1922     qh_inthresholds()
1923 
1924   design:
1925     for each 'Pdn' or 'PDn' option
1926       check syntax
1927       set qh.lower_threshold or qh.upper_threshold
1928     set qh.GOODthreshold if an unbounded threshold is used
1929     set qh.SPLITthreshold if a bounded threshold is used
1930 */
qh_initthresholds(char * command)1931 void qh_initthresholds(char *command) {
1932   realT value;
1933   int idx, maxdim, k;
1934   char *s= command; /* non-const due to strtol */
1935   char key;
1936 
1937   maxdim= qh input_dim;
1938   if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput))
1939     maxdim++;
1940   while (*s) {
1941     if (*s == '-')
1942       s++;
1943     if (*s == 'P') {
1944       s++;
1945       while (*s && !isspace(key= *s++)) {
1946         if (key == 'd' || key == 'D') {
1947           if (!isdigit(*s)) {
1948             qh_fprintf(qh ferr, 7044, "qhull warning: no dimension given for Print option '%c' at: %s.  Ignored\n",
1949                     key, s-1);
1950             continue;
1951           }
1952           idx= qh_strtol(s, &s);
1953           if (idx >= qh hull_dim) {
1954             qh_fprintf(qh ferr, 7045, "qhull warning: dimension %d for Print option '%c' is >= %d.  Ignored\n",
1955                 idx, key, qh hull_dim);
1956             continue;
1957           }
1958           if (*s == ':') {
1959             s++;
1960             value= qh_strtod(s, &s);
1961             if (fabs((double)value) > 1.0) {
1962               qh_fprintf(qh ferr, 7046, "qhull warning: value %2.4g for Print option %c is > +1 or < -1.  Ignored\n",
1963                       value, key);
1964               continue;
1965             }
1966           }else
1967             value= 0.0;
1968           if (key == 'd')
1969             qh lower_threshold[idx]= value;
1970           else
1971             qh upper_threshold[idx]= value;
1972         }
1973       }
1974     }else if (*s == 'Q') {
1975       s++;
1976       while (*s && !isspace(key= *s++)) {
1977         if (key == 'b' && *s == 'B') {
1978           s++;
1979           for (k=maxdim; k--; ) {
1980             qh lower_bound[k]= -qh_DEFAULTbox;
1981             qh upper_bound[k]= qh_DEFAULTbox;
1982           }
1983         }else if (key == 'b' && *s == 'b')
1984           s++;
1985         else if (key == 'b' || key == 'B') {
1986           if (!isdigit(*s)) {
1987             qh_fprintf(qh ferr, 7047, "qhull warning: no dimension given for Qhull option %c.  Ignored\n",
1988                     key);
1989             continue;
1990           }
1991           idx= qh_strtol(s, &s);
1992           if (idx >= maxdim) {
1993             qh_fprintf(qh ferr, 7048, "qhull warning: dimension %d for Qhull option %c is >= %d.  Ignored\n",
1994                 idx, key, maxdim);
1995             continue;
1996           }
1997           if (*s == ':') {
1998             s++;
1999             value= qh_strtod(s, &s);
2000           }else if (key == 'b')
2001             value= -qh_DEFAULTbox;
2002           else
2003             value= qh_DEFAULTbox;
2004           if (key == 'b')
2005             qh lower_bound[idx]= value;
2006           else
2007             qh upper_bound[idx]= value;
2008         }
2009       }
2010     }else {
2011       while (*s && !isspace(*s))
2012         s++;
2013     }
2014     while (isspace(*s))
2015       s++;
2016   }
2017   for (k=qh hull_dim; k--; ) {
2018     if (qh lower_threshold[k] > -REALmax/2) {
2019       qh GOODthreshold= True;
2020       if (qh upper_threshold[k] < REALmax/2) {
2021         qh SPLITthresholds= True;
2022         qh GOODthreshold= False;
2023         break;
2024       }
2025     }else if (qh upper_threshold[k] < REALmax/2)
2026       qh GOODthreshold= True;
2027   }
2028 } /* initthresholds */
2029 
2030 /*-<a                             href="qh-globa.htm#TOC"
2031   >-------------------------------</a><a name="lib_check">-</a>
2032 
2033   qh_lib_check( qhullLibraryType, qhTsize, vertexTsize, ridgeTsize, facetTsize, setTsize, qhmemTsize )
2034     Report error if library does not agree with caller
2035 
2036   notes:
2037     NOerrors -- qh_lib_check can not call qh_errexit()
2038 */
qh_lib_check(int qhullLibraryType,int qhTsize,int vertexTsize,int ridgeTsize,int facetTsize,int setTsize,int qhmemTsize)2039 void qh_lib_check(int qhullLibraryType, int qhTsize, int vertexTsize, int ridgeTsize, int facetTsize, int setTsize, int qhmemTsize) {
2040     boolT iserror= False;
2041 
2042 #if defined(_MSC_VER) && defined(_DEBUG) && defined(QHULL_CRTDBG)  /* user_r.h */
2043     // _CrtSetBreakAlloc(744);  /* Break at memalloc {744}, or 'watch' _crtBreakAlloc */
2044     _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) );
2045     _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
2046     _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
2047     _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
2048     _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
2049     _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG );
2050     _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
2051 #endif
2052 
2053     if (qhullLibraryType==QHULL_NON_REENTRANT) { /* 0 */
2054         if (qh_QHpointer) {
2055             qh_fprintf_stderr(6246, "qh_lib_check: Incorrect qhull library called.  Caller uses a static qhT while library uses a dynamic qhT via qh_QHpointer.  Both caller and library are non-reentrant.\n");
2056             iserror= True;
2057         }
2058     }else if (qhullLibraryType==QHULL_QH_POINTER) { /* 1 */
2059         if (!qh_QHpointer) {
2060             qh_fprintf_stderr(6247, "qh_lib_check: Incorrect qhull library called.  Caller uses a dynamic qhT via qh_QHpointer while library uses a static qhT.  Both caller and library are non-reentrant.\n");
2061             iserror= True;
2062         }
2063     }else if (qhullLibraryType==QHULL_REENTRANT) { /* 2 */
2064         qh_fprintf_stderr(6248, "qh_lib_check: Incorrect qhull library called.  Caller uses reentrant Qhull while library is non-reentrant\n");
2065         iserror= True;
2066     }else{
2067         qh_fprintf_stderr(6262, "qh_lib_check: Expecting qhullLibraryType QHULL_NON_REENTRANT(0), QHULL_QH_POINTER(1), or QHULL_REENTRANT(2).  Got %d\n", qhullLibraryType);
2068         iserror= True;
2069     }
2070     if (qhTsize != sizeof(qhT)) {
2071         qh_fprintf_stderr(6249, "qh_lib_check: Incorrect qhull library called.  Size of qhT for caller is %d, but for library is %d.\n", qhTsize, sizeof(qhT));
2072         iserror= True;
2073     }
2074     if (vertexTsize != sizeof(vertexT)) {
2075         qh_fprintf_stderr(6250, "qh_lib_check: Incorrect qhull library called.  Size of vertexT for caller is %d, but for library is %d.\n", vertexTsize, sizeof(vertexT));
2076         iserror= True;
2077     }
2078     if (ridgeTsize != sizeof(ridgeT)) {
2079         qh_fprintf_stderr(6251, "qh_lib_check: Incorrect qhull library called.  Size of ridgeT for caller is %d, but for library is %d.\n", ridgeTsize, sizeof(ridgeT));
2080         iserror= True;
2081     }
2082     if (facetTsize != sizeof(facetT)) {
2083         qh_fprintf_stderr(6252, "qh_lib_check: Incorrect qhull library called.  Size of facetT for caller is %d, but for library is %d.\n", facetTsize, sizeof(facetT));
2084         iserror= True;
2085     }
2086     if (setTsize && setTsize != sizeof(setT)) {
2087         qh_fprintf_stderr(6253, "qh_lib_check: Incorrect qhull library called.  Size of setT for caller is %d, but for library is %d.\n", setTsize, sizeof(setT));
2088         iserror= True;
2089     }
2090     if (qhmemTsize && qhmemTsize != sizeof(qhmemT)) {
2091         qh_fprintf_stderr(6254, "qh_lib_check: Incorrect qhull library called.  Size of qhmemT for caller is %d, but for library is %d.\n", qhmemTsize, sizeof(qhmemT));
2092         iserror= True;
2093     }
2094     if (iserror) {
2095         if(qh_QHpointer){
2096             qh_fprintf_stderr(6255, "qh_lib_check: Cannot continue.  Library '%s' uses a dynamic qhT via qh_QHpointer (e.g., qhull_p.so)\n", qh_version2);
2097         }else{
2098             qh_fprintf_stderr(6256, "qh_lib_check: Cannot continue.  Library '%s' uses a static qhT (e.g., libqhull.so)\n", qh_version2);
2099         }
2100         qh_exit(qh_ERRqhull);  /* can not use qh_errexit() */
2101     }
2102 } /* lib_check */
2103 
2104 /*-<a                             href="qh-globa.htm#TOC"
2105   >-------------------------------</a><a name="option">-</a>
2106 
2107   qh_option( option, intVal, realVal )
2108     add an option description to qh.qhull_options
2109 
2110   notes:
2111     NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2]
2112     will be printed with statistics ('Ts') and errors
2113     strlen(option) < 40
2114 */
qh_option(const char * option,int * i,realT * r)2115 void qh_option(const char *option, int *i, realT *r) {
2116   char buf[200];
2117   int len, maxlen;
2118 
2119   sprintf(buf, "  %s", option);
2120   if (i)
2121     sprintf(buf+strlen(buf), " %d", *i);
2122   if (r)
2123     sprintf(buf+strlen(buf), " %2.2g", *r);
2124   len= (int)strlen(buf);  /* WARN64 */
2125   qh qhull_optionlen += len;
2126   maxlen= sizeof(qh qhull_options) - len -1;
2127   maximize_(maxlen, 0);
2128   if (qh qhull_optionlen >= qh_OPTIONline && maxlen > 0) {
2129     qh qhull_optionlen= len;
2130     strncat(qh qhull_options, "\n", (size_t)(maxlen--));
2131   }
2132   strncat(qh qhull_options, buf, (size_t)maxlen);
2133 } /* option */
2134 
2135 #if qh_QHpointer
2136 /*-<a                             href="qh-globa.htm#TOC"
2137   >-------------------------------</a><a name="restore_qhull">-</a>
2138 
2139   qh_restore_qhull( oldqh )
2140     restores a previously saved qhull
2141     also restores qh_qhstat and qhmem.tempstack
2142     Sets *oldqh to NULL
2143   notes:
2144     errors if current qhull hasn't been saved or freed
2145     uses qhmem for error reporting
2146 
2147   NOTE 1998/5/11:
2148     Freeing memory after qh_save_qhull and qh_restore_qhull
2149     is complicated.  The procedures will be redesigned.
2150 
2151   see:
2152     qh_save_qhull(), UsingLibQhull
2153 */
qh_restore_qhull(qhT ** oldqh)2154 void qh_restore_qhull(qhT **oldqh) {
2155 
2156   if (*oldqh && strcmp((*oldqh)->qhull, "qhull")) {
2157     qh_fprintf(qhmem.ferr, 6061, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n",
2158                   *oldqh);
2159     qh_errexit(qh_ERRqhull, NULL, NULL);
2160   }
2161   if (qh_qh) {
2162     qh_fprintf(qhmem.ferr, 6062, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n");
2163     qh_errexit(qh_ERRqhull, NULL, NULL);
2164   }
2165   if (!*oldqh || !(*oldqh)->old_qhstat) {
2166     qh_fprintf(qhmem.ferr, 6063, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n",
2167                   *oldqh);
2168     qh_errexit(qh_ERRqhull, NULL, NULL);
2169   }
2170   qh_qh= *oldqh;
2171   *oldqh= NULL;
2172   qh_qhstat= qh old_qhstat;
2173   qhmem.tempstack= qh old_tempstack;
2174   qh old_qhstat= 0;
2175   qh old_tempstack= 0;
2176   trace1((qh ferr, 1007, "qh_restore_qhull: restored qhull from %p\n", *oldqh));
2177 } /* restore_qhull */
2178 
2179 /*-<a                             href="qh-globa.htm#TOC"
2180   >-------------------------------</a><a name="save_qhull">-</a>
2181 
2182   qh_save_qhull(  )
2183     saves qhull for a later qh_restore_qhull
2184     also saves qh_qhstat and qhmem.tempstack
2185 
2186   returns:
2187     qh_qh=NULL
2188 
2189   notes:
2190     need to initialize qhull or call qh_restore_qhull before continuing
2191 
2192   NOTE 1998/5/11:
2193     Freeing memory after qh_save_qhull and qh_restore_qhull
2194     is complicated.  The procedures will be redesigned.
2195 
2196   see:
2197     qh_restore_qhull()
2198 */
qh_save_qhull(void)2199 qhT *qh_save_qhull(void) {
2200   qhT *oldqh;
2201 
2202   trace1((qhmem.ferr, 1045, "qh_save_qhull: save qhull %p\n", qh_qh));
2203   if (!qh_qh) {
2204     qh_fprintf(qhmem.ferr, 6064, "qhull internal error (qh_save_qhull): qhull not initialized\n");
2205     qh_errexit(qh_ERRqhull, NULL, NULL);
2206   }
2207   qh old_qhstat= qh_qhstat;
2208   qh_qhstat= NULL;
2209   qh old_tempstack= qhmem.tempstack;
2210   qhmem.tempstack= NULL;
2211   oldqh= qh_qh;
2212   qh_qh= NULL;
2213   return oldqh;
2214 } /* save_qhull */
2215 
2216 #endif
2217 
2218