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