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