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