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

File Contents

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