diff options
Diffstat (limited to 'extern/qhull/src/global.c')
-rwxr-xr-x | extern/qhull/src/global.c | 2018 |
1 files changed, 2018 insertions, 0 deletions
diff --git a/extern/qhull/src/global.c b/extern/qhull/src/global.c new file mode 100755 index 00000000000..d3e141aa985 --- /dev/null +++ b/extern/qhull/src/global.c @@ -0,0 +1,2018 @@ +/*<html><pre> -<a href="qh-globa.htm" + >-------------------------------</a><a name="TOP">-</a> + + global.c + initializes all the globals of the qhull application + + see README + + see qhull.h for qh.globals and function prototypes + + see qhull_a.h for internal functions + + copyright (c) 1993-2002, The Geometry Center + */ + +#include "qhull_a.h" + +/*========= qh definition =======================*/ + +#if qh_QHpointer +qhT *qh_qh= NULL; /* pointer to all global variables */ +#else +qhT qh_qh; /* all global variables. + Add "= {0}" if this causes a compiler error. + Also qh_qhstat in stat.c and qhmem in mem.c. */ +#endif + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="appendprint">-</a> + + qh_appendprint( printFormat ) + append printFormat to qh.PRINTout unless already defined +*/ +void qh_appendprint (qh_PRINT format) { + int i; + + for (i=0; i < qh_PRINTEND; i++) { + if (qh PRINTout[i] == format && format != qh_PRINTqhull) + break; + if (!qh PRINTout[i]) { + qh PRINTout[i]= format; + break; + } + } +} /* appendprint */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="checkflags">-</a> + + qh_checkflags( commandStr, hiddenFlags ) + errors if commandStr contains hiddenFlags + hiddenFlags starts and ends with a space and is space deliminated (checked) + + notes: + ignores first word (e.g., "qconvex i") + use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces + + see: + qh_initflags() initializes Qhull according to commandStr +*/ +void qh_checkflags(char *command, char *hiddenflags) { + char *s= command, *t, *chkerr, key, opt, prevopt; + char chkkey[]= " "; + char chkopt[]= " "; + char chkopt2[]= " "; + + if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') { + fprintf(qh ferr, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags); + qh_errexit(qh_ERRinput, NULL, NULL); + } + if (strpbrk(hiddenflags, ",\n\r\t")) { + fprintf(qh ferr, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags); + qh_errexit(qh_ERRinput, NULL, NULL); + } + while (*s && !isspace(*s)) /* skip program name */ + s++; + while (*s) { + while (*s && isspace(*s)) + s++; + if (*s == '-') + s++; + if (!*s) + break; + key = *s++; + chkerr = NULL; + if (key == '\'') { /* TO 'file name' */ + t= strchr(s, '\''); + if (!t) { + fprintf(qh ferr, "qhull error (qh_checkflags): missing the 2nd single-quote for:\n%s\n", s-1); + qh_errexit(qh_ERRinput, NULL, NULL); + } + s= t+1; + continue; + } + chkkey[1]= key; + if (strstr(hiddenflags, chkkey)) { + chkerr= chkkey; + }else if (isupper(key)) { + opt= ' '; + prevopt= ' '; + chkopt[1]= key; + chkopt2[1]= key; + while (!chkerr && *s && !isspace(*s)) { + opt= *s++; + if (isalpha(opt)) { + chkopt[2]= opt; + if (strstr(hiddenflags, chkopt)) + chkerr= chkopt; + if (prevopt != ' ') { + chkopt2[2]= prevopt; + chkopt2[3]= opt; + if (strstr(hiddenflags, chkopt2)) + chkerr= chkopt2; + } + }else if (key == 'Q' && isdigit(opt) && prevopt != 'b' + && (prevopt == ' ' || islower(prevopt))) { + chkopt[2]= opt; + if (strstr(hiddenflags, chkopt)) + chkerr= chkopt; + }else { + qh_strtod (s-1, &t); + if (s < t) + s= t; + } + prevopt= opt; + } + } + if (chkerr) { + *chkerr= '\''; + chkerr[strlen(chkerr)-1]= '\''; + fprintf(qh ferr, "qhull error: option %s is not used with this program.\n It may be used with qhull.\n", chkerr); + qh_errexit(qh_ERRinput, NULL, NULL); + } + } +} /* checkflags */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="clock">-</a> + + qh_clock() + return user CPU time in 100ths (qh_SECtick) + only defined for qh_CLOCKtype == 2 + + notes: + use first value to determine time 0 + from Stevens '92 8.15 +*/ +unsigned long qh_clock (void) { + +#if (qh_CLOCKtype == 2) + struct tms time; + static long clktck; /* initialized first call */ + double ratio, cpu; + unsigned long ticks; + + if (!clktck) { + if ((clktck= sysconf (_SC_CLK_TCK)) < 0) { + fprintf (qh ferr, "qhull internal error (qh_clock): sysconf() failed. Use qh_CLOCKtype 1 in user.h\n"); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + } + if (times (&time) == -1) { + fprintf (qh ferr, "qhull internal error (qh_clock): times() failed. Use qh_CLOCKtype 1 in user.h\n"); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + ratio= qh_SECticks / (double)clktck; + ticks= time.tms_utime * ratio; + return ticks; +#else + fprintf (qh ferr, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n"); + qh_errexit (qh_ERRqhull, NULL, NULL); /* never returns */ + return 0; +#endif +} /* clock */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="freebuffers">-</a> + + qh_freebuffers() + free up global memory buffers + + notes: + must match qh_initbuffers() +*/ +void qh_freebuffers (void) { + + trace5((qh ferr, "qh_freebuffers: freeing up global memory buffers\n")); + /* allocated by qh_initqhull_buffers */ + qh_memfree (qh NEARzero, qh hull_dim * sizeof(realT)); + qh_memfree (qh lower_threshold, (qh input_dim+1) * sizeof(realT)); + qh_memfree (qh upper_threshold, (qh input_dim+1) * sizeof(realT)); + qh_memfree (qh lower_bound, (qh input_dim+1) * sizeof(realT)); + qh_memfree (qh upper_bound, (qh input_dim+1) * sizeof(realT)); + qh_memfree (qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT)); + qh_memfree (qh gm_row, (qh hull_dim+1) * sizeof(coordT *)); + qh NEARzero= qh lower_threshold= qh upper_threshold= NULL; + qh lower_bound= qh upper_bound= NULL; + qh gm_matrix= NULL; + qh gm_row= NULL; + qh_setfree (&qh other_points); + qh_setfree (&qh del_vertices); + qh_setfree (&qh coplanarset); + if (qh line) /* allocated by qh_readinput, freed if no error */ + free (qh line); + if (qh half_space) + free (qh half_space); + if (qh temp_malloc) + free (qh temp_malloc); + if (qh feasible_point) /* allocated by qh_readfeasible */ + free (qh feasible_point); + if (qh feasible_string) /* allocated by qh_initflags */ + free (qh feasible_string); + qh line= qh feasible_string= NULL; + qh half_space= qh feasible_point= qh temp_malloc= NULL; + /* usually allocated by qh_readinput */ + if (qh first_point && qh POINTSmalloc) { + free(qh first_point); + qh first_point= NULL; + } + if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */ + free (qh input_points); + qh input_points= NULL; + } + trace5((qh ferr, "qh_freebuffers: finished\n")); +} /* freebuffers */ + + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="freebuild">-</a> + + qh_freebuild( allmem ) + free global memory used by qh_initbuild and qh_buildhull + if !allmem, + does not free short memory (freed by qh_memfreeshort) + + design: + free centrums + free each vertex + mark unattached ridges + for each facet + free ridges + free outside set, coplanar set, neighbor set, ridge set, vertex set + free facet + free hash table + free interior point + free merge set + free temporary sets +*/ +void qh_freebuild (boolT allmem) { + facetT *facet; + vertexT *vertex; + ridgeT *ridge, **ridgep; + mergeT *merge, **mergep; + + trace1((qh ferr, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n")); + if (qh del_vertices) + qh_settruncate (qh del_vertices, 0); + if (allmem) { + qh_clearcenters (qh_ASnone); + while ((vertex= qh vertex_list)) { + if (vertex->next) + qh_delvertex (vertex); + else { + qh_memfree (vertex, sizeof(vertexT)); + qh newvertex_list= qh vertex_list= NULL; + } + } + }else if (qh VERTEXneighbors) { + FORALLvertices + qh_setfreelong (&(vertex->neighbors)); + } + qh VERTEXneighbors= False; + qh GOODclosest= NULL; + if (allmem) { + FORALLfacets { + FOREACHridge_(facet->ridges) + ridge->seen= False; + } + FORALLfacets { + if (facet->visible) { + FOREACHridge_(facet->ridges) { + if (!otherfacet_(ridge, facet)->visible) + ridge->seen= True; /* an unattached ridge */ + } + } + } + while ((facet= qh facet_list)) { + FOREACHridge_(facet->ridges) { + if (ridge->seen) { + qh_setfree(&(ridge->vertices)); + qh_memfree(ridge, sizeof(ridgeT)); + }else + ridge->seen= True; + } + qh_setfree (&(facet->outsideset)); + qh_setfree (&(facet->coplanarset)); + qh_setfree (&(facet->neighbors)); + qh_setfree (&(facet->ridges)); + qh_setfree (&(facet->vertices)); + if (facet->next) + qh_delfacet (facet); + else { + qh_memfree (facet, sizeof(facetT)); + qh visible_list= qh newfacet_list= qh facet_list= NULL; + } + } + }else { + FORALLfacets { + qh_setfreelong (&(facet->outsideset)); + qh_setfreelong (&(facet->coplanarset)); + if (!facet->simplicial) { + qh_setfreelong (&(facet->neighbors)); + qh_setfreelong (&(facet->ridges)); + qh_setfreelong (&(facet->vertices)); + } + } + } + qh_setfree (&(qh hash_table)); + qh_memfree (qh interior_point, qh normal_size); + qh interior_point= NULL; + FOREACHmerge_(qh facet_mergeset) /* usually empty */ + qh_memfree (merge, sizeof(mergeT)); + qh facet_mergeset= NULL; /* temp set */ + qh degen_mergeset= NULL; /* temp set */ + qh_settempfree_all(); +} /* freebuild */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="freeqhull">-</a> + + qh_freeqhull( allmem ) + free global memory + if !allmem, + does not free short memory (freed by qh_memfreeshort) + + notes: + sets qh.NOerrexit in case caller forgets to + + design: + free global and temporary memory from qh_initbuild and qh_buildhull + free buffers + free statistics +*/ +void qh_freeqhull (boolT allmem) { + + trace1((qh ferr, "qh_freeqhull: free global memory\n")); + qh NOerrexit= True; /* no more setjmp since called at exit */ + qh_freebuild (allmem); + qh_freebuffers(); + qh_freestatistics(); +#if qh_QHpointer + free (qh_qh); + qh_qh= NULL; +#else + memset((char *)&qh_qh, 0, sizeof(qhT)); + qh NOerrexit= True; +#endif +} /* freeqhull */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="init_A">-</a> + + qh_init_A( infile, outfile, errfile, argc, argv ) + initialize memory and stdio files + convert input options to option string (qh.qhull_command) + + notes: + infile may be NULL if qh_readpoints() is not called + + errfile should always be defined. It is used for reporting + errors. outfile is used for output and format options. + + argc/argv may be 0/NULL + + called before error handling initialized + qh_errexit() may not be used +*/ +void qh_init_A (FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) { + qh_meminit (errfile); + qh_initqhull_start (infile, outfile, errfile); + qh_init_qhull_command (argc, argv); +} /* init_A */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="init_B">-</a> + + qh_init_B( points, numpoints, dim, ismalloc ) + initialize globals for points array + + points has numpoints dim-dimensional points + points[0] is the first coordinate of the first point + points[1] is the second coordinate of the first point + points[dim] is the first coordinate of the second point + + ismalloc=True + Qhull will call free(points) on exit or input transformation + ismalloc=False + Qhull will allocate a new point array if needed for input transformation + + qh.qhull_command + is the option string. + It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags + + returns: + if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay) + projects the input to a new point array + + if qh.DELAUNAY, + qh.hull_dim is increased by one + if qh.ATinfinity, + qh_projectinput adds point-at-infinity for Delaunay tri. + + if qh.SCALEinput + changes the upper and lower bounds of the input, see qh_scaleinput() + + if qh.ROTATEinput + rotates the input by a random rotation, see qh_rotateinput() + if qh.DELAUNAY + rotates about the last coordinate + + notes: + called after points are defined + qh_errexit() may be used +*/ +void qh_init_B (coordT *points, int numpoints, int dim, boolT ismalloc) { + qh_initqhull_globals (points, numpoints, dim, ismalloc); + if (qhmem.LASTsize == 0) + qh_initqhull_mem(); + /* mem.c and qset.c are initialized */ + qh_initqhull_buffers(); + qh_initthresholds (qh qhull_command); + if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) + qh_projectinput(); + if (qh SCALEinput) + qh_scaleinput(); + if (qh ROTATErandom >= 0) { + qh_randommatrix (qh gm_matrix, qh hull_dim, qh gm_row); + if (qh DELAUNAY) { + int k, lastk= qh hull_dim-1; + for (k= 0; k < lastk; k++) { + qh gm_row[k][lastk]= 0.0; + qh gm_row[lastk][k]= 0.0; + } + qh gm_row[lastk][lastk]= 1.0; + } + qh_gram_schmidt (qh hull_dim, qh gm_row); + qh_rotateinput (qh gm_row); + } +} /* init_B */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="init_qhull_command">-</a> + + qh_init_qhull_command( argc, argv ) + build qh.qhull_command from argc/argv + + returns: + a space-deliminated string of options (just as typed) + + notes: + makes option string easy to input and output + + argc/argv may be 0/NULL +*/ +void qh_init_qhull_command(int argc, char *argv[]) { + int i; + char *s; + + if (argc) { + if ((s= strrchr( argv[0], '\\'))) /* Borland gives full path */ + strcpy (qh qhull_command, s+1); + else + strcpy (qh qhull_command, argv[0]); + if ((s= strstr (qh qhull_command, ".EXE")) + || (s= strstr (qh qhull_command, ".exe"))) + *s= '\0'; + } + for (i=1; i < argc; i++) { + if (strlen (qh qhull_command) + strlen(argv[i]) + 1 < sizeof(qh qhull_command)) { + strcat (qh qhull_command, " "); + strcat (qh qhull_command, argv[i]); + }else { + fprintf (qh ferr, "qhull input error: more than %d characters in command line\n", + (int)sizeof(qh qhull_command)); + exit (1); /* can not use qh_errexit */ + } + } +} /* init_qhull_command */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="initflags">-</a> + + qh_initflags( commandStr ) + set flags and initialized constants from commandStr + + returns: + sets qh.qhull_command to command if needed + + notes: + ignores first word (e.g., "qhull d") + use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces + + see: + qh_initthresholds() continues processing of 'Pdn' and 'PDn' + 'prompt' in unix.c for documentation + + design: + for each space-deliminated option group + if top-level option + check syntax + append approriate option to option string + set appropriate global variable or append printFormat to print options + else + for each sub-option + check syntax + append approriate option to option string + set appropriate global variable or append printFormat to print options + + +*/ +void qh_initflags(char *command) { + int k, i, lastproject; + char *s= command, *t, *prev_s, *start, key; + boolT isgeom= False, wasproject; + realT r; + + if (command != &qh qhull_command[0]) { + *qh qhull_command= '\0'; + strncat( qh qhull_command, command, sizeof( qh qhull_command)); + } + while (*s && !isspace(*s)) /* skip program name */ + s++; + while (*s) { + while (*s && isspace(*s)) + s++; + if (*s == '-') + s++; + if (!*s) + break; + prev_s= s; + switch (*s++) { + case 'd': + qh_option ("delaunay", NULL, NULL); + qh DELAUNAY= True; + break; + case 'f': + qh_option ("facets", NULL, NULL); + qh_appendprint (qh_PRINTfacets); + break; + case 'i': + qh_option ("incidence", NULL, NULL); + qh_appendprint (qh_PRINTincidences); + break; + case 'm': + qh_option ("mathematica", NULL, NULL); + qh_appendprint (qh_PRINTmathematica); + break; + case 'n': + qh_option ("normals", NULL, NULL); + qh_appendprint (qh_PRINTnormals); + break; + case 'o': + qh_option ("offFile", NULL, NULL); + qh_appendprint (qh_PRINToff); + break; + case 'p': + qh_option ("points", NULL, NULL); + qh_appendprint (qh_PRINTpoints); + break; + case 's': + qh_option ("summary", NULL, NULL); + qh PRINTsummary= True; + break; + case 'v': + qh_option ("voronoi", NULL, NULL); + qh VORONOI= True; + qh DELAUNAY= True; + break; + case 'A': + if (!isdigit(*s) && *s != '.' && *s != '-') + fprintf(qh ferr, "qhull warning: no maximum cosine angle given for option 'An'. Ignored.\n"); + else { + if (*s == '-') { + qh premerge_cos= -qh_strtod (s, &s); + qh_option ("Angle-premerge-", NULL, &qh premerge_cos); + qh PREmerge= True; + }else { + qh postmerge_cos= qh_strtod (s, &s); + qh_option ("Angle-postmerge", NULL, &qh postmerge_cos); + qh POSTmerge= True; + } + qh MERGING= True; + } + break; + case 'C': + if (!isdigit(*s) && *s != '.' && *s != '-') + fprintf(qh ferr, "qhull warning: no centrum radius given for option 'Cn'. Ignored.\n"); + else { + if (*s == '-') { + qh premerge_centrum= -qh_strtod (s, &s); + qh_option ("Centrum-premerge-", NULL, &qh premerge_centrum); + qh PREmerge= True; + }else { + qh postmerge_centrum= qh_strtod (s, &s); + qh_option ("Centrum-postmerge", NULL, &qh postmerge_centrum); + qh POSTmerge= True; + } + qh MERGING= True; + } + break; + case 'E': + if (*s == '-') + fprintf(qh ferr, "qhull warning: negative maximum roundoff given for option 'An'. Ignored.\n"); + else if (!isdigit(*s)) + fprintf(qh ferr, "qhull warning: no maximum roundoff given for option 'En'. Ignored.\n"); + else { + qh DISTround= qh_strtod (s, &s); + qh_option ("Distance-roundoff", NULL, &qh DISTround); + qh SETroundoff= True; + } + break; + case 'H': + start= s; + qh HALFspace= True; + qh_strtod (s, &t); + while (t > s) { + if (*t && !isspace (*t)) { + if (*t == ',') + t++; + else + fprintf (qh ferr, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n"); + } + s= t; + qh_strtod (s, &t); + } + if (start < t) { + if (!(qh feasible_string= (char*)calloc (t-start+1, 1))) { + fprintf(qh ferr, "qhull error: insufficient memory for 'Hn,n,n'\n"); + qh_errexit(qh_ERRmem, NULL, NULL); + } + strncpy (qh feasible_string, start, t-start); + qh_option ("Halfspace-about", NULL, NULL); + qh_option (qh feasible_string, NULL, NULL); + }else + qh_option ("Halfspace", NULL, NULL); + break; + case 'R': + if (!isdigit(*s)) + fprintf(qh ferr, "qhull warning: missing random perturbation for option 'Rn'. Ignored\n"); + else { + qh RANDOMfactor= qh_strtod (s, &s); + qh_option ("Random_perturb", NULL, &qh RANDOMfactor); + qh RANDOMdist= True; + } + break; + case 'V': + if (!isdigit(*s) && *s != '-') + fprintf(qh ferr, "qhull warning: missing visible distance for option 'Vn'. Ignored\n"); + else { + qh MINvisible= qh_strtod (s, &s); + qh_option ("Visible", NULL, &qh MINvisible); + } + break; + case 'U': + if (!isdigit(*s) && *s != '-') + fprintf(qh ferr, "qhull warning: missing coplanar distance for option 'Un'. Ignored\n"); + else { + qh MAXcoplanar= qh_strtod (s, &s); + qh_option ("U-coplanar", NULL, &qh MAXcoplanar); + } + break; + case 'W': + if (*s == '-') + fprintf(qh ferr, "qhull warning: negative outside width for option 'Wn'. Ignored.\n"); + else if (!isdigit(*s)) + fprintf(qh ferr, "qhull warning: missing outside width for option 'Wn'. Ignored\n"); + else { + qh MINoutside= qh_strtod (s, &s); + qh_option ("W-outside", NULL, &qh MINoutside); + qh APPROXhull= True; + } + break; + /************ sub menus ***************/ + case 'F': + while (*s && !isspace(*s)) { + switch(*s++) { + case 'a': + qh_option ("Farea", NULL, NULL); + qh_appendprint (qh_PRINTarea); + qh GETarea= True; + break; + case 'A': + qh_option ("FArea-total", NULL, NULL); + qh GETarea= True; + break; + case 'c': + qh_option ("Fcoplanars", NULL, NULL); + qh_appendprint (qh_PRINTcoplanars); + break; + case 'C': + qh_option ("FCentrums", NULL, NULL); + qh_appendprint (qh_PRINTcentrums); + break; + case 'd': + qh_option ("Fd-cdd-in", NULL, NULL); + qh CDDinput= True; + break; + case 'D': + qh_option ("FD-cdd-out", NULL, NULL); + qh CDDoutput= True; + break; + case 'F': + qh_option ("FFacets-xridge", NULL, NULL); + qh_appendprint (qh_PRINTfacets_xridge); + break; + case 'i': + qh_option ("Finner", NULL, NULL); + qh_appendprint (qh_PRINTinner); + break; + case 'I': + qh_option ("FIDs", NULL, NULL); + qh_appendprint (qh_PRINTids); + break; + case 'm': + qh_option ("Fmerges", NULL, NULL); + qh_appendprint (qh_PRINTmerges); + break; + case 'n': + qh_option ("Fneighbors", NULL, NULL); + qh_appendprint (qh_PRINTneighbors); + break; + case 'N': + qh_option ("FNeighbors-vertex", NULL, NULL); + qh_appendprint (qh_PRINTvneighbors); + break; + case 'o': + qh_option ("Fouter", NULL, NULL); + qh_appendprint (qh_PRINTouter); + break; + case 'O': + if (qh PRINToptions1st) { + qh_option ("FOptions", NULL, NULL); + qh_appendprint (qh_PRINToptions); + }else + qh PRINToptions1st= True; + break; + case 'p': + qh_option ("Fpoint-intersect", NULL, NULL); + qh_appendprint (qh_PRINTpointintersect); + break; + case 'P': + qh_option ("FPoint-nearest", NULL, NULL); + qh_appendprint (qh_PRINTpointnearest); + break; + case 'Q': + qh_option ("FQhull", NULL, NULL); + qh_appendprint (qh_PRINTqhull); + break; + case 's': + qh_option ("Fsummary", NULL, NULL); + qh_appendprint (qh_PRINTsummary); + break; + case 'S': + qh_option ("FSize", NULL, NULL); + qh_appendprint (qh_PRINTsize); + qh GETarea= True; + break; + case 't': + qh_option ("Ftriangles", NULL, NULL); + qh_appendprint (qh_PRINTtriangles); + break; + case 'v': + /* option set in qh_initqhull_globals */ + qh_appendprint (qh_PRINTvertices); + break; + case 'V': + qh_option ("FVertex-average", NULL, NULL); + qh_appendprint (qh_PRINTaverage); + break; + case 'x': + qh_option ("Fxtremes", NULL, NULL); + qh_appendprint (qh_PRINTextremes); + break; + default: + s--; + fprintf (qh ferr, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]); + while (*++s && !isspace(*s)); + break; + } + } + break; + case 'G': + isgeom= True; + qh_appendprint (qh_PRINTgeom); + while (*s && !isspace(*s)) { + switch(*s++) { + case 'a': + qh_option ("Gall-points", NULL, NULL); + qh PRINTdots= True; + break; + case 'c': + qh_option ("Gcentrums", NULL, NULL); + qh PRINTcentrums= True; + break; + case 'h': + qh_option ("Gintersections", NULL, NULL); + qh DOintersections= True; + break; + case 'i': + qh_option ("Ginner", NULL, NULL); + qh PRINTinner= True; + break; + case 'n': + qh_option ("Gno-planes", NULL, NULL); + qh PRINTnoplanes= True; + break; + case 'o': + qh_option ("Gouter", NULL, NULL); + qh PRINTouter= True; + break; + case 'p': + qh_option ("Gpoints", NULL, NULL); + qh PRINTcoplanar= True; + break; + case 'r': + qh_option ("Gridges", NULL, NULL); + qh PRINTridges= True; + break; + case 't': + qh_option ("Gtransparent", NULL, NULL); + qh PRINTtransparent= True; + break; + case 'v': + qh_option ("Gvertices", NULL, NULL); + qh PRINTspheres= True; + break; + case 'D': + if (!isdigit (*s)) + fprintf (qh ferr, "qhull input error: missing dimension for option 'GDn'\n"); + else { + if (qh DROPdim >= 0) + fprintf (qh ferr, "qhull warning: can only drop one dimension. Previous 'GD%d' ignored\n", + qh DROPdim); + qh DROPdim= qh_strtol (s, &s); + qh_option ("GDrop-dim", &qh DROPdim, NULL); + } + break; + default: + s--; + fprintf (qh ferr, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]); + while (*++s && !isspace(*s)); + break; + } + } + break; + case 'P': + while (*s && !isspace(*s)) { + switch(*s++) { + case 'd': case 'D': /* see qh_initthresholds() */ + key= s[-1]; + i= qh_strtol (s, &s); + r= 0; + if (*s == ':') { + s++; + r= qh_strtod (s, &s); + } + if (key == 'd') + qh_option ("Pdrop-facets-dim-less", &i, &r); + else + qh_option ("PDrop-facets-dim-more", &i, &r); + break; + case 'g': + qh_option ("Pgood-facets", NULL, NULL); + qh PRINTgood= True; + break; + case 'G': + qh_option ("PGood-facet-neighbors", NULL, NULL); + qh PRINTneighbors= True; + break; + case 'o': + qh_option ("Poutput-forced", NULL, NULL); + qh FORCEoutput= True; + break; + case 'p': + qh_option ("Pprecision-ignore", NULL, NULL); + qh PRINTprecision= False; + break; + case 'A': + if (!isdigit (*s)) + fprintf (qh ferr, "qhull input error: missing facet count for keep area option 'PAn'\n"); + else { + qh KEEParea= qh_strtol (s, &s); + qh_option ("PArea-keep", &qh KEEParea, NULL); + qh GETarea= True; + } + break; + case 'F': + if (!isdigit (*s)) + fprintf (qh ferr, "qhull input error: missing facet area for option 'PFn'\n"); + else { + qh KEEPminArea= qh_strtod (s, &s); + qh_option ("PFacet-area-keep", NULL, &qh KEEPminArea); + qh GETarea= True; + } + break; + case 'M': + if (!isdigit (*s)) + fprintf (qh ferr, "qhull input error: missing merge count for option 'PMn'\n"); + else { + qh KEEPmerge= qh_strtol (s, &s); + qh_option ("PMerge-keep", &qh KEEPmerge, NULL); + } + break; + default: + s--; + fprintf (qh ferr, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]); + while (*++s && !isspace(*s)); + break; + } + } + break; + case 'Q': + lastproject= -1; + while (*s && !isspace(*s)) { + switch(*s++) { + case 'b': case 'B': /* handled by qh_initthresholds */ + key= s[-1]; + if (key == 'b' && *s == 'B') { + s++; + r= qh_DEFAULTbox; + qh SCALEinput= True; + qh_option ("QbBound-unit-box", NULL, &r); + break; + } + if (key == 'b' && *s == 'b') { + s++; + qh SCALElast= True; + qh_option ("Qbbound-last", NULL, NULL); + break; + } + k= qh_strtol (s, &s); + r= 0.0; + wasproject= False; + if (*s == ':') { + s++; + if ((r= qh_strtod(s, &s)) == 0.0) { + t= s; /* need true dimension for memory allocation */ + while (*t && !isspace(*t)) { + if (toupper(*t++) == 'B' + && k == qh_strtol (t, &t) + && *t++ == ':' + && qh_strtod(t, &t) == 0.0) { + qh PROJECTinput++; + trace2((qh ferr, "qh_initflags: project dimension %d\n", k)); + qh_option ("Qb-project-dim", &k, NULL); + wasproject= True; + lastproject= k; + break; + } + } + } + } + if (!wasproject) { + if (lastproject == k && r == 0.0) + lastproject= -1; /* doesn't catch all possible sequences */ + else if (key == 'b') { + qh SCALEinput= True; + if (r == 0.0) + r= -qh_DEFAULTbox; + qh_option ("Qbound-dim-low", &k, &r); + }else { + qh SCALEinput= True; + if (r == 0.0) + r= qh_DEFAULTbox; + qh_option ("QBound-dim-high", &k, &r); + } + } + break; + case 'c': + qh_option ("Qcoplanar-keep", NULL, NULL); + qh KEEPcoplanar= True; + break; + case 'f': + qh_option ("Qfurthest-outside", NULL, NULL); + qh BESToutside= True; + break; + case 'g': + qh_option ("Qgood-facets-only", NULL, NULL); + qh ONLYgood= True; + break; + case 'i': + qh_option ("Qinterior-keep", NULL, NULL); + qh KEEPinside= True; + break; + case 'm': + qh_option ("Qmax-outside-only", NULL, NULL); + qh ONLYmax= True; + break; + case 'r': + qh_option ("Qrandom-outside", NULL, NULL); + qh RANDOMoutside= True; + break; + case 's': + qh_option ("Qsearch-initial-simplex", NULL, NULL); + qh ALLpoints= True; + break; + case 't': + qh_option ("Qtriangulate", NULL, NULL); + qh TRIangulate= True; + break; + case 'T': + qh_option ("QTestPoints", NULL, NULL); + if (!isdigit (*s)) + fprintf (qh ferr, "qhull input error: missing number of test points for option 'QTn'\n"); + else { + qh TESTpoints= qh_strtol (s, &s); + qh_option ("QTestPoints", &qh TESTpoints, NULL); + } + break; + case 'u': + qh_option ("QupperDelaunay", NULL, NULL); + qh UPPERdelaunay= True; + break; + case 'v': + qh_option ("Qvertex-neighbors-convex", NULL, NULL); + qh TESTvneighbors= True; + break; + case 'x': + qh_option ("Qxact-merge", NULL, NULL); + qh MERGEexact= True; + break; + case 'z': + qh_option ("Qz-infinity-point", NULL, NULL); + qh ATinfinity= True; + break; + case '0': + qh_option ("Q0-no-premerge", NULL, NULL); + qh NOpremerge= True; + break; + case '1': + if (!isdigit(*s)) { + qh_option ("Q1-no-angle-sort", NULL, NULL); + qh ANGLEmerge= False; + break; + } + switch(*s++) { + case '0': + qh_option ("Q10-no-narrow", NULL, NULL); + qh NOnarrow= True; + break; + case '1': + qh_option ("Q11-trinormals Qtriangulate", NULL, NULL); + qh TRInormals= True; + qh TRIangulate= True; + break; + default: + s--; + fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]); + while (*++s && !isspace(*s)); + break; + } + break; + case '2': + qh_option ("Q2-no-merge-independent", NULL, NULL); + qh MERGEindependent= False; + goto LABELcheckdigit; + break; /* no warnings */ + case '3': + qh_option ("Q3-no-merge-vertices", NULL, NULL); + qh MERGEvertices= False; + LABELcheckdigit: + if (isdigit(*s)) + fprintf (qh ferr, "qhull warning: can not follow '1', '2', or '3' with a digit. '%c' skipped.\n", + *s++); + break; + case '4': + qh_option ("Q4-avoid-old-into-new", NULL, NULL); + qh AVOIDold= True; + break; + case '5': + qh_option ("Q5-no-check-outer", NULL, NULL); + qh SKIPcheckmax= True; + break; + case '6': + qh_option ("Q6-no-concave-merge", NULL, NULL); + qh SKIPconvex= True; + break; + case '7': + qh_option ("Q7-no-breadth-first", NULL, NULL); + qh VIRTUALmemory= True; + break; + case '8': + qh_option ("Q8-no-near-inside", NULL, NULL); + qh NOnearinside= True; + break; + case '9': + qh_option ("Q9-pick-furthest", NULL, NULL); + qh PICKfurthest= True; + break; + case 'G': + i= qh_strtol (s, &t); + if (qh GOODpoint) + fprintf (qh ferr, "qhull warning: good point already defined for option 'QGn'. Ignored\n"); + else if (s == t) + fprintf (qh ferr, "qhull warning: missing good point id for option 'QGn'. Ignored\n"); + else if (i < 0 || *s == '-') { + qh GOODpoint= i-1; + qh_option ("QGood-if-dont-see-point", &i, NULL); + }else { + qh GOODpoint= i+1; + qh_option ("QGood-if-see-point", &i, NULL); + } + s= t; + break; + case 'J': + if (!isdigit(*s) && *s != '-') + qh JOGGLEmax= 0.0; + else { + qh JOGGLEmax= (realT) qh_strtod (s, &s); + qh_option ("QJoggle", NULL, &qh JOGGLEmax); + } + break; + case 'R': + if (!isdigit(*s) && *s != '-') + fprintf (qh ferr, "qhull warning: missing random seed for option 'QRn'. Ignored\n"); + else { + qh ROTATErandom= i= qh_strtol(s, &s); + if (i > 0) + qh_option ("QRotate-id", &i, NULL ); + else if (i < -1) + qh_option ("QRandom-seed", &i, NULL ); + } + break; + case 'V': + i= qh_strtol (s, &t); + if (qh GOODvertex) + fprintf (qh ferr, "qhull warning: good vertex already defined for option 'QVn'. Ignored\n"); + else if (s == t) + fprintf (qh ferr, "qhull warning: no good point id given for option 'QVn'. Ignored\n"); + else if (i < 0) { + qh GOODvertex= i - 1; + qh_option ("QV-good-facets-not-point", &i, NULL); + }else { + qh_option ("QV-good-facets-point", &i, NULL); + qh GOODvertex= i + 1; + } + s= t; + break; + default: + s--; + fprintf (qh ferr, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]); + while (*++s && !isspace(*s)); + break; + } + } + break; + case 'T': + while (*s && !isspace(*s)) { + if (isdigit(*s) || *s == '-') + qh IStracing= qh_strtol(s, &s); + else switch(*s++) { + case 'c': + qh_option ("Tcheck-frequently", NULL, NULL); + qh CHECKfrequently= True; + break; + case 's': + qh_option ("Tstatistics", NULL, NULL); + qh PRINTstatistics= True; + break; + case 'v': + qh_option ("Tverify", NULL, NULL); + qh VERIFYoutput= True; + break; + case 'z': + if (!qh fout) + fprintf (qh ferr, "qhull warning: output file undefined (stdout). Option 'Tz' ignored.\n"); + else { + qh_option ("Tz-stdout", NULL, NULL); + qh ferr= qh fout; + qhmem.ferr= qh fout; + } + break; + case 'C': + if (!isdigit(*s)) + fprintf (qh ferr, "qhull warning: missing point id for cone for trace option 'TCn'. Ignored\n"); + else { + i= qh_strtol (s, &s); + qh_option ("TCone-stop", &i, NULL); + qh STOPcone= i + 1; + } + break; + case 'F': + if (!isdigit(*s)) + fprintf (qh ferr, "qhull warning: missing frequency count for trace option 'TFn'. Ignored\n"); + else { + qh REPORTfreq= qh_strtol (s, &s); + qh_option ("TFacet-log", &qh REPORTfreq, NULL); + qh REPORTfreq2= qh REPORTfreq/2; /* for tracemerging() */ + } + break; + case 'I': + if (s[0] != ' ' || s[1] == '\"' || s[1] == '\'' ||isspace (s[1])) { + s++; + fprintf (qh ferr, "qhull warning: option 'TI' mistyped.\nUse 'TI', one space, file name, and space or end-of-line.\nDo not use quotes. Option 'FI' ignored.\n"); + }else { /* not a procedure because of qh_option (filename, NULL, NULL); */ + char filename[500], *t= filename; + + s++; + while (*s) { + if (t - filename >= sizeof (filename)-2) { + fprintf (qh ferr, "qhull error: filename for 'TI' too long.\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (isspace (*s)) + break; + *(t++)= *s++; + } + *t= '\0'; + if (!freopen (filename, "r", stdin)) { + fprintf (qh ferr, "qhull error: could not open file \"%s\".", filename); + qh_errexit (qh_ERRinput, NULL, NULL); + }else { + qh_option ("TInput-file", NULL, NULL); + qh_option (filename, NULL, NULL); + } + } + break; + case 'O': + if (s[0] != ' ' || s[1] == '\"' || isspace (s[1])) { + s++; + fprintf (qh ferr, "qhull warning: option 'TO' mistyped.\nUse 'TO', one space, file name, and space or end-of-line.\nThe file name may be enclosed in single quotes.\nDo not use double quotes. Option 'FO' ignored.\n"); + }else { /* not a procedure because of qh_option (filename, NULL, NULL); */ + char filename[500], *t= filename; + boolT isquote= False; + + s++; + if (*s == '\'') { + isquote= True; + s++; + } + while (*s) { + if (t - filename >= sizeof (filename)-2) { + fprintf (qh ferr, "qhull error: filename for 'TO' too long.\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (isquote) { + if (*s == '\'') { + s++; + isquote= False; + break; + } + }else if (isspace (*s)) + break; + *(t++)= *s++; + } + *t= '\0'; + if (isquote) + fprintf (qh ferr, "qhull error: missing end quote for option 'TO'. Rest of line ignored.\n"); + else if (!freopen (filename, "w", stdout)) { + fprintf (qh ferr, "qhull error: could not open file \"%s\".", filename); + qh_errexit (qh_ERRinput, NULL, NULL); + }else { + qh_option ("TOutput-file", NULL, NULL); + qh_option (filename, NULL, NULL); + } + } + break; + case 'P': + if (!isdigit(*s)) + fprintf (qh ferr, "qhull warning: missing point id for trace option 'TPn'. Ignored\n"); + else { + qh TRACEpoint= qh_strtol (s, &s); + qh_option ("Trace-point", &qh TRACEpoint, NULL); + } + break; + case 'M': + if (!isdigit(*s)) + fprintf (qh ferr, "qhull warning: missing merge id for trace option 'TMn'. Ignored\n"); + else { + qh TRACEmerge= qh_strtol (s, &s); + qh_option ("Trace-merge", &qh TRACEmerge, NULL); + } + break; + case 'R': + if (!isdigit(*s)) + fprintf (qh ferr, "qhull warning: missing rerun count for trace option 'TRn'. Ignored\n"); + else { + qh RERUN= qh_strtol (s, &s); + qh_option ("TRerun", &qh RERUN, NULL); + } + break; + case 'V': + i= qh_strtol (s, &t); + if (s == t) + fprintf (qh ferr, "qhull warning: missing furthest point id for trace option 'TVn'. Ignored\n"); + else if (i < 0) { + qh STOPpoint= i - 1; + qh_option ("TV-stop-before-point", &i, NULL); + }else { + qh STOPpoint= i + 1; + qh_option ("TV-stop-after-point", &i, NULL); + } + s= t; + break; + case 'W': + if (!isdigit(*s)) + fprintf (qh ferr, "qhull warning: missing max width for trace option 'TWn'. Ignored\n"); + else { + qh TRACEdist= (realT) qh_strtod (s, &s); + qh_option ("TWide-trace", NULL, &qh TRACEdist); + } + break; + default: + s--; + fprintf (qh ferr, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]); + while (*++s && !isspace(*s)); + break; + } + } + break; + default: + fprintf (qh ferr, "qhull warning: unknown flag %c (%x)\n", (int)s[-1], + (int)s[-1]); + break; + } + if (s-1 == prev_s && *s && !isspace(*s)) { + fprintf (qh ferr, "qhull warning: missing space after flag %c (%x); reserved for menu. Skipped.\n", + (int)*prev_s, (int)*prev_s); + while (*s && !isspace(*s)) + s++; + } + } + if (isgeom && !qh FORCEoutput && qh PRINTout[1]) + fprintf (qh ferr, "qhull warning: additional output formats are not compatible with Geomview\n"); + /* set derived values in qh_initqhull_globals */ +} /* initflags */ + + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="initqhull_buffers">-</a> + + qh_initqhull_buffers() + initialize global memory buffers + + notes: + must match qh_freebuffers() +*/ +void qh_initqhull_buffers (void) { + int k; + + qh TEMPsize= (qhmem.LASTsize - sizeof (setT))/SETelemsize; + if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize) + qh TEMPsize= 8; /* e.g., if qh_NOmem */ + qh other_points= qh_setnew (qh TEMPsize); + qh del_vertices= qh_setnew (qh TEMPsize); + qh coplanarset= qh_setnew (qh TEMPsize); + qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT)); + qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); + qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); + qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); + qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); + for(k= qh input_dim+1; k--; ) { + qh lower_threshold[k]= -REALmax; + qh upper_threshold[k]= REALmax; + qh lower_bound[k]= -REALmax; + qh upper_bound[k]= REALmax; + } + qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT)); + qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *)); +} /* initqhull_buffers */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="initqhull_globals">-</a> + + qh_initqhull_globals( points, numpoints, dim, ismalloc ) + initialize globals + if ismalloc + points were malloc'd and qhull should free at end + + returns: + sets qh.first_point, num_points, input_dim, hull_dim and others + seeds random number generator (seed=1 if tracing) + modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput) + adjust user flags as needed + also checks DIM3 dependencies and constants + + notes: + do not use qh_point() since an input transformation may move them elsewhere + + see: + qh_initqhull_start() sets default values for non-zero globals + + design: + initialize points array from input arguments + test for qh.ZEROcentrum + (i.e., use opposite vertex instead of cetrum for convexity testing) + test for qh.PRINTgood (i.e., only print 'good' facets) + initialize qh.CENTERtype, qh.normal_size, + qh.center_size, qh.TRACEpoint/level, + initialize and test random numbers + check for conflicting print output options +*/ +void qh_initqhull_globals (coordT *points, int numpoints, int dim, boolT ismalloc) { + int seed, pointsneeded, extra= 0, i, randi, k; + boolT printgeom= False, printmath= False, printcoplanar= False; + realT randr; + realT factorial; + + time_t timedata; + + trace0((qh ferr, "qh_initqhull_globals: for %s | %s\n", qh rbox_command, + qh qhull_command)); + qh POINTSmalloc= ismalloc; + qh first_point= points; + qh num_points= numpoints; + qh hull_dim= qh input_dim= dim; + if (!qh NOpremerge && !qh MERGEexact && !qh PREmerge && qh JOGGLEmax > REALmax/2) { + qh MERGING= True; + if (qh hull_dim <= 4) { + qh PREmerge= True; + qh_option ("_pre-merge", NULL, NULL); + }else { + qh MERGEexact= True; + qh_option ("Qxact_merge", NULL, NULL); + } + }else if (qh MERGEexact) + qh MERGING= True; + if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) { +#ifdef qh_NOmerge + qh JOGGLEmax= 0.0; +#endif + } + if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && qh PRINTprecision) + fprintf(qh ferr, "qhull warning: joggle ('QJ') always produces simplicial output. Triangulated output ('Qt') does nothing.\n"); + if (qh JOGGLEmax < REALmax/2 && qh DELAUNAY && !qh SCALEinput && !qh SCALElast) { + qh SCALElast= True; + qh_option ("Qbbound-last-qj", NULL, NULL); + } + if (qh MERGING && !qh POSTmerge && qh premerge_cos > REALmax/2 + && qh premerge_centrum == 0) { + qh ZEROcentrum= True; + qh ZEROall_ok= True; + qh_option ("_zero-centrum", NULL, NULL); + } + if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision) + fprintf(qh ferr, "qhull warning: real epsilon, %2.2g, is probably too large for joggle ('QJn')\nRecompile with double precision reals (see user.h).\n", + REALepsilon); +#ifdef qh_NOmerge + if (qh MERGING) { + fprintf (qh ferr, "qhull input error: merging not installed (qh_NOmerge + 'Qx', 'Cn' or 'An')\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } +#endif + if (!(qh PRINTgood || qh PRINTneighbors)) { + if (qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge || qh DELAUNAY + || (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) { + qh PRINTgood= True; + qh_option ("Pgood", NULL, NULL); + } + } + if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) { + qh KEEPinside= True; + qh_option ("Qinterior-keep", NULL, NULL); + } + if (qh DELAUNAY && qh HALFspace) { + fprintf (qh ferr, "qhull input error: can not use Delaunay ('d') or Voronoi ('v') with halfspace intersection ('H')\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) { + fprintf (qh ferr, "qhull input error: use upper-Delaunay ('Qu') or infinity-point ('Qz') with Delaunay ('d') or Voronoi ('v')\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (qh UPPERdelaunay && qh ATinfinity) { + fprintf (qh ferr, "qhull input error: can not use infinity-point ('Qz') with upper-Delaunay ('Qu')\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision) + fprintf (qh ferr, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n"); + qh DOcheckmax= (!qh SKIPcheckmax && qh MERGING ); + qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar) + && !qh NOnearinside); + if (qh MERGING) + qh CENTERtype= qh_AScentrum; + else if (qh VORONOI) + qh CENTERtype= qh_ASvoronoi; + if (qh TESTvneighbors && !qh MERGING) { + fprintf(qh ferr, "qhull input error: test vertex neighbors ('Qv') needs a merge option\n"); + qh_errexit (qh_ERRinput, NULL ,NULL); + } + if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) { + qh hull_dim -= qh PROJECTinput; + if (qh DELAUNAY) { + qh hull_dim++; + extra= 1; + } + } + if (qh hull_dim <= 1) { + fprintf(qh ferr, "qhull error: dimension %d must be > 1\n", qh hull_dim); + qh_errexit (qh_ERRinput, NULL, NULL); + } + for (k= 2, factorial=1.0; k < qh hull_dim; k++) + factorial *= k; + qh AREAfactor= 1.0 / factorial; + trace2((qh ferr, "qh_initqhull_globals: initialize globals. dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n", + dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim)); + qh normal_size= qh hull_dim * sizeof(coordT); + qh center_size= qh normal_size - sizeof(coordT); + pointsneeded= qh hull_dim+1; + if (qh hull_dim > qh_DIMmergeVertex) { + qh MERGEvertices= False; + qh_option ("Q3-no-merge-vertices-dim-high", NULL, NULL); + } + if (qh GOODpoint) + pointsneeded++; +#ifdef qh_NOtrace + if (qh IStracing) { + fprintf (qh ferr, "qhull input error: tracing is not installed (qh_NOtrace in user.h)"); + qh_errexit (qh_ERRqhull, NULL, NULL); + } +#endif + if (qh RERUN > 1) { + qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */ + if (qh IStracing != -1) + qh IStracing= 0; + }else if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) { + qh TRACElevel= (qh IStracing? qh IStracing : 3); + qh IStracing= 0; + } + if (qh ROTATErandom == 0 || qh ROTATErandom == -1) { + seed= time (&timedata); + if (qh ROTATErandom == -1) { + seed= -seed; + qh_option ("QRandom-seed", &seed, NULL ); + }else + qh_option ("QRotate-random", &seed, NULL); + qh ROTATErandom= seed; + } + seed= qh ROTATErandom; + if (seed == INT_MIN) /* default value */ + seed= 1; + else if (seed < 0) + seed= -seed; + qh_RANDOMseed_(seed); + randr= 0.0; + for (i= 1000; i--; ) { + randi= qh_RANDOMint; + randr += randi; + if (randi > qh_RANDOMmax) { + fprintf (qh ferr, "\ +qhull configuration error (qh_RANDOMmax in user.h):\n\ + random integer %d > qh_RANDOMmax (%.8g)\n", + randi, qh_RANDOMmax); + qh_errexit (qh_ERRinput, NULL, NULL); + } + } + qh_RANDOMseed_(seed); + randr = randr/1000; + if (randr < qh_RANDOMmax/10 + || randr > qh_RANDOMmax * 5) + fprintf (qh ferr, "\ +qhull configuration warning (qh_RANDOMmax in user.h):\n\ + average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\ + Is qh_RANDOMmax (%.2g) wrong?\n", + randr, qh_RANDOMmax/2.0, qh_RANDOMmax); + qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax; + qh RANDOMb= 1.0 - qh RANDOMfactor; + if (qh_HASHfactor < 1.1) { + fprintf(qh ferr, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1. Qhull uses linear hash probing\n", + qh_HASHfactor); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + if (numpoints+extra < pointsneeded) { + fprintf(qh ferr,"qhull input error: not enough points (%d) to construct initial simplex (need %d)\n", + numpoints, pointsneeded); + qh_errexit(qh_ERRinput, NULL, NULL); + } + if (qh PRINTtransparent) { + if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) { + fprintf(qh ferr,"qhull input error: transparent Delaunay ('Gt') needs 3-d Delaunay ('d') w/o 'GDn'\n"); + qh_errexit(qh_ERRinput, NULL, NULL); + } + qh DROPdim = 3; + qh PRINTridges = True; + } + for (i= qh_PRINTEND; i--; ) { + if (qh PRINTout[i] == qh_PRINTgeom) + printgeom= True; + else if (qh PRINTout[i] == qh_PRINTmathematica) + printmath= True; + else if (qh PRINTout[i] == qh_PRINTcoplanars) + printcoplanar= True; + else if (qh PRINTout[i] == qh_PRINTpointnearest) + printcoplanar= True; + else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) { + fprintf (qh ferr, "qhull input error: option 'Fp' is only used for \nhalfspace intersection ('Hn,n,n').\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) { + fprintf (qh ferr, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) { + fprintf (qh ferr, "qhull input error: option 'FC' is not available for Voronoi vertices ('v')\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + }else if (qh PRINTout[i] == qh_PRINTvertices) { + if (qh VORONOI) + qh_option ("Fvoronoi", NULL, NULL); + else + qh_option ("Fvertices", NULL, NULL); + } + } + if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) { + if (qh PRINTprecision) + fprintf (qh ferr, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n"); + } + if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) { + if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) { + qh KEEPcoplanar = True; + qh_option ("Qcoplanar", NULL, NULL); + } + } + if (printmath && (qh hull_dim > 3 || qh VORONOI)) { + fprintf (qh ferr, "qhull input error: Mathematica output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (printgeom) { + if (qh hull_dim > 4) { + fprintf (qh ferr, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums + + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) { + fprintf (qh ferr, "qhull input error: no output specified for Geomview\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) { + fprintf (qh ferr, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n"); + qh_errexit (qh_ERRinput, NULL, NULL); + } + /* can not warn about furthest-site Geomview output: no lower_threshold */ + if (qh hull_dim == 4 && qh DROPdim == -1 && + (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) { + fprintf (qh ferr, "qhull input warning: coplanars, vertices, and centrums output not\n\ +available for 4-d output (ignored). Could use 'GDn' instead.\n"); + qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False; + } + } + qh PRINTdim= qh hull_dim; + if (qh DROPdim >=0) { /* after Geomview checks */ + if (qh DROPdim < qh hull_dim) { + qh PRINTdim--; + if (!printgeom || qh hull_dim < 3) + fprintf (qh ferr, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim); + }else + qh DROPdim= -1; + }else if (qh VORONOI) { + qh DROPdim= qh hull_dim-1; + qh PRINTdim= qh hull_dim-1; + } +} /* initqhull_globals */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="initqhull_mem">-</a> + + qh_initqhull_mem( ) + initialize mem.c for qhull + qh.hull_dim and qh.normal_size determine some of the allocation sizes + if qh.MERGING, + includes ridgeT + calls qh_user_memsizes() to add up to 10 additional sizes for quick allocation + (see numsizes below) + + returns: + mem.c already for qh_memalloc/qh_memfree (errors if called beforehand) + + notes: + qh_produceoutput() prints memsizes + +*/ +void qh_initqhull_mem (void) { + int numsizes; + int i; + + numsizes= 8+10; + qh_meminitbuffers (qh IStracing, qh_MEMalign, numsizes, + qh_MEMbufsize,qh_MEMinitbuf); + qh_memsize(sizeof(vertexT)); + if (qh MERGING) { + qh_memsize(sizeof(ridgeT)); + qh_memsize(sizeof(mergeT)); + } + qh_memsize(sizeof(facetT)); + i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize; /* ridge.vertices */ + qh_memsize(i); + qh_memsize(qh normal_size); /* normal */ + i += SETelemsize; /* facet.vertices, .ridges, .neighbors */ + qh_memsize(i); + qh_user_memsizes(); + qh_memsetup(); +} /* initqhull_mem */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="initqhull_start">-</a> + + qh_initqhull_start( infile, outfile, errfile ) + start initialization of qhull + initialize statistics, stdio, default values for global variables + + see: + qh_maxmin() determines the precision constants +*/ +void qh_initqhull_start (FILE *infile, FILE *outfile, FILE *errfile) { + + qh_CPUclock; /* start the clock */ +#if qh_QHpointer + if (!(qh_qh= (qhT *)malloc (sizeof(qhT)))) { + fprintf (errfile, "qhull error (qh_initqhull_globals): insufficient memory\n"); + exit (qh_ERRmem); /* no error handler */ + } + memset((char *)qh_qh, 0, sizeof(qhT)); /* every field is 0, FALSE, NULL */ +#else + memset((char *)&qh_qh, 0, sizeof(qhT)); +#endif + strcat (qh qhull, "qhull"); + qh_initstatistics(); + qh ANGLEmerge= True; + qh DROPdim= -1; + qh ferr= errfile; + qh fin= infile; + qh fout= outfile; + qh furthest_id= -1; + qh JOGGLEmax= REALmax; + qh KEEPminArea = REALmax; + qh last_low= REALmax; + qh last_high= REALmax; + qh last_newhigh= REALmax; + qh max_outside= 0.0; + qh max_vertex= 0.0; + qh MAXabs_coord= 0.0; + qh MAXsumcoord= 0.0; + qh MAXwidth= -REALmax; + qh MERGEindependent= True; + qh MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */ + qh MINoutside= 0.0; + qh MINvisible= REALmax; + qh MAXcoplanar= REALmax; + qh outside_err= REALmax; + qh premerge_centrum= 0.0; + qh premerge_cos= REALmax; + qh PRINTprecision= True; + qh PRINTradius= 0.0; + qh postmerge_cos= REALmax; + qh postmerge_centrum= 0.0; + qh ROTATErandom= INT_MIN; + qh MERGEvertices= True; + qh totarea= 0.0; + qh totvol= 0.0; + qh TRACEdist= REALmax; + qh TRACEpoint= -1; /* recompile or use 'TPn' */ + qh tracefacet_id= UINT_MAX; /* recompile to trace a facet */ + qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex */ + qh_RANDOMseed_(1); +} /* initqhull_start */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="initthresholds">-</a> + + qh_initthresholds( commandString ) + set thresholds for printing and scaling from commandString + + returns: + sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used + + see: + qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk' + qh_inthresholds() + + design: + for each 'Pdn' or 'PDn' option + check syntax + set qh.lower_threshold or qh.upper_threshold + set qh.GOODthreshold if an unbounded threshold is used + set qh.SPLITthreshold if a bounded threshold is used +*/ +void qh_initthresholds(char *command) { + realT value; + int index, maxdim, k; + char *s= command; + char key; + + maxdim= qh input_dim; + if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput)) + maxdim++; + while (*s) { + if (*s == '-') + s++; + if (*s == 'P') { + s++; + while (*s && !isspace(key= *s++)) { + if (key == 'd' || key == 'D') { + if (!isdigit(*s)) { + fprintf(qh ferr, "qhull warning: no dimension given for Print option '%c' at: %s. Ignored\n", + key, s-1); + continue; + } + index= qh_strtol (s, &s); + if (index >= qh hull_dim) { + fprintf(qh ferr, "qhull warning: dimension %d for Print option '%c' is >= %d. Ignored\n", + index, key, qh hull_dim); + continue; + } + if (*s == ':') { + s++; + value= qh_strtod(s, &s); + if (fabs((double)value) > 1.0) { + fprintf(qh ferr, "qhull warning: value %2.4g for Print option %c is > +1 or < -1. Ignored\n", + value, key); + continue; + } + }else + value= 0.0; + if (key == 'd') + qh lower_threshold[index]= value; + else + qh upper_threshold[index]= value; + } + } + }else if (*s == 'Q') { + s++; + while (*s && !isspace(key= *s++)) { + if (key == 'b' && *s == 'B') { + s++; + for (k=maxdim; k--; ) { + qh lower_bound[k]= -qh_DEFAULTbox; + qh upper_bound[k]= qh_DEFAULTbox; + } + }else if (key == 'b' && *s == 'b') + s++; + else if (key == 'b' || key == 'B') { + if (!isdigit(*s)) { + fprintf(qh ferr, "qhull warning: no dimension given for Qhull option %c. Ignored\n", + key); + continue; + } + index= qh_strtol (s, &s); + if (index >= maxdim) { + fprintf(qh ferr, "qhull warning: dimension %d for Qhull option %c is >= %d. Ignored\n", + index, key, maxdim); + continue; + } + if (*s == ':') { + s++; + value= qh_strtod(s, &s); + }else if (key == 'b') + value= -qh_DEFAULTbox; + else + value= qh_DEFAULTbox; + if (key == 'b') + qh lower_bound[index]= value; + else + qh upper_bound[index]= value; + } + } + }else { + while (*s && !isspace (*s)) + s++; + } + while (isspace (*s)) + s++; + } + for (k= qh hull_dim; k--; ) { + if (qh lower_threshold[k] > -REALmax/2) { + qh GOODthreshold= True; + if (qh upper_threshold[k] < REALmax/2) { + qh SPLITthresholds= True; + qh GOODthreshold= False; + break; + } + }else if (qh upper_threshold[k] < REALmax/2) + qh GOODthreshold= True; + } +} /* initthresholds */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="option">-</a> + + qh_option( option, intVal, realVal ) + add an option description to qh.qhull_options + + notes: + will be printed with statistics ('Ts') and errors + strlen(option) < 40 +*/ +void qh_option (char *option, int *i, realT *r) { + char buf[200]; + int len, maxlen; + + sprintf (buf, " %s", option); + if (i) + sprintf (buf+strlen(buf), " %d", *i); + if (r) + sprintf (buf+strlen(buf), " %2.2g", *r); + len= strlen(buf); + qh qhull_optionlen += len; + maxlen= sizeof (qh qhull_options) - len -1; + maximize_(maxlen, 0); + if (qh qhull_optionlen >= 80 && maxlen > 0) { + qh qhull_optionlen= len; + strncat (qh qhull_options, "\n", maxlen--); + } + strncat (qh qhull_options, buf, maxlen); +} /* option */ + +#if qh_QHpointer +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="restore_qhull">-</a> + + qh_restore_qhull( oldqh ) + restores a previously saved qhull + also restores qh_qhstat and qhmem.tempstack + + notes: + errors if current qhull hasn't been saved or freed + uses qhmem for error reporting + + NOTE 1998/5/11: + Freeing memory after qh_save_qhull and qh_restore_qhull + is complicated. The procedures will be redesigned. + + see: + qh_save_qhull() +*/ +void qh_restore_qhull (qhT **oldqh) { + + if (*oldqh && strcmp ((*oldqh)->qhull, "qhull")) { + fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n", + *oldqh); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + if (qh_qh) { + fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n"); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + if (!*oldqh || !(*oldqh)->old_qhstat) { + fprintf (qhmem.ferr, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n", + *oldqh); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + qh_qh= *oldqh; + *oldqh= NULL; + qh_qhstat= qh old_qhstat; + qhmem.tempstack= qh old_tempstack; + trace1((qh ferr, "qh_restore_qhull: restored qhull from %p\n", *oldqh)); +} /* restore_qhull */ + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="save_qhull">-</a> + + qh_save_qhull( ) + saves qhull for a later qh_restore_qhull + also saves qh_qhstat and qhmem.tempstack + + returns: + qh_qh=NULL + + notes: + need to initialize qhull or call qh_restore_qhull before continuing + + NOTE 1998/5/11: + Freeing memory after qh_save_qhull and qh_restore_qhull + is complicated. The procedures will be redesigned. + + see: + qh_restore_qhull() +*/ +qhT *qh_save_qhull (void) { + qhT *oldqh; + + trace1((qhmem.ferr, "qh_save_qhull: save qhull %p\n", qh_qh)); + if (!qh_qh) { + fprintf (qhmem.ferr, "qhull internal error (qh_save_qhull): qhull not initialized\n"); + qh_errexit (qh_ERRqhull, NULL, NULL); + } + qh old_qhstat= qh_qhstat; + qh_qhstat= NULL; + qh old_tempstack= qhmem.tempstack; + qhmem.tempstack= NULL; + oldqh= qh_qh; + qh_qh= NULL; + return oldqh; +} /* save_qhull */ + +#endif + +/*-<a href="qh-globa.htm#TOC" + >-------------------------------</a><a name="strtol">-</a> + + qh_strtol( s, endp) qh_strtod( s, endp) + internal versions of strtol() and strtod() + does not skip trailing spaces + notes: + some implementations of strtol()/strtod() skip trailing spaces +*/ +double qh_strtod (const char *s, char **endp) { + double result; + + result= strtod (s, endp); + if (s < (*endp) && (*endp)[-1] == ' ') + (*endp)--; + return result; +} /* strtod */ + +int qh_strtol (const char *s, char **endp) { + int result; + + result= (int) strtol (s, endp, 10); + if (s< (*endp) && (*endp)[-1] == ' ') + (*endp)--; + return result; +} /* strtol */ |